1
// Copyright 2012 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
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
17
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
21
if err := setIPv4ReceiveTTL(fd, on); err != nil {
31
if err := setIPv4PacketInfo(fd, on); err != nil {
37
opt.clear(cf & pktinfo)
43
func newControlMessage(opt *rawOpt) (oob []byte) {
47
if opt.isset(FlagTTL) {
48
l += syscall.CmsgSpace(1)
50
if opt.isset(pktinfo) {
51
l += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
55
if opt.isset(FlagTTL) {
56
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
57
m.Level = ianaProtocolIP
58
m.Type = syscall.IP_RECVTTL
59
m.SetLen(syscall.CmsgLen(1))
60
off += syscall.CmsgSpace(1)
62
if opt.isset(pktinfo) {
63
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
64
m.Level = ianaProtocolIP
65
m.Type = syscall.IP_PKTINFO
66
m.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
67
off += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
73
func parseControlMessage(b []byte) (*ControlMessage, error) {
77
cmsgs, err := syscall.ParseSocketControlMessage(b)
79
return nil, os.NewSyscallError("parse socket control message", err)
81
cm := &ControlMessage{}
82
for _, m := range cmsgs {
83
if m.Header.Level != ianaProtocolIP {
86
switch m.Header.Type {
88
cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
89
case syscall.IP_PKTINFO:
90
pi := (*syscall.Inet4Pktinfo)(unsafe.Pointer(&m.Data[0]))
91
cm.IfIndex = int(pi.Ifindex)
98
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
104
if cm.Src.To4() != nil || cm.IfIndex != 0 {
106
l += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
109
oob = make([]byte, l)
111
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
112
m.Level = ianaProtocolIP
113
m.Type = syscall.IP_PKTINFO
114
m.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
115
pi := (*syscall.Inet4Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
116
if ip := cm.Src.To4(); ip != nil {
120
pi.Ifindex = int32(cm.IfIndex)
122
off += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)