DBS on tertun palvelinohjelma, joka vastaanottaa asiakkaan selaimelta sivupyyntöjä, kutsuu sovellusohjelmaa (DBA), joka muotostaa sivupyynnön pohjalta vastauksen. Vastaus palautetaan DBS:lle, joka lähettää tuloksen asiakkaalle.
Edit: muutoksia julkaisun jälkeen:
Palvelimissa on vielä ongelmaa Safari-selaimen kanssa, safari menee “luuppiin”, jos haetaan sekä portillista ja portitonta URL:ää vuorotellen (moijari.com ja moijari.com:5005).
.ico (favicon.ico) tiedostopyyntöjen ohittamista varten lisätty muuttuja htmlextension muuttuja, sille hakurutiini dbs_html_parse_extension ja kutsu edelliselle rutiinille. Ei korjannut safari ongelmaa. Seuraavana ressu3 (moijari.com:5005) koodi:
void dba_loop()
{
html_clear_all();
if(!strcmp(htmlextension,"ico")) {
dbs_html_set(0);
dbs_html_printf("HTTP/1.0 404 Not Found\r\n");
dbs_html_printf("Location: \r\n");
dbs_html_printf("Server: %s\r\n", programname);
} else {
dbs_html_set(0);
dbs_html_printf("HTTP/1.0 200 OK\r\n");
dbs_html_printf("Location: \r\n");
dbs_html_printf("Server: %s\r\n", programname);
dbs_html_printf("Date: %s\r\n", htmltime);
dbs_html_set(1);
dbs_html_printf("\n<!doctype html>\r\n");
dbs_html_printf("<html lang=\"fi\">");
dbs_html_printf("<head>");
dbs_html_printf("<meta charset=\"utf-8\">");
dbs_html_printf("<title>%s</title>",proctitle);
dbs_html_printf("<meta name=\"author\" content=\"Jari Kuivaniemi\">");
dbs_html_printf("<meta name=\"copyright\" content=\"Jari Kuivaniemi\">");
dbs_html_printf("</head>");
dbs_html_printf("<body>");
ressu3_app();
dbs_html_printf("<br><br>%s, sha256(%s)<br><br>", programname,
htmldigest);
dbs_html_printf("\t\toriginal url: <a href=\"https://moijari.com:5001\">https://moijari.com:5005</a>\n");
dbs_html_printf("\t\t or <a href=\"https://moijari.com:5005\">https://moijari.com:5005</a><br>\n");
dbs_html_printf("</body>");
dbs_html_printf("</html>");
int len;
dbs_html_set(0);
len=strlen(html_get_string(1)) +
strlen(html_get_string(2)) +
strlen(html_get_string(3)) +
strlen(html_get_string(4));
dbs_html_printf("Content-Length: %d", len);
dbs_html_printf("\r\n\r\n");
}
}
End of muutokset.
Ohjelman käyttämiä muuttujia:
unsigned char *htmlin;
int htmlinlen=2048;
unsigned char htmlmethod[10];
unsigned char htmlpath[128];
unsigned char htmlversion[32];
unsigned char htmlfilename[64];
unsigned char htmlextension[10];
unsigned char htmlsessionid[33];
unsigned char htmltime[32];
unsigned char htmltimeshort[32];
unsigned char *htmlparams=NULL;
unsigned char htmldigest[HashLen*2+1];
unsigned char htmlmode[10];
unsigned char htmlip[32];
unsigned char htmlsslcipher[64];
unsigned char htmlhostname[33];
unsigned char htmlport[10];
unsigned char htmllanguage[10];
Rutiini muuttaa html-scriptin hexana esitetyn yksi numeroisen luvun int:iksi.
static int dbs_parse_hex1(unsigned char **str) /* 20131003 JariK */
{
unsigned char *p;
int digit;
p=*str;
digit=0;
if(*p>='a'&&*p<='f')
digit=*p-'a'+10,p++;
else if(*p>='A'&&*p<='F')
digit=*p-'A'+10,p++;
else if(*p>='0'&&*p<='9')
digit=*p-'0',p++;
else digit=-1;
*str=p;
return(digit);
}
Tämä rutiini muodostaa html parametristä UTF8-merkkinonon.
Tässä versiossa on lisätty satunnaisuuden keräysrutiineja fort:lle (FORT_EVENTS_START ja FORT_EVENT_END), kuten muissakin myöhemmissä rutiineissa.
static int dbs_parse_html_string(
int stringlen, unsigned char *string,
unsigned char **html)
{
int c,d,count,ok;
unsigned char *s=string;
unsigned char *h=*html;
FORT_EVENTS_START(300)
ok=0;
count=0;
while(isalnum(*h)||*h=='%'||*h=='+'||*h=='-'||*h=='_' || *h=='.'|| *h==',' || *h=='*') {
ok=1;
if(*h=='%') {
h++;
if((c=dbs_parse_hex1(&h))>=0) {
if((d=dbs_parse_hex1(&h))>=0) {
c=c*16+d;
} else
c=c;
} else
c=64;
if(++count<stringlen)
*s++=c;
} else if(*h=='+') {
if(++count<stringlen)
*s++=' ';
h++;
} else {
if(++count<stringlen)
*s++=*h;
h++;
}
}
*s='\0';
*html=h;
FORT_EVENTS_END(301)
return(ok);
}
Seuraavassa rutiinit, joita käytetään satunnaisuuden keräämiseen edellisessä ja seuraavissa funktioissa. Olen lisännyt sen sellaisiin rutiineihin jotka sisältävät suorituspituutensa puolesta suoritusajan vaihtelua. Jos et halua käyttää näitä lisää pikku-a FORT_EVENTS määritykseen. Voit tarkastella tapahtumien satunnaisuutta “grep source=300 fortevents.deb” komennolla, jossa 300 on halutun lähteen numero.
#ifdef FORT_EVENTS
#define FORT_EVENTS_START(source) \
IUTIME micros; \
static int \
pool=0, pool2=0; \
if(fort_events) { \
fort_add_random_event_time(&pool, \
source, fort_event_mode); \
fort_add_random_event_timer_start(µs); \
}
#else
#define FORT_EVENTS_START(source)
#endif
#ifdef FORT_EVENTS
#define FORT_EVENTS_END(source) \
if(fort_events) \
fort_add_random_event_timer_do(&pool2, \
source, fort_event_mode, \
µs);
#else
#define FORT_EVENTS_END(source)
#endif
dbs_html_get_string muuntaa koko merkkijonon, ei pelkästään parametrejä UTF8 muotoon(se sisältää myös parametrierottimen ‘&’).
#include <stdarg.h>
int dbs_html_get_string(unsigned char *string,unsigned char **str,int len)
{
int c,d,ok,count;
unsigned char *p,*n;
FORT_EVENTS_START(302)
n=string;
p=*str;
ok=0;
count=0;
while(isalnum(*p)||*p=='%'||*p=='+'||
*p=='-'||*p=='_'||*p=='=' || *p=='&' ||
*p=='.' || *p=='*') {
ok=1;
if(*p=='%') {
p++;
if((c=dbs_parse_hex1(&p))>=0) {
if((d=dbs_parse_hex1(&p))>=0) {
c=c*16+d;
} else
c=c;
} else
c=64;
if(count++<len)
*n++=c;
} else if(*p=='+') {
if(count++<len)
*n++=' ';
p++;
} else {
if(count++<len)
*n++=*p++;
else
p++;
}
}
*n='\0';
*str=p;
FORT_EVENTS_END(303)
return(ok);
}
Seuraava rutiini palauttaa seuraavan parametrin nimen ja arvon. Merkkijonon parsiminen aloitetaan s osoitteesta ja suorituksen jälkeen uusi merkkijonon kohta talletetaan takaisin s muuttujaan (**):
int dbs_parse_html_parameter(int namelen, unsigned char *name,
int valuelen,unsigned char *value,
unsigned char **s)
{
FORT_EVENTS_START(304)
if(dbs_parse_html_string(namelen, name, s)==0)
return(0);
if((**s)=='=')
(*s)++;
dbs_parse_html_string(valuelen, value, s);
#ifdef OLD1
if(dbs_parse_html_string(valuelen, value, s)==0)
return(0);
#endif
if(**s=='&')
(*s)++;
FORT_EVENTS_END(305)
return(1);
}
Seuraava rutiini palauttaa halutun nimisen parametrin html sivun parametreista: Parametrit alkavat kohdasta htmlparams.
int dbs_get_parameter(char *name, int valuelen, unsigned char *value)
{
int ok;
unsigned char name2[32];
unsigned char *h=htmlparams;
FORT_EVENTS_START(306)
value[0]='\0';
ok=0;
while(*h!='\0') {
dbs_parse_html_parameter(sizeof(name2), name2, valuelen, value, &h);
if(!strcmp(name,name2)) {
ok=1;
break;
}
}
FORT_EVENTS_END(307)
return(ok);
}
Tässä vanha tuttu sekuntien haku:
static unsigned long dbs_getseconds()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return((IUTIME)tv.tv_sec);
}
Seuraavalla rutiinilla palautetaan html-otsakkeen rivi, joka alkaa tietyllä merkkijonolla: (tällä haetaan ainakin Cookie ja Content-Length -rivit: (sessionid kenttää (+ ip:tä) ei vielä tarkasteta, ip:t poistettu, sessionid poistettu)
EET20201211183424, ip="x.x.x.x", callid="1826"
POST /app HTTP/1.1^M
Host: x.x.x.x:5004^M
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0^M
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8^M
Accept-Language: en-US,en;q=0.5^M
Accept-Encoding: gzip, deflate, br^M
Content-Type: application/x-www-form-urlencoded^M
Content-Length: 230^M
Origin: https://x.x.x.x:5004^M
Connection: keep-alive^M
Referer: https://x.x.x.x:5004/logon^M
Cookie: sessionid=012345678901234567890123456789012; mode=Display; language=fi^M
Upgrade-Insecure-Requests: 1^M
static unsigned char *dbs_html_get_request_line(unsigned char *name)
{
unsigned char *p;
FORT_EVENTS_START(308)
p=htmlin;
while(*p!='\0') {
if(!strncmp(p,"\r\n",2)) {
p+=2;
if(!strncmp(p,name,strlen(name))) {
p+=strlen(name);
if(*p==':') {
p++;
while(isblank(*p))
p++;
return(p);
}
}
}
p++;
}
FORT_EVENTS_END(309)
return(NULL);
}
Tällä haetaan numeerinen html-otsakkeen rivi: (käytetään Content-Length haussa)
static void dbs_html_get_request_line_num(
unsigned char *name,
int lenbuffer, unsigned char *buffer)
{
int len;
unsigned char *n, *p;
FORT_EVENTS_START(310)
if((p=dbs_html_get_request_line(name))==NULL)
sprintf(buffer,"0");
else {
len=0;
n=buffer;
while(isdigit(*p)) {
if(++len<lenbuffer)
*n++=*p;
p++;
}
*n='\0';
}
FORT_EVENTS_END(311)
}
Tällä haetaan nimetty cookie:
void dbs_get_cookie(unsigned char *name,
int valuelen, unsigned char *value)
{
int len;
unsigned char *p,*n;
FORT_EVENTS_START(312)
if((p=dbs_html_get_request_line("Cookie"))==NULL) {
return;
}
while(*p!='\n' && *p!='\0') {
while(isblank(*p))
p++;
if(!strncmp(p,name,strlen(name))) {
p+=strlen(name);
while(isblank(*p))
p++;
if(*p=='=')
p++;
while(isblank(*p))
p++;
n=value;
len=0;
while(*p!=';' && isprint(*p)) {
if(++len<sizeof(htmlsessionid))
*n++=*p;
p++;
}
*n='\0';
return;
}
while(*p!=';' && *p!='\n' && *p!='\0')
p++;
if(*p==';')
p++;
while(isblank(*p))
p++;
}
FORT_EVENTS_END(313)
}
Tätä käytetään välilyönneillä erotellun cr-lf loppuisen merkkijonon parsimiseen: Se on lähinnä käytössä html-otsakkeen ensimmäisellä rivillä (POST /app HTTP/1.1^M)
static void dbs_html_parse_string(int buflen, char *buf, unsigned char **p2)
{
int len;
unsigned char *p;
FORT_EVENTS_START(314)
p=*p2;
len=0;
while(!isblank(*p) && *p!='\n' && *p!='\r') {
if(++len<buflen) {
*buf++=*p;
}
p++;
}
*buf='\0';
while(isblank(*p))
p++;
*p2=p;
FORT_EVENTS_END(315)
}
Tätä käytetään välilyönneillä erotellun cr-lf loppuisen merkkijoon parsimiseen. Se parsii tiedostopolun tiedostonimen: Se on käytössä html-otsakkeen ensimmäisellä rivillä (POST /app HTTP/1.1^M). Tiedostonimi on tietenkin tiedostopolun viimeisen kauttaviivan jälkeinen osa.
static void dbs_html_parse_filename(int buflen, char *buf,
unsigned char *p)
{
int len;
unsigned char *n;
FORT_EVENTS_START(316)
len=0;
n=buf;
while(*p!='\0') {
if(*p=='/') {
n=buf;
len=0;
} else {
if(++len<buflen)
*n++=*p;
}
p++;
}
*n='\0';
FORT_EVENTS_END(317)
}
Tämä rutiini hakee tiedoston nimen jatkeen (extension) edellisen kappaleen palauttamasta tiedostonimestä:
static void dbs_html_parse_extension(int buflen, char *buf, unsigned char *p)
{
int len;
unsigned char *n;
FORT_EVENTS_START(330)
len=0;
n=buf;
while(*p!='\0') {
if(*p=='.') {
n=buf;
len=0;
} else {
if(++len<buflen)
*n++=*p;
}
p++;
}
*n='\0';
FORT_EVENTS_END(331)
}
Seuraavaa käytetään html-otsakkeen “payload” kentän hakuun. Se sisältää pyynnöstä riippuen joko parametrien arvot tai asiakkaalle palautetun html-sivun rivit. Payload kenttä löytyy html-otsakkeen ensimmäisen “\r\n\r\n”-merkkijonon jälkeen.
static unsigned char *dbs_html_get_params()
{
int ok=0;
unsigned char *p=htmlin;
FORT_EVENTS_START(318)
while(*p!='\0') {
if(!strncmp(p,"\r\n\r\n",4)) {
p+=4;
ok=1;
break;
}
p++;
}
FORT_EVENTS_END(319)
if(ok==0)
return(NULL);
else
return(p);
}
Aliohjelmaa käytetään lähinnä ohjelman lokien talletuksessa.
static void dbs_add_end_new_str(char *filename, char *string)
{
int ok;
char buffer[256];
FILE *fp1;
ok=0;
if((fp1=fopen(filename,"r"))!=NULL) {
while(fgets(buffer,sizeof(buffer),fp1)!=NULL) {
buffer[strlen(buffer)-1]='\0';
if(!strcmp(buffer,string)) {
ok=1;
break;
}
}
fclose(fp1);
}
if(!ok) {
if((fp1=fopen(filename,"a"))!=NULL) {
fprintf(fp1,"%s\n",string);
fclose(fp1);
}
}
}
Tätä rutiinia käytetään https- ja http-palvelimien jälkeen ja se hakee yhteyden ja html-otsakkeen tiedot lokien ja asiakasohjelman käyttämiin kenttiin. Lisäksi tämä kerää lokitietoja edellisistä.
void dba_loop();
static void dbs_run_loop()
{
unsigned char *p;
FORT_EVENTS_START(320)
p=htmlin;
dbs_html_parse_string(sizeof(htmlmethod), htmlmethod,&p);
fprintf(stdout,"htmlmethod: \"%s\"", htmlmethod);
fflush(stdout);
dbs_html_parse_string(sizeof(htmlpath), htmlpath, &p);
fprintf(stdout,", htmlpath: \"%s\"", htmlpath);
fflush(stdout);
dbs_html_parse_string(sizeof(htmlversion), htmlversion, &p);
fprintf(stdout,", htmlversion: \"%s\"", htmlversion);
fflush(stdout);
dbs_html_parse_filename(sizeof(htmlfilename), htmlfilename, htmlpath);
fprintf(stdout,", htmlfilename: \"%s\"", htmlfilename);
fflush(stdout);
dbs_html_parse_extension(sizeof(htmlextension), htmlextension, htmlfilename);
fprintf(stdout,", htmlextension: \"%s\"", htmlextension);
fflush(stdout);
htmlparams=dbs_html_get_params();
if(htmlparams==NULL)
htmlparams="";
fprintf(stdout,", htmlparamslen: \"%ld\"", strlen(htmlparams));
html_clear_all();
dba_loop();
FILE *fp1;
char filename[64];
sprintf(filename,"%stimelog.deb",filenamehead);
if((fp1=fopen(filename,"a"))!=NULL) {
fprintf(fp1,"%s, ip=\"%s\"\n",htmltime, htmlip);
fclose(fp1);
}
sprintf(filename,"%sips.deb",filenamehead);
dbs_add_end_new_str(filename, htmlip);
sprintf(filename,"%shostname.deb",filenamehead);
dbs_add_end_new_str(filename, htmlhostname);
if(htmlsslcipher[0]!='\0') {
sprintf(filename,"%sciphers.deb",filenamehead);
dbs_add_end_new_str(filename,htmlsslcipher);
}
sprintf(filename,"%shtml.deb",filenamehead);
if((fp1 = fopen(filename,"a")) != NULL) {
fprintf(fp1,"%s, ip=\"%s\", callid=\"%d\"\n",htmltime, htmlip, callid);
fprintf(fp1,"%s\n",htmlin);
for(int c=0;c<HTML_BUFFERS;c++) {
if(strlen(html_get_string(c))>0) {
fprintf(fp1,"%d: %s\n",c,html_get_string(c));
}
}
fclose(fp1);
}
fprintf(stdout,"\ncallid: %d\n", callid++);
sprintf(filename,"%scallid.deb",filenamehead);
if((fp1 = fopen(filename,"w")) != NULL) {
fprintf(fp1,"%d\n", callid);
fclose(fp1);
}
FORT_EVENTS_END(321)
}
Seuraavana lopun palvelinohjelmien osat, joita käytetään sekä https- että http-palvelimissa.
#include <errno.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* See: http://h41379.www4.hpe.com/doc/83final/ba554_90007/ch04s03.html */
#include <netdb.h>
#define backlog 5
int s,news;
char *cert_file = "cert.pem";
char *privatekey_file = "key.pem";
extern char *myport;
static int server_getaddrinfo(unsigned char *myport, struct addrinfo **res)
{
int status;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((status = getaddrinfo(NULL, myport, &hints, res)) != 0) {
fprintf(stderr, "\n%s: getaddrinfo error: %s",
procname, gai_strerror(status));
fprintf(stderr, ", error code %d\n", status);
fflush(stderr);
}
return(status);
}
static int server_socket(struct addrinfo *res)
{
int s;
if((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol))==-1) {
fprintf(stderr, "%s: socket(), error: %d\n", procname, errno);
perror("socket");
fflush(stderr);
}
return(s);
}
static void server_bind(int s, struct addrinfo *res)
{
if(bind(s, res->ai_addr, res->ai_addrlen)==-1) {
if(errno == 98) {
fprintf(stdout,"%s cannot bind, waiting to bind", procname);
fflush(stdout);
while(errno == 98) {
sleep(10);
fprintf(stdout,".");
fflush(stdout);
bind(s, res->ai_addr, res->ai_addrlen);
}
fprintf(stdout,"bind done!\n");
fflush(stdout);
} else {
fprintf(stderr,"\n%s: cannot bind(), error: %d\n", procname, errno);
perror("bind");
fflush(stderr);
}
}
}
static int server_listen(int s)
{
int listenfd;
if((listenfd=listen(s,backlog))==-1) {
fprintf(stderr,"\n%s: cannot listen()\n", procname);
perror("listen");
fflush(stderr);
}
return(listenfd);
}
static void server_close(int s)
{
if(close(s)==-1) {
fprintf(stderr,"\n%s: cannot close()\n", procname);
perror("close");
fflush(stderr);
}
}
Palvelimiin on lisätty metodilla GET ehto, jolloin GET pyynnöt voivat olla yksi blokkisia.
Seuraavassa http-osuus palvelimesta:
#include <sys/socket.h>
#define TIMEFORMAT "%Z%Y%m%d%H%M%S"
#define HTMLTIMEFORMAT "%a, %d %b %Y %H:%M:%S %Z"
static void http_server()
{
int addr_size;
struct sockaddr_in sa_cli;
struct addrinfo *res;
unsigned char buffer10[10];
FORT_EVENTS_START(322)
// plus space for '\0'
htmlin = malloc(htmlinlen+1);
signal(SIGPIPE, SIG_IGN);
server_getaddrinfo(myport,&res);
s = server_socket(res);
server_bind(s,res);
freeaddrinfo(res);
server_listen(s); //listenfd=server_listen(s);
for(;;) {
FORT_EVENTS_START(323)
addr_size = sizeof(sa_cli);
news = accept(s, (struct sockaddr *)&sa_cli, &addr_size);
strcpy(htmlip, inet_ntoa(sa_cli.sin_addr));
sprintf(htmlport,"%d", sa_cli.sin_port);
htmlsslcipher[0] = '\0';
char host[32], serv[32];
getnameinfo((struct sockaddr *)&sa_cli,addr_size,host,sizeof(host),serv,sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV);
fprintf(stdout," numeric hostname:%s",host);
fprintf(stdout," numeric service:%s",serv);
getnameinfo((struct sockaddr *)&sa_cli,addr_size,host,sizeof(host),serv,sizeof(serv),NI_NUMERICSERV);
fprintf(stdout," name hostname:%s",host);
fprintf(stdout," service:%s",serv);
htmlhostname[0]='\0';
unsigned long seconds = dbs_getseconds();
strftime(htmltimeshort, sizeof(htmltimeshort), TIMEFORMAT,
localtime((time_t *)&seconds));
strftime(htmltime, sizeof(htmltime), HTMLTIMEFORMAT,
localtime((time_t *)&seconds));
fprintf(stdout,"\nConnection(http) from %x", sa_cli.sin_addr.s_addr);
fprintf(stdout,", ip %s", htmlip);
fprintf(stdout,", port %s", htmlport);
fprintf(stdout,", at %s\n", htmltime);
int clen = 0;
int reads = 0;
int first = 1;
int bytes, totalbytes=0;
htmlparams = NULL;
htmlin[0]='\0';
while(htmlparams == NULL ||
clen-strlen(htmlparams) > 0) {
if(!first) {
fprintf(stdout,", ");
}
fprintf(stdout,"read %d", reads);
fflush(stdout);
if((bytes=read(news, htmlin+totalbytes, htmlinlen-totalbytes))<0) {
fprintf(stderr,"\n%s: cannot read()\n", procname);
perror("read");
fflush(stderr);
}
fprintf(stdout,"(%d bytes)", bytes);
if(bytes==0)
break;
if(bytes>3 &&
!isprint(htmlin[0]) &&
!isprint(htmlin[1]) &&
!isprint(htmlin[2])) {
fprintf(stdout,"https packet?\n");
htmlin[0]='\0';
totalbytes=0;
bytes=0;
break;
}
*(htmlin+totalbytes+bytes) = '\0';
fprintf(stdout,"%s\n",htmlin);
totalbytes+=bytes;
if(totalbytes>=htmlinlen) {
// plus space for '\0'
htmlin=realloc(htmlin, htmlinlen*2+1);
htmlinlen*=2;
}
htmlparams = dbs_html_get_params();
unsigned char *p=htmlin;
dbs_html_parse_string(sizeof(htmlmethod), htmlmethod,&p);
if(!strcmp(htmlmethod,"GET"))
break;
dbs_html_get_request_line_num("Content-Length", sizeof(buffer10), buffer10);
clen = atoi(buffer10);
reads++;
first = 0;
}
if(totalbytes==0)
continue;
fprintf(stdout,"\n%d reads", reads);
fprintf(stdout,", received %d chars", totalbytes);
fprintf(stdout,", read %d total bytes", totalbytes);
fprintf(stdout,", input buffer size %d chars", htmlinlen);
fprintf(stdout,", data=\"%s\"\n", htmlin);
dbs_run_loop();
for(int c=0;c<HTML_BUFFERS;c++) {
if(strlen(html_get_string(c))>0) {
if((bytes=write(news, html_get_string(c), strlen(html_get_string(c))))==-1) {
fprintf(stderr,"\n%s: cannot write() dbs_html[%d]\n", procname, c);
perror("write");
fflush(stderr);
}
}
}
server_close(news);
fflush(stdout);
FORT_EVENTS_END(324)
}
FORT_EVENTS_END(325)
}
Seuraavaksi https-palvelin:
static void https_server()
{
int status, addr_size;
SSL_METHOD *method=NULL;
SSL_CTX *ctx=NULL;
SSL *ssl;
X509 *peer_cert;
struct sockaddr_in sa_cli;
struct addrinfo *res;
unsigned char buffer10[10];
FORT_EVENTS_START(326)
// plus space for '\0'
htmlin = malloc(htmlinlen+1);
signal(SIGPIPE, SIG_IGN);
SSL_library_init();
OpenSSL_add_ssl_algorithms();
OpenSSL_add_all_ciphers();
SSL_load_error_strings();
if((method = (SSL_METHOD *)
SSLv23_server_method()) == NULL) {
fprintf(stderr,"\n%s: cannot SSLv3_server_method()", procname);
fflush(stderr);
}
if((ctx=SSL_CTX_new(method)) == NULL) {
fprintf(stderr,"\n%s: cannot SSL_CTX_new()", procname);
fflush(stderr);
}
if(SSL_CTX_use_certificate_file(ctx,
cert_file, SSL_FILETYPE_PEM) <= 0) {
fprintf(stderr,"\n%s: cannot SSL_CTX_use_certificate()", procname);
fflush(stderr);
}
if(SSL_CTX_use_PrivateKey_file(ctx,
privatekey_file, SSL_FILETYPE_PEM)<=0) {
fprintf(stderr,"\n%s: cannot SSL_CTX_use_certificate()", procname);
fflush(stderr);
}
if(!SSL_CTX_load_verify_locations(ctx,
cert_file, NULL)) {
fprintf(stderr,"\n%s: cannot SSL_CTX_verify_locations()", procname);
fflush(stderr);
}
server_getaddrinfo(myport, &res);
s=server_socket(res);
server_bind(s, res);
freeaddrinfo(res);
server_listen(s); // listenfd = server_listen(s);
for(;;) {
FORT_EVENTS_START(327)
addr_size = sizeof(sa_cli);
if((news=accept(s, (struct sockaddr *)&sa_cli, &addr_size))==-1) {
fprintf(stderr,"\n%s: cannot accept()\n", procname);
perror("accept");
fflush(stderr);
}
strcpy(htmlip, inet_ntoa(sa_cli.sin_addr));
sprintf(htmlport,"%d", sa_cli.sin_port);
char host[32], serv[32];
getnameinfo((struct sockaddr *)&sa_cli,addr_size,host,sizeof(host),serv,sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV);
fprintf(stdout," numeric hostname:%s",host);
fprintf(stdout," numeric service:%s",serv);
getnameinfo((struct sockaddr *)&sa_cli,addr_size,host,sizeof(host),serv,sizeof(serv),NI_NUMERICSERV);
fprintf(stdout," name hostname:%s",host);
fprintf(stdout," service:%s",serv);
unsigned long seconds = dbs_getseconds();
strftime(htmltimeshort, sizeof(htmltimeshort), TIMEFORMAT,
localtime((time_t *)&seconds));
strftime(htmltime, sizeof(htmltime), HTMLTIMEFORMAT,
localtime((time_t *)&seconds));
fprintf(stdout,"\nConnection(https) from %x", sa_cli.sin_addr.s_addr);
fprintf(stdout,", ip %s", htmlip);
fprintf(stdout,", port %s", htmlport);
fprintf(stdout,", at %s\n", htmltime);
if((ssl=SSL_new(ctx)) == NULL) {
fprintf(stderr,"\n%s: cannot SSL_new()", procname);
fflush(stderr);
}
if(SSL_set_fd(ssl,news) != 1) {
fprintf(stderr,"\n%s: cannot SSL_set_fd()", procname);
fflush(stderr);
}
int doreadwrite=1,tries=0;
for(;;) {
tries++;
if(tries>4) {
doreadwrite=0;
break;
}
status=SSL_accept(ssl);
if(status==-1) {
int sslerr=SSL_get_error(ssl,status);
int saveerrno=errno;
fprintf(stderr,"\n%s: cannot SSL_accept(), status: %d, SSL error: %d, errno: %d",
procname, status, sslerr, saveerrno);
fflush(stderr);
switch(sslerr) {
case SSL_ERROR_WANT_READ:
fprintf(stderr,", sslerr: SSL_ERROR_WANT_READ, retrying");
continue;
case SSL_ERROR_WANT_WRITE:
fprintf(stderr,", sslerr: SSL_ERROR_WANT_WRITE, retrying");
continue;
case SSL_ERROR_SYSCALL:
fprintf(stderr,", sslerr: SSL_ERROR_SYSCALL(5), errno: %d, retrying\n",saveerrno);
ERR_print_errors_fp(stderr);
continue;
}
} else
break;
}
if(doreadwrite) {
peer_cert = SSL_get_peer_certificate(ssl);
if(peer_cert == NULL) {
fprintf(stdout,", No peer certificate");
fflush(stdout);
}
fprintf(stdout,"\n");
int clen = 0;
int reads = 0;
int first = 1;
htmlparams = NULL;
int bytes, totalbytes = 0;
while(htmlparams==NULL || clen-strlen(htmlparams) > 0) {
if(!first) {
fprintf(stdout,", ");
}
fprintf(stdout,"read %d", reads);
fflush(stdout);
if((bytes = SSL_read(ssl, htmlin+totalbytes, htmlinlen-totalbytes))<0) {
fprintf(stderr,"\n%s: cannot SSL_read()\n", procname);
perror("SSL_read");
fflush(stderr);
}
fprintf(stdout,"(%d bytes)", bytes);
if(bytes==0)
break;
*(htmlin+totalbytes+bytes) = '\0';
totalbytes+=bytes;
if(totalbytes >= htmlinlen) {
// plus space for '\0'
htmlin=realloc(htmlin, htmlinlen*2+1);
htmlinlen *= 2;
}
htmlparams = dbs_html_get_params();
unsigned char *p=htmlin;
dbs_html_parse_string(sizeof(htmlmethod), htmlmethod,&p);
if(!strcmp(htmlmethod,"GET"))
break;
dbs_html_get_request_line_num("Content-Length",
sizeof(buffer10), buffer10);
clen = atoi(buffer10);
reads++;
first = 0;
}
fprintf(stdout,"\n%d reads", reads);
fprintf(stdout,", received %d chars", totalbytes);
fprintf(stdout,", read %d total bytes", totalbytes);
fprintf(stdout,", input buffer size %d chars", htmlinlen);
fprintf(stdout,", data=\"%s\"\n", htmlin);
strncpy(htmlsslcipher, SSL_get_cipher(ssl), sizeof(htmlsslcipher));
dbs_run_loop();
for(int c=0;c<HTML_BUFFERS;c++) {
if(strlen(html_get_string(c))>0) {
if((status=SSL_write(ssl, html_get_string(c), strlen(html_get_string(c))))<1) {
fprintf(stderr,"\n%s: cannot SSL_write(), buffer %d, status: %d, SSL error: %d",
procname, c, status, SSL_get_error(ssl,status));
fflush(stderr);
}
}
}
}
fprintf(stdout,"\nSSL connection using %s", htmlsslcipher);
fflush(stderr);
SSL_free(ssl);
server_close(news);
fflush(stdout);
FORT_EVENTS_END(328)
} // for(;;)
SSL_CTX_free(ctx);
FORT_EVENTS_END(329)
}
Tässä rutiini merkkijonon tallettamiseen. Käytetään lähinnä ohjelman parametreissa.
static unsigned char *dbs_save_string(unsigned char *string)
{
unsigned char *temp = malloc(strlen(string)+1);
strcpy(temp, string);
return(temp);
}
Tällä lasketaan tiedoston eli tässä ajettavan ohjelman “sormenjälki”.
static void dbs_file_digest(char *filename,unsigned char *hash)
{
int c;
unsigned char buffer[1024];
FILE *fp1;
HashCtx ctx;
HashInit(&ctx);
if((fp1 = fopen(filename, "rb"))!=NULL) {
while((c=fread(buffer, 1, sizeof(buffer), fp1)) > 0)
HashUpdate(&ctx, buffer, c);
fclose(fp1);
}
HashFinal(hash, &ctx);
}
Ja varsin pääohjelma:
int dba_main(int argc,char *argv[]);
static void dbs_version()
{
fprintf(stdout,"%s, ", programname);
fprintf(stdout,"%s\n", copyright);
fflush(stdout);
}
int https=1;
int dbs_main(int argc,char *argv[])
{
int c;
for(c = 1; c < argc; c++) {
if(!strncmp(argv[c], "--https",7))
https = 1;
else if(!strncmp(argv[c], "--http",6))
https = 0;
else if(!strncmp(argv[c], "--port",6)) {
if(argv[c][6] != '\0')
myport = dbs_save_string(&argv[c][6]);
else
myport = dbs_save_string(argv[++c]);
} else if(!strncmp(argv[c], "-p",2)) {
if(argv[c][2] != '\0')
myport = dbs_save_string(&argv[c][2]);
else
myport = dbs_save_string(argv[++c]);
} else if(!strncmp(argv[c], "--version",9)) {
dbs_version();
} else if(!strncmp(argv[c], "-v",2)) {
dbs_version();
}
}
return(0);
}
int main(int argc,char *argv[])
{
unsigned char filedigest[HashLen],buffer10[10];
procname=argv[0];
dbs_file_digest("/proc/self/exe", filedigest);
htmldigest[0]='\0';
for(int c = 0;c < HashLen; c++) {
char twodigits[3];
sprintf(twodigits,"%02x", filedigest[c]);
strcat(htmldigest, twodigits);
}
fprintf(stdout,"%s", programname);
fflush(stdout);
if(https)
fprintf(stdout,", https");
else
fprintf(stdout,", http");
fprintf(stdout,", port %s", myport);
fprintf(stdout,", sha256(%s)\n", htmldigest);
fprintf(stdout,"%s\n\n", copyright);
fflush(stdout);
dbs_main(argc,argv);
dba_main(argc,argv);
FILE *fp1;
unsigned char filename[64];
callid = 0;
sprintf(filename,"%scallid.deb",filenamehead);
if((fp1 = fopen(filename,"r")) != NULL) {
fgets(buffer10, sizeof(buffer10), fp1);
callid = atoi(buffer10);
fclose(fp1);
}
sprintf(filename,"%spid.deb",filenamehead);
if((fp1 = fopen(filename,"w")) != NULL) {
fprintf(fp1,"%d\n", getpid());
fclose(fp1);
}
if(https)
https_server();
else
http_server();
exit(0);
}