|
| 1 | +require 'ipaddr' |
| 2 | + |
1 | 3 | module CloudController |
2 | 4 | class RuleValidator |
3 | 5 | class_attribute :required_fields, :optional_fields |
@@ -53,11 +55,7 @@ def self.validate_destination(destination) |
53 | 55 | ips = parse_ip(address_list) |
54 | 56 | return false if ips.nil? |
55 | 57 |
|
56 | | - sorted_ips = if ips.first.is_a?(NetAddr::IPv4) |
57 | | - NetAddr.sort_IPv4(ips) |
58 | | - else |
59 | | - NetAddr.sort_IPv6(ips) |
60 | | - end |
| 58 | + sorted_ips = ips.sort |
61 | 59 |
|
62 | 60 | return true if ips.first == sorted_ips.first |
63 | 61 | end |
@@ -122,26 +120,46 @@ def self.no_leading_zeros(destination) |
122 | 120 |
|
123 | 121 | private_class_method def self.parse_ipv4(val) |
124 | 122 | if val.is_a?(Array) |
125 | | - val.map do |ip| |
126 | | - NetAddr::IPv4.parse(ip) |
127 | | - end |
| 123 | + val.map { |ip| parse_address(ip, :ipv4?) } |
128 | 124 | else |
129 | | - NetAddr::IPv4Net.parse(val) |
| 125 | + parse_cidr(val, :ipv4?) |
130 | 126 | end |
131 | | - rescue NetAddr::ValidationError |
| 127 | + rescue IPAddr::Error |
132 | 128 | nil |
133 | 129 | end |
134 | 130 |
|
135 | 131 | private_class_method def self.parse_ipv6(val) |
136 | 132 | if val.is_a?(Array) |
137 | | - val.map do |ip| |
138 | | - NetAddr::IPv6.parse(ip) |
139 | | - end |
| 133 | + val.map { |ip| parse_address(ip, :ipv6?) } |
140 | 134 | else |
141 | | - NetAddr::IPv6Net.parse(val) |
| 135 | + parse_cidr(val, :ipv6?) |
142 | 136 | end |
143 | | - rescue NetAddr::ValidationError |
| 137 | + rescue IPAddr::Error |
144 | 138 | nil |
145 | 139 | end |
| 140 | + |
| 141 | + # A range endpoint must be a plain address, so a prefix is not allowed here. |
| 142 | + private_class_method def self.parse_address(val, family) |
| 143 | + raise IPAddr::InvalidAddressError if val.include?('/') |
| 144 | + |
| 145 | + parse_cidr(val, family) |
| 146 | + end |
| 147 | + |
| 148 | + private_class_method def self.parse_cidr(val, family) |
| 149 | + ip = IPAddr.new(drop_leading_zeros(val)) |
| 150 | + raise IPAddr::InvalidAddressError unless ip.public_send(family) |
| 151 | + |
| 152 | + ip |
| 153 | + end |
| 154 | + |
| 155 | + # IPAddr rejects zero-padded IPv4 octets (e.g. '010.0.0.53'); normalise them to plain decimals. |
| 156 | + private_class_method def self.drop_leading_zeros(val) |
| 157 | + return val unless val.include?('.') |
| 158 | + |
| 159 | + addr, prefix = val.split('/', 2) |
| 160 | + # For every octet, delete its leading zeros when a digit follows (e.g. '03.005.10.02' -> '3.5.10.2', but a lone '0' stays); non-numeric octets are left for IPAddr to reject. |
| 161 | + addr = addr.split('.').map { |octet| octet.sub(/\A0+(?=\d)/, '') }.join('.') |
| 162 | + prefix ? "#{addr}/#{prefix}" : addr |
| 163 | + end |
146 | 164 | end |
147 | 165 | end |
0 commit comments