123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- package ipv6
- import (
- "fmt"
- "net"
- "sync"
- "golang.org/x/net/internal/iana"
- "golang.org/x/net/internal/socket"
- )
- type rawOpt struct {
- sync.RWMutex
- cflags ControlFlags
- }
- func (c *rawOpt) set(f ControlFlags) { c.cflags |= f }
- func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f }
- func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
- type ControlFlags uint
- const (
- FlagTrafficClass ControlFlags = 1 << iota
- FlagHopLimit
- FlagSrc
- FlagDst
- FlagInterface
- FlagPathMTU
- )
- const flagPacketInfo = FlagDst | FlagInterface
- type ControlMessage struct {
-
-
-
-
-
-
-
-
- TrafficClass int
- HopLimit int
- Src net.IP
- Dst net.IP
- IfIndex int
- NextHop net.IP
- MTU int
- }
- func (cm *ControlMessage) String() string {
- if cm == nil {
- return "<nil>"
- }
- return fmt.Sprintf("tclass=%#x hoplim=%d src=%v dst=%v ifindex=%d nexthop=%v mtu=%d", cm.TrafficClass, cm.HopLimit, cm.Src, cm.Dst, cm.IfIndex, cm.NextHop, cm.MTU)
- }
- func (cm *ControlMessage) Marshal() []byte {
- if cm == nil {
- return nil
- }
- var l int
- tclass := false
- if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
- tclass = true
- l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
- }
- hoplimit := false
- if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
- hoplimit = true
- l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
- }
- pktinfo := false
- if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) {
- pktinfo = true
- l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
- }
- nexthop := false
- if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
- nexthop = true
- l += socket.ControlMessageSpace(ctlOpts[ctlNextHop].length)
- }
- var b []byte
- if l > 0 {
- b = make([]byte, l)
- bb := b
- if tclass {
- bb = ctlOpts[ctlTrafficClass].marshal(bb, cm)
- }
- if hoplimit {
- bb = ctlOpts[ctlHopLimit].marshal(bb, cm)
- }
- if pktinfo {
- bb = ctlOpts[ctlPacketInfo].marshal(bb, cm)
- }
- if nexthop {
- bb = ctlOpts[ctlNextHop].marshal(bb, cm)
- }
- }
- return b
- }
- func (cm *ControlMessage) Parse(b []byte) error {
- ms, err := socket.ControlMessage(b).Parse()
- if err != nil {
- return err
- }
- for _, m := range ms {
- lvl, typ, l, err := m.ParseHeader()
- if err != nil {
- return err
- }
- if lvl != iana.ProtocolIPv6 {
- continue
- }
- switch typ {
- case ctlOpts[ctlTrafficClass].name:
- ctlOpts[ctlTrafficClass].parse(cm, m.Data(l))
- case ctlOpts[ctlHopLimit].name:
- ctlOpts[ctlHopLimit].parse(cm, m.Data(l))
- case ctlOpts[ctlPacketInfo].name:
- ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
- case ctlOpts[ctlPathMTU].name:
- ctlOpts[ctlPathMTU].parse(cm, m.Data(l))
- }
- }
- return nil
- }
- func NewControlMessage(cf ControlFlags) []byte {
- opt := rawOpt{cflags: cf}
- var l int
- if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
- l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
- }
- if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
- l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
- }
- if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
- l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
- }
- if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
- l += socket.ControlMessageSpace(ctlOpts[ctlPathMTU].length)
- }
- var b []byte
- if l > 0 {
- b = make([]byte, l)
- }
- return b
- }
- const (
- ctlTrafficClass = iota
- ctlHopLimit
- ctlPacketInfo
- ctlNextHop
- ctlPathMTU
- ctlMax
- )
- type ctlOpt struct {
- name int
- length int
- marshal func([]byte, *ControlMessage) []byte
- parse func(*ControlMessage, []byte)
- }
|