| | @@ -34,10 +34,11 @@ |
| 34 | 34 | # include <arpa/inet.h> |
| 35 | 35 | # include <sys/times.h> |
| 36 | 36 | # include <sys/time.h> |
| 37 | 37 | # include <sys/wait.h> |
| 38 | 38 | # include <sys/select.h> |
| 39 | +# include <netdb.h> /* for NI_NUMERICHOST */ |
| 39 | 40 | #endif |
| 40 | 41 | #ifdef __EMX__ |
| 41 | 42 | typedef int socklen_t; |
| 42 | 43 | #endif |
| 43 | 44 | #include <time.h> |
| | @@ -992,12 +993,12 @@ |
| 992 | 993 | ** and subsequent code handles the actual generation of the webpage. |
| 993 | 994 | */ |
| 994 | 995 | void cgi_handle_http_request(const char *zIpAddr){ |
| 995 | 996 | char *z, *zToken; |
| 996 | 997 | int i; |
| 997 | | - struct sockaddr_in remoteName; |
| 998 | | - socklen_t size = sizeof(struct sockaddr_in); |
| 998 | + struct sockaddr_storage remoteName; |
| 999 | + socklen_t size = sizeof(remoteName); |
| 999 | 1000 | char zLine[2000]; /* A single line of input. */ |
| 1000 | 1001 | |
| 1001 | 1002 | g.fullHttpReply = 1; |
| 1002 | 1003 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 1003 | 1004 | malformed_request(); |
| | @@ -1019,20 +1020,10 @@ |
| 1019 | 1020 | cgi_setenv("REQUEST_URI", zToken); |
| 1020 | 1021 | for(i=0; zToken[i] && zToken[i]!='?'; i++){} |
| 1021 | 1022 | if( zToken[i] ) zToken[i++] = 0; |
| 1022 | 1023 | cgi_setenv("PATH_INFO", zToken); |
| 1023 | 1024 | cgi_setenv("QUERY_STRING", &zToken[i]); |
| 1024 | | - if( zIpAddr==0 && |
| 1025 | | - getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName, |
| 1026 | | - &size)>=0 |
| 1027 | | - ){ |
| 1028 | | - zIpAddr = inet_ntoa(remoteName.sin_addr); |
| 1029 | | - } |
| 1030 | | - if( zIpAddr ){ |
| 1031 | | - cgi_setenv("REMOTE_ADDR", zIpAddr); |
| 1032 | | - g.zIpAddr = mprintf("%s", zIpAddr); |
| 1033 | | - } |
| 1034 | 1025 | |
| 1035 | 1026 | /* Get all the optional fields that follow the first line. |
| 1036 | 1027 | */ |
| 1037 | 1028 | while( fgets(zLine,sizeof(zLine),g.httpIn) ){ |
| 1038 | 1029 | char *zFieldName; |
| | @@ -1059,19 +1050,54 @@ |
| 1059 | 1050 | cgi_setenv("HTTP_HOST", zVal); |
| 1060 | 1051 | }else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){ |
| 1061 | 1052 | cgi_setenv("HTTP_IF_NONE_MATCH", zVal); |
| 1062 | 1053 | }else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){ |
| 1063 | 1054 | cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); |
| 1055 | + }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){ |
| 1056 | + char* p = zVal; |
| 1057 | + /* |
| 1058 | + ** x-forwarded-for header is a list of comma-separated addresses, |
| 1059 | + ** with leftmost address corresponding to the client |
| 1060 | + */ |
| 1061 | + while(*p && *p != ',') p++; |
| 1062 | + *p = '\0'; |
| 1063 | + zIpAddr = mprintf( "%s", zVal ); |
| 1064 | 1064 | } |
| 1065 | 1065 | #if 0 |
| 1066 | 1066 | else if( fossil_strcmp(zFieldName,"referer:")==0 ){ |
| 1067 | 1067 | cgi_setenv("HTTP_REFERER", zVal); |
| 1068 | 1068 | }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ |
| 1069 | 1069 | cgi_setenv("HTTP_USER_AGENT", zVal); |
| 1070 | 1070 | } |
| 1071 | 1071 | #endif |
| 1072 | 1072 | } |
| 1073 | + |
| 1074 | + if( zIpAddr==0 && |
| 1075 | + getsockname(fileno(g.httpIn), (struct sockaddr*)&remoteName, |
| 1076 | + &size)>=0 |
| 1077 | + ){ |
| 1078 | + sa_family_t family; |
| 1079 | + int v4mapped=0; |
| 1080 | + if( remoteName.ss_family == AF_INET6 && |
| 1081 | + IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6*)&remoteName)->sin6_addr)) ){ |
| 1082 | + v4mapped = 1; |
| 1083 | + } |
| 1084 | + if(!getnameinfo((struct sockaddr*)&remoteName, remoteName.ss_len, zLine, sizeof(zLine), |
| 1085 | + NULL, 0, NI_NUMERICHOST)){ |
| 1086 | + zIpAddr = zLine; |
| 1087 | + } else { |
| 1088 | + zIpAddr = NULL; |
| 1089 | + } |
| 1090 | + if(zIpAddr && v4mapped) { |
| 1091 | + /* ::ffff:172.16.0.2 */ |
| 1092 | + zIpAddr += 7; |
| 1093 | + } |
| 1094 | + } |
| 1095 | + if( zIpAddr ){ |
| 1096 | + cgi_setenv("REMOTE_ADDR", zIpAddr); |
| 1097 | + g.zIpAddr = mprintf("%s", zIpAddr); |
| 1098 | + } |
| 1073 | 1099 | |
| 1074 | 1100 | cgi_init(); |
| 1075 | 1101 | } |
| 1076 | 1102 | |
| 1077 | 1103 | #if INTERFACE |
| | @@ -1108,31 +1134,57 @@ |
| 1108 | 1134 | fd_set readfds; /* Set of file descriptors for select() */ |
| 1109 | 1135 | socklen_t lenaddr; /* Length of the inaddr structure */ |
| 1110 | 1136 | int child; /* PID of the child process */ |
| 1111 | 1137 | int nchildren = 0; /* Number of child processes */ |
| 1112 | 1138 | struct timeval delay; /* How long to wait inside select() */ |
| 1139 | +#ifdef WITH_IPV6 |
| 1140 | + struct sockaddr_in6 inaddr; /* The socket address */ |
| 1141 | +#else |
| 1113 | 1142 | struct sockaddr_in inaddr; /* The socket address */ |
| 1143 | +#endif |
| 1114 | 1144 | int opt = 1; /* setsockopt flag */ |
| 1115 | 1145 | int iPort = mnPort; |
| 1116 | 1146 | |
| 1117 | 1147 | while( iPort<=mxPort ){ |
| 1118 | 1148 | memset(&inaddr, 0, sizeof(inaddr)); |
| 1149 | +#ifdef WITH_IPV6 |
| 1150 | + inaddr.sin6_family = AF_INET6; |
| 1151 | +#else |
| 1119 | 1152 | inaddr.sin_family = AF_INET; |
| 1153 | +#endif |
| 1120 | 1154 | if( flags & HTTP_SERVER_LOCALHOST ){ |
| 1155 | +#ifdef WITH_IPV6 |
| 1156 | + memcpy(&inaddr.sin6_addr, &in6addr_loopback, sizeof(inaddr.sin6_addr)); |
| 1157 | +#else |
| 1121 | 1158 | inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| 1159 | +#endif |
| 1122 | 1160 | }else{ |
| 1161 | +#ifdef WITH_IPV6 |
| 1162 | + memcpy(&inaddr.sin6_addr, &in6addr_any, sizeof(inaddr.sin6_addr)); |
| 1163 | +#else |
| 1123 | 1164 | inaddr.sin_addr.s_addr = htonl(INADDR_ANY); |
| 1165 | +#endif |
| 1124 | 1166 | } |
| 1167 | +#ifdef WITH_IPV6 |
| 1168 | + inaddr.sin6_port = htons(iPort); |
| 1169 | + listener = socket(AF_INET6, SOCK_STREAM, 0); |
| 1170 | +#else |
| 1125 | 1171 | inaddr.sin_port = htons(iPort); |
| 1126 | 1172 | listener = socket(AF_INET, SOCK_STREAM, 0); |
| 1173 | +#endif |
| 1127 | 1174 | if( listener<0 ){ |
| 1128 | 1175 | iPort++; |
| 1129 | 1176 | continue; |
| 1130 | 1177 | } |
| 1131 | 1178 | |
| 1132 | 1179 | /* if we can't terminate nicely, at least allow the socket to be reused */ |
| 1133 | 1180 | setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); |
| 1181 | + |
| 1182 | +#ifdef WITH_IPV6 |
| 1183 | + opt=0; |
| 1184 | + setsockopt(listener, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)); |
| 1185 | +#endif |
| 1134 | 1186 | |
| 1135 | 1187 | if( bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr))<0 ){ |
| 1136 | 1188 | close(listener); |
| 1137 | 1189 | iPort++; |
| 1138 | 1190 | continue; |
| 1139 | 1191 | |