/* * ZLint Copyright 2018 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 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 } 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"}, lisp: {"2001:5::/32"}, // TODO: this could expire at 2019-09. Please check https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml for updates 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) } } }