Files
2016-05-04 00:26:27 -04:00

448 lines
12 KiB
C

#ifndef _GATLING_H
#define _GATLING_H
#define _FILE_OFFSET_BITS 64
#include "gatling_features.h"
#include "iob.h"
#include "array.h"
#include "buffer.h"
#include "uint16.h"
#include "uint32.h"
#include "uint64.h"
#include <sys/stat.h>
#include <regex.h>
#include <sys/un.h>
#include <time.h>
#ifdef STATE_DEBUG
#include <stdio.h>
#endif
#ifdef SUPPORT_FTP
enum ftpstate {
GREETING,
WAITINGFORUSER,
LOGGEDIN,
WAITCONNECT,
DOWNLOADING,
UPLOADING,
};
extern int askforpassword;
#endif
#ifdef SUPPORT_PROXY
enum proxyprotocol {
HTTP,
FASTCGI,
SCGI,
};
#endif
enum encoding {
NORMAL=0,
GZIP=1,
#ifdef SUPPORT_BZIP2
BZIP2=2,
#endif
};
enum conntype {
UNUSED,
HTTPSERVER6, /* call socket_accept6() */
HTTPSERVER4, /* call socket_accept4() */
HTTPREQUEST, /* read and handle http request */
#ifdef SUPPORT_FTP
FTPSERVER6, /* call socket_accept6() */
FTPSERVER4, /* call socket_accept4() */
FTPCONTROL6, /* read and handle ftp commands */
FTPCONTROL4, /* read and handle ftp commands */
FTPPASSIVE, /* accept a slave connection */
FTPACTIVE, /* still need to connect slave connection */
FTPSLAVE, /* send/receive files */
#endif
#ifdef SUPPORT_SMB
SMBSERVER6, /* call socket_accept6() */
SMBSERVER4, /* call socket_accept4() */
SMBREQUEST, /* read and handle SMB request */
#endif
#ifdef SUPPORT_PROXY
PROXYSLAVE, /* write-to-proxy connection. */
/* write HTTP header; switch type to PROXYPOST */
PROXYPOST, /* while still_to_copy>0: write POST data; relay answer */
HTTPPOST, /* type of HTTP request with POST data
read post data and write them to proxy (ctx->buddy) */
#endif
#ifdef SUPPORT_HTTPS
HTTPSSERVER4, /* call socket_accept6() */
HTTPSSERVER6, /* call socket_accept4() */
HTTPSACCEPT, /* call SSL_accept() */
HTTPSACCEPT_CHECK, /* check whether input looks like SSL, then call SSL_accept() */
HTTPSREQUEST, /* read and handle https request */
HTTPSRESPONSE, /* write response to https request */
HTTPSPOST, /* like HTTPPOST but using SSL */
#endif
PUNISHMENT, /* if we detected a DoS and tarpit someone */
LAST_UNUNSED
};
#ifdef SUPPORT_HTTPS
#ifdef USE_POLARSSL
#undef USE_OPENSSL
#else
#define USE_OPENSSL
#endif
#ifdef USE_OPENSSL
/* in ssl.c */
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/engine.h>
extern int init_serverside_tls(SSL** ssl,int sock);
#endif
#ifdef USE_POLARSSL
/* in pssl.c */
#include <polarssl/ssl.h>
extern int init_serverside_tls(ssl_context* ssl,int sock);
#endif
#endif
/* the tree id is always 1 (we export exactly one tree in TreeConnectAndX)
* the user id is always 1, too (we hand it out in SessionSetupAndX)
* we need to hand out file handles relative to the PID though */
struct handle {
uint32_t pid,handle;
int fd;
off_t size,cur;
unsigned short* filename;
};
struct handles {
size_t u,a; /* used, allocated */
struct handle* h;
};
struct http_data {
enum conntype t;
#ifdef SUPPORT_FTP
enum ftpstate f;
#endif
array r;
io_batch iob;
char myip[16]; /* this is needed for virtual hosting */
uint32 myscope_id; /* in the absence of a Host header */
uint16 myport,peerport;
uint16 destport; /* port on remote system, used for active FTP */
char* hdrbuf,* bodybuf;
const char *mimetype;
int hlen,blen; /* hlen == length of hdrbuf, blen == length of bodybuf */
int keepalive; /* 1 if we want the TCP connection to stay connected */
/* this is always 1 for FTP except after the client said QUIT */
int filefd; /* -1 or the descriptor of the file we are sending out */
int buddy; /* descriptor for the other connection, used for FTP and proxy/CGI */
char peerip[16]; /* needed for active FTP */
unsigned long long received,sent;
enum encoding encoding;
#if defined(SUPPORT_FTP) || defined(SUPPORT_SMB)
char* ftppath; /* for FTP we store the path here, for SMB the last FIRST_FIRST2 glob expression */
#endif
#ifdef SUPPORT_SMB
uint32_t smbattrs; /* attributes from FIND_FIRST2 so FIND_NEXT2 knows whether to return directories */
#endif
#ifdef SUPPORT_FTP
uint64 ftp_rest; /* offset to start transfer at */
#endif
uint64 sent_until,prefetched_until;
#ifdef SUPPORT_PROXY
enum proxyprotocol proxyproto;
unsigned long long still_to_copy; /* for POST/PUT requests */
int havefirst; /* first read contains cgi header */
char* oldheader; /* old, unmodified request */
#endif
#ifdef SUPPORT_HTTPS
#ifdef USE_POLARSSL
ssl_context ssl;
#endif
#ifdef USE_OPENSSL
SSL* ssl;
#endif
#if 0
int writefail;
#endif
#endif
#ifdef SUPPORT_SMB
struct handles h;
#endif
#ifdef SUPPORT_THREADED_OPEN
int try_encoding;
int cwd;
char* name_of_file_to_open;
struct stat ss;
#endif
#ifdef STATE_DEBUG
int myfd;
#endif
};
#ifdef STATE_DEBUG
extern const char* state2string(enum conntype t);
#endif
static inline void changestate(struct http_data* x,enum conntype t) {
#ifdef STATE_DEBUG
if (x->t==UNUSED)
printf("STATE: new fd %d: state %s\n",x->myfd,state2string(t));
else
printf("STATE: fd %d: state change from %s to %s\n",x->myfd,state2string(x->t),state2string(t));
#endif
x->t=t;
}
#ifdef SUPPORT_HTTPS
extern char* sshd;
#endif
extern size_t max_handles;
extern struct handle* alloc_handle(struct handles* h);
extern struct handle* deref_handle(struct handles* h,uint32_t handle);
extern void close_handle(struct handle* h);
extern void close_all_handles(struct handles* h);
extern int virtual_hosts;
extern int transproxy;
extern int directory_index;
extern int logging;
extern int nouploads;
extern int chmoduploads;
extern const char months[];
#ifdef __MINGW32__
extern char origdir[PATH_MAX];
#else
extern int64 origdir;
#endif
typedef struct de {
long name; /* offset within b */
struct stat ss;
int todir;
} de;
extern char* base;
extern int sort_name_a(de* x,de* y);
extern int sort_name_d(de* x,de* y);
extern int sort_mtime_a(de* x,de* y);
extern int sort_mtime_d(de* x,de* y);
extern int sort_size_a(de* x,de* y);
extern int sort_size_d(de* x,de* y);
extern unsigned long connections;
extern unsigned long http_connections, https_connections, ftp_connections, smb_connections;
extern unsigned long cps,cps1; /* connections per second */
extern unsigned long rps,rps1; /* requests per second */
extern unsigned long eps,eps1; /* events per second */
extern unsigned long long tin,tin1; /* traffic inbound */
extern unsigned long long tout,tout1; /* traffic outbound */
extern int open_for_reading(int64* fd,const char* name,struct stat* SS);
extern unsigned int fmt_2digits(char* dest,int i);
extern int canonpath(char* s);
extern int open_for_writing(int64* fd,const char* name);
#ifdef SUPPORT_FTP
extern void ftpresponse(struct http_data* h,int64 s);
extern void handle_read_ftppassive(int64 i,struct http_data* H);
extern void handle_write_ftpactive(int64 i,struct http_data* h);
#endif
#if defined(SUPPORT_PROXY) || defined(SUPPORT_CGI)
/* You configure a list of regular expressions, and if a request matches
* one of them, the request is forwarded to some other IP:port. You can
* run another httpd there that can handle CGI, PHP, JSP and whatnot. */
struct cgi_proxy {
regex_t r;
int file_executable;
char ip[16];
uint32 port,scope_id;
struct sockaddr_un uds;
struct cgi_proxy* next;
#ifdef SUPPORT_PROXY
enum proxyprotocol proxyproto;
#endif
};
extern struct cgi_proxy* last,* cgis;
extern char** _envp;
#endif
#ifdef SUPPORT_CGI
extern int forksock[2];
#endif
extern void httpresponse(struct http_data* h,int64 s,long headerlen);
extern char* http_header(struct http_data* r,char* h);
extern int ip_vhost(struct http_data* h);
#ifdef SUPPORT_FALLBACK_REDIR
extern const char* redir;
#endif
extern tai6464 now,next;
extern unsigned long timeout_secs;
extern const char* mimetypesfilename;
extern const char* mimetype(const char* filename,int fd);
extern int add_proxy(const char* c);
extern void handle_read_proxypost(int64 i,struct http_data* H);
extern void handle_read_httppost(int64 i,struct http_data* H);
extern void handle_write_proxypost(int64 i,struct http_data* h);
extern void handle_write_httppost(int64 i,struct http_data* h);
extern void handle_write_proxyslave(int64 i,struct http_data* h);
extern void cleanup(int64 sock);
extern size_t header_complete(struct http_data* r,int64 sock);
extern void httperror_realm(struct http_data* r,const char* title,const char* message,const char* realm,int nobody);
extern void httperror(struct http_data* r,const char* title,const char* message,int nobody);
extern int buffer_putlogstr(buffer* b,const char* s);
extern char fsbuf[8192];
extern void forkslave(int fd,buffer* in,int savedir,const char* chroot_to);
#ifdef USE_ZLIB
#include <zlib.h>
#endif
#ifdef SUPPORT_SMB
extern int smbresponse(struct http_data* h,int64 s);
extern char workgroup[20];
extern int wglen;
extern char workgroup_utf16[100];
extern int wglen16;
#endif
extern int64 origdir;
#include "version.h"
#define RELEASE "Gatling/" VERSION
extern unsigned int max_requests_per_minute;
/* call this function when a request comes in, with the peer's IP
* address as argument */
int new_request_from_ip(const char ip[16],time_t now);
/* returns 0 if the request was added and should be serviced.
* returns 1 if a denial of service attack from this IP was detected and
* the request should not be serviced
* returns -1 if we ran out of memory trying to add the request */
#ifdef SUPPORT_HTTPS
extern int64 https_write_callback(int64 sock,const void* buf,uint64 n);
extern int handle_ssl_error_code(int sock,int code,int reading);
#endif
extern char* magicelfvalue;
extern char serverroot[];
extern char* defaultindex;
#ifdef DEBUG_EVENTS
#include "fmt.h"
static void new_io_wantwrite(int64 s,const char* file,unsigned int line) {
char a[FMT_ULONG];
char b[FMT_ULONG];
char c[100];
#ifdef STATE_DEBUG
struct http_data* h=io_getcookie(s);
if (h)
c[fmt_strm(c," [state ",state2string(h->t),"]")]=0;
else
strcpy(c," [cookie is NULL]");
#else
c[0]=0;
#endif
a[fmt_ulong(a,s)]=0;
b[fmt_ulong(b,line)]=0;
buffer_putmflush(buffer_2,"DEBUG: ",file,":",b,": io_wantwrite(",a,")",c,"\n");
io_wantwrite(s);
}
static void new_io_dontwantwrite(int64 s,const char* file,unsigned int line) {
char a[FMT_ULONG];
char b[FMT_ULONG];
char c[100];
#ifdef STATE_DEBUG
struct http_data* h=io_getcookie(s);
if (h)
c[fmt_strm(c," [state ",state2string(h->t),"]")]=0;
else
strcpy(c," [cookie is NULL]");
#else
c[0]=0;
#endif
a[fmt_ulong(a,s)]=0;
b[fmt_ulong(b,line)]=0;
buffer_putmflush(buffer_2,"DEBUG: ",file,":",b,": io_dontwantwrite(",a,")",c,"\n");
io_dontwantwrite(s);
}
static void new_io_wantread(int64 s,const char* file,unsigned int line) {
char a[FMT_ULONG];
char b[FMT_ULONG];
char c[100];
#ifdef STATE_DEBUG
struct http_data* h=io_getcookie(s);
if (h)
c[fmt_strm(c," [state ",state2string(h->t),"]")]=0;
else
strcpy(c," [cookie is NULL]");
#else
c[0]=0;
#endif
a[fmt_ulong(a,s)]=0;
b[fmt_ulong(b,line)]=0;
buffer_putmflush(buffer_2,"DEBUG: ",file,":",b,": io_wantread(",a,")",c,"\n");
io_wantread(s);
}
static void new_io_dontwantread(int64 s,const char* file,unsigned int line) {
char a[FMT_ULONG];
char b[FMT_ULONG];
struct http_data* h=io_getcookie(s);
char c[100];
c[0]=0;
#ifdef STATE_DEBUG
if (h)
c[fmt_strm(c," [state ",state2string(h->t),"]")]=0;
else
strcpy(c," [cookie is NULL]");
#endif
a[fmt_ulong(a,s)]=0;
b[fmt_ulong(b,line)]=0;
buffer_putmflush(buffer_2,"DEBUG: ",file,":",b,": io_dontwantread(",a,")",c,"\n");
io_dontwantread(s);
}
#define io_wantwrite(s) new_io_wantwrite(s,__FILE__,__LINE__)
#define io_wantread(s) new_io_wantread(s,__FILE__,__LINE__)
#define io_dontwantwrite(s) new_io_dontwantwrite(s,__FILE__,__LINE__)
#define io_dontwantread(s) new_io_dontwantread(s,__FILE__,__LINE__)
#endif
#endif