1255332Scy/* $FreeBSD$ */ 2255332Scy 3170263Sdarrenr/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 5170263Sdarrenr * 6170263Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7170263Sdarrenr * 8255332Scy * $Id: load_http.c,v 1.5.2.5 2012/07/22 08:04:24 darren_r Exp $ 9170263Sdarrenr */ 10170263Sdarrenr 11170263Sdarrenr#include "ipf.h" 12255332Scy#include <ctype.h> 13170263Sdarrenr 14170263Sdarrenr/* 15255332Scy * Because the URL can be included twice into the buffer, once as the 16255332Scy * full path for the "GET" and once as the "Host:", the buffer it is 17255332Scy * put in needs to be larger than 512*2 to make room for the supporting 18255332Scy * text. Why not just use snprintf and truncate? The warning about the 19255332Scy * URL being too long tells you something is wrong and does not fetch 20255332Scy * any data - just truncating the URL (with snprintf, etc) and sending 21255332Scy * that to the server is allowing an unknown and unintentioned action 22255332Scy * to happen. 23255332Scy */ 24255332Scy#define MAX_URL_LEN 512 25255332Scy#define LOAD_BUFSIZE (MAX_URL_LEN * 2 + 128) 26255332Scy 27255332Scy/* 28170263Sdarrenr * Format expected is one addres per line, at the start of each line. 29170263Sdarrenr */ 30170263Sdarrenralist_t * 31170263Sdarrenrload_http(char *url) 32170263Sdarrenr{ 33255332Scy int fd, len, left, port, endhdr, removed, linenum = 0; 34255332Scy char *s, *t, *u, buffer[LOAD_BUFSIZE], *myurl; 35170263Sdarrenr alist_t *a, *rtop, *rbot; 36193043Sstas size_t avail; 37193043Sstas int error; 38170263Sdarrenr 39170263Sdarrenr /* 40170263Sdarrenr * More than this would just be absurd. 41170263Sdarrenr */ 42255332Scy if (strlen(url) > MAX_URL_LEN) { 43255332Scy fprintf(stderr, "load_http has a URL > %d bytes?!\n", 44255332Scy MAX_URL_LEN); 45170263Sdarrenr return NULL; 46170263Sdarrenr } 47170263Sdarrenr 48170263Sdarrenr fd = -1; 49170263Sdarrenr rtop = NULL; 50170263Sdarrenr rbot = NULL; 51170263Sdarrenr 52193043Sstas avail = sizeof(buffer); 53193043Sstas error = snprintf(buffer, avail, "GET %s HTTP/1.0\r\n", url); 54170263Sdarrenr 55193043Sstas /* 56193043Sstas * error is always less then avail due to the constraint on 57193043Sstas * the url length above. 58193043Sstas */ 59193043Sstas avail -= error; 60193043Sstas 61170263Sdarrenr myurl = strdup(url); 62170263Sdarrenr if (myurl == NULL) 63170263Sdarrenr goto done; 64170263Sdarrenr 65170263Sdarrenr s = myurl + 7; /* http:// */ 66170263Sdarrenr t = strchr(s, '/'); 67170263Sdarrenr if (t == NULL) { 68170263Sdarrenr fprintf(stderr, "load_http has a malformed URL '%s'\n", url); 69170263Sdarrenr free(myurl); 70170263Sdarrenr return NULL; 71170263Sdarrenr } 72170263Sdarrenr *t++ = '\0'; 73170263Sdarrenr 74255332Scy /* 75255332Scy * 10 is the length of 'Host: \r\n\r\n' below. 76255332Scy */ 77255332Scy if (strlen(s) + strlen(buffer) + 10 > sizeof(buffer)) { 78255332Scy fprintf(stderr, "load_http has a malformed URL '%s'\n", url); 79255332Scy free(myurl); 80255332Scy return NULL; 81255332Scy } 82255332Scy 83170263Sdarrenr u = strchr(s, '@'); 84170263Sdarrenr if (u != NULL) 85170263Sdarrenr s = u + 1; /* AUTH */ 86170263Sdarrenr 87193043Sstas error = snprintf(buffer + strlen(buffer), avail, "Host: %s\r\n\r\n", s); 88193043Sstas if (error >= avail) { 89193043Sstas fprintf(stderr, "URL is too large: %s\n", url); 90193043Sstas goto done; 91193043Sstas } 92170263Sdarrenr 93170263Sdarrenr u = strchr(s, ':'); 94170263Sdarrenr if (u != NULL) { 95170263Sdarrenr *u++ = '\0'; 96170263Sdarrenr port = atoi(u); 97170263Sdarrenr if (port < 0 || port > 65535) 98170263Sdarrenr goto done; 99170263Sdarrenr } else { 100170263Sdarrenr port = 80; 101170263Sdarrenr } 102170263Sdarrenr 103170263Sdarrenr 104255332Scy fd = connecttcp(s, port); 105170263Sdarrenr if (fd == -1) 106170263Sdarrenr goto done; 107170263Sdarrenr 108170263Sdarrenr 109170263Sdarrenr len = strlen(buffer); 110193043Sstas if (write(fd, buffer, len) != len) 111170263Sdarrenr goto done; 112170263Sdarrenr 113170263Sdarrenr s = buffer; 114170263Sdarrenr endhdr = 0; 115170263Sdarrenr left = sizeof(buffer) - 1; 116170263Sdarrenr 117170263Sdarrenr while ((len = read(fd, s, left)) > 0) { 118170263Sdarrenr s[len] = '\0'; 119170263Sdarrenr left -= len; 120170263Sdarrenr s += len; 121170263Sdarrenr 122170263Sdarrenr if (endhdr >= 0) { 123170263Sdarrenr if (endhdr == 0) { 124170263Sdarrenr t = strchr(buffer, ' '); 125170263Sdarrenr if (t == NULL) 126170263Sdarrenr continue; 127170263Sdarrenr t++; 128170263Sdarrenr if (*t != '2') 129170263Sdarrenr break; 130170263Sdarrenr } 131170263Sdarrenr 132170263Sdarrenr u = buffer; 133170263Sdarrenr while ((t = strchr(u, '\r')) != NULL) { 134170263Sdarrenr if (t == u) { 135170263Sdarrenr if (*(t + 1) == '\n') { 136170263Sdarrenr u = t + 2; 137170263Sdarrenr endhdr = -1; 138170263Sdarrenr break; 139170263Sdarrenr } else 140170263Sdarrenr t++; 141170263Sdarrenr } else if (*(t + 1) == '\n') { 142170263Sdarrenr endhdr++; 143170263Sdarrenr u = t + 2; 144170263Sdarrenr } else 145170263Sdarrenr u = t + 1; 146170263Sdarrenr } 147170263Sdarrenr if (endhdr >= 0) 148170263Sdarrenr continue; 149170263Sdarrenr removed = (u - buffer) + 1; 150170263Sdarrenr memmove(buffer, u, (sizeof(buffer) - left) - removed); 151170263Sdarrenr s -= removed; 152170263Sdarrenr left += removed; 153170263Sdarrenr } 154170263Sdarrenr 155170263Sdarrenr do { 156170263Sdarrenr t = strchr(buffer, '\n'); 157170263Sdarrenr if (t == NULL) 158170263Sdarrenr break; 159170263Sdarrenr 160255332Scy linenum++; 161255332Scy *t = '\0'; 162170263Sdarrenr 163255332Scy /* 164255332Scy * Remove comment and continue to the next line if 165255332Scy * the comment is at the start of the line. 166255332Scy */ 167255332Scy u = strchr(buffer, '#'); 168255332Scy if (u != NULL) { 169255332Scy *u = '\0'; 170255332Scy if (u == buffer) 171255332Scy continue; 172170263Sdarrenr } 173170263Sdarrenr 174255332Scy /* 175255332Scy * Trim off tailing white spaces, will include \r 176255332Scy */ 177255332Scy for (u = t - 1; (u >= buffer) && ISSPACE(*u); u--) 178255332Scy *u = '\0'; 179255332Scy 180255332Scy a = alist_new(AF_UNSPEC, buffer); 181170263Sdarrenr if (a != NULL) { 182170263Sdarrenr if (rbot != NULL) 183170263Sdarrenr rbot->al_next = a; 184170263Sdarrenr else 185170263Sdarrenr rtop = a; 186170263Sdarrenr rbot = a; 187255332Scy } else { 188255332Scy fprintf(stderr, 189255332Scy "%s:%d unrecognised content:%s\n", 190255332Scy url, linenum, buffer); 191170263Sdarrenr } 192170263Sdarrenr 193255332Scy t++; 194170263Sdarrenr removed = t - buffer; 195170263Sdarrenr memmove(buffer, t, sizeof(buffer) - left - removed); 196170263Sdarrenr s -= removed; 197170263Sdarrenr left += removed; 198170263Sdarrenr 199170263Sdarrenr } while (1); 200170263Sdarrenr } 201170263Sdarrenr 202170263Sdarrenrdone: 203170263Sdarrenr if (myurl != NULL) 204170263Sdarrenr free(myurl); 205170263Sdarrenr if (fd != -1) 206170263Sdarrenr close(fd); 207170263Sdarrenr return rtop; 208170263Sdarrenr} 209