1// Package types contains types that are common across libnetwork project
2package types
3
4import (
5	"bytes"
6	"fmt"
7	"net"
8	"strconv"
9	"strings"
10)
11
12// constants for the IP address type
13const (
14	IP = iota // IPv4 and IPv6
15	IPv4
16	IPv6
17)
18
19// EncryptionKey is the libnetwork representation of the key distributed by the lead
20// manager.
21type EncryptionKey struct {
22	Subsystem   string
23	Algorithm   int32
24	Key         []byte
25	LamportTime uint64
26}
27
28// UUID represents a globally unique ID of various resources like network and endpoint
29type UUID string
30
31// QosPolicy represents a quality of service policy on an endpoint
32type QosPolicy struct {
33	MaxEgressBandwidth uint64
34}
35
36// TransportPort represents a local Layer 4 endpoint
37type TransportPort struct {
38	Proto Protocol
39	Port  uint16
40}
41
42// Equal checks if this instance of Transportport is equal to the passed one
43func (t *TransportPort) Equal(o *TransportPort) bool {
44	if t == o {
45		return true
46	}
47
48	if o == nil {
49		return false
50	}
51
52	if t.Proto != o.Proto || t.Port != o.Port {
53		return false
54	}
55
56	return true
57}
58
59// GetCopy returns a copy of this TransportPort structure instance
60func (t *TransportPort) GetCopy() TransportPort {
61	return TransportPort{Proto: t.Proto, Port: t.Port}
62}
63
64// String returns the TransportPort structure in string form
65func (t *TransportPort) String() string {
66	return fmt.Sprintf("%s/%d", t.Proto.String(), t.Port)
67}
68
69// FromString reads the TransportPort structure from string
70func (t *TransportPort) FromString(s string) error {
71	ps := strings.Split(s, "/")
72	if len(ps) == 2 {
73		t.Proto = ParseProtocol(ps[0])
74		if p, err := strconv.ParseUint(ps[1], 10, 16); err == nil {
75			t.Port = uint16(p)
76			return nil
77		}
78	}
79	return BadRequestErrorf("invalid format for transport port: %s", s)
80}
81
82// PortBinding represents a port binding between the container and the host
83type PortBinding struct {
84	Proto       Protocol
85	IP          net.IP
86	Port        uint16
87	HostIP      net.IP
88	HostPort    uint16
89	HostPortEnd uint16
90}
91
92// HostAddr returns the host side transport address
93func (p PortBinding) HostAddr() (net.Addr, error) {
94	switch p.Proto {
95	case UDP:
96		return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
97	case TCP:
98		return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
99	default:
100		return nil, ErrInvalidProtocolBinding(p.Proto.String())
101	}
102}
103
104// ContainerAddr returns the container side transport address
105func (p PortBinding) ContainerAddr() (net.Addr, error) {
106	switch p.Proto {
107	case UDP:
108		return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil
109	case TCP:
110		return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil
111	default:
112		return nil, ErrInvalidProtocolBinding(p.Proto.String())
113	}
114}
115
116// GetCopy returns a copy of this PortBinding structure instance
117func (p *PortBinding) GetCopy() PortBinding {
118	return PortBinding{
119		Proto:       p.Proto,
120		IP:          GetIPCopy(p.IP),
121		Port:        p.Port,
122		HostIP:      GetIPCopy(p.HostIP),
123		HostPort:    p.HostPort,
124		HostPortEnd: p.HostPortEnd,
125	}
126}
127
128// String returns the PortBinding structure in string form
129func (p *PortBinding) String() string {
130	ret := fmt.Sprintf("%s/", p.Proto)
131	if p.IP != nil {
132		ret += p.IP.String()
133	}
134	ret = fmt.Sprintf("%s:%d/", ret, p.Port)
135	if p.HostIP != nil {
136		ret += p.HostIP.String()
137	}
138	ret = fmt.Sprintf("%s:%d", ret, p.HostPort)
139	return ret
140}
141
142// FromString reads the TransportPort structure from string
143func (p *PortBinding) FromString(s string) error {
144	ps := strings.Split(s, "/")
145	if len(ps) != 3 {
146		return BadRequestErrorf("invalid format for port binding: %s", s)
147	}
148
149	p.Proto = ParseProtocol(ps[0])
150
151	var err error
152	if p.IP, p.Port, err = parseIPPort(ps[1]); err != nil {
153		return BadRequestErrorf("failed to parse Container IP/Port in port binding: %s", err.Error())
154	}
155
156	if p.HostIP, p.HostPort, err = parseIPPort(ps[2]); err != nil {
157		return BadRequestErrorf("failed to parse Host IP/Port in port binding: %s", err.Error())
158	}
159
160	return nil
161}
162
163func parseIPPort(s string) (net.IP, uint16, error) {
164	pp := strings.Split(s, ":")
165	if len(pp) != 2 {
166		return nil, 0, BadRequestErrorf("invalid format: %s", s)
167	}
168
169	var ip net.IP
170	if pp[0] != "" {
171		if ip = net.ParseIP(pp[0]); ip == nil {
172			return nil, 0, BadRequestErrorf("invalid ip: %s", pp[0])
173		}
174	}
175
176	port, err := strconv.ParseUint(pp[1], 10, 16)
177	if err != nil {
178		return nil, 0, BadRequestErrorf("invalid port: %s", pp[1])
179	}
180
181	return ip, uint16(port), nil
182}
183
184// Equal checks if this instance of PortBinding is equal to the passed one
185func (p *PortBinding) Equal(o *PortBinding) bool {
186	if p == o {
187		return true
188	}
189
190	if o == nil {
191		return false
192	}
193
194	if p.Proto != o.Proto || p.Port != o.Port ||
195		p.HostPort != o.HostPort || p.HostPortEnd != o.HostPortEnd {
196		return false
197	}
198
199	if p.IP != nil {
200		if !p.IP.Equal(o.IP) {
201			return false
202		}
203	} else {
204		if o.IP != nil {
205			return false
206		}
207	}
208
209	if p.HostIP != nil {
210		if !p.HostIP.Equal(o.HostIP) {
211			return false
212		}
213	} else {
214		if o.HostIP != nil {
215			return false
216		}
217	}
218
219	return true
220}
221
222// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid.
223type ErrInvalidProtocolBinding string
224
225func (ipb ErrInvalidProtocolBinding) Error() string {
226	return fmt.Sprintf("invalid transport protocol: %s", string(ipb))
227}
228
229const (
230	// ICMP is for the ICMP ip protocol
231	ICMP = 1
232	// TCP is for the TCP ip protocol
233	TCP = 6
234	// UDP is for the UDP ip protocol
235	UDP = 17
236)
237
238// Protocol represents an IP protocol number
239type Protocol uint8
240
241func (p Protocol) String() string {
242	switch p {
243	case ICMP:
244		return "icmp"
245	case TCP:
246		return "tcp"
247	case UDP:
248		return "udp"
249	default:
250		return fmt.Sprintf("%d", p)
251	}
252}
253
254// ParseProtocol returns the respective Protocol type for the passed string
255func ParseProtocol(s string) Protocol {
256	switch strings.ToLower(s) {
257	case "icmp":
258		return ICMP
259	case "udp":
260		return UDP
261	case "tcp":
262		return TCP
263	default:
264		return 0
265	}
266}
267
268// GetMacCopy returns a copy of the passed MAC address
269func GetMacCopy(from net.HardwareAddr) net.HardwareAddr {
270	if from == nil {
271		return nil
272	}
273	to := make(net.HardwareAddr, len(from))
274	copy(to, from)
275	return to
276}
277
278// GetIPCopy returns a copy of the passed IP address
279func GetIPCopy(from net.IP) net.IP {
280	if from == nil {
281		return nil
282	}
283	to := make(net.IP, len(from))
284	copy(to, from)
285	return to
286}
287
288// GetIPNetCopy returns a copy of the passed IP Network
289func GetIPNetCopy(from *net.IPNet) *net.IPNet {
290	if from == nil {
291		return nil
292	}
293	bm := make(net.IPMask, len(from.Mask))
294	copy(bm, from.Mask)
295	return &net.IPNet{IP: GetIPCopy(from.IP), Mask: bm}
296}
297
298// GetIPNetCanonical returns the canonical form for the passed network
299func GetIPNetCanonical(nw *net.IPNet) *net.IPNet {
300	if nw == nil {
301		return nil
302	}
303	c := GetIPNetCopy(nw)
304	c.IP = c.IP.Mask(nw.Mask)
305	return c
306}
307
308// CompareIPNet returns equal if the two IP Networks are equal
309func CompareIPNet(a, b *net.IPNet) bool {
310	if a == b {
311		return true
312	}
313	if a == nil || b == nil {
314		return false
315	}
316	return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
317}
318
319// GetMinimalIP returns the address in its shortest form
320func GetMinimalIP(ip net.IP) net.IP {
321	if ip != nil && ip.To4() != nil {
322		return ip.To4()
323	}
324	return ip
325}
326
327// GetMinimalIPNet returns a copy of the passed IP Network with congruent ip and mask notation
328func GetMinimalIPNet(nw *net.IPNet) *net.IPNet {
329	if nw == nil {
330		return nil
331	}
332	if len(nw.IP) == 16 && nw.IP.To4() != nil {
333		m := nw.Mask
334		if len(m) == 16 {
335			m = m[12:16]
336		}
337		return &net.IPNet{IP: nw.IP.To4(), Mask: m}
338	}
339	return nw
340}
341
342// IsIPNetValid returns true if the ipnet is a valid network/mask
343// combination. Otherwise returns false.
344func IsIPNetValid(nw *net.IPNet) bool {
345	return nw.String() != "0.0.0.0/0"
346}
347
348var v4inV6MaskPrefix = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
349
350// compareIPMask checks if the passed ip and mask are semantically compatible.
351// It returns the byte indexes for the address and mask so that caller can
352// do bitwise operations without modifying address representation.
353func compareIPMask(ip net.IP, mask net.IPMask) (is int, ms int, err error) {
354	// Find the effective starting of address and mask
355	if len(ip) == net.IPv6len && ip.To4() != nil {
356		is = 12
357	}
358	if len(ip[is:]) == net.IPv4len && len(mask) == net.IPv6len && bytes.Equal(mask[:12], v4inV6MaskPrefix) {
359		ms = 12
360	}
361	// Check if address and mask are semantically compatible
362	if len(ip[is:]) != len(mask[ms:]) {
363		err = fmt.Errorf("ip and mask are not compatible: (%#v, %#v)", ip, mask)
364	}
365	return
366}
367
368// GetHostPartIP returns the host portion of the ip address identified by the mask.
369// IP address representation is not modified. If address and mask are not compatible
370// an error is returned.
371func GetHostPartIP(ip net.IP, mask net.IPMask) (net.IP, error) {
372	// Find the effective starting of address and mask
373	is, ms, err := compareIPMask(ip, mask)
374	if err != nil {
375		return nil, fmt.Errorf("cannot compute host portion ip address because %s", err)
376	}
377
378	// Compute host portion
379	out := GetIPCopy(ip)
380	for i := 0; i < len(mask[ms:]); i++ {
381		out[is+i] &= ^mask[ms+i]
382	}
383
384	return out, nil
385}
386
387// GetBroadcastIP returns the broadcast ip address for the passed network (ip and mask).
388// IP address representation is not modified. If address and mask are not compatible
389// an error is returned.
390func GetBroadcastIP(ip net.IP, mask net.IPMask) (net.IP, error) {
391	// Find the effective starting of address and mask
392	is, ms, err := compareIPMask(ip, mask)
393	if err != nil {
394		return nil, fmt.Errorf("cannot compute broadcast ip address because %s", err)
395	}
396
397	// Compute broadcast address
398	out := GetIPCopy(ip)
399	for i := 0; i < len(mask[ms:]); i++ {
400		out[is+i] |= ^mask[ms+i]
401	}
402
403	return out, nil
404}
405
406// ParseCIDR returns the *net.IPNet represented by the passed CIDR notation
407func ParseCIDR(cidr string) (n *net.IPNet, e error) {
408	var i net.IP
409	if i, n, e = net.ParseCIDR(cidr); e == nil {
410		n.IP = i
411	}
412	return
413}
414
415const (
416	// NEXTHOP indicates a StaticRoute with an IP next hop.
417	NEXTHOP = iota
418
419	// CONNECTED indicates a StaticRoute with an interface for directly connected peers.
420	CONNECTED
421)
422
423// StaticRoute is a statically-provisioned IP route.
424type StaticRoute struct {
425	Destination *net.IPNet
426
427	RouteType int // NEXT_HOP or CONNECTED
428
429	// NextHop will be resolved by the kernel (i.e. as a loose hop).
430	NextHop net.IP
431}
432
433// GetCopy returns a copy of this StaticRoute structure
434func (r *StaticRoute) GetCopy() *StaticRoute {
435	d := GetIPNetCopy(r.Destination)
436	nh := GetIPCopy(r.NextHop)
437	return &StaticRoute{Destination: d,
438		RouteType: r.RouteType,
439		NextHop:   nh,
440	}
441}
442
443// InterfaceStatistics represents the interface's statistics
444type InterfaceStatistics struct {
445	RxBytes   uint64
446	RxPackets uint64
447	RxErrors  uint64
448	RxDropped uint64
449	TxBytes   uint64
450	TxPackets uint64
451	TxErrors  uint64
452	TxDropped uint64
453}
454
455func (is *InterfaceStatistics) String() string {
456	return fmt.Sprintf("\nRxBytes: %d, RxPackets: %d, RxErrors: %d, RxDropped: %d, TxBytes: %d, TxPackets: %d, TxErrors: %d, TxDropped: %d",
457		is.RxBytes, is.RxPackets, is.RxErrors, is.RxDropped, is.TxBytes, is.TxPackets, is.TxErrors, is.TxDropped)
458}
459
460/******************************
461 * Well-known Error Interfaces
462 ******************************/
463
464// MaskableError is an interface for errors which can be ignored by caller
465type MaskableError interface {
466	// Maskable makes implementer into MaskableError type
467	Maskable()
468}
469
470// RetryError is an interface for errors which might get resolved through retry
471type RetryError interface {
472	// Retry makes implementer into RetryError type
473	Retry()
474}
475
476// BadRequestError is an interface for errors originated by a bad request
477type BadRequestError interface {
478	// BadRequest makes implementer into BadRequestError type
479	BadRequest()
480}
481
482// NotFoundError is an interface for errors raised because a needed resource is not available
483type NotFoundError interface {
484	// NotFound makes implementer into NotFoundError type
485	NotFound()
486}
487
488// ForbiddenError is an interface for errors which denote a valid request that cannot be honored
489type ForbiddenError interface {
490	// Forbidden makes implementer into ForbiddenError type
491	Forbidden()
492}
493
494// NoServiceError is an interface for errors returned when the required service is not available
495type NoServiceError interface {
496	// NoService makes implementer into NoServiceError type
497	NoService()
498}
499
500// TimeoutError is an interface for errors raised because of timeout
501type TimeoutError interface {
502	// Timeout makes implementer into TimeoutError type
503	Timeout()
504}
505
506// NotImplementedError is an interface for errors raised because of requested functionality is not yet implemented
507type NotImplementedError interface {
508	// NotImplemented makes implementer into NotImplementedError type
509	NotImplemented()
510}
511
512// InternalError is an interface for errors raised because of an internal error
513type InternalError interface {
514	// Internal makes implementer into InternalError type
515	Internal()
516}
517
518/******************************
519 * Well-known Error Formatters
520 ******************************/
521
522// BadRequestErrorf creates an instance of BadRequestError
523func BadRequestErrorf(format string, params ...interface{}) error {
524	return badRequest(fmt.Sprintf(format, params...))
525}
526
527// NotFoundErrorf creates an instance of NotFoundError
528func NotFoundErrorf(format string, params ...interface{}) error {
529	return notFound(fmt.Sprintf(format, params...))
530}
531
532// ForbiddenErrorf creates an instance of ForbiddenError
533func ForbiddenErrorf(format string, params ...interface{}) error {
534	return forbidden(fmt.Sprintf(format, params...))
535}
536
537// NoServiceErrorf creates an instance of NoServiceError
538func NoServiceErrorf(format string, params ...interface{}) error {
539	return noService(fmt.Sprintf(format, params...))
540}
541
542// NotImplementedErrorf creates an instance of NotImplementedError
543func NotImplementedErrorf(format string, params ...interface{}) error {
544	return notImpl(fmt.Sprintf(format, params...))
545}
546
547// TimeoutErrorf creates an instance of TimeoutError
548func TimeoutErrorf(format string, params ...interface{}) error {
549	return timeout(fmt.Sprintf(format, params...))
550}
551
552// InternalErrorf creates an instance of InternalError
553func InternalErrorf(format string, params ...interface{}) error {
554	return internal(fmt.Sprintf(format, params...))
555}
556
557// InternalMaskableErrorf creates an instance of InternalError and MaskableError
558func InternalMaskableErrorf(format string, params ...interface{}) error {
559	return maskInternal(fmt.Sprintf(format, params...))
560}
561
562// RetryErrorf creates an instance of RetryError
563func RetryErrorf(format string, params ...interface{}) error {
564	return retry(fmt.Sprintf(format, params...))
565}
566
567/***********************
568 * Internal Error Types
569 ***********************/
570type badRequest string
571
572func (br badRequest) Error() string {
573	return string(br)
574}
575func (br badRequest) BadRequest() {}
576
577type maskBadRequest string
578
579type notFound string
580
581func (nf notFound) Error() string {
582	return string(nf)
583}
584func (nf notFound) NotFound() {}
585
586type forbidden string
587
588func (frb forbidden) Error() string {
589	return string(frb)
590}
591func (frb forbidden) Forbidden() {}
592
593type noService string
594
595func (ns noService) Error() string {
596	return string(ns)
597}
598func (ns noService) NoService() {}
599
600type maskNoService string
601
602type timeout string
603
604func (to timeout) Error() string {
605	return string(to)
606}
607func (to timeout) Timeout() {}
608
609type notImpl string
610
611func (ni notImpl) Error() string {
612	return string(ni)
613}
614func (ni notImpl) NotImplemented() {}
615
616type internal string
617
618func (nt internal) Error() string {
619	return string(nt)
620}
621func (nt internal) Internal() {}
622
623type maskInternal string
624
625func (mnt maskInternal) Error() string {
626	return string(mnt)
627}
628func (mnt maskInternal) Internal() {}
629func (mnt maskInternal) Maskable() {}
630
631type retry string
632
633func (r retry) Error() string {
634	return string(r)
635}
636func (r retry) Retry() {}
637