blob: 721ed295025f321e11232c6ede4c66be4aada38c [file] [log] [blame]
Cosmos Nicolaou6c6fa112014-08-19 13:22:33 -07001package net
2
3import (
4 "fmt"
5 "net"
6
7 // TODO(cnicolaou): move this out of the runtimes and into here.
8 "veyron/runtimes/google/lib/netconfig"
9)
10
11// ipAndIf is a map of interface name to the set of IP addresses available on
12// that interface.
13type ipAndIf map[string][]net.IP
14
15func (ifcs ipAndIf) String() string {
16 r := ""
17 for k, v := range ifcs {
18 r += fmt.Sprintf("(%v: %v)", k, v)
19 }
20 return r
21}
22
23// empty returns true if there are no addresses on any interfaces.
24func (ifcs ipAndIf) empty() bool {
25 for _, addrs := range ifcs {
26 if len(addrs) > 0 {
27 return false
28 }
29 }
30 return true
31}
32
33func (ifcs ipAndIf) first() (string, net.IP) {
34 for ifc, addrs := range ifcs {
35 if len(addrs) > 0 {
36 return ifc, addrs[0]
37 }
38 }
39 return "", nil
40}
41
42func (ifcs ipAndIf) has(ip net.IP) bool {
43 for _, addrs := range ifcs {
44 for _, a := range addrs {
45 if a.Equal(ip) {
46 return true
47 }
48 }
49 }
50 return false
51}
52
53// ipState returns the set of IPv4 and IPv6 addresses available to the running
54// process.
55func ipState() (ip4, ip6 ipAndIf, err error) {
56 interfaces, err := net.Interfaces()
57 if err != nil {
58 return nil, nil, err
59 }
60 ip4 = make(ipAndIf)
61 ip6 = make(ipAndIf)
62 for _, ifc := range interfaces {
63 addrs, err := ifc.Addrs()
64 if err != nil {
65 continue
66 }
67 for _, addr := range addrs {
Cosmos Nicolaoub82cedb2014-08-24 18:12:01 -070068 ipn, ok := addr.(*net.IPNet)
69 if !ok {
Cosmos Nicolaou6c6fa112014-08-19 13:22:33 -070070 continue
71 }
Cosmos Nicolaoub82cedb2014-08-24 18:12:01 -070072 ip := ipn.IP
Cosmos Nicolaou6c6fa112014-08-19 13:22:33 -070073 if ip == nil || ip.IsLoopback() {
74 continue
75 }
76 if t := ip.To4(); t != nil {
77 ip4[ifc.Name] = append(ip4[ifc.Name], ip)
78 }
79 if t := ip.To16(); t != nil {
80 ip6[ifc.Name] = append(ip6[ifc.Name], ip)
81 }
82 }
83 }
84 return ip4, ip6, nil
85}
86
87func filterPublic(ips ipAndIf) ipAndIf {
88 public := make(ipAndIf)
89 for ifc, addrs := range ips {
90 for _, a := range addrs {
91 if publicIP(a) {
92 public[ifc] = append(public[ifc], a)
93 }
94 }
95 }
96 return public
97}
98
99// publicIPState returns the set of IPv4 and IPv6 addresses available
100// to the running process that are publicly/globally routable.
101func publicIPState() (ipAndIf, ipAndIf, error) {
102 v4, v6, err := ipState()
103 if err != nil {
104 return nil, nil, err
105 }
106 return filterPublic(v4), filterPublic(v6), nil
107}
108
109// publicIP returns true if the supplied IP address is publicly/gobally
110// routable.
111func publicIP(ip net.IP) bool {
112 if ip == nil {
113 return false
114 }
115 return netconfig.IsGloballyRoutable(ip)
116}
117
Cosmos Nicolaoub82cedb2014-08-24 18:12:01 -0700118func diffAB(a, b ipAndIf) ipAndIf {
Cosmos Nicolaou6c6fa112014-08-19 13:22:33 -0700119 diff := make(ipAndIf)
120 for ak, av := range a {
121 if b[ak] == nil {
Cosmos Nicolaoub82cedb2014-08-24 18:12:01 -0700122 diff[ak] = av
Cosmos Nicolaou6c6fa112014-08-19 13:22:33 -0700123 continue
124 }
125 for _, v := range av {
126 found := false
127 for _, bv := range b[ak] {
128 if v.Equal(bv) {
129 found = true
130 break
131 }
132 }
133 if !found {
134 diff[ak] = append(diff[ak], v)
135 }
136 }
137 }
138 return diff
139}
140
141// findAdded returns the set of interfaces and/or addresses that are
142// present in b, but not in a - i.e. have been added.
143func findAdded(a, b ipAndIf) ipAndIf {
Cosmos Nicolaoub82cedb2014-08-24 18:12:01 -0700144 return diffAB(b, a)
Cosmos Nicolaou6c6fa112014-08-19 13:22:33 -0700145}
146
147// findRemoved returns the set of interfaces and/or addresses that
148// are present in a, but not in b - i.e. have been removed.
149func findRemoved(a, b ipAndIf) ipAndIf {
Cosmos Nicolaoub82cedb2014-08-24 18:12:01 -0700150 return diffAB(a, b)
Cosmos Nicolaou6c6fa112014-08-19 13:22:33 -0700151}