9191#define FORMAT_IPV4 4
9292#define FORMAT_IPV6 6
9393
94- static int _php_filter_validate_ipv6 (char * str , size_t str_len );
94+ static int _php_filter_validate_ipv6 (char * str , size_t str_len , int ip [ 8 ] );
9595
9696static int php_filter_parse_int (const char * str , size_t str_len , zend_long * ret ) { /* {{{ */
9797 zend_long ctx_value ;
@@ -609,7 +609,7 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
609609 t = e - 1 ;
610610
611611 /* An IPv6 enclosed by square brackets is a valid hostname */
612- if (* s == '[' && * t == ']' && _php_filter_validate_ipv6 ((s + 1 ), l - 2 )) {
612+ if (* s == '[' && * t == ']' && _php_filter_validate_ipv6 ((s + 1 ), l - 2 , NULL )) {
613613 php_url_free (url );
614614 return ;
615615 }
@@ -749,11 +749,11 @@ static int _php_filter_validate_ipv4(char *str, size_t str_len, int *ip) /* {{{
749749}
750750/* }}} */
751751
752- static int _php_filter_validate_ipv6 (char * str , size_t str_len ) /* {{{ */
752+ static int _php_filter_validate_ipv6 (char * str , size_t str_len , int ip [ 8 ] ) /* {{{ */
753753{
754- int compressed = 0 ;
754+ int compressed_pos = -1 ;
755755 int blocks = 0 ;
756- int n ;
756+ int num , n , i ;
757757 char * ipv4 ;
758758 char * end ;
759759 int ip4elm [4 ];
@@ -796,35 +796,67 @@ static int _php_filter_validate_ipv6(char *str, size_t str_len) /* {{{ */
796796 return 0 ;
797797 }
798798 if (* str == ':' ) {
799- if (compressed ) {
799+ if (compressed_pos >= 0 ) {
800800 return 0 ;
801801 }
802- blocks ++ ; /* :: means 1 or more 16-bit 0 blocks */
803- compressed = 1 ;
804-
802+ if (ip && blocks < 8 ) {
803+ ip [blocks ] = -1 ;
804+ }
805+ compressed_pos = blocks ++ ; /* :: means 1 or more 16-bit 0 blocks */
805806 if (++ str == end ) {
806- return (blocks <= 8 );
807+ if (blocks > 8 ) {
808+ return 0 ;
809+ }
810+ goto fixup_ip ;
807811 }
808812 } else if ((str - 1 ) == s ) {
809813 /* don't allow leading : without another : following */
810814 return 0 ;
811815 }
812816 }
813- n = 0 ;
814- while ((str < end ) &&
815- ((* str >= '0' && * str <= '9' ) ||
816- (* str >= 'a' && * str <= 'f' ) ||
817- (* str >= 'A' && * str <= 'F' ))) {
817+ num = n = 0 ;
818+ while (str < end ) {
819+ if (* str >= '0' && * str <= '9' ) {
820+ num = 16 * num + (* str - '0' );
821+ } else if (* str >= 'a' && * str <= 'f' ) {
822+ num = 16 * num + (* str - 'a' ) + 10 ;
823+ } else if (* str >= 'A' && * str <= 'F' ) {
824+ num = 16 * num + (* str - 'A' ) + 10 ;
825+ } else {
826+ break ;
827+ }
818828 n ++ ;
819829 str ++ ;
820830 }
831+ if (ip && blocks < 8 ) {
832+ ip [blocks ] = num ;
833+ }
821834 if (n < 1 || n > 4 ) {
822835 return 0 ;
823836 }
824837 if (++ blocks > 8 )
825838 return 0 ;
826839 }
827- return ((compressed && blocks <= 8 ) || blocks == 8 );
840+
841+ fixup_ip :
842+ if (ip && ipv4 ) {
843+ for (i = 0 ; i < 5 ; i ++ ) {
844+ ip [i ] = 0 ;
845+ }
846+ ip [i ++ ] = 0xffff ;
847+ ip [i ++ ] = 256 * ip4elm [0 ] + ip4elm [1 ];
848+ ip [i ++ ] = 256 * ip4elm [2 ] + ip4elm [3 ];
849+ } else if (ip && compressed_pos >= 0 && blocks <= 8 ) {
850+ int offset = 8 - blocks ;
851+ for (i = 7 ; i > compressed_pos + offset ; i -- ) {
852+ ip [i ] = ip [i - offset ];
853+ }
854+ for (i = compressed_pos + offset ; i >= compressed_pos ; i -- ) {
855+ ip [i ] = 0 ;
856+ }
857+ }
858+
859+ return (compressed_pos >= 0 && blocks <= 8 ) || blocks == 8 ;
828860}
829861/* }}} */
830862
@@ -835,7 +867,7 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
835867 * allow_ipv4 and allow_ipv6 flags flag are used, then the first dot or
836868 * colon determine the format */
837869
838- int ip [4 ];
870+ int ip [8 ];
839871 int mode ;
840872
841873 if (memchr (Z_STRVAL_P (value ), ':' , Z_STRLEN_P (value ))) {
@@ -886,49 +918,25 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
886918 case FORMAT_IPV6 :
887919 {
888920 int res = 0 ;
889- res = _php_filter_validate_ipv6 (Z_STRVAL_P (value ), Z_STRLEN_P (value ));
921+ res = _php_filter_validate_ipv6 (Z_STRVAL_P (value ), Z_STRLEN_P (value ), ip );
890922 if (res < 1 ) {
891923 RETURN_VALIDATION_FAILED
892924 }
893925 /* Check flags */
894926 if (flags & FILTER_FLAG_NO_PRIV_RANGE ) {
895- if (Z_STRLEN_P ( value ) >=2 && (! strncasecmp ( "FC" , Z_STRVAL_P ( value ), 2 ) || ! strncasecmp ( "FD" , Z_STRVAL_P ( value ), 2 )) ) {
927+ if (ip [ 0 ] >= 0xfc00 && ip [ 0 ] <= 0xfdff ) {
896928 RETURN_VALIDATION_FAILED
897929 }
898930 }
899931 if (flags & FILTER_FLAG_NO_RES_RANGE ) {
900- switch (Z_STRLEN_P (value )) {
901- case 1 : case 0 :
902- break ;
903- case 2 :
904- if (!strcmp ("::" , Z_STRVAL_P (value ))) {
905- RETURN_VALIDATION_FAILED
906- }
907- break ;
908- case 3 :
909- if (!strcmp ("::1" , Z_STRVAL_P (value )) || !strcmp ("5f:" , Z_STRVAL_P (value ))) {
910- RETURN_VALIDATION_FAILED
911- }
912- break ;
913- default :
914- if (Z_STRLEN_P (value ) >= 5 ) {
915- if (
916- !strncasecmp ("fe8" , Z_STRVAL_P (value ), 3 ) ||
917- !strncasecmp ("fe9" , Z_STRVAL_P (value ), 3 ) ||
918- !strncasecmp ("fea" , Z_STRVAL_P (value ), 3 ) ||
919- !strncasecmp ("feb" , Z_STRVAL_P (value ), 3 )
920- ) {
921- RETURN_VALIDATION_FAILED
922- }
923- }
924- if (
925- (Z_STRLEN_P (value ) >= 9 && !strncasecmp ("2001:0db8" , Z_STRVAL_P (value ), 9 )) ||
926- (Z_STRLEN_P (value ) >= 2 && !strncasecmp ("5f" , Z_STRVAL_P (value ), 2 )) ||
927- (Z_STRLEN_P (value ) >= 4 && !strncasecmp ("3ff3" , Z_STRVAL_P (value ), 4 )) ||
928- (Z_STRLEN_P (value ) >= 8 && !strncasecmp ("2001:001" , Z_STRVAL_P (value ), 8 ))
929- ) {
930- RETURN_VALIDATION_FAILED
931- }
932+ if ((ip [0 ] == 0 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] == 0
933+ && ip [4 ] == 0 && ip [5 ] == 0 && ip [6 ] == 0 && (ip [7 ] == 0 || ip [7 ] == 1 ))
934+ || (ip [0 ] == 0x5f )
935+ || (ip [0 ] >= 0xfe80 && ip [0 ] <= 0xfebf )
936+ || ((ip [0 ] == 0x2001 && ip [1 ] == 0x0db8 ) || (ip [1 ] >= 0x0010 && ip [1 ] <= 0x001f ))
937+ || (ip [0 ] == 0x3ff3 )
938+ ) {
939+ RETURN_VALIDATION_FAILED
932940 }
933941 }
934942 }
0 commit comments