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