1 /* $FreeBSD$ */
2
3 /*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 *
8 * $Id: load_http.c,v 1.5.2.5 2012/07/22 08:04:24 darren_r Exp $
9 */
10
11 #include "ipf.h"
12 #include <ctype.h>
13
14 /*
15 * Because the URL can be included twice into the buffer, once as the
16 * full path for the "GET" and once as the "Host:", the buffer it is
17 * put in needs to be larger than 512*2 to make room for the supporting
18 * text. Why not just use snprintf and truncate? The warning about the
19 * URL being too long tells you something is wrong and does not fetch
20 * any data - just truncating the URL (with snprintf, etc) and sending
21 * that to the server is allowing an unknown and unintentioned action
22 * to happen.
23 */
24 #define MAX_URL_LEN 512
25 #define LOAD_BUFSIZE (MAX_URL_LEN * 2 + 128)
26
27 /*
28 * Format expected is one addres per line, at the start of each line.
29 */
30 alist_t *
load_http(char * url)31 load_http(char *url)
32 {
33 int fd, len, left, port, endhdr, removed, linenum = 0;
34 char *s, *t, *u, buffer[LOAD_BUFSIZE], *myurl;
35 alist_t *a, *rtop, *rbot;
36 size_t avail;
37 int error;
38
39 /*
40 * More than this would just be absurd.
41 */
42 if (strlen(url) > MAX_URL_LEN) {
43 fprintf(stderr, "load_http has a URL > %d bytes?!\n",
44 MAX_URL_LEN);
45 return (NULL);
46 }
47
48 fd = -1;
49 rtop = NULL;
50 rbot = NULL;
51
52 avail = sizeof(buffer);
53 error = snprintf(buffer, avail, "GET %s HTTP/1.0\r\n", url);
54
55 /*
56 * error is always less then avail due to the constraint on
57 * the url length above.
58 */
59 avail -= error;
60
61 myurl = strdup(url);
62 if (myurl == NULL)
63 goto done;
64
65 s = myurl + 7; /* http:// */
66 t = strchr(s, '/');
67 if (t == NULL) {
68 fprintf(stderr, "load_http has a malformed URL '%s'\n", url);
69 free(myurl);
70 return (NULL);
71 }
72 *t++ = '\0';
73
74 /*
75 * 10 is the length of 'Host: \r\n\r\n' below.
76 */
77 if (strlen(s) + strlen(buffer) + 10 > sizeof(buffer)) {
78 fprintf(stderr, "load_http has a malformed URL '%s'\n", url);
79 free(myurl);
80 return (NULL);
81 }
82
83 u = strchr(s, '@');
84 if (u != NULL)
85 s = u + 1; /* AUTH */
86
87 error = snprintf(buffer + strlen(buffer), avail, "Host: %s\r\n\r\n", s);
88 if (error >= avail) {
89 fprintf(stderr, "URL is too large: %s\n", url);
90 goto done;
91 }
92
93 u = strchr(s, ':');
94 if (u != NULL) {
95 *u++ = '\0';
96 port = atoi(u);
97 if (port < 0 || port > 65535)
98 goto done;
99 } else {
100 port = 80;
101 }
102
103
104 fd = connecttcp(s, port);
105 if (fd == -1)
106 goto done;
107
108
109 len = strlen(buffer);
110 if (write(fd, buffer, len) != len)
111 goto done;
112
113 s = buffer;
114 endhdr = 0;
115 left = sizeof(buffer) - 1;
116
117 while ((len = read(fd, s, left)) > 0) {
118 s[len] = '\0';
119 left -= len;
120 s += len;
121
122 if (endhdr >= 0) {
123 if (endhdr == 0) {
124 t = strchr(buffer, ' ');
125 if (t == NULL)
126 continue;
127 t++;
128 if (*t != '2')
129 break;
130 }
131
132 u = buffer;
133 while ((t = strchr(u, '\r')) != NULL) {
134 if (t == u) {
135 if (*(t + 1) == '\n') {
136 u = t + 2;
137 endhdr = -1;
138 break;
139 } else
140 t++;
141 } else if (*(t + 1) == '\n') {
142 endhdr++;
143 u = t + 2;
144 } else
145 u = t + 1;
146 }
147 if (endhdr >= 0)
148 continue;
149 removed = (u - buffer) + 1;
150 memmove(buffer, u, (sizeof(buffer) - left) - removed);
151 s -= removed;
152 left += removed;
153 }
154
155 do {
156 t = strchr(buffer, '\n');
157 if (t == NULL)
158 break;
159
160 linenum++;
161 *t = '\0';
162
163 /*
164 * Remove comment and continue to the next line if
165 * the comment is at the start of the line.
166 */
167 u = strchr(buffer, '#');
168 if (u != NULL) {
169 *u = '\0';
170 if (u == buffer)
171 continue;
172 }
173
174 /*
175 * Trim off tailing white spaces, will include \r
176 */
177 for (u = t - 1; (u >= buffer) && ISSPACE(*u); u--)
178 *u = '\0';
179
180 a = alist_new(AF_UNSPEC, buffer);
181 if (a != NULL) {
182 if (rbot != NULL)
183 rbot->al_next = a;
184 else
185 rtop = a;
186 rbot = a;
187 } else {
188 fprintf(stderr,
189 "%s:%d unrecognised content:%s\n",
190 url, linenum, buffer);
191 }
192
193 t++;
194 removed = t - buffer;
195 memmove(buffer, t, sizeof(buffer) - left - removed);
196 s -= removed;
197 left += removed;
198
199 } while (1);
200 }
201
202 done:
203 if (myurl != NULL)
204 free(myurl);
205 if (fd != -1)
206 close(fd);
207 return (rtop);
208 }
209