Annotation of embedaddon/php/ext/filter/logical_filters.c, revision 1.1.1.3
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.3 ! misho 5: | Copyright (c) 1997-2013 The PHP Group |
1.1 misho 6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Authors: Derick Rethans <derick@php.net> |
16: | Pierre-A. Joye <pierre@php.net> |
17: +----------------------------------------------------------------------+
18: */
19:
1.1.1.2 misho 20: /* $Id$ */
1.1 misho 21:
22: #include "php_filter.h"
23: #include "filter_private.h"
24: #include "ext/standard/url.h"
25: #include "ext/pcre/php_pcre.h"
26:
27: #include "zend_multiply.h"
28:
29: #if HAVE_ARPA_INET_H
30: # include <arpa/inet.h>
31: #endif
32:
33: #ifndef INADDR_NONE
34: # define INADDR_NONE ((unsigned long int) -1)
35: #endif
36:
37:
38: /* {{{ FETCH_LONG_OPTION(var_name, option_name) */
39: #define FETCH_LONG_OPTION(var_name, option_name) \
40: var_name = 0; \
41: var_name##_set = 0; \
42: if (option_array) { \
43: if (zend_hash_find(HASH_OF(option_array), option_name, sizeof(option_name), (void **) &option_val) == SUCCESS) { \
44: PHP_FILTER_GET_LONG_OPT(option_val, var_name); \
45: var_name##_set = 1; \
46: } \
47: }
48: /* }}} */
49:
50: /* {{{ FETCH_STRING_OPTION(var_name, option_name) */
51: #define FETCH_STRING_OPTION(var_name, option_name) \
52: var_name = NULL; \
53: var_name##_set = 0; \
54: var_name##_len = 0; \
55: if (option_array) { \
56: if (zend_hash_find(HASH_OF(option_array), option_name, sizeof(option_name), (void **) &option_val) == SUCCESS) { \
57: if (Z_TYPE_PP(option_val) == IS_STRING) { \
58: var_name = Z_STRVAL_PP(option_val); \
59: var_name##_len = Z_STRLEN_PP(option_val); \
60: var_name##_set = 1; \
61: } \
62: } \
63: }
64: /* }}} */
65:
66: #define FORMAT_IPV4 4
67: #define FORMAT_IPV6 6
68:
69: static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
70: long ctx_value;
71: int sign = 0, digit = 0;
72: const char *end = str + str_len;
73:
74: switch (*str) {
75: case '-':
76: sign = 1;
77: case '+':
78: str++;
79: default:
80: break;
81: }
82:
1.1.1.3 ! misho 83: if (*str == '0' && str + 1 == end) {
! 84: /* Special cases: +0 and -0 */
! 85: return 1;
! 86: }
! 87:
1.1 misho 88: /* must start with 1..9*/
89: if (str < end && *str >= '1' && *str <= '9') {
90: ctx_value = ((sign)?-1:1) * ((*(str++)) - '0');
91: } else {
92: return -1;
93: }
94:
95: if ((end - str > MAX_LENGTH_OF_LONG - 1) /* number too long */
96: || (SIZEOF_LONG == 4 && (end - str == MAX_LENGTH_OF_LONG - 1) && *str > '2')) {
97: /* overflow */
98: return -1;
99: }
100:
101: while (str < end) {
102: if (*str >= '0' && *str <= '9') {
103: digit = (*(str++) - '0');
104: if ( (!sign) && ctx_value <= (LONG_MAX-digit)/10 ) {
105: ctx_value = (ctx_value * 10) + digit;
106: } else if ( sign && ctx_value >= (LONG_MIN+digit)/10) {
107: ctx_value = (ctx_value * 10) - digit;
108: } else {
109: return -1;
110: }
111: } else {
112: return -1;
113: }
114: }
115:
116: *ret = ctx_value;
117: return 1;
118: }
119: /* }}} */
120:
121: static int php_filter_parse_octal(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
122: unsigned long ctx_value = 0;
123: const char *end = str + str_len;
124:
125: while (str < end) {
126: if (*str >= '0' && *str <= '7') {
127: unsigned long n = ((*(str++)) - '0');
128:
129: if ((ctx_value > ((unsigned long)(~(long)0)) / 8) ||
130: ((ctx_value = ctx_value * 8) > ((unsigned long)(~(long)0)) - n)) {
131: return -1;
132: }
133: ctx_value += n;
134: } else {
135: return -1;
136: }
137: }
138:
139: *ret = (long)ctx_value;
140: return 1;
141: }
142: /* }}} */
143:
144: static int php_filter_parse_hex(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
145: unsigned long ctx_value = 0;
146: const char *end = str + str_len;
147: unsigned long n;
148:
149: while (str < end) {
150: if (*str >= '0' && *str <= '9') {
151: n = ((*(str++)) - '0');
152: } else if (*str >= 'a' && *str <= 'f') {
153: n = ((*(str++)) - ('a' - 10));
154: } else if (*str >= 'A' && *str <= 'F') {
155: n = ((*(str++)) - ('A' - 10));
156: } else {
157: return -1;
158: }
159: if ((ctx_value > ((unsigned long)(~(long)0)) / 16) ||
160: ((ctx_value = ctx_value * 16) > ((unsigned long)(~(long)0)) - n)) {
161: return -1;
162: }
163: ctx_value += n;
164: }
165:
166: *ret = (long)ctx_value;
167: return 1;
168: }
169: /* }}} */
170:
171: void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
172: {
173: zval **option_val;
174: long min_range, max_range, option_flags;
175: int min_range_set, max_range_set;
176: int allow_octal = 0, allow_hex = 0;
177: int len, error = 0;
178: long ctx_value;
179: char *p;
180:
181: /* Parse options */
182: FETCH_LONG_OPTION(min_range, "min_range");
183: FETCH_LONG_OPTION(max_range, "max_range");
184: option_flags = flags;
185:
186: len = Z_STRLEN_P(value);
187:
188: if (len == 0) {
189: RETURN_VALIDATION_FAILED
190: }
191:
192: if (option_flags & FILTER_FLAG_ALLOW_OCTAL) {
193: allow_octal = 1;
194: }
195:
196: if (option_flags & FILTER_FLAG_ALLOW_HEX) {
197: allow_hex = 1;
198: }
199:
200: /* Start the validating loop */
201: p = Z_STRVAL_P(value);
202: ctx_value = 0;
203:
204: PHP_FILTER_TRIM_DEFAULT(p, len);
205:
206: if (*p == '0') {
207: p++; len--;
208: if (allow_hex && (*p == 'x' || *p == 'X')) {
209: p++; len--;
210: if (php_filter_parse_hex(p, len, &ctx_value TSRMLS_CC) < 0) {
211: error = 1;
212: }
213: } else if (allow_octal) {
214: if (php_filter_parse_octal(p, len, &ctx_value TSRMLS_CC) < 0) {
215: error = 1;
216: }
217: } else if (len != 0) {
218: error = 1;
219: }
220: } else {
221: if (php_filter_parse_int(p, len, &ctx_value TSRMLS_CC) < 0) {
222: error = 1;
223: }
224: }
225:
226: if (error > 0 || (min_range_set && (ctx_value < min_range)) || (max_range_set && (ctx_value > max_range))) {
227: RETURN_VALIDATION_FAILED
228: } else {
229: zval_dtor(value);
230: Z_TYPE_P(value) = IS_LONG;
231: Z_LVAL_P(value) = ctx_value;
232: return;
233: }
234: }
235: /* }}} */
236:
237: void php_filter_boolean(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
238: {
239: char *str = Z_STRVAL_P(value);
240: int len = Z_STRLEN_P(value);
241: int ret;
242:
1.1.1.3 ! misho 243: PHP_FILTER_TRIM_DEFAULT_EX(str, len, 0);
1.1 misho 244:
245: /* returns true for "1", "true", "on" and "yes"
246: * returns false for "0", "false", "off", "no", and ""
247: * null otherwise. */
248: switch (len) {
1.1.1.3 ! misho 249: case 0:
! 250: ret = 0;
! 251: break;
1.1 misho 252: case 1:
253: if (*str == '1') {
254: ret = 1;
255: } else if (*str == '0') {
256: ret = 0;
257: } else {
258: ret = -1;
259: }
260: break;
261: case 2:
262: if (strncasecmp(str, "on", 2) == 0) {
263: ret = 1;
264: } else if (strncasecmp(str, "no", 2) == 0) {
265: ret = 0;
266: } else {
267: ret = -1;
268: }
269: break;
270: case 3:
271: if (strncasecmp(str, "yes", 3) == 0) {
272: ret = 1;
273: } else if (strncasecmp(str, "off", 3) == 0) {
274: ret = 0;
275: } else {
276: ret = -1;
277: }
278: break;
279: case 4:
280: if (strncasecmp(str, "true", 4) == 0) {
281: ret = 1;
282: } else {
283: ret = -1;
284: }
285: break;
286: case 5:
287: if (strncasecmp(str, "false", 5) == 0) {
288: ret = 0;
289: } else {
290: ret = -1;
291: }
292: break;
293: default:
294: ret = -1;
295: }
296:
1.1.1.3 ! misho 297: if (ret == -1) {
1.1 misho 298: RETURN_VALIDATION_FAILED
299: } else {
300: zval_dtor(value);
301: ZVAL_BOOL(value, ret);
302: }
303: }
304: /* }}} */
305:
306: void php_filter_float(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
307: {
308: int len;
309: char *str, *end;
310: char *num, *p;
311:
312: zval **option_val;
313: char *decimal;
314: int decimal_set, decimal_len;
315: char dec_sep = '.';
316: char tsd_sep[3] = "',.";
317:
318: long lval;
319: double dval;
320:
321: int first, n;
322:
323: len = Z_STRLEN_P(value);
324: str = Z_STRVAL_P(value);
325:
326: PHP_FILTER_TRIM_DEFAULT(str, len);
327: end = str + len;
328:
329: FETCH_STRING_OPTION(decimal, "decimal");
330:
331: if (decimal_set) {
332: if (decimal_len != 1) {
333: php_error_docref(NULL TSRMLS_CC, E_WARNING, "decimal separator must be one char");
334: RETURN_VALIDATION_FAILED
335: } else {
336: dec_sep = *decimal;
337: }
338: }
339:
340: num = p = emalloc(len+1);
341: if (str < end && (*str == '+' || *str == '-')) {
342: *p++ = *str++;
343: }
344: first = 1;
345: while (1) {
346: n = 0;
347: while (str < end && *str >= '0' && *str <= '9') {
348: ++n;
349: *p++ = *str++;
350: }
351: if (str == end || *str == dec_sep || *str == 'e' || *str == 'E') {
352: if (!first && n != 3) {
353: goto error;
354: }
355: if (*str == dec_sep) {
356: *p++ = '.';
357: str++;
358: while (str < end && *str >= '0' && *str <= '9') {
359: *p++ = *str++;
360: }
361: }
362: if (*str == 'e' || *str == 'E') {
363: *p++ = *str++;
364: if (str < end && (*str == '+' || *str == '-')) {
365: *p++ = *str++;
366: }
367: while (str < end && *str >= '0' && *str <= '9') {
368: *p++ = *str++;
369: }
370: }
371: break;
372: }
373: if ((flags & FILTER_FLAG_ALLOW_THOUSAND) && (*str == tsd_sep[0] || *str == tsd_sep[1] || *str == tsd_sep[2])) {
374: if (first?(n < 1 || n > 3):(n != 3)) {
375: goto error;
376: }
377: first = 0;
378: str++;
379: } else {
380: goto error;
381: }
382: }
383: if (str != end) {
384: goto error;
385: }
386: *p = 0;
387:
388: switch (is_numeric_string(num, p - num, &lval, &dval, 0)) {
389: case IS_LONG:
390: zval_dtor(value);
391: Z_TYPE_P(value) = IS_DOUBLE;
392: Z_DVAL_P(value) = lval;
393: break;
394: case IS_DOUBLE:
395: if ((!dval && p - num > 1 && strpbrk(num, "123456789")) || !zend_finite(dval)) {
396: goto error;
397: }
398: zval_dtor(value);
399: Z_TYPE_P(value) = IS_DOUBLE;
400: Z_DVAL_P(value) = dval;
401: break;
402: default:
403: error:
404: efree(num);
405: RETURN_VALIDATION_FAILED
406: }
407: efree(num);
408: }
409: /* }}} */
410:
411: void php_filter_validate_regexp(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
412: {
413: zval **option_val;
414: char *regexp;
415: int regexp_len;
416: long option_flags;
417: int regexp_set, option_flags_set;
418:
419: pcre *re = NULL;
420: pcre_extra *pcre_extra = NULL;
421: int preg_options = 0;
422:
423: int ovector[3];
424: int matches;
425:
426: /* Parse options */
427: FETCH_STRING_OPTION(regexp, "regexp");
428: FETCH_LONG_OPTION(option_flags, "flags");
429:
430: if (!regexp_set) {
431: php_error_docref(NULL TSRMLS_CC, E_WARNING, "'regexp' option missing");
432: RETURN_VALIDATION_FAILED
433: }
434:
435: re = pcre_get_compiled_regex(regexp, &pcre_extra, &preg_options TSRMLS_CC);
436: if (!re) {
437: RETURN_VALIDATION_FAILED
438: }
439: matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);
440:
441: /* 0 means that the vector is too small to hold all the captured substring offsets */
442: if (matches < 0) {
443: RETURN_VALIDATION_FAILED
444: }
445: }
446: /* }}} */
447:
448: void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
449: {
450: php_url *url;
451: int old_len = Z_STRLEN_P(value);
452:
453: php_filter_url(value, flags, option_array, charset TSRMLS_CC);
454:
455: if (Z_TYPE_P(value) != IS_STRING || old_len != Z_STRLEN_P(value)) {
456: RETURN_VALIDATION_FAILED
457: }
458:
459: /* Use parse_url - if it returns false, we return NULL */
460: url = php_url_parse_ex(Z_STRVAL_P(value), Z_STRLEN_P(value));
461:
462: if (url == NULL) {
463: RETURN_VALIDATION_FAILED
464: }
465:
466: if (url->scheme != NULL && (!strcasecmp(url->scheme, "http") || !strcasecmp(url->scheme, "https"))) {
467: char *e, *s;
468:
469: if (url->host == NULL) {
470: goto bad_url;
471: }
472:
473: e = url->host + strlen(url->host);
474: s = url->host;
475:
476: /* First char of hostname must be alphanumeric */
477: if(!isalnum((int)*(unsigned char *)s)) {
478: goto bad_url;
479: }
480:
481: while (s < e) {
482: if (!isalnum((int)*(unsigned char *)s) && *s != '-' && *s != '.') {
483: goto bad_url;
484: }
485: s++;
486: }
487:
488: if (*(e - 1) == '.') {
489: goto bad_url;
490: }
491: }
492:
493: if (
494: url->scheme == NULL ||
495: /* some schemas allow the host to be empty */
496: (url->host == NULL && (strcmp(url->scheme, "mailto") && strcmp(url->scheme, "news") && strcmp(url->scheme, "file"))) ||
497: ((flags & FILTER_FLAG_PATH_REQUIRED) && url->path == NULL) || ((flags & FILTER_FLAG_QUERY_REQUIRED) && url->query == NULL)
498: ) {
499: bad_url:
500: php_url_free(url);
501: RETURN_VALIDATION_FAILED
502: }
503: php_url_free(url);
504: }
505: /* }}} */
506:
507: void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
508: {
509: /*
510: * The regex below is based on a regex by Michael Rushton.
511: * However, it is not identical. I changed it to only consider routeable
512: * addresses as valid. Michael's regex considers a@b a valid address
513: * which conflicts with section 2.3.5 of RFC 5321 which states that:
514: *
515: * Only resolvable, fully-qualified domain names (FQDNs) are permitted
516: * when domain names are used in SMTP. In other words, names that can
517: * be resolved to MX RRs or address (i.e., A or AAAA) RRs (as discussed
518: * in Section 5) are permitted, as are CNAME RRs whose targets can be
519: * resolved, in turn, to MX or address RRs. Local nicknames or
520: * unqualified names MUST NOT be used.
521: *
522: * This regex does not handle comments and folding whitespace. While
523: * this is technically valid in an email address, these parts aren't
524: * actually part of the address itself.
525: *
526: * Michael's regex carries this copyright:
527: *
528: * Copyright © Michael Rushton 2009-10
529: * http://squiloople.com/
530: * Feel free to use and redistribute this code. But please keep this copyright notice.
531: *
532: */
533: const char regexp[] = "/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD";
534:
535: pcre *re = NULL;
536: pcre_extra *pcre_extra = NULL;
537: int preg_options = 0;
538: int ovector[150]; /* Needs to be a multiple of 3 */
539: int matches;
540:
541:
542: /* The maximum length of an e-mail address is 320 octets, per RFC 2821. */
543: if (Z_STRLEN_P(value) > 320) {
544: RETURN_VALIDATION_FAILED
545: }
546:
547: re = pcre_get_compiled_regex((char *)regexp, &pcre_extra, &preg_options TSRMLS_CC);
548: if (!re) {
549: RETURN_VALIDATION_FAILED
550: }
551: matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);
552:
553: /* 0 means that the vector is too small to hold all the captured substring offsets */
554: if (matches < 0) {
555: RETURN_VALIDATION_FAILED
556: }
557:
558: }
559: /* }}} */
560:
561: static int _php_filter_validate_ipv4(char *str, int str_len, int *ip) /* {{{ */
562: {
563: const char *end = str + str_len;
564: int num, m;
565: int n = 0;
566:
567: while (str < end) {
568: int leading_zero;
569: if (*str < '0' || *str > '9') {
570: return 0;
571: }
572: leading_zero = (*str == '0');
573: m = 1;
574: num = ((*(str++)) - '0');
575: while (str < end && (*str >= '0' && *str <= '9')) {
576: num = num * 10 + ((*(str++)) - '0');
577: if (num > 255 || ++m > 3) {
578: return 0;
579: }
580: }
581: /* don't allow a leading 0; that introduces octal numbers,
582: * which we don't support */
583: if (leading_zero && (num != 0 || m > 1))
584: return 0;
585: ip[n++] = num;
586: if (n == 4) {
587: return str == end;
588: } else if (str >= end || *(str++) != '.') {
589: return 0;
590: }
591: }
592: return 0;
593: }
594: /* }}} */
595:
596: static int _php_filter_validate_ipv6(char *str, int str_len TSRMLS_DC) /* {{{ */
597: {
598: int compressed = 0;
599: int blocks = 0;
600: int n;
601: char *ipv4;
602: char *end;
603: int ip4elm[4];
604: char *s = str;
605:
606: if (!memchr(str, ':', str_len)) {
607: return 0;
608: }
609:
610: /* check for bundled IPv4 */
611: ipv4 = memchr(str, '.', str_len);
612: if (ipv4) {
613: while (ipv4 > str && *(ipv4-1) != ':') {
614: ipv4--;
615: }
616:
617: if (!_php_filter_validate_ipv4(ipv4, (str_len - (ipv4 - str)), ip4elm)) {
618: return 0;
619: }
620:
621: str_len = ipv4 - str; /* length excluding ipv4 */
622: if (str_len < 2) {
623: return 0;
624: }
625:
626: if (ipv4[-2] != ':') {
627: /* don't include : before ipv4 unless it's a :: */
628: str_len--;
629: }
630:
631: blocks = 2;
632: }
633:
634: end = str + str_len;
635:
636: while (str < end) {
637: if (*str == ':') {
638: if (++str >= end) {
639: /* cannot end in : without previous : */
640: return 0;
641: }
642: if (*str == ':') {
643: if (compressed) {
644: return 0;
645: }
646: blocks++; /* :: means 1 or more 16-bit 0 blocks */
647: compressed = 1;
648:
649: if (++str == end) {
650: return (blocks <= 8);
651: }
652: } else if ((str - 1) == s) {
653: /* dont allow leading : without another : following */
654: return 0;
655: }
656: }
657: n = 0;
658: while ((str < end) &&
659: ((*str >= '0' && *str <= '9') ||
660: (*str >= 'a' && *str <= 'f') ||
661: (*str >= 'A' && *str <= 'F'))) {
662: n++;
663: str++;
664: }
665: if (n < 1 || n > 4) {
666: return 0;
667: }
668: if (++blocks > 8)
669: return 0;
670: }
671: return ((compressed && blocks <= 8) || blocks == 8);
672: }
673: /* }}} */
674:
675: void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
676: {
677: /* validates an ipv4 or ipv6 IP, based on the flag (4, 6, or both) add a
678: * flag to throw out reserved ranges; multicast ranges... etc. If both
679: * allow_ipv4 and allow_ipv6 flags flag are used, then the first dot or
680: * colon determine the format */
681:
682: int ip[4];
683: int mode;
684:
685: if (memchr(Z_STRVAL_P(value), ':', Z_STRLEN_P(value))) {
686: mode = FORMAT_IPV6;
687: } else if (memchr(Z_STRVAL_P(value), '.', Z_STRLEN_P(value))) {
688: mode = FORMAT_IPV4;
689: } else {
690: RETURN_VALIDATION_FAILED
691: }
692:
693: if ((flags & FILTER_FLAG_IPV4) && (flags & FILTER_FLAG_IPV6)) {
694: /* Both formats are cool */
695: } else if ((flags & FILTER_FLAG_IPV4) && mode == FORMAT_IPV6) {
696: RETURN_VALIDATION_FAILED
697: } else if ((flags & FILTER_FLAG_IPV6) && mode == FORMAT_IPV4) {
698: RETURN_VALIDATION_FAILED
699: }
700:
701: switch (mode) {
702: case FORMAT_IPV4:
703: if (!_php_filter_validate_ipv4(Z_STRVAL_P(value), Z_STRLEN_P(value), ip)) {
704: RETURN_VALIDATION_FAILED
705: }
706:
707: /* Check flags */
708: if (flags & FILTER_FLAG_NO_PRIV_RANGE) {
709: if (
710: (ip[0] == 10) ||
711: (ip[0] == 172 && (ip[1] >= 16 && ip[1] <= 31)) ||
712: (ip[0] == 192 && ip[1] == 168)
713: ) {
714: RETURN_VALIDATION_FAILED
715: }
716: }
717:
718: if (flags & FILTER_FLAG_NO_RES_RANGE) {
719: if (
720: (ip[0] == 0) ||
721: (ip[0] == 128 && ip[1] == 0) ||
722: (ip[0] == 191 && ip[1] == 255) ||
723: (ip[0] == 169 && ip[1] == 254) ||
724: (ip[0] == 192 && ip[1] == 0 && ip[2] == 2) ||
725: (ip[0] == 127 && ip[1] == 0 && ip[2] == 0 && ip[3] == 1) ||
726: (ip[0] >= 224 && ip[0] <= 255)
727: ) {
728: RETURN_VALIDATION_FAILED
729: }
730: }
731: break;
732:
733: case FORMAT_IPV6:
734: {
735: int res = 0;
736: res = _php_filter_validate_ipv6(Z_STRVAL_P(value), Z_STRLEN_P(value) TSRMLS_CC);
737: if (res < 1) {
738: RETURN_VALIDATION_FAILED
739: }
740: /* Check flags */
741: if (flags & FILTER_FLAG_NO_PRIV_RANGE) {
742: if (Z_STRLEN_P(value) >=2 && (!strncasecmp("FC", Z_STRVAL_P(value), 2) || !strncasecmp("FD", Z_STRVAL_P(value), 2))) {
743: RETURN_VALIDATION_FAILED
744: }
745: }
746: if (flags & FILTER_FLAG_NO_RES_RANGE) {
747: switch (Z_STRLEN_P(value)) {
748: case 1: case 0:
749: break;
750: case 2:
751: if (!strcmp("::", Z_STRVAL_P(value))) {
752: RETURN_VALIDATION_FAILED
753: }
754: break;
755: case 3:
756: if (!strcmp("::1", Z_STRVAL_P(value)) || !strcmp("5f:", Z_STRVAL_P(value))) {
757: RETURN_VALIDATION_FAILED
758: }
759: break;
760: default:
761: if (Z_STRLEN_P(value) >= 5) {
762: if (
763: !strncasecmp("fe8", Z_STRVAL_P(value), 3) ||
764: !strncasecmp("fe9", Z_STRVAL_P(value), 3) ||
765: !strncasecmp("fea", Z_STRVAL_P(value), 3) ||
766: !strncasecmp("feb", Z_STRVAL_P(value), 3)
767: ) {
768: RETURN_VALIDATION_FAILED
769: }
770: }
771: if (
772: (Z_STRLEN_P(value) >= 9 && !strncasecmp("2001:0db8", Z_STRVAL_P(value), 9)) ||
773: (Z_STRLEN_P(value) >= 2 && !strncasecmp("5f", Z_STRVAL_P(value), 2)) ||
774: (Z_STRLEN_P(value) >= 4 && !strncasecmp("3ff3", Z_STRVAL_P(value), 4)) ||
775: (Z_STRLEN_P(value) >= 8 && !strncasecmp("2001:001", Z_STRVAL_P(value), 8))
776: ) {
777: RETURN_VALIDATION_FAILED
778: }
779: }
780: }
781: }
782: break;
783: }
784: }
785: /* }}} */
786:
787: /*
788: * Local variables:
789: * tab-width: 4
790: * c-basic-offset: 4
791: * End:
792: * vim600: noet sw=4 ts=4 fdm=marker
793: * vim<600: noet sw=4 ts=4
794: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>