@@ -869,15 +869,120 @@ static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8])
869869}
870870/* }}} */
871871
872- void php_filter_validate_ip (PHP_INPUT_FILTER_PARAM_DECL ) /* {{{ */
872+ /* From the tables in RFC 6890 - Special-Purpose IP Address Registriesi
873+ * Including errata: https://www.rfc-editor.org/errata_search.php?rfc=6890&rec_status=1 */
874+ static bool ipv4_get_status_flags (const int ip [8 ], bool * global , bool * reserved , bool * private )
875+ {
876+ * global = false;
877+ * reserved = false;
878+ * private = false;
879+
880+ if (ip [0 ] == 0 ) {
881+ /* RFC 0791 - This network */
882+ * reserved = true;
883+ } else if (ip [0 ] == 0 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] == 0 ) {
884+ /* RFC 1122 - This host on this network */
885+ * reserved = true;
886+ } else if (ip [0 ] == 10 ) {
887+ /* RFC 1918 - Private Use */
888+ * private = true;
889+ } else if (ip [0 ] == 100 && ip [1 ] >= 64 && ip [1 ] <= 127 ) {
890+ /* RFC 6598 - Shared Address Space */
891+ } else if (ip [0 ] == 127 ) {
892+ /* RFC 1122 - Loopback */
893+ * reserved = true;
894+ } else if (ip [0 ] == 169 && ip [1 ] == 254 ) {
895+ /* RFC 3927 - Link Local */
896+ * reserved = true;
897+ } else if (ip [0 ] == 172 && ip [1 ] >= 16 && ip [1 ] <= 31 ) {
898+ /* RFC 1918 - Private Use */
899+ * private = true;
900+ } else if (ip [0 ] == 192 && ip [1 ] == 0 && ip [2 ] == 0 ) {
901+ /* RFC 6890 - IETF Protocol Assignments */
902+ } else if (ip [0 ] == 192 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] >= 0 && ip [3 ] <= 7 ) {
903+ /* RFC 6333 - DS-Lite */
904+ } else if (ip [0 ] == 192 && ip [1 ] == 0 && ip [2 ] == 2 ) {
905+ /* RFC 5737 - Documentation */
906+ } else if (ip [0 ] == 192 && ip [1 ] == 88 && ip [2 ] == 99 ) {
907+ /* RFC 3068 - 6to4 Relay Anycast */
908+ * global = true;
909+ } else if (ip [0 ] == 192 && ip [1 ] == 168 ) {
910+ /* RFC 1918 - Private Use */
911+ * private = true;
912+ } else if (ip [0 ] == 198 && ip [1 ] >= 18 && ip [1 ] <= 19 ) {
913+ /* RFC 2544 - Benchmarking */
914+ } else if (ip [0 ] == 198 && ip [1 ] == 51 && ip [2 ] == 100 ) {
915+ /* RFC 5737 - Documentation */
916+ } else if (ip [0 ] == 203 && ip [1 ] == 0 && ip [2 ] == 113 ) {
917+ /* RFC 5737 - Documentation */
918+ } else if (ip [0 ] >= 240 && ip [1 ] <= 255 ) {
919+ /* RFC 1122 - Reserved */
920+ * reserved = true;
921+ } else if (ip [0 ] == 255 && ip [1 ] == 255 && ip [2 ] == 255 && ip [3 ] == 255 ) {
922+ /* RFC 0919 - Limited Broadcast, Updated by RFC 8190, 2.2. */
923+ * reserved = true;
924+ } else {
925+ return false;
926+ }
927+
928+ return true;
929+ }
930+
931+ /* From the tables in RFC 6890 - Special-Purpose IP Address Registries */
932+ static bool ipv6_get_status_flags (const int ip [8 ], bool * global , bool * reserved , bool * private )
873933{
874- /* validates an ipv4 or ipv6 IP, based on the flag (4, 6, or both) add a
875- * flag to throw out reserved ranges; multicast ranges... etc. If both
876- * allow_ipv4 and allow_ipv6 flags flag are used, then the first dot or
877- * colon determine the format */
934+ * global = false;
935+ * reserved = false;
936+ * private = false;
937+
938+ if (ip [0 ] == 0 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] == 0 && ip [4 ] == 0 && ip [5 ] == 0 && ip [6 ] == 0 && ip [7 ] == 0 ) {
939+ /* RFC 4291 - Unspecified Address */
940+ * reserved = true;
941+ } else if (ip [0 ] == 0 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] == 0 && ip [4 ] == 0 && ip [5 ] == 0 && ip [6 ] == 0 && ip [7 ] == 1 ) {
942+ /* RFC 4291 - Loopback Address */
943+ * reserved = true;
944+ } else if (ip [0 ] == 0x0064 && ip [1 ] == 0xff9b ) {
945+ /* RFC 6052 - IPv4-IPv6 Translation */
946+ * global = true;
947+ } else if (ip [0 ] == 0 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] == 0 && ip [4 ] == 0 && ip [5 ] == 0xffff ) {
948+ /* RFC 4291 - IPv4-mapped Address */
949+ * reserved = true;
950+ } else if (ip [0 ] == 0x0100 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] == 0 ) {
951+ /* RFC 6666 - Discard-Only Address Block */
952+ } else if (ip [0 ] == 0x2001 && ip [1 ] == 0x0000 ) {
953+ /* RFC 4380 - TEREDO */
954+ } else if (ip [0 ] == 0x2001 && ip [1 ] <= 0x01ff ) {
955+ /* RFC 2928 - IETF Protocol Assignments */
956+ } else if (ip [0 ] == 0x2001 && ip [1 ] == 0x0002 && ip [2 ] == 0 ) {
957+ /* RFC 5180 - Benchmarking */
958+ } else if (ip [0 ] == 0x2001 && ip [1 ] == 0x0db8 ) {
959+ /* RFC 3849 - Documentation */
960+ } else if (ip [0 ] == 0x2001 && ip [1 ] >= 0x0010 && ip [1 ] <= 0x001f ) {
961+ /* RFC 4843 - ORCHID */
962+ } else if (ip [0 ] == 0x2002 ) {
963+ /* RFC 3056 - 6to4 */
964+ } else if (ip [0 ] >= 0xfc00 && ip [0 ] <= 0xfdff ) {
965+ /* RFC 4193 - Unique-Local */
966+ * private = true;
967+ } else if (ip [0 ] >= 0xfe80 && ip [0 ] <= 0xfebf ) {
968+ /* RFC 4291 - Linked-Scoped Unicast */
969+ * reserved = true;
970+ } else {
971+ return false;
972+ }
878973
879- int ip [8 ];
880- int mode ;
974+ return true;
975+ }
976+
977+ /* Validates an ipv4 or ipv6 IP, based on the flag (4, 6, or both) add a flag
978+ * to throw out reserved ranges; multicast ranges... etc. If both allow_ipv4
979+ * and allow_ipv6 flags flag are used, then the first dot or colon determine
980+ * the format */
981+ void php_filter_validate_ip (PHP_INPUT_FILTER_PARAM_DECL ) /* {{{ */
982+ {
983+ int ip [8 ];
984+ int mode ;
985+ bool flag_global , flag_reserved , flag_private ; /* flags for ranges as determined by RFC 6890 */
881986
882987 if (memchr (Z_STRVAL_P (value ), ':' , Z_STRLEN_P (value ))) {
883988 mode = FORMAT_IPV6 ;
@@ -895,86 +1000,35 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
8951000 RETURN_VALIDATION_FAILED
8961001 }
8971002
898- switch (mode ) {
899- case FORMAT_IPV4 :
900- if (!_php_filter_validate_ipv4 (Z_STRVAL_P (value ), Z_STRLEN_P (value ), ip )) {
901- RETURN_VALIDATION_FAILED
902- }
1003+ if (mode == FORMAT_IPV4 ) {
1004+ if (!_php_filter_validate_ipv4 (Z_STRVAL_P (value ), Z_STRLEN_P (value ), ip )) {
1005+ RETURN_VALIDATION_FAILED
1006+ }
9031007
904- /* Check flags */
905- if (flags & FILTER_FLAG_NO_PRIV_RANGE || flags & FILTER_FLAG_GLOBAL_RANGE ) {
906- if (
907- (ip [0 ] == 10 ) ||
908- (ip [0 ] == 172 && ip [1 ] >= 16 && ip [1 ] <= 31 ) ||
909- (ip [0 ] == 192 && ip [1 ] == 168 )
910- ) {
911- RETURN_VALIDATION_FAILED
912- }
913- }
1008+ if (!ipv4_get_status_flags (ip , & flag_global , & flag_reserved , & flag_private )) {
1009+ return ; /* no special block */
1010+ }
1011+ }
1012+ else if (mode == FORMAT_IPV6 ) {
1013+ if (_php_filter_validate_ipv6 (Z_STRVAL_P (value ), Z_STRLEN_P (value ), ip ) < 1 ) {
1014+ RETURN_VALIDATION_FAILED
1015+ }
9141016
915- if (flags & FILTER_FLAG_NO_RES_RANGE || flags & FILTER_FLAG_GLOBAL_RANGE ) {
916- if (
917- (ip [0 ] == 0 ) ||
918- (ip [0 ] >= 240 ) ||
919- (ip [0 ] == 127 ) ||
920- (ip [0 ] == 169 && ip [1 ] == 254 )
921- ) {
922- RETURN_VALIDATION_FAILED
923- }
924- }
1017+ if (!ipv6_get_status_flags (ip , & flag_global , & flag_reserved , & flag_private )) {
1018+ return ; /* no special block */
1019+ }
1020+ }
9251021
926- if (flags & FILTER_FLAG_GLOBAL_RANGE ) {
927- if (
928- (ip [0 ] == 100 && ip [1 ] >= 64 && ip [1 ] <= 127 ) ||
929- (ip [0 ] == 192 && ip [1 ] == 0 && ip [2 ] == 0 ) ||
930- (ip [0 ] == 192 && ip [1 ] == 0 && ip [2 ] == 2 ) ||
931- (ip [0 ] == 198 && ip [1 ] >= 18 && ip [1 ] <= 19 ) ||
932- (ip [0 ] == 198 && ip [1 ] == 51 && ip [2 ] == 100 ) ||
933- (ip [0 ] == 203 && ip [1 ] == 0 && ip [2 ] == 113 )
934- ) {
935- RETURN_VALIDATION_FAILED
936- }
937- }
1022+ if ((flags & FILTER_FLAG_GLOBAL_RANGE ) && flag_global != true) {
1023+ RETURN_VALIDATION_FAILED
1024+ }
9381025
939- break ;
1026+ if ((flags & FILTER_FLAG_NO_PRIV_RANGE ) && flag_private == true) {
1027+ RETURN_VALIDATION_FAILED
1028+ }
9401029
941- case FORMAT_IPV6 :
942- {
943- int res = 0 ;
944- res = _php_filter_validate_ipv6 (Z_STRVAL_P (value ), Z_STRLEN_P (value ), ip );
945- if (res < 1 ) {
946- RETURN_VALIDATION_FAILED
947- }
948- /* Check flags */
949- if (flags & FILTER_FLAG_NO_PRIV_RANGE || flags & FILTER_FLAG_GLOBAL_RANGE ) {
950- if (ip [0 ] >= 0xfc00 && ip [0 ] <= 0xfdff ) {
951- RETURN_VALIDATION_FAILED
952- }
953- }
954- if (flags & FILTER_FLAG_NO_RES_RANGE || flags & FILTER_FLAG_GLOBAL_RANGE ) {
955- if (
956- (ip [0 ] == 0 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] == 0 && ip [4 ] == 0 && ip [5 ] == 0 && ip [6 ] == 0 && (ip [7 ] == 0 || ip [7 ] == 1 )) ||
957- (ip [0 ] == 0x5f ) ||
958- (ip [0 ] >= 0xfe80 && ip [0 ] <= 0xfebf ) ||
959- (ip [0 ] == 0x2001 && (ip [1 ] == 0x0db8 || (ip [1 ] >= 0x0010 && ip [1 ] <= 0x001f ))) ||
960- (ip [0 ] == 0x3ff3 )
961- ) {
962- RETURN_VALIDATION_FAILED
963- }
964- }
965- if (flags & FILTER_FLAG_GLOBAL_RANGE ) {
966- if (
967- (ip [0 ] == 0 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] == 0 && ip [4 ] == 0 && ip [5 ] == 0xffff ) ||
968- (ip [0 ] == 0x0100 && ip [1 ] == 0 && ip [2 ] == 0 && ip [3 ] == 0 ) ||
969- (ip [0 ] == 0x2001 && ip [1 ] <= 0x01ff ) ||
970- (ip [0 ] == 0x2001 && ip [1 ] == 0x0002 && ip [2 ] == 0 ) ||
971- (ip [0 ] >= 0xfc00 && ip [0 ] <= 0xfdff )
972- ) {
973- RETURN_VALIDATION_FAILED
974- }
975- }
976- }
977- break ;
1030+ if ((flags & FILTER_FLAG_NO_RES_RANGE ) && flag_reserved == true) {
1031+ RETURN_VALIDATION_FAILED
9781032 }
9791033}
9801034/* }}} */
0 commit comments