Mikio Hara | d2e5a12 | 2012-09-26 21:03:09 +0900 | [diff] [blame] | 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. |
| 4 | |
| 5 | package ipv4 |
| 6 | |
| 7 | import ( |
| 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. |
| 16 | const pktinfo = FlagSrc | FlagDst | FlagInterface |
| 17 | |
| 18 | func 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 | |
| 44 | func 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 | |
| 66 | func 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 | |
| 91 | func 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 Hara | b38392a | 2013-02-14 07:01:07 +0900 | [diff] [blame] | 98 | copy(pi.Spec_dst[:], ip[:net.IPv4len]) |
Mikio Hara | d2e5a12 | 2012-09-26 21:03:09 +0900 | [diff] [blame] | 99 | 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 Hara | b38392a | 2013-02-14 07:01:07 +0900 | [diff] [blame] | 112 | copy(data[:syscall.SizeofInet4Pktinfo], (*[syscall.SizeofInet4Pktinfo]byte)(unsafe.Pointer(pi))[:syscall.SizeofInet4Pktinfo]) |
Mikio Hara | d2e5a12 | 2012-09-26 21:03:09 +0900 | [diff] [blame] | 113 | oob = append(oob, b...) |
| 114 | } |
| 115 | return |
| 116 | } |