...
1
2
3
4
5 package ipv6
6
7 import (
8 "fmt"
9 "net"
10 "sync"
11
12 "golang.org/x/net/internal/iana"
13 "golang.org/x/net/internal/socket"
14 )
15
16
17
18
19
20
21 type rawOpt struct {
22 sync.RWMutex
23 cflags ControlFlags
24 }
25
26 func (c *rawOpt) set(f ControlFlags) { c.cflags |= f }
27 func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f }
28 func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
29
30
31
32 type ControlFlags uint
33
34 const (
35 FlagTrafficClass ControlFlags = 1 << iota
36 FlagHopLimit
37 FlagSrc
38 FlagDst
39 FlagInterface
40 FlagPathMTU
41 )
42
43 const flagPacketInfo = FlagDst | FlagInterface
44
45
46
47 type ControlMessage struct {
48
49
50
51
52
53
54
55
56 TrafficClass int
57 HopLimit int
58 Src net.IP
59 Dst net.IP
60 IfIndex int
61 NextHop net.IP
62 MTU int
63 }
64
65 func (cm *ControlMessage) String() string {
66 if cm == nil {
67 return "<nil>"
68 }
69 return fmt.Sprintf("tclass=%#x hoplim=%d src=%v dst=%v ifindex=%d nexthop=%v mtu=%d", cm.TrafficClass, cm.HopLimit, cm.Src, cm.Dst, cm.IfIndex, cm.NextHop, cm.MTU)
70 }
71
72
73 func (cm *ControlMessage) Marshal() []byte {
74 if cm == nil {
75 return nil
76 }
77 var l int
78 tclass := false
79 if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
80 tclass = true
81 l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
82 }
83 hoplimit := false
84 if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
85 hoplimit = true
86 l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
87 }
88 pktinfo := false
89 if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) {
90 pktinfo = true
91 l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
92 }
93 nexthop := false
94 if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
95 nexthop = true
96 l += socket.ControlMessageSpace(ctlOpts[ctlNextHop].length)
97 }
98 var b []byte
99 if l > 0 {
100 b = make([]byte, l)
101 bb := b
102 if tclass {
103 bb = ctlOpts[ctlTrafficClass].marshal(bb, cm)
104 }
105 if hoplimit {
106 bb = ctlOpts[ctlHopLimit].marshal(bb, cm)
107 }
108 if pktinfo {
109 bb = ctlOpts[ctlPacketInfo].marshal(bb, cm)
110 }
111 if nexthop {
112 bb = ctlOpts[ctlNextHop].marshal(bb, cm)
113 }
114 }
115 return b
116 }
117
118
119 func (cm *ControlMessage) Parse(b []byte) error {
120 ms, err := socket.ControlMessage(b).Parse()
121 if err != nil {
122 return err
123 }
124 for _, m := range ms {
125 lvl, typ, l, err := m.ParseHeader()
126 if err != nil {
127 return err
128 }
129 if lvl != iana.ProtocolIPv6 {
130 continue
131 }
132 switch {
133 case typ == ctlOpts[ctlTrafficClass].name && l >= ctlOpts[ctlTrafficClass].length:
134 ctlOpts[ctlTrafficClass].parse(cm, m.Data(l))
135 case typ == ctlOpts[ctlHopLimit].name && l >= ctlOpts[ctlHopLimit].length:
136 ctlOpts[ctlHopLimit].parse(cm, m.Data(l))
137 case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length:
138 ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
139 case typ == ctlOpts[ctlPathMTU].name && l >= ctlOpts[ctlPathMTU].length:
140 ctlOpts[ctlPathMTU].parse(cm, m.Data(l))
141 }
142 }
143 return nil
144 }
145
146
147
148
149 func NewControlMessage(cf ControlFlags) []byte {
150 opt := rawOpt{cflags: cf}
151 var l int
152 if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
153 l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
154 }
155 if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
156 l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
157 }
158 if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
159 l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
160 }
161 if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
162 l += socket.ControlMessageSpace(ctlOpts[ctlPathMTU].length)
163 }
164 var b []byte
165 if l > 0 {
166 b = make([]byte, l)
167 }
168 return b
169 }
170
171
172 const (
173 ctlTrafficClass = iota
174 ctlHopLimit
175 ctlPacketInfo
176 ctlNextHop
177 ctlPathMTU
178 ctlMax
179 )
180
181
182 type ctlOpt struct {
183 name int
184 length int
185 marshal func([]byte, *ControlMessage) []byte
186 parse func(*ControlMessage, []byte)
187 }
188
View as plain text