123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- // 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.
- // +build darwin dragonfly freebsd linux netbsd openbsd solaris
- package ipv4
- import (
- "os"
- "syscall"
- "unsafe"
- "golang.org/x/net/internal/iana"
- )
- func setControlMessage(s uintptr, opt *rawOpt, cf ControlFlags, on bool) error {
- opt.Lock()
- defer opt.Unlock()
- if cf&FlagTTL != 0 && sockOpts[ssoReceiveTTL].name > 0 {
- if err := setInt(s, &sockOpts[ssoReceiveTTL], boolint(on)); err != nil {
- return err
- }
- if on {
- opt.set(FlagTTL)
- } else {
- opt.clear(FlagTTL)
- }
- }
- if sockOpts[ssoPacketInfo].name > 0 {
- if cf&(FlagSrc|FlagDst|FlagInterface) != 0 {
- if err := setInt(s, &sockOpts[ssoPacketInfo], boolint(on)); err != nil {
- return err
- }
- if on {
- opt.set(cf & (FlagSrc | FlagDst | FlagInterface))
- } else {
- opt.clear(cf & (FlagSrc | FlagDst | FlagInterface))
- }
- }
- } else {
- if cf&FlagDst != 0 && sockOpts[ssoReceiveDst].name > 0 {
- if err := setInt(s, &sockOpts[ssoReceiveDst], boolint(on)); err != nil {
- return err
- }
- if on {
- opt.set(FlagDst)
- } else {
- opt.clear(FlagDst)
- }
- }
- if cf&FlagInterface != 0 && sockOpts[ssoReceiveInterface].name > 0 {
- if err := setInt(s, &sockOpts[ssoReceiveInterface], boolint(on)); err != nil {
- return err
- }
- if on {
- opt.set(FlagInterface)
- } else {
- opt.clear(FlagInterface)
- }
- }
- }
- return nil
- }
- func newControlMessage(opt *rawOpt) (oob []byte) {
- opt.RLock()
- var l int
- if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlTTL].length)
- }
- if ctlOpts[ctlPacketInfo].name > 0 {
- if opt.isset(FlagSrc | FlagDst | FlagInterface) {
- l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
- }
- } else {
- if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlDst].length)
- }
- if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlInterface].length)
- }
- }
- if l > 0 {
- oob = make([]byte, l)
- }
- opt.RUnlock()
- return
- }
- func parseControlMessage(b []byte) (*ControlMessage, error) {
- if len(b) == 0 {
- return nil, nil
- }
- cmsgs, err := syscall.ParseSocketControlMessage(b)
- if err != nil {
- return nil, os.NewSyscallError("parse socket control message", err)
- }
- cm := &ControlMessage{}
- for _, m := range cmsgs {
- if m.Header.Level != iana.ProtocolIP {
- continue
- }
- switch int(m.Header.Type) {
- case ctlOpts[ctlTTL].name:
- ctlOpts[ctlTTL].parse(cm, m.Data[:])
- case ctlOpts[ctlDst].name:
- ctlOpts[ctlDst].parse(cm, m.Data[:])
- case ctlOpts[ctlInterface].name:
- ctlOpts[ctlInterface].parse(cm, m.Data[:])
- case ctlOpts[ctlPacketInfo].name:
- ctlOpts[ctlPacketInfo].parse(cm, m.Data[:])
- }
- }
- return cm, nil
- }
- func marshalControlMessage(cm *ControlMessage) (oob []byte) {
- if cm == nil {
- return nil
- }
- var l int
- pktinfo := false
- if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To4() != nil || cm.IfIndex > 0) {
- pktinfo = true
- l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
- }
- if l > 0 {
- oob = make([]byte, l)
- b := oob
- if pktinfo {
- b = ctlOpts[ctlPacketInfo].marshal(b, cm)
- }
- }
- return
- }
- func marshalTTL(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIP
- m.Type = sysIP_RECVTTL
- m.SetLen(syscall.CmsgLen(1))
- return b[syscall.CmsgSpace(1):]
- }
- func parseTTL(cm *ControlMessage, b []byte) {
- cm.TTL = int(*(*byte)(unsafe.Pointer(&b[:1][0])))
- }
|