150
161
* it may be form-encoded. (Although RFC 1738 doesn't allow this -
151
162
* it only permits ; / ? : @ = & as reserved chars.)
154
allowed = "$-_.+!*'(),;:@&=";
155
else if (t == enc_search)
156
allowed = "$-_.!*'(),;:@&=";
157
else if (t == enc_user)
158
allowed = "$-_.+!*'(),;@&=";
159
else if (t == enc_fpath)
160
allowed = "$-_.+!*'(),?:@&=";
161
else /* if (t == enc_parm) */
162
allowed = "$-_.+!*'(),?/:@&=";
165
allowed = "~$-_.+!*'(),;:@&=";
167
else if (t == enc_search) {
168
allowed = "$-_.!*'(),;:@&=";
170
else if (t == enc_user) {
171
allowed = "$-_.+!*'(),;@&=";
173
else if (t == enc_fpath) {
174
allowed = "$-_.+!*'(),?:@&=";
176
else { /* if (t == enc_parm) */
177
allowed = "$-_.+!*'(),?/:@&=";
166
else if (t == enc_search)
183
else if (t == enc_search) {
171
190
y = apr_palloc(p, 3 * len + 1);
173
192
for (i = 0, j = 0; i < len; i++, j++) {
174
193
/* always handle '/' first */
176
if (strchr(reserved, ch)) {
195
if (strchr(reserved, ch)) {
181
200
* decode it if not already done. do not decode reverse proxied URLs
182
201
* unless specifically forced
184
if ((forcedec || (proxyreq && proxyreq != PROXYREQ_REVERSE)) && ch == '%') {
185
if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2]))
187
ch = ap_proxy_hex2c(&x[i + 1]);
189
if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */
190
ap_proxy_c2hex(ch, &y[j]);
203
if ((forcedec || (proxyreq && proxyreq != PROXYREQ_REVERSE)) && ch == '%') {
204
if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2])) {
207
ch = ap_proxy_hex2c(&x[i + 1]);
209
if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */
210
ap_proxy_c2hex(ch, &y[j]);
195
215
/* recode it, if necessary */
196
if (!apr_isalnum(ch) && !strchr(allowed, ch)) {
197
ap_proxy_c2hex(ch, &y[j]);
216
if (!apr_isalnum(ch) && !strchr(allowed, ch)) {
217
ap_proxy_c2hex(ch, &y[j]);
223
244
apr_port_t tmp_port;
226
if (url[0] != '/' || url[1] != '/')
227
return "Malformed URL";
247
if (url[0] != '/' || url[1] != '/') {
248
return "Malformed URL";
229
251
url = strchr(host, '/');
233
*(url++) = '\0'; /* skip seperating '/' */
256
*(url++) = '\0'; /* skip seperating '/' */
235
259
/* find _last_ '@' since it might occur in user/password part */
236
260
strp = strrchr(host, '@');
238
262
if (strp != NULL) {
243
267
/* find password */
244
strp = strchr(user, ':');
247
password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1, 0);
248
if (password == NULL)
249
return "Bad %-escape in URL (password)";
268
strp = strchr(user, ':');
271
password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1, 0);
272
if (password == NULL) {
273
return "Bad %-escape in URL (password)";
252
user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1, 0);
254
return "Bad %-escape in URL (username)";
277
user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1, 0);
279
return "Bad %-escape in URL (username)";
256
282
if (userp != NULL) {
259
285
if (passwordp != NULL) {
260
*passwordp = password;
286
*passwordp = password;
283
static const char * const lwday[7] =
284
{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
287
310
* If the date is a valid RFC 850 date or asctime() date, then it
288
* is converted to the RFC 1123 format, otherwise it is not modified.
289
* This routine is not very fast at doing conversions, as it uses
290
* sscanf and sprintf. However, if the date is already correctly
291
* formatted, then it exits very quickly.
311
* is converted to the RFC 1123 format.
293
313
PROXY_DECLARE(const char *)
294
ap_proxy_date_canon(apr_pool_t *p, const char *x1)
314
ap_proxy_date_canon(apr_pool_t *p, const char *date)
296
char *x = apr_pstrdup(p, x1);
297
int wk, mday, year, hour, min, sec, mon;
298
char *q, month[4], zone[4], week[4];
301
/* check for RFC 850 date */
302
if (q != NULL && q - x > 3 && q[1] == ' ') {
304
for (wk = 0; wk < 7; wk++)
305
if (strcmp(x, lwday[wk]) == 0)
309
return x; /* not a valid date */
310
if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
311
q[17] != ':' || strcmp(&q[20], " GMT") != 0)
313
if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
314
&hour, &min, &sec, zone) != 7)
322
/* check for acstime() date */
323
if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
324
x[16] != ':' || x[19] != ' ' || x[24] != '\0')
326
if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
327
&min, &sec, &year) != 7)
329
for (wk = 0; wk < 7; wk++)
330
if (strcmp(week, apr_day_snames[wk]) == 0)
337
for (mon = 0; mon < 12; mon++)
338
if (strcmp(month, apr_month_snames[mon]) == 0)
343
q = apr_palloc(p, 30);
344
apr_snprintf(q, 30, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", apr_day_snames[wk],
345
mday, apr_month_snames[mon], year, hour, min, sec);
319
apr_time_t time = apr_date_parse_http(date);
324
ndate = apr_palloc(p, APR_RFC822_DATE_LEN);
325
rv = apr_rfc822_date(ndate, time);
326
if (rv != APR_SUCCESS) {
349
333
PROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
568
567
/* Iterate over up to 4 (dotted) quads. */
569
568
for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {
572
if (*addr == '/' && quads > 0) /* netmask starts here. */
575
if (!apr_isdigit(*addr))
576
return 0; /* no digit at start of quad */
578
ip_addr[quads] = strtol(addr, &tmp, 0);
580
if (tmp == addr) /* expected a digit, found something else */
583
if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
590
if (*addr == '.' && quads != 3)
591
++addr; /* after the 4th quad, a dot would be illegal */
594
for (This->addr.s_addr = 0, i = 0; i < quads; ++i)
595
This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
571
if (*addr == '/' && quads > 0) { /* netmask starts here. */
575
if (!apr_isdigit(*addr)) {
576
return 0; /* no digit at start of quad */
579
ip_addr[quads] = strtol(addr, &tmp, 0);
581
if (tmp == addr) { /* expected a digit, found something else */
585
if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
592
if (*addr == '.' && quads != 3) {
593
++addr; /* after the 4th quad, a dot would be illegal */
597
for (This->addr.s_addr = 0, i = 0; i < quads; ++i) {
598
This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
597
601
if (addr[0] == '/' && apr_isdigit(addr[1])) { /* net mask follows: */
602
bits = strtol(addr, &tmp, 0);
604
if (tmp == addr) /* expected a digit, found something else */
609
if (bits < 0 || bits > 32) /* netmask must be between 0 and 32 */
606
bits = strtol(addr, &tmp, 0);
608
if (tmp == addr) { /* expected a digit, found something else */
614
if (bits < 0 || bits > 32) { /* netmask must be between 0 and 32 */
615
* Determine (i.e., "guess") netmask by counting the
616
* number of trailing .0's; reduce #quads appropriately
617
* (so that 192.168.0.0 is equivalent to 192.168.)
619
while (quads > 0 && ip_addr[quads - 1] == 0)
622
/* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
626
/* every zero-byte counts as 8 zero-bits */
629
if (bits != 32) /* no warning for fully qualified IP address */
621
* Determine (i.e., "guess") netmask by counting the
622
* number of trailing .0's; reduce #quads appropriately
623
* (so that 192.168.0.0 is equivalent to 192.168.)
625
while (quads > 0 && ip_addr[quads - 1] == 0) {
629
/* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
634
/* every zero-byte counts as 8 zero-bits */
637
if (bits != 32) { /* no warning for fully qualified IP address */
630
638
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
631
"Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld",
632
inet_ntoa(This->addr), bits);
639
"Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld",
640
inet_ntoa(This->addr), bits);
635
644
This->mask.s_addr = htonl(APR_INADDR_NONE << (32 - bits));
637
646
if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
638
647
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
639
"Warning: NetMask and IP-Addr disagree in %s/%ld",
640
inet_ntoa(This->addr), bits);
641
This->addr.s_addr &= This->mask.s_addr;
648
"Warning: NetMask and IP-Addr disagree in %s/%ld",
649
inet_ntoa(This->addr), bits);
650
This->addr.s_addr &= This->mask.s_addr;
642
651
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
644
inet_ntoa(This->addr), bits);
652
" Set to %s/%ld", inet_ntoa(This->addr), bits);
647
655
if (*addr == '\0') {
648
This->matcher = proxy_match_ipaddr;
652
return (*addr == '\0'); /* okay iff we've parsed the whole string */
656
This->matcher = proxy_match_ipaddr;
660
return (*addr == '\0'); /* okay iff we've parsed the whole string */
655
664
/* Return TRUE if addr represents an IP address (or an IP network address) */
659
668
struct in_addr addr, *ip;
660
669
const char *host = proxy_get_host_of_request(r);
662
if (host == NULL) /* oops! */
671
if (host == NULL) { /* oops! */
665
675
memset(&addr, '\0', sizeof addr);
666
676
memset(ip_addr, '\0', sizeof ip_addr);
668
678
if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
669
for (addr.s_addr = 0, i = 0; i < 4; ++i)
670
addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
679
for (addr.s_addr = 0, i = 0; i < 4; ++i) {
680
addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
672
if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
683
if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
674
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
685
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
675
686
"1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));
676
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
687
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
677
688
"%s/", inet_ntoa(This->addr));
678
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
689
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
679
690
"%s", inet_ntoa(This->mask));
685
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
696
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
686
697
"1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
687
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
698
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
688
699
"%s/", inet_ntoa(This->addr));
689
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
700
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
690
701
"%s", inet_ntoa(This->mask));
695
struct apr_sockaddr_t *reqaddr;
706
struct apr_sockaddr_t *reqaddr;
697
708
if (apr_sockaddr_info_get(&reqaddr, host, APR_UNSPEC, 0, 0, r->pool)
700
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
701
"2)IP-NoMatch: hostname=%s msg=Host not found",
711
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
712
"2)IP-NoMatch: hostname=%s msg=Host not found", host);
707
/* Try to deal with multiple IP addr's for a host */
708
/* FIXME: This needs to be able to deal with IPv6 */
710
ip = (struct in_addr *) reqaddr->ipaddr_ptr;
711
if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) {
713
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
714
"3)IP-Match: %s[%s] <-> ", host,
716
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
717
"%s/", inet_ntoa(This->addr));
718
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
719
"%s", inet_ntoa(This->mask));
725
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
726
"3)IP-NoMatch: %s[%s] <-> ", host,
728
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
729
"%s/", inet_ntoa(This->addr));
730
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
731
"%s", inet_ntoa(This->mask));
734
reqaddr = reqaddr->next;
717
/* Try to deal with multiple IP addr's for a host */
718
/* FIXME: This needs to be able to deal with IPv6 */
720
ip = (struct in_addr *) reqaddr->ipaddr_ptr;
721
if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) {
723
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
724
"3)IP-Match: %s[%s] <-> ", host, inet_ntoa(*ip));
725
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
726
"%s/", inet_ntoa(This->addr));
727
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
728
"%s", inet_ntoa(This->mask));
734
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
735
"3)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(*ip));
736
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
737
"%s/", inet_ntoa(This->addr));
738
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
739
"%s", inet_ntoa(This->mask));
742
reqaddr = reqaddr->next;