8989#define FORMAT_IPV4 4
9090#define FORMAT_IPV6 6
9191
92- static int _php_filter_validate_ipv6 (char * str , size_t str_len );
92+ static int _php_filter_validate_ipv6 (char * str , size_t str_len , int ip [ 8 ] );
9393
9494static int php_filter_parse_int (const char * str , size_t str_len , zend_long * ret ) { /* {{{ */
9595 zend_long ctx_value ;
@@ -613,7 +613,7 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
613613 t = e - 1 ;
614614
615615 /* An IPv6 enclosed by square brackets is a valid hostname */
616- if (* s == '[' && * t == ']' && _php_filter_validate_ipv6 ((s + 1 ), l - 2 )) {
616+ if (* s == '[' && * t == ']' && _php_filter_validate_ipv6 ((s + 1 ), l - 2 , NULL )) {
617617 php_url_free (url );
618618 return ;
619619 }
@@ -753,11 +753,11 @@ static int _php_filter_validate_ipv4(char *str, size_t str_len, int *ip) /* {{{
753753}
754754/* }}} */
755755
756- static int _php_filter_validate_ipv6 (char * str , size_t str_len ) /* {{{ */
756+ static int _php_filter_validate_ipv6 (char * str , size_t str_len , int ip [ 8 ] ) /* {{{ */
757757{
758- int compressed = 0 ;
758+ int compressed_pos = -1 ;
759759 int blocks = 0 ;
760- int n ;
760+ int num , n , i ;
761761 char * ipv4 ;
762762 char * end ;
763763 int ip4elm [4 ];
@@ -800,35 +800,67 @@ static int _php_filter_validate_ipv6(char *str, size_t str_len) /* {{{ */
800800 return 0 ;
801801 }
802802 if (* str == ':' ) {
803- if (compressed ) {
803+ if (compressed_pos >= 0 ) {
804804 return 0 ;
805805 }
806- blocks ++ ; /* :: means 1 or more 16-bit 0 blocks */
807- compressed = 1 ;
808-
806+ if (ip && blocks < 8 ) {
807+ ip [blocks ] = -1 ;
808+ }
809+ compressed_pos = blocks ++ ; /* :: means 1 or more 16-bit 0 blocks */
809810 if (++ str == end ) {
810- return (blocks <= 8 );
811+ if (blocks > 8 ) {
812+ return 0 ;
813+ }
814+ goto fixup_ip ;
811815 }
812816 } else if ((str - 1 ) == s ) {
813817 /* don't allow leading : without another : following */
814818 return 0 ;
815819 }
816820 }
817- n = 0 ;
818- while ((str < end ) &&
819- ((* str >= '0' && * str <= '9' ) ||
820- (* str >= 'a' && * str <= 'f' ) ||
821- (* str >= 'A' && * str <= 'F' ))) {
821+ num = n = 0 ;
822+ while (str < end ) {
823+ if (* str >= '0' && * str <= '9' ) {
824+ num = 16 * num + (* str - '0' );
825+ } else if (* str >= 'a' && * str <= 'f' ) {
826+ num = 16 * num + (* str - 'a' ) + 10 ;
827+ } else if (* str >= 'A' && * str <= 'F' ) {
828+ num = 16 * num + (* str - 'A' ) + 10 ;
829+ } else {
830+ break ;
831+ }
822832 n ++ ;
823833 str ++ ;
824834 }
835+ if (ip && blocks < 8 ) {
836+ ip [blocks ] = num ;
837+ }
825838 if (n < 1 || n > 4 ) {
826839 return 0 ;
827840 }
828841 if (++ blocks > 8 )
829842 return 0 ;
830843 }
831- return ((compressed && blocks <= 8 ) || blocks == 8 );
844+
845+ fixup_ip :
846+ if (ip && ipv4 ) {
847+ for (i = 0 ; i < 5 ; i ++ ) {
848+ ip [i ] = 0 ;
849+ }
850+ ip [i ++ ] = 0xffff ;
851+ ip [i ++ ] = 256 * ip4elm [0 ] + ip4elm [1 ];
852+ ip [i ++ ] = 256 * ip4elm [2 ] + ip4elm [3 ];
853+ } else if (ip && compressed_pos >= 0 && blocks <= 8 ) {
854+ int offset = 8 - blocks ;
855+ for (i = 7 ; i > compressed_pos + offset ; i -- ) {
856+ ip [i ] = ip [i - offset ];
857+ }
858+ for (i = compressed_pos + offset ; i >= compressed_pos ; i -- ) {
859+ ip [i ] = 0 ;
860+ }
861+ }
862+
863+ return (compressed_pos >= 0 && blocks <= 8 ) || blocks == 8 ;
832864}
833865/* }}} */
834866
@@ -839,7 +871,7 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
839871 * allow_ipv4 and allow_ipv6 flags flag are used, then the first dot or
840872 * colon determine the format */
841873
842- int ip [4 ];
874+ int ip [8 ];
843875 int mode ;
844876
845877 if (memchr (Z_STRVAL_P (value ), ':' , Z_STRLEN_P (value ))) {
@@ -890,52 +922,28 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
890922 case FORMAT_IPV6 :
891923 {
892924 int res = 0 ;
893- res = _php_filter_validate_ipv6 (Z_STRVAL_P (value ), Z_STRLEN_P (value ));
925+ res = _php_filter_validate_ipv6 (Z_STRVAL_P (value ), Z_STRLEN_P (value ), ip );
894926 if (res < 1 ) {
895927 RETURN_VALIDATION_FAILED
896928 }
897929 /* Check flags */
898930 if (flags & FILTER_FLAG_NO_PRIV_RANGE ) {
899- if (Z_STRLEN_P ( value ) >=2 && (! strncasecmp ( "FC" , Z_STRVAL_P ( value ), 2 ) || ! strncasecmp ( "FD" , Z_STRVAL_P ( value ), 2 )) ) {
931+ if (ip [ 0 ] >= 0xfc00 && ip [ 0 ] <= 0xfdff ) {
900932 RETURN_VALIDATION_FAILED
901933 }
902934 }
903935 if (flags & FILTER_FLAG_NO_RES_RANGE ) {
904- switch (Z_STRLEN_P (value )) {
905- case 1 : case 0 :
906- break ;
907- case 2 :
908- if (zend_string_equals_literal (Z_STR_P (value ), "::" )) {
909- RETURN_VALIDATION_FAILED
910- }
911- break ;
912- case 3 :
913- if (zend_string_equals_literal (Z_STR_P (value ), "::1" ) || zend_string_equals_literal (Z_STR_P (value ), "5f:" )) {
914- RETURN_VALIDATION_FAILED
915- }
916- break ;
917- default :
918- if (Z_STRLEN_P (value ) >= 5 ) {
919- if (
920- !strncasecmp ("fe8" , Z_STRVAL_P (value ), 3 ) ||
921- !strncasecmp ("fe9" , Z_STRVAL_P (value ), 3 ) ||
922- !strncasecmp ("fea" , Z_STRVAL_P (value ), 3 ) ||
923- !strncasecmp ("feb" , Z_STRVAL_P (value ), 3 )
936+ if ((ip [0 ] == 0 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] == 0
937+ && ip [4 ] == 0 && ip [5 ] == 0 && ip [6 ] == 0 && (ip [7 ] == 0 || ip [7 ] == 1 ))
938+ || (ip [0 ] == 0x5f )
939+ || (ip [0 ] >= 0xfe80 && ip [0 ] <= 0xfebf )
940+ || ((ip [0 ] == 0x2001 && ip [1 ] == 0x0db8 ) || (ip [1 ] >= 0x0010 && ip [1 ] <= 0x001f ))
941+ || (ip [0 ] == 0x3ff3 )
924942 ) {
925943 RETURN_VALIDATION_FAILED
926944 }
927945 }
928- if (
929- (Z_STRLEN_P (value ) >= 9 && !strncasecmp ("2001:0db8" , Z_STRVAL_P (value ), 9 )) ||
930- (Z_STRLEN_P (value ) >= 2 && !strncasecmp ("5f" , Z_STRVAL_P (value ), 2 )) ||
931- (Z_STRLEN_P (value ) >= 4 && !strncasecmp ("3ff3" , Z_STRVAL_P (value ), 4 )) ||
932- (Z_STRLEN_P (value ) >= 8 && !strncasecmp ("2001:001" , Z_STRVAL_P (value ), 8 ))
933- ) {
934- RETURN_VALIDATION_FAILED
935946 }
936- }
937- }
938- }
939947 break ;
940948 }
941949}
0 commit comments