LEFT | RIGHT |
1 // Copyright 2012 The Go Authors. All rights reserved. | 1 // Copyright 2012 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package ipv4 | 5 package ipv4 |
6 | 6 |
7 import ( | 7 import ( |
8 "os" | |
9 "syscall" | 8 "syscall" |
10 "unsafe" | 9 "unsafe" |
11 ) | 10 ) |
12 | |
13 // Linux provides a convenient path control option IP_PKTINFO that | |
14 // contains IP_SENDSRCADDR, IP_RECVDSTADDR, IP_RECVIF and IP_SENDIF. | |
15 const pktinfo = FlagSrc | FlagDst | FlagInterface | |
16 | 11 |
17 func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { | 12 func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { |
18 opt.Lock() | 13 opt.Lock() |
19 defer opt.Unlock() | 14 defer opt.Unlock() |
20 if cf&FlagTTL != 0 { | 15 if cf&FlagTTL != 0 { |
21 if err := setIPv4ReceiveTTL(fd, on); err != nil { | 16 if err := setIPv4ReceiveTTL(fd, on); err != nil { |
22 return err | 17 return err |
23 } | 18 } |
24 if on { | 19 if on { |
25 opt.set(FlagTTL) | 20 opt.set(FlagTTL) |
26 } else { | 21 } else { |
27 opt.clear(FlagTTL) | 22 opt.clear(FlagTTL) |
28 } | 23 } |
29 } | 24 } |
30 » if cf&pktinfo != 0 { | 25 » if cf&(FlagSrc|FlagDst|FlagInterface) != 0 { |
31 if err := setIPv4PacketInfo(fd, on); err != nil { | 26 if err := setIPv4PacketInfo(fd, on); err != nil { |
32 return err | 27 return err |
33 } | 28 } |
34 if on { | 29 if on { |
35 » » » opt.set(cf & pktinfo) | 30 » » » opt.set(cf & (FlagSrc | FlagDst | FlagInterface)) |
36 } else { | 31 } else { |
37 » » » opt.clear(cf & pktinfo) | 32 » » » opt.clear(cf & (FlagSrc | FlagDst | FlagInterface)) |
38 } | 33 } |
39 } | 34 } |
40 return nil | 35 return nil |
41 } | 36 } |
42 | 37 |
43 func newControlMessage(opt *rawOpt) (oob []byte) { | 38 func (opt *rawOpt) oobLen() (l int) { |
44 » opt.Lock() | |
45 » defer opt.Unlock() | |
46 » l, off := 0, 0 | |
47 if opt.isset(FlagTTL) { | 39 if opt.isset(FlagTTL) { |
48 l += syscall.CmsgSpace(1) | 40 l += syscall.CmsgSpace(1) |
49 } | 41 } |
50 » if opt.isset(pktinfo) { | 42 » if opt.isset(FlagSrc | FlagDst | FlagInterface) { |
51 l += syscall.CmsgSpace(sysSizeofPacketInfo) | 43 l += syscall.CmsgSpace(sysSizeofPacketInfo) |
52 } | |
53 if l > 0 { | |
54 oob = make([]byte, l) | |
55 if opt.isset(FlagTTL) { | |
56 m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) | |
57 m.Level = ianaProtocolIP | |
58 m.Type = sysSockoptReceiveTTL | |
59 m.SetLen(syscall.CmsgLen(1)) | |
60 off += syscall.CmsgSpace(1) | |
61 } | |
62 if opt.isset(pktinfo) { | |
63 m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) | |
64 m.Level = ianaProtocolIP | |
65 m.Type = sysSockoptPacketInfo | |
66 m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo)) | |
67 off += syscall.CmsgSpace(sysSizeofPacketInfo) | |
68 } | |
69 } | 44 } |
70 return | 45 return |
71 } | 46 } |
72 | 47 |
73 func parseControlMessage(b []byte) (*ControlMessage, error) { | 48 func (opt *rawOpt) marshalControlMessage() (oob []byte) { |
74 » if len(b) == 0 { | 49 » var off int |
75 » » return nil, nil | 50 » oob = make([]byte, opt.oobLen()) |
| 51 » if opt.isset(FlagTTL) { |
| 52 » » m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) |
| 53 » » m.Level = ianaProtocolIP |
| 54 » » m.Type = sysSockoptReceiveTTL |
| 55 » » m.SetLen(syscall.CmsgLen(1)) |
| 56 » » off += syscall.CmsgSpace(1) |
76 } | 57 } |
77 » cmsgs, err := syscall.ParseSocketControlMessage(b) | 58 » if opt.isset(FlagSrc | FlagDst | FlagInterface) { |
78 » if err != nil { | 59 » » m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[0])) |
79 » » return nil, os.NewSyscallError("parse socket control message", e
rr) | 60 » » m.Level = ianaProtocolIP |
80 » } | 61 » » m.Type = sysSockoptPacketInfo |
81 » cm := &ControlMessage{} | 62 » » m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo)) |
82 » for _, m := range cmsgs { | 63 » » off += syscall.CmsgSpace(sysSizeofPacketInfo) |
83 » » if m.Header.Level != ianaProtocolIP { | |
84 » » » continue | |
85 » » } | |
86 » » switch m.Header.Type { | |
87 » » case sysSockoptTTL: | |
88 » » » cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) | |
89 » » case sysSockoptPacketInfo: | |
90 » » » pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0])) | |
91 » » » cm.IfIndex = int(pi.IfIndex) | |
92 » » » cm.Dst = pi.IP[:] | |
93 » » } | |
94 » } | |
95 » return cm, nil | |
96 } | |
97 | |
98 func marshalControlMessage(cm *ControlMessage) (oob []byte) { | |
99 » if cm == nil { | |
100 » » return | |
101 » } | |
102 » l, off := 0, 0 | |
103 » pion := false | |
104 » if cm.Src.To4() != nil || cm.IfIndex != 0 { | |
105 » » pion = true | |
106 » » l += syscall.CmsgSpace(sysSizeofPacketInfo) | |
107 » } | |
108 » if l > 0 { | |
109 » » oob = make([]byte, l) | |
110 » » if pion { | |
111 » » » m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) | |
112 » » » m.Level = ianaProtocolIP | |
113 » » » m.Type = sysSockoptPacketInfo | |
114 » » » m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo)) | |
115 » » » pi := (*sysPacketInfo)(unsafe.Pointer(&oob[off+syscall.C
msgLen(0)])) | |
116 » » » if ip := cm.Src.To4(); ip != nil { | |
117 » » » » copy(pi.IP[:], ip) | |
118 » » » } | |
119 » » » if cm.IfIndex != 0 { | |
120 » » » » pi.IfIndex = int32(cm.IfIndex) | |
121 » » » } | |
122 » » » off += syscall.CmsgSpace(sysSizeofPacketInfo) | |
123 » » } | |
124 } | 64 } |
125 return | 65 return |
126 } | 66 } |
| 67 |
| 68 func (cm *ControlMessage) oobLen() (l int) { |
| 69 if cm.Src.To4() != nil || cm.IfIndex != 0 { |
| 70 l += syscall.CmsgSpace(sysSizeofPacketInfo) |
| 71 } |
| 72 return |
| 73 } |
| 74 |
| 75 func (cm *ControlMessage) parseControlMessage(m *syscall.SocketControlMessage) { |
| 76 switch m.Header.Type { |
| 77 case sysSockoptTTL: |
| 78 cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) |
| 79 case sysSockoptPacketInfo: |
| 80 pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0])) |
| 81 cm.IfIndex = int(pi.IfIndex) |
| 82 cm.Dst = pi.IP[:] |
| 83 } |
| 84 } |
LEFT | RIGHT |