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 * 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