-
Notifications
You must be signed in to change notification settings - Fork 3
/
conn.go
144 lines (121 loc) · 3.55 KB
/
conn.go
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package ospf3
import (
"net"
"time"
"golang.org/x/net/ipv6"
)
// Fixed IPv6 header parameters for Conn use.
const (
tclass = 0xc0 // DSCP CS6, per appendix A.1.
hopLimit = 1
)
var (
// AllSPFRouters is the IPv6 multicast group address that all routers
// running OSPFv3 should participate in.
AllSPFRouters = &net.IPAddr{IP: net.ParseIP("ff02::5")}
// AllDRouters is the IPv6 multicast group address that the Designated
// Router and Backup Designated Router running OSPFv3 must participate in.
AllDRouters = &net.IPAddr{IP: net.ParseIP("ff02::6")}
)
// A Conn can send and receive OSPFv3 packets which implement the Packet
// interface.
type Conn struct {
c *ipv6.PacketConn
ifi *net.Interface
groups []*net.IPAddr
}
// Listen creates a *Conn using the specified network interface.
func Listen(ifi *net.Interface) (*Conn, error) {
// IP protocol number 89 is OSPF.
conn, err := net.ListenPacket("ip6:89", "::")
if err != nil {
return nil, err
}
c := ipv6.NewPacketConn(conn)
// Return all possible control message information to the caller so they
// can make more informed choices.
if err := c.SetControlMessage(^ipv6.ControlFlags(0), true); err != nil {
return nil, err
}
// Process checksums in the OSPFv3 header.
if err := c.SetChecksum(true, 12); err != nil {
return nil, err
}
// Set IPv6 header parameters per the RFC.
if err := c.SetHopLimit(hopLimit); err != nil {
return nil, err
}
if err := c.SetMulticastHopLimit(hopLimit); err != nil {
return nil, err
}
if err := c.SetTrafficClass(tclass); err != nil {
return nil, err
}
// Join the appropriate multicast groups. Note that point-to-point links
// don't use DR/BDR and can skip joining that group.
if err := c.SetMulticastInterface(ifi); err != nil {
return nil, err
}
groups := []*net.IPAddr{AllSPFRouters}
if ifi.Flags&net.FlagPointToPoint == 0 {
groups = append(groups, AllDRouters)
}
for _, g := range groups {
if err := c.JoinGroup(ifi, g); err != nil {
return nil, err
}
}
// Don't read our own multicast packets during concurrent read/write.
if err := c.SetMulticastLoopback(false); err != nil {
return nil, err
}
return &Conn{
c: c,
ifi: ifi,
groups: groups,
}, nil
}
// Close closes the Conn's underlying network connection.
func (c *Conn) Close() error {
for _, g := range c.groups {
if err := c.c.LeaveGroup(c.ifi, g); err != nil {
return err
}
}
return c.c.Close()
}
// SetReadDeadline sets the read deadline associated with the Conn.
func (c *Conn) SetReadDeadline(t time.Time) error {
return c.c.SetReadDeadline(t)
}
// ReadFrom reads a single OSPFv3 packet and returns a Packet along with its
// associated IPv6 control message and source address. ReadFrom will block until
// a timeout occurs or a valid OSPFv3 packet is read.
func (c *Conn) ReadFrom() (Packet, *ipv6.ControlMessage, *net.IPAddr, error) {
b := make([]byte, c.ifi.MTU)
for {
n, cm, src, err := c.c.ReadFrom(b)
if err != nil {
return nil, nil, nil, err
}
p, err := ParsePacket(b[:n])
if err != nil {
// Assume invalid OSPFv3 data, keep reading.
continue
}
return p, cm, src.(*net.IPAddr), nil
}
}
// WriteTo writes a single OSPFv3 Packet to the specified destination address
// or multicast group.
func (c *Conn) WriteTo(p Packet, dst *net.IPAddr) error {
b, err := MarshalPacket(p)
if err != nil {
return err
}
// TODO(mdlayher): consider parameterizing control message if necessary but
// it seems that x/net/ipv6 lets us configure the kernel to do a lot of the
// work for us.
_, err = c.c.WriteTo(b, nil, dst)
return err
}