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