blob: 51b9a14b1d7b8a8287249c971d6b74e7238803f4 [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 (
8 "net"
9 "os"
10 "syscall"
11 "unsafe"
12)
13
14// Linux provides a convenient path control option IP_PKTINFO that
15// contains IP_SENDSRCADDR, IP_RECVDSTADDR, IP_RECVIF and IP_SENDIF.
16const pktinfo = FlagSrc | FlagDst | FlagInterface
17
18func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
19 opt.lock()
20 defer opt.unlock()
21 if cf&FlagTTL != 0 {
22 if err := setIPv4ReceiveTTL(fd, on); err != nil {
23 return err
24 }
25 if on {
26 opt.set(FlagTTL)
27 } else {
28 opt.clear(FlagTTL)
29 }
30 }
31 if cf&pktinfo != 0 {
32 if err := setIPv4PacketInfo(fd, on); err != nil {
33 return err
34 }
35 if on {
36 opt.set(cf & pktinfo)
37 } else {
38 opt.clear(cf & pktinfo)
39 }
40 }
41 return nil
42}
43
44func newControlMessage(opt *rawOpt) (oob []byte) {
45 opt.lock()
46 defer opt.unlock()
47 if opt.isset(FlagTTL) {
48 b := make([]byte, syscall.CmsgSpace(1))
49 cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
50 cmsg.Level = syscall.IPPROTO_IP
51 cmsg.Type = syscall.IP_RECVTTL
52 cmsg.SetLen(syscall.CmsgLen(1))
53 oob = append(oob, b...)
54 }
55 if opt.isset(pktinfo) {
56 b := make([]byte, syscall.CmsgSpace(syscall.SizeofInet4Pktinfo))
57 cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
58 cmsg.Level = syscall.IPPROTO_IP
59 cmsg.Type = syscall.IP_PKTINFO
60 cmsg.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
61 oob = append(oob, b...)
62 }
63 return
64}
65
66func parseControlMessage(b []byte) (*ControlMessage, error) {
67 cmsgs, err := syscall.ParseSocketControlMessage(b)
68 if err != nil {
69 return nil, os.NewSyscallError("parse socket control message", err)
70 }
71 if len(b) == 0 {
72 return nil, nil
73 }
74 cm := &ControlMessage{}
75 for _, m := range cmsgs {
76 if m.Header.Level != syscall.IPPROTO_IP {
77 continue
78 }
79 switch m.Header.Type {
80 case syscall.IP_TTL:
81 cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
82 case syscall.IP_PKTINFO:
83 pi := (*syscall.Inet4Pktinfo)(unsafe.Pointer(&m.Data[0]))
84 cm.IfIndex = int(pi.Ifindex)
85 cm.Dst = net.IPv4(pi.Addr[0], pi.Addr[1], pi.Addr[2], pi.Addr[3])
86 }
87 }
88 return cm, nil
89}
90
91func marshalControlMessage(cm *ControlMessage) (oob []byte) {
92 if cm == nil {
93 return
94 }
95 pi := &syscall.Inet4Pktinfo{}
96 pion := false
97 if ip := cm.Src.To4(); ip != nil {
Mikio Harab38392a2013-02-14 07:01:07 +090098 copy(pi.Spec_dst[:], ip[:net.IPv4len])
Mikio Harad2e5a122012-09-26 21:03:09 +090099 pion = true
100 }
101 if cm.IfIndex != 0 {
102 pi.Ifindex = int32(cm.IfIndex)
103 pion = true
104 }
105 if pion {
106 b := make([]byte, syscall.CmsgSpace(syscall.SizeofInet4Pktinfo))
107 cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
108 cmsg.Level = syscall.IPPROTO_IP
109 cmsg.Type = syscall.IP_PKTINFO
110 cmsg.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
111 data := b[syscall.CmsgLen(0):]
Mikio Harab38392a2013-02-14 07:01:07 +0900112 copy(data[:syscall.SizeofInet4Pktinfo], (*[syscall.SizeofInet4Pktinfo]byte)(unsafe.Pointer(pi))[:syscall.SizeofInet4Pktinfo])
Mikio Harad2e5a122012-09-26 21:03:09 +0900113 oob = append(oob, b...)
114 }
115 return
116}