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