1package libnetwork
2
3import (
4	"encoding/json"
5	"fmt"
6	"net"
7
8	"github.com/docker/libnetwork/driverapi"
9	"github.com/docker/libnetwork/types"
10)
11
12// EndpointInfo provides an interface to retrieve network resources bound to the endpoint.
13type EndpointInfo interface {
14	// Iface returns InterfaceInfo, go interface that can be used
15	// to get more information on the interface which was assigned to
16	// the endpoint by the driver. This can be used after the
17	// endpoint has been created.
18	Iface() InterfaceInfo
19
20	// Gateway returns the IPv4 gateway assigned by the driver.
21	// This will only return a valid value if a container has joined the endpoint.
22	Gateway() net.IP
23
24	// GatewayIPv6 returns the IPv6 gateway assigned by the driver.
25	// This will only return a valid value if a container has joined the endpoint.
26	GatewayIPv6() net.IP
27
28	// StaticRoutes returns the list of static routes configured by the network
29	// driver when the container joins a network
30	StaticRoutes() []*types.StaticRoute
31
32	// Sandbox returns the attached sandbox if there, nil otherwise.
33	Sandbox() Sandbox
34
35	// LoadBalancer returns whether the endpoint is the load balancer endpoint for the network.
36	LoadBalancer() bool
37}
38
39// InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
40type InterfaceInfo interface {
41	// MacAddress returns the MAC address assigned to the endpoint.
42	MacAddress() net.HardwareAddr
43
44	// Address returns the IPv4 address assigned to the endpoint.
45	Address() *net.IPNet
46
47	// AddressIPv6 returns the IPv6 address assigned to the endpoint.
48	AddressIPv6() *net.IPNet
49
50	// LinkLocalAddresses returns the list of link-local (IPv4/IPv6) addresses assigned to the endpoint.
51	LinkLocalAddresses() []*net.IPNet
52
53	// SrcName returns the name of the interface w/in the container
54	SrcName() string
55}
56
57type endpointInterface struct {
58	mac       net.HardwareAddr
59	addr      *net.IPNet
60	addrv6    *net.IPNet
61	llAddrs   []*net.IPNet
62	srcName   string
63	dstPrefix string
64	routes    []*net.IPNet
65	v4PoolID  string
66	v6PoolID  string
67}
68
69func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
70	epMap := make(map[string]interface{})
71	if epi.mac != nil {
72		epMap["mac"] = epi.mac.String()
73	}
74	if epi.addr != nil {
75		epMap["addr"] = epi.addr.String()
76	}
77	if epi.addrv6 != nil {
78		epMap["addrv6"] = epi.addrv6.String()
79	}
80	if len(epi.llAddrs) != 0 {
81		list := make([]string, 0, len(epi.llAddrs))
82		for _, ll := range epi.llAddrs {
83			list = append(list, ll.String())
84		}
85		epMap["llAddrs"] = list
86	}
87	epMap["srcName"] = epi.srcName
88	epMap["dstPrefix"] = epi.dstPrefix
89	var routes []string
90	for _, route := range epi.routes {
91		routes = append(routes, route.String())
92	}
93	epMap["routes"] = routes
94	epMap["v4PoolID"] = epi.v4PoolID
95	epMap["v6PoolID"] = epi.v6PoolID
96	return json.Marshal(epMap)
97}
98
99func (epi *endpointInterface) UnmarshalJSON(b []byte) error {
100	var (
101		err   error
102		epMap map[string]interface{}
103	)
104	if err = json.Unmarshal(b, &epMap); err != nil {
105		return err
106	}
107	if v, ok := epMap["mac"]; ok {
108		if epi.mac, err = net.ParseMAC(v.(string)); err != nil {
109			return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string))
110		}
111	}
112	if v, ok := epMap["addr"]; ok {
113		if epi.addr, err = types.ParseCIDR(v.(string)); err != nil {
114			return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err)
115		}
116	}
117	if v, ok := epMap["addrv6"]; ok {
118		if epi.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
119			return types.InternalErrorf("failed to decode endpoint interface ipv6 address after json unmarshal: %v", err)
120		}
121	}
122	if v, ok := epMap["llAddrs"]; ok {
123		list := v.([]interface{})
124		epi.llAddrs = make([]*net.IPNet, 0, len(list))
125		for _, llS := range list {
126			ll, err := types.ParseCIDR(llS.(string))
127			if err != nil {
128				return types.InternalErrorf("failed to decode endpoint interface link-local address (%v) after json unmarshal: %v", llS, err)
129			}
130			epi.llAddrs = append(epi.llAddrs, ll)
131		}
132	}
133	epi.srcName = epMap["srcName"].(string)
134	epi.dstPrefix = epMap["dstPrefix"].(string)
135
136	rb, _ := json.Marshal(epMap["routes"])
137	var routes []string
138	json.Unmarshal(rb, &routes)
139	epi.routes = make([]*net.IPNet, 0)
140	for _, route := range routes {
141		ip, ipr, err := net.ParseCIDR(route)
142		if err == nil {
143			ipr.IP = ip
144			epi.routes = append(epi.routes, ipr)
145		}
146	}
147	epi.v4PoolID = epMap["v4PoolID"].(string)
148	epi.v6PoolID = epMap["v6PoolID"].(string)
149
150	return nil
151}
152
153func (epi *endpointInterface) CopyTo(dstEpi *endpointInterface) error {
154	dstEpi.mac = types.GetMacCopy(epi.mac)
155	dstEpi.addr = types.GetIPNetCopy(epi.addr)
156	dstEpi.addrv6 = types.GetIPNetCopy(epi.addrv6)
157	dstEpi.srcName = epi.srcName
158	dstEpi.dstPrefix = epi.dstPrefix
159	dstEpi.v4PoolID = epi.v4PoolID
160	dstEpi.v6PoolID = epi.v6PoolID
161	if len(epi.llAddrs) != 0 {
162		dstEpi.llAddrs = make([]*net.IPNet, 0, len(epi.llAddrs))
163		dstEpi.llAddrs = append(dstEpi.llAddrs, epi.llAddrs...)
164	}
165
166	for _, route := range epi.routes {
167		dstEpi.routes = append(dstEpi.routes, types.GetIPNetCopy(route))
168	}
169
170	return nil
171}
172
173type endpointJoinInfo struct {
174	gw                    net.IP
175	gw6                   net.IP
176	StaticRoutes          []*types.StaticRoute
177	driverTableEntries    []*tableEntry
178	disableGatewayService bool
179}
180
181type tableEntry struct {
182	tableName string
183	key       string
184	value     []byte
185}
186
187func (ep *endpoint) Info() EndpointInfo {
188	if ep.sandboxID != "" {
189		return ep
190	}
191	n, err := ep.getNetworkFromStore()
192	if err != nil {
193		return nil
194	}
195
196	ep, err = n.getEndpointFromStore(ep.ID())
197	if err != nil {
198		return nil
199	}
200
201	sb, ok := ep.getSandbox()
202	if !ok {
203		// endpoint hasn't joined any sandbox.
204		// Just return the endpoint
205		return ep
206	}
207
208	return sb.getEndpoint(ep.ID())
209}
210
211func (ep *endpoint) Iface() InterfaceInfo {
212	ep.Lock()
213	defer ep.Unlock()
214
215	if ep.iface != nil {
216		return ep.iface
217	}
218
219	return nil
220}
221
222func (ep *endpoint) Interface() driverapi.InterfaceInfo {
223	ep.Lock()
224	defer ep.Unlock()
225
226	if ep.iface != nil {
227		return ep.iface
228	}
229
230	return nil
231}
232
233func (epi *endpointInterface) SetMacAddress(mac net.HardwareAddr) error {
234	if epi.mac != nil {
235		return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", epi.mac, mac)
236	}
237	if mac == nil {
238		return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
239	}
240	epi.mac = types.GetMacCopy(mac)
241	return nil
242}
243
244func (epi *endpointInterface) SetIPAddress(address *net.IPNet) error {
245	if address.IP == nil {
246		return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
247	}
248	if address.IP.To4() == nil {
249		return setAddress(&epi.addrv6, address)
250	}
251	return setAddress(&epi.addr, address)
252}
253
254func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
255	if *ifaceAddr != nil {
256		return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
257	}
258	*ifaceAddr = types.GetIPNetCopy(address)
259	return nil
260}
261
262func (epi *endpointInterface) MacAddress() net.HardwareAddr {
263	return types.GetMacCopy(epi.mac)
264}
265
266func (epi *endpointInterface) Address() *net.IPNet {
267	return types.GetIPNetCopy(epi.addr)
268}
269
270func (epi *endpointInterface) AddressIPv6() *net.IPNet {
271	return types.GetIPNetCopy(epi.addrv6)
272}
273
274func (epi *endpointInterface) LinkLocalAddresses() []*net.IPNet {
275	return epi.llAddrs
276}
277
278func (epi *endpointInterface) SrcName() string {
279	return epi.srcName
280}
281
282func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
283	epi.srcName = srcName
284	epi.dstPrefix = dstPrefix
285	return nil
286}
287
288func (ep *endpoint) InterfaceName() driverapi.InterfaceNameInfo {
289	ep.Lock()
290	defer ep.Unlock()
291
292	if ep.iface != nil {
293		return ep.iface
294	}
295
296	return nil
297}
298
299func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
300	ep.Lock()
301	defer ep.Unlock()
302
303	r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop}
304
305	if routeType == types.NEXTHOP {
306		// If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface).
307		ep.joinInfo.StaticRoutes = append(ep.joinInfo.StaticRoutes, &r)
308	} else {
309		// If the route doesn't specify a next-hop, it must be a connected route, bound to an interface.
310		ep.iface.routes = append(ep.iface.routes, r.Destination)
311	}
312	return nil
313}
314
315func (ep *endpoint) AddTableEntry(tableName, key string, value []byte) error {
316	ep.Lock()
317	defer ep.Unlock()
318
319	ep.joinInfo.driverTableEntries = append(ep.joinInfo.driverTableEntries, &tableEntry{
320		tableName: tableName,
321		key:       key,
322		value:     value,
323	})
324
325	return nil
326}
327
328func (ep *endpoint) Sandbox() Sandbox {
329	cnt, ok := ep.getSandbox()
330	if !ok {
331		return nil
332	}
333	return cnt
334}
335
336func (ep *endpoint) LoadBalancer() bool {
337	ep.Lock()
338	defer ep.Unlock()
339	return ep.loadBalancer
340}
341
342func (ep *endpoint) StaticRoutes() []*types.StaticRoute {
343	ep.Lock()
344	defer ep.Unlock()
345
346	if ep.joinInfo == nil {
347		return nil
348	}
349
350	return ep.joinInfo.StaticRoutes
351}
352
353func (ep *endpoint) Gateway() net.IP {
354	ep.Lock()
355	defer ep.Unlock()
356
357	if ep.joinInfo == nil {
358		return net.IP{}
359	}
360
361	return types.GetIPCopy(ep.joinInfo.gw)
362}
363
364func (ep *endpoint) GatewayIPv6() net.IP {
365	ep.Lock()
366	defer ep.Unlock()
367
368	if ep.joinInfo == nil {
369		return net.IP{}
370	}
371
372	return types.GetIPCopy(ep.joinInfo.gw6)
373}
374
375func (ep *endpoint) SetGateway(gw net.IP) error {
376	ep.Lock()
377	defer ep.Unlock()
378
379	ep.joinInfo.gw = types.GetIPCopy(gw)
380	return nil
381}
382
383func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
384	ep.Lock()
385	defer ep.Unlock()
386
387	ep.joinInfo.gw6 = types.GetIPCopy(gw6)
388	return nil
389}
390
391func (ep *endpoint) retrieveFromStore() (*endpoint, error) {
392	n, err := ep.getNetworkFromStore()
393	if err != nil {
394		return nil, fmt.Errorf("could not find network in store to get latest endpoint %s: %v", ep.Name(), err)
395	}
396	return n.getEndpointFromStore(ep.ID())
397}
398
399func (ep *endpoint) DisableGatewayService() {
400	ep.Lock()
401	defer ep.Unlock()
402
403	ep.joinInfo.disableGatewayService = true
404}
405
406func (epj *endpointJoinInfo) MarshalJSON() ([]byte, error) {
407	epMap := make(map[string]interface{})
408	if epj.gw != nil {
409		epMap["gw"] = epj.gw.String()
410	}
411	if epj.gw6 != nil {
412		epMap["gw6"] = epj.gw6.String()
413	}
414	epMap["disableGatewayService"] = epj.disableGatewayService
415	epMap["StaticRoutes"] = epj.StaticRoutes
416	return json.Marshal(epMap)
417}
418
419func (epj *endpointJoinInfo) UnmarshalJSON(b []byte) error {
420	var (
421		err   error
422		epMap map[string]interface{}
423	)
424	if err = json.Unmarshal(b, &epMap); err != nil {
425		return err
426	}
427	if v, ok := epMap["gw"]; ok {
428		epj.gw = net.ParseIP(v.(string))
429	}
430	if v, ok := epMap["gw6"]; ok {
431		epj.gw6 = net.ParseIP(v.(string))
432	}
433	epj.disableGatewayService = epMap["disableGatewayService"].(bool)
434
435	var tStaticRoute []types.StaticRoute
436	if v, ok := epMap["StaticRoutes"]; ok {
437		tb, _ := json.Marshal(v)
438		var tStaticRoute []types.StaticRoute
439		json.Unmarshal(tb, &tStaticRoute)
440	}
441	var StaticRoutes []*types.StaticRoute
442	for _, r := range tStaticRoute {
443		StaticRoutes = append(StaticRoutes, &r)
444	}
445	epj.StaticRoutes = StaticRoutes
446
447	return nil
448}
449
450func (epj *endpointJoinInfo) CopyTo(dstEpj *endpointJoinInfo) error {
451	dstEpj.disableGatewayService = epj.disableGatewayService
452	dstEpj.StaticRoutes = make([]*types.StaticRoute, len(epj.StaticRoutes))
453	copy(dstEpj.StaticRoutes, epj.StaticRoutes)
454	dstEpj.driverTableEntries = make([]*tableEntry, len(epj.driverTableEntries))
455	copy(dstEpj.driverTableEntries, epj.driverTableEntries)
456	dstEpj.gw = types.GetIPCopy(epj.gw)
457	dstEpj.gw6 = types.GetIPCopy(epj.gw6)
458	return nil
459}
460