gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

control.go (4319B)


      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 	"fmt"
      9 	"net"
     10 	"sync"
     11 
     12 	"golang.org/x/net/internal/iana"
     13 	"golang.org/x/net/internal/socket"
     14 )
     15 
     16 type rawOpt struct {
     17 	sync.RWMutex
     18 	cflags ControlFlags
     19 }
     20 
     21 func (c *rawOpt) set(f ControlFlags)        { c.cflags |= f }
     22 func (c *rawOpt) clear(f ControlFlags)      { c.cflags &^= f }
     23 func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
     24 
     25 type ControlFlags uint
     26 
     27 const (
     28 	FlagTTL       ControlFlags = 1 << iota // pass the TTL on the received packet
     29 	FlagSrc                                // pass the source address on the received packet
     30 	FlagDst                                // pass the destination address on the received packet
     31 	FlagInterface                          // pass the interface index on the received packet
     32 )
     33 
     34 // A ControlMessage represents per packet basis IP-level socket options.
     35 type ControlMessage struct {
     36 	// Receiving socket options: SetControlMessage allows to
     37 	// receive the options from the protocol stack using ReadFrom
     38 	// method of PacketConn or RawConn.
     39 	//
     40 	// Specifying socket options: ControlMessage for WriteTo
     41 	// method of PacketConn or RawConn allows to send the options
     42 	// to the protocol stack.
     43 	//
     44 	TTL     int    // time-to-live, receiving only
     45 	Src     net.IP // source address, specifying only
     46 	Dst     net.IP // destination address, receiving only
     47 	IfIndex int    // interface index, must be 1 <= value when specifying
     48 }
     49 
     50 func (cm *ControlMessage) String() string {
     51 	if cm == nil {
     52 		return "<nil>"
     53 	}
     54 	return fmt.Sprintf("ttl=%d src=%v dst=%v ifindex=%d", cm.TTL, cm.Src, cm.Dst, cm.IfIndex)
     55 }
     56 
     57 // Marshal returns the binary encoding of cm.
     58 func (cm *ControlMessage) Marshal() []byte {
     59 	if cm == nil {
     60 		return nil
     61 	}
     62 	var m socket.ControlMessage
     63 	if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To4() != nil || cm.IfIndex > 0) {
     64 		m = socket.NewControlMessage([]int{ctlOpts[ctlPacketInfo].length})
     65 	}
     66 	if len(m) > 0 {
     67 		ctlOpts[ctlPacketInfo].marshal(m, cm)
     68 	}
     69 	return m
     70 }
     71 
     72 // Parse parses b as a control message and stores the result in cm.
     73 func (cm *ControlMessage) Parse(b []byte) error {
     74 	ms, err := socket.ControlMessage(b).Parse()
     75 	if err != nil {
     76 		return err
     77 	}
     78 	for _, m := range ms {
     79 		lvl, typ, l, err := m.ParseHeader()
     80 		if err != nil {
     81 			return err
     82 		}
     83 		if lvl != iana.ProtocolIP {
     84 			continue
     85 		}
     86 		switch {
     87 		case typ == ctlOpts[ctlTTL].name && l >= ctlOpts[ctlTTL].length:
     88 			ctlOpts[ctlTTL].parse(cm, m.Data(l))
     89 		case typ == ctlOpts[ctlDst].name && l >= ctlOpts[ctlDst].length:
     90 			ctlOpts[ctlDst].parse(cm, m.Data(l))
     91 		case typ == ctlOpts[ctlInterface].name && l >= ctlOpts[ctlInterface].length:
     92 			ctlOpts[ctlInterface].parse(cm, m.Data(l))
     93 		case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length:
     94 			ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
     95 		}
     96 	}
     97 	return nil
     98 }
     99 
    100 // NewControlMessage returns a new control message.
    101 //
    102 // The returned message is large enough for options specified by cf.
    103 func NewControlMessage(cf ControlFlags) []byte {
    104 	opt := rawOpt{cflags: cf}
    105 	var l int
    106 	if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 {
    107 		l += socket.ControlMessageSpace(ctlOpts[ctlTTL].length)
    108 	}
    109 	if ctlOpts[ctlPacketInfo].name > 0 {
    110 		if opt.isset(FlagSrc | FlagDst | FlagInterface) {
    111 			l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
    112 		}
    113 	} else {
    114 		if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 {
    115 			l += socket.ControlMessageSpace(ctlOpts[ctlDst].length)
    116 		}
    117 		if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 {
    118 			l += socket.ControlMessageSpace(ctlOpts[ctlInterface].length)
    119 		}
    120 	}
    121 	var b []byte
    122 	if l > 0 {
    123 		b = make([]byte, l)
    124 	}
    125 	return b
    126 }
    127 
    128 // Ancillary data socket options
    129 const (
    130 	ctlTTL        = iota // header field
    131 	ctlSrc               // header field
    132 	ctlDst               // header field
    133 	ctlInterface         // inbound or outbound interface
    134 	ctlPacketInfo        // inbound or outbound packet path
    135 	ctlMax
    136 )
    137 
    138 // A ctlOpt represents a binding for ancillary data socket option.
    139 type ctlOpt struct {
    140 	name    int // option name, must be equal or greater than 1
    141 	length  int // option length
    142 	marshal func([]byte, *ControlMessage) []byte
    143 	parse   func(*ControlMessage, []byte)
    144 }