mirror of
https://github.com/golang/net.git
synced 2026-03-31 18:37:08 +09:00
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
117 lines
2.9 KiB
Go
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
|
|
}
|