Files
golang.net/ipv4/control_linux.go
Mikio Hara 8108b4b39d go.net/ipv4: drop DIffServ and ECN constants, add ICMPType
This CL removes DiffServ and ECN constants assigned by IANA because
for now we don't have an appropriate package to put those constants
as part of API. There were used for the type-of-service field of IPv4
header and the traffic class field of IPv6 header.

Also adds ICMPType for convenience, makes use of internal IANA
protocol number constants instead of syscall's to prevent churning of
package syscall in the near future.

R=dave
CC=golang-dev
https://golang.org/cl/9353045
2013-06-07 14:52:58 +09:00

117 lines
2.9 KiB
Go

// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ipv4
import (
"net"
"os"
"syscall"
"unsafe"
)
// Linux provides a convenient path control option IP_PKTINFO that
// contains IP_SENDSRCADDR, IP_RECVDSTADDR, IP_RECVIF and IP_SENDIF.
const pktinfo = FlagSrc | FlagDst | FlagInterface
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
opt.lock()
defer opt.unlock()
if cf&FlagTTL != 0 {
if err := setIPv4ReceiveTTL(fd, on); err != nil {
return err
}
if on {
opt.set(FlagTTL)
} else {
opt.clear(FlagTTL)
}
}
if cf&pktinfo != 0 {
if err := setIPv4PacketInfo(fd, on); err != nil {
return err
}
if on {
opt.set(cf & pktinfo)
} else {
opt.clear(cf & pktinfo)
}
}
return nil
}
func newControlMessage(opt *rawOpt) (oob []byte) {
opt.lock()
defer opt.unlock()
if opt.isset(FlagTTL) {
b := make([]byte, syscall.CmsgSpace(1))
cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
cmsg.Level = ianaProtocolIP
cmsg.Type = syscall.IP_RECVTTL
cmsg.SetLen(syscall.CmsgLen(1))
oob = append(oob, b...)
}
if opt.isset(pktinfo) {
b := make([]byte, syscall.CmsgSpace(syscall.SizeofInet4Pktinfo))
cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
cmsg.Level = ianaProtocolIP
cmsg.Type = syscall.IP_PKTINFO
cmsg.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
oob = append(oob, b...)
}
return
}
func parseControlMessage(b []byte) (*ControlMessage, error) {
cmsgs, err := syscall.ParseSocketControlMessage(b)
if err != nil {
return nil, os.NewSyscallError("parse socket control message", err)
}
if len(b) == 0 {
return nil, nil
}
cm := &ControlMessage{}
for _, m := range cmsgs {
if m.Header.Level != ianaProtocolIP {
continue
}
switch m.Header.Type {
case syscall.IP_TTL:
cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
case syscall.IP_PKTINFO:
pi := (*syscall.Inet4Pktinfo)(unsafe.Pointer(&m.Data[0]))
cm.IfIndex = int(pi.Ifindex)
cm.Dst = net.IPv4(pi.Addr[0], pi.Addr[1], pi.Addr[2], pi.Addr[3])
}
}
return cm, nil
}
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
if cm == nil {
return
}
pi := &syscall.Inet4Pktinfo{}
pion := false
if ip := cm.Src.To4(); ip != nil {
copy(pi.Spec_dst[:], ip[:net.IPv4len])
pion = true
}
if cm.IfIndex != 0 {
pi.Ifindex = int32(cm.IfIndex)
pion = true
}
if pion {
b := make([]byte, syscall.CmsgSpace(syscall.SizeofInet4Pktinfo))
cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
cmsg.Level = ianaProtocolIP
cmsg.Type = syscall.IP_PKTINFO
cmsg.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
data := b[syscall.CmsgLen(0):]
copy(data[:syscall.SizeofInet4Pktinfo], (*[syscall.SizeofInet4Pktinfo]byte)(unsafe.Pointer(pi))[:syscall.SizeofInet4Pktinfo])
oob = append(oob, b...)
}
return
}