blob: fa7630fdf9d9fe62a626918a0dc6b8312bd8df3d [file] [log] [blame]
Mikio Harad2e5a122012-09-26 21:03:09 +09001// 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.
4
5package ipv4
6
7import (
Mikio Harad2e5a122012-09-26 21:03:09 +09008 "os"
9 "syscall"
10 "unsafe"
11)
12
13// Linux provides a convenient path control option IP_PKTINFO that
14// contains IP_SENDSRCADDR, IP_RECVDSTADDR, IP_RECVIF and IP_SENDIF.
15const pktinfo = FlagSrc | FlagDst | FlagInterface
16
17func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
Mikio Haraecb7ecd2013-06-17 00:40:07 +090018 opt.Lock()
19 defer opt.Unlock()
Mikio Harad2e5a122012-09-26 21:03:09 +090020 if cf&FlagTTL != 0 {
21 if err := setIPv4ReceiveTTL(fd, on); err != nil {
22 return err
23 }
24 if on {
25 opt.set(FlagTTL)
26 } else {
27 opt.clear(FlagTTL)
28 }
29 }
30 if cf&pktinfo != 0 {
31 if err := setIPv4PacketInfo(fd, on); err != nil {
32 return err
33 }
34 if on {
35 opt.set(cf & pktinfo)
36 } else {
37 opt.clear(cf & pktinfo)
38 }
39 }
40 return nil
41}
42
43func newControlMessage(opt *rawOpt) (oob []byte) {
Mikio Haraecb7ecd2013-06-17 00:40:07 +090044 opt.Lock()
45 defer opt.Unlock()
46 l, off := 0, 0
Mikio Harad2e5a122012-09-26 21:03:09 +090047 if opt.isset(FlagTTL) {
Mikio Haraecb7ecd2013-06-17 00:40:07 +090048 l += syscall.CmsgSpace(1)
Mikio Harad2e5a122012-09-26 21:03:09 +090049 }
50 if opt.isset(pktinfo) {
Mikio Haraecb7ecd2013-06-17 00:40:07 +090051 l += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
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 = syscall.IP_RECVTTL
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 = syscall.IP_PKTINFO
66 m.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
67 off += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
68 }
Mikio Harad2e5a122012-09-26 21:03:09 +090069 }
70 return
71}
72
73func parseControlMessage(b []byte) (*ControlMessage, error) {
Mikio Haraecb7ecd2013-06-17 00:40:07 +090074 if len(b) == 0 {
75 return nil, nil
76 }
Mikio Harad2e5a122012-09-26 21:03:09 +090077 cmsgs, err := syscall.ParseSocketControlMessage(b)
78 if err != nil {
79 return nil, os.NewSyscallError("parse socket control message", err)
80 }
Mikio Harad2e5a122012-09-26 21:03:09 +090081 cm := &ControlMessage{}
82 for _, m := range cmsgs {
Mikio Hara8108b4b2013-06-07 14:52:58 +090083 if m.Header.Level != ianaProtocolIP {
Mikio Harad2e5a122012-09-26 21:03:09 +090084 continue
85 }
86 switch m.Header.Type {
87 case syscall.IP_TTL:
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)
Mikio Haraecb7ecd2013-06-17 00:40:07 +090092 cm.Dst = pi.Addr[:]
Mikio Harad2e5a122012-09-26 21:03:09 +090093 }
94 }
95 return cm, nil
96}
97
98func marshalControlMessage(cm *ControlMessage) (oob []byte) {
99 if cm == nil {
100 return
101 }
Mikio Haraecb7ecd2013-06-17 00:40:07 +0900102 l, off := 0, 0
Mikio Harad2e5a122012-09-26 21:03:09 +0900103 pion := false
Mikio Haraecb7ecd2013-06-17 00:40:07 +0900104 if cm.Src.To4() != nil || cm.IfIndex != 0 {
Mikio Harad2e5a122012-09-26 21:03:09 +0900105 pion = true
Mikio Haraecb7ecd2013-06-17 00:40:07 +0900106 l += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
Mikio Harad2e5a122012-09-26 21:03:09 +0900107 }
Mikio Haraecb7ecd2013-06-17 00:40:07 +0900108 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 = 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 {
117 copy(pi.Addr[:], ip)
118 }
119 if cm.IfIndex != 0 {
120 pi.Ifindex = int32(cm.IfIndex)
121 }
122 off += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
123 }
Mikio Harad2e5a122012-09-26 21:03:09 +0900124 }
125 return
126}