1 1.3 darrenr /* $NetBSD: load_http.c,v 1.3 2012/07/22 14:27:36 darrenr Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.3 darrenr * Copyright (C) 2012 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.3 darrenr * Id: load_http.c,v 1.1.1.2 2012/07/22 13:44:39 darrenr 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