1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
/*
* ZLint Copyright 2024 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// contains helper functions for ip address lints
package util
import (
"fmt"
"net"
)
type subnetCategory int
const (
privateUse subnetCategory = iota
sharedAddressSpace
benchmarking
documentation
reserved
protocolAssignment
as112
amt
orchidV2
_ // deprecated: lisp
thisHostOnThisNetwork
translatableAddress6to4
translatableAddress4to6
dummyAddress
portControlProtocolAnycast
traversalUsingRelaysAroundNATAnycast
nat64DNS64Discovery
limitedBroadcast
discardOnly
teredo
uniqueLocal
linkLocalUnicast
ianaReservedForFutureUse
ianaReservedMulticast
)
var reservedNetworks []*net.IPNet
// IsIANAReserved checks IP validity as per IANA reserved IPs
//
// IPv4
// https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
// https://www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xml
// IPv6
// https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
// https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
func IsIANAReserved(ip net.IP) bool {
if !ip.IsGlobalUnicast() {
return true
}
for _, network := range reservedNetworks {
if network.Contains(ip) {
return true
}
}
return false
}
// IntersectsIANAReserved checks if a CIDR intersects any IANA reserved CIDRs
func IntersectsIANAReserved(net net.IPNet) bool {
if !net.IP.IsGlobalUnicast() {
return true
}
for _, reserved := range reservedNetworks {
if reserved.Contains(net.IP) || net.Contains(reserved.IP) {
return true
}
}
return false
}
func init() {
var networks = map[subnetCategory][]string{
privateUse: {"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"},
sharedAddressSpace: {"100.64.0.0/10"},
benchmarking: {"198.18.0.0/15", "2001:2::/48"},
documentation: {"192.0.2.0/24", "198.51.100.0/24", "203.0.113.0/24", "2001:db8::/32"},
reserved: {"240.0.0.0/4", "0400::/6", "0800::/5", "1000::/4", "4000::/3", "6000::/3", "8000::/3", "a000::/3", "c000::/3", "e000::/4", "f000::/5", "f800::/6", "fe00::/9"}, // https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
protocolAssignment: {"192.0.0.0/24", "2001::/23"}, // 192.0.0.0/24 contains 192.0.0.0/29 - IPv4 Service Continuity Prefix
as112: {"192.31.196.0/24", "192.175.48.0/24", "2001:4:112::/48", "2620:4f:8000::/48"},
amt: {"192.52.193.0/24", "2001:3::/32"},
orchidV2: {"2001:20::/28"},
thisHostOnThisNetwork: {"0.0.0.0/8"},
translatableAddress4to6: {"2002::/16"},
translatableAddress6to4: {"64:ff9b::/96", "64:ff9b:1::/48"},
dummyAddress: {"192.0.0.8/32"},
portControlProtocolAnycast: {"192.0.0.9/32", "2001:1::1/128"},
traversalUsingRelaysAroundNATAnycast: {"192.0.0.10/32", "2001:1::2/128"},
nat64DNS64Discovery: {"192.0.0.170/32", "192.0.0.171/32"},
limitedBroadcast: {"255.255.255.255/32"},
discardOnly: {"100::/64"},
teredo: {"2001::/32"},
uniqueLocal: {"fc00::/7"},
linkLocalUnicast: {"fe80::/10", "169.254.0.0/16"}, // this range is covered by ip.IsLinkLocalUnicast(), which is in turn called by net.IP.IsGlobalUnicast(ip)
ianaReservedForFutureUse: {"255.0.0.0/8", "254.0.0.0/8", "253.0.0.0/8", "252.0.0.0/8", "251.0.0.0/8", "250.0.0.0/8", "249.0.0.0/8", "248.0.0.0/8", "247.0.0.0/8", "246.0.0.0/8", "245.0.0.0/8", "244.0.0.0/8", "243.0.0.0/8", "242.0.0.0/8", "241.0.0.0/8", "240.0.0.0/8"},
ianaReservedMulticast: {"239.0.0.0/8", "238.0.0.0/8", "237.0.0.0/8", "236.0.0.0/8", "235.0.0.0/8", "234.0.0.0/8", "233.0.0.0/8", "232.0.0.0/8", "231.0.0.0/8", "230.0.0.0/8", "229.0.0.0/8", "228.0.0.0/8", "227.0.0.0/8", "226.0.0.0/8", "225.0.0.0/8", "224.0.0.0/8", "ff00::/8"}, // this range is covered by ip.IsMulticast() call, which is in turn called by net.IP.IsGlobalUnicast(ip)
}
for _, netList := range networks {
for _, network := range netList {
var ipNet *net.IPNet
var err error
if _, ipNet, err = net.ParseCIDR(network); err != nil {
panic(fmt.Sprintf("unexpected internal network value provided: %s", err.Error()))
}
reservedNetworks = append(reservedNetworks, ipNet)
}
}
}
|