blob: cd9dc87289a11eb71dd3ad2519b16bb560628ea7 [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
5// +build darwin freebsd netbsd openbsd
6
7package ipv4
8
9import (
10 "net"
11 "os"
12 "syscall"
13 "unsafe"
14)
15
16func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
17 opt.lock()
18 defer opt.unlock()
19 if cf&FlagTTL != 0 {
20 if err := setIPv4ReceiveTTL(fd, on); err != nil {
21 return err
22 }
23 if on {
24 opt.set(FlagTTL)
25 } else {
26 opt.clear(FlagTTL)
27 }
28 }
29 if cf&FlagDst != 0 {
30 if err := setIPv4ReceiveDestinationAddress(fd, on); err != nil {
31 return err
32 }
33 if on {
34 opt.set(FlagDst)
35 } else {
36 opt.clear(FlagDst)
37 }
38 }
39 if cf&FlagInterface != 0 {
40 if err := setIPv4ReceiveInterface(fd, on); err != nil {
41 return err
42 }
43 if on {
44 opt.set(FlagInterface)
45 } else {
46 opt.clear(FlagInterface)
47 }
48 }
49 return nil
50}
51
52func newControlMessage(opt *rawOpt) (oob []byte) {
53 opt.lock()
54 defer opt.unlock()
55 if opt.isset(FlagTTL) {
56 b := make([]byte, syscall.CmsgSpace(1))
57 cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
Mikio Hara8108b4b2013-06-07 14:52:58 +090058 cmsg.Level = ianaProtocolIP
Mikio Harad2e5a122012-09-26 21:03:09 +090059 cmsg.Type = syscall.IP_RECVTTL
60 cmsg.SetLen(syscall.CmsgLen(1))
61 oob = append(oob, b...)
62 }
63 if opt.isset(FlagDst) {
64 b := make([]byte, syscall.CmsgSpace(net.IPv4len))
65 cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
Mikio Hara8108b4b2013-06-07 14:52:58 +090066 cmsg.Level = ianaProtocolIP
Mikio Harad2e5a122012-09-26 21:03:09 +090067 cmsg.Type = syscall.IP_RECVDSTADDR
68 cmsg.SetLen(syscall.CmsgLen(net.IPv4len))
69 oob = append(oob, b...)
70 }
71 if opt.isset(FlagInterface) {
72 b := make([]byte, syscall.CmsgSpace(syscall.SizeofSockaddrDatalink))
73 cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
Mikio Hara8108b4b2013-06-07 14:52:58 +090074 cmsg.Level = ianaProtocolIP
Mikio Harad2e5a122012-09-26 21:03:09 +090075 cmsg.Type = syscall.IP_RECVIF
76 cmsg.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrDatalink))
77 oob = append(oob, b...)
78 }
79 return
80}
81
82func parseControlMessage(b []byte) (*ControlMessage, error) {
83 cmsgs, err := syscall.ParseSocketControlMessage(b)
84 if err != nil {
85 return nil, os.NewSyscallError("parse socket control message", err)
86 }
87 if len(b) == 0 {
88 return nil, nil
89 }
90 cm := &ControlMessage{}
91 for _, m := range cmsgs {
Mikio Hara8108b4b2013-06-07 14:52:58 +090092 if m.Header.Level != ianaProtocolIP {
Mikio Harad2e5a122012-09-26 21:03:09 +090093 continue
94 }
95 switch m.Header.Type {
96 case syscall.IP_RECVTTL:
97 cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
98 case syscall.IP_RECVDSTADDR:
99 v := m.Data[:4]
100 cm.Dst = net.IPv4(v[0], v[1], v[2], v[3])
101 case syscall.IP_RECVIF:
102 sadl := (*syscall.SockaddrDatalink)(unsafe.Pointer(&m.Data[0]))
103 cm.IfIndex = int(sadl.Index)
104 }
105 }
106 return cm, nil
107}
108
109func marshalControlMessage(cm *ControlMessage) []byte {
110 // TODO(mikio): Implement IP_PKTINFO stuff when OS X 10.8 comes
111 return nil
112}