Fossil SCM

Improved code to discover the IP address of the peer. Record the IP address of the peer in a Received: header line of all input emails.

drh 2018-07-13 18:20 trunk
Commit 9979edbdef54f547ffd2f41882691a4c60fa6df5a4fbbb9445aa6b150a73ef2f
2 files changed +21 -7 +23
+21 -7
--- src/cgi.c
+++ src/cgi.c
@@ -1377,10 +1377,29 @@
13771377
while( fossil_isspace(*zInput) ){ zInput++; }
13781378
}
13791379
if( zLeftOver ){ *zLeftOver = zInput; }
13801380
return zResult;
13811381
}
1382
+
1383
+/*
1384
+** Determine the IP address on the other side of a connection.
1385
+** Return a pointer to a string. Or return 0 if unable.
1386
+**
1387
+** The string is held in a static buffer that is overwritten on
1388
+** each call.
1389
+*/
1390
+char *cgi_remote_ip(int fd){
1391
+ static char zIp[100];
1392
+ struct sockaddr_in6 addr;
1393
+ socklen_t sz = sizeof(addr);
1394
+ if( getpeername(fd, &addr, &sz) ) return 0;
1395
+ zIp[0] = 0;
1396
+ if( inet_ntop(AF_INET6, &addr, zIp, sizeof(zIp))==0 ){
1397
+ return 0;
1398
+ }
1399
+ return zIp;
1400
+}
13821401
13831402
/*
13841403
** This routine handles a single HTTP request which is coming in on
13851404
** g.httpIn and which replies on g.httpOut
13861405
**
@@ -1391,12 +1410,10 @@
13911410
** and subsequent code handles the actual generation of the webpage.
13921411
*/
13931412
void cgi_handle_http_request(const char *zIpAddr){
13941413
char *z, *zToken;
13951414
int i;
1396
- struct sockaddr_in remoteName;
1397
- socklen_t size = sizeof(struct sockaddr_in);
13981415
char zLine[2000]; /* A single line of input. */
13991416
g.fullHttpReply = 1;
14001417
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
14011418
malformed_request("missing HTTP header");
14021419
}
@@ -1420,15 +1437,12 @@
14201437
cgi_setenv("SCRIPT_NAME", "");
14211438
for(i=0; zToken[i] && zToken[i]!='?'; i++){}
14221439
if( zToken[i] ) zToken[i++] = 0;
14231440
cgi_setenv("PATH_INFO", zToken);
14241441
cgi_setenv("QUERY_STRING", &zToken[i]);
1425
- if( zIpAddr==0 &&
1426
- getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName,
1427
- &size)>=0
1428
- ){
1429
- zIpAddr = inet_ntoa(remoteName.sin_addr);
1442
+ if( zIpAddr==0 ){
1443
+ zIpAddr = cgi_remote_ip(fileno(g.httpIn));
14301444
}
14311445
if( zIpAddr ){
14321446
cgi_setenv("REMOTE_ADDR", zIpAddr);
14331447
g.zIpAddr = mprintf("%s", zIpAddr);
14341448
}
14351449
--- src/cgi.c
+++ src/cgi.c
@@ -1377,10 +1377,29 @@
1377 while( fossil_isspace(*zInput) ){ zInput++; }
1378 }
1379 if( zLeftOver ){ *zLeftOver = zInput; }
1380 return zResult;
1381 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1382
1383 /*
1384 ** This routine handles a single HTTP request which is coming in on
1385 ** g.httpIn and which replies on g.httpOut
1386 **
@@ -1391,12 +1410,10 @@
1391 ** and subsequent code handles the actual generation of the webpage.
1392 */
1393 void cgi_handle_http_request(const char *zIpAddr){
1394 char *z, *zToken;
1395 int i;
1396 struct sockaddr_in remoteName;
1397 socklen_t size = sizeof(struct sockaddr_in);
1398 char zLine[2000]; /* A single line of input. */
1399 g.fullHttpReply = 1;
1400 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1401 malformed_request("missing HTTP header");
1402 }
@@ -1420,15 +1437,12 @@
1420 cgi_setenv("SCRIPT_NAME", "");
1421 for(i=0; zToken[i] && zToken[i]!='?'; i++){}
1422 if( zToken[i] ) zToken[i++] = 0;
1423 cgi_setenv("PATH_INFO", zToken);
1424 cgi_setenv("QUERY_STRING", &zToken[i]);
1425 if( zIpAddr==0 &&
1426 getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName,
1427 &size)>=0
1428 ){
1429 zIpAddr = inet_ntoa(remoteName.sin_addr);
1430 }
1431 if( zIpAddr ){
1432 cgi_setenv("REMOTE_ADDR", zIpAddr);
1433 g.zIpAddr = mprintf("%s", zIpAddr);
1434 }
1435
--- src/cgi.c
+++ src/cgi.c
@@ -1377,10 +1377,29 @@
1377 while( fossil_isspace(*zInput) ){ zInput++; }
1378 }
1379 if( zLeftOver ){ *zLeftOver = zInput; }
1380 return zResult;
1381 }
1382
1383 /*
1384 ** Determine the IP address on the other side of a connection.
1385 ** Return a pointer to a string. Or return 0 if unable.
1386 **
1387 ** The string is held in a static buffer that is overwritten on
1388 ** each call.
1389 */
1390 char *cgi_remote_ip(int fd){
1391 static char zIp[100];
1392 struct sockaddr_in6 addr;
1393 socklen_t sz = sizeof(addr);
1394 if( getpeername(fd, &addr, &sz) ) return 0;
1395 zIp[0] = 0;
1396 if( inet_ntop(AF_INET6, &addr, zIp, sizeof(zIp))==0 ){
1397 return 0;
1398 }
1399 return zIp;
1400 }
1401
1402 /*
1403 ** This routine handles a single HTTP request which is coming in on
1404 ** g.httpIn and which replies on g.httpOut
1405 **
@@ -1391,12 +1410,10 @@
1410 ** and subsequent code handles the actual generation of the webpage.
1411 */
1412 void cgi_handle_http_request(const char *zIpAddr){
1413 char *z, *zToken;
1414 int i;
 
 
1415 char zLine[2000]; /* A single line of input. */
1416 g.fullHttpReply = 1;
1417 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1418 malformed_request("missing HTTP header");
1419 }
@@ -1420,15 +1437,12 @@
1437 cgi_setenv("SCRIPT_NAME", "");
1438 for(i=0; zToken[i] && zToken[i]!='?'; i++){}
1439 if( zToken[i] ) zToken[i++] = 0;
1440 cgi_setenv("PATH_INFO", zToken);
1441 cgi_setenv("QUERY_STRING", &zToken[i]);
1442 if( zIpAddr==0 ){
1443 zIpAddr = cgi_remote_ip(fileno(g.httpIn));
 
 
 
1444 }
1445 if( zIpAddr ){
1446 cgi_setenv("REMOTE_ADDR", zIpAddr);
1447 g.zIpAddr = mprintf("%s", zIpAddr);
1448 }
1449
+23
--- src/smtp.c
+++ src/smtp.c
@@ -737,10 +737,11 @@
737737
** State information for the server
738738
*/
739739
struct SmtpServer {
740740
sqlite3_int64 idTranscript; /* Transcript ID number */
741741
sqlite3_int64 idMsg; /* Message ID number */
742
+ const char *zIpAddr; /* Remote IP address */
742743
char *zEhlo; /* Client domain on the EHLO line */
743744
char *zFrom; /* MAIL FROM: argument */
744745
int nTo; /* Number of RCPT TO: lines seen */
745746
struct SmtpTo {
746747
char *z; /* Address in each RCPT TO line */
@@ -855,10 +856,18 @@
855856
fprintf(stderr, "C: %s", aBuf);
856857
}
857858
}
858859
return rc;
859860
}
861
+
862
+/*
863
+** RFC-5321 requires certain content be prepended to an email header
864
+** as that email is received.
865
+*/
866
+static void smtp_server_prepend_header_lines(SmtpServer *p){
867
+ blob_appendf(&p->msg, "Received: from %s by Fossil-smtp\r\n", p->zIpAddr);
868
+}
860869
861870
/*
862871
** Capture the incoming email data into the p->msg blob. Dequote
863872
** lines of "..\r\n" into just ".\r\n".
864873
*/
@@ -1007,10 +1016,14 @@
10071016
**
10081017
** --dryrun Do not record any emails in the database
10091018
**
10101019
** --trace Print a transcript of the conversation on stderr
10111020
** for debugging and analysis
1021
+**
1022
+** --ipaddr ADDR The SMTP connection originates at ADDR. Or if ADDR
1023
+** is the name of an environment variable, the address
1024
+** is ready from that environment variable.
10121025
*/
10131026
void smtp_server(void){
10141027
char *zDbName;
10151028
const char *zDomain;
10161029
SmtpServer x;
@@ -1020,10 +1033,19 @@
10201033
zDomain = find_option("domain",0,1);
10211034
if( zDomain==0 ) zDomain = "";
10221035
x.srvrFlags = SMTPSRV_LOG;
10231036
if( find_option("trace",0,0)!=0 ) x.srvrFlags |= SMTPSRV_STDERR;
10241037
if( find_option("dryrun",0,0)!=0 ) x.srvrFlags |= SMTPSRV_DRYRUN;
1038
+ x.zIpAddr = find_option("ipaddr",0,1);
1039
+ if( x.zIpAddr ){
1040
+ const char *zNew = fossil_getenv(x.zIpAddr);
1041
+ if( zNew && zNew[0] ) x.zIpAddr = zNew;
1042
+ }
1043
+ if( x.zIpAddr==0 ){
1044
+ x.zIpAddr = cgi_remote_ip(0);
1045
+ if( x.zIpAddr==0 ) x.zIpAddr = "?.?.?.?";
1046
+ }
10251047
verify_all_options();
10261048
if( g.argc!=3 ) usage("DBNAME");
10271049
zDbName = g.argv[2];
10281050
zDbName = enter_chroot_jail(zDbName, 0);
10291051
db_open_repository(zDbName);
@@ -1069,10 +1091,11 @@
10691091
if( x.zFrom==0 || x.nTo==0 ){
10701092
smtp_server_send(&x, "500 missing RCPT TO\r\n");
10711093
continue;
10721094
}
10731095
smtp_server_send(&x, "354 ready\r\n");
1096
+ smtp_server_prepend_header_lines(&x);
10741097
smtp_server_capture_data(&x, z, sizeof(z));
10751098
smtp_server_send(&x, "250 ok\r\n");
10761099
}else
10771100
if( strncmp(z, "QUIT", 4)==0 && fossil_isspace(z[4]) ){
10781101
smtp_server_send(&x, "221 closing connection\r\n");
10791102
--- src/smtp.c
+++ src/smtp.c
@@ -737,10 +737,11 @@
737 ** State information for the server
738 */
739 struct SmtpServer {
740 sqlite3_int64 idTranscript; /* Transcript ID number */
741 sqlite3_int64 idMsg; /* Message ID number */
 
742 char *zEhlo; /* Client domain on the EHLO line */
743 char *zFrom; /* MAIL FROM: argument */
744 int nTo; /* Number of RCPT TO: lines seen */
745 struct SmtpTo {
746 char *z; /* Address in each RCPT TO line */
@@ -855,10 +856,18 @@
855 fprintf(stderr, "C: %s", aBuf);
856 }
857 }
858 return rc;
859 }
 
 
 
 
 
 
 
 
860
861 /*
862 ** Capture the incoming email data into the p->msg blob. Dequote
863 ** lines of "..\r\n" into just ".\r\n".
864 */
@@ -1007,10 +1016,14 @@
1007 **
1008 ** --dryrun Do not record any emails in the database
1009 **
1010 ** --trace Print a transcript of the conversation on stderr
1011 ** for debugging and analysis
 
 
 
 
1012 */
1013 void smtp_server(void){
1014 char *zDbName;
1015 const char *zDomain;
1016 SmtpServer x;
@@ -1020,10 +1033,19 @@
1020 zDomain = find_option("domain",0,1);
1021 if( zDomain==0 ) zDomain = "";
1022 x.srvrFlags = SMTPSRV_LOG;
1023 if( find_option("trace",0,0)!=0 ) x.srvrFlags |= SMTPSRV_STDERR;
1024 if( find_option("dryrun",0,0)!=0 ) x.srvrFlags |= SMTPSRV_DRYRUN;
 
 
 
 
 
 
 
 
 
1025 verify_all_options();
1026 if( g.argc!=3 ) usage("DBNAME");
1027 zDbName = g.argv[2];
1028 zDbName = enter_chroot_jail(zDbName, 0);
1029 db_open_repository(zDbName);
@@ -1069,10 +1091,11 @@
1069 if( x.zFrom==0 || x.nTo==0 ){
1070 smtp_server_send(&x, "500 missing RCPT TO\r\n");
1071 continue;
1072 }
1073 smtp_server_send(&x, "354 ready\r\n");
 
1074 smtp_server_capture_data(&x, z, sizeof(z));
1075 smtp_server_send(&x, "250 ok\r\n");
1076 }else
1077 if( strncmp(z, "QUIT", 4)==0 && fossil_isspace(z[4]) ){
1078 smtp_server_send(&x, "221 closing connection\r\n");
1079
--- src/smtp.c
+++ src/smtp.c
@@ -737,10 +737,11 @@
737 ** State information for the server
738 */
739 struct SmtpServer {
740 sqlite3_int64 idTranscript; /* Transcript ID number */
741 sqlite3_int64 idMsg; /* Message ID number */
742 const char *zIpAddr; /* Remote IP address */
743 char *zEhlo; /* Client domain on the EHLO line */
744 char *zFrom; /* MAIL FROM: argument */
745 int nTo; /* Number of RCPT TO: lines seen */
746 struct SmtpTo {
747 char *z; /* Address in each RCPT TO line */
@@ -855,10 +856,18 @@
856 fprintf(stderr, "C: %s", aBuf);
857 }
858 }
859 return rc;
860 }
861
862 /*
863 ** RFC-5321 requires certain content be prepended to an email header
864 ** as that email is received.
865 */
866 static void smtp_server_prepend_header_lines(SmtpServer *p){
867 blob_appendf(&p->msg, "Received: from %s by Fossil-smtp\r\n", p->zIpAddr);
868 }
869
870 /*
871 ** Capture the incoming email data into the p->msg blob. Dequote
872 ** lines of "..\r\n" into just ".\r\n".
873 */
@@ -1007,10 +1016,14 @@
1016 **
1017 ** --dryrun Do not record any emails in the database
1018 **
1019 ** --trace Print a transcript of the conversation on stderr
1020 ** for debugging and analysis
1021 **
1022 ** --ipaddr ADDR The SMTP connection originates at ADDR. Or if ADDR
1023 ** is the name of an environment variable, the address
1024 ** is ready from that environment variable.
1025 */
1026 void smtp_server(void){
1027 char *zDbName;
1028 const char *zDomain;
1029 SmtpServer x;
@@ -1020,10 +1033,19 @@
1033 zDomain = find_option("domain",0,1);
1034 if( zDomain==0 ) zDomain = "";
1035 x.srvrFlags = SMTPSRV_LOG;
1036 if( find_option("trace",0,0)!=0 ) x.srvrFlags |= SMTPSRV_STDERR;
1037 if( find_option("dryrun",0,0)!=0 ) x.srvrFlags |= SMTPSRV_DRYRUN;
1038 x.zIpAddr = find_option("ipaddr",0,1);
1039 if( x.zIpAddr ){
1040 const char *zNew = fossil_getenv(x.zIpAddr);
1041 if( zNew && zNew[0] ) x.zIpAddr = zNew;
1042 }
1043 if( x.zIpAddr==0 ){
1044 x.zIpAddr = cgi_remote_ip(0);
1045 if( x.zIpAddr==0 ) x.zIpAddr = "?.?.?.?";
1046 }
1047 verify_all_options();
1048 if( g.argc!=3 ) usage("DBNAME");
1049 zDbName = g.argv[2];
1050 zDbName = enter_chroot_jail(zDbName, 0);
1051 db_open_repository(zDbName);
@@ -1069,10 +1091,11 @@
1091 if( x.zFrom==0 || x.nTo==0 ){
1092 smtp_server_send(&x, "500 missing RCPT TO\r\n");
1093 continue;
1094 }
1095 smtp_server_send(&x, "354 ready\r\n");
1096 smtp_server_prepend_header_lines(&x);
1097 smtp_server_capture_data(&x, z, sizeof(z));
1098 smtp_server_send(&x, "250 ok\r\n");
1099 }else
1100 if( strncmp(z, "QUIT", 4)==0 && fossil_isspace(z[4]) ){
1101 smtp_server_send(&x, "221 closing connection\r\n");
1102

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button