|
|
bitreich-httpd.c - bitreich-httpd - Bitreich HTTPD service |
|
|
 |
git clone git://bitreich.org/bitreich-httpd git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/bitreich-httpd (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
 |
LICENSE |
|
|
|
--- |
|
|
|
bitreich-httpd.c (6666B) |
|
|
|
--- |
|
|
|
1 /* |
|
|
|
2 * Copy me if you can. |
|
|
|
3 * by 20h |
|
|
|
4 */ |
|
|
|
5 |
|
|
|
6 #include <unistd.h> |
|
|
|
7 #include <stdio.h> |
|
|
|
8 #include <stdlib.h> |
|
|
|
9 #include <time.h> |
|
|
|
10 #include <sys/types.h> |
|
|
|
11 #include <sys/stat.h> |
|
|
|
12 #include <fcntl.h> |
|
|
|
13 #include <string.h> |
|
|
|
14 #include <strings.h> |
|
|
|
15 #include <sys/socket.h> |
|
|
|
16 #include <sys/wait.h> |
|
|
|
17 #include <netdb.h> |
|
|
|
18 #include <time.h> |
|
|
|
19 |
|
|
|
20 void * |
|
|
|
21 xmalloc(size_t size) |
|
|
|
22 { |
|
|
|
23 void *p; |
|
|
|
24 |
|
|
|
25 if (!(p = malloc(size))) { |
|
|
|
26 perror("malloc"); |
|
|
|
27 exit(1); |
|
|
|
28 } |
|
|
|
29 |
|
|
|
30 return p; |
|
|
|
31 } |
|
|
|
32 |
|
|
|
33 void |
|
|
|
34 print404(void) |
|
|
|
35 { |
|
|
|
36 printf("HTTP/1.1 404 Google Broke The Web\r\n"); |
|
|
|
37 printf("\r\n"); |
|
|
|
38 } |
|
|
|
39 |
|
|
|
40 void |
|
|
|
41 printheaders(char *ctype) |
|
|
|
42 { |
|
|
|
43 time_t t; |
|
|
|
44 |
|
|
|
45 t = time(NULL); |
|
|
|
46 if (t > 0) |
|
|
|
47 printf("Date: %s", asctime(gmtime(&t))); |
|
|
|
48 printf("X-Future: Gopher ftw!\r\n"); |
|
|
|
49 printf("Content-Type: %s\r\n", ctype); |
|
|
|
50 printf("X-Irritate: Be irritated.\r\n"); |
|
|
|
51 printf("X-Use-Gopher: gopher://bitreich.org\r\n"); |
|
|
|
52 printf("If-By-Whiskey: Terrorist\r\n"); |
|
|
|
53 printf("Permission-Policy: interest-cohort=()\r\n"); |
|
|
|
54 printf("Fuck-Off: Google\r\n"); |
|
|
|
55 printf("Server: bitreich-httpd/2.0\r\n"); |
|
|
|
56 printf("X-Alarm: <script>window.alert(\"Turn off Javascript, it hurts me.\");</script>\r\n"); |
|
|
|
57 printf("X-Goat-0: (_(\r\n"); |
|
|
|
58 printf("X-Goat-1: /_/'_____/)\r\n"); |
|
|
|
59 printf("X-Goat-2: \" | |\r\n"); |
|
|
|
60 printf("X-Goat-3: |\"\"\"\"\"\"| \r\n"); |
|
|
|
61 printf("Host: bitreich.org\r\n"); |
|
|
|
62 printf("Connection: close\r\n"); |
|
|
|
63 } |
|
|
|
64 |
|
|
|
65 int |
|
|
|
66 servefile(char *path, char *ctype, int sock) |
|
|
|
67 { |
|
|
|
68 struct stat st; |
|
|
|
69 char *sendb, *sendi; |
|
|
|
70 size_t bufsiz = BUFSIZ; |
|
|
|
71 int len, sent, fd; |
|
|
|
72 |
|
|
|
73 fd = open(path, O_RDONLY); |
|
|
|
74 if (fd < 0) { |
|
|
|
75 print404(); |
|
|
|
76 return 1; |
|
|
|
77 } |
|
|
|
78 |
|
|
|
79 printf("HTTP/1.1 200 OK\r\n"); |
|
|
|
80 printheaders(ctype); |
|
|
|
81 |
|
|
|
82 if (fstat(fd, &st) >= 0) |
|
|
|
83 if ((bufsiz = st.st_blksize) < BUFSIZ) |
|
|
|
84 bufsiz = BUFSIZ; |
|
|
|
85 |
|
|
|
86 printf("Content-Length: %ld\r\n", st.st_size); |
|
|
|
87 printf("\r\n"); |
|
|
|
88 fflush(stdout); |
|
|
|
89 |
|
|
|
90 sendb = xmalloc(bufsiz); |
|
|
|
91 while ((len = read(fd, sendb, bufsiz)) > 0) { |
|
|
|
92 sendi = sendb; |
|
|
|
93 while (len > 0) { |
|
|
|
94 if ((sent = write(sock, sendi, len)) < 0) { |
|
|
|
95 free(sendb); |
|
|
|
96 return 1; |
|
|
|
97 } |
|
|
|
98 len -= sent; |
|
|
|
99 sendi += sent; |
|
|
|
100 } |
|
|
|
101 } |
|
|
|
102 free(sendb); |
|
|
|
103 |
|
|
|
104 return 0; |
|
|
|
105 } |
|
|
|
106 |
|
|
|
107 char * |
|
|
|
108 read_line(int fd, int *len, int maxread) |
|
|
|
109 { |
|
|
|
110 char *buf; |
|
|
|
111 int r, rbytes; |
|
|
|
112 |
|
|
|
113 buf = xmalloc(maxread+1); |
|
|
|
114 memset(buf, 0, maxread+1); |
|
|
|
115 |
|
|
|
116 rbytes = 0; |
|
|
|
117 while (rbytes < maxread) { |
|
|
|
118 r = read(fd, &buf[rbytes], 1); |
|
|
|
119 if (r < 0) { |
|
|
|
120 free(buf); |
|
|
|
121 return NULL; |
|
|
|
122 } |
|
|
|
123 if (r == 0) |
|
|
|
124 break; |
|
|
|
125 if (buf[rbytes] == '\n') { |
|
|
|
126 buf[rbytes] = '\0'; |
|
|
|
127 break; |
|
|
|
128 } |
|
|
|
129 rbytes += r; |
|
|
|
130 } |
|
|
|
131 |
|
|
|
132 *len = rbytes; |
|
|
|
133 return buf; |
|
|
|
134 } |
|
|
|
135 |
|
|
|
136 int |
|
|
|
137 main(int argc, char *argv[]) |
|
|
|
138 { |
|
|
|
139 char *wwwbase, *wwwindex, *request, *ctype, *path, *le_file, |
|
|
|
140 *le_base, clienth[NI_MAXHOST], clientp[NI_MAXSERV], *zuccbase, |
|
|
|
141 *requested, *header, *headerval, *hosthdr; |
|
|
|
142 int rlen, i, user_agent_script_pid; |
|
|
|
143 struct sockaddr_storage clt; |
|
|
|
144 socklen_t cltlen = sizeof(clt); |
|
|
|
145 time_t tim; |
|
|
|
146 |
|
|
|
147 hosthdr = NULL; |
|
|
|
148 user_agent_script_pid = -1; |
|
|
|
149 |
|
|
|
150 wwwbase = "/bitreich/www"; |
|
|
|
151 wwwindex = "index.html"; |
|
|
|
152 |
|
|
|
153 le_base = "/br/www/uacme"; |
|
|
|
154 zuccbase = "/br/www/zuccless"; |
|
|
|
155 |
|
|
|
156 if (!getpeername(0, (struct sockaddr *)&clt, &cltlen)) { |
|
|
|
157 if (getnameinfo((struct sockaddr *)&clt, cltlen, clienth, |
|
|
|
158 sizeof(clienth), clientp, sizeof(clientp), |
|
|
|
159 NI_NUMERICHOST|NI_NUMERICSERV)) { |
|
|
|
160 clienth[0] = clientp[0] = '\0'; |
|
|
|
161 } |
|
|
|
162 if (!strncmp(clienth, "::ffff:", 7)) |
|
|
|
163 memmove(clienth, clienth+7, strlen(clienth)-6); |
|
|
|
164 } else { |
|
|
|
165 clienth[0] = clientp[0] = '\0'; |
|
|
|
166 } |
|
|
|
167 |
|
|
|
168 request = read_line(0, &rlen, 512); |
|
|
|
169 if (request == NULL) |
|
|
|
170 return 1; |
|
|
|
171 if (request[rlen-1] == '\r') |
|
|
|
172 request[rlen-1] = '\0'; |
|
|
|
173 |
|
|
|
174 /* Header parsing. */ |
|
|
|
175 /* At max read 16 headers. Do not allow DDoS. */ |
|
|
|
176 for (i = 0; i < 16; i++) { |
|
|
|
177 header = read_line(0, &rlen, 512); |
|
|
|
178 if (header == NULL || rlen == 0) |
|
|
|
179 break; |
|
|
|
180 if (header[rlen-1] == '\r') { |
|
|
|
181 header[rlen-1] = '\0'; |
|
|
|
182 if (rlen == 1) { |
|
|
|
183 free(header); |
|
|
|
184 break; |
|
|
|
185 } |
|
|
|
186 } |
|
|
|
187 headerval = strchr(header, ':'); |
|
|
|
188 if (headerval == NULL) { |
|
|
|
189 free(header); |
|
|
|
190 continue; |
|
|
|
191 } |
|
|
|
192 *headerval = '\0'; |
|
|
|
193 headerval += 2; |
|
|
|
194 if (headerval > (header + rlen)) { |
|
|
|
195 free(header); |
|
|
|
196 continue; |
|
|
|
197 } |
|
|
|
198 if (!strcasecmp(header, "user-agent")) { |
|
|
|
199 user_agent_script_pid = fork(); |
|
|
|
200 switch (user_agent_script_pid) { |
|
|
|
201 case -1: |
|
|
|
202 perror("fork"); |
|
|
|
203 return 1; |
|
|
|
204 case 0: |
|
|
|
205 return execl("add-user-agent.sh", |
|
|
|
206 "/home/annna/bin/modules/http-user-agent/add-user-agent.sh", |
|
|
|
207 headerval, 0); |
|
|
|
208 } |
|
|
|
209 } |
|
|
|
210 if (!strcasecmp(header, "host")) { |
|
|
|
211 rlen = strlen(headerval); |
|
|
|
212 hosthdr = xmalloc(rlen+1); |
|
|
|
213 memset(hosthdr, 0, rlen+1); |
|
|
|
214 strncpy(hosthdr, headerval, rlen); |
|
|
|
215 } |
|
|
|
216 free(header); |
|
|
|
217 } |
|
|
|
218 |
|
|
|
219 if (strncmp(request, "GET ", 4)) |
|
|
|
220 return 1; |
|
|
|
221 |
|
|
|
222 if (strstr(request, "s/bitreich.sh")) { |
|
|
|
223 asprintf(&path, "%s/s/bitreich.sh", wwwbase); |
|
|
|
224 ctype = "text/plain"; |
|
|
|
225 } else if (strstr(request, "favicon.gif")) { |
|
|
|
226 asprintf(&path, "%s/s/favicon.gif", wwwbase); |
|
|
|
227 ctype = "image/gif"; |
|
|
|
228 } else if (strstr(request, "deep-thinker.gif")) { |
|
|
|
229 asprintf(&path, "%s/s/deep-thinker.gif", wwwbase); |
|
|
|
230 ctype = "image/gif"; |
|
|
|
231 } else if (strstr(request, "startup.mp3")) { |
|
|
|
232 asprintf(&path, "%s/s/startup.mp3", wwwbase); |
|
|
|
233 ctype = "audio/mpeg"; |
|
|
|
234 } else if (strstr(request, "padme-hum.mp3")) { |
|
|
|
235 asprintf(&path, "%s/s/padme-hum.mp3", wwwbase); |
|
|
|
236 ctype = "audio/mpeg"; |
|
|
|
237 } else if (strstr(request, "dickbutt")) { |
|
|
|
238 asprintf(&path, |
|
|
|
239 "/home/annna/bin/locate-cake-hater \"%s\" \"%s\"", |
|
|
|
240 clienth, clientp); |
|
|
|
241 system(path); |
|
|
|
242 free(path); |
|
|
|
243 asprintf(&path, "%s/s/dickbutt.jpg", wwwbase); |
|
|
|
244 ctype = "image/jpeg"; |
|
|
|
245 } else if (strstr(request, "bitreich.css")) { |
|
|
|
246 asprintf(&path, "%s/s/bitreich.css", wwwbase); |
|
|
|
247 ctype = "text/css"; |
|
|
|
248 } else if (strstr(request, "yolo-css-")) { |
|
|
|
249 /* We hate CSS in here. */ |
|
|
|
250 sleep(1); |
|
|
|
251 asprintf(&path, "%s/s/yolo-css.css", wwwbase); |
|
|
|
252 ctype = "text/css"; |
|
|
|
253 } else if ((le_file = strstr(request, ".well-known/acme-challenge/"))) { |
|
|
|
254 /* Setup for Letsencrypt */ |
|
|
|
255 le_file += strlen(".well-known/acme-challenge/"); |
|
|
|
256 requested = strtok(le_file, " "); |
|
|
|
257 if (strchr(requested, '/') != NULL) { |
|
|
|
258 /* Get Zucced, no path exploitation. */ |
|
|
|
259 asprintf(&path, "%s/zucc-job.webm", zuccbase); |
|
|
|
260 ctype = "video/webm"; |
|
|
|
261 } else { |
|
|
|
262 /* Seems legit. */ |
|
|
|
263 asprintf(&path, "%s/%s", le_base, requested); |
|
|
|
264 ctype = "text/plain"; |
|
|
|
265 } |
|
|
|
266 } else { |
|
|
|
267 if (strstr(hosthdr, "zuccless.org")) { |
|
|
|
268 tim = time(NULL); |
|
|
|
269 srandom(tim); |
|
|
|
270 wwwbase = zuccbase; |
|
|
|
271 switch (random() % 3) { |
|
|
|
272 case 0: |
|
|
|
273 asprintf(&path, "%s/zucc-job.webm", zuccbase); |
|
|
|
274 break; |
|
|
|
275 default: |
|
|
|
276 asprintf(&path, "%s/zucc-meat.webm", zuccbase); |
|
|
|
277 break; |
|
|
|
278 } |
|
|
|
279 ctype = "video/webm"; |
|
|
|
280 } else { |
|
|
|
281 asprintf(&path, "%s/%s", wwwbase, wwwindex); |
|
|
|
282 ctype = "text/html"; |
|
|
|
283 } |
|
|
|
284 } |
|
|
|
285 if (hosthdr != NULL) |
|
|
|
286 free(hosthdr); |
|
|
|
287 free(request); |
|
|
|
288 |
|
|
|
289 rlen = servefile(path, ctype, 1); |
|
|
|
290 free(path); |
|
|
|
291 |
|
|
|
292 if (user_agent_script_pid != -1) { |
|
|
|
293 if (waitpid(user_agent_script_pid, NULL, 0) < 0) { |
|
|
|
294 perror("waitpid"); |
|
|
|
295 return 1; |
|
|
|
296 } |
|
|
|
297 } |
|
|
|
298 |
|
|
|
299 return rlen; |
|
|
|
300 } |
|
|
|
301 |
|