xref: /freebsd/sbin/ipf/libipf/load_http.c (revision 02e9120893770924227138ba49df1edb3896112a)
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 *
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