if l == 0 {
return 0
}
- i := int(float64(l) * q)
+ i := int(math.Ceil(float64(l) * q))
if i > 0 {
i -= 1
}
default:
key = fmt.Sprint(x)
}
- if x, ok := v.(error); ok {
- v = safeError(x)
- }
// We want json.Marshaler and encoding.TextMarshaller to take priority over
// err.Error() and v.String(). But json.Marshall (called later) does that by
-package log
+package log
import (
"io"
-Copyright 2014 Chris Hines
+The MIT License (MIT)
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
+Copyright (c) 2014 Chris Hines
- http://www.apache.org/licenses/LICENSE-2.0
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
}
c.pc = pcs[1]
- if runtime.FuncForPC(pcs[0]) != sigpanic {
+ if runtime.FuncForPC(pcs[0]).Name() != "runtime.sigpanic" {
c.pc--
}
c.fn = runtime.FuncForPC(c.pc)
// %s source file
// %d line number
// %n function name
+// %k last segment of the package path
// %v equivalent to %s:%d
//
// It accepts the '+' and '#' flags for most of the verbs as follows.
// %+s path of source file relative to the compile time GOPATH
// %#s full path of source file
// %+n import path qualified function name
+// %+k full package path
// %+v equivalent to %+s:%d
// %#v equivalent to %#s:%d
func (c Call) Format(s fmt.State, verb rune) {
buf := [6]byte{}
s.Write(strconv.AppendInt(buf[:0], int64(line), 10))
+ case 'k':
+ name := c.fn.Name()
+ const pathSep = "/"
+ start, end := 0, len(name)
+ if i := strings.LastIndex(name, pathSep); i != -1 {
+ start = i + len(pathSep)
+ }
+ const pkgSep = "."
+ if i := strings.Index(name[start:], pkgSep); i != -1 {
+ end = start + i
+ }
+ if s.Flag('+') {
+ start = 0
+ }
+ io.WriteString(s, name[start:end])
+
case 'n':
name := c.fn.Name()
if !s.Flag('+') {
s.Write(closeBracketBytes)
}
-// findSigpanic intentionally executes faulting code to generate a stack trace
-// containing an entry for runtime.sigpanic.
-func findSigpanic() *runtime.Func {
- var fn *runtime.Func
- var p *int
- func() int {
- defer func() {
- if p := recover(); p != nil {
- var pcs [512]uintptr
- n := runtime.Callers(2, pcs[:])
- for _, pc := range pcs[:n] {
- f := runtime.FuncForPC(pc)
- if f.Name() == "runtime.sigpanic" {
- fn = f
- break
- }
- }
- }
- }()
- // intentional nil pointer dereference to trigger sigpanic
- return *p
- }()
- return fn
-}
-
-var sigpanic = findSigpanic()
-
// Trace returns a CallStack for the current goroutine with element 0
// identifying the calling function.
func Trace() CallStack {
for i, pc := range pcs[:n] {
pcFix := pc
- if i > 0 && cs[i-1].fn != sigpanic {
+ if i > 0 && cs[i-1].fn.Name() != "runtime.sigpanic" {
pcFix--
}
cs[i] = Call{
mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
}
- if emIn, ok := in.Addr().Interface().(extendableProto); ok {
- emOut := out.Addr().Interface().(extendableProto)
- mergeExtension(emOut.ExtensionMap(), emIn.ExtensionMap())
+ if emIn, ok := extendable(in.Addr().Interface()); ok {
+ emOut, _ := extendable(out.Addr().Interface())
+ mIn, muIn := emIn.extensionsRead()
+ if mIn != nil {
+ mOut := emOut.extensionsWrite()
+ muIn.Lock()
+ mergeExtension(mOut, mIn)
+ muIn.Unlock()
+ }
}
uf := in.FieldByName("XXX_unrecognized")
// int32, int64, uint32, uint64, bool, and enum
// protocol buffer types.
func DecodeVarint(buf []byte) (x uint64, n int) {
- // x, n already 0
for shift := uint(0); shift < 64; shift += 7 {
if n >= len(buf) {
return 0, 0
return 0, 0
}
-// DecodeVarint reads a varint-encoded integer from the Buffer.
-// This is the format for the
-// int32, int64, uint32, uint64, bool, and enum
-// protocol buffer types.
-func (p *Buffer) DecodeVarint() (x uint64, err error) {
- // x, err already 0
-
+func (p *Buffer) decodeVarintSlow() (x uint64, err error) {
i := p.index
l := len(p.buf)
return
}
+// DecodeVarint reads a varint-encoded integer from the Buffer.
+// This is the format for the
+// int32, int64, uint32, uint64, bool, and enum
+// protocol buffer types.
+func (p *Buffer) DecodeVarint() (x uint64, err error) {
+ i := p.index
+ buf := p.buf
+
+ if i >= len(buf) {
+ return 0, io.ErrUnexpectedEOF
+ } else if buf[i] < 0x80 {
+ p.index++
+ return uint64(buf[i]), nil
+ } else if len(buf)-i < 10 {
+ return p.decodeVarintSlow()
+ }
+
+ var b uint64
+ // we already checked the first byte
+ x = uint64(buf[i]) - 0x80
+ i++
+
+ b = uint64(buf[i])
+ i++
+ x += b << 7
+ if b&0x80 == 0 {
+ goto done
+ }
+ x -= 0x80 << 7
+
+ b = uint64(buf[i])
+ i++
+ x += b << 14
+ if b&0x80 == 0 {
+ goto done
+ }
+ x -= 0x80 << 14
+
+ b = uint64(buf[i])
+ i++
+ x += b << 21
+ if b&0x80 == 0 {
+ goto done
+ }
+ x -= 0x80 << 21
+
+ b = uint64(buf[i])
+ i++
+ x += b << 28
+ if b&0x80 == 0 {
+ goto done
+ }
+ x -= 0x80 << 28
+
+ b = uint64(buf[i])
+ i++
+ x += b << 35
+ if b&0x80 == 0 {
+ goto done
+ }
+ x -= 0x80 << 35
+
+ b = uint64(buf[i])
+ i++
+ x += b << 42
+ if b&0x80 == 0 {
+ goto done
+ }
+ x -= 0x80 << 42
+
+ b = uint64(buf[i])
+ i++
+ x += b << 49
+ if b&0x80 == 0 {
+ goto done
+ }
+ x -= 0x80 << 49
+
+ b = uint64(buf[i])
+ i++
+ x += b << 56
+ if b&0x80 == 0 {
+ goto done
+ }
+ x -= 0x80 << 56
+
+ b = uint64(buf[i])
+ i++
+ x += b << 63
+ if b&0x80 == 0 {
+ goto done
+ }
+ // x -= 0x80 << 63 // Always zero.
+
+ return 0, errOverflow
+
+done:
+ p.index = i
+ return x, nil
+}
+
// DecodeFixed64 reads a 64-bit integer from the Buffer.
// This is the format for the
// fixed64, sfixed64, and double protocol buffer types.
// Buffer and places the decoded result in pb. If the struct
// underlying pb does not match the data in the buffer, the results can be
// unpredictable.
+//
+// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal.
func (p *Buffer) Unmarshal(pb Message) error {
// If the object can unmarshal itself, let it.
if u, ok := pb.(Unmarshaler); ok {
wire := int(u & 0x7)
if wire == WireEndGroup {
if is_group {
+ if required > 0 {
+ // Not enough information to determine the exact field.
+ // (See below.)
+ return &RequiredNotSetError{"{Unknown}"}
+ }
return nil // input is satisfied
}
return fmt.Errorf("proto: %s: wiretype end group for non-group", st)
if !ok {
// Maybe it's an extension?
if prop.extendable {
- if e := structPointer_Interface(base, st).(extendableProto); isExtensionField(e, int32(tag)) {
+ if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) {
if err = o.skip(st, tag, wire); err == nil {
- ext := e.ExtensionMap()[int32(tag)] // may be missing
+ extmap := e.extensionsWrite()
+ ext := extmap[int32(tag)] // may be missing
ext.enc = append(ext.enc, o.buf[oi:o.index]...)
- e.ExtensionMap()[int32(tag)] = ext
+ extmap[int32(tag)] = ext
}
continue
}
// ErrNil is the error returned if Marshal is called with nil.
ErrNil = errors.New("proto: Marshal called with nil")
+
+ // ErrTooLarge is the error returned if Marshal is called with a
+ // message that encodes to >2GB.
+ ErrTooLarge = errors.New("proto: message encodes to over 2 GB")
)
// The fundamental encoders that put bytes on the wire.
const maxVarintBytes = 10 // maximum length of a varint
+// maxMarshalSize is the largest allowed size of an encoded protobuf,
+// since C++ and Java use signed int32s for the size.
+const maxMarshalSize = 1<<31 - 1
+
// EncodeVarint returns the varint encoding of x.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
// This is the format used for the sint64 protocol buffer type.
func (p *Buffer) EncodeZigzag64(x uint64) error {
// use signed number to get arithmetic right shift.
- return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+ return p.EncodeVarint((x << 1) ^ uint64((int64(x) >> 63)))
}
func sizeZigzag64(x uint64) int {
- return sizeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+ return sizeVarint((x << 1) ^ uint64((int64(x) >> 63)))
}
// EncodeZigzag32 writes a zigzag-encoded 32-bit integer
}
p := NewBuffer(nil)
err := p.Marshal(pb)
- var state errorState
- if err != nil && !state.shouldContinue(err, nil) {
- return nil, err
- }
if p.buf == nil && err == nil {
// Return a non-nil slice on success.
return []byte{}, nil
// Can the object marshal itself?
if m, ok := pb.(Marshaler); ok {
data, err := m.Marshal()
- if err != nil {
- return err
- }
p.buf = append(p.buf, data...)
- return nil
+ return err
}
t, base, err := getbase(pb)
}
if collectStats {
- stats.Encode++
+ (stats).Encode++ // Parens are to work around a goimports bug.
}
+ if len(p.buf) > maxMarshalSize {
+ return ErrTooLarge
+ }
return err
}
}
if collectStats {
- stats.Size++
+ (stats).Size++ // Parens are to work around a goimports bug.
}
return
if p.isMarshaler {
m := structPointer_Interface(structp, p.stype).(Marshaler)
data, _ := m.Marshal()
- n += len(p.tagcode)
n += sizeRawBytes(data)
continue
}
// Encode an extension map.
func (o *Buffer) enc_map(p *Properties, base structPointer) error {
- v := *structPointer_ExtMap(base, p.field)
- if err := encodeExtensionMap(v); err != nil {
+ exts := structPointer_ExtMap(base, p.field)
+ if err := encodeExtensionsMap(*exts); err != nil {
return err
}
+
+ return o.enc_map_body(*exts)
+}
+
+func (o *Buffer) enc_exts(p *Properties, base structPointer) error {
+ exts := structPointer_Extensions(base, p.field)
+
+ v, mu := exts.extensionsRead()
+ if v == nil {
+ return nil
+ }
+
+ mu.Lock()
+ defer mu.Unlock()
+ if err := encodeExtensionsMap(v); err != nil {
+ return err
+ }
+
+ return o.enc_map_body(v)
+}
+
+func (o *Buffer) enc_map_body(v map[int32]Extension) error {
// Fast-path for common cases: zero or one extensions.
if len(v) <= 1 {
for _, e := range v {
}
func size_map(p *Properties, base structPointer) int {
- v := *structPointer_ExtMap(base, p.field)
- return sizeExtensionMap(v)
+ v := structPointer_ExtMap(base, p.field)
+ return extensionsMapSize(*v)
+}
+
+func size_exts(p *Properties, base structPointer) int {
+ v := structPointer_Extensions(base, p.field)
+ return extensionsSize(v)
}
// Encode a map field.
if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil {
return err
}
- if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil {
+ if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil {
return err
}
return nil
for _, key := range v.MapKeys() {
val := v.MapIndex(key)
- // The only illegal map entry values are nil message pointers.
- if val.Kind() == reflect.Ptr && val.IsNil() {
- return errors.New("proto: map has nil element")
- }
-
keycopy.Set(key)
valcopy.Set(val)
return err
}
}
+ if len(o.buf) > maxMarshalSize {
+ return ErrTooLarge
+ }
}
}
// Add unrecognized fields at the end.
if prop.unrecField.IsValid() {
v := *structPointer_Bytes(base, prop.unrecField)
+ if len(o.buf)+len(v) > maxMarshalSize {
+ return ErrTooLarge
+ }
if len(v) > 0 {
o.buf = append(o.buf, v...)
}
in a proto3 .proto file, fields are not "set"; specifically,
zero length proto3 "bytes" fields are equal (nil == {}).
- Two repeated fields are equal iff their lengths are the same,
- and their corresponding elements are equal (a "bytes" field,
- although represented by []byte, is not a repeated field)
+ and their corresponding elements are equal. Note a "bytes" field,
+ although represented by []byte, is not a repeated field and the
+ rule for the scalar fields described above applies.
- Two unset fields are equal.
- Two unknown field sets are equal if their current
encoded state is equal.
- Two extension sets are equal iff they have corresponding
elements that are pairwise equal.
+ - Two map fields are equal iff their lengths are the same,
+ and they contain the same set of elements. Zero-length map
+ fields are equal.
- Every other combination of things are not equal.
The return value is undefined if a and b are not protocol buffers.
}
}
+ if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() {
+ em2 := v2.FieldByName("XXX_InternalExtensions")
+ if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) {
+ return false
+ }
+ }
+
if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() {
em2 := v2.FieldByName("XXX_extensions")
- if !equalExtensions(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) {
+ if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) {
return false
}
}
}
return true
case reflect.Ptr:
+ // Maps may have nil values in them, so check for nil.
+ if v1.IsNil() && v2.IsNil() {
+ return true
+ }
+ if v1.IsNil() != v2.IsNil() {
+ return false
+ }
return equalAny(v1.Elem(), v2.Elem(), prop)
case reflect.Slice:
if v1.Type().Elem().Kind() == reflect.Uint8 {
}
// base is the struct type that the extensions are based on.
-// em1 and em2 are extension maps.
-func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
+// x1 and x2 are InternalExtensions.
+func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool {
+ em1, _ := x1.extensionsRead()
+ em2, _ := x2.extensionsRead()
+ return equalExtMap(base, em1, em2)
+}
+
+func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
if len(em1) != len(em2) {
return false
}
Start, End int32 // both inclusive
}
-// extendableProto is an interface implemented by any protocol buffer that may be extended.
+// extendableProto is an interface implemented by any protocol buffer generated by the current
+// proto compiler that may be extended.
type extendableProto interface {
+ Message
+ ExtensionRangeArray() []ExtensionRange
+ extensionsWrite() map[int32]Extension
+ extensionsRead() (map[int32]Extension, sync.Locker)
+}
+
+// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous
+// version of the proto compiler that may be extended.
+type extendableProtoV1 interface {
Message
ExtensionRangeArray() []ExtensionRange
ExtensionMap() map[int32]Extension
}
+// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto.
+type extensionAdapter struct {
+ extendableProtoV1
+}
+
+func (e extensionAdapter) extensionsWrite() map[int32]Extension {
+ return e.ExtensionMap()
+}
+
+func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) {
+ return e.ExtensionMap(), notLocker{}
+}
+
+// notLocker is a sync.Locker whose Lock and Unlock methods are nops.
+type notLocker struct{}
+
+func (n notLocker) Lock() {}
+func (n notLocker) Unlock() {}
+
+// extendable returns the extendableProto interface for the given generated proto message.
+// If the proto message has the old extension format, it returns a wrapper that implements
+// the extendableProto interface.
+func extendable(p interface{}) (extendableProto, bool) {
+ if ep, ok := p.(extendableProto); ok {
+ return ep, ok
+ }
+ if ep, ok := p.(extendableProtoV1); ok {
+ return extensionAdapter{ep}, ok
+ }
+ return nil, false
+}
+
+// XXX_InternalExtensions is an internal representation of proto extensions.
+//
+// Each generated message struct type embeds an anonymous XXX_InternalExtensions field,
+// thus gaining the unexported 'extensions' method, which can be called only from the proto package.
+//
+// The methods of XXX_InternalExtensions are not concurrency safe in general,
+// but calls to logically read-only methods such as has and get may be executed concurrently.
+type XXX_InternalExtensions struct {
+ // The struct must be indirect so that if a user inadvertently copies a
+ // generated message and its embedded XXX_InternalExtensions, they
+ // avoid the mayhem of a copied mutex.
+ //
+ // The mutex serializes all logically read-only operations to p.extensionMap.
+ // It is up to the client to ensure that write operations to p.extensionMap are
+ // mutually exclusive with other accesses.
+ p *struct {
+ mu sync.Mutex
+ extensionMap map[int32]Extension
+ }
+}
+
+// extensionsWrite returns the extension map, creating it on first use.
+func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension {
+ if e.p == nil {
+ e.p = new(struct {
+ mu sync.Mutex
+ extensionMap map[int32]Extension
+ })
+ e.p.extensionMap = make(map[int32]Extension)
+ }
+ return e.p.extensionMap
+}
+
+// extensionsRead returns the extensions map for read-only use. It may be nil.
+// The caller must hold the returned mutex's lock when accessing Elements within the map.
+func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) {
+ if e.p == nil {
+ return nil, nil
+ }
+ return e.p.extensionMap, &e.p.mu
+}
+
var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem()
+var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem()
// ExtensionDesc represents an extension specification.
// Used in generated code from the protocol compiler.
Field int32 // field number
Name string // fully-qualified name of extension, for text formatting
Tag string // protobuf tag style
+ Filename string // name of the file in which the extension is defined
}
func (ed *ExtensionDesc) repeated() bool {
}
// SetRawExtension is for testing only.
-func SetRawExtension(base extendableProto, id int32, b []byte) {
- base.ExtensionMap()[id] = Extension{enc: b}
+func SetRawExtension(base Message, id int32, b []byte) {
+ epb, ok := extendable(base)
+ if !ok {
+ return
+ }
+ extmap := epb.extensionsWrite()
+ extmap[id] = Extension{enc: b}
}
// isExtensionField returns true iff the given field number is in an extension range.
// checkExtensionTypes checks that the given extension is valid for pb.
func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
+ var pbi interface{} = pb
// Check the extended type.
- if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
+ if ea, ok := pbi.(extensionAdapter); ok {
+ pbi = ea.extendableProtoV1
+ }
+ if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b {
return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String())
}
// Check the range.
return prop
}
-// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m.
-func encodeExtensionMap(m map[int32]Extension) error {
+// encode encodes any unmarshaled (unencoded) extensions in e.
+func encodeExtensions(e *XXX_InternalExtensions) error {
+ m, mu := e.extensionsRead()
+ if m == nil {
+ return nil // fast path
+ }
+ mu.Lock()
+ defer mu.Unlock()
+ return encodeExtensionsMap(m)
+}
+
+// encode encodes any unmarshaled (unencoded) extensions in e.
+func encodeExtensionsMap(m map[int32]Extension) error {
for k, e := range m {
if e.value == nil || e.desc == nil {
// Extension is only in its encoded form.
return nil
}
-func sizeExtensionMap(m map[int32]Extension) (n int) {
+func extensionsSize(e *XXX_InternalExtensions) (n int) {
+ m, mu := e.extensionsRead()
+ if m == nil {
+ return 0
+ }
+ mu.Lock()
+ defer mu.Unlock()
+ return extensionsMapSize(m)
+}
+
+func extensionsMapSize(m map[int32]Extension) (n int) {
for _, e := range m {
if e.value == nil || e.desc == nil {
// Extension is only in its encoded form.
}
// HasExtension returns whether the given extension is present in pb.
-func HasExtension(pb extendableProto, extension *ExtensionDesc) bool {
+func HasExtension(pb Message, extension *ExtensionDesc) bool {
// TODO: Check types, field numbers, etc.?
- _, ok := pb.ExtensionMap()[extension.Field]
+ epb, ok := extendable(pb)
+ if !ok {
+ return false
+ }
+ extmap, mu := epb.extensionsRead()
+ if extmap == nil {
+ return false
+ }
+ mu.Lock()
+ _, ok = extmap[extension.Field]
+ mu.Unlock()
return ok
}
// ClearExtension removes the given extension from pb.
-func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
+func ClearExtension(pb Message, extension *ExtensionDesc) {
+ epb, ok := extendable(pb)
+ if !ok {
+ return
+ }
// TODO: Check types, field numbers, etc.?
- delete(pb.ExtensionMap(), extension.Field)
+ extmap := epb.extensionsWrite()
+ delete(extmap, extension.Field)
}
// GetExtension parses and returns the given extension of pb.
// If the extension is not present and has no default value it returns ErrMissingExtension.
-func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) {
- if err := checkExtensionTypes(pb, extension); err != nil {
+func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
+ epb, ok := extendable(pb)
+ if !ok {
+ return nil, errors.New("proto: not an extendable proto")
+ }
+
+ if err := checkExtensionTypes(epb, extension); err != nil {
return nil, err
}
- emap := pb.ExtensionMap()
+ emap, mu := epb.extensionsRead()
+ if emap == nil {
+ return defaultExtensionValue(extension)
+ }
+ mu.Lock()
+ defer mu.Unlock()
e, ok := emap[extension.Field]
if !ok {
// defaultExtensionValue returns the default value or
// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
// The returned slice has the same length as es; missing extensions will appear as nil elements.
func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
- epb, ok := pb.(extendableProto)
+ epb, ok := extendable(pb)
if !ok {
- err = errors.New("proto: not an extendable proto")
- return
+ return nil, errors.New("proto: not an extendable proto")
}
extensions = make([]interface{}, len(es))
for i, e := range es {
return
}
+// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order.
+// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing
+// just the Field field, which defines the extension's field number.
+func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) {
+ epb, ok := extendable(pb)
+ if !ok {
+ return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb)
+ }
+ registeredExtensions := RegisteredExtensions(pb)
+
+ emap, mu := epb.extensionsRead()
+ if emap == nil {
+ return nil, nil
+ }
+ mu.Lock()
+ defer mu.Unlock()
+ extensions := make([]*ExtensionDesc, 0, len(emap))
+ for extid, e := range emap {
+ desc := e.desc
+ if desc == nil {
+ desc = registeredExtensions[extid]
+ if desc == nil {
+ desc = &ExtensionDesc{Field: extid}
+ }
+ }
+
+ extensions = append(extensions, desc)
+ }
+ return extensions, nil
+}
+
// SetExtension sets the specified extension of pb to the specified value.
-func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error {
- if err := checkExtensionTypes(pb, extension); err != nil {
+func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error {
+ epb, ok := extendable(pb)
+ if !ok {
+ return errors.New("proto: not an extendable proto")
+ }
+ if err := checkExtensionTypes(epb, extension); err != nil {
return err
}
typ := reflect.TypeOf(extension.ExtensionType)
return fmt.Errorf("proto: SetExtension called with nil value of type %T", value)
}
- pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
+ extmap := epb.extensionsWrite()
+ extmap[extension.Field] = Extension{desc: extension, value: value}
return nil
}
+// ClearAllExtensions clears all extensions from pb.
+func ClearAllExtensions(pb Message) {
+ epb, ok := extendable(pb)
+ if !ok {
+ return
+ }
+ m := epb.extensionsWrite()
+ for k := range m {
+ delete(m, k)
+ }
+}
+
// A global registry of extensions.
// The generated code will register the generated descriptors by calling RegisterExtension.
When the .proto file specifies `syntax="proto3"`, there are some differences:
- Non-repeated fields of non-message type are values instead of pointers.
- - Getters are only generated for message and oneof fields.
- Enum types do not get an Enum method.
The simplest way to describe this is to see an example.
// temporary Buffer and are fine for most applications.
type Buffer struct {
buf []byte // encode/decode byte stream
- index int // write point
+ index int // read point
// pools of basic types to amortize allocation.
bools []bool
return false
}
+// ProtoPackageIsVersion2 is referenced from generated protocol buffer files
+// to assert that that code is compatible with this version of the proto package.
+const ProtoPackageIsVersion2 = true
+
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
// to assert that that code is compatible with this version of the proto package.
const ProtoPackageIsVersion1 = true
// MarshalMessageSet encodes the extension map represented by m in the message set wire format.
// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
-func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
- if err := encodeExtensionMap(m); err != nil {
- return nil, err
+func MarshalMessageSet(exts interface{}) ([]byte, error) {
+ var m map[int32]Extension
+ switch exts := exts.(type) {
+ case *XXX_InternalExtensions:
+ if err := encodeExtensions(exts); err != nil {
+ return nil, err
+ }
+ m, _ = exts.extensionsRead()
+ case map[int32]Extension:
+ if err := encodeExtensionsMap(exts); err != nil {
+ return nil, err
+ }
+ m = exts
+ default:
+ return nil, errors.New("proto: not an extension map")
}
// Sort extension IDs to provide a deterministic encoding.
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
-func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error {
+func UnmarshalMessageSet(buf []byte, exts interface{}) error {
+ var m map[int32]Extension
+ switch exts := exts.(type) {
+ case *XXX_InternalExtensions:
+ m = exts.extensionsWrite()
+ case map[int32]Extension:
+ m = exts
+ default:
+ return errors.New("proto: not an extension map")
+ }
+
ms := new(messageSet)
if err := Unmarshal(buf, ms); err != nil {
return err
// MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
-func MarshalMessageSetJSON(m map[int32]Extension) ([]byte, error) {
+func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
+ var m map[int32]Extension
+ switch exts := exts.(type) {
+ case *XXX_InternalExtensions:
+ m, _ = exts.extensionsRead()
+ case map[int32]Extension:
+ m = exts
+ default:
+ return nil, errors.New("proto: not an extension map")
+ }
var b bytes.Buffer
b.WriteByte('{')
// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
-func UnmarshalMessageSetJSON(buf []byte, m map[int32]Extension) error {
+func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error {
// Common-case fast path.
if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) {
return nil
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// +build appengine
+// +build appengine js
// This file contains an implementation of proto field accesses using package reflect.
// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can
return structPointer_ifield(p, f).(*[]string)
}
+// Extensions returns the address of an extension map field in the struct.
+func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions {
+ return structPointer_ifield(p, f).(*XXX_InternalExtensions)
+}
+
// ExtMap returns the address of an extension map field in the struct.
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
return structPointer_ifield(p, f).(*map[int32]Extension)
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// +build !appengine
+// +build !appengine,!js
// This file contains the implementation of the proto field accesses using package unsafe.
}
// ExtMap returns the address of an extension map field in the struct.
+func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions {
+ return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+}
+
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
p.dec = (*Buffer).dec_slice_int64
p.packedDec = (*Buffer).dec_slice_packed_int64
case reflect.Uint8:
- p.enc = (*Buffer).enc_slice_byte
p.dec = (*Buffer).dec_slice_byte
- p.size = size_slice_byte
- // This is a []byte, which is either a bytes field,
- // or the value of a map field. In the latter case,
- // we always encode an empty []byte, so we should not
- // use the proto3 enc/size funcs.
- // f == nil iff this is the key/value of a map field.
- if p.proto3 && f != nil {
+ if p.proto3 {
p.enc = (*Buffer).enc_proto3_slice_byte
p.size = size_proto3_slice_byte
+ } else {
+ p.enc = (*Buffer).enc_slice_byte
+ p.size = size_slice_byte
}
case reflect.Float32, reflect.Float64:
switch t2.Bits() {
propertiesMap[t] = prop
// build properties
- prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType)
+ prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) ||
+ reflect.PtrTo(t).Implements(extendableProtoV1Type)
prop.unrecField = invalidField
prop.Prop = make([]*Properties, t.NumField())
prop.order = make([]int, t.NumField())
name := f.Name
p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
- if f.Name == "XXX_extensions" { // special case
+ if f.Name == "XXX_InternalExtensions" { // special case
+ p.enc = (*Buffer).enc_exts
+ p.dec = nil // not needed
+ p.size = size_exts
+ } else if f.Name == "XXX_extensions" { // special case
p.enc = (*Buffer).enc_map
p.dec = nil // not needed
p.size = size_map
- }
- if f.Name == "XXX_unrecognized" { // special case
+ } else if f.Name == "XXX_unrecognized" { // special case
prop.unrecField = toField(&f)
}
- oneof := f.Tag.Get("protobuf_oneof") != "" // special case
+ oneof := f.Tag.Get("protobuf_oneof") // special case
+ if oneof != "" {
+ // Oneof fields don't use the traditional protobuf tag.
+ p.OrigName = oneof
+ }
prop.Prop[i] = p
prop.order[i] = i
if debug {
}
print("\n")
}
- if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && !oneof {
+ if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" {
fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
}
}
}
// MessageName returns the fully-qualified proto name for the given message type.
-func MessageName(x Message) string { return revProtoTypes[reflect.TypeOf(x)] }
+func MessageName(x Message) string {
+ type xname interface {
+ XXX_MessageName() string
+ }
+ if m, ok := x.(xname); ok {
+ return m.XXX_MessageName()
+ }
+ return revProtoTypes[reflect.TypeOf(x)]
+}
// MessageType returns the message type (pointer to struct) for a named message.
func MessageType(name string) reflect.Type { return protoTypes[name] }
+
+// A registry of all linked proto files.
+var (
+ protoFiles = make(map[string][]byte) // file name => fileDescriptor
+)
+
+// RegisterFile is called from generated code and maps from the
+// full file name of a .proto file to its compressed FileDescriptorProto.
+func RegisterFile(filename string, fileDescriptor []byte) {
+ protoFiles[filename] = fileDescriptor
+}
+
+// FileDescriptor returns the compressed FileDescriptorProto for a .proto file.
+func FileDescriptor(filename string) []byte { return protoFiles[filename] }
func (w *textWriter) unindent() {
if w.ind == 0 {
- log.Printf("proto: textWriter unindented too far")
+ log.Print("proto: textWriter unindented too far")
return
}
w.ind--
// Extensions (the XXX_extensions field).
pv := sv.Addr()
- if pv.Type().Implements(extendableProtoType) {
+ if _, ok := extendable(pv.Interface()); ok {
if err := tm.writeExtensions(w, pv); err != nil {
return err
}
switch v.Kind() {
case reflect.Slice:
// Should only be a []byte; repeated fields are handled in writeStruct.
- if err := writeString(w, string(v.Interface().([]byte))); err != nil {
+ if err := writeString(w, string(v.Bytes())); err != nil {
return err
}
case reflect.String:
// pv is assumed to be a pointer to a protocol message struct that is extendable.
func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error {
emap := extensionMaps[pv.Type().Elem()]
- ep := pv.Interface().(extendableProto)
+ ep, _ := extendable(pv.Interface())
// Order the extensions by ID.
// This isn't strictly necessary, but it will give us
// canonical output, which will also make testing easier.
- m := ep.ExtensionMap()
+ m, mu := ep.extensionsRead()
+ if m == nil {
+ return nil
+ }
+ mu.Lock()
ids := make([]int32, 0, len(m))
for id := range m {
ids = append(ids, id)
}
sort.Sort(int32Slice(ids))
+ mu.Unlock()
for _, extNum := range ids {
ext := m[extNum]
"unicode/utf8"
)
+// Error string emitted when deserializing Any and fields are already set
+const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set"
+
type ParseError struct {
Message string
Line int // 1-based line number
if err != nil {
return p.errorf("failed to marshal message of type %q: %v", messageName, err)
}
+ if fieldSet["type_url"] {
+ return p.errorf(anyRepeatedlyUnpacked, "type_url")
+ }
+ if fieldSet["value"] {
+ return p.errorf(anyRepeatedlyUnpacked, "value")
+ }
sv.FieldByName("TypeUrl").SetString(extName)
sv.FieldByName("Value").SetBytes(b)
+ fieldSet["type_url"] = true
+ fieldSet["value"] = true
continue
}
}
reqFieldErr = err
}
- ep := sv.Addr().Interface().(extendableProto)
+ ep := sv.Addr().Interface().(Message)
if !rep {
SetExtension(ep, desc, ext.Interface())
} else {
props = oop.Prop
nv := reflect.New(oop.Type.Elem())
dst = nv.Elem().Field(0)
- sv.Field(oop.Field).Set(nv)
+ field := sv.Field(oop.Field)
+ if !field.IsNil() {
+ return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name)
+ }
+ field.Set(nv)
}
if !dst.IsValid() {
return p.errorf("unknown field name %q in %v", name, st)
// The map entry should be this sequence of tokens:
// < key : KEY value : VALUE >
- // Technically the "key" and "value" could come in any order,
- // but in practice they won't.
+ // However, implementations may omit key or value, and technically
+ // we should support them in any order. See b/28924776 for a time
+ // this went wrong.
tok := p.next()
var terminator string
default:
return p.errorf("expected '{' or '<', found %q", tok.value)
}
- if err := p.consumeToken("key"); err != nil {
- return err
- }
- if err := p.consumeToken(":"); err != nil {
- return err
- }
- if err := p.readAny(key, props.mkeyprop); err != nil {
- return err
- }
- if err := p.consumeOptionalSeparator(); err != nil {
- return err
- }
- if err := p.consumeToken("value"); err != nil {
- return err
- }
- if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil {
- return err
- }
- if err := p.readAny(val, props.mvalprop); err != nil {
- return err
- }
- if err := p.consumeOptionalSeparator(); err != nil {
- return err
- }
- if err := p.consumeToken(terminator); err != nil {
- return err
+ for {
+ tok := p.next()
+ if tok.err != nil {
+ return tok.err
+ }
+ if tok.value == terminator {
+ break
+ }
+ switch tok.value {
+ case "key":
+ if err := p.consumeToken(":"); err != nil {
+ return err
+ }
+ if err := p.readAny(key, props.mkeyprop); err != nil {
+ return err
+ }
+ if err := p.consumeOptionalSeparator(); err != nil {
+ return err
+ }
+ case "value":
+ if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil {
+ return err
+ }
+ if err := p.readAny(val, props.mvalprop); err != nil {
+ return err
+ }
+ if err := p.consumeOptionalSeparator(); err != nil {
+ return err
+ }
+ default:
+ p.back()
+ return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value)
+ }
}
dst.SetMapIndex(key, val)
return err
}
reqFieldErr = err
- } else if props.Required {
+ }
+ if props.Required {
reqCount--
}
fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem()))
return p.readAny(fv.Index(fv.Len()-1), props)
case reflect.Bool:
- // Either "true", "false", 1 or 0.
+ // true/1/t/True or false/f/0/False.
switch tok.value {
- case "true", "1":
+ case "true", "1", "t", "True":
fv.SetBool(true)
return nil
- case "false", "0":
+ case "false", "0", "f", "False":
fv.SetBool(false)
return nil
}
return p.readStruct(fv, terminator)
case reflect.Uint32:
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
- fv.SetUint(uint64(x))
+ fv.SetUint(x)
return nil
}
case reflect.Uint64:
[![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns)
+[![](https://godoc.org/github.com/miekg/dns?status.svg)](https://godoc.org/github.com/miekg/dns)
# Alternative (more granular) approach to a DNS library
We try to keep the "master" branch as sane as possible and at the bleeding edge
of standards, avoiding breaking changes wherever reasonable. We support the last
-two versions of Go, currently: 1.5 and 1.6.
+two versions of Go, currently: 1.7 and 1.8.
# Goals
* KISS;
* Fast;
-* Small API, if its easy to code in Go, don't make a function for it.
+* Small API. If it's easy to code in Go, don't make a function for it.
# Users
A not-so-up-to-date-list-that-may-be-actually-current:
+* https://github.com/coredns/coredns
* https://cloudflare.com
* https://github.com/abh/geodns
* http://www.statdns.com/
* https://dnslookup.org
* https://github.com/looterz/grimd
* https://github.com/phamhongviet/serf-dns
+* https://github.com/mehrdadrad/mylg
+* https://github.com/bamarni/dockness
+* https://github.com/fffaraz/microdns
+* http://quilt.io
+* https://github.com/ipdcode/hades (JD.COM)
+* https://github.com/StackExchange/dnscontrol/
+* https://www.dnsperf.com/
+* https://dnssectest.net/
Send pull request if you want to be listed here.
* 6975 - Algorithm Understanding in DNSSEC
* 7043 - EUI48/EUI64 records
* 7314 - DNS (EDNS) EXPIRE Option
+* 7828 - edns-tcp-keepalive EDNS0 Option
* 7553 - URI record
* 7858 - DNS over TLS: Initiation and Performance Considerations (draft)
* 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies)
import (
"bytes"
+ "context"
"crypto/tls"
"encoding/binary"
"io"
}
// Exchange performs a synchronous UDP query. It sends the message m to the address
-// contained in a and waits for an reply. Exchange does not retry a failed query, nor
+// contained in a and waits for a reply. Exchange does not retry a failed query, nor
// will it fall back to TCP in case of truncation.
// See client.Exchange for more information on setting larger buffer sizes.
func Exchange(m *Msg, a string) (r *Msg, err error) {
return r, err
}
+// ExchangeContext performs a synchronous UDP query, like Exchange. It
+// additionally obeys deadlines from the passed Context.
+func ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, err error) {
+ // Combine context deadline with built-in timeout. Context chooses whichever
+ // is sooner.
+ timeoutCtx, cancel := context.WithTimeout(ctx, dnsTimeout)
+ defer cancel()
+ deadline, _ := timeoutCtx.Deadline()
+
+ co := new(Conn)
+ dialer := net.Dialer{}
+ co.Conn, err = dialer.DialContext(timeoutCtx, "udp", a)
+ if err != nil {
+ return nil, err
+ }
+
+ defer co.Conn.Close()
+
+ opt := m.IsEdns0()
+ // If EDNS0 is used use that for size.
+ if opt != nil && opt.UDPSize() >= MinMsgSize {
+ co.UDPSize = opt.UDPSize()
+ }
+
+ co.SetWriteDeadline(deadline)
+ if err = co.WriteMsg(m); err != nil {
+ return nil, err
+ }
+
+ co.SetReadDeadline(deadline)
+ r, err = co.ReadMsg()
+ if err == nil && r.Id != m.Id {
+ err = ErrId
+ }
+ return r, err
+}
+
// ExchangeConn performs a synchronous query. It sends the message m via the connection
// c and waits for a reply. The connection c is not closed by ExchangeConn.
// This function is going away, but can easily be mimicked:
return r, err
}
-// Exchange performs an synchronous query. It sends the message m to the address
-// contained in a and waits for an reply. Basic use pattern with a *dns.Client:
+// Exchange performs a synchronous query. It sends the message m to the address
+// contained in a and waits for a reply. Basic use pattern with a *dns.Client:
//
// c := new(dns.Client)
// in, rtt, err := c.Exchange(message, "127.0.0.1:53")
// case of truncation.
// It is up to the caller to create a message that allows for larger responses to be
// returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger
-// buffer, see SetEdns0. Messsages without an OPT RR will fallback to the historic limit
+// buffer, see SetEdns0. Messages without an OPT RR will fallback to the historic limit
// of 512 bytes.
func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
+ return c.ExchangeContext(context.Background(), m, a)
+}
+
+// ExchangeContext acts like Exchange, but honors the deadline on the provided
+// context, if present. If there is both a context deadline and a configured
+// timeout on the client, the earliest of the two takes effect.
+func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (
+ r *Msg,
+ rtt time.Duration,
+ err error) {
if !c.SingleInflight {
- return c.exchange(m, a)
+ return c.exchange(ctx, m, a)
}
// This adds a bunch of garbage, TODO(miek).
t := "nop"
cl = cl1
}
r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
- return c.exchange(m, a)
+ return c.exchange(ctx, m, a)
})
+ if r != nil && shared {
+ r = r.Copy()
+ }
if err != nil {
return r, rtt, err
}
- if shared {
- return r.Copy(), rtt, nil
- }
return r, rtt, nil
}
return dnsTimeout
}
-func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
+func (c *Client) exchange(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
var co *Conn
network := "udp"
tls := false
deadline = time.Now().Add(c.Timeout)
}
+ dialDeadline := deadlineOrTimeoutOrCtx(ctx, deadline, c.dialTimeout())
+ dialTimeout := dialDeadline.Sub(time.Now())
+
if tls {
- co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, c.dialTimeout())
+ co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, dialTimeout)
} else {
- co, err = DialTimeout(network, a, c.dialTimeout())
+ co, err = DialTimeout(network, a, dialTimeout)
}
if err != nil {
}
co.TsigSecret = c.TsigSecret
- co.SetWriteDeadline(deadlineOrTimeout(deadline, c.writeTimeout()))
+ co.SetWriteDeadline(deadlineOrTimeoutOrCtx(ctx, deadline, c.writeTimeout()))
if err = co.WriteMsg(m); err != nil {
return nil, 0, err
}
- co.SetReadDeadline(deadlineOrTimeout(deadline, c.readTimeout()))
+ co.SetReadDeadline(deadlineOrTimeoutOrCtx(ctx, deadline, c.readTimeout()))
r, err = co.ReadMsg()
if err == nil && r.Id != m.Id {
err = ErrId
if err != nil {
return 0, err
}
+
+ // As seen with my local router/switch, retursn 1 byte on the above read,
+ // resulting a a ShortRead. Just write it out (instead of loop) and read the
+ // other byte.
+ if n == 1 {
+ n1, err := t.Read(p[1:])
+ if err != nil {
+ return 0, err
+ }
+ n += n1
+ }
+
if n != 2 {
return 0, ErrShortRead
}
n, err := io.Copy(w, bytes.NewReader(p))
return int(n), err
}
- n, err = co.Conn.(*net.UDPConn).Write(p)
+ n, err = co.Conn.Write(p)
return n, err
}
return conn, nil
}
+// deadlineOrTimeout chooses between the provided deadline and timeout
+// by always preferring the deadline so long as it's non-zero (regardless
+// of which is bigger), and returns the equivalent deadline value.
func deadlineOrTimeout(deadline time.Time, timeout time.Duration) time.Time {
if deadline.IsZero() {
return time.Now().Add(timeout)
}
return deadline
}
+
+// deadlineOrTimeoutOrCtx returns the earliest of: a context deadline, or the
+// output of deadlineOrtimeout.
+func deadlineOrTimeoutOrCtx(ctx context.Context, deadline time.Time, timeout time.Duration) time.Time {
+ result := deadlineOrTimeout(deadline, timeout)
+ if ctxDeadline, ok := ctx.Deadline(); ok && ctxDeadline.Before(result) {
+ result = ctxDeadline
+ }
+ return result
+}
}
return c, nil
}
+
+// NameList returns all of the names that should be queried based on the
+// config. It is based off of go's net/dns name building, but it does not
+// check the length of the resulting names.
+func (c *ClientConfig) NameList(name string) []string {
+ // if this domain is already fully qualified, no append needed.
+ if IsFqdn(name) {
+ return []string{name}
+ }
+
+ // Check to see if the name has more labels than Ndots. Do this before making
+ // the domain fully qualified.
+ hasNdots := CountLabel(name) > c.Ndots
+ // Make the domain fully qualified.
+ name = Fqdn(name)
+
+ // Make a list of names based off search.
+ names := []string{}
+
+ // If name has enough dots, try that first.
+ if hasNdots {
+ names = append(names, name)
+ }
+ for _, s := range c.Search {
+ names = append(names, Fqdn(name+s))
+ }
+ // If we didn't have enough dots, try after suffixes.
+ if !hasNdots {
+ names = append(names, name)
+ }
+ return names
+}
// SetReply creates a reply message from a request message.
func (dns *Msg) SetReply(request *Msg) *Msg {
dns.Id = request.Id
- dns.RecursionDesired = request.RecursionDesired // Copy rd bit
dns.Response = true
- dns.Opcode = OpcodeQuery
+ dns.Opcode = request.Opcode
+ if dns.Opcode == OpcodeQuery {
+ dns.RecursionDesired = request.RecursionDesired // Copy rd bit
+ dns.CheckingDisabled = request.CheckingDisabled // Copy cd bit
+ }
dns.Rcode = RcodeSuccess
if len(request.Question) > 0 {
dns.Question = make([]Question, 1)
// SetTsig appends a TSIG RR to the message.
// This is only a skeleton TSIG RR that is added as the last RR in the
// additional section. The Tsig is calculated when the message is being send.
-func (dns *Msg) SetTsig(z, algo string, fudge, timesigned int64) *Msg {
+func (dns *Msg) SetTsig(z, algo string, fudge uint16, timesigned int64) *Msg {
t := new(TSIG)
t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0}
t.Algorithm = algo
- t.Fudge = 300
+ t.Fudge = fudge
t.TimeSigned = uint64(timesigned)
t.OrigId = dns.Id
dns.Extra = append(dns.Extra, t)
PRIVATEOID uint8 = 254
)
-// Map for algorithm names.
+// AlgorithmToString is a map of algorithm IDs to algorithm names.
var AlgorithmToString = map[uint8]string{
RSAMD5: "RSAMD5",
DH: "DH",
PRIVATEOID: "PRIVATEOID",
}
-// Map of algorithm strings.
+// StringToAlgorithm is the reverse of AlgorithmToString.
var StringToAlgorithm = reverseInt8(AlgorithmToString)
-// Map of algorithm crypto hashes.
+// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
var AlgorithmToHash = map[uint8]crypto.Hash{
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
RSASHA1: crypto.SHA1,
SHA512 // Experimental
)
-// Map for hash names.
+// HashToString is a map of hash IDs to names.
var HashToString = map[uint8]string{
SHA1: "SHA1",
SHA256: "SHA256",
SHA512: "SHA512",
}
-// Map of hash strings.
+// StringToHash is a map of names to hash IDs.
var StringToHash = reverseInt8(HashToString)
// DNSKEY flag values.
// "|" denotes concatenation
// DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
- // digest buffer
- digest := append(owner, wire...) // another copy
-
var hash crypto.Hash
switch h {
case SHA1:
}
s := hash.New()
- s.Write(digest)
+ s.Write(owner)
+ s.Write(wire)
ds.Digest = hex.EncodeToString(s.Sum(nil))
return ds
}
if err != nil {
return err
}
- signdata = append(signdata, wire...)
hash, ok := AlgorithmToHash[rr.Algorithm]
if !ok {
h := hash.New()
h.Write(signdata)
+ h.Write(wire)
signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
if err != nil {
if err != nil {
return err
}
- signeddata = append(signeddata, wire...)
sigbuf := rr.sigBuf() // Get the binary signature data
if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
h := hash.New()
h.Write(signeddata)
+ h.Write(wire)
return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
case ECDSAP256SHA256, ECDSAP384SHA384:
h := hash.New()
h.Write(signeddata)
+ h.Write(wire)
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
return nil
}
}
// Remainder
expo += uint64(keybuf[keyoff])
- if expo > 2<<31 {
+ if expo > (2<<31)+1 {
// Larger expo than supported.
// println("dns: F5 primes (or larger) are not supported")
return nil
// RFC 3110: Section 2. RSA Public KEY Resource Records
func exponentToBuf(_E int) []byte {
var buf []byte
- i := big.NewInt(int64(_E))
- if len(i.Bytes()) < 256 {
- buf = make([]byte, 1)
- buf[0] = uint8(len(i.Bytes()))
+ i := big.NewInt(int64(_E)).Bytes()
+ if len(i) < 256 {
+ buf = make([]byte, 1, 1+len(i))
+ buf[0] = uint8(len(i))
} else {
- buf = make([]byte, 3)
+ buf = make([]byte, 3, 3+len(i))
buf[0] = 0
- buf[1] = uint8(len(i.Bytes()) >> 8)
- buf[2] = uint8(len(i.Bytes()))
+ buf[1] = uint8(len(i) >> 8)
+ buf[2] = uint8(len(i))
}
- buf = append(buf, i.Bytes()...)
+ buf = append(buf, i...)
return buf
}
// NewPrivateKey returns a PrivateKey by parsing the string s.
// s should be in the same form of the BIND private key files.
func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
- if s[len(s)-1] != '\n' { // We need a closing newline
+ if s == "" || s[len(s)-1] != '\n' { // We need a closing newline
return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
}
return k.ReadPrivateKey(strings.NewReader(s), "")
return nil, ErrPrivKey
}
// TODO(mg): check if the pubkey matches the private key
- algo, err := strconv.Atoi(strings.SplitN(m["algorithm"], " ", 2)[0])
+ algo, err := strconv.ParseUint(strings.SplitN(m["algorithm"], " ", 2)[0], 10, 8)
if err != nil {
return nil, ErrPrivKey
}
is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
can be used, before requesting an official type code from IANA.
-see http://miek.nl/posts/2014/Sep/21/Private%20RRs%20and%20IDN%20in%20Go%20DNS/ for more
+see http://miek.nl/2014/September/21/idn-and-private-rr-in-go-dns/ for more
information.
EDNS0
"encoding/binary"
"encoding/hex"
"errors"
+ "fmt"
"net"
"strconv"
)
// EDNS0 Option codes.
const (
- EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
- EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
- EDNS0NSID = 0x3 // nsid (RFC5001)
- EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
- EDNS0DHU = 0x6 // DS Hash Understood
- EDNS0N3U = 0x7 // NSEC3 Hash Understood
- EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
- EDNS0EXPIRE = 0x9 // EDNS0 expire
- EDNS0COOKIE = 0xa // EDNS0 Cookie
- EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
- EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891)
- EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891)
- _DO = 1 << 15 // dnssec ok
+ EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
+ EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
+ EDNS0NSID = 0x3 // nsid (RFC5001)
+ EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
+ EDNS0DHU = 0x6 // DS Hash Understood
+ EDNS0N3U = 0x7 // NSEC3 Hash Understood
+ EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
+ EDNS0EXPIRE = 0x9 // EDNS0 expire
+ EDNS0COOKIE = 0xa // EDNS0 Cookie
+ EDNS0TCPKEEPALIVE = 0xb // EDNS0 tcp keep alive (RFC7828)
+ EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
+ EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891)
+ EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891)
+ _DO = 1 << 15 // dnssec ok
)
// OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
}
// SetDo sets the DO (DNSSEC OK) bit.
-func (rr *OPT) SetDo() {
- rr.Hdr.Ttl |= _DO
+// If we pass an argument, set the DO bit to that value.
+// It is possible to pass 2 or more arguments. Any arguments after the 1st is silently ignored.
+func (rr *OPT) SetDo(do ...bool) {
+ if len(do) == 1 {
+ if do[0] {
+ rr.Hdr.Ttl |= _DO
+ } else {
+ rr.Hdr.Ttl &^= _DO
+ }
+ } else {
+ rr.Hdr.Ttl |= _DO
+ }
}
// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it.
String() string
}
-// The nsid EDNS0 option is used to retrieve a nameserver
+// EDNS0_NSID option is used to retrieve a nameserver
// identifier. When sending a request Nsid must be set to the empty string
// The identifier is an opaque string encoded as hex.
// Basic use pattern for creating an nsid option:
// e := new(dns.EDNS0_SUBNET)
// e.Code = dns.EDNS0SUBNET
// e.Family = 1 // 1 for IPv4 source address, 2 for IPv6
-// e.NetMask = 32 // 32 for IPV4, 128 for IPv6
+// e.SourceNetmask = 32 // 32 for IPV4, 128 for IPv6
// e.SourceScope = 0
// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
return
}
-// The Cookie EDNS0 option
+// The EDNS0_COOKIE option is used to add a DNS Cookie to a message.
//
// o := new(dns.OPT)
// o.Hdr.Name = "."
}
return nil
}
+
+// EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep
+// the TCP connection alive. See RFC 7828.
+type EDNS0_TCP_KEEPALIVE struct {
+ Code uint16 // Always EDNSTCPKEEPALIVE
+ Length uint16 // the value 0 if the TIMEOUT is omitted, the value 2 if it is present;
+ Timeout uint16 // an idle timeout value for the TCP connection, specified in units of 100 milliseconds, encoded in network byte order.
+}
+
+func (e *EDNS0_TCP_KEEPALIVE) Option() uint16 { return EDNS0TCPKEEPALIVE }
+
+func (e *EDNS0_TCP_KEEPALIVE) pack() ([]byte, error) {
+ if e.Timeout != 0 && e.Length != 2 {
+ return nil, errors.New("dns: timeout specified but length is not 2")
+ }
+ if e.Timeout == 0 && e.Length != 0 {
+ return nil, errors.New("dns: timeout not specified but length is not 0")
+ }
+ b := make([]byte, 4+e.Length)
+ binary.BigEndian.PutUint16(b[0:], e.Code)
+ binary.BigEndian.PutUint16(b[2:], e.Length)
+ if e.Length == 2 {
+ binary.BigEndian.PutUint16(b[4:], e.Timeout)
+ }
+ return b, nil
+}
+
+func (e *EDNS0_TCP_KEEPALIVE) unpack(b []byte) error {
+ if len(b) < 4 {
+ return ErrBuf
+ }
+ e.Length = binary.BigEndian.Uint16(b[2:4])
+ if e.Length != 0 && e.Length != 2 {
+ return errors.New("dns: length mismatch, want 0/2 but got " + strconv.FormatUint(uint64(e.Length), 10))
+ }
+ if e.Length == 2 {
+ if len(b) < 6 {
+ return ErrBuf
+ }
+ e.Timeout = binary.BigEndian.Uint16(b[4:6])
+ }
+ return nil
+}
+
+func (e *EDNS0_TCP_KEEPALIVE) String() (s string) {
+ s = "use tcp keep-alive"
+ if e.Length == 0 {
+ s += ", timeout omitted"
+ } else {
+ s += fmt.Sprintf(", timeout %dms", e.Timeout*100)
+ }
+ return
+}
package dns
+import "strings"
+
// Holds a bunch of helper functions for dealing with labels.
// SplitDomainName splits a name string into it's labels.
//
// s1 and s2 must be syntactically valid domain names.
func CompareDomainName(s1, s2 string) (n int) {
+ s1, s2 = strings.ToLower(s1), strings.ToLower(s2)
s1 = Fqdn(s1)
s2 = Fqdn(s2)
l1 := Split(s1)
package dns
//go:generate go run msg_generate.go
+//go:generate go run compress_generate.go
import (
crand "crypto/rand"
"encoding/binary"
+ "fmt"
"math/big"
"math/rand"
"strconv"
+ "sync"
)
-func init() {
- // Initialize default math/rand source using crypto/rand to provide better
- // security without the performance trade-off.
- buf := make([]byte, 8)
- _, err := crand.Read(buf)
- if err != nil {
- // Failed to read from cryptographic source, fallback to default initial
- // seed (1) by returning early
- return
- }
- seed := binary.BigEndian.Uint64(buf)
- rand.Seed(int64(seed))
-}
-
-const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
+const (
+ maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
+ maxDomainNameWireOctets = 255 // See RFC 1035 section 2.3.4
+)
var (
ErrAlg error = &Error{err: "bad algorithm"} // ErrAlg indicates an error with the (DNSSEC) algorithm.
ErrAuth error = &Error{err: "bad authentication"} // ErrAuth indicates an error in the TSIG authentication.
- ErrBuf error = &Error{err: "buffer size too small"} // ErrBuf indicates that the buffer used it too small for the message.
- ErrConnEmpty error = &Error{err: "conn has no connection"} // ErrConnEmpty indicates a connection is being uses before it is initialized.
+ ErrBuf error = &Error{err: "buffer size too small"} // ErrBuf indicates that the buffer used is too small for the message.
+ ErrConnEmpty error = &Error{err: "conn has no connection"} // ErrConnEmpty indicates a connection is being used before it is initialized.
ErrExtendedRcode error = &Error{err: "bad extended rcode"} // ErrExtendedRcode ...
ErrFqdn error = &Error{err: "domain must be fully qualified"} // ErrFqdn indicates that a domain name does not have a closing dot.
ErrId error = &Error{err: "id mismatch"} // ErrId indicates there is a mismatch with the message's ID.
ErrKeyAlg error = &Error{err: "bad key algorithm"} // ErrKeyAlg indicates that the algorithm in the key is not valid.
ErrKey error = &Error{err: "bad key"}
ErrKeySize error = &Error{err: "bad key size"}
+ ErrLongDomain error = &Error{err: fmt.Sprintf("domain name exceeded %d wire-format octets", maxDomainNameWireOctets)}
ErrNoSig error = &Error{err: "no signature found"}
ErrPrivKey error = &Error{err: "bad private key"}
ErrRcode error = &Error{err: "bad rcode"}
ErrTruncated error = &Error{err: "failed to unpack truncated message"} // ErrTruncated indicates that we failed to unpack a truncated message. We unpacked as much as we had so Msg can still be used, if desired.
)
-// Id, by default, returns a 16 bits random number to be used as a
+// Id by default, returns a 16 bits random number to be used as a
// message id. The random provided should be good enough. This being a
// variable the function can be reassigned to a custom function.
// For instance, to make it return a static value:
// dns.Id = func() uint16 { return 3 }
var Id func() uint16 = id
+var (
+ idLock sync.Mutex
+ idRand *rand.Rand
+)
+
// id returns a 16 bits random number to be used as a
// message id. The random provided should be good enough.
func id() uint16 {
- id32 := rand.Uint32()
- return uint16(id32)
+ idLock.Lock()
+
+ if idRand == nil {
+ // This (partially) works around
+ // https://github.com/golang/go/issues/11833 by only
+ // seeding idRand upon the first call to id.
+
+ var seed int64
+ var buf [8]byte
+
+ if _, err := crand.Read(buf[:]); err == nil {
+ seed = int64(binary.LittleEndian.Uint64(buf[:]))
+ } else {
+ seed = rand.Int63()
+ }
+
+ idRand = rand.New(rand.NewSource(seed))
+ }
+
+ // The call to idRand.Uint32 must be within the
+ // mutex lock because *rand.Rand is not safe for
+ // concurrent use.
+ //
+ // There is no added performance overhead to calling
+ // idRand.Uint32 inside a mutex lock over just
+ // calling rand.Uint32 as the global math/rand rng
+ // is internally protected by a sync.Mutex.
+ id := uint16(idRand.Uint32())
+
+ idLock.Unlock()
+ return id
}
// MsgHdr is a a manually-unpacked version of (id, bits).
bs[j] = bs[j+2]
}
ls -= 2
- } else if bs[i] == 't' {
- bs[i] = '\t'
- } else if bs[i] == 'r' {
- bs[i] = '\r'
- } else if bs[i] == 'n' {
- bs[i] = '\n'
}
escapedDot = bs[i] == '.'
bsFresh = false
bsFresh = true
}
// Don't try to compress '.'
- if compress && roBs[begin:] != "." {
+ // We should only compress when compress it true, but we should also still pick
+ // up names that can be used for *future* compression(s).
+ if compression != nil && roBs[begin:] != "." {
if p, ok := compression[roBs[begin:]]; !ok {
// Only offsets smaller than this can be used.
if offset < maxCompressionOffset {
s := make([]byte, 0, 64)
off1 := 0
lenmsg := len(msg)
+ maxLen := maxDomainNameWireOctets
ptr := 0 // number of pointers followed
Loop:
for {
fallthrough
case '"', '\\':
s = append(s, '\\', b)
- case '\t':
- s = append(s, '\\', 't')
- case '\r':
- s = append(s, '\\', 'r')
+ // presentation-format \X escapes add an extra byte
+ maxLen += 1
default:
- if b < 32 || b >= 127 { // unprintable use \DDD
+ if b < 32 || b >= 127 { // unprintable, use \DDD
var buf [3]byte
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
s = append(s, '\\')
for _, r := range bufs {
s = append(s, r)
}
+ // presentation-format \DDD escapes add 3 extra bytes
+ maxLen += 3
} else {
s = append(s, b)
}
if ptr++; ptr > 10 {
return "", lenmsg, &Error{err: "too many compression pointers"}
}
+ // pointer should guarantee that it advances and points forwards at least
+ // but the condition on previous three lines guarantees that it's
+ // at least loop-free
off = (c^0xC0)<<8 | int(c1)
default:
// 0x80 and 0x40 are reserved
}
if len(s) == 0 {
s = []byte(".")
+ } else if len(s) >= maxLen {
+ // error if the name is too long, but don't throw it away
+ return string(s), lenmsg, ErrLongDomain
}
return string(s), off1, nil
}
if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
msg[offset] = dddToByte(bs[i:])
i += 2
- } else if bs[i] == 't' {
- msg[offset] = '\t'
- } else if bs[i] == 'r' {
- msg[offset] = '\r'
- } else if bs[i] == 'n' {
- msg[offset] = '\n'
} else {
msg[offset] = bs[i]
}
switch b {
case '"', '\\':
s = append(s, '\\', b)
- case '\t':
- s = append(s, `\t`...)
- case '\r':
- s = append(s, `\r`...)
- case '\n':
- s = append(s, `\n`...)
default:
if b < 32 || b > 127 { // unprintable
var buf [3]byte
// We need the uncompressed length here, because we first pack it and then compress it.
msg = buf
- compress := dns.Compress
- dns.Compress = false
- if packLen := dns.Len() + 1; len(msg) < packLen {
+ uncompressedLen := compressedLen(dns, false)
+ if packLen := uncompressedLen + 1; len(msg) < packLen {
msg = make([]byte, packLen)
}
- dns.Compress = compress
// Pack it in: header and then the pieces.
off := 0
if dh, off, err = unpackMsgHdr(msg, off); err != nil {
return err
}
- if off == len(msg) {
- return ErrTruncated
- }
dns.Id = dh.Id
dns.Response = (dh.Bits & _QR) != 0
dns.CheckingDisabled = (dh.Bits & _CD) != 0
dns.Rcode = int(dh.Bits & 0xF)
+ if off == len(msg) {
+ return ErrTruncated
+ }
+
// Optimistically use the count given to us in the header
dns.Question = make([]Question, 0, int(dh.Qdcount))
// If dns.Compress is true compression it is taken into account. Len()
// is provided to be a faster way to get the size of the resulting packet,
// than packing it, measuring the size and discarding the buffer.
-func (dns *Msg) Len() int {
+func (dns *Msg) Len() int { return compressedLen(dns, dns.Compress) }
+
+// compressedLen returns the message length when in compressed wire format
+// when compress is true, otherwise the uncompressed length is returned.
+func compressedLen(dns *Msg, compress bool) int {
// We always return one more than needed.
l := 12 // Message header is always 12 bytes
- var compression map[string]int
- if dns.Compress {
- compression = make(map[string]int)
- }
+ compression := map[string]int{}
+
for i := 0; i < len(dns.Question); i++ {
l += dns.Question[i].len()
- if dns.Compress {
+ if compress {
compressionLenHelper(compression, dns.Question[i].Name)
}
}
continue
}
l += dns.Answer[i].len()
- if dns.Compress {
+ if compress {
k, ok := compressionLenSearch(compression, dns.Answer[i].Header().Name)
if ok {
l += 1 - k
continue
}
l += dns.Ns[i].len()
- if dns.Compress {
+ if compress {
k, ok := compressionLenSearch(compression, dns.Ns[i].Header().Name)
if ok {
l += 1 - k
continue
}
l += dns.Extra[i].len()
- if dns.Compress {
+ if compress {
k, ok := compressionLenSearch(compression, dns.Extra[i].Header().Name)
if ok {
l += 1 - k
return 0, false
}
-// TODO(miek): should add all types, because the all can be *used* for compression. Autogenerate from msg_generate and put in zmsg.go
-func compressionLenHelperType(c map[string]int, r RR) {
- switch x := r.(type) {
- case *NS:
- compressionLenHelper(c, x.Ns)
- case *MX:
- compressionLenHelper(c, x.Mx)
- case *CNAME:
- compressionLenHelper(c, x.Target)
- case *PTR:
- compressionLenHelper(c, x.Ptr)
- case *SOA:
- compressionLenHelper(c, x.Ns)
- compressionLenHelper(c, x.Mbox)
- case *MB:
- compressionLenHelper(c, x.Mb)
- case *MG:
- compressionLenHelper(c, x.Mg)
- case *MR:
- compressionLenHelper(c, x.Mr)
- case *MF:
- compressionLenHelper(c, x.Mf)
- case *MD:
- compressionLenHelper(c, x.Md)
- case *RT:
- compressionLenHelper(c, x.Host)
- case *RP:
- compressionLenHelper(c, x.Mbox)
- compressionLenHelper(c, x.Txt)
- case *MINFO:
- compressionLenHelper(c, x.Rmail)
- compressionLenHelper(c, x.Email)
- case *AFSDB:
- compressionLenHelper(c, x.Hostname)
- case *SRV:
- compressionLenHelper(c, x.Target)
- case *NAPTR:
- compressionLenHelper(c, x.Replacement)
- case *RRSIG:
- compressionLenHelper(c, x.SignerName)
- case *NSEC:
- compressionLenHelper(c, x.NextDomain)
- // HIP?
- }
-}
-
-// Only search on compressing these types.
-func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
- switch x := r.(type) {
- case *NS:
- return compressionLenSearch(c, x.Ns)
- case *MX:
- return compressionLenSearch(c, x.Mx)
- case *CNAME:
- return compressionLenSearch(c, x.Target)
- case *DNAME:
- return compressionLenSearch(c, x.Target)
- case *PTR:
- return compressionLenSearch(c, x.Ptr)
- case *SOA:
- k, ok := compressionLenSearch(c, x.Ns)
- k1, ok1 := compressionLenSearch(c, x.Mbox)
- if !ok && !ok1 {
- return 0, false
- }
- return k + k1, true
- case *MB:
- return compressionLenSearch(c, x.Mb)
- case *MG:
- return compressionLenSearch(c, x.Mg)
- case *MR:
- return compressionLenSearch(c, x.Mr)
- case *MF:
- return compressionLenSearch(c, x.Mf)
- case *MD:
- return compressionLenSearch(c, x.Md)
- case *RT:
- return compressionLenSearch(c, x.Host)
- case *MINFO:
- k, ok := compressionLenSearch(c, x.Rmail)
- k1, ok1 := compressionLenSearch(c, x.Email)
- if !ok && !ok1 {
- return 0, false
- }
- return k + k1, true
- case *AFSDB:
- return compressionLenSearch(c, x.Hostname)
- }
- return 0, false
-}
-
// Copy returns a new RR which is a deep-copy of r.
func Copy(r RR) RR { r1 := r.copy(); return r1 }
switch {
case st.Tag(i) == `dns:"-"`: // ignored
case st.Tag(i) == `dns:"cdomain-name"`:
- fallthrough
- case st.Tag(i) == `dns:"domain-name"`:
o("off, err = PackDomainName(rr.%s, msg, off, compression, compress)\n")
+ case st.Tag(i) == `dns:"domain-name"`:
+ o("off, err = PackDomainName(rr.%s, msg, off, compression, false)\n")
case st.Tag(i) == `dns:"a"`:
o("off, err = packDataA(rr.%s, msg, off)\n")
case st.Tag(i) == `dns:"aaaa"`:
case st.Tag(i) == `dns:"base64"`:
o("off, err = packStringBase64(rr.%s, msg, off)\n")
+ case strings.HasPrefix(st.Tag(i), `dns:"size-hex:SaltLength`):
+ // directly write instead of using o() so we get the error check in the correct place
+ field := st.Field(i).Name()
+ fmt.Fprintf(b, `// Only pack salt if value is not "-", i.e. empty
+if rr.%s != "-" {
+ off, err = packStringHex(rr.%s, msg, off)
+ if err != nil {
+ return off, err
+ }
+}
+`, field, field)
+ continue
case strings.HasPrefix(st.Tag(i), `dns:"size-hex`): // size-hex can be packed just like hex
fallthrough
case st.Tag(i) == `dns:"hex"`:
}
}
// We have packed everything, only now we know the rdlength of this RR
- fmt.Fprintln(b, "rr.Header().Rdlength = uint16(off- headerEnd)")
+ fmt.Fprintln(b, "rr.Header().Rdlength = uint16(off-headerEnd)")
fmt.Fprintln(b, "return off, nil }\n")
}
return hdr, len(msg), msg, err
}
msg, err = truncateMsgFromRdlength(msg, off, hdr.Rdlength)
- return hdr, off, msg, nil
+ return hdr, off, msg, err
}
// pack packs an RR header, returning the offset to the end of the header.
}
func fromBase32(s []byte) (buf []byte, err error) {
+ for i, b := range s {
+ if b >= 'a' && b <= 'z' {
+ s[i] = b - 32
+ }
+ }
buflen := base32.HexEncoding.DecodedLen(len(s))
buf = make([]byte, buflen)
n, err := base32.HexEncoding.Decode(buf, s)
switch b {
case '"', '\\':
s = append(s, '\\', b)
- case '\t', '\r', '\n':
- s = append(s, b)
default:
if b < 32 || b > 127 { // unprintable
var buf [3]byte
import (
"crypto/sha1"
"hash"
- "io"
"strings"
)
}
// k = 0
- name = append(name, wire...)
- io.WriteString(s, string(name))
+ s.Write(name)
+ s.Write(wire)
nsec3 := s.Sum(nil)
// k > 0
for k := uint16(0); k < iter; k++ {
s.Reset()
- nsec3 = append(nsec3, wire...)
- io.WriteString(s, string(nsec3))
- nsec3 = s.Sum(nil)
+ s.Write(nsec3)
+ s.Write(wire)
+ nsec3 = s.Sum(nsec3[:0])
}
return toBase32(nsec3)
}
-// Denialer is an interface that should be implemented by types that are used to denial
-// answers in DNSSEC.
-type Denialer interface {
- // Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3.
- Cover(name string) bool
- // Match will check if the ownername matches the (unhashed) name for this NSEC3 or NSEC3.
- Match(name string) bool
-}
-
-// Cover implements the Denialer interface.
-func (rr *NSEC) Cover(name string) bool {
- return true
-}
-
-// Match implements the Denialer interface.
-func (rr *NSEC) Match(name string) bool {
- return true
-}
-
-// Cover implements the Denialer interface.
+// Cover returns true if a name is covered by the NSEC3 record
func (rr *NSEC3) Cover(name string) bool {
- // FIXME(miek): check if the zones match
- // FIXME(miek): check if we're not dealing with parent nsec3
- hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
- labels := Split(rr.Hdr.Name)
- if len(labels) < 2 {
+ nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
+ owner := strings.ToUpper(rr.Hdr.Name)
+ labelIndices := Split(owner)
+ if len(labelIndices) < 2 {
return false
}
- hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the dot
- if hash == rr.NextDomain {
- return false // empty interval
- }
- if hash > rr.NextDomain { // last name, points to apex
- // hname > hash
- // hname > rr.NextDomain
- // TODO(miek)
+ ownerHash := owner[:labelIndices[1]-1]
+ ownerZone := owner[labelIndices[1]:]
+ if !IsSubDomain(ownerZone, strings.ToUpper(name)) { // name is outside owner zone
+ return false
}
- if hname <= hash {
+
+ nextHash := rr.NextDomain
+ if ownerHash == nextHash { // empty interval
return false
}
- if hname >= rr.NextDomain {
+ if ownerHash > nextHash { // end of zone
+ if nameHash > ownerHash { // covered since there is nothing after ownerHash
+ return true
+ }
+ return nameHash < nextHash // if nameHash is before beginning of zone it is covered
+ }
+ if nameHash < ownerHash { // nameHash is before ownerHash, not covered
return false
}
- return true
+ return nameHash < nextHash // if nameHash is before nextHash is it covered (between ownerHash and nextHash)
}
-// Match implements the Denialer interface.
+// Match returns true if a name matches the NSEC3 record
func (rr *NSEC3) Match(name string) bool {
- // FIXME(miek): Check if we are in the same zone
- hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
- labels := Split(rr.Hdr.Name)
- if len(labels) < 2 {
+ nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
+ owner := strings.ToUpper(rr.Hdr.Name)
+ labelIndices := Split(owner)
+ if len(labelIndices) < 2 {
+ return false
+ }
+ ownerHash := owner[:labelIndices[1]-1]
+ ownerZone := owner[labelIndices[1]:]
+ if !IsSubDomain(ownerZone, strings.ToUpper(name)) { // name is outside owner zone
return false
}
- hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the .
- if hash == hname {
+ if ownerHash == nameHash {
return true
}
return false
// StringToClass is the reverse of ClassToString, needed for string parsing.
var StringToClass = reverseInt16(ClassToString)
-// Map of opcodes strings.
+// StringToOpcode is a map of opcodes to strings.
var StringToOpcode = reverseInt(OpcodeToString)
-// Map of rcodes strings.
+// StringToRcode is a map of rcodes to strings.
var StringToRcode = reverseInt(RcodeToString)
// Reverse a map
return
}
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
- l := <-c
- switch l.value {
+ switch l := <-c; l.value {
case zBlank:
l := <-c
if l.value == zString {
t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
return
}
- parseZone(r1, l.token, neworigin, t, include+1)
+ parseZone(r1, neworigin, l.token, t, include+1)
st = zExpectOwnerDir
case zExpectDirTtlBl:
if l.value != zBlank {
if stri > 0 {
l.value = zString
l.token = string(str[:stri])
+ l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
debug.Printf("[4 %+v]", l.token)
c <- l
owner = true
l.value = zNewline
l.token = "\n"
+ l.tokenUpper = l.token
l.length = 1
l.comment = string(com[:comi])
debug.Printf("[3 %+v %+v]", l.token, l.comment)
}
l.value = zNewline
l.token = "\n"
+ l.tokenUpper = l.token
l.length = 1
debug.Printf("[1 %+v]", l.token)
c <- l
if stri != 0 {
l.value = zString
l.token = string(str[:stri])
+ l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
debug.Printf("[%+v]", l.token)
// send quote itself as separate token
l.value = zQuote
l.token = "\""
+ l.tokenUpper = l.token
l.length = 1
c <- l
quote = !quote
brace--
if brace < 0 {
l.token = "extra closing brace"
+ l.tokenUpper = l.token
l.err = true
debug.Printf("[%+v]", l.token)
c <- l
if stri > 0 {
// Send remainder
l.token = string(str[:stri])
+ l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
l.value = zString
debug.Printf("[%+v]", l.token)
c <- l
}
+ if brace != 0 {
+ l.token = "unbalanced brace"
+ l.tokenUpper = l.token
+ l.err = true
+ c <- l
+ }
}
// Extract the class number from CLASSxx
if len(token) < offset+1 {
return 0, false
}
- class, ok := strconv.Atoi(token[offset:])
- if ok != nil || class > maxUint16 {
+ class, err := strconv.ParseUint(token[offset:], 10, 16)
+ if err != nil {
return 0, false
}
return uint16(class), true
if len(token) < offset+1 {
return 0, false
}
- typ, ok := strconv.Atoi(token[offset:])
- if ok != nil || typ > maxUint16 {
+ typ, err := strconv.ParseUint(token[offset:], 10, 16)
+ if err != nil {
return 0, false
}
return uint16(typ), true
return s, nil, l.comment
}
-// A remainder of the rdata with embedded spaces, return the parsed string slice (sans the spaces)
-// or an error
+// A remainder of the rdata with embedded spaces, split on unquoted whitespace
+// and return the parsed string slice or an error
func endingToTxtSlice(c chan lex, errstr, f string) ([]string, *ParseError, string) {
// Get the remaining data until we see a zNewline
- quote := false
l := <-c
- var s []string
if l.err {
- return s, &ParseError{f, errstr, l}, ""
- }
- switch l.value == zQuote {
- case true: // A number of quoted string
- s = make([]string, 0)
- empty := true
- for l.value != zNewline && l.value != zEOF {
- if l.err {
- return nil, &ParseError{f, errstr, l}, ""
- }
- switch l.value {
- case zString:
- empty = false
- if len(l.token) > 255 {
- // split up tokens that are larger than 255 into 255-chunks
- sx := []string{}
- p, i := 0, 255
- for {
- if i <= len(l.token) {
- sx = append(sx, l.token[p:i])
- } else {
- sx = append(sx, l.token[p:])
- break
-
- }
- p, i = p+255, i+255
+ return nil, &ParseError{f, errstr, l}, ""
+ }
+
+ // Build the slice
+ s := make([]string, 0)
+ quote := false
+ empty := false
+ for l.value != zNewline && l.value != zEOF {
+ if l.err {
+ return nil, &ParseError{f, errstr, l}, ""
+ }
+ switch l.value {
+ case zString:
+ empty = false
+ if len(l.token) > 255 {
+ // split up tokens that are larger than 255 into 255-chunks
+ sx := []string{}
+ p, i := 0, 255
+ for {
+ if i <= len(l.token) {
+ sx = append(sx, l.token[p:i])
+ } else {
+ sx = append(sx, l.token[p:])
+ break
+
}
- s = append(s, sx...)
- break
+ p, i = p+255, i+255
}
+ s = append(s, sx...)
+ break
+ }
- s = append(s, l.token)
- case zBlank:
- if quote {
- // zBlank can only be seen in between txt parts.
- return nil, &ParseError{f, errstr, l}, ""
- }
- case zQuote:
- if empty && quote {
- s = append(s, "")
- }
- quote = !quote
- empty = true
- default:
+ s = append(s, l.token)
+ case zBlank:
+ if quote {
+ // zBlank can only be seen in between txt parts.
return nil, &ParseError{f, errstr, l}, ""
}
- l = <-c
- }
- if quote {
- return nil, &ParseError{f, errstr, l}, ""
- }
- case false: // Unquoted text record
- s = make([]string, 1)
- for l.value != zNewline && l.value != zEOF {
- if l.err {
- return s, &ParseError{f, errstr, l}, ""
+ case zQuote:
+ if empty && quote {
+ s = append(s, "")
}
- s[0] += l.token
- l = <-c
+ quote = !quote
+ empty = true
+ default:
+ return nil, &ParseError{f, errstr, l}, ""
}
+ l = <-c
+ }
+ if quote {
+ return nil, &ParseError{f, errstr, l}, ""
}
return s, nil, l.comment
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad MX Pref", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil {
return nil, &ParseError{f, "bad RT Preference", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad AFSDB Subtype", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad KX Pref", l}, ""
}
if l.err {
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
}
- if j, e := strconv.Atoi(l.token); e != nil {
+ if j, e := strconv.ParseUint(l.token, 10, 32); e != nil {
if i == 0 {
// Serial should be a number
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad SRV Priority", l}, ""
}
rr.Priority = uint16(i)
<-c // zBlank
l = <-c // zString
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad SRV Weight", l}, ""
}
rr.Weight = uint16(i)
<-c // zBlank
l = <-c // zString
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad SRV Port", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad NAPTR Order", l}, ""
}
rr.Order = uint16(i)
<-c // zBlank
l = <-c // zString
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad NAPTR Preference", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return nil, &ParseError{f, "bad LOC Latitude", l}, ""
}
if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
goto East
}
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return nil, &ParseError{f, "bad LOC Latitude minutes", l}, ""
}
// East
<-c // zBlank
l = <-c
- if i, e := strconv.Atoi(l.token); e != nil || l.err {
+ if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err {
return nil, &ParseError{f, "bad LOC Longitude", l}, ""
} else {
rr.Longitude = 1000 * 60 * 60 * uint32(i)
if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
goto Altitude
}
- if i, e := strconv.Atoi(l.token); e != nil || l.err {
+ if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err {
return nil, &ParseError{f, "bad LOC Longitude minutes", l}, ""
} else {
rr.Longitude += 1000 * 60 * uint32(i)
if l.length == 0 {
return rr, nil, l.comment
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, ""
}
}
if v, ok := StringToCertType[l.token]; ok {
rr.Type = v
- } else if i, e := strconv.Atoi(l.token); e != nil {
+ } else if i, e := strconv.ParseUint(l.token, 10, 16); e != nil {
return nil, &ParseError{f, "bad CERT Type", l}, ""
} else {
rr.Type = uint16(i)
}
<-c // zBlank
l = <-c // zString
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad CERT KeyTag", l}, ""
}
l = <-c // zString
if v, ok := StringToAlgorithm[l.token]; ok {
rr.Algorithm = v
- } else if i, e := strconv.Atoi(l.token); e != nil {
+ } else if i, e := strconv.ParseUint(l.token, 10, 8); e != nil {
return nil, &ParseError{f, "bad CERT Algorithm", l}, ""
} else {
rr.Algorithm = uint8(i)
}
<-c // zBlank
l = <-c
- i, err := strconv.Atoi(l.token)
+ i, err := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return nil, &ParseError{f, "bad RRSIG Algorithm", l}, ""
}
rr.Algorithm = uint8(i)
<-c // zBlank
l = <-c
- i, err = strconv.Atoi(l.token)
+ i, err = strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return nil, &ParseError{f, "bad RRSIG Labels", l}, ""
}
rr.Labels = uint8(i)
<-c // zBlank
l = <-c
- i, err = strconv.Atoi(l.token)
+ i, err = strconv.ParseUint(l.token, 10, 32)
if err != nil || l.err {
return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, ""
}
}
<-c // zBlank
l = <-c
- i, err = strconv.Atoi(l.token)
+ i, err = strconv.ParseUint(l.token, 10, 16)
if err != nil || l.err {
return nil, &ParseError{f, "bad RRSIG KeyTag", l}, ""
}
if l.length == 0 {
return rr, nil, l.comment
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3 Hash", l}, ""
}
rr.Hash = uint8(i)
<-c // zBlank
l = <-c
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3 Flags", l}, ""
}
rr.Flags = uint8(i)
<-c // zBlank
l = <-c
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3 Iterations", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, ""
}
rr.Hash = uint8(i)
<-c // zBlank
l = <-c
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3PARAM Flags", l}, ""
}
rr.Flags = uint8(i)
<-c // zBlank
l = <-c
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3PARAM Iterations", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad SSHFP Algorithm", l}, ""
}
rr.Algorithm = uint8(i)
<-c // zBlank
l = <-c
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad SSHFP Type", l}, ""
}
if l.length == 0 {
return rr, nil, l.comment
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad " + typ + " Flags", l}, ""
}
rr.Flags = uint16(i)
<-c // zBlank
l = <-c // zString
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad " + typ + " Protocol", l}, ""
}
rr.Protocol = uint8(i)
<-c // zBlank
l = <-c // zString
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
}
if l.length == 0 {
return rr, nil, l.comment
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad RKEY Flags", l}, ""
}
rr.Flags = uint16(i)
<-c // zBlank
l = <-c // zString
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad RKEY Protocol", l}, ""
}
rr.Protocol = uint8(i)
<-c // zBlank
l = <-c // zString
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad RKEY Algorithm", l}, ""
}
if l.length == 0 {
return rr, nil, l.comment
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, ""
}
rr.KeyTag = uint16(i)
<-c // zBlank
l = <-c
- if i, e := strconv.Atoi(l.token); e != nil {
+ if i, e = strconv.ParseUint(l.token, 10, 8); e != nil {
i, ok := StringToAlgorithm[l.tokenUpper]
if !ok || l.err {
return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
}
<-c // zBlank
l = <-c
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad " + typ + " DigestType", l}, ""
}
if l.length == 0 {
return rr, nil, l.comment
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad TA KeyTag", l}, ""
}
rr.KeyTag = uint16(i)
<-c // zBlank
l = <-c
- if i, e := strconv.Atoi(l.token); e != nil {
+ if i, e := strconv.ParseUint(l.token, 10, 8); e != nil {
i, ok := StringToAlgorithm[l.tokenUpper]
if !ok || l.err {
return nil, &ParseError{f, "bad TA Algorithm", l}, ""
}
<-c // zBlank
l = <-c
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad TA DigestType", l}, ""
}
if l.length == 0 {
return rr, nil, l.comment
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad TLSA Usage", l}, ""
}
rr.Usage = uint8(i)
<-c // zBlank
l = <-c
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad TLSA Selector", l}, ""
}
rr.Selector = uint8(i)
<-c // zBlank
l = <-c
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad TLSA MatchingType", l}, ""
}
return rr, nil, c1
}
+func setSMIMEA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+ rr := new(SMIMEA)
+ rr.Hdr = h
+ l := <-c
+ if l.length == 0 {
+ return rr, nil, l.comment
+ }
+ i, e := strconv.ParseUint(l.token, 10, 8)
+ if e != nil || l.err {
+ return nil, &ParseError{f, "bad SMIMEA Usage", l}, ""
+ }
+ rr.Usage = uint8(i)
+ <-c // zBlank
+ l = <-c
+ i, e = strconv.ParseUint(l.token, 10, 8)
+ if e != nil || l.err {
+ return nil, &ParseError{f, "bad SMIMEA Selector", l}, ""
+ }
+ rr.Selector = uint8(i)
+ <-c // zBlank
+ l = <-c
+ i, e = strconv.ParseUint(l.token, 10, 8)
+ if e != nil || l.err {
+ return nil, &ParseError{f, "bad SMIMEA MatchingType", l}, ""
+ }
+ rr.MatchingType = uint8(i)
+ // So this needs be e2 (i.e. different than e), because...??t
+ s, e2, c1 := endingToString(c, "bad SMIMEA Certificate", f)
+ if e2 != nil {
+ return nil, e2, c1
+ }
+ rr.Certificate = s
+ return rr, nil, c1
+}
+
func setRFC3597(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
rr := new(RFC3597)
rr.Hdr = h
return rr, nil, c1
}
+func setAVC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+ rr := new(AVC)
+ rr.Hdr = h
+
+ s, e, c1 := endingToTxtSlice(c, "bad AVC Txt", f)
+ if e != nil {
+ return nil, e, ""
+ }
+ rr.Txt = s
+ return rr, nil, c1
+}
+
func setTXT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
rr := new(TXT)
rr.Hdr = h
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad URI Priority", l}, ""
}
rr.Priority = uint16(i)
<-c // zBlank
l = <-c
- i, e = strconv.Atoi(l.token)
+ i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad URI Weight", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad NID Preference", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad L32 Preference", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad LP Preference", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad L64 Preference", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return nil, &ParseError{f, "bad UID Uid", l}, ""
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return nil, &ParseError{f, "bad GID Gid", l}, ""
}
rr.Hdr = h
s, e, c1 := endingToTxtSlice(c, "bad UINFO Uinfo", f)
if e != nil {
- return nil, e, ""
+ return nil, e, c1
+ }
+ if ln := len(s); ln == 0 {
+ return rr, nil, c1
}
- rr.Uinfo = s[0] // silently discard anything above
+ rr.Uinfo = s[0] // silently discard anything after the first character-string
return rr, nil, c1
}
if l.length == 0 {
return rr, nil, ""
}
- i, e := strconv.Atoi(l.token)
+ i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad PX Preference", l}, ""
}
if l.length == 0 {
return rr, nil, l.comment
}
- i, err := strconv.Atoi(l.token)
+ i, err := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return nil, &ParseError{f, "bad CAA Flag", l}, ""
}
TypeRP: {setRP, false},
TypeRRSIG: {setRRSIG, true},
TypeRT: {setRT, false},
+ TypeSMIMEA: {setSMIMEA, true},
TypeSOA: {setSOA, false},
TypeSPF: {setSPF, true},
+ TypeAVC: {setAVC, true},
TypeSRV: {setSRV, false},
TypeSSHFP: {setSSHFP, true},
TypeTALINK: {setTALINK, false},
b[i] |= ('a' - 'A')
}
}
- if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
+ if h, ok := mux.z[string(b[:l])]; ok { // causes garbage, might want to change the map key
if t != TypeDS {
return h
}
network := "tcp"
if srv.Net == "tcp4-tls" {
network = "tcp4"
- } else if srv.Net == "tcp6" {
+ } else if srv.Net == "tcp6-tls" {
network = "tcp6"
}
if srv.UDPSize == 0 {
srv.UDPSize = MinMsgSize
}
- if t, ok := pConn.(*net.UDPConn); ok {
+ // Check PacketConn interface's type is valid and value
+ // is not nil
+ if t, ok := pConn.(*net.UDPConn); ok && t != nil {
if e := setUDPSocketOptions(t); e != nil {
return e
}
}
rr.Signature = toBase64(signature)
- sig := string(signature)
- buf = append(buf, sig...)
+ buf = append(buf, signature...)
if len(buf) > int(^uint16(0)) {
return nil, ErrBuf
}
// Adjust sig data length
rdoff := len(mbuf) + 1 + 2 + 2 + 4
rdlen := binary.BigEndian.Uint16(buf[rdoff:])
- rdlen += uint16(len(sig))
+ rdlen += uint16(len(signature))
binary.BigEndian.PutUint16(buf[rdoff:], rdlen)
// Adjust additional count
adc := binary.BigEndian.Uint16(buf[10:])
package dns
import (
- "crypto/sha256"
- "crypto/sha512"
"crypto/x509"
- "encoding/hex"
- "errors"
- "io"
"net"
"strconv"
)
-// CertificateToDANE converts a certificate to a hex string as used in the TLSA record.
-func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) {
- switch matchingType {
- case 0:
- switch selector {
- case 0:
- return hex.EncodeToString(cert.Raw), nil
- case 1:
- return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil
- }
- case 1:
- h := sha256.New()
- switch selector {
- case 0:
- io.WriteString(h, string(cert.Raw))
- return hex.EncodeToString(h.Sum(nil)), nil
- case 1:
- io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
- return hex.EncodeToString(h.Sum(nil)), nil
- }
- case 2:
- h := sha512.New()
- switch selector {
- case 0:
- io.WriteString(h, string(cert.Raw))
- return hex.EncodeToString(h.Sum(nil)), nil
- case 1:
- io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
- return hex.EncodeToString(h.Sum(nil)), nil
- }
- }
- return "", errors.New("dns: bad TLSA MatchingType or TLSA Selector")
-}
-
// Sign creates a TLSA record from an SSL certificate.
func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
r.Hdr.Rrtype = TypeTLSA
"encoding/binary"
"encoding/hex"
"hash"
- "io"
"strconv"
"strings"
"time"
default:
return nil, "", ErrKeyAlg
}
- io.WriteString(h, string(buf))
+ h.Write(buf)
t.MAC = hex.EncodeToString(h.Sum(nil))
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
rr.Fudge = 300 // Standard (RFC) default.
}
+ // Replace message ID in header with original ID from TSIG
+ binary.BigEndian.PutUint16(msgbuf[0:2], rr.OrigId)
+
if requestMAC != "" {
m := new(macWireFmt)
m.MACSize = uint16(len(requestMAC) / 2)
TypeNSEC3 uint16 = 50
TypeNSEC3PARAM uint16 = 51
TypeTLSA uint16 = 52
+ TypeSMIMEA uint16 = 53
TypeHIP uint16 = 55
TypeNINFO uint16 = 56
TypeRKEY uint16 = 57
TypeEUI64 uint16 = 109
TypeURI uint16 = 256
TypeCAA uint16 = 257
+ TypeAVC uint16 = 258
TypeTKEY uint16 = 249
TypeTSIG uint16 = 250
ClassNONE = 254
ClassANY = 255
- // Message Response Codes.
- RcodeSuccess = 0
- RcodeFormatError = 1
- RcodeServerFailure = 2
- RcodeNameError = 3
- RcodeNotImplemented = 4
- RcodeRefused = 5
- RcodeYXDomain = 6
- RcodeYXRrset = 7
- RcodeNXRrset = 8
- RcodeNotAuth = 9
- RcodeNotZone = 10
- RcodeBadSig = 16 // TSIG
- RcodeBadVers = 16 // EDNS0
- RcodeBadKey = 17
- RcodeBadTime = 18
- RcodeBadMode = 19 // TKEY
- RcodeBadName = 20
- RcodeBadAlg = 21
- RcodeBadTrunc = 22 // TSIG
- RcodeBadCookie = 23 // DNS Cookies
+ // Message Response Codes, see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
+ RcodeSuccess = 0 // NoError - No Error [DNS]
+ RcodeFormatError = 1 // FormErr - Format Error [DNS]
+ RcodeServerFailure = 2 // ServFail - Server Failure [DNS]
+ RcodeNameError = 3 // NXDomain - Non-Existent Domain [DNS]
+ RcodeNotImplemented = 4 // NotImp - Not Implemented [DNS]
+ RcodeRefused = 5 // Refused - Query Refused [DNS]
+ RcodeYXDomain = 6 // YXDomain - Name Exists when it should not [DNS Update]
+ RcodeYXRrset = 7 // YXRRSet - RR Set Exists when it should not [DNS Update]
+ RcodeNXRrset = 8 // NXRRSet - RR Set that should exist does not [DNS Update]
+ RcodeNotAuth = 9 // NotAuth - Server Not Authoritative for zone [DNS Update]
+ RcodeNotZone = 10 // NotZone - Name not contained in zone [DNS Update/TSIG]
+ RcodeBadSig = 16 // BADSIG - TSIG Signature Failure [TSIG]
+ RcodeBadVers = 16 // BADVERS - Bad OPT Version [EDNS0]
+ RcodeBadKey = 17 // BADKEY - Key not recognized [TSIG]
+ RcodeBadTime = 18 // BADTIME - Signature out of time window [TSIG]
+ RcodeBadMode = 19 // BADMODE - Bad TKEY Mode [TKEY]
+ RcodeBadName = 20 // BADNAME - Duplicate key name [TKEY]
+ RcodeBadAlg = 21 // BADALG - Algorithm not supported [TKEY]
+ RcodeBadTrunc = 22 // BADTRUNC - Bad Truncation [TSIG]
+ RcodeBadCookie = 23 // BADCOOKIE - Bad/missing Server Cookie [DNS Cookies]
// Message Opcodes. There is no 3.
OpcodeQuery = 0
OpcodeUpdate = 5
)
-// Headers is the wire format for the DNS packet header.
+// Header is the wire format for the DNS packet header.
type Header struct {
Id uint16
Bits uint16
func appendTXTStringByte(s []byte, b byte) []byte {
switch b {
- case '\t':
- return append(s, '\\', 't')
- case '\r':
- return append(s, '\\', 'r')
- case '\n':
- return append(s, '\\', 'n')
case '"', '\\':
return append(s, '\\', b)
}
return dddToByte(b[offset+1:]), 4
}
}
- // not \ddd, maybe a control char
- switch b[offset+1] {
- case 't':
- return '\t', 2
- case 'r':
- return '\r', 2
- case 'n':
- return '\n', 2
- default:
- return b[offset+1], 2
- }
+ // not \ddd, just an RFC 1035 "quoted" character
+ return b[offset+1], 2
}
type SPF struct {
func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
+type AVC struct {
+ Hdr RR_Header
+ Txt []string `dns:"txt"`
+}
+
+func (rr *AVC) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
+
type SRV struct {
Hdr RR_Header
Priority uint16
Flags uint8
Iterations uint16
SaltLength uint8
- Salt string `dns:"hex"`
+ Salt string `dns:"size-hex:SaltLength"`
}
func (rr *NSEC3PARAM) String() string {
" " + rr.Certificate
}
+type SMIMEA struct {
+ Hdr RR_Header
+ Usage uint8
+ Selector uint8
+ MatchingType uint8
+ Certificate string `dns:"hex"`
+}
+
+func (rr *SMIMEA) String() string {
+ s := rr.Hdr.String() +
+ strconv.Itoa(int(rr.Usage)) +
+ " " + strconv.Itoa(int(rr.Selector)) +
+ " " + strconv.Itoa(int(rr.MatchingType))
+
+ // Every Nth char needs a space on this output. If we output
+ // this as one giant line, we can't read it can in because in some cases
+ // the cert length overflows scan.maxTok (2048).
+ sx := splitN(rr.Certificate, 1024) // conservative value here
+ s += " " + strings.Join(sx, " ")
+ return s
+}
+
type HIP struct {
Hdr RR_Header
HitLength uint8
return uint32(t.Unix() - (mod * year68)), nil
}
-// saltToString converts a NSECX salt to uppercase and
-// returns "-" when it is empty
+// saltToString converts a NSECX salt to uppercase and returns "-" when it is empty.
func saltToString(s string) string {
if len(s) == 0 {
return "-"
copy(p, ip)
return p
}
+
+// SplitN splits a string into N sized string chunks.
+// This might become an exported function once.
+func splitN(s string, n int) []string {
+ if len(s) < n {
+ return []string{s}
+ }
+ sx := []string{}
+ p, i := 0, n
+ for {
+ if i <= len(s) {
+ sx = append(sx, s[p:i])
+ } else {
+ sx = append(sx, s[p:])
+ break
+
+ }
+ p, i = p+n, i+n
+ }
+
+ return sx
+}
case st.Tag(i) == "":
switch st.Field(i).Type().(*types.Basic).Kind() {
case types.Uint8:
- o("l += 1 // %s\n")
+ o("l++ // %s\n")
case types.Uint16:
o("l += 2 // %s\n")
case types.Uint32:
-// +build !windows,!plan9
+// +build !windows
package dns
import (
"net"
- "syscall"
)
// SessionUDP holds the remote address and the associated
// RemoteAddr returns the remote network address.
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
-// setUDPSocketOptions sets the UDP socket options.
-// This function is implemented on a per platform basis. See udp_*.go for more details
-func setUDPSocketOptions(conn *net.UDPConn) error {
- sa, err := getUDPSocketName(conn)
- if err != nil {
- return err
- }
- switch sa.(type) {
- case *syscall.SockaddrInet6:
- v6only, err := getUDPSocketOptions6Only(conn)
- if err != nil {
- return err
- }
- setUDPSocketOptions6(conn)
- if !v6only {
- setUDPSocketOptions4(conn)
- }
- case *syscall.SockaddrInet4:
- setUDPSocketOptions4(conn)
- }
- return nil
-}
-
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
// net.UDPAddr.
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
-// +build linux
+// +build linux,!appengine
package dns
"syscall"
)
+// setUDPSocketOptions sets the UDP socket options.
+// This function is implemented on a per platform basis. See udp_*.go for more details
+func setUDPSocketOptions(conn *net.UDPConn) error {
+ sa, err := getUDPSocketName(conn)
+ if err != nil {
+ return err
+ }
+ switch sa.(type) {
+ case *syscall.SockaddrInet6:
+ v6only, err := getUDPSocketOptions6Only(conn)
+ if err != nil {
+ return err
+ }
+ setUDPSocketOptions6(conn)
+ if !v6only {
+ setUDPSocketOptions4(conn)
+ }
+ case *syscall.SockaddrInet4:
+ setUDPSocketOptions4(conn)
+ }
+ return nil
+}
+
// setUDPSocketOptions4 prepares the v4 socket for sessions.
func setUDPSocketOptions4(conn *net.UDPConn) error {
file, err := conn.File()
return err
}
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
+ file.Close()
return err
}
// Calling File() above results in the connection becoming blocking, we must fix that.
// See https://github.com/miekg/dns/issues/279
err = syscall.SetNonblock(int(file.Fd()), true)
if err != nil {
+ file.Close()
return err
}
+ file.Close()
return nil
}
return err
}
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
+ file.Close()
return err
}
err = syscall.SetNonblock(int(file.Fd()), true)
if err != nil {
+ file.Close()
return err
}
+ file.Close()
return nil
}
// dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections
v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY)
if err != nil {
+ file.Close()
return false, err
}
+ file.Close()
return v6only == 1, nil
}
if err != nil {
return nil, err
}
+ defer file.Close()
return syscall.Getsockname(int(file.Fd()))
}
-// +build !linux,!plan9
+// +build !linux appengine
package dns
import (
"net"
- "syscall"
)
// These do nothing. See udp_linux.go for an example of how to implement this.
// We tried to adhire to some kind of naming scheme.
-
+func setUDPSocketOptions(conn *net.UDPConn) error { return nil }
func setUDPSocketOptions4(conn *net.UDPConn) error { return nil }
func setUDPSocketOptions6(conn *net.UDPConn) error { return nil }
func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) { return false, nil }
-func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { return nil, nil }
+++ /dev/null
-package dns
-
-import (
- "net"
-)
-
-func setUDPSocketOptions(conn *net.UDPConn) error { return nil }
-
-// SessionUDP holds the remote address and the associated
-// out-of-band data.
-type SessionUDP struct {
- raddr *net.UDPAddr
- context []byte
-}
-
-// RemoteAddr returns the remote network address.
-func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
-
-// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
-// net.UDPAddr.
-func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
- oob := make([]byte, 40)
- n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
- if err != nil {
- return n, nil, err
- }
- return n, &SessionUDP{raddr, oob[:oobn]}, err
-}
-
-// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
-func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
- n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
- return n, err
-}
raddr *net.UDPAddr
}
+func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
+
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
// net.UDPAddr.
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
return n, err
}
-func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
-
-// setUDPSocketOptions sets the UDP socket options.
-// This function is implemented on a per platform basis. See udp_*.go for more details
-func setUDPSocketOptions(conn *net.UDPConn) error {
- return nil
-}
package dns
import (
+ "fmt"
"time"
)
return
}
if first {
+ if in.Rcode != RcodeSuccess {
+ c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
+ return
+ }
if !isSOAFirst(in) {
c <- &Envelope{in.Answer, ErrSoa}
return
return
}
if first {
+ if in.Rcode != RcodeSuccess {
+ c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
+ return
+ }
// A single SOA RR signals "no changes"
if len(in.Answer) == 1 && isSOAFirst(in) {
c <- &Envelope{in.Answer, nil}
}
return false
}
+
+const errXFR = "bad xfr rcode: %d"
return off, nil
}
+func (rr *AVC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+ off, err := rr.Hdr.pack(msg, off, compression, compress)
+ if err != nil {
+ return off, err
+ }
+ headerEnd := off
+ off, err = packStringTxt(rr.Txt, msg, off)
+ if err != nil {
+ return off, err
+ }
+ rr.Header().Rdlength = uint16(off - headerEnd)
+ return off, nil
+}
+
func (rr *CAA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
off, err := rr.Hdr.pack(msg, off, compression, compress)
if err != nil {
return off, err
}
headerEnd := off
- off, err = PackDomainName(rr.Target, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Target, msg, off, compression, false)
if err != nil {
return off, err
}
if err != nil {
return off, err
}
- off, err = PackDomainName(rr.Exchanger, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Exchanger, msg, off, compression, false)
if err != nil {
return off, err
}
if err != nil {
return off, err
}
- off, err = PackDomainName(rr.Fqdn, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Fqdn, msg, off, compression, false)
if err != nil {
return off, err
}
if err != nil {
return off, err
}
- off, err = PackDomainName(rr.Replacement, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Replacement, msg, off, compression, false)
if err != nil {
return off, err
}
return off, err
}
headerEnd := off
- off, err = PackDomainName(rr.Ptr, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Ptr, msg, off, compression, false)
if err != nil {
return off, err
}
return off, err
}
headerEnd := off
- off, err = PackDomainName(rr.NextDomain, msg, off, compression, compress)
+ off, err = PackDomainName(rr.NextDomain, msg, off, compression, false)
if err != nil {
return off, err
}
if err != nil {
return off, err
}
- off, err = packStringHex(rr.Salt, msg, off)
- if err != nil {
- return off, err
+ // Only pack salt if value is not "-", i.e. empty
+ if rr.Salt != "-" {
+ off, err = packStringHex(rr.Salt, msg, off)
+ if err != nil {
+ return off, err
+ }
}
off, err = packUint8(rr.HashLength, msg, off)
if err != nil {
if err != nil {
return off, err
}
- off, err = packStringHex(rr.Salt, msg, off)
- if err != nil {
- return off, err
+ // Only pack salt if value is not "-", i.e. empty
+ if rr.Salt != "-" {
+ off, err = packStringHex(rr.Salt, msg, off)
+ if err != nil {
+ return off, err
+ }
}
rr.Header().Rdlength = uint16(off - headerEnd)
return off, nil
if err != nil {
return off, err
}
- off, err = PackDomainName(rr.Map822, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Map822, msg, off, compression, false)
if err != nil {
return off, err
}
- off, err = PackDomainName(rr.Mapx400, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Mapx400, msg, off, compression, false)
if err != nil {
return off, err
}
return off, err
}
headerEnd := off
- off, err = PackDomainName(rr.Mbox, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Mbox, msg, off, compression, false)
if err != nil {
return off, err
}
- off, err = PackDomainName(rr.Txt, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Txt, msg, off, compression, false)
if err != nil {
return off, err
}
if err != nil {
return off, err
}
- off, err = PackDomainName(rr.SignerName, msg, off, compression, compress)
+ off, err = PackDomainName(rr.SignerName, msg, off, compression, false)
if err != nil {
return off, err
}
if err != nil {
return off, err
}
- off, err = PackDomainName(rr.SignerName, msg, off, compression, compress)
+ off, err = PackDomainName(rr.SignerName, msg, off, compression, false)
if err != nil {
return off, err
}
return off, nil
}
+func (rr *SMIMEA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+ off, err := rr.Hdr.pack(msg, off, compression, compress)
+ if err != nil {
+ return off, err
+ }
+ headerEnd := off
+ off, err = packUint8(rr.Usage, msg, off)
+ if err != nil {
+ return off, err
+ }
+ off, err = packUint8(rr.Selector, msg, off)
+ if err != nil {
+ return off, err
+ }
+ off, err = packUint8(rr.MatchingType, msg, off)
+ if err != nil {
+ return off, err
+ }
+ off, err = packStringHex(rr.Certificate, msg, off)
+ if err != nil {
+ return off, err
+ }
+ rr.Header().Rdlength = uint16(off - headerEnd)
+ return off, nil
+}
+
func (rr *SOA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
off, err := rr.Hdr.pack(msg, off, compression, compress)
if err != nil {
if err != nil {
return off, err
}
- off, err = PackDomainName(rr.Target, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Target, msg, off, compression, false)
if err != nil {
return off, err
}
return off, err
}
headerEnd := off
- off, err = PackDomainName(rr.PreviousName, msg, off, compression, compress)
+ off, err = PackDomainName(rr.PreviousName, msg, off, compression, false)
if err != nil {
return off, err
}
- off, err = PackDomainName(rr.NextName, msg, off, compression, compress)
+ off, err = PackDomainName(rr.NextName, msg, off, compression, false)
if err != nil {
return off, err
}
return off, err
}
headerEnd := off
- off, err = PackDomainName(rr.Algorithm, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Algorithm, msg, off, compression, false)
if err != nil {
return off, err
}
return off, err
}
headerEnd := off
- off, err = PackDomainName(rr.Algorithm, msg, off, compression, compress)
+ off, err = PackDomainName(rr.Algorithm, msg, off, compression, false)
if err != nil {
return off, err
}
return rr, off, err
}
+func unpackAVC(h RR_Header, msg []byte, off int) (RR, int, error) {
+ rr := new(AVC)
+ rr.Hdr = h
+ if noRdata(h) {
+ return rr, off, nil
+ }
+ var err error
+ rdStart := off
+ _ = rdStart
+
+ rr.Txt, off, err = unpackStringTxt(msg, off)
+ if err != nil {
+ return rr, off, err
+ }
+ return rr, off, err
+}
+
func unpackCAA(h RR_Header, msg []byte, off int) (RR, int, error) {
rr := new(CAA)
rr.Hdr = h
if off == len(msg) {
return rr, off, nil
}
- rr.Salt, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+ rr.Salt, off, err = unpackStringHex(msg, off, off+int(rr.SaltLength))
if err != nil {
return rr, off, err
}
return rr, off, err
}
+func unpackSMIMEA(h RR_Header, msg []byte, off int) (RR, int, error) {
+ rr := new(SMIMEA)
+ rr.Hdr = h
+ if noRdata(h) {
+ return rr, off, nil
+ }
+ var err error
+ rdStart := off
+ _ = rdStart
+
+ rr.Usage, off, err = unpackUint8(msg, off)
+ if err != nil {
+ return rr, off, err
+ }
+ if off == len(msg) {
+ return rr, off, nil
+ }
+ rr.Selector, off, err = unpackUint8(msg, off)
+ if err != nil {
+ return rr, off, err
+ }
+ if off == len(msg) {
+ return rr, off, nil
+ }
+ rr.MatchingType, off, err = unpackUint8(msg, off)
+ if err != nil {
+ return rr, off, err
+ }
+ if off == len(msg) {
+ return rr, off, nil
+ }
+ rr.Certificate, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+ if err != nil {
+ return rr, off, err
+ }
+ return rr, off, err
+}
+
func unpackSOA(h RR_Header, msg []byte, off int) (RR, int, error) {
rr := new(SOA)
rr.Hdr = h
TypeAAAA: unpackAAAA,
TypeAFSDB: unpackAFSDB,
TypeANY: unpackANY,
+ TypeAVC: unpackAVC,
TypeCAA: unpackCAA,
TypeCDNSKEY: unpackCDNSKEY,
TypeCDS: unpackCDS,
TypeRRSIG: unpackRRSIG,
TypeRT: unpackRT,
TypeSIG: unpackSIG,
+ TypeSMIMEA: unpackSMIMEA,
TypeSOA: unpackSOA,
TypeSPF: unpackSPF,
TypeSRV: unpackSRV,
TypeAAAA: func() RR { return new(AAAA) },
TypeAFSDB: func() RR { return new(AFSDB) },
TypeANY: func() RR { return new(ANY) },
+ TypeAVC: func() RR { return new(AVC) },
TypeCAA: func() RR { return new(CAA) },
TypeCDNSKEY: func() RR { return new(CDNSKEY) },
TypeCDS: func() RR { return new(CDS) },
TypeRRSIG: func() RR { return new(RRSIG) },
TypeRT: func() RR { return new(RT) },
TypeSIG: func() RR { return new(SIG) },
+ TypeSMIMEA: func() RR { return new(SMIMEA) },
TypeSOA: func() RR { return new(SOA) },
TypeSPF: func() RR { return new(SPF) },
TypeSRV: func() RR { return new(SRV) },
TypeAFSDB: "AFSDB",
TypeANY: "ANY",
TypeATMA: "ATMA",
+ TypeAVC: "AVC",
TypeAXFR: "AXFR",
TypeCAA: "CAA",
TypeCDNSKEY: "CDNSKEY",
TypeRT: "RT",
TypeReserved: "Reserved",
TypeSIG: "SIG",
+ TypeSMIMEA: "SMIMEA",
TypeSOA: "SOA",
TypeSPF: "SPF",
TypeSRV: "SRV",
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
+func (rr *AVC) Header() *RR_Header { return &rr.Hdr }
func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr }
func (rr *CDS) Header() *RR_Header { return &rr.Hdr }
func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
func (rr *RT) Header() *RR_Header { return &rr.Hdr }
func (rr *SIG) Header() *RR_Header { return &rr.Hdr }
+func (rr *SMIMEA) Header() *RR_Header { return &rr.Hdr }
func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
l := rr.Hdr.len()
return l
}
+func (rr *AVC) len() int {
+ l := rr.Hdr.len()
+ for _, x := range rr.Txt {
+ l += len(x) + 1
+ }
+ return l
+}
func (rr *CAA) len() int {
l := rr.Hdr.len()
- l += 1 // Flag
+ l++ // Flag
l += len(rr.Tag) + 1
l += len(rr.Value)
return l
l := rr.Hdr.len()
l += 2 // Type
l += 2 // KeyTag
- l += 1 // Algorithm
+ l++ // Algorithm
l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
return l
}
func (rr *DNSKEY) len() int {
l := rr.Hdr.len()
l += 2 // Flags
- l += 1 // Protocol
- l += 1 // Algorithm
+ l++ // Protocol
+ l++ // Algorithm
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
return l
}
func (rr *DS) len() int {
l := rr.Hdr.len()
l += 2 // KeyTag
- l += 1 // Algorithm
- l += 1 // DigestType
+ l++ // Algorithm
+ l++ // DigestType
l += len(rr.Digest)/2 + 1
return l
}
}
func (rr *HIP) len() int {
l := rr.Hdr.len()
- l += 1 // HitLength
- l += 1 // PublicKeyAlgorithm
+ l++ // HitLength
+ l++ // PublicKeyAlgorithm
l += 2 // PublicKeyLength
l += len(rr.Hit)/2 + 1
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
}
func (rr *LOC) len() int {
l := rr.Hdr.len()
- l += 1 // Version
- l += 1 // Size
- l += 1 // HorizPre
- l += 1 // VertPre
+ l++ // Version
+ l++ // Size
+ l++ // HorizPre
+ l++ // VertPre
l += 4 // Latitude
l += 4 // Longitude
l += 4 // Altitude
}
func (rr *NSEC3PARAM) len() int {
l := rr.Hdr.len()
- l += 1 // Hash
- l += 1 // Flags
+ l++ // Hash
+ l++ // Flags
l += 2 // Iterations
- l += 1 // SaltLength
+ l++ // SaltLength
l += len(rr.Salt)/2 + 1
return l
}
func (rr *RKEY) len() int {
l := rr.Hdr.len()
l += 2 // Flags
- l += 1 // Protocol
- l += 1 // Algorithm
+ l++ // Protocol
+ l++ // Algorithm
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
return l
}
func (rr *RRSIG) len() int {
l := rr.Hdr.len()
l += 2 // TypeCovered
- l += 1 // Algorithm
- l += 1 // Labels
+ l++ // Algorithm
+ l++ // Labels
l += 4 // OrigTtl
l += 4 // Expiration
l += 4 // Inception
l += len(rr.Host) + 1
return l
}
+func (rr *SMIMEA) len() int {
+ l := rr.Hdr.len()
+ l++ // Usage
+ l++ // Selector
+ l++ // MatchingType
+ l += len(rr.Certificate)/2 + 1
+ return l
+}
func (rr *SOA) len() int {
l := rr.Hdr.len()
l += len(rr.Ns) + 1
}
func (rr *SSHFP) len() int {
l := rr.Hdr.len()
- l += 1 // Algorithm
- l += 1 // Type
+ l++ // Algorithm
+ l++ // Type
l += len(rr.FingerPrint)/2 + 1
return l
}
func (rr *TA) len() int {
l := rr.Hdr.len()
l += 2 // KeyTag
- l += 1 // Algorithm
- l += 1 // DigestType
+ l++ // Algorithm
+ l++ // DigestType
l += len(rr.Digest)/2 + 1
return l
}
}
func (rr *TLSA) len() int {
l := rr.Hdr.len()
- l += 1 // Usage
- l += 1 // Selector
- l += 1 // MatchingType
+ l++ // Usage
+ l++ // Selector
+ l++ // MatchingType
l += len(rr.Certificate)/2 + 1
return l
}
func (rr *ANY) copy() RR {
return &ANY{*rr.Hdr.copyHeader()}
}
+func (rr *AVC) copy() RR {
+ Txt := make([]string, len(rr.Txt))
+ copy(Txt, rr.Txt)
+ return &AVC{*rr.Hdr.copyHeader(), Txt}
+}
func (rr *CAA) copy() RR {
return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value}
}
func (rr *RT) copy() RR {
return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host}
}
+func (rr *SMIMEA) copy() RR {
+ return &SMIMEA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
+}
func (rr *SOA) copy() RR {
return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
+// Format formats the stack of Frames according to the fmt.Formatter interface.
+//
+// %s lists source files for each Frame in the stack
+// %v lists the source file and line number for each Frame in the stack
+//
+// Format accepts flags that alter the printing of some verbs, as follows:
+//
+// %+v Prints filename, function, and line number for each Frame in the stack.
func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
// if you want to count the same thing partitioned by various dimensions
// (e.g. number of HTTP requests, partitioned by response code and
// method). Create instances with NewCounterVec.
-//
-// CounterVec embeds MetricVec. See there for a full list of methods with
-// detailed documentation.
type CounterVec struct {
- *MetricVec
+ *metricVec
}
// NewCounterVec creates a new CounterVec based on the provided CounterOpts and
-// partitioned by the given label names. At least one label name must be
-// provided.
+// partitioned by the given label names.
func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
desc := NewDesc(
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.ConstLabels,
)
return &CounterVec{
- MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
+ metricVec: newMetricVec(desc, func(lvs ...string) Metric {
result := &counter{value: value{
desc: desc,
valType: CounterValue,
}
}
-// GetMetricWithLabelValues replaces the method of the same name in
-// MetricVec. The difference is that this method returns a Counter and not a
-// Metric so that no type conversion is required.
+// GetMetricWithLabelValues returns the Counter for the given slice of label
+// values (same order as the VariableLabels in Desc). If that combination of
+// label values is accessed for the first time, a new Counter is created.
+//
+// It is possible to call this method without using the returned Counter to only
+// create the new Counter but leave it at its starting value 0. See also the
+// SummaryVec example.
+//
+// Keeping the Counter for later use is possible (and should be considered if
+// performance is critical), but keep in mind that Reset, DeleteLabelValues and
+// Delete can be used to delete the Counter from the CounterVec. In that case,
+// the Counter will still exist, but it will not be exported anymore, even if a
+// Counter with the same label values is created later.
+//
+// An error is returned if the number of label values is not the same as the
+// number of VariableLabels in Desc.
+//
+// Note that for more than one label value, this method is prone to mistakes
+// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
+// an alternative to avoid that type of mistake. For higher label numbers, the
+// latter has a much more readable (albeit more verbose) syntax, but it comes
+// with a performance overhead (for creating and processing the Labels map).
+// See also the GaugeVec example.
func (m *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
- metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
+ metric, err := m.metricVec.getMetricWithLabelValues(lvs...)
if metric != nil {
return metric.(Counter), err
}
return nil, err
}
-// GetMetricWith replaces the method of the same name in MetricVec. The
-// difference is that this method returns a Counter and not a Metric so that no
-// type conversion is required.
+// GetMetricWith returns the Counter for the given Labels map (the label names
+// must match those of the VariableLabels in Desc). If that label map is
+// accessed for the first time, a new Counter is created. Implications of
+// creating a Counter without using it and keeping the Counter for later use are
+// the same as for GetMetricWithLabelValues.
+//
+// An error is returned if the number and names of the Labels are inconsistent
+// with those of the VariableLabels in Desc.
+//
+// This method is used for the same purpose as
+// GetMetricWithLabelValues(...string). See there for pros and cons of the two
+// methods.
func (m *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
- metric, err := m.MetricVec.GetMetricWith(labels)
+ metric, err := m.metricVec.getMetricWith(labels)
if metric != nil {
return metric.(Counter), err
}
// error, WithLabelValues allows shortcuts like
// myVec.WithLabelValues("404", "GET").Add(42)
func (m *CounterVec) WithLabelValues(lvs ...string) Counter {
- return m.MetricVec.WithLabelValues(lvs...).(Counter)
+ return m.metricVec.withLabelValues(lvs...).(Counter)
}
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
// returned an error. By not returning an error, With allows shortcuts like
// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42)
func (m *CounterVec) With(labels Labels) Counter {
- return m.MetricVec.With(labels).(Counter)
+ return m.metricVec.with(labels).(Counter)
}
// CounterFunc is a Counter whose value is determined at collect time by calling a
dto "github.com/prometheus/client_model/go"
)
-// reservedLabelPrefix is a prefix which is not legal in user-supplied
-// label names.
-const reservedLabelPrefix = "__"
-
-// Labels represents a collection of label name -> value mappings. This type is
-// commonly used with the With(Labels) and GetMetricWith(Labels) methods of
-// metric vector Collectors, e.g.:
-// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42)
-//
-// The other use-case is the specification of constant label pairs in Opts or to
-// create a Desc.
-type Labels map[string]string
-
// Desc is the descriptor used by every Prometheus Metric. It is essentially
// the immutable meta-data of a Metric. The normal Metric implementations
// included in this package manage their Desc under the hood. Users only have to
for _, labelName := range labelNames {
labelValues = append(labelValues, constLabels[labelName])
}
+ // Validate the const label values. They can't have a wrong cardinality, so
+ // use in len(labelValues) as expectedNumberOfValues.
+ if err := validateLabelValues(labelValues, len(labelValues)); err != nil {
+ d.err = err
+ return d
+ }
// Now add the variable label names, but prefix them with something that
// cannot be in a regular label name. That prevents matching the label
// dimension with a different mix between preset and variable labels.
d.err = errors.New("duplicate label names")
return d
}
+
vh := hashNew()
for _, val := range labelValues {
vh = hashAdd(vh, val)
d.variableLabels,
)
}
-
-func checkLabelName(l string) bool {
- return model.LabelName(l).IsValid() &&
- !strings.HasPrefix(l, reservedLabelPrefix)
-}
// package main
//
// import (
+// "log"
// "net/http"
//
// "github.com/prometheus/client_golang/prometheus"
// // The Handler function provides a default handler to expose metrics
// // via an HTTP server. "/metrics" is the usual endpoint for that.
// http.Handle("/metrics", promhttp.Handler())
-// log.Fatal(http.ListenAndServe(":8080", nil))
+// log.Fatal(http.ListenAndServe(":8080", nil))
// }
//
//
// registry.
//
// So far, everything we did operated on the so-called default registry, as it
-// can be found in the global DefaultRegistry variable. With NewRegistry, you
+// can be found in the global DefaultRegisterer variable. With NewRegistry, you
// can create a custom registry, or you can even implement the Registerer or
// Gatherer interfaces yourself. The methods Register and Unregister work in the
// same way on a custom registry as the global functions Register and Unregister
//
// There are a number of uses for custom registries: You can use registries with
// special properties, see NewPedanticRegistry. You can avoid global state, as
-// it is imposed by the DefaultRegistry. You can use multiple registries at the
-// same time to expose different metrics in different ways. You can use separate
-// registries for testing purposes.
+// it is imposed by the DefaultRegisterer. You can use multiple registries at
+// the same time to expose different metrics in different ways. You can use
+// separate registries for testing purposes.
//
-// Also note that the DefaultRegistry comes registered with a Collector for Go
+// Also note that the DefaultRegisterer comes registered with a Collector for Go
// runtime metrics (via NewGoCollector) and a Collector for process metrics (via
// NewProcessCollector). With a custom registry, you are in control and decide
// yourself about the Collectors to register.
// (e.g. number of operations queued, partitioned by user and operation
// type). Create instances with NewGaugeVec.
type GaugeVec struct {
- *MetricVec
+ *metricVec
}
// NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
-// partitioned by the given label names. At least one label name must be
-// provided.
+// partitioned by the given label names.
func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
desc := NewDesc(
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.ConstLabels,
)
return &GaugeVec{
- MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
+ metricVec: newMetricVec(desc, func(lvs ...string) Metric {
return newValue(desc, GaugeValue, 0, lvs...)
}),
}
}
-// GetMetricWithLabelValues replaces the method of the same name in
-// MetricVec. The difference is that this method returns a Gauge and not a
-// Metric so that no type conversion is required.
+// GetMetricWithLabelValues returns the Gauge for the given slice of label
+// values (same order as the VariableLabels in Desc). If that combination of
+// label values is accessed for the first time, a new Gauge is created.
+//
+// It is possible to call this method without using the returned Gauge to only
+// create the new Gauge but leave it at its starting value 0. See also the
+// SummaryVec example.
+//
+// Keeping the Gauge for later use is possible (and should be considered if
+// performance is critical), but keep in mind that Reset, DeleteLabelValues and
+// Delete can be used to delete the Gauge from the GaugeVec. In that case, the
+// Gauge will still exist, but it will not be exported anymore, even if a
+// Gauge with the same label values is created later. See also the CounterVec
+// example.
+//
+// An error is returned if the number of label values is not the same as the
+// number of VariableLabels in Desc.
+//
+// Note that for more than one label value, this method is prone to mistakes
+// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
+// an alternative to avoid that type of mistake. For higher label numbers, the
+// latter has a much more readable (albeit more verbose) syntax, but it comes
+// with a performance overhead (for creating and processing the Labels map).
func (m *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) {
- metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
+ metric, err := m.metricVec.getMetricWithLabelValues(lvs...)
if metric != nil {
return metric.(Gauge), err
}
return nil, err
}
-// GetMetricWith replaces the method of the same name in MetricVec. The
-// difference is that this method returns a Gauge and not a Metric so that no
-// type conversion is required.
+// GetMetricWith returns the Gauge for the given Labels map (the label names
+// must match those of the VariableLabels in Desc). If that label map is
+// accessed for the first time, a new Gauge is created. Implications of
+// creating a Gauge without using it and keeping the Gauge for later use are
+// the same as for GetMetricWithLabelValues.
+//
+// An error is returned if the number and names of the Labels are inconsistent
+// with those of the VariableLabels in Desc.
+//
+// This method is used for the same purpose as
+// GetMetricWithLabelValues(...string). See there for pros and cons of the two
+// methods.
func (m *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) {
- metric, err := m.MetricVec.GetMetricWith(labels)
+ metric, err := m.metricVec.getMetricWith(labels)
if metric != nil {
return metric.(Gauge), err
}
// error, WithLabelValues allows shortcuts like
// myVec.WithLabelValues("404", "GET").Add(42)
func (m *GaugeVec) WithLabelValues(lvs ...string) Gauge {
- return m.MetricVec.WithLabelValues(lvs...).(Gauge)
+ return m.metricVec.withLabelValues(lvs...).(Gauge)
}
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
// returned an error. By not returning an error, With allows shortcuts like
// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42)
func (m *GaugeVec) With(labels Labels) Gauge {
- return m.MetricVec.With(labels).(Gauge)
+ return m.metricVec.with(labels).(Gauge)
}
// GaugeFunc is a Gauge whose value is determined at collect time by calling a
goroutinesDesc *Desc
threadsDesc *Desc
gcDesc *Desc
+ goInfoDesc *Desc
// metrics to describe and collect
metrics memStatsMetrics
nil, nil),
threadsDesc: NewDesc(
"go_threads",
- "Number of OS threads created",
+ "Number of OS threads created.",
nil, nil),
gcDesc: NewDesc(
"go_gc_duration_seconds",
"A summary of the GC invocation durations.",
nil, nil),
+ goInfoDesc: NewDesc(
+ "go_info",
+ "Information about the Go environment.",
+ nil, Labels{"version": runtime.Version()}),
metrics: memStatsMetrics{
{
desc: NewDesc(
ch <- c.goroutinesDesc
ch <- c.threadsDesc
ch <- c.gcDesc
+ ch <- c.goInfoDesc
for _, i := range c.metrics {
ch <- i.desc
}
quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles)
+ ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1)
+
ms := &runtime.MemStats{}
runtime.ReadMemStats(ms)
for _, i := range c.metrics {
// (e.g. HTTP request latencies, partitioned by status code and method). Create
// instances with NewHistogramVec.
type HistogramVec struct {
- *MetricVec
+ *metricVec
}
// NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and
-// partitioned by the given label names. At least one label name must be
-// provided.
+// partitioned by the given label names.
func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
desc := NewDesc(
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.ConstLabels,
)
return &HistogramVec{
- MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
+ metricVec: newMetricVec(desc, func(lvs ...string) Metric {
return newHistogram(desc, opts, lvs...)
}),
}
}
-// GetMetricWithLabelValues replaces the method of the same name in
-// MetricVec. The difference is that this method returns an Observer and not a
-// Metric so that no type conversion to an Observer is required.
+// GetMetricWithLabelValues returns the Histogram for the given slice of label
+// values (same order as the VariableLabels in Desc). If that combination of
+// label values is accessed for the first time, a new Histogram is created.
+//
+// It is possible to call this method without using the returned Histogram to only
+// create the new Histogram but leave it at its starting value, a Histogram without
+// any observations.
+//
+// Keeping the Histogram for later use is possible (and should be considered if
+// performance is critical), but keep in mind that Reset, DeleteLabelValues and
+// Delete can be used to delete the Histogram from the HistogramVec. In that case, the
+// Histogram will still exist, but it will not be exported anymore, even if a
+// Histogram with the same label values is created later. See also the CounterVec
+// example.
+//
+// An error is returned if the number of label values is not the same as the
+// number of VariableLabels in Desc.
+//
+// Note that for more than one label value, this method is prone to mistakes
+// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
+// an alternative to avoid that type of mistake. For higher label numbers, the
+// latter has a much more readable (albeit more verbose) syntax, but it comes
+// with a performance overhead (for creating and processing the Labels map).
+// See also the GaugeVec example.
func (m *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
- metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
+ metric, err := m.metricVec.getMetricWithLabelValues(lvs...)
if metric != nil {
return metric.(Observer), err
}
return nil, err
}
-// GetMetricWith replaces the method of the same name in MetricVec. The
-// difference is that this method returns an Observer and not a Metric so that no
-// type conversion to an Observer is required.
+// GetMetricWith returns the Histogram for the given Labels map (the label names
+// must match those of the VariableLabels in Desc). If that label map is
+// accessed for the first time, a new Histogram is created. Implications of
+// creating a Histogram without using it and keeping the Histogram for later use
+// are the same as for GetMetricWithLabelValues.
+//
+// An error is returned if the number and names of the Labels are inconsistent
+// with those of the VariableLabels in Desc.
+//
+// This method is used for the same purpose as
+// GetMetricWithLabelValues(...string). See there for pros and cons of the two
+// methods.
func (m *HistogramVec) GetMetricWith(labels Labels) (Observer, error) {
- metric, err := m.MetricVec.GetMetricWith(labels)
+ metric, err := m.metricVec.getMetricWith(labels)
if metric != nil {
return metric.(Observer), err
}
// error, WithLabelValues allows shortcuts like
// myVec.WithLabelValues("404", "GET").Observe(42.21)
func (m *HistogramVec) WithLabelValues(lvs ...string) Observer {
- return m.MetricVec.WithLabelValues(lvs...).(Observer)
+ return m.metricVec.withLabelValues(lvs...).(Observer)
}
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
// returned an error. By not returning an error, With allows shortcuts like
// myVec.With(Labels{"code": "404", "method": "GET"}).Observe(42.21)
func (m *HistogramVec) With(labels Labels) Observer {
- return m.MetricVec.With(labels).(Observer)
+ return m.metricVec.with(labels).(Observer)
}
type constHistogram struct {
buckets map[float64]uint64,
labelValues ...string,
) (Metric, error) {
- if len(desc.variableLabels) != len(labelValues) {
- return nil, errInconsistentCardinality
+ if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
+ return nil, err
}
return &constHistogram{
desc: desc,
//
// Deprecated: Please note the issues described in the doc comment of
// InstrumentHandler. You might want to consider using promhttp.Handler instead
-// (which is not instrumented).
+// (which is not instrumented, but can be instrumented with the tooling provided
+// in package promhttp).
func Handler() http.Handler {
return InstrumentHandler("prometheus", UninstrumentedHandler())
}
closer.Close()
}
if lastErr != nil && buf.Len() == 0 {
- http.Error(w, "No metrics encoded, last error:\n\n"+err.Error(), http.StatusInternalServerError)
+ http.Error(w, "No metrics encoded, last error:\n\n"+lastErr.Error(), http.StatusInternalServerError)
return
}
header := w.Header()
// value. http_requests_total is a metric vector partitioned by HTTP method
// (label name "method") and HTTP status code (label name "code").
//
-// Deprecated: InstrumentHandler has several issues:
+// Deprecated: InstrumentHandler has several issues. Use the tooling provided in
+// package promhttp instead. The issues are the following:
//
// - It uses Summaries rather than Histograms. Summaries are not useful if
// aggregation across multiple instances is required.
//
// - It has additional issues with HTTP/2, cf.
// https://github.com/prometheus/client_golang/issues/272.
-//
-// Upcoming versions of this package will provide ways of instrumenting HTTP
-// handlers that are more flexible and have fewer issues. Please prefer direct
-// instrumentation in the meantime.
func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFunc {
return InstrumentHandlerFunc(handlerName, handler.ServeHTTP)
}
// issues).
//
// Deprecated: InstrumentHandlerFunc is deprecated for the same reasons as
-// InstrumentHandler is.
+// InstrumentHandler is. Use the tooling provided in package promhttp instead.
func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
return InstrumentHandlerFuncWithOpts(
SummaryOpts{
// SummaryOpts.
//
// Deprecated: InstrumentHandlerWithOpts is deprecated for the same reasons as
-// InstrumentHandler is.
+// InstrumentHandler is. Use the tooling provided in package promhttp instead.
func InstrumentHandlerWithOpts(opts SummaryOpts, handler http.Handler) http.HandlerFunc {
return InstrumentHandlerFuncWithOpts(opts, handler.ServeHTTP)
}
// SummaryOpts are used.
//
// Deprecated: InstrumentHandlerFuncWithOpts is deprecated for the same reasons
-// as InstrumentHandler is.
+// as InstrumentHandler is. Use the tooling provided in package promhttp instead.
func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
reqCnt := NewCounterVec(
CounterOpts{
+++ /dev/null
-// Copyright 2017 The Prometheus Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !go1.8
-
-package promhttp
-
-import (
- "io"
- "net/http"
-)
-
-func newDelegator(w http.ResponseWriter) delegator {
- d := &responseWriterDelegator{ResponseWriter: w}
-
- _, cn := w.(http.CloseNotifier)
- _, fl := w.(http.Flusher)
- _, hj := w.(http.Hijacker)
- _, rf := w.(io.ReaderFrom)
- if cn && fl && hj && rf {
- return &fancyDelegator{d}
- }
-
- return d
-}
"net/http"
)
-// newDelegator handles the four different methods of upgrading a
-// http.ResponseWriter to delegator.
-func newDelegator(w http.ResponseWriter) delegator {
- d := &responseWriterDelegator{ResponseWriter: w}
+type pusherDelegator struct{ *responseWriterDelegator }
- _, cn := w.(http.CloseNotifier)
- _, fl := w.(http.Flusher)
- _, hj := w.(http.Hijacker)
- _, ps := w.(http.Pusher)
- _, rf := w.(io.ReaderFrom)
-
- // Check for the four most common combination of interfaces a
- // http.ResponseWriter might implement.
- switch {
- case cn && fl && hj && rf && ps:
- // All interfaces.
- return &fancyPushDelegator{
- fancyDelegator: &fancyDelegator{d},
- p: &pushDelegator{d},
- }
- case cn && fl && hj && rf:
- // All interfaces, except http.Pusher.
- return &fancyDelegator{d}
- case ps:
- // Just http.Pusher.
- return &pushDelegator{d}
- }
-
- return d
+func (d *pusherDelegator) Push(target string, opts *http.PushOptions) error {
+ return d.ResponseWriter.(http.Pusher).Push(target, opts)
}
-type fancyPushDelegator struct {
- p *pushDelegator
-
- *fancyDelegator
+func init() {
+ pickDelegator[pusher] = func(d *responseWriterDelegator) delegator { // 16
+ return pusherDelegator{d}
+ }
+ pickDelegator[pusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 17
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.CloseNotifier
+ }{d, &pusherDelegator{d}, &closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+flusher] = func(d *responseWriterDelegator) delegator { // 18
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Flusher
+ }{d, &pusherDelegator{d}, &flusherDelegator{d}}
+ }
+ pickDelegator[pusher+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 19
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Flusher
+ http.CloseNotifier
+ }{d, &pusherDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+hijacker] = func(d *responseWriterDelegator) delegator { // 20
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Hijacker
+ }{d, &pusherDelegator{d}, &hijackerDelegator{d}}
+ }
+ pickDelegator[pusher+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 21
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Hijacker
+ http.CloseNotifier
+ }{d, &pusherDelegator{d}, &hijackerDelegator{d}, &closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 22
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Hijacker
+ http.Flusher
+ }{d, &pusherDelegator{d}, &hijackerDelegator{d}, &flusherDelegator{d}}
+ }
+ pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Hijacker
+ http.Flusher
+ http.CloseNotifier
+ }{d, &pusherDelegator{d}, &hijackerDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom] = func(d *responseWriterDelegator) delegator { // 24
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ }{d, &pusherDelegator{d}, &readerFromDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 25
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.CloseNotifier
+ }{d, &pusherDelegator{d}, &readerFromDelegator{d}, &closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 26
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Flusher
+ }{d, &pusherDelegator{d}, &readerFromDelegator{d}, &flusherDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 27
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Flusher
+ http.CloseNotifier
+ }{d, &pusherDelegator{d}, &readerFromDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 28
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Hijacker
+ }{d, &pusherDelegator{d}, &readerFromDelegator{d}, &hijackerDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 29
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Hijacker
+ http.CloseNotifier
+ }{d, &pusherDelegator{d}, &readerFromDelegator{d}, &hijackerDelegator{d}, &closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 30
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Hijacker
+ http.Flusher
+ }{d, &pusherDelegator{d}, &readerFromDelegator{d}, &hijackerDelegator{d}, &flusherDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 31
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Hijacker
+ http.Flusher
+ http.CloseNotifier
+ }{d, &pusherDelegator{d}, &readerFromDelegator{d}, &hijackerDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}}
+ }
}
-func (f *fancyPushDelegator) Push(target string, opts *http.PushOptions) error {
- return f.p.Push(target, opts)
-}
+func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator {
+ d := &responseWriterDelegator{
+ ResponseWriter: w,
+ observeWriteHeader: observeWriteHeaderFunc,
+ }
-type pushDelegator struct {
- *responseWriterDelegator
-}
+ id := 0
+ if _, ok := w.(http.CloseNotifier); ok {
+ id += closeNotifier
+ }
+ if _, ok := w.(http.Flusher); ok {
+ id += flusher
+ }
+ if _, ok := w.(http.Hijacker); ok {
+ id += hijacker
+ }
+ if _, ok := w.(io.ReaderFrom); ok {
+ id += readerFrom
+ }
+ if _, ok := w.(http.Pusher); ok {
+ id += pusher
+ }
-func (f *pushDelegator) Push(target string, opts *http.PushOptions) error {
- return f.ResponseWriter.(http.Pusher).Push(target, opts)
+ return pickDelegator[id](d)
}
// via middleware. Middleware wrappers follow the naming scheme
// InstrumentHandlerX, where X describes the intended use of the middleware.
// See each function's doc comment for specific details.
+//
+// Finally, the package allows for an http.RoundTripper to be instrumented via
+// middleware. Middleware wrappers follow the naming scheme
+// InstrumentRoundTripperX, where X describes the intended use of the
+// middleware. See each function's doc comment for specific details.
package promhttp
import (
closer.Close()
}
if lastErr != nil && buf.Len() == 0 {
- http.Error(w, "No metrics encoded, last error:\n\n"+err.Error(), http.StatusInternalServerError)
+ http.Error(w, "No metrics encoded, last error:\n\n"+lastErr.Error(), http.StatusInternalServerError)
return
}
header := w.Header()
package promhttp
import (
- "bufio"
- "io"
- "net"
"net/http"
"strconv"
"strings"
"github.com/prometheus/client_golang/prometheus"
)
+// magicString is used for the hacky label test in checkLabels. Remove once fixed.
+const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa"
+
// InstrumentHandlerInFlight is a middleware that wraps the provided
// http.Handler. It sets the provided prometheus.Gauge to the number of
// requests currently handled by the wrapped http.Handler.
// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
//
// If the wrapped Handler panics, no values are reported.
+//
+// Note that this method is only guaranteed to never observe negative durations
+// if used with Go1.9+.
func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
code, method := checkLabels(obs)
if code {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
now := time.Now()
- d := newDelegator(w)
+ d := newDelegator(w, nil)
next.ServeHTTP(d, r)
obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds())
// names are "code" and "method". The function panics if any other instance
// labels are provided. Partitioning of the CounterVec happens by HTTP status
// code and/or HTTP method if the respective instance label names are present
-// in the CounterVec. For unpartitioned observations, use a CounterVec with
+// in the CounterVec. For unpartitioned counting, use a CounterVec with
// zero labels.
//
// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
if code {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- d := newDelegator(w)
+ d := newDelegator(w, nil)
next.ServeHTTP(d, r)
counter.With(labels(code, method, r.Method, d.Status())).Inc()
})
})
}
+// InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided
+// http.Handler to observe with the provided ObserverVec the request duration
+// until the response headers are written. The ObserverVec must have zero, one,
+// or two labels. The only allowed label names are "code" and "method". The
+// function panics if any other instance labels are provided. The Observe
+// method of the Observer in the ObserverVec is called with the request
+// duration in seconds. Partitioning happens by HTTP status code and/or HTTP
+// method if the respective instance label names are present in the
+// ObserverVec. For unpartitioned observations, use an ObserverVec with zero
+// labels. Note that partitioning of Histograms is expensive and should be used
+// judiciously.
+//
+// If the wrapped Handler panics before calling WriteHeader, no value is
+// reported.
+//
+// Note that this method is only guaranteed to never observe negative durations
+// if used with Go1.9+.
+//
+// See the example for InstrumentHandlerDuration for example usage.
+func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
+ code, method := checkLabels(obs)
+
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ now := time.Now()
+ d := newDelegator(w, func(status int) {
+ obs.With(labels(code, method, r.Method, status)).Observe(time.Since(now).Seconds())
+ })
+ next.ServeHTTP(d, r)
+ })
+}
+
// InstrumentHandlerRequestSize is a middleware that wraps the provided
// http.Handler to observe the request size with the provided ObserverVec.
// The ObserverVec must have zero, one, or two labels. The only allowed label
if code {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- d := newDelegator(w)
+ d := newDelegator(w, nil)
next.ServeHTTP(d, r)
size := computeApproximateRequestSize(r)
obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size))
func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler {
code, method := checkLabels(obs)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- d := newDelegator(w)
+ d := newDelegator(w, nil)
next.ServeHTTP(d, r)
obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written()))
})
if _, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0); err == nil {
return
- } else if m, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, ""); err == nil {
+ }
+ if m, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, magicString); err == nil {
if err := m.Write(&pm); err != nil {
panic("error checking metric for labels")
}
-
- name := *pm.Label[0].Name
- if name == "code" {
- code = true
- } else if name == "method" {
- method = true
- } else {
- panic("metric partitioned with non-supported labels")
+ for _, label := range pm.Label {
+ name, value := label.GetName(), label.GetValue()
+ if value != magicString {
+ continue
+ }
+ switch name {
+ case "code":
+ code = true
+ case "method":
+ method = true
+ default:
+ panic("metric partitioned with non-supported labels")
+ }
+ return
}
- return
- } else if m, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, "", ""); err == nil {
+ panic("previously set label not found – this must never happen")
+ }
+ if m, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, magicString, magicString); err == nil {
if err := m.Write(&pm); err != nil {
panic("error checking metric for labels")
}
-
for _, label := range pm.Label {
- if *label.Name == "code" || *label.Name == "method" {
+ name, value := label.GetName(), label.GetValue()
+ if value != magicString {
+ continue
+ }
+ if name == "code" || name == "method" {
continue
}
panic("metric partitioned with non-supported labels")
}
-
code = true
method = true
return
}
-
panic("metric partitioned with non-supported labels")
}
return strconv.Itoa(s)
}
}
-
-type delegator interface {
- Status() int
- Written() int64
-
- http.ResponseWriter
-}
-
-type responseWriterDelegator struct {
- http.ResponseWriter
-
- handler, method string
- status int
- written int64
- wroteHeader bool
-}
-
-func (r *responseWriterDelegator) Status() int {
- return r.status
-}
-
-func (r *responseWriterDelegator) Written() int64 {
- return r.written
-}
-
-func (r *responseWriterDelegator) WriteHeader(code int) {
- r.status = code
- r.wroteHeader = true
- r.ResponseWriter.WriteHeader(code)
-}
-
-func (r *responseWriterDelegator) Write(b []byte) (int, error) {
- if !r.wroteHeader {
- r.WriteHeader(http.StatusOK)
- }
- n, err := r.ResponseWriter.Write(b)
- r.written += int64(n)
- return n, err
-}
-
-type fancyDelegator struct {
- *responseWriterDelegator
-}
-
-func (r *fancyDelegator) CloseNotify() <-chan bool {
- return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
-}
-
-func (r *fancyDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
- return r.ResponseWriter.(http.Hijacker).Hijack()
-}
-
-func (r *fancyDelegator) Flush() {
- r.ResponseWriter.(http.Flusher).Flush()
-}
-
-func (r *fancyDelegator) ReadFrom(re io.Reader) (int64, error) {
- if !r.wroteHeader {
- r.WriteHeader(http.StatusOK)
- }
- n, err := r.ResponseWriter.(io.ReaderFrom).ReadFrom(re)
- r.written += n
- return n, err
-}
"os"
"sort"
"sync"
+ "unicode/utf8"
"github.com/golang/protobuf/proto"
// Registerer is the interface for the part of a registry in charge of
// registering and unregistering. Users of custom registries should use
-// Registerer as type for registration purposes (rather then the Registry type
+// Registerer as type for registration purposes (rather than the Registry type
// directly). In that way, they are free to use custom Registerer implementation
// (e.g. for testing purposes).
type Registerer interface {
)
}
+ for _, labelPair := range dtoMetric.GetLabel() {
+ if !utf8.ValidString(*labelPair.Value) {
+ return fmt.Errorf("collected metric's label %s is not utf8: %#v", *labelPair.Name, *labelPair.Value)
+ }
+ }
+
// Is the metric unique (i.e. no other metric with the same name and the same label values)?
h := hashNew()
h = hashAdd(h, metricFamily.GetName())
//
// A typical use-case is the observation of request latencies. By default, a
// Summary provides the median, the 90th and the 99th percentile of the latency
-// as rank estimations.
+// as rank estimations. However, the default behavior will change in the
+// upcoming v0.10 of the library. There will be no rank estiamtions at all by
+// default. For a sane transition, it is recommended to set the desired rank
+// estimations explicitly.
//
// Note that the rank estimations cannot be aggregated in a meaningful way with
// the Prometheus query language (i.e. you cannot average or add them). If you
)
// SummaryOpts bundles the options for creating a Summary metric. It is
-// mandatory to set Name and Help to a non-empty string. All other fields are
-// optional and can safely be left at their zero value.
+// mandatory to set Name and Help to a non-empty string. While all other fields
+// are optional and can safely be left at their zero value, it is recommended to
+// explicitly set the Objectives field to the desired value as the default value
+// will change in the upcoming v0.10 of the library.
type SummaryOpts struct {
// Namespace, Subsystem, and Name are components of the fully-qualified
// name of the Summary (created by joining these components with
// (e.g. HTTP request latencies, partitioned by status code and method). Create
// instances with NewSummaryVec.
type SummaryVec struct {
- *MetricVec
+ *metricVec
}
// NewSummaryVec creates a new SummaryVec based on the provided SummaryOpts and
-// partitioned by the given label names. At least one label name must be
-// provided.
+// partitioned by the given label names.
func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
desc := NewDesc(
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.ConstLabels,
)
return &SummaryVec{
- MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
+ metricVec: newMetricVec(desc, func(lvs ...string) Metric {
return newSummary(desc, opts, lvs...)
}),
}
}
-// GetMetricWithLabelValues replaces the method of the same name in MetricVec.
-// The difference is that this method returns an Observer and not a Metric so
-// that no type conversion to an Observer is required.
+// GetMetricWithLabelValues returns the Summary for the given slice of label
+// values (same order as the VariableLabels in Desc). If that combination of
+// label values is accessed for the first time, a new Summary is created.
+//
+// It is possible to call this method without using the returned Summary to only
+// create the new Summary but leave it at its starting value, a Summary without
+// any observations.
+//
+// Keeping the Summary for later use is possible (and should be considered if
+// performance is critical), but keep in mind that Reset, DeleteLabelValues and
+// Delete can be used to delete the Summary from the SummaryVec. In that case, the
+// Summary will still exist, but it will not be exported anymore, even if a
+// Summary with the same label values is created later. See also the CounterVec
+// example.
+//
+// An error is returned if the number of label values is not the same as the
+// number of VariableLabels in Desc.
+//
+// Note that for more than one label value, this method is prone to mistakes
+// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
+// an alternative to avoid that type of mistake. For higher label numbers, the
+// latter has a much more readable (albeit more verbose) syntax, but it comes
+// with a performance overhead (for creating and processing the Labels map).
+// See also the GaugeVec example.
func (m *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
- metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
+ metric, err := m.metricVec.getMetricWithLabelValues(lvs...)
if metric != nil {
return metric.(Observer), err
}
return nil, err
}
-// GetMetricWith replaces the method of the same name in MetricVec. The
-// difference is that this method returns an Observer and not a Metric so that
-// no type conversion to an Observer is required.
+// GetMetricWith returns the Summary for the given Labels map (the label names
+// must match those of the VariableLabels in Desc). If that label map is
+// accessed for the first time, a new Summary is created. Implications of
+// creating a Summary without using it and keeping the Summary for later use are
+// the same as for GetMetricWithLabelValues.
+//
+// An error is returned if the number and names of the Labels are inconsistent
+// with those of the VariableLabels in Desc.
+//
+// This method is used for the same purpose as
+// GetMetricWithLabelValues(...string). See there for pros and cons of the two
+// methods.
func (m *SummaryVec) GetMetricWith(labels Labels) (Observer, error) {
- metric, err := m.MetricVec.GetMetricWith(labels)
+ metric, err := m.metricVec.getMetricWith(labels)
if metric != nil {
return metric.(Observer), err
}
// error, WithLabelValues allows shortcuts like
// myVec.WithLabelValues("404", "GET").Observe(42.21)
func (m *SummaryVec) WithLabelValues(lvs ...string) Observer {
- return m.MetricVec.WithLabelValues(lvs...).(Observer)
+ return m.metricVec.withLabelValues(lvs...).(Observer)
}
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
// returned an error. By not returning an error, With allows shortcuts like
// myVec.With(Labels{"code": "404", "method": "GET"}).Observe(42.21)
func (m *SummaryVec) With(labels Labels) Observer {
- return m.MetricVec.With(labels).(Observer)
+ return m.metricVec.with(labels).(Observer)
}
type constSummary struct {
quantiles map[float64]float64,
labelValues ...string,
) (Metric, error) {
- if len(desc.variableLabels) != len(labelValues) {
- return nil, errInconsistentCardinality
+ if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
+ return nil, err
}
return &constSummary{
desc: desc,
// NewTimer. It calls the Observe method of the Observer provided during
// construction with the duration in seconds as an argument. ObserveDuration is
// usually called with a defer statement.
+//
+// Note that this method is only guaranteed to never observe negative durations
+// if used with Go1.9+.
func (t *Timer) ObserveDuration() {
if t.observer != nil {
t.observer.Observe(time.Since(t.begin).Seconds())
package prometheus
-// Untyped is a Metric that represents a single numerical value that can
-// arbitrarily go up and down.
-//
-// An Untyped metric works the same as a Gauge. The only difference is that to
-// no type information is implied.
-//
-// To create Untyped instances, use NewUntyped.
-//
-// Deprecated: The Untyped type is deprecated because it doesn't make sense in
-// direct instrumentation. If you need to mirror an external metric of unknown
-// type (usually while writing exporters), Use MustNewConstMetric to create an
-// untyped metric instance on the fly.
-type Untyped interface {
- Metric
- Collector
-
- // Set sets the Untyped metric to an arbitrary value.
- Set(float64)
- // Inc increments the Untyped metric by 1.
- Inc()
- // Dec decrements the Untyped metric by 1.
- Dec()
- // Add adds the given value to the Untyped metric. (The value can be
- // negative, resulting in a decrease.)
- Add(float64)
- // Sub subtracts the given value from the Untyped metric. (The value can
- // be negative, resulting in an increase.)
- Sub(float64)
-}
-
// UntypedOpts is an alias for Opts. See there for doc comments.
type UntypedOpts Opts
-// NewUntyped creates a new Untyped metric from the provided UntypedOpts.
-func NewUntyped(opts UntypedOpts) Untyped {
- return newValue(NewDesc(
- BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
- opts.Help,
- nil,
- opts.ConstLabels,
- ), UntypedValue, 0)
-}
-
-// UntypedVec is a Collector that bundles a set of Untyped metrics that all
-// share the same Desc, but have different values for their variable
-// labels. This is used if you want to count the same thing partitioned by
-// various dimensions. Create instances with NewUntypedVec.
-type UntypedVec struct {
- *MetricVec
-}
-
-// NewUntypedVec creates a new UntypedVec based on the provided UntypedOpts and
-// partitioned by the given label names. At least one label name must be
-// provided.
-func NewUntypedVec(opts UntypedOpts, labelNames []string) *UntypedVec {
- desc := NewDesc(
- BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
- opts.Help,
- labelNames,
- opts.ConstLabels,
- )
- return &UntypedVec{
- MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
- return newValue(desc, UntypedValue, 0, lvs...)
- }),
- }
-}
-
-// GetMetricWithLabelValues replaces the method of the same name in
-// MetricVec. The difference is that this method returns an Untyped and not a
-// Metric so that no type conversion is required.
-func (m *UntypedVec) GetMetricWithLabelValues(lvs ...string) (Untyped, error) {
- metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
- if metric != nil {
- return metric.(Untyped), err
- }
- return nil, err
-}
-
-// GetMetricWith replaces the method of the same name in MetricVec. The
-// difference is that this method returns an Untyped and not a Metric so that no
-// type conversion is required.
-func (m *UntypedVec) GetMetricWith(labels Labels) (Untyped, error) {
- metric, err := m.MetricVec.GetMetricWith(labels)
- if metric != nil {
- return metric.(Untyped), err
- }
- return nil, err
-}
-
-// WithLabelValues works as GetMetricWithLabelValues, but panics where
-// GetMetricWithLabelValues would have returned an error. By not returning an
-// error, WithLabelValues allows shortcuts like
-// myVec.WithLabelValues("404", "GET").Add(42)
-func (m *UntypedVec) WithLabelValues(lvs ...string) Untyped {
- return m.MetricVec.WithLabelValues(lvs...).(Untyped)
-}
-
-// With works as GetMetricWith, but panics where GetMetricWithLabels would have
-// returned an error. By not returning an error, With allows shortcuts like
-// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42)
-func (m *UntypedVec) With(labels Labels) Untyped {
- return m.MetricVec.With(labels).(Untyped)
-}
-
-// UntypedFunc is an Untyped whose value is determined at collect time by
-// calling a provided function.
+// UntypedFunc works like GaugeFunc but the collected metric is of type
+// "Untyped". UntypedFunc is useful to mirror an external metric of unknown
+// type.
//
// To create UntypedFunc instances, use NewUntypedFunc.
type UntypedFunc interface {
package prometheus
import (
- "errors"
"fmt"
"math"
"sort"
UntypedValue
)
-var errInconsistentCardinality = errors.New("inconsistent label cardinality")
-
// value is a generic metric for simple values. It implements Metric, Collector,
// Counter, Gauge, and Untyped. Its effective type is determined by
// ValueType. This is a low-level building block used by the library to back the
// the Collect method. NewConstMetric returns an error if the length of
// labelValues is not consistent with the variable labels in Desc.
func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) {
- if len(desc.variableLabels) != len(labelValues) {
- return nil, errInconsistentCardinality
+ if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
+ return nil, err
}
return &constMetric{
desc: desc,
"github.com/prometheus/common/model"
)
-// MetricVec is a Collector to bundle metrics of the same name that
-// differ in their label values. MetricVec is usually not used directly but as a
-// building block for implementations of vectors of a given metric
-// type. GaugeVec, CounterVec, SummaryVec, and UntypedVec are examples already
-// provided in this package.
-type MetricVec struct {
+// metricVec is a Collector to bundle metrics of the same name that differ in
+// their label values. metricVec is not used directly (and therefore
+// unexported). It is used as a building block for implementations of vectors of
+// a given metric type, like GaugeVec, CounterVec, SummaryVec, HistogramVec, and
+// UntypedVec.
+type metricVec struct {
mtx sync.RWMutex // Protects the children.
children map[uint64][]metricWithLabelValues
desc *Desc
hashAddByte func(h uint64, b byte) uint64
}
-// newMetricVec returns an initialized MetricVec. The concrete value is
-// returned for embedding into another struct.
-func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *MetricVec {
- return &MetricVec{
+// newMetricVec returns an initialized metricVec.
+func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *metricVec {
+ return &metricVec{
children: map[uint64][]metricWithLabelValues{},
desc: desc,
newMetric: newMetric,
// Describe implements Collector. The length of the returned slice
// is always one.
-func (m *MetricVec) Describe(ch chan<- *Desc) {
+func (m *metricVec) Describe(ch chan<- *Desc) {
ch <- m.desc
}
// Collect implements Collector.
-func (m *MetricVec) Collect(ch chan<- Metric) {
+func (m *metricVec) Collect(ch chan<- Metric) {
m.mtx.RLock()
defer m.mtx.RUnlock()
}
}
-// GetMetricWithLabelValues returns the Metric for the given slice of label
-// values (same order as the VariableLabels in Desc). If that combination of
-// label values is accessed for the first time, a new Metric is created.
-//
-// It is possible to call this method without using the returned Metric to only
-// create the new Metric but leave it at its start value (e.g. a Summary or
-// Histogram without any observations). See also the SummaryVec example.
-//
-// Keeping the Metric for later use is possible (and should be considered if
-// performance is critical), but keep in mind that Reset, DeleteLabelValues and
-// Delete can be used to delete the Metric from the MetricVec. In that case, the
-// Metric will still exist, but it will not be exported anymore, even if a
-// Metric with the same label values is created later. See also the CounterVec
-// example.
-//
-// An error is returned if the number of label values is not the same as the
-// number of VariableLabels in Desc.
-//
-// Note that for more than one label value, this method is prone to mistakes
-// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
-// an alternative to avoid that type of mistake. For higher label numbers, the
-// latter has a much more readable (albeit more verbose) syntax, but it comes
-// with a performance overhead (for creating and processing the Labels map).
-// See also the GaugeVec example.
-func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
+func (m *metricVec) getMetricWithLabelValues(lvs ...string) (Metric, error) {
h, err := m.hashLabelValues(lvs)
if err != nil {
return nil, err
return m.getOrCreateMetricWithLabelValues(h, lvs), nil
}
-// GetMetricWith returns the Metric for the given Labels map (the label names
-// must match those of the VariableLabels in Desc). If that label map is
-// accessed for the first time, a new Metric is created. Implications of
-// creating a Metric without using it and keeping the Metric for later use are
-// the same as for GetMetricWithLabelValues.
-//
-// An error is returned if the number and names of the Labels are inconsistent
-// with those of the VariableLabels in Desc.
-//
-// This method is used for the same purpose as
-// GetMetricWithLabelValues(...string). See there for pros and cons of the two
-// methods.
-func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) {
+func (m *metricVec) getMetricWith(labels Labels) (Metric, error) {
h, err := m.hashLabels(labels)
if err != nil {
return nil, err
return m.getOrCreateMetricWithLabels(h, labels), nil
}
-// WithLabelValues works as GetMetricWithLabelValues, but panics if an error
-// occurs. The method allows neat syntax like:
-// httpReqs.WithLabelValues("404", "POST").Inc()
-func (m *MetricVec) WithLabelValues(lvs ...string) Metric {
- metric, err := m.GetMetricWithLabelValues(lvs...)
+func (m *metricVec) withLabelValues(lvs ...string) Metric {
+ metric, err := m.getMetricWithLabelValues(lvs...)
if err != nil {
panic(err)
}
return metric
}
-// With works as GetMetricWith, but panics if an error occurs. The method allows
-// neat syntax like:
-// httpReqs.With(Labels{"status":"404", "method":"POST"}).Inc()
-func (m *MetricVec) With(labels Labels) Metric {
- metric, err := m.GetMetricWith(labels)
+func (m *metricVec) with(labels Labels) Metric {
+ metric, err := m.getMetricWith(labels)
if err != nil {
panic(err)
}
// returns true if a metric was deleted.
//
// It is not an error if the number of label values is not the same as the
-// number of VariableLabels in Desc. However, such inconsistent label count can
-// never match an actual Metric, so the method will always return false in that
+// number of VariableLabels in Desc. However, such inconsistent label count can
+// never match an actual metric, so the method will always return false in that
// case.
//
// Note that for more than one label value, this method is prone to mistakes
// latter has a much more readable (albeit more verbose) syntax, but it comes
// with a performance overhead (for creating and processing the Labels map).
// See also the CounterVec example.
-func (m *MetricVec) DeleteLabelValues(lvs ...string) bool {
+func (m *metricVec) DeleteLabelValues(lvs ...string) bool {
m.mtx.Lock()
defer m.mtx.Unlock()
// passed in as labels. It returns true if a metric was deleted.
//
// It is not an error if the number and names of the Labels are inconsistent
-// with those of the VariableLabels in the Desc of the MetricVec. However, such
-// inconsistent Labels can never match an actual Metric, so the method will
-// always return false in that case.
+// with those of the VariableLabels in Desc. However, such inconsistent Labels
+// can never match an actual metric, so the method will always return false in
+// that case.
//
// This method is used for the same purpose as DeleteLabelValues(...string). See
// there for pros and cons of the two methods.
-func (m *MetricVec) Delete(labels Labels) bool {
+func (m *metricVec) Delete(labels Labels) bool {
m.mtx.Lock()
defer m.mtx.Unlock()
// deleteByHashWithLabelValues removes the metric from the hash bucket h. If
// there are multiple matches in the bucket, use lvs to select a metric and
// remove only that metric.
-func (m *MetricVec) deleteByHashWithLabelValues(h uint64, lvs []string) bool {
+func (m *metricVec) deleteByHashWithLabelValues(h uint64, lvs []string) bool {
metrics, ok := m.children[h]
if !ok {
return false
// deleteByHashWithLabels removes the metric from the hash bucket h. If there
// are multiple matches in the bucket, use lvs to select a metric and remove
// only that metric.
-func (m *MetricVec) deleteByHashWithLabels(h uint64, labels Labels) bool {
+func (m *metricVec) deleteByHashWithLabels(h uint64, labels Labels) bool {
metrics, ok := m.children[h]
if !ok {
return false
}
// Reset deletes all metrics in this vector.
-func (m *MetricVec) Reset() {
+func (m *metricVec) Reset() {
m.mtx.Lock()
defer m.mtx.Unlock()
}
}
-func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) {
- if len(vals) != len(m.desc.variableLabels) {
- return 0, errInconsistentCardinality
+func (m *metricVec) hashLabelValues(vals []string) (uint64, error) {
+ if err := validateLabelValues(vals, len(m.desc.variableLabels)); err != nil {
+ return 0, err
}
+
h := hashNew()
for _, val := range vals {
h = m.hashAdd(h, val)
return h, nil
}
-func (m *MetricVec) hashLabels(labels Labels) (uint64, error) {
- if len(labels) != len(m.desc.variableLabels) {
- return 0, errInconsistentCardinality
+func (m *metricVec) hashLabels(labels Labels) (uint64, error) {
+ if err := validateValuesInLabels(labels, len(m.desc.variableLabels)); err != nil {
+ return 0, err
}
+
h := hashNew()
for _, label := range m.desc.variableLabels {
val, ok := labels[label]
// or creates it and returns the new one.
//
// This function holds the mutex.
-func (m *MetricVec) getOrCreateMetricWithLabelValues(hash uint64, lvs []string) Metric {
+func (m *metricVec) getOrCreateMetricWithLabelValues(hash uint64, lvs []string) Metric {
m.mtx.RLock()
- metric, ok := m.getMetricWithLabelValues(hash, lvs)
+ metric, ok := m.getMetricWithHashAndLabelValues(hash, lvs)
m.mtx.RUnlock()
if ok {
return metric
m.mtx.Lock()
defer m.mtx.Unlock()
- metric, ok = m.getMetricWithLabelValues(hash, lvs)
+ metric, ok = m.getMetricWithHashAndLabelValues(hash, lvs)
if !ok {
// Copy to avoid allocation in case wo don't go down this code path.
copiedLVs := make([]string, len(lvs))
// or creates it and returns the new one.
//
// This function holds the mutex.
-func (m *MetricVec) getOrCreateMetricWithLabels(hash uint64, labels Labels) Metric {
+func (m *metricVec) getOrCreateMetricWithLabels(hash uint64, labels Labels) Metric {
m.mtx.RLock()
- metric, ok := m.getMetricWithLabels(hash, labels)
+ metric, ok := m.getMetricWithHashAndLabels(hash, labels)
m.mtx.RUnlock()
if ok {
return metric
m.mtx.Lock()
defer m.mtx.Unlock()
- metric, ok = m.getMetricWithLabels(hash, labels)
+ metric, ok = m.getMetricWithHashAndLabels(hash, labels)
if !ok {
lvs := m.extractLabelValues(labels)
metric = m.newMetric(lvs...)
return metric
}
-// getMetricWithLabelValues gets a metric while handling possible collisions in
-// the hash space. Must be called while holding read mutex.
-func (m *MetricVec) getMetricWithLabelValues(h uint64, lvs []string) (Metric, bool) {
+// getMetricWithHashAndLabelValues gets a metric while handling possible
+// collisions in the hash space. Must be called while holding the read mutex.
+func (m *metricVec) getMetricWithHashAndLabelValues(h uint64, lvs []string) (Metric, bool) {
metrics, ok := m.children[h]
if ok {
if i := m.findMetricWithLabelValues(metrics, lvs); i < len(metrics) {
return nil, false
}
-// getMetricWithLabels gets a metric while handling possible collisions in
+// getMetricWithHashAndLabels gets a metric while handling possible collisions in
// the hash space. Must be called while holding read mutex.
-func (m *MetricVec) getMetricWithLabels(h uint64, labels Labels) (Metric, bool) {
+func (m *metricVec) getMetricWithHashAndLabels(h uint64, labels Labels) (Metric, bool) {
metrics, ok := m.children[h]
if ok {
if i := m.findMetricWithLabels(metrics, labels); i < len(metrics) {
// findMetricWithLabelValues returns the index of the matching metric or
// len(metrics) if not found.
-func (m *MetricVec) findMetricWithLabelValues(metrics []metricWithLabelValues, lvs []string) int {
+func (m *metricVec) findMetricWithLabelValues(metrics []metricWithLabelValues, lvs []string) int {
for i, metric := range metrics {
if m.matchLabelValues(metric.values, lvs) {
return i
// findMetricWithLabels returns the index of the matching metric or len(metrics)
// if not found.
-func (m *MetricVec) findMetricWithLabels(metrics []metricWithLabelValues, labels Labels) int {
+func (m *metricVec) findMetricWithLabels(metrics []metricWithLabelValues, labels Labels) int {
for i, metric := range metrics {
if m.matchLabels(metric.values, labels) {
return i
return len(metrics)
}
-func (m *MetricVec) matchLabelValues(values []string, lvs []string) bool {
+func (m *metricVec) matchLabelValues(values []string, lvs []string) bool {
if len(values) != len(lvs) {
return false
}
return true
}
-func (m *MetricVec) matchLabels(values []string, labels Labels) bool {
+func (m *metricVec) matchLabels(values []string, labels Labels) bool {
if len(labels) != len(values) {
return false
}
return true
}
-func (m *MetricVec) extractLabelValues(labels Labels) []string {
+func (m *metricVec) extractLabelValues(labels Labels) []string {
labelValues := make([]string, len(labels))
for i, k := range m.desc.variableLabels {
labelValues[i] = labels[k]
// with a timestamp. The output always goes to stderr.
func New(al AllowedLevel) log.Logger {
l := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
+ l = level.NewFilter(l, al.o)
l = log.With(l, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
return l
}
+++ /dev/null
-The Prometheus project was started by Matt T. Proud (emeritus) and
-Julius Volz in 2012.
-
-Maintainers of this repository:
-
-* Tobias Schmidt <ts@soundcloud.com>
-
-The following individuals have contributed code to this repository
-(listed in alphabetical order):
-
-* Armen Baghumian <abaghumian@noggin.com.au>
-* Bjoern Rabenstein <beorn@soundcloud.com>
-* David Cournapeau <cournape@gmail.com>
-* Ji-Hoon, Seol <jihoon.seol@gmail.com>
-* Jonas Große Sundrup <cherti@letopolis.de>
-* Julius Volz <julius.volz@gmail.com>
-* Matthias Rampke <mr@soundcloud.com>
-* Nicky Gerritsen <nicky@streamone.nl>
-* Rémi Audebert <contact@halfr.net>
-* Tobias Schmidt <tobidt@gmail.com>
Prometheus uses GitHub to manage reviews of pull requests.
-* If you have a trivial fix or improvement, go ahead and create a pull
- request, addressing (with `@...`) one or more of the maintainers
- (see [AUTHORS.md](AUTHORS.md)) in the description of the pull request.
+* If you have a trivial fix or improvement, go ahead and create a pull request,
+ addressing (with `@...`) the maintainer of this repository (see
+ [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request.
* If you plan to do something more involved, first discuss your ideas
on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers).
-ci:
+ci: fmt lint test
+
+fmt:
! gofmt -l *.go | read nothing
go vet
- go test -v ./...
+
+lint:
go get github.com/golang/lint/golint
golint *.go
+
+test: sysfs/fixtures/.unpacked
+ go test -v ./...
+
+sysfs/fixtures/.unpacked: sysfs/fixtures.ttar
+ ./ttar -C sysfs -x -f sysfs/fixtures.ttar
+ touch $@
+
+.PHONY: fmt lint test ci
[![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs)
[![Build Status](https://travis-ci.org/prometheus/procfs.svg?branch=master)](https://travis-ci.org/prometheus/procfs)
+[![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/procfs)](https://goreportcard.com/report/github.com/prometheus/procfs)
"fmt"
"os"
"path"
+
+ "github.com/prometheus/procfs/xfs"
)
// FS represents the pseudo-filesystem proc, which provides an interface to
func (fs FS) Path(p ...string) string {
return path.Join(append([]string{string(fs)}, p...)...)
}
+
+// XFSStats retrieves XFS filesystem runtime statistics.
+func (fs FS) XFSStats() (*xfs.Stats, error) {
+ f, err := os.Open(fs.Path("fs/xfs/stat"))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return xfs.ParseStats(f)
+}
LocalAddress net.IP
// The local (virtual) port.
LocalPort uint16
+ // The local firewall mark
+ LocalMark string
// The transport protocol (TCP, UDP).
Proto string
// The remote (real) IP address.
status []IPVSBackendStatus
scanner = bufio.NewScanner(file)
proto string
+ localMark string
localAddress net.IP
localPort uint16
err error
continue
}
proto = fields[0]
+ localMark = ""
localAddress, localPort, err = parseIPPort(fields[1])
if err != nil {
return nil, err
}
+ case fields[0] == "FWM":
+ if len(fields) < 2 {
+ continue
+ }
+ proto = fields[0]
+ localMark = fields[1]
+ localAddress = nil
+ localPort = 0
case fields[0] == "->":
if len(fields) < 6 {
continue
status = append(status, IPVSBackendStatus{
LocalAddress: localAddress,
LocalPort: localPort,
+ LocalMark: localMark,
RemoteAddress: remoteAddress,
RemotePort: remotePort,
Proto: proto,
}
func parseIPPort(s string) (net.IP, uint16, error) {
- tmp := strings.SplitN(s, ":", 2)
-
- if len(tmp) != 2 {
- return nil, 0, fmt.Errorf("invalid IP:Port: %s", s)
- }
+ var (
+ ip net.IP
+ err error
+ )
- if len(tmp[0]) != 8 && len(tmp[0]) != 32 {
- return nil, 0, fmt.Errorf("invalid IP: %s", tmp[0])
+ switch len(s) {
+ case 13:
+ ip, err = hex.DecodeString(s[0:8])
+ if err != nil {
+ return nil, 0, err
+ }
+ case 46:
+ ip = net.ParseIP(s[1:40])
+ if ip == nil {
+ return nil, 0, fmt.Errorf("invalid IPv6 address: %s", s[1:40])
+ }
+ default:
+ return nil, 0, fmt.Errorf("unexpected IP:Port: %s", s)
}
- ip, err := hex.DecodeString(tmp[0])
- if err != nil {
- return nil, 0, err
+ portString := s[len(s)-4:]
+ if len(portString) != 4 {
+ return nil, 0, fmt.Errorf("unexpected port string format: %s", portString)
}
-
- port, err := strconv.ParseUint(tmp[1], 16, 16)
+ port, err := strconv.ParseUint(portString, 16, 16)
if err != nil {
return nil, 0, err
}
return fs.NewProc(pid)
}
-// AllProcs returns a list of all currently avaible processes under /proc.
+// AllProcs returns a list of all currently available processes under /proc.
func AllProcs() (Procs, error) {
fs, err := NewFS(DefaultMountPoint)
if err != nil {
return Proc{PID: pid, fs: fs}, nil
}
-// AllProcs returns a list of all currently avaible processes.
+// AllProcs returns a list of all currently available processes.
func (fs FS) AllProcs() (Procs, error) {
d, err := os.Open(fs.Path())
if err != nil {
return len(fds), nil
}
+// MountStats retrieves statistics and configuration for mount points in a
+// process's namespace.
+func (p Proc) MountStats() ([]*Mount, error) {
+ f, err := os.Open(p.path("mountstats"))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return parseMountStats(f)
+}
+
func (p Proc) fileDescriptors() ([]string, error) {
d, err := os.Open(p.path("fd"))
if err != nil {
case "Max cpu time":
l.CPUTime, err = parseInt(fields[1])
case "Max file size":
- l.FileLocks, err = parseInt(fields[1])
+ l.FileSize, err = parseInt(fields[1])
case "Max data size":
l.DataSize, err = parseInt(fields[1])
case "Max stack size":
import (
"bufio"
"fmt"
+ "io"
"os"
"strconv"
"strings"
)
+// CPUStat shows how much time the cpu spend in various stages.
+type CPUStat struct {
+ User float64
+ Nice float64
+ System float64
+ Idle float64
+ Iowait float64
+ IRQ float64
+ SoftIRQ float64
+ Steal float64
+ Guest float64
+ GuestNice float64
+}
+
+// SoftIRQStat represent the softirq statistics as exported in the procfs stat file.
+// A nice introduction can be found at https://0xax.gitbooks.io/linux-insides/content/interrupts/interrupts-9.html
+// It is possible to get per-cpu stats by reading /proc/softirqs
+type SoftIRQStat struct {
+ Hi uint64
+ Timer uint64
+ NetTx uint64
+ NetRx uint64
+ Block uint64
+ BlockIoPoll uint64
+ Tasklet uint64
+ Sched uint64
+ Hrtimer uint64
+ Rcu uint64
+}
+
// Stat represents kernel/system statistics.
type Stat struct {
// Boot time in seconds since the Epoch.
- BootTime int64
+ BootTime uint64
+ // Summed up cpu statistics.
+ CPUTotal CPUStat
+ // Per-CPU statistics.
+ CPU []CPUStat
+ // Number of times interrupts were handled, which contains numbered and unnumbered IRQs.
+ IRQTotal uint64
+ // Number of times a numbered IRQ was triggered.
+ IRQ []uint64
+ // Number of times a context switch happened.
+ ContextSwitches uint64
+ // Number of times a process was created.
+ ProcessCreated uint64
+ // Number of processes currently running.
+ ProcessesRunning uint64
+ // Number of processes currently blocked (waiting for IO).
+ ProcessesBlocked uint64
+ // Number of times a softirq was scheduled.
+ SoftIRQTotal uint64
+ // Detailed softirq statistics.
+ SoftIRQ SoftIRQStat
}
// NewStat returns kernel/system statistics read from /proc/stat.
return fs.NewStat()
}
+// Parse a cpu statistics line and returns the CPUStat struct plus the cpu id (or -1 for the overall sum).
+func parseCPUStat(line string) (CPUStat, int64, error) {
+ cpuStat := CPUStat{}
+ var cpu string
+
+ count, err := fmt.Sscanf(line, "%s %f %f %f %f %f %f %f %f %f %f",
+ &cpu,
+ &cpuStat.User, &cpuStat.Nice, &cpuStat.System, &cpuStat.Idle,
+ &cpuStat.Iowait, &cpuStat.IRQ, &cpuStat.SoftIRQ, &cpuStat.Steal,
+ &cpuStat.Guest, &cpuStat.GuestNice)
+
+ if err != nil && err != io.EOF {
+ return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): %s", line, err)
+ }
+ if count == 0 {
+ return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): 0 elements parsed", line)
+ }
+
+ cpuStat.User /= userHZ
+ cpuStat.Nice /= userHZ
+ cpuStat.System /= userHZ
+ cpuStat.Idle /= userHZ
+ cpuStat.Iowait /= userHZ
+ cpuStat.IRQ /= userHZ
+ cpuStat.SoftIRQ /= userHZ
+ cpuStat.Steal /= userHZ
+ cpuStat.Guest /= userHZ
+ cpuStat.GuestNice /= userHZ
+
+ if cpu == "cpu" {
+ return cpuStat, -1, nil
+ }
+
+ cpuID, err := strconv.ParseInt(cpu[3:], 10, 64)
+ if err != nil {
+ return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu/cpuid): %s", line, err)
+ }
+
+ return cpuStat, cpuID, nil
+}
+
+// Parse a softirq line.
+func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) {
+ softIRQStat := SoftIRQStat{}
+ var total uint64
+ var prefix string
+
+ _, err := fmt.Sscanf(line, "%s %d %d %d %d %d %d %d %d %d %d %d",
+ &prefix, &total,
+ &softIRQStat.Hi, &softIRQStat.Timer, &softIRQStat.NetTx, &softIRQStat.NetRx,
+ &softIRQStat.Block, &softIRQStat.BlockIoPoll,
+ &softIRQStat.Tasklet, &softIRQStat.Sched,
+ &softIRQStat.Hrtimer, &softIRQStat.Rcu)
+
+ if err != nil {
+ return SoftIRQStat{}, 0, fmt.Errorf("couldn't parse %s (softirq): %s", line, err)
+ }
+
+ return softIRQStat, total, nil
+}
+
// NewStat returns an information about current kernel/system statistics.
func (fs FS) NewStat() (Stat, error) {
+ // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
+
f, err := os.Open(fs.Path("stat"))
if err != nil {
return Stat{}, err
}
defer f.Close()
- s := bufio.NewScanner(f)
- for s.Scan() {
- line := s.Text()
- if !strings.HasPrefix(line, "btime") {
+ stat := Stat{}
+
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ line := scanner.Text()
+ parts := strings.Fields(scanner.Text())
+ // require at least <key> <value>
+ if len(parts) < 2 {
continue
}
- fields := strings.Fields(line)
- if len(fields) != 2 {
- return Stat{}, fmt.Errorf("couldn't parse %s line %s", f.Name(), line)
- }
- i, err := strconv.ParseInt(fields[1], 10, 32)
- if err != nil {
- return Stat{}, fmt.Errorf("couldn't parse %s: %s", fields[1], err)
+ switch {
+ case parts[0] == "btime":
+ if stat.BootTime, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (btime): %s", parts[1], err)
+ }
+ case parts[0] == "intr":
+ if stat.IRQTotal, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (intr): %s", parts[1], err)
+ }
+ numberedIRQs := parts[2:]
+ stat.IRQ = make([]uint64, len(numberedIRQs))
+ for i, count := range numberedIRQs {
+ if stat.IRQ[i], err = strconv.ParseUint(count, 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (intr%d): %s", count, i, err)
+ }
+ }
+ case parts[0] == "ctxt":
+ if stat.ContextSwitches, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (ctxt): %s", parts[1], err)
+ }
+ case parts[0] == "processes":
+ if stat.ProcessCreated, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (processes): %s", parts[1], err)
+ }
+ case parts[0] == "procs_running":
+ if stat.ProcessesRunning, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (procs_running): %s", parts[1], err)
+ }
+ case parts[0] == "procs_blocked":
+ if stat.ProcessesBlocked, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (procs_blocked): %s", parts[1], err)
+ }
+ case parts[0] == "softirq":
+ softIRQStats, total, err := parseSoftIRQStat(line)
+ if err != nil {
+ return Stat{}, err
+ }
+ stat.SoftIRQTotal = total
+ stat.SoftIRQ = softIRQStats
+ case strings.HasPrefix(parts[0], "cpu"):
+ cpuStat, cpuID, err := parseCPUStat(line)
+ if err != nil {
+ return Stat{}, err
+ }
+ if cpuID == -1 {
+ stat.CPUTotal = cpuStat
+ } else {
+ for int64(len(stat.CPU)) <= cpuID {
+ stat.CPU = append(stat.CPU, CPUStat{})
+ }
+ stat.CPU[cpuID] = cpuStat
+ }
}
- return Stat{BootTime: i}, nil
}
- if err := s.Err(); err != nil {
+
+ if err := scanner.Err(); err != nil {
return Stat{}, fmt.Errorf("couldn't parse %s: %s", f.Name(), err)
}
- return Stat{}, fmt.Errorf("couldn't parse %s, missing btime", f.Name())
+ return stat, nil
}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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.
}
// Please be informed that ipv4.NewPacketConn enables
// IP_STRIPHDR option by default on Darwin.
- // See golang.org/issue/9395 for futher information.
+ // See golang.org/issue/9395 for further information.
if runtime.GOOS == "darwin" && c.p4 != nil {
n, _, peer, err := c.p4.ReadFrom(b)
return n, peer, err
+++ /dev/null
-// Copyright 2016 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 icmp
-
-import (
- "encoding/binary"
- "unsafe"
-)
-
-var (
- // See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
- freebsdVersion uint32
-
- nativeEndian binary.ByteOrder
-)
-
-func init() {
- i := uint32(1)
- b := (*[4]byte)(unsafe.Pointer(&i))
- if b[0] == 1 {
- nativeEndian = binary.LittleEndian
- } else {
- nativeEndian = binary.BigEndian
- }
-}
"net"
"runtime"
+ "golang.org/x/net/internal/socket"
"golang.org/x/net/ipv4"
)
+// freebsdVersion is set in sys_freebsd.go.
+// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
+var freebsdVersion uint32
+
// ParseIPv4Header parses b as an IPv4 header of ICMP error message
// invoking packet, which is contained in ICMP error message.
func ParseIPv4Header(b []byte) (*ipv4.Header, error) {
}
switch runtime.GOOS {
case "darwin":
- h.TotalLen = int(nativeEndian.Uint16(b[2:4]))
+ h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4]))
case "freebsd":
if freebsdVersion >= 1000000 {
h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
} else {
- h.TotalLen = int(nativeEndian.Uint16(b[2:4]))
+ h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4]))
}
default:
h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
if err != nil {
return nil, os.NewSyscallError("socket", err)
}
- defer syscall.Close(s)
if runtime.GOOS == "darwin" && family == syscall.AF_INET {
if err := syscall.SetsockoptInt(s, iana.ProtocolIP, sysIP_STRIPHDR, 1); err != nil {
+ syscall.Close(s)
return nil, os.NewSyscallError("setsockopt", err)
}
}
sa, err := sockaddr(family, address)
if err != nil {
+ syscall.Close(s)
return nil, err
}
if err := syscall.Bind(s, sa); err != nil {
+ syscall.Close(s)
return nil, os.NewSyscallError("bind", err)
}
f := os.NewFile(uintptr(s), "datagram-oriented icmp")
- defer f.Close()
c, cerr = net.FilePacketConn(f)
+ f.Close()
default:
c, cerr = net.ListenPacket(network, address)
}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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.
"golang.org/x/net/ipv6"
)
+// BUG(mikio): This package is not implemented on NaCl and Plan 9.
+
var (
errMessageTooShort = errors.New("message too short")
errHeaderTooShort = errors.New("header too short")
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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 iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
package iana // import "golang.org/x/net/internal/iana"
-// Differentiated Services Field Codepoints (DSCP), Updated: 2013-06-25
+// Differentiated Services Field Codepoints (DSCP), Updated: 2017-05-12
const (
DiffServCS0 = 0x0 // CS0
DiffServCS1 = 0x20 // CS1
DiffServAF41 = 0x88 // AF41
DiffServAF42 = 0x90 // AF42
DiffServAF43 = 0x98 // AF43
- DiffServEFPHB = 0xb8 // EF PHB
+ DiffServEF = 0xb8 // EF
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
)
CongestionExperienced = 0x3 // CE (Congestion Experienced)
)
-// Protocol Numbers, Updated: 2015-10-06
+// Protocol Numbers, Updated: 2016-06-22
const (
ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number
ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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.
"fmt"
"net"
"sync"
+
+ "golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
type rawOpt struct {
return fmt.Sprintf("ttl=%d src=%v dst=%v ifindex=%d", cm.TTL, cm.Src, cm.Dst, cm.IfIndex)
}
+// Marshal returns the binary encoding of cm.
+func (cm *ControlMessage) Marshal() []byte {
+ if cm == nil {
+ return nil
+ }
+ var m socket.ControlMessage
+ if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To4() != nil || cm.IfIndex > 0) {
+ m = socket.NewControlMessage([]int{ctlOpts[ctlPacketInfo].length})
+ }
+ if len(m) > 0 {
+ ctlOpts[ctlPacketInfo].marshal(m, cm)
+ }
+ return m
+}
+
+// Parse parses b as a control message and stores the result in cm.
+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.ProtocolIP {
+ continue
+ }
+ switch {
+ case typ == ctlOpts[ctlTTL].name && l >= ctlOpts[ctlTTL].length:
+ ctlOpts[ctlTTL].parse(cm, m.Data(l))
+ case typ == ctlOpts[ctlDst].name && l >= ctlOpts[ctlDst].length:
+ ctlOpts[ctlDst].parse(cm, m.Data(l))
+ case typ == ctlOpts[ctlInterface].name && l >= ctlOpts[ctlInterface].length:
+ ctlOpts[ctlInterface].parse(cm, m.Data(l))
+ case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length:
+ ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
+ }
+ }
+ return nil
+}
+
+// NewControlMessage returns a new control message.
+//
+// The returned message is large enough for options specified by cf.
+func NewControlMessage(cf ControlFlags) []byte {
+ opt := rawOpt{cflags: cf}
+ var l int
+ if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 {
+ l += socket.ControlMessageSpace(ctlOpts[ctlTTL].length)
+ }
+ if ctlOpts[ctlPacketInfo].name > 0 {
+ if opt.isset(FlagSrc | FlagDst | FlagInterface) {
+ l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
+ }
+ } else {
+ if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 {
+ l += socket.ControlMessageSpace(ctlOpts[ctlDst].length)
+ }
+ if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 {
+ l += socket.ControlMessageSpace(ctlOpts[ctlInterface].length)
+ }
+ }
+ var b []byte
+ if l > 0 {
+ b = make([]byte, l)
+ }
+ return b
+}
+
// Ancillary data socket options
const (
ctlTTL = iota // header field
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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.
"unsafe"
"golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
func marshalDst(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIP
- m.Type = sysIP_RECVDSTADDR
- m.SetLen(syscall.CmsgLen(net.IPv4len))
- return b[syscall.CmsgSpace(net.IPv4len):]
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIP, sysIP_RECVDSTADDR, net.IPv4len)
+ return m.Next(net.IPv4len)
}
func parseDst(cm *ControlMessage, b []byte) {
- cm.Dst = b[:net.IPv4len]
+ if len(cm.Dst) < net.IPv4len {
+ cm.Dst = make(net.IP, net.IPv4len)
+ }
+ copy(cm.Dst, b[:net.IPv4len])
}
func marshalInterface(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIP
- m.Type = sysIP_RECVIF
- m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrDatalink))
- return b[syscall.CmsgSpace(syscall.SizeofSockaddrDatalink):]
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIP, sysIP_RECVIF, syscall.SizeofSockaddrDatalink)
+ return m.Next(syscall.SizeofSockaddrDatalink)
}
func parseInterface(cm *ControlMessage, b []byte) {
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin linux
+// +build darwin linux solaris
package ipv4
import (
- "syscall"
+ "net"
"unsafe"
"golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIP
- m.Type = sysIP_PKTINFO
- m.SetLen(syscall.CmsgLen(sysSizeofInetPktinfo))
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIP, sysIP_PKTINFO, sizeofInetPktinfo)
if cm != nil {
- pi := (*sysInetPktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
+ pi := (*inetPktinfo)(unsafe.Pointer(&m.Data(sizeofInetPktinfo)[0]))
if ip := cm.Src.To4(); ip != nil {
copy(pi.Spec_dst[:], ip)
}
pi.setIfindex(cm.IfIndex)
}
}
- return b[syscall.CmsgSpace(sysSizeofInetPktinfo):]
+ return m.Next(sizeofInetPktinfo)
}
func parsePacketInfo(cm *ControlMessage, b []byte) {
- pi := (*sysInetPktinfo)(unsafe.Pointer(&b[0]))
+ pi := (*inetPktinfo)(unsafe.Pointer(&b[0]))
cm.IfIndex = int(pi.Ifindex)
- cm.Dst = pi.Addr[:]
+ if len(cm.Dst) < net.IPv4len {
+ cm.Dst = make(net.IP, net.IPv4len)
+ }
+ copy(cm.Dst, pi.Addr[:])
}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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 nacl plan9 solaris
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
package ipv4
-func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
- return errOpNoSupport
-}
-
-func newControlMessage(opt *rawOpt) []byte {
- return nil
-}
+import "golang.org/x/net/internal/socket"
-func parseControlMessage(b []byte) (*ControlMessage, error) {
- return nil, errOpNoSupport
-}
-
-func marshalControlMessage(cm *ControlMessage) []byte {
- return nil
+func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
+ return errOpNoSupport
}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv4
import (
- "os"
- "syscall"
"unsafe"
"golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
-func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
+func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
opt.Lock()
defer opt.Unlock()
- if cf&FlagTTL != 0 && sockOpts[ssoReceiveTTL].name > 0 {
- if err := setInt(fd, &sockOpts[ssoReceiveTTL], boolint(on)); err != nil {
+ if so, ok := sockOpts[ssoReceiveTTL]; ok && cf&FlagTTL != 0 {
+ if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.clear(FlagTTL)
}
}
- if sockOpts[ssoPacketInfo].name > 0 {
+ if so, ok := sockOpts[ssoPacketInfo]; ok {
if cf&(FlagSrc|FlagDst|FlagInterface) != 0 {
- if err := setInt(fd, &sockOpts[ssoPacketInfo], boolint(on)); err != nil {
+ if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
}
}
} else {
- if cf&FlagDst != 0 && sockOpts[ssoReceiveDst].name > 0 {
- if err := setInt(fd, &sockOpts[ssoReceiveDst], boolint(on)); err != nil {
+ if so, ok := sockOpts[ssoReceiveDst]; ok && cf&FlagDst != 0 {
+ if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.clear(FlagDst)
}
}
- if cf&FlagInterface != 0 && sockOpts[ssoReceiveInterface].name > 0 {
- if err := setInt(fd, &sockOpts[ssoReceiveInterface], boolint(on)); err != nil {
+ if so, ok := sockOpts[ssoReceiveInterface]; ok && cf&FlagInterface != 0 {
+ if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
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)
- b := oob
- if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 {
- b = ctlOpts[ctlTTL].marshal(b, nil)
- }
- if ctlOpts[ctlPacketInfo].name > 0 {
- if opt.isset(FlagSrc | FlagDst | FlagInterface) {
- b = ctlOpts[ctlPacketInfo].marshal(b, nil)
- }
- } else {
- if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 {
- b = ctlOpts[ctlDst].marshal(b, nil)
- }
- if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 {
- b = ctlOpts[ctlInterface].marshal(b, nil)
- }
- }
- }
- 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):]
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIP, sysIP_RECVTTL, 1)
+ return m.Next(1)
}
func parseTTL(cm *ControlMessage, b []byte) {
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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 "syscall"
+import (
+ "syscall"
-func setControlMessage(fd syscall.Handle, opt *rawOpt, cf ControlFlags, on bool) error {
- // TODO(mikio): implement this
- return syscall.EWINDOWS
-}
-
-func newControlMessage(opt *rawOpt) []byte {
- // TODO(mikio): implement this
- return nil
-}
+ "golang.org/x/net/internal/socket"
+)
-func parseControlMessage(b []byte) (*ControlMessage, error) {
+func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
// TODO(mikio): implement this
- return nil, syscall.EWINDOWS
-}
-
-func marshalControlMessage(cm *ControlMessage) []byte {
- // TODO(mikio): implement this
- return nil
+ return syscall.EWINDOWS
}
sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE
sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE
- sysSizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
- sysSizeofSockaddrInet = C.sizeof_struct_sockaddr_in
- sysSizeofInetPktinfo = C.sizeof_struct_in_pktinfo
-
- sysSizeofIPMreq = C.sizeof_struct_ip_mreq
- sysSizeofIPMreqn = C.sizeof_struct_ip_mreqn
- sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
- sysSizeofGroupReq = C.sizeof_struct_group_req
- sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req
+ sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+ sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
+ sizeofInetPktinfo = C.sizeof_struct_in_pktinfo
+
+ sizeofIPMreq = C.sizeof_struct_ip_mreq
+ sizeofIPMreqn = C.sizeof_struct_ip_mreqn
+ sizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
+ sizeofGroupReq = C.sizeof_struct_group_req
+ sizeofGroupSourceReq = C.sizeof_struct_group_source_req
)
-type sysSockaddrStorage C.struct_sockaddr_storage
+type sockaddrStorage C.struct_sockaddr_storage
-type sysSockaddrInet C.struct_sockaddr_in
+type sockaddrInet C.struct_sockaddr_in
-type sysInetPktinfo C.struct_in_pktinfo
+type inetPktinfo C.struct_in_pktinfo
-type sysIPMreq C.struct_ip_mreq
+type ipMreq C.struct_ip_mreq
-type sysIPMreqn C.struct_ip_mreqn
+type ipMreqn C.struct_ip_mreqn
-type sysIPMreqSource C.struct_ip_mreq_source
+type ipMreqSource C.struct_ip_mreq_source
-type sysGroupReq C.struct_group_req
+type groupReq C.struct_group_req
-type sysGroupSourceReq C.struct_group_source_req
+type groupSourceReq C.struct_group_source_req
sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP
sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP
- sysSizeofIPMreq = C.sizeof_struct_ip_mreq
+ sizeofIPMreq = C.sizeof_struct_ip_mreq
)
-type sysIPMreq C.struct_ip_mreq
+type ipMreq C.struct_ip_mreq
sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE
sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE
- sysSizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
- sysSizeofSockaddrInet = C.sizeof_struct_sockaddr_in
-
- sysSizeofIPMreq = C.sizeof_struct_ip_mreq
- sysSizeofIPMreqn = C.sizeof_struct_ip_mreqn
- sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
- sysSizeofGroupReq = C.sizeof_struct_group_req
- sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req
+ sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+ sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
+
+ sizeofIPMreq = C.sizeof_struct_ip_mreq
+ sizeofIPMreqn = C.sizeof_struct_ip_mreqn
+ sizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
+ sizeofGroupReq = C.sizeof_struct_group_req
+ sizeofGroupSourceReq = C.sizeof_struct_group_source_req
)
-type sysSockaddrStorage C.struct_sockaddr_storage
+type sockaddrStorage C.struct_sockaddr_storage
-type sysSockaddrInet C.struct_sockaddr_in
+type sockaddrInet C.struct_sockaddr_in
-type sysIPMreq C.struct_ip_mreq
+type ipMreq C.struct_ip_mreq
-type sysIPMreqn C.struct_ip_mreqn
+type ipMreqn C.struct_ip_mreqn
-type sysIPMreqSource C.struct_ip_mreq_source
+type ipMreqSource C.struct_ip_mreq_source
-type sysGroupReq C.struct_group_req
+type groupReq C.struct_group_req
-type sysGroupSourceReq C.struct_group_source_req
+type groupSourceReq C.struct_group_source_req
#include <linux/errqueue.h>
#include <linux/icmp.h>
#include <linux/in.h>
+#include <linux/filter.h>
+#include <sys/socket.h>
*/
import "C"
sysSO_EE_ORIGIN_TXSTATUS = C.SO_EE_ORIGIN_TXSTATUS
sysSO_EE_ORIGIN_TIMESTAMPING = C.SO_EE_ORIGIN_TIMESTAMPING
- sysSizeofKernelSockaddrStorage = C.sizeof_struct___kernel_sockaddr_storage
- sysSizeofSockaddrInet = C.sizeof_struct_sockaddr_in
- sysSizeofInetPktinfo = C.sizeof_struct_in_pktinfo
- sysSizeofSockExtendedErr = C.sizeof_struct_sock_extended_err
+ sysSOL_SOCKET = C.SOL_SOCKET
+ sysSO_ATTACH_FILTER = C.SO_ATTACH_FILTER
- sysSizeofIPMreq = C.sizeof_struct_ip_mreq
- sysSizeofIPMreqn = C.sizeof_struct_ip_mreqn
- sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
- sysSizeofGroupReq = C.sizeof_struct_group_req
- sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req
+ sizeofKernelSockaddrStorage = C.sizeof_struct___kernel_sockaddr_storage
+ sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
+ sizeofInetPktinfo = C.sizeof_struct_in_pktinfo
+ sizeofSockExtendedErr = C.sizeof_struct_sock_extended_err
- sysSizeofICMPFilter = C.sizeof_struct_icmp_filter
+ sizeofIPMreq = C.sizeof_struct_ip_mreq
+ sizeofIPMreqn = C.sizeof_struct_ip_mreqn
+ sizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
+ sizeofGroupReq = C.sizeof_struct_group_req
+ sizeofGroupSourceReq = C.sizeof_struct_group_source_req
+
+ sizeofICMPFilter = C.sizeof_struct_icmp_filter
+
+ sizeofSockFprog = C.sizeof_struct_sock_fprog
)
-type sysKernelSockaddrStorage C.struct___kernel_sockaddr_storage
+type kernelSockaddrStorage C.struct___kernel_sockaddr_storage
+
+type sockaddrInet C.struct_sockaddr_in
+
+type inetPktinfo C.struct_in_pktinfo
-type sysSockaddrInet C.struct_sockaddr_in
+type sockExtendedErr C.struct_sock_extended_err
-type sysInetPktinfo C.struct_in_pktinfo
+type ipMreq C.struct_ip_mreq
-type sysSockExtendedErr C.struct_sock_extended_err
+type ipMreqn C.struct_ip_mreqn
-type sysIPMreq C.struct_ip_mreq
+type ipMreqSource C.struct_ip_mreq_source
-type sysIPMreqn C.struct_ip_mreqn
+type groupReq C.struct_group_req
-type sysIPMreqSource C.struct_ip_mreq_source
+type groupSourceReq C.struct_group_source_req
-type sysGroupReq C.struct_group_req
+type icmpFilter C.struct_icmp_filter
-type sysGroupSourceReq C.struct_group_source_req
+type sockFProg C.struct_sock_fprog
-type sysICMPFilter C.struct_icmp_filter
+type sockFilter C.struct_sock_filter
sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP
sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP
- sysSizeofIPMreq = C.sizeof_struct_ip_mreq
+ sizeofIPMreq = C.sizeof_struct_ip_mreq
)
-type sysIPMreq C.struct_ip_mreq
+type ipMreq C.struct_ip_mreq
sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP
sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP
- sysSizeofIPMreq = C.sizeof_struct_ip_mreq
+ sizeofIPMreq = C.sizeof_struct_ip_mreq
)
-type sysIPMreq C.struct_ip_mreq
+type ipMreq C.struct_ip_mreq
package ipv4
/*
+#include <sys/socket.h>
+
#include <netinet/in.h>
*/
import "C"
const (
- sysIP_OPTIONS = C.IP_OPTIONS
- sysIP_HDRINCL = C.IP_HDRINCL
- sysIP_TOS = C.IP_TOS
- sysIP_TTL = C.IP_TTL
- sysIP_RECVOPTS = C.IP_RECVOPTS
- sysIP_RECVRETOPTS = C.IP_RECVRETOPTS
- sysIP_RECVDSTADDR = C.IP_RECVDSTADDR
- sysIP_RETOPTS = C.IP_RETOPTS
- sysIP_RECVIF = C.IP_RECVIF
- sysIP_RECVSLLA = C.IP_RECVSLLA
- sysIP_RECVTTL = C.IP_RECVTTL
- sysIP_NEXTHOP = C.IP_NEXTHOP
- sysIP_PKTINFO = C.IP_PKTINFO
- sysIP_RECVPKTINFO = C.IP_RECVPKTINFO
- sysIP_DONTFRAG = C.IP_DONTFRAG
- sysIP_BOUND_IF = C.IP_BOUND_IF
- sysIP_UNSPEC_SRC = C.IP_UNSPEC_SRC
- sysIP_BROADCAST_TTL = C.IP_BROADCAST_TTL
- sysIP_DHCPINIT_IF = C.IP_DHCPINIT_IF
+ sysIP_OPTIONS = C.IP_OPTIONS
+ sysIP_HDRINCL = C.IP_HDRINCL
+ sysIP_TOS = C.IP_TOS
+ sysIP_TTL = C.IP_TTL
+ sysIP_RECVOPTS = C.IP_RECVOPTS
+ sysIP_RECVRETOPTS = C.IP_RECVRETOPTS
+ sysIP_RECVDSTADDR = C.IP_RECVDSTADDR
+ sysIP_RETOPTS = C.IP_RETOPTS
+ sysIP_RECVIF = C.IP_RECVIF
+ sysIP_RECVSLLA = C.IP_RECVSLLA
+ sysIP_RECVTTL = C.IP_RECVTTL
sysIP_MULTICAST_IF = C.IP_MULTICAST_IF
sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL
sysIP_UNBLOCK_SOURCE = C.IP_UNBLOCK_SOURCE
sysIP_ADD_SOURCE_MEMBERSHIP = C.IP_ADD_SOURCE_MEMBERSHIP
sysIP_DROP_SOURCE_MEMBERSHIP = C.IP_DROP_SOURCE_MEMBERSHIP
+ sysIP_NEXTHOP = C.IP_NEXTHOP
- sysSizeofInetPktinfo = C.sizeof_struct_in_pktinfo
+ sysIP_PKTINFO = C.IP_PKTINFO
+ sysIP_RECVPKTINFO = C.IP_RECVPKTINFO
+ sysIP_DONTFRAG = C.IP_DONTFRAG
- sysSizeofIPMreq = C.sizeof_struct_ip_mreq
- sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
+ sysIP_BOUND_IF = C.IP_BOUND_IF
+ sysIP_UNSPEC_SRC = C.IP_UNSPEC_SRC
+ sysIP_BROADCAST_TTL = C.IP_BROADCAST_TTL
+ sysIP_DHCPINIT_IF = C.IP_DHCPINIT_IF
+
+ sysIP_REUSEADDR = C.IP_REUSEADDR
+ sysIP_DONTROUTE = C.IP_DONTROUTE
+ sysIP_BROADCAST = C.IP_BROADCAST
+
+ sysMCAST_JOIN_GROUP = C.MCAST_JOIN_GROUP
+ sysMCAST_LEAVE_GROUP = C.MCAST_LEAVE_GROUP
+ sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE
+ sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE
+ sysMCAST_JOIN_SOURCE_GROUP = C.MCAST_JOIN_SOURCE_GROUP
+ sysMCAST_LEAVE_SOURCE_GROUP = C.MCAST_LEAVE_SOURCE_GROUP
+
+ sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+ sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
+ sizeofInetPktinfo = C.sizeof_struct_in_pktinfo
+
+ sizeofIPMreq = C.sizeof_struct_ip_mreq
+ sizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
+ sizeofGroupReq = C.sizeof_struct_group_req
+ sizeofGroupSourceReq = C.sizeof_struct_group_source_req
)
-type sysInetPktinfo C.struct_in_pktinfo
+type sockaddrStorage C.struct_sockaddr_storage
+
+type sockaddrInet C.struct_sockaddr_in
+
+type inetPktinfo C.struct_in_pktinfo
+
+type ipMreq C.struct_ip_mreq
+
+type ipMreqSource C.struct_ip_mreq_source
-type sysIPMreq C.struct_ip_mreq
+type groupReq C.struct_group_req
-type sysIPMreqSource C.struct_ip_mreq_source
+type groupSourceReq C.struct_group_source_req
+++ /dev/null
-// 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 windows
-
-package ipv4
-
-import (
- "net"
- "syscall"
-)
-
-// MulticastTTL returns the time-to-live field value for outgoing
-// multicast packets.
-func (c *dgramOpt) MulticastTTL() (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return 0, err
- }
- return getInt(fd, &sockOpts[ssoMulticastTTL])
-}
-
-// SetMulticastTTL sets the time-to-live field value for future
-// outgoing multicast packets.
-func (c *dgramOpt) SetMulticastTTL(ttl int) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setInt(fd, &sockOpts[ssoMulticastTTL], ttl)
-}
-
-// MulticastInterface returns the default interface for multicast
-// packet transmissions.
-func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
- if !c.ok() {
- return nil, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return nil, err
- }
- return getInterface(fd, &sockOpts[ssoMulticastInterface])
-}
-
-// SetMulticastInterface sets the default interface for future
-// multicast packet transmissions.
-func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setInterface(fd, &sockOpts[ssoMulticastInterface], ifi)
-}
-
-// MulticastLoopback reports whether transmitted multicast packets
-// should be copied and send back to the originator.
-func (c *dgramOpt) MulticastLoopback() (bool, error) {
- if !c.ok() {
- return false, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return false, err
- }
- on, err := getInt(fd, &sockOpts[ssoMulticastLoopback])
- if err != nil {
- return false, err
- }
- return on == 1, nil
-}
-
-// SetMulticastLoopback sets whether transmitted multicast packets
-// should be copied and send back to the originator.
-func (c *dgramOpt) SetMulticastLoopback(on bool) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setInt(fd, &sockOpts[ssoMulticastLoopback], boolint(on))
-}
-
-// JoinGroup joins the group address group on the interface ifi.
-// By default all sources that can cast data to group are accepted.
-// It's possible to mute and unmute data transmission from a specific
-// source by using ExcludeSourceSpecificGroup and
-// IncludeSourceSpecificGroup.
-// JoinGroup uses the system assigned multicast interface when ifi is
-// nil, although this is not recommended because the assignment
-// depends on platforms and sometimes it might require routing
-// configuration.
-func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP4(group)
- if grp == nil {
- return errMissingAddress
- }
- return setGroup(fd, &sockOpts[ssoJoinGroup], ifi, grp)
-}
-
-// LeaveGroup leaves the group address group on the interface ifi
-// regardless of whether the group is any-source group or
-// source-specific group.
-func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP4(group)
- if grp == nil {
- return errMissingAddress
- }
- return setGroup(fd, &sockOpts[ssoLeaveGroup], ifi, grp)
-}
-
-// JoinSourceSpecificGroup joins the source-specific group comprising
-// group and source on the interface ifi.
-// JoinSourceSpecificGroup uses the system assigned multicast
-// interface when ifi is nil, although this is not recommended because
-// the assignment depends on platforms and sometimes it might require
-// routing configuration.
-func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP4(group)
- if grp == nil {
- return errMissingAddress
- }
- src := netAddrToIP4(source)
- if src == nil {
- return errMissingAddress
- }
- return setSourceGroup(fd, &sockOpts[ssoJoinSourceGroup], ifi, grp, src)
-}
-
-// LeaveSourceSpecificGroup leaves the source-specific group on the
-// interface ifi.
-func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP4(group)
- if grp == nil {
- return errMissingAddress
- }
- src := netAddrToIP4(source)
- if src == nil {
- return errMissingAddress
- }
- return setSourceGroup(fd, &sockOpts[ssoLeaveSourceGroup], ifi, grp, src)
-}
-
-// ExcludeSourceSpecificGroup excludes the source-specific group from
-// the already joined any-source groups by JoinGroup on the interface
-// ifi.
-func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP4(group)
- if grp == nil {
- return errMissingAddress
- }
- src := netAddrToIP4(source)
- if src == nil {
- return errMissingAddress
- }
- return setSourceGroup(fd, &sockOpts[ssoBlockSourceGroup], ifi, grp, src)
-}
-
-// IncludeSourceSpecificGroup includes the excluded source-specific
-// group by ExcludeSourceSpecificGroup again on the interface ifi.
-func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP4(group)
- if grp == nil {
- return errMissingAddress
- }
- src := netAddrToIP4(source)
- if src == nil {
- return errMissingAddress
- }
- return setSourceGroup(fd, &sockOpts[ssoUnblockSourceGroup], ifi, grp, src)
-}
-
-// ICMPFilter returns an ICMP filter.
-// Currently only Linux supports this.
-func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
- if !c.ok() {
- return nil, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return nil, err
- }
- return getICMPFilter(fd, &sockOpts[ssoICMPFilter])
-}
-
-// SetICMPFilter deploys the ICMP filter.
-// Currently only Linux supports this.
-func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setICMPFilter(fd, &sockOpts[ssoICMPFilter], f)
-}
+++ /dev/null
-// 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 nacl plan9 solaris
-
-package ipv4
-
-import "net"
-
-// MulticastTTL returns the time-to-live field value for outgoing
-// multicast packets.
-func (c *dgramOpt) MulticastTTL() (int, error) {
- return 0, errOpNoSupport
-}
-
-// SetMulticastTTL sets the time-to-live field value for future
-// outgoing multicast packets.
-func (c *dgramOpt) SetMulticastTTL(ttl int) error {
- return errOpNoSupport
-}
-
-// MulticastInterface returns the default interface for multicast
-// packet transmissions.
-func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
- return nil, errOpNoSupport
-}
-
-// SetMulticastInterface sets the default interface for future
-// multicast packet transmissions.
-func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
- return errOpNoSupport
-}
-
-// MulticastLoopback reports whether transmitted multicast packets
-// should be copied and send back to the originator.
-func (c *dgramOpt) MulticastLoopback() (bool, error) {
- return false, errOpNoSupport
-}
-
-// SetMulticastLoopback sets whether transmitted multicast packets
-// should be copied and send back to the originator.
-func (c *dgramOpt) SetMulticastLoopback(on bool) error {
- return errOpNoSupport
-}
-
-// JoinGroup joins the group address group on the interface ifi.
-// By default all sources that can cast data to group are accepted.
-// It's possible to mute and unmute data transmission from a specific
-// source by using ExcludeSourceSpecificGroup and
-// IncludeSourceSpecificGroup.
-// JoinGroup uses the system assigned multicast interface when ifi is
-// nil, although this is not recommended because the assignment
-// depends on platforms and sometimes it might require routing
-// configuration.
-func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
- return errOpNoSupport
-}
-
-// LeaveGroup leaves the group address group on the interface ifi
-// regardless of whether the group is any-source group or
-// source-specific group.
-func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
- return errOpNoSupport
-}
-
-// JoinSourceSpecificGroup joins the source-specific group comprising
-// group and source on the interface ifi.
-// JoinSourceSpecificGroup uses the system assigned multicast
-// interface when ifi is nil, although this is not recommended because
-// the assignment depends on platforms and sometimes it might require
-// routing configuration.
-func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- return errOpNoSupport
-}
-
-// LeaveSourceSpecificGroup leaves the source-specific group on the
-// interface ifi.
-func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- return errOpNoSupport
-}
-
-// ExcludeSourceSpecificGroup excludes the source-specific group from
-// the already joined any-source groups by JoinGroup on the interface
-// ifi.
-func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- return errOpNoSupport
-}
-
-// IncludeSourceSpecificGroup includes the excluded source-specific
-// group by ExcludeSourceSpecificGroup again on the interface ifi.
-func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- return errOpNoSupport
-}
-
-// ICMPFilter returns an ICMP filter.
-// Currently only Linux supports this.
-func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
- return nil, errOpNoSupport
-}
-
-// SetICMPFilter deploys the ICMP filter.
-// Currently only Linux supports this.
-func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
- return errOpNoSupport
-}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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.
//
// The options for unicasting are available for net.TCPConn,
// net.UDPConn and net.IPConn which are created as network connections
-// that use the IPv4 transport. When a single TCP connection carrying
+// that use the IPv4 transport. When a single TCP connection carrying
// a data flow of multiple packets needs to indicate the flow is
-// important, ipv4.Conn is used to set the type-of-service field on
-// the IPv4 header for each packet.
+// important, Conn is used to set the type-of-service field on the
+// IPv4 header for each packet.
//
// ln, err := net.Listen("tcp4", "0.0.0.0:1024")
// if err != nil {
//
// The options for multicasting are available for net.UDPConn and
// net.IPconn which are created as network connections that use the
-// IPv4 transport. A few network facilities must be prepared before
+// IPv4 transport. A few network facilities must be prepared before
// you begin multicasting, at a minimum joining network interfaces and
// multicast groups.
//
// defer c.Close()
//
// Second, the application joins multicast groups, starts listening to
-// the groups on the specified network interfaces. Note that the
+// the groups on the specified network interfaces. Note that the
// service port for transport layer protocol does not matter with this
// operation as joining groups affects only network and link layer
// protocols, such as IPv4 and Ethernet.
// }
//
// The application might set per packet control message transmissions
-// between the protocol stack within the kernel. When the application
+// between the protocol stack within the kernel. When the application
// needs a destination address on an incoming packet,
-// SetControlMessage of ipv4.PacketConn is used to enable control
-// message transmissons.
+// SetControlMessage of PacketConn is used to enable control message
+// transmissions.
//
// if err := p.SetControlMessage(ipv4.FlagDst, true); err != nil {
// // error handling
// More multicasting
//
// An application that uses PacketConn or RawConn may join multiple
-// multicast groups. For example, a UDP listener with port 1024 might
+// multicast groups. For example, a UDP listener with port 1024 might
// join two different groups across over two different network
// interfaces by using:
//
// }
//
// It is possible for multiple UDP listeners that listen on the same
-// UDP port to join the same multicast group. The net package will
+// UDP port to join the same multicast group. The net package will
// provide a socket that listens to a wildcard address with reusable
// UDP port when an appropriate multicast address prefix is passed to
// the net.ListenPacket or net.ListenUDP.
// In the fallback case, ExcludeSourceSpecificGroup and
// IncludeSourceSpecificGroup may return an error.
package ipv4 // import "golang.org/x/net/ipv4"
+
+// BUG(mikio): This package is not implemented on NaCl and Plan 9.
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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.
"net"
"syscall"
"time"
+
+ "golang.org/x/net/internal/socket"
)
+// BUG(mikio): On Windows, the JoinSourceSpecificGroup,
+// LeaveSourceSpecificGroup, ExcludeSourceSpecificGroup and
+// IncludeSourceSpecificGroup methods of PacketConn and RawConn are
+// not implemented.
+
// A Conn represents a network endpoint that uses the IPv4 transport.
// It is used to control basic IP-level socket options such as TOS and
// TTL.
}
type genericOpt struct {
- net.Conn
+ *socket.Conn
}
func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil }
// NewConn returns a new Conn.
func NewConn(c net.Conn) *Conn {
+ cc, _ := socket.NewConn(c)
return &Conn{
- genericOpt: genericOpt{Conn: c},
+ genericOpt: genericOpt{Conn: cc},
}
}
// A PacketConn represents a packet network endpoint that uses the
-// IPv4 transport. It is used to control several IP-level socket
-// options including multicasting. It also provides datagram based
+// IPv4 transport. It is used to control several IP-level socket
+// options including multicasting. It also provides datagram based
// network I/O methods specific to the IPv4 and higher layer protocols
// such as UDP.
type PacketConn struct {
}
type dgramOpt struct {
- net.PacketConn
+ *socket.Conn
}
-func (c *dgramOpt) ok() bool { return c != nil && c.PacketConn != nil }
+func (c *dgramOpt) ok() bool { return c != nil && c.Conn != nil }
// SetControlMessage sets the per packet IP-level socket options.
func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
}
- fd, err := c.payloadHandler.sysfd()
- if err != nil {
- return err
- }
- return setControlMessage(fd, &c.payloadHandler.rawOpt, cf, on)
+ return setControlMessage(c.dgramOpt.Conn, &c.payloadHandler.rawOpt, cf, on)
}
// SetDeadline sets the read and write deadlines associated with the
// NewPacketConn returns a new PacketConn using c as its underlying
// transport.
func NewPacketConn(c net.PacketConn) *PacketConn {
+ cc, _ := socket.NewConn(c.(net.Conn))
p := &PacketConn{
- genericOpt: genericOpt{Conn: c.(net.Conn)},
- dgramOpt: dgramOpt{PacketConn: c},
- payloadHandler: payloadHandler{PacketConn: c},
- }
- if _, ok := c.(*net.IPConn); ok && sockOpts[ssoStripHeader].name > 0 {
- if fd, err := p.payloadHandler.sysfd(); err == nil {
- setInt(fd, &sockOpts[ssoStripHeader], boolint(true))
- }
+ genericOpt: genericOpt{Conn: cc},
+ dgramOpt: dgramOpt{Conn: cc},
+ payloadHandler: payloadHandler{PacketConn: c, Conn: cc},
}
return p
}
// A RawConn represents a packet network endpoint that uses the IPv4
-// transport. It is used to control several IP-level socket options
-// including IPv4 header manipulation. It also provides datagram
+// transport. It is used to control several IP-level socket options
+// including IPv4 header manipulation. It also provides datagram
// based network I/O methods specific to the IPv4 and higher layer
// protocols that handle IPv4 datagram directly such as OSPF, GRE.
type RawConn struct {
if !c.packetHandler.ok() {
return syscall.EINVAL
}
- fd, err := c.packetHandler.sysfd()
- if err != nil {
- return err
- }
- return setControlMessage(fd, &c.packetHandler.rawOpt, cf, on)
+ return setControlMessage(c.dgramOpt.Conn, &c.packetHandler.rawOpt, cf, on)
}
// SetDeadline sets the read and write deadlines associated with the
if !c.packetHandler.ok() {
return syscall.EINVAL
}
- return c.packetHandler.c.SetDeadline(t)
+ return c.packetHandler.IPConn.SetDeadline(t)
}
// SetReadDeadline sets the read deadline associated with the
if !c.packetHandler.ok() {
return syscall.EINVAL
}
- return c.packetHandler.c.SetReadDeadline(t)
+ return c.packetHandler.IPConn.SetReadDeadline(t)
}
// SetWriteDeadline sets the write deadline associated with the
if !c.packetHandler.ok() {
return syscall.EINVAL
}
- return c.packetHandler.c.SetWriteDeadline(t)
+ return c.packetHandler.IPConn.SetWriteDeadline(t)
}
// Close closes the endpoint.
if !c.packetHandler.ok() {
return syscall.EINVAL
}
- return c.packetHandler.c.Close()
+ return c.packetHandler.IPConn.Close()
}
// NewRawConn returns a new RawConn using c as its underlying
// transport.
func NewRawConn(c net.PacketConn) (*RawConn, error) {
- r := &RawConn{
- genericOpt: genericOpt{Conn: c.(net.Conn)},
- dgramOpt: dgramOpt{PacketConn: c},
- packetHandler: packetHandler{c: c.(*net.IPConn)},
- }
- fd, err := r.packetHandler.sysfd()
+ cc, err := socket.NewConn(c.(net.Conn))
if err != nil {
return nil, err
}
- if err := setInt(fd, &sockOpts[ssoHeaderPrepend], boolint(true)); err != nil {
+ r := &RawConn{
+ genericOpt: genericOpt{Conn: cc},
+ dgramOpt: dgramOpt{Conn: cc},
+ packetHandler: packetHandler{IPConn: c.(*net.IPConn), Conn: cc},
+ }
+ so, ok := sockOpts[ssoHeaderPrepend]
+ if !ok {
+ return nil, errOpNoSupport
+ }
+ if err := so.SetInt(r.dgramOpt.Conn, boolint(true)); err != nil {
return nil, err
}
return r, nil
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
if err != nil {
return err
}
- // The ipv4 pacakge still supports go1.2, and so we need to
- // take care of additional platforms in go1.3 and above for
- // working with go1.2.
- switch {
- case runtime.GOOS == "dragonfly" || runtime.GOOS == "solaris":
- b = bytes.Replace(b, []byte("package ipv4\n"), []byte("// +build "+runtime.GOOS+"\n\npackage ipv4\n"), 1)
- case runtime.GOOS == "linux" && (runtime.GOARCH == "arm64" || runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le"):
- b = bytes.Replace(b, []byte("package ipv4\n"), []byte("// +build "+runtime.GOOS+","+runtime.GOARCH+"\n\npackage ipv4\n"), 1)
- }
b, err = format.Source(b)
if err != nil {
return err
+++ /dev/null
-// 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 windows
-
-package ipv4
-
-import "syscall"
-
-// TOS returns the type-of-service field value for outgoing packets.
-func (c *genericOpt) TOS() (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return 0, err
- }
- return getInt(fd, &sockOpts[ssoTOS])
-}
-
-// SetTOS sets the type-of-service field value for future outgoing
-// packets.
-func (c *genericOpt) SetTOS(tos int) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setInt(fd, &sockOpts[ssoTOS], tos)
-}
-
-// TTL returns the time-to-live field value for outgoing packets.
-func (c *genericOpt) TTL() (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return 0, err
- }
- return getInt(fd, &sockOpts[ssoTTL])
-}
-
-// SetTTL sets the time-to-live field value for future outgoing
-// packets.
-func (c *genericOpt) SetTTL(ttl int) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setInt(fd, &sockOpts[ssoTTL], ttl)
-}
+++ /dev/null
-// 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 nacl plan9 solaris
-
-package ipv4
-
-// TOS returns the type-of-service field value for outgoing packets.
-func (c *genericOpt) TOS() (int, error) {
- return 0, errOpNoSupport
-}
-
-// SetTOS sets the type-of-service field value for future outgoing
-// packets.
-func (c *genericOpt) SetTOS(tos int) error {
- return errOpNoSupport
-}
-
-// TTL returns the time-to-live field value for outgoing packets.
-func (c *genericOpt) TTL() (int, error) {
- return 0, errOpNoSupport
-}
-
-// SetTTL sets the time-to-live field value for future outgoing
-// packets.
-func (c *genericOpt) SetTTL(ttl int) error {
- return errOpNoSupport
-}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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.
"net"
"runtime"
"syscall"
+
+ "golang.org/x/net/internal/socket"
)
const (
return fmt.Sprintf("ver=%d hdrlen=%d tos=%#x totallen=%d id=%#x flags=%#x fragoff=%#x ttl=%d proto=%d cksum=%#x src=%v dst=%v", h.Version, h.Len, h.TOS, h.TotalLen, h.ID, h.Flags, h.FragOff, h.TTL, h.Protocol, h.Checksum, h.Src, h.Dst)
}
-// Marshal returns the binary encoding of the IPv4 header h.
+// Marshal returns the binary encoding of h.
func (h *Header) Marshal() ([]byte, error) {
if h == nil {
return nil, syscall.EINVAL
b[1] = byte(h.TOS)
flagsAndFragOff := (h.FragOff & 0x1fff) | int(h.Flags<<13)
switch runtime.GOOS {
- case "darwin", "dragonfly", "freebsd", "netbsd":
- nativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
- nativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
+ case "darwin", "dragonfly", "netbsd":
+ socket.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
+ socket.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
+ case "freebsd":
+ if freebsdVersion < 1100000 {
+ socket.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
+ socket.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
+ } else {
+ binary.BigEndian.PutUint16(b[2:4], uint16(h.TotalLen))
+ binary.BigEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
+ }
default:
binary.BigEndian.PutUint16(b[2:4], uint16(h.TotalLen))
binary.BigEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
return b, nil
}
-// ParseHeader parses b as an IPv4 header.
-func ParseHeader(b []byte) (*Header, error) {
- if len(b) < HeaderLen {
- return nil, errHeaderTooShort
+// Parse parses b as an IPv4 header and sotres the result in h.
+func (h *Header) Parse(b []byte) error {
+ if h == nil || len(b) < HeaderLen {
+ return errHeaderTooShort
}
hdrlen := int(b[0]&0x0f) << 2
if hdrlen > len(b) {
- return nil, errBufferTooShort
- }
- h := &Header{
- Version: int(b[0] >> 4),
- Len: hdrlen,
- TOS: int(b[1]),
- ID: int(binary.BigEndian.Uint16(b[4:6])),
- TTL: int(b[8]),
- Protocol: int(b[9]),
- Checksum: int(binary.BigEndian.Uint16(b[10:12])),
- Src: net.IPv4(b[12], b[13], b[14], b[15]),
- Dst: net.IPv4(b[16], b[17], b[18], b[19]),
+ return errBufferTooShort
}
+ h.Version = int(b[0] >> 4)
+ h.Len = hdrlen
+ h.TOS = int(b[1])
+ h.ID = int(binary.BigEndian.Uint16(b[4:6]))
+ h.TTL = int(b[8])
+ h.Protocol = int(b[9])
+ h.Checksum = int(binary.BigEndian.Uint16(b[10:12]))
+ h.Src = net.IPv4(b[12], b[13], b[14], b[15])
+ h.Dst = net.IPv4(b[16], b[17], b[18], b[19])
switch runtime.GOOS {
case "darwin", "dragonfly", "netbsd":
- h.TotalLen = int(nativeEndian.Uint16(b[2:4])) + hdrlen
- h.FragOff = int(nativeEndian.Uint16(b[6:8]))
+ h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4])) + hdrlen
+ h.FragOff = int(socket.NativeEndian.Uint16(b[6:8]))
case "freebsd":
- h.TotalLen = int(nativeEndian.Uint16(b[2:4]))
- if freebsdVersion < 1000000 {
- h.TotalLen += hdrlen
+ if freebsdVersion < 1100000 {
+ h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4]))
+ if freebsdVersion < 1000000 {
+ h.TotalLen += hdrlen
+ }
+ h.FragOff = int(socket.NativeEndian.Uint16(b[6:8]))
+ } else {
+ h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
+ h.FragOff = int(binary.BigEndian.Uint16(b[6:8]))
}
- h.FragOff = int(nativeEndian.Uint16(b[6:8]))
default:
h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
h.FragOff = int(binary.BigEndian.Uint16(b[6:8]))
}
h.Flags = HeaderFlags(h.FragOff&0xe000) >> 13
h.FragOff = h.FragOff & 0x1fff
- if hdrlen-HeaderLen > 0 {
- h.Options = make([]byte, hdrlen-HeaderLen)
- copy(h.Options, b[HeaderLen:])
+ optlen := hdrlen - HeaderLen
+ if optlen > 0 && len(b) >= hdrlen {
+ if cap(h.Options) < optlen {
+ h.Options = make([]byte, optlen)
+ } else {
+ h.Options = h.Options[:optlen]
+ }
+ copy(h.Options, b[HeaderLen:hdrlen])
+ }
+ return nil
+}
+
+// ParseHeader parses b as an IPv4 header.
+func ParseHeader(b []byte) (*Header, error) {
+ h := new(Header)
+ if err := h.Parse(b); err != nil {
+ return nil, err
}
return h, nil
}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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 (
- "encoding/binary"
"errors"
"net"
- "unsafe"
)
var (
// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
freebsdVersion uint32
-
- nativeEndian binary.ByteOrder
)
-func init() {
- i := uint32(1)
- b := (*[4]byte)(unsafe.Pointer(&i))
- if b[0] == 1 {
- nativeEndian = binary.LittleEndian
- } else {
- nativeEndian = binary.BigEndian
- }
-}
-
func boolint(b bool) int {
if b {
return 1
}
return nil
}
+
+func opAddr(a net.Addr) net.Addr {
+ switch a.(type) {
+ case *net.TCPAddr:
+ if a == nil {
+ return nil
+ }
+ case *net.UDPAddr:
+ if a == nil {
+ return nil
+ }
+ case *net.IPAddr:
+ if a == nil {
+ return nil
+ }
+ }
+ return a
+}
+++ /dev/null
-// 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 nacl plan9 solaris
-
-package ipv4
-
-func (c *genericOpt) sysfd() (int, error) {
- return 0, errOpNoSupport
-}
-
-func (c *dgramOpt) sysfd() (int, error) {
- return 0, errOpNoSupport
-}
-
-func (c *payloadHandler) sysfd() (int, error) {
- return 0, errOpNoSupport
-}
-
-func (c *packetHandler) sysfd() (int, error) {
- return 0, errOpNoSupport
-}
+++ /dev/null
-// 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
-
-package ipv4
-
-import (
- "net"
- "reflect"
-)
-
-func (c *genericOpt) sysfd() (int, error) {
- switch p := c.Conn.(type) {
- case *net.TCPConn, *net.UDPConn, *net.IPConn:
- return sysfd(p)
- }
- return 0, errInvalidConnType
-}
-
-func (c *dgramOpt) sysfd() (int, error) {
- switch p := c.PacketConn.(type) {
- case *net.UDPConn, *net.IPConn:
- return sysfd(p.(net.Conn))
- }
- return 0, errInvalidConnType
-}
-
-func (c *payloadHandler) sysfd() (int, error) {
- return sysfd(c.PacketConn.(net.Conn))
-}
-
-func (c *packetHandler) sysfd() (int, error) {
- return sysfd(c.c)
-}
-
-func sysfd(c net.Conn) (int, error) {
- cv := reflect.ValueOf(c)
- switch ce := cv.Elem(); ce.Kind() {
- case reflect.Struct:
- netfd := ce.FieldByName("conn").FieldByName("fd")
- switch fe := netfd.Elem(); fe.Kind() {
- case reflect.Struct:
- fd := fe.FieldByName("sysfd")
- return int(fd.Int()), nil
- }
- }
- return 0, errInvalidConnType
-}
+++ /dev/null
-// 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"
- "reflect"
- "syscall"
-)
-
-func (c *genericOpt) sysfd() (syscall.Handle, error) {
- switch p := c.Conn.(type) {
- case *net.TCPConn, *net.UDPConn, *net.IPConn:
- return sysfd(p)
- }
- return syscall.InvalidHandle, errInvalidConnType
-}
-
-func (c *dgramOpt) sysfd() (syscall.Handle, error) {
- switch p := c.PacketConn.(type) {
- case *net.UDPConn, *net.IPConn:
- return sysfd(p.(net.Conn))
- }
- return syscall.InvalidHandle, errInvalidConnType
-}
-
-func (c *payloadHandler) sysfd() (syscall.Handle, error) {
- return sysfd(c.PacketConn.(net.Conn))
-}
-
-func (c *packetHandler) sysfd() (syscall.Handle, error) {
- return sysfd(c.c)
-}
-
-func sysfd(c net.Conn) (syscall.Handle, error) {
- cv := reflect.ValueOf(c)
- switch ce := cv.Elem(); ce.Kind() {
- case reflect.Struct:
- netfd := ce.FieldByName("conn").FieldByName("fd")
- switch fe := netfd.Elem(); fe.Kind() {
- case reflect.Struct:
- fd := fe.FieldByName("sysfd")
- return syscall.Handle(fd.Uint()), nil
- }
- }
- return syscall.InvalidHandle, errInvalidConnType
-}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
// packets. The filter belongs to a packet delivery path on a host and
// it cannot interact with forwarding packets or tunnel-outer packets.
//
-// Note: RFC 2460 defines a reasonable role model and it works not
+// Note: RFC 8200 defines a reasonable role model and it works not
// only for IPv6 but IPv4. A node means a device that implements IP.
// A router means a node that forwards IP packets not explicitly
// addressed to itself, and a host means a node that is not a router.
type ICMPFilter struct {
- sysICMPFilter
+ icmpFilter
}
// Accept accepts incoming ICMP packets including the type field value
package ipv4
-func (f *sysICMPFilter) accept(typ ICMPType) {
+func (f *icmpFilter) accept(typ ICMPType) {
f.Data &^= 1 << (uint32(typ) & 31)
}
-func (f *sysICMPFilter) block(typ ICMPType) {
+func (f *icmpFilter) block(typ ICMPType) {
f.Data |= 1 << (uint32(typ) & 31)
}
-func (f *sysICMPFilter) setAll(block bool) {
+func (f *icmpFilter) setAll(block bool) {
if block {
f.Data = 1<<32 - 1
} else {
}
}
-func (f *sysICMPFilter) willBlock(typ ICMPType) bool {
+func (f *icmpFilter) willBlock(typ ICMPType) bool {
return f.Data&(1<<(uint32(typ)&31)) != 0
}
package ipv4
-const sysSizeofICMPFilter = 0x0
+const sizeofICMPFilter = 0x0
-type sysICMPFilter struct {
+type icmpFilter struct {
}
-func (f *sysICMPFilter) accept(typ ICMPType) {
+func (f *icmpFilter) accept(typ ICMPType) {
}
-func (f *sysICMPFilter) block(typ ICMPType) {
+func (f *icmpFilter) block(typ ICMPType) {
}
-func (f *sysICMPFilter) setAll(block bool) {
+func (f *icmpFilter) setAll(block bool) {
}
-func (f *sysICMPFilter) willBlock(typ ICMPType) bool {
+func (f *icmpFilter) willBlock(typ ICMPType) bool {
return false
}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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.
import (
"net"
"syscall"
+
+ "golang.org/x/net/internal/socket"
)
+// BUG(mikio): On Windows, the ReadFrom and WriteTo methods of RawConn
+// are not implemented.
+
// A packetHandler represents the IPv4 datagram handler.
type packetHandler struct {
- c *net.IPConn
+ *net.IPConn
+ *socket.Conn
rawOpt
}
-func (c *packetHandler) ok() bool { return c != nil && c.c != nil }
+func (c *packetHandler) ok() bool { return c != nil && c.IPConn != nil && c.Conn != nil }
// ReadFrom reads an IPv4 datagram from the endpoint c, copying the
-// datagram into b. It returns the received datagram as the IPv4
+// datagram into b. It returns the received datagram as the IPv4
// header h, the payload p and the control message cm.
func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) {
if !c.ok() {
return nil, nil, nil, syscall.EINVAL
}
- oob := newControlMessage(&c.rawOpt)
- n, oobn, _, src, err := c.c.ReadMsgIP(b, oob)
- if err != nil {
- return nil, nil, nil, err
- }
- var hs []byte
- if hs, p, err = slicePacket(b[:n]); err != nil {
- return nil, nil, nil, err
- }
- if h, err = ParseHeader(hs); err != nil {
- return nil, nil, nil, err
- }
- if cm, err = parseControlMessage(oob[:oobn]); err != nil {
- return nil, nil, nil, err
- }
- if src != nil && cm != nil {
- cm.Src = src.IP
- }
- return
+ return c.readFrom(b)
}
func slicePacket(b []byte) (h, p []byte, err error) {
}
// WriteTo writes an IPv4 datagram through the endpoint c, copying the
-// datagram from the IPv4 header h and the payload p. The control
+// datagram from the IPv4 header h and the payload p. The control
// message cm allows the datagram path and the outgoing interface to be
-// specified. Currently only Darwin and Linux support this. The cm
+// specified. Currently only Darwin and Linux support this. The cm
// may be nil if control of the outgoing datagram is not required.
//
// The IPv4 header h must contain appropriate fields that include:
//
-// Version = ipv4.Version
+// Version = <must be specified>
// Len = <must be specified>
// TOS = <must be specified>
// TotalLen = <must be specified>
if !c.ok() {
return syscall.EINVAL
}
- oob := marshalControlMessage(cm)
- wh, err := h.Marshal()
- if err != nil {
- return err
- }
- dst := &net.IPAddr{}
- if cm != nil {
- if ip := cm.Dst.To4(); ip != nil {
- dst.IP = ip
- }
- }
- if dst.IP == nil {
- dst.IP = h.Dst
- }
- wh = append(wh, p...)
- _, _, err = c.c.WriteMsgIP(wh, oob, dst)
- return err
+ return c.writeTo(h, p, cm)
}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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"
+import (
+ "net"
+
+ "golang.org/x/net/internal/socket"
+)
+
+// BUG(mikio): On Windows, the ControlMessage for ReadFrom and WriteTo
+// methods of PacketConn is not implemented.
// A payloadHandler represents the IPv4 datagram payload handler.
type payloadHandler struct {
net.PacketConn
+ *socket.Conn
rawOpt
}
-func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil }
+func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil && c.Conn != nil }
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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 !plan9,!solaris,!windows
+// +build !nacl,!plan9,!windows
package ipv4
)
// ReadFrom reads a payload of the received IPv4 datagram, from the
-// endpoint c, copying the payload into b. It returns the number of
+// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, syscall.EINVAL
}
- oob := newControlMessage(&c.rawOpt)
- var oobn int
- switch c := c.PacketConn.(type) {
- case *net.UDPConn:
- if n, oobn, _, src, err = c.ReadMsgUDP(b, oob); err != nil {
- return 0, nil, nil, err
- }
- case *net.IPConn:
- if sockOpts[ssoStripHeader].name > 0 {
- if n, oobn, _, src, err = c.ReadMsgIP(b, oob); err != nil {
- return 0, nil, nil, err
- }
- } else {
- nb := make([]byte, maxHeaderLen+len(b))
- if n, oobn, _, src, err = c.ReadMsgIP(nb, oob); err != nil {
- return 0, nil, nil, err
- }
- hdrlen := int(nb[0]&0x0f) << 2
- copy(b, nb[hdrlen:])
- n -= hdrlen
- }
- default:
- return 0, nil, nil, errInvalidConnType
- }
- if cm, err = parseControlMessage(oob[:oobn]); err != nil {
- return 0, nil, nil, err
- }
- if cm != nil {
- cm.Src = netAddrToIP4(src)
- }
- return
+ return c.readFrom(b)
}
// WriteTo writes a payload of the IPv4 datagram, to the destination
-// address dst through the endpoint c, copying the payload from b. It
-// returns the number of bytes written. The control message cm allows
+// address dst through the endpoint c, copying the payload from b. It
+// returns the number of bytes written. The control message cm allows
// the datagram path and the outgoing interface to be specified.
-// Currently only Darwin and Linux support this. The cm may be nil if
+// Currently only Darwin and Linux support this. The cm may be nil if
// control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, syscall.EINVAL
}
- oob := marshalControlMessage(cm)
- if dst == nil {
- return 0, errMissingAddress
- }
- switch c := c.PacketConn.(type) {
- case *net.UDPConn:
- n, _, err = c.WriteMsgUDP(b, oob, dst.(*net.UDPAddr))
- case *net.IPConn:
- n, _, err = c.WriteMsgIP(b, oob, dst.(*net.IPAddr))
- default:
- return 0, errInvalidConnType
- }
- if err != nil {
- return 0, err
- }
- return
+ return c.writeTo(b, cm, dst)
}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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 plan9 solaris windows
+// +build nacl plan9 windows
package ipv4
)
// ReadFrom reads a payload of the received IPv4 datagram, from the
-// endpoint c, copying the payload into b. It returns the number of
+// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
}
// WriteTo writes a payload of the IPv4 datagram, to the destination
-// address dst through the endpoint c, copying the payload from b. It
-// returns the number of bytes written. The control message cm allows
+// address dst through the endpoint c, copying the payload from b. It
+// returns the number of bytes written. The control message cm allows
// the datagram path and the outgoing interface to be specified.
-// Currently only Darwin and Linux support this. The cm may be nil if
+// Currently only Darwin and Linux support this. The cm may be nil if
// control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
package ipv4
+import "golang.org/x/net/internal/socket"
+
// Sticky socket options
const (
ssoTOS = iota // header field for unicast packet
ssoLeaveSourceGroup // source-specific multicast
ssoBlockSourceGroup // any-source or source-specific multicast
ssoUnblockSourceGroup // any-source or source-specific multicast
- ssoMax
+ ssoAttachFilter // attach BPF for filtering inbound traffic
)
// Sticky socket option value types
const (
- ssoTypeByte = iota + 1
- ssoTypeInt
- ssoTypeInterface
- ssoTypeICMPFilter
- ssoTypeIPMreq
+ ssoTypeIPMreq = iota + 1
ssoTypeIPMreqn
ssoTypeGroupReq
ssoTypeGroupSourceReq
// A sockOpt represents a binding for sticky socket option.
type sockOpt struct {
- name int // option name, must be equal or greater than 1
- typ int // option value type, must be equal or greater than 1
+ socket.Option
+ typ int // hint for option value type; optional
}
+++ /dev/null
-// 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 netbsd openbsd windows
-
-package ipv4
-
-import "net"
-
-func setIPMreqInterface(mreq *sysIPMreq, ifi *net.Interface) error {
- if ifi == nil {
- return nil
- }
- ifat, err := ifi.Addrs()
- if err != nil {
- return err
- }
- for _, ifa := range ifat {
- switch ifa := ifa.(type) {
- case *net.IPAddr:
- if ip := ifa.IP.To4(); ip != nil {
- copy(mreq.Interface[:], ip)
- return nil
- }
- case *net.IPNet:
- if ip := ifa.IP.To4(); ip != nil {
- copy(mreq.Interface[:], ip)
- return nil
- }
- }
- }
- return errNoSuchInterface
-}
-
-func netIP4ToInterface(ip net.IP) (*net.Interface, error) {
- ift, err := net.Interfaces()
- if err != nil {
- return nil, err
- }
- for _, ifi := range ift {
- ifat, err := ifi.Addrs()
- if err != nil {
- return nil, err
- }
- for _, ifa := range ifat {
- switch ifa := ifa.(type) {
- case *net.IPAddr:
- if ip.Equal(ifa.IP) {
- return &ifi, nil
- }
- case *net.IPNet:
- if ip.Equal(ifa.IP) {
- return &ifi, nil
- }
- }
- }
- }
- return nil, errNoSuchInterface
-}
-
-func netInterfaceToIP4(ifi *net.Interface) (net.IP, error) {
- if ifi == nil {
- return net.IPv4zero.To4(), nil
- }
- ifat, err := ifi.Addrs()
- if err != nil {
- return nil, err
- }
- for _, ifa := range ifat {
- switch ifa := ifa.(type) {
- case *net.IPAddr:
- if ip := ifa.IP.To4(); ip != nil {
- return ip, nil
- }
- case *net.IPNet:
- if ip := ifa.IP.To4(); ip != nil {
- return ip, nil
- }
- }
- }
- return nil, errNoSuchInterface
-}
+++ /dev/null
-// 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,!netbsd,!openbsd,!windows
-
-package ipv4
-
-import "net"
-
-func setsockoptIPMreq(fd, name int, ifi *net.Interface, grp net.IP) error {
- return errOpNoSupport
-}
-
-func getsockoptInterface(fd, name int) (*net.Interface, error) {
- return nil, errOpNoSupport
-}
-
-func setsockoptInterface(fd, name int, ifi *net.Interface) error {
- return errOpNoSupport
-}
+++ /dev/null
-// 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 netbsd openbsd
-
-package ipv4
-
-import (
- "net"
- "os"
- "unsafe"
-
- "golang.org/x/net/internal/iana"
-)
-
-func setsockoptIPMreq(fd, name int, ifi *net.Interface, grp net.IP) error {
- mreq := sysIPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
- if err := setIPMreqInterface(&mreq, ifi); err != nil {
- return err
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&mreq), sysSizeofIPMreq))
-}
-
-func getsockoptInterface(fd, name int) (*net.Interface, error) {
- var b [4]byte
- l := sysSockoptLen(4)
- if err := getsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&b[0]), &l); err != nil {
- return nil, os.NewSyscallError("getsockopt", err)
- }
- ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3]))
- if err != nil {
- return nil, err
- }
- return ifi, nil
-}
-
-func setsockoptInterface(fd, name int, ifi *net.Interface) error {
- ip, err := netInterfaceToIP4(ifi)
- if err != nil {
- return err
- }
- var b [4]byte
- copy(b[:], ip)
- return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&b[0]), sysSockoptLen(4)))
-}
+++ /dev/null
-// 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"
-
- "golang.org/x/net/internal/iana"
-)
-
-func setsockoptIPMreq(fd syscall.Handle, name int, ifi *net.Interface, grp net.IP) error {
- mreq := sysIPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
- if err := setIPMreqInterface(&mreq, ifi); err != nil {
- return err
- }
- return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, iana.ProtocolIP, int32(name), (*byte)(unsafe.Pointer(&mreq)), int32(sysSizeofIPMreq)))
-}
-
-func getsockoptInterface(fd syscall.Handle, name int) (*net.Interface, error) {
- var b [4]byte
- l := int32(4)
- if err := syscall.Getsockopt(fd, iana.ProtocolIP, int32(name), (*byte)(unsafe.Pointer(&b[0])), &l); err != nil {
- return nil, os.NewSyscallError("getsockopt", err)
- }
- ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3]))
- if err != nil {
- return nil, err
- }
- return ifi, nil
-}
-
-func setsockoptInterface(fd syscall.Handle, name int, ifi *net.Interface) error {
- ip, err := netInterfaceToIP4(ifi)
- if err != nil {
- return err
- }
- var b [4]byte
- copy(b[:], ip)
- return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, iana.ProtocolIP, int32(name), (*byte)(unsafe.Pointer(&b[0])), 4))
-}
+++ /dev/null
-// Copyright 2014 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,!freebsd,!linux,!windows
-
-package ipv4
-
-import "net"
-
-func getsockoptIPMreqn(fd, name int) (*net.Interface, error) {
- return nil, errOpNoSupport
-}
-
-func setsockoptIPMreqn(fd, name int, ifi *net.Interface, grp net.IP) error {
- return errOpNoSupport
-}
+++ /dev/null
-// Copyright 2014 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 freebsd linux
-
-package ipv4
-
-import (
- "net"
- "os"
- "unsafe"
-
- "golang.org/x/net/internal/iana"
-)
-
-func getsockoptIPMreqn(fd, name int) (*net.Interface, error) {
- var mreqn sysIPMreqn
- l := sysSockoptLen(sysSizeofIPMreqn)
- if err := getsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&mreqn), &l); err != nil {
- return nil, os.NewSyscallError("getsockopt", err)
- }
- if mreqn.Ifindex == 0 {
- return nil, nil
- }
- ifi, err := net.InterfaceByIndex(int(mreqn.Ifindex))
- if err != nil {
- return nil, err
- }
- return ifi, nil
-}
-
-func setsockoptIPMreqn(fd, name int, ifi *net.Interface, grp net.IP) error {
- var mreqn sysIPMreqn
- if ifi != nil {
- mreqn.Ifindex = int32(ifi.Index)
- }
- if grp != nil {
- mreqn.Multiaddr = [4]byte{grp[0], grp[1], grp[2], grp[3]}
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&mreqn), sysSizeofIPMreqn))
-}
+++ /dev/null
-// Copyright 2014 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,!freebsd,!linux
-
-package ipv4
-
-import "net"
-
-func setsockoptGroupReq(fd, name int, ifi *net.Interface, grp net.IP) error {
- return errOpNoSupport
-}
-
-func setsockoptGroupSourceReq(fd, name int, ifi *net.Interface, grp, src net.IP) error {
- return errOpNoSupport
-}
+++ /dev/null
-// Copyright 2014 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 freebsd linux
-
-package ipv4
-
-import (
- "net"
- "os"
- "unsafe"
-
- "golang.org/x/net/internal/iana"
-)
-
-var freebsd32o64 bool
-
-func setsockoptGroupReq(fd, name int, ifi *net.Interface, grp net.IP) error {
- var gr sysGroupReq
- if ifi != nil {
- gr.Interface = uint32(ifi.Index)
- }
- gr.setGroup(grp)
- var p unsafe.Pointer
- var l sysSockoptLen
- if freebsd32o64 {
- var d [sysSizeofGroupReq + 4]byte
- s := (*[sysSizeofGroupReq]byte)(unsafe.Pointer(&gr))
- copy(d[:4], s[:4])
- copy(d[8:], s[4:])
- p = unsafe.Pointer(&d[0])
- l = sysSizeofGroupReq + 4
- } else {
- p = unsafe.Pointer(&gr)
- l = sysSizeofGroupReq
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, p, l))
-}
-
-func setsockoptGroupSourceReq(fd, name int, ifi *net.Interface, grp, src net.IP) error {
- var gsr sysGroupSourceReq
- if ifi != nil {
- gsr.Interface = uint32(ifi.Index)
- }
- gsr.setSourceGroup(grp, src)
- var p unsafe.Pointer
- var l sysSockoptLen
- if freebsd32o64 {
- var d [sysSizeofGroupSourceReq + 4]byte
- s := (*[sysSizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))
- copy(d[:4], s[:4])
- copy(d[8:], s[4:])
- p = unsafe.Pointer(&d[0])
- l = sysSizeofGroupSourceReq + 4
- } else {
- p = unsafe.Pointer(&gsr)
- l = sysSizeofGroupSourceReq
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, p, l))
-}
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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 nacl plan9 solaris
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
package ipv4
-func setInt(fd int, opt *sockOpt, v int) error {
+import (
+ "net"
+
+ "golang.org/x/net/bpf"
+ "golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
+ return nil, errOpNoSupport
+}
+
+func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
+ return errOpNoSupport
+}
+
+func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
+ return nil, errOpNoSupport
+}
+
+func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
+ return errOpNoSupport
+}
+
+func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
+ return errOpNoSupport
+}
+
+func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
+ return errOpNoSupport
+}
+
+func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
return errOpNoSupport
}
+++ /dev/null
-// 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
-
-package ipv4
-
-import (
- "net"
- "os"
- "unsafe"
-
- "golang.org/x/net/internal/iana"
-)
-
-func getInt(fd int, opt *sockOpt) (int, error) {
- if opt.name < 1 || (opt.typ != ssoTypeByte && opt.typ != ssoTypeInt) {
- return 0, errOpNoSupport
- }
- var i int32
- var b byte
- p := unsafe.Pointer(&i)
- l := sysSockoptLen(4)
- if opt.typ == ssoTypeByte {
- p = unsafe.Pointer(&b)
- l = sysSockoptLen(1)
- }
- if err := getsockopt(fd, iana.ProtocolIP, opt.name, p, &l); err != nil {
- return 0, os.NewSyscallError("getsockopt", err)
- }
- if opt.typ == ssoTypeByte {
- return int(b), nil
- }
- return int(i), nil
-}
-
-func setInt(fd int, opt *sockOpt, v int) error {
- if opt.name < 1 || (opt.typ != ssoTypeByte && opt.typ != ssoTypeInt) {
- return errOpNoSupport
- }
- i := int32(v)
- var b byte
- p := unsafe.Pointer(&i)
- l := sysSockoptLen(4)
- if opt.typ == ssoTypeByte {
- b = byte(v)
- p = unsafe.Pointer(&b)
- l = sysSockoptLen(1)
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, opt.name, p, l))
-}
-
-func getInterface(fd int, opt *sockOpt) (*net.Interface, error) {
- if opt.name < 1 {
- return nil, errOpNoSupport
- }
- switch opt.typ {
- case ssoTypeInterface:
- return getsockoptInterface(fd, opt.name)
- case ssoTypeIPMreqn:
- return getsockoptIPMreqn(fd, opt.name)
- default:
- return nil, errOpNoSupport
- }
-}
-
-func setInterface(fd int, opt *sockOpt, ifi *net.Interface) error {
- if opt.name < 1 {
- return errOpNoSupport
- }
- switch opt.typ {
- case ssoTypeInterface:
- return setsockoptInterface(fd, opt.name, ifi)
- case ssoTypeIPMreqn:
- return setsockoptIPMreqn(fd, opt.name, ifi, nil)
- default:
- return errOpNoSupport
- }
-}
-
-func getICMPFilter(fd int, opt *sockOpt) (*ICMPFilter, error) {
- if opt.name < 1 || opt.typ != ssoTypeICMPFilter {
- return nil, errOpNoSupport
- }
- var f ICMPFilter
- l := sysSockoptLen(sysSizeofICMPFilter)
- if err := getsockopt(fd, iana.ProtocolReserved, opt.name, unsafe.Pointer(&f.sysICMPFilter), &l); err != nil {
- return nil, os.NewSyscallError("getsockopt", err)
- }
- return &f, nil
-}
-
-func setICMPFilter(fd int, opt *sockOpt, f *ICMPFilter) error {
- if opt.name < 1 || opt.typ != ssoTypeICMPFilter {
- return errOpNoSupport
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolReserved, opt.name, unsafe.Pointer(&f.sysICMPFilter), sysSizeofICMPFilter))
-}
-
-func setGroup(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
- if opt.name < 1 {
- return errOpNoSupport
- }
- switch opt.typ {
- case ssoTypeIPMreq:
- return setsockoptIPMreq(fd, opt.name, ifi, grp)
- case ssoTypeIPMreqn:
- return setsockoptIPMreqn(fd, opt.name, ifi, grp)
- case ssoTypeGroupReq:
- return setsockoptGroupReq(fd, opt.name, ifi, grp)
- default:
- return errOpNoSupport
- }
-}
-
-func setSourceGroup(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
- if opt.name < 1 || opt.typ != ssoTypeGroupSourceReq {
- return errOpNoSupport
- }
- return setsockoptGroupSourceReq(fd, opt.name, ifi, grp, src)
-}
+++ /dev/null
-// 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"
-
- "golang.org/x/net/internal/iana"
-)
-
-func getInt(fd syscall.Handle, opt *sockOpt) (int, error) {
- if opt.name < 1 || opt.typ != ssoTypeInt {
- return 0, errOpNoSupport
- }
- var i int32
- l := int32(4)
- if err := syscall.Getsockopt(fd, iana.ProtocolIP, int32(opt.name), (*byte)(unsafe.Pointer(&i)), &l); err != nil {
- return 0, os.NewSyscallError("getsockopt", err)
- }
- return int(i), nil
-}
-
-func setInt(fd syscall.Handle, opt *sockOpt, v int) error {
- if opt.name < 1 || opt.typ != ssoTypeInt {
- return errOpNoSupport
- }
- i := int32(v)
- return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, iana.ProtocolIP, int32(opt.name), (*byte)(unsafe.Pointer(&i)), 4))
-}
-
-func getInterface(fd syscall.Handle, opt *sockOpt) (*net.Interface, error) {
- if opt.name < 1 || opt.typ != ssoTypeInterface {
- return nil, errOpNoSupport
- }
- return getsockoptInterface(fd, opt.name)
-}
-
-func setInterface(fd syscall.Handle, opt *sockOpt, ifi *net.Interface) error {
- if opt.name < 1 || opt.typ != ssoTypeInterface {
- return errOpNoSupport
- }
- return setsockoptInterface(fd, opt.name, ifi)
-}
-
-func getICMPFilter(fd syscall.Handle, opt *sockOpt) (*ICMPFilter, error) {
- return nil, errOpNoSupport
-}
-
-func setICMPFilter(fd syscall.Handle, opt *sockOpt, f *ICMPFilter) error {
- return errOpNoSupport
-}
-
-func setGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
- if opt.name < 1 || opt.typ != ssoTypeIPMreq {
- return errOpNoSupport
- }
- return setsockoptIPMreq(fd, opt.name, ifi, grp)
-}
-
-func setSourceGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
- // TODO(mikio): implement this
- return errOpNoSupport
-}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build dragonfly netbsd
+// +build netbsd openbsd
package ipv4
import (
"net"
"syscall"
-)
-type sysSockoptLen int32
+ "golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
+)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
}
- sockOpts = [ssoMax]sockOpt{
- ssoTOS: {sysIP_TOS, ssoTypeInt},
- ssoTTL: {sysIP_TTL, ssoTypeInt},
- ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte},
- ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
- ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt},
- ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
- ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt},
- ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt},
- ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
- ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
- ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
+ sockOpts = map[int]*sockOpt{
+ ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+ ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+ ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 1}},
+ ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: 4}},
+ ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 1}},
+ ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVTTL, Len: 4}},
+ ssoReceiveDst: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVDSTADDR, Len: 4}},
+ ssoReceiveInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVIF, Len: 4}},
+ ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+ ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
+ ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
}
)
import (
"net"
+ "strconv"
+ "strings"
"syscall"
"unsafe"
-)
-type sysSockoptLen int32
+ "golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
+)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
}
- sockOpts = [ssoMax]sockOpt{
- ssoTOS: {sysIP_TOS, ssoTypeInt},
- ssoTTL: {sysIP_TTL, ssoTypeInt},
- ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte},
- ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
- ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt},
- ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
- ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt},
- ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt},
- ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
- ssoStripHeader: {sysIP_STRIPHDR, ssoTypeInt},
- ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
- ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
+ sockOpts = map[int]*sockOpt{
+ ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+ ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+ ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 1}},
+ ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: 4}},
+ ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 4}},
+ ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVTTL, Len: 4}},
+ ssoReceiveDst: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVDSTADDR, Len: 4}},
+ ssoReceiveInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVIF, Len: 4}},
+ ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+ ssoStripHeader: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_STRIPHDR, Len: 4}},
+ ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
+ ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
}
)
func init() {
// Seems like kern.osreldate is veiled on latest OS X. We use
// kern.osrelease instead.
- osver, err := syscall.Sysctl("kern.osrelease")
+ s, err := syscall.Sysctl("kern.osrelease")
if err != nil {
return
}
- var i int
- for i = range osver {
- if osver[i] == '.' {
- break
- }
+ ss := strings.Split(s, ".")
+ if len(ss) == 0 {
+ return
}
// The IP_PKTINFO and protocol-independent multicast API were
- // introduced in OS X 10.7 (Darwin 11.0.0). But it looks like
- // those features require OS X 10.8 (Darwin 12.0.0) and above.
+ // introduced in OS X 10.7 (Darwin 11). But it looks like
+ // those features require OS X 10.8 (Darwin 12) or above.
// See http://support.apple.com/kb/HT1633.
- if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '2' {
- ctlOpts[ctlPacketInfo].name = sysIP_PKTINFO
- ctlOpts[ctlPacketInfo].length = sysSizeofInetPktinfo
- ctlOpts[ctlPacketInfo].marshal = marshalPacketInfo
- ctlOpts[ctlPacketInfo].parse = parsePacketInfo
- sockOpts[ssoPacketInfo].name = sysIP_RECVPKTINFO
- sockOpts[ssoPacketInfo].typ = ssoTypeInt
- sockOpts[ssoMulticastInterface].typ = ssoTypeIPMreqn
- sockOpts[ssoJoinGroup].name = sysMCAST_JOIN_GROUP
- sockOpts[ssoJoinGroup].typ = ssoTypeGroupReq
- sockOpts[ssoLeaveGroup].name = sysMCAST_LEAVE_GROUP
- sockOpts[ssoLeaveGroup].typ = ssoTypeGroupReq
- sockOpts[ssoJoinSourceGroup].name = sysMCAST_JOIN_SOURCE_GROUP
- sockOpts[ssoJoinSourceGroup].typ = ssoTypeGroupSourceReq
- sockOpts[ssoLeaveSourceGroup].name = sysMCAST_LEAVE_SOURCE_GROUP
- sockOpts[ssoLeaveSourceGroup].typ = ssoTypeGroupSourceReq
- sockOpts[ssoBlockSourceGroup].name = sysMCAST_BLOCK_SOURCE
- sockOpts[ssoBlockSourceGroup].typ = ssoTypeGroupSourceReq
- sockOpts[ssoUnblockSourceGroup].name = sysMCAST_UNBLOCK_SOURCE
- sockOpts[ssoUnblockSourceGroup].typ = ssoTypeGroupSourceReq
+ if mjver, err := strconv.Atoi(ss[0]); err != nil || mjver < 12 {
+ return
}
+ ctlOpts[ctlPacketInfo].name = sysIP_PKTINFO
+ ctlOpts[ctlPacketInfo].length = sizeofInetPktinfo
+ ctlOpts[ctlPacketInfo].marshal = marshalPacketInfo
+ ctlOpts[ctlPacketInfo].parse = parsePacketInfo
+ sockOpts[ssoPacketInfo] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVPKTINFO, Len: 4}}
+ sockOpts[ssoMulticastInterface] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: sizeofIPMreqn}, typ: ssoTypeIPMreqn}
+ sockOpts[ssoJoinGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq}
+ sockOpts[ssoLeaveGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq}
+ sockOpts[ssoJoinSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+ sockOpts[ssoLeaveSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+ sockOpts[ssoBlockSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+ sockOpts[ssoUnblockSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
}
-func (pi *sysInetPktinfo) setIfindex(i int) {
+func (pi *inetPktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
-func (gr *sysGroupReq) setGroup(grp net.IP) {
- sa := (*sysSockaddrInet)(unsafe.Pointer(&gr.Pad_cgo_0[0]))
- sa.Len = sysSizeofSockaddrInet
+func (gr *groupReq) setGroup(grp net.IP) {
+ sa := (*sockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gr)) + 4))
+ sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
}
-func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
- sa := (*sysSockaddrInet)(unsafe.Pointer(&gsr.Pad_cgo_0[0]))
- sa.Len = sysSizeofSockaddrInet
+func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
+ sa := (*sockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 4))
+ sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
- sa = (*sysSockaddrInet)(unsafe.Pointer(&gsr.Pad_cgo_1[0]))
- sa.Len = sysSizeofSockaddrInet
+ sa = (*sockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 132))
+ sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], src)
}
"strings"
"syscall"
"unsafe"
-)
-type sysSockoptLen int32
+ "golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
+)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
}
- sockOpts = [ssoMax]sockOpt{
- ssoTOS: {sysIP_TOS, ssoTypeInt},
- ssoTTL: {sysIP_TTL, ssoTypeInt},
- ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte},
- ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
- ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt},
- ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
- ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt},
- ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt},
- ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
- ssoJoinGroup: {sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
- ssoLeaveGroup: {sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
- ssoJoinSourceGroup: {sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
- ssoLeaveSourceGroup: {sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
- ssoBlockSourceGroup: {sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
- ssoUnblockSourceGroup: {sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
+ sockOpts = map[int]*sockOpt{
+ ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+ ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+ ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 1}},
+ ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: 4}},
+ ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 4}},
+ ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVTTL, Len: 4}},
+ ssoReceiveDst: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVDSTADDR, Len: 4}},
+ ssoReceiveInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVIF, Len: 4}},
+ ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+ ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+ ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+ ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
}
)
func init() {
freebsdVersion, _ = syscall.SysctlUint32("kern.osreldate")
if freebsdVersion >= 1000000 {
- sockOpts[ssoMulticastInterface].typ = ssoTypeIPMreqn
+ sockOpts[ssoMulticastInterface] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: sizeofIPMreqn}, typ: ssoTypeIPMreqn}
}
if runtime.GOOS == "freebsd" && runtime.GOARCH == "386" {
archs, _ := syscall.Sysctl("kern.supported_archs")
}
}
-func (gr *sysGroupReq) setGroup(grp net.IP) {
- sa := (*sysSockaddrInet)(unsafe.Pointer(&gr.Group))
- sa.Len = sysSizeofSockaddrInet
+func (gr *groupReq) setGroup(grp net.IP) {
+ sa := (*sockaddrInet)(unsafe.Pointer(&gr.Group))
+ sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
}
-func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
- sa := (*sysSockaddrInet)(unsafe.Pointer(&gsr.Group))
- sa.Len = sysSizeofSockaddrInet
+func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
+ sa := (*sockaddrInet)(unsafe.Pointer(&gsr.Group))
+ sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
- sa = (*sysSockaddrInet)(unsafe.Pointer(&gsr.Source))
- sa.Len = sysSizeofSockaddrInet
+ sa = (*sockaddrInet)(unsafe.Pointer(&gsr.Source))
+ sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], src)
}
"net"
"syscall"
"unsafe"
-)
-type sysSockoptLen int32
+ "golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
+)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTTL: {sysIP_TTL, 1, marshalTTL, parseTTL},
- ctlPacketInfo: {sysIP_PKTINFO, sysSizeofInetPktinfo, marshalPacketInfo, parsePacketInfo},
+ ctlPacketInfo: {sysIP_PKTINFO, sizeofInetPktinfo, marshalPacketInfo, parsePacketInfo},
}
- sockOpts = [ssoMax]sockOpt{
- ssoTOS: {sysIP_TOS, ssoTypeInt},
- ssoTTL: {sysIP_TTL, ssoTypeInt},
- ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeInt},
- ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeIPMreqn},
- ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt},
- ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
- ssoPacketInfo: {sysIP_PKTINFO, ssoTypeInt},
- ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
- ssoICMPFilter: {sysICMP_FILTER, ssoTypeICMPFilter},
- ssoJoinGroup: {sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
- ssoLeaveGroup: {sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
- ssoJoinSourceGroup: {sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
- ssoLeaveSourceGroup: {sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
- ssoBlockSourceGroup: {sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
- ssoUnblockSourceGroup: {sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
+ sockOpts = map[int]*sockOpt{
+ ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+ ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+ ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 4}},
+ ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: sizeofIPMreqn}, typ: ssoTypeIPMreqn},
+ ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 4}},
+ ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVTTL, Len: 4}},
+ ssoPacketInfo: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_PKTINFO, Len: 4}},
+ ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+ ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolReserved, Name: sysICMP_FILTER, Len: sizeofICMPFilter}},
+ ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+ ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+ ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoAttachFilter: {Option: socket.Option{Level: sysSOL_SOCKET, Name: sysSO_ATTACH_FILTER, Len: sizeofSockFprog}},
}
)
-func (pi *sysInetPktinfo) setIfindex(i int) {
+func (pi *inetPktinfo) setIfindex(i int) {
pi.Ifindex = int32(i)
}
-func (gr *sysGroupReq) setGroup(grp net.IP) {
- sa := (*sysSockaddrInet)(unsafe.Pointer(&gr.Group))
+func (gr *groupReq) setGroup(grp net.IP) {
+ sa := (*sockaddrInet)(unsafe.Pointer(&gr.Group))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
}
-func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
- sa := (*sysSockaddrInet)(unsafe.Pointer(&gsr.Group))
+func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
+ sa := (*sockaddrInet)(unsafe.Pointer(&gsr.Group))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
- sa = (*sysSockaddrInet)(unsafe.Pointer(&gsr.Source))
+ sa = (*sockaddrInet)(unsafe.Pointer(&gsr.Source))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], src)
}
+++ /dev/null
-// Copyright 2014 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"
- "syscall"
-)
-
-type sysSockoptLen int32
-
-var (
- ctlOpts = [ctlMax]ctlOpt{
- ctlTTL: {sysIP_RECVTTL, 1, marshalTTL, parseTTL},
- ctlDst: {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
- ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
- }
-
- sockOpts = [ssoMax]sockOpt{
- ssoTOS: {sysIP_TOS, ssoTypeInt},
- ssoTTL: {sysIP_TTL, ssoTypeInt},
- ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte},
- ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
- ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeByte},
- ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
- ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt},
- ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt},
- ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
- ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
- ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
- }
-)
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nacl plan9 solaris
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
package ipv4
-type sysSockoptLen int32
-
var (
ctlOpts = [ctlMax]ctlOpt{}
- sockOpts = [ssoMax]sockOpt{}
+ sockOpts = map[int]*sockOpt{}
)
package ipv4
+import (
+ "golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
+)
+
const (
// See ws2tcpip.h.
sysIP_OPTIONS = 0x1
sysIP_DROP_SOURCE_MEMBERSHIP = 0x10
sysIP_PKTINFO = 0x13
- sysSizeofInetPktinfo = 0x8
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqSource = 0xc
+ sizeofInetPktinfo = 0x8
+ sizeofIPMreq = 0x8
+ sizeofIPMreqSource = 0xc
)
-type sysInetPktinfo struct {
+type inetPktinfo struct {
Addr [4]byte
Ifindex int32
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte
Interface [4]byte
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr [4]byte
Sourceaddr [4]byte
Interface [4]byte
var (
ctlOpts = [ctlMax]ctlOpt{}
- sockOpts = [ssoMax]sockOpt{
- ssoTOS: {sysIP_TOS, ssoTypeInt},
- ssoTTL: {sysIP_TTL, ssoTypeInt},
- ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeInt},
- ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
- ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt},
- ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
- ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
+ sockOpts = map[int]*sockOpt{
+ ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+ ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+ ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 4}},
+ ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: 4}},
+ ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 4}},
+ ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+ ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
+ ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
}
)
-func (pi *sysInetPktinfo) setIfindex(i int) {
+func (pi *inetPktinfo) setIfindex(i int) {
pi.Ifindex = int32(i)
}
+++ /dev/null
-// Copyright 2014 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 (
- "syscall"
- "unsafe"
-)
-
-const (
- sysGETSOCKOPT = 0xf
- sysSETSOCKOPT = 0xe
-)
-
-func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
-
-func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error {
- if _, errno := socketcall(sysGETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
- return error(errno)
- }
- return nil
-}
-
-func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error {
- if _, errno := socketcall(sysSETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
- return error(errno)
- }
- return nil
-}
+++ /dev/null
-// Copyright 2014 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,!386 netbsd openbsd
-
-package ipv4
-
-import (
- "syscall"
- "unsafe"
-)
-
-func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error {
- if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
- return error(errno)
- }
- return nil
-}
-
-func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error {
- if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
- return error(errno)
- }
- return nil
-}
+++ /dev/null
-// Copyright 2014 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 go1.2
-
-TEXT ·socketcall(SB),4,$0-36
- JMP syscall·socketcall(SB)
sysMCAST_BLOCK_SOURCE = 0x54
sysMCAST_UNBLOCK_SOURCE = 0x55
- sysSizeofSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
- sysSizeofInetPktinfo = 0xc
+ sizeofSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
+ sizeofInetPktinfo = 0xc
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x84
- sysSizeofGroupSourceReq = 0x104
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x84
+ sizeofGroupSourceReq = 0x104
)
-type sysSockaddrStorage struct {
+type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_pad2 [112]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Zero [8]int8
}
-type sysInetPktinfo struct {
+type inetPktinfo struct {
Ifindex uint32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [128]byte
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [128]byte
Pad_cgo_1 [128]byte
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_dragonfly.go
-// +build dragonfly
-
package ipv4
const (
sysIP_ADD_MEMBERSHIP = 0xc
sysIP_DROP_MEMBERSHIP = 0xd
- sysSizeofIPMreq = 0x8
+ sizeofIPMreq = 0x8
)
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
sysMCAST_BLOCK_SOURCE = 0x54
sysMCAST_UNBLOCK_SOURCE = 0x55
- sysSizeofSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
+ sizeofSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x84
- sysSizeofGroupSourceReq = 0x104
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x84
+ sizeofGroupSourceReq = 0x104
)
-type sysSockaddrStorage struct {
+type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_pad2 [112]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Zero [8]int8
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
- Group sysSockaddrStorage
+ Group sockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
- Group sysSockaddrStorage
- Source sysSockaddrStorage
+ Group sockaddrStorage
+ Source sockaddrStorage
}
sysMCAST_BLOCK_SOURCE = 0x54
sysMCAST_UNBLOCK_SOURCE = 0x55
- sysSizeofSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
+ sizeofSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
)
-type sysSockaddrStorage struct {
+type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_pad2 [112]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Zero [8]int8
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysSockaddrStorage
+ Group sockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysSockaddrStorage
- Source sysSockaddrStorage
+ Group sockaddrStorage
+ Source sockaddrStorage
}
sysMCAST_BLOCK_SOURCE = 0x54
sysMCAST_UNBLOCK_SOURCE = 0x55
- sysSizeofSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
+ sizeofSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
)
-type sysSockaddrStorage struct {
+type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_pad2 [112]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Zero [8]int8
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysSockaddrStorage
+ Group sockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysSockaddrStorage
- Source sysSockaddrStorage
+ Group sockaddrStorage
+ Source sockaddrStorage
}
sysSO_EE_ORIGIN_TXSTATUS = 0x4
sysSO_EE_ORIGIN_TIMESTAMPING = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
- sysSizeofInetPktinfo = 0xc
- sysSizeofSockExtendedErr = 0x10
-
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x84
- sysSizeofGroupSourceReq = 0x104
-
- sysSizeofICMPFilter = 0x4
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
+ sizeofInetPktinfo = 0xc
+ sizeofSockExtendedErr = 0x10
+
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x84
+ sizeofGroupSourceReq = 0x104
+
+ sizeofICMPFilter = 0x4
+
+ sizeofSockFprog = 0x8
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
-type sysInetPktinfo struct {
+type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
-type sysSockExtendedErr struct {
+type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Data uint32
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPFilter struct {
+type icmpFilter struct {
Data uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [2]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
sysSO_EE_ORIGIN_TXSTATUS = 0x4
sysSO_EE_ORIGIN_TIMESTAMPING = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
- sysSizeofInetPktinfo = 0xc
- sysSizeofSockExtendedErr = 0x10
-
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
-
- sysSizeofICMPFilter = 0x4
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
+ sizeofInetPktinfo = 0xc
+ sizeofSockExtendedErr = 0x10
+
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
+
+ sizeofICMPFilter = 0x4
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
-type sysInetPktinfo struct {
+type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
-type sysSockExtendedErr struct {
+type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Data uint32
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPFilter struct {
+type icmpFilter struct {
Data uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
sysSO_EE_ORIGIN_TXSTATUS = 0x4
sysSO_EE_ORIGIN_TIMESTAMPING = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
- sysSizeofInetPktinfo = 0xc
- sysSizeofSockExtendedErr = 0x10
-
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x84
- sysSizeofGroupSourceReq = 0x104
-
- sysSizeofICMPFilter = 0x4
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
+ sizeofInetPktinfo = 0xc
+ sizeofSockExtendedErr = 0x10
+
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x84
+ sizeofGroupSourceReq = 0x104
+
+ sizeofICMPFilter = 0x4
+
+ sizeofSockFprog = 0x8
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
-type sysInetPktinfo struct {
+type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
-type sysSockExtendedErr struct {
+type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Data uint32
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPFilter struct {
+type icmpFilter struct {
Data uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [2]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_linux.go
-// +build linux,arm64
-
package ipv4
const (
sysSO_EE_ORIGIN_TXSTATUS = 0x4
sysSO_EE_ORIGIN_TIMESTAMPING = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
- sysSizeofInetPktinfo = 0xc
- sysSizeofSockExtendedErr = 0x10
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
+ sizeofInetPktinfo = 0xc
+ sizeofSockExtendedErr = 0x10
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPFilter = 0x4
+ sizeofICMPFilter = 0x4
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
-type sysInetPktinfo struct {
+type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
-type sysSockExtendedErr struct {
+type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Data uint32
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPFilter struct {
+type icmpFilter struct {
Data uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_linux.go
-// +build linux,mips64
-
package ipv4
const (
sysSO_EE_ORIGIN_TXSTATUS = 0x4
sysSO_EE_ORIGIN_TIMESTAMPING = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
- sysSizeofInetPktinfo = 0xc
- sysSizeofSockExtendedErr = 0x10
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
+ sizeofInetPktinfo = 0xc
+ sizeofSockExtendedErr = 0x10
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPFilter = 0x4
+ sizeofICMPFilter = 0x4
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
-type sysInetPktinfo struct {
+type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
-type sysSockExtendedErr struct {
+type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Data uint32
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPFilter struct {
+type icmpFilter struct {
Data uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_linux.go
-// +build linux,mips64le
-
package ipv4
const (
sysSO_EE_ORIGIN_TXSTATUS = 0x4
sysSO_EE_ORIGIN_TIMESTAMPING = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
- sysSizeofInetPktinfo = 0xc
- sysSizeofSockExtendedErr = 0x10
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
+ sizeofInetPktinfo = 0xc
+ sizeofSockExtendedErr = 0x10
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPFilter = 0x4
+ sizeofICMPFilter = 0x4
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
-type sysInetPktinfo struct {
+type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
-type sysSockExtendedErr struct {
+type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Data uint32
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPFilter struct {
+type icmpFilter struct {
Data uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_linux.go
-// +build linux,ppc64
-
package ipv4
const (
sysSO_EE_ORIGIN_TXSTATUS = 0x4
sysSO_EE_ORIGIN_TIMESTAMPING = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
- sysSizeofInetPktinfo = 0xc
- sysSizeofSockExtendedErr = 0x10
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
+ sizeofInetPktinfo = 0xc
+ sizeofSockExtendedErr = 0x10
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPFilter = 0x4
+ sizeofICMPFilter = 0x4
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
-type sysInetPktinfo struct {
+type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
-type sysSockExtendedErr struct {
+type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Data uint32
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPFilter struct {
+type icmpFilter struct {
Data uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_linux.go
-// +build linux,ppc64le
-
package ipv4
const (
sysSO_EE_ORIGIN_TXSTATUS = 0x4
sysSO_EE_ORIGIN_TIMESTAMPING = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet = 0x10
- sysSizeofInetPktinfo = 0xc
- sysSizeofSockExtendedErr = 0x10
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet = 0x10
+ sizeofInetPktinfo = 0xc
+ sizeofSockExtendedErr = 0x10
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqn = 0xc
- sysSizeofIPMreqSource = 0xc
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPMreq = 0x8
+ sizeofIPMreqn = 0xc
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPFilter = 0x4
+ sizeofICMPFilter = 0x4
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet struct {
+type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
-type sysInetPktinfo struct {
+type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
-type sysSockExtendedErr struct {
+type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Data uint32
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqn struct {
+type ipMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPFilter struct {
+type icmpFilter struct {
Data uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
sysIP_ADD_MEMBERSHIP = 0xc
sysIP_DROP_MEMBERSHIP = 0xd
- sysSizeofIPMreq = 0x8
+ sizeofIPMreq = 0x8
)
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
sysIP_ADD_MEMBERSHIP = 0xc
sysIP_DROP_MEMBERSHIP = 0xd
- sysSizeofIPMreq = 0x8
+ sizeofIPMreq = 0x8
)
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_solaris.go
-// +build solaris
-
package ipv4
const (
- sysIP_OPTIONS = 0x1
- sysIP_HDRINCL = 0x2
- sysIP_TOS = 0x3
- sysIP_TTL = 0x4
- sysIP_RECVOPTS = 0x5
- sysIP_RECVRETOPTS = 0x6
- sysIP_RECVDSTADDR = 0x7
- sysIP_RETOPTS = 0x8
- sysIP_RECVIF = 0x9
- sysIP_RECVSLLA = 0xa
- sysIP_RECVTTL = 0xb
- sysIP_NEXTHOP = 0x19
- sysIP_PKTINFO = 0x1a
- sysIP_RECVPKTINFO = 0x1a
- sysIP_DONTFRAG = 0x1b
- sysIP_BOUND_IF = 0x41
- sysIP_UNSPEC_SRC = 0x42
- sysIP_BROADCAST_TTL = 0x43
- sysIP_DHCPINIT_IF = 0x45
+ sysIP_OPTIONS = 0x1
+ sysIP_HDRINCL = 0x2
+ sysIP_TOS = 0x3
+ sysIP_TTL = 0x4
+ sysIP_RECVOPTS = 0x5
+ sysIP_RECVRETOPTS = 0x6
+ sysIP_RECVDSTADDR = 0x7
+ sysIP_RETOPTS = 0x8
+ sysIP_RECVIF = 0x9
+ sysIP_RECVSLLA = 0xa
+ sysIP_RECVTTL = 0xb
sysIP_MULTICAST_IF = 0x10
sysIP_MULTICAST_TTL = 0x11
sysIP_UNBLOCK_SOURCE = 0x16
sysIP_ADD_SOURCE_MEMBERSHIP = 0x17
sysIP_DROP_SOURCE_MEMBERSHIP = 0x18
+ sysIP_NEXTHOP = 0x19
+
+ sysIP_PKTINFO = 0x1a
+ sysIP_RECVPKTINFO = 0x1a
+ sysIP_DONTFRAG = 0x1b
+
+ sysIP_BOUND_IF = 0x41
+ sysIP_UNSPEC_SRC = 0x42
+ sysIP_BROADCAST_TTL = 0x43
+ sysIP_DHCPINIT_IF = 0x45
- sysSizeofInetPktinfo = 0xc
+ sysIP_REUSEADDR = 0x104
+ sysIP_DONTROUTE = 0x105
+ sysIP_BROADCAST = 0x106
- sysSizeofIPMreq = 0x8
- sysSizeofIPMreqSource = 0xc
+ sysMCAST_JOIN_GROUP = 0x29
+ sysMCAST_LEAVE_GROUP = 0x2a
+ sysMCAST_BLOCK_SOURCE = 0x2b
+ sysMCAST_UNBLOCK_SOURCE = 0x2c
+ sysMCAST_JOIN_SOURCE_GROUP = 0x2d
+ sysMCAST_LEAVE_SOURCE_GROUP = 0x2e
+
+ sizeofSockaddrStorage = 0x100
+ sizeofSockaddrInet = 0x10
+ sizeofInetPktinfo = 0xc
+
+ sizeofIPMreq = 0x8
+ sizeofIPMreqSource = 0xc
+ sizeofGroupReq = 0x104
+ sizeofGroupSourceReq = 0x204
)
-type sysInetPktinfo struct {
+type sockaddrStorage struct {
+ Family uint16
+ X_ss_pad1 [6]int8
+ X_ss_align float64
+ X_ss_pad2 [240]int8
+}
+
+type sockaddrInet struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type inetPktinfo struct {
Ifindex uint32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
-type sysIPMreq struct {
+type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
-type sysIPMreqSource struct {
+type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
+
+type groupReq struct {
+ Interface uint32
+ Pad_cgo_0 [256]byte
+}
+
+type groupSourceReq struct {
+ Interface uint32
+ Pad_cgo_0 [256]byte
+ Pad_cgo_1 [256]byte
+}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
"fmt"
"net"
"sync"
+
+ "golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
// Note that RFC 3542 obsoletes RFC 2292 but OS X Snow Leopard and the
-// former still support RFC 2292 only. Please be aware that almost
+// former still support RFC 2292 only. Please be aware that almost
// all protocol implementations prohibit using a combination of RFC
// 2292 and RFC 3542 for some practical reasons.
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)
}
+// Marshal returns the binary encoding of cm.
+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
+}
+
+// Parse parses b as a control message and stores the result in cm.
+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 {
+ case typ == ctlOpts[ctlTrafficClass].name && l >= ctlOpts[ctlTrafficClass].length:
+ ctlOpts[ctlTrafficClass].parse(cm, m.Data(l))
+ case typ == ctlOpts[ctlHopLimit].name && l >= ctlOpts[ctlHopLimit].length:
+ ctlOpts[ctlHopLimit].parse(cm, m.Data(l))
+ case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length:
+ ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
+ case typ == ctlOpts[ctlPathMTU].name && l >= ctlOpts[ctlPathMTU].length:
+ ctlOpts[ctlPathMTU].parse(cm, m.Data(l))
+ }
+ }
+ return nil
+}
+
+// NewControlMessage returns a new control message.
+//
+// The returned message is large enough for options specified by cf.
+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
+}
+
// Ancillary data socket options
const (
ctlTrafficClass = iota // header field
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 ipv6
import (
- "syscall"
"unsafe"
"golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
func marshal2292HopLimit(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIPv6
- m.Type = sysIPV6_2292HOPLIMIT
- m.SetLen(syscall.CmsgLen(4))
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIPv6, sysIPV6_2292HOPLIMIT, 4)
if cm != nil {
- data := b[syscall.CmsgLen(0):]
- nativeEndian.PutUint32(data[:4], uint32(cm.HopLimit))
+ socket.NativeEndian.PutUint32(m.Data(4), uint32(cm.HopLimit))
}
- return b[syscall.CmsgSpace(4):]
+ return m.Next(4)
}
func marshal2292PacketInfo(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIPv6
- m.Type = sysIPV6_2292PKTINFO
- m.SetLen(syscall.CmsgLen(sysSizeofInet6Pktinfo))
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIPv6, sysIPV6_2292PKTINFO, sizeofInet6Pktinfo)
if cm != nil {
- pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
+ pi := (*inet6Pktinfo)(unsafe.Pointer(&m.Data(sizeofInet6Pktinfo)[0]))
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
copy(pi.Addr[:], ip)
}
pi.setIfindex(cm.IfIndex)
}
}
- return b[syscall.CmsgSpace(sysSizeofInet6Pktinfo):]
+ return m.Next(sizeofInet6Pktinfo)
}
func marshal2292NextHop(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIPv6
- m.Type = sysIPV6_2292NEXTHOP
- m.SetLen(syscall.CmsgLen(sysSizeofSockaddrInet6))
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIPv6, sysIPV6_2292NEXTHOP, sizeofSockaddrInet6)
if cm != nil {
- sa := (*sysSockaddrInet6)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
+ sa := (*sockaddrInet6)(unsafe.Pointer(&m.Data(sizeofSockaddrInet6)[0]))
sa.setSockaddr(cm.NextHop, cm.IfIndex)
}
- return b[syscall.CmsgSpace(sysSizeofSockaddrInet6):]
+ return m.Next(sizeofSockaddrInet6)
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv6
import (
- "syscall"
+ "net"
"unsafe"
"golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
func marshalTrafficClass(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIPv6
- m.Type = sysIPV6_TCLASS
- m.SetLen(syscall.CmsgLen(4))
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIPv6, sysIPV6_TCLASS, 4)
if cm != nil {
- data := b[syscall.CmsgLen(0):]
- nativeEndian.PutUint32(data[:4], uint32(cm.TrafficClass))
+ socket.NativeEndian.PutUint32(m.Data(4), uint32(cm.TrafficClass))
}
- return b[syscall.CmsgSpace(4):]
+ return m.Next(4)
}
func parseTrafficClass(cm *ControlMessage, b []byte) {
- cm.TrafficClass = int(nativeEndian.Uint32(b[:4]))
+ cm.TrafficClass = int(socket.NativeEndian.Uint32(b[:4]))
}
func marshalHopLimit(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIPv6
- m.Type = sysIPV6_HOPLIMIT
- m.SetLen(syscall.CmsgLen(4))
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIPv6, sysIPV6_HOPLIMIT, 4)
if cm != nil {
- data := b[syscall.CmsgLen(0):]
- nativeEndian.PutUint32(data[:4], uint32(cm.HopLimit))
+ socket.NativeEndian.PutUint32(m.Data(4), uint32(cm.HopLimit))
}
- return b[syscall.CmsgSpace(4):]
+ return m.Next(4)
}
func parseHopLimit(cm *ControlMessage, b []byte) {
- cm.HopLimit = int(nativeEndian.Uint32(b[:4]))
+ cm.HopLimit = int(socket.NativeEndian.Uint32(b[:4]))
}
func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIPv6
- m.Type = sysIPV6_PKTINFO
- m.SetLen(syscall.CmsgLen(sysSizeofInet6Pktinfo))
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIPv6, sysIPV6_PKTINFO, sizeofInet6Pktinfo)
if cm != nil {
- pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
+ pi := (*inet6Pktinfo)(unsafe.Pointer(&m.Data(sizeofInet6Pktinfo)[0]))
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
copy(pi.Addr[:], ip)
}
pi.setIfindex(cm.IfIndex)
}
}
- return b[syscall.CmsgSpace(sysSizeofInet6Pktinfo):]
+ return m.Next(sizeofInet6Pktinfo)
}
func parsePacketInfo(cm *ControlMessage, b []byte) {
- pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[0]))
- cm.Dst = pi.Addr[:]
+ pi := (*inet6Pktinfo)(unsafe.Pointer(&b[0]))
+ if len(cm.Dst) < net.IPv6len {
+ cm.Dst = make(net.IP, net.IPv6len)
+ }
+ copy(cm.Dst, pi.Addr[:])
cm.IfIndex = int(pi.Ifindex)
}
func marshalNextHop(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIPv6
- m.Type = sysIPV6_NEXTHOP
- m.SetLen(syscall.CmsgLen(sysSizeofSockaddrInet6))
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIPv6, sysIPV6_NEXTHOP, sizeofSockaddrInet6)
if cm != nil {
- sa := (*sysSockaddrInet6)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
+ sa := (*sockaddrInet6)(unsafe.Pointer(&m.Data(sizeofSockaddrInet6)[0]))
sa.setSockaddr(cm.NextHop, cm.IfIndex)
}
- return b[syscall.CmsgSpace(sysSizeofSockaddrInet6):]
+ return m.Next(sizeofSockaddrInet6)
}
func parseNextHop(cm *ControlMessage, b []byte) {
}
func marshalPathMTU(b []byte, cm *ControlMessage) []byte {
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
- m.Level = iana.ProtocolIPv6
- m.Type = sysIPV6_PATHMTU
- m.SetLen(syscall.CmsgLen(sysSizeofIPv6Mtuinfo))
- return b[syscall.CmsgSpace(sysSizeofIPv6Mtuinfo):]
+ m := socket.ControlMessage(b)
+ m.MarshalHeader(iana.ProtocolIPv6, sysIPV6_PATHMTU, sizeofIPv6Mtuinfo)
+ return m.Next(sizeofIPv6Mtuinfo)
}
func parsePathMTU(cm *ControlMessage, b []byte) {
- mi := (*sysIPv6Mtuinfo)(unsafe.Pointer(&b[0]))
- cm.Dst = mi.Addr.Addr[:]
+ mi := (*ipv6Mtuinfo)(unsafe.Pointer(&b[0]))
+ if len(cm.Dst) < net.IPv6len {
+ cm.Dst = make(net.IP, net.IPv6len)
+ }
+ copy(cm.Dst, mi.Addr.Addr[:])
cm.IfIndex = int(mi.Addr.Scope_id)
cm.MTU = int(mi.Mtu)
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 nacl plan9 solaris
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
package ipv6
-func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
- return errOpNoSupport
-}
-
-func newControlMessage(opt *rawOpt) (oob []byte) {
- return nil
-}
+import "golang.org/x/net/internal/socket"
-func parseControlMessage(b []byte) (*ControlMessage, error) {
- return nil, errOpNoSupport
-}
-
-func marshalControlMessage(cm *ControlMessage) (oob []byte) {
- return nil
+func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
+ return errOpNoSupport
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv6
-import (
- "os"
- "syscall"
+import "golang.org/x/net/internal/socket"
- "golang.org/x/net/internal/iana"
-)
-
-func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
+func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
opt.Lock()
defer opt.Unlock()
- if cf&FlagTrafficClass != 0 && sockOpts[ssoReceiveTrafficClass].name > 0 {
- if err := setInt(fd, &sockOpts[ssoReceiveTrafficClass], boolint(on)); err != nil {
+ if so, ok := sockOpts[ssoReceiveTrafficClass]; ok && cf&FlagTrafficClass != 0 {
+ if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.clear(FlagTrafficClass)
}
}
- if cf&FlagHopLimit != 0 && sockOpts[ssoReceiveHopLimit].name > 0 {
- if err := setInt(fd, &sockOpts[ssoReceiveHopLimit], boolint(on)); err != nil {
+ if so, ok := sockOpts[ssoReceiveHopLimit]; ok && cf&FlagHopLimit != 0 {
+ if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.clear(FlagHopLimit)
}
}
- if cf&flagPacketInfo != 0 && sockOpts[ssoReceivePacketInfo].name > 0 {
- if err := setInt(fd, &sockOpts[ssoReceivePacketInfo], boolint(on)); err != nil {
+ if so, ok := sockOpts[ssoReceivePacketInfo]; ok && cf&flagPacketInfo != 0 {
+ if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.clear(cf & flagPacketInfo)
}
}
- if cf&FlagPathMTU != 0 && sockOpts[ssoReceivePathMTU].name > 0 {
- if err := setInt(fd, &sockOpts[ssoReceivePathMTU], boolint(on)); err != nil {
+ if so, ok := sockOpts[ssoReceivePathMTU]; ok && cf&FlagPathMTU != 0 {
+ if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
}
return nil
}
-
-func newControlMessage(opt *rawOpt) (oob []byte) {
- opt.RLock()
- var l int
- if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
- }
- if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
- }
- if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
- }
- if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlPathMTU].length)
- }
- if l > 0 {
- oob = make([]byte, l)
- b := oob
- if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
- b = ctlOpts[ctlTrafficClass].marshal(b, nil)
- }
- if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
- b = ctlOpts[ctlHopLimit].marshal(b, nil)
- }
- if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
- b = ctlOpts[ctlPacketInfo].marshal(b, nil)
- }
- if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
- b = ctlOpts[ctlPathMTU].marshal(b, nil)
- }
- }
- 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.ProtocolIPv6 {
- continue
- }
- switch int(m.Header.Type) {
- case ctlOpts[ctlTrafficClass].name:
- ctlOpts[ctlTrafficClass].parse(cm, m.Data[:])
- case ctlOpts[ctlHopLimit].name:
- ctlOpts[ctlHopLimit].parse(cm, m.Data[:])
- case ctlOpts[ctlPacketInfo].name:
- ctlOpts[ctlPacketInfo].parse(cm, m.Data[:])
- case ctlOpts[ctlPathMTU].name:
- ctlOpts[ctlPathMTU].parse(cm, m.Data[:])
- }
- }
- return cm, nil
-}
-
-func marshalControlMessage(cm *ControlMessage) (oob []byte) {
- if cm == nil {
- return
- }
- var l int
- tclass := false
- if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
- tclass = true
- l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
- }
- hoplimit := false
- if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
- hoplimit = true
- l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
- }
- pktinfo := false
- if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) {
- pktinfo = true
- l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
- }
- nexthop := false
- if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
- nexthop = true
- l += syscall.CmsgSpace(ctlOpts[ctlNextHop].length)
- }
- if l > 0 {
- oob = make([]byte, l)
- b := oob
- if tclass {
- b = ctlOpts[ctlTrafficClass].marshal(b, cm)
- }
- if hoplimit {
- b = ctlOpts[ctlHopLimit].marshal(b, cm)
- }
- if pktinfo {
- b = ctlOpts[ctlPacketInfo].marshal(b, cm)
- }
- if nexthop {
- b = ctlOpts[ctlNextHop].marshal(b, cm)
- }
- }
- return
-}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 ipv6
-import "syscall"
+import (
+ "syscall"
-func setControlMessage(fd syscall.Handle, opt *rawOpt, cf ControlFlags, on bool) error {
- // TODO(mikio): implement this
- return syscall.EWINDOWS
-}
-
-func newControlMessage(opt *rawOpt) (oob []byte) {
- // TODO(mikio): implement this
- return nil
-}
+ "golang.org/x/net/internal/socket"
+)
-func parseControlMessage(b []byte) (*ControlMessage, error) {
+func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
// TODO(mikio): implement this
- return nil, syscall.EWINDOWS
-}
-
-func marshalControlMessage(cm *ControlMessage) (oob []byte) {
- // TODO(mikio): implement this
- return nil
+ return syscall.EWINDOWS
}
sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH
sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW
- sysSizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
- sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
- sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
- sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
+ sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+ sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ sizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+ sizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
- sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
- sysSizeofGroupReq = C.sizeof_struct_group_req
- sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req
+ sizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ sizeofGroupReq = C.sizeof_struct_group_req
+ sizeofGroupSourceReq = C.sizeof_struct_group_source_req
- sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+ sizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
)
-type sysSockaddrStorage C.struct_sockaddr_storage
+type sockaddrStorage C.struct_sockaddr_storage
-type sysSockaddrInet6 C.struct_sockaddr_in6
+type sockaddrInet6 C.struct_sockaddr_in6
-type sysInet6Pktinfo C.struct_in6_pktinfo
+type inet6Pktinfo C.struct_in6_pktinfo
-type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
+type ipv6Mtuinfo C.struct_ip6_mtuinfo
-type sysIPv6Mreq C.struct_ipv6_mreq
+type ipv6Mreq C.struct_ipv6_mreq
-type sysICMPv6Filter C.struct_icmp6_filter
+type icmpv6Filter C.struct_icmp6_filter
-type sysGroupReq C.struct_group_req
+type groupReq C.struct_group_req
-type sysGroupSourceReq C.struct_group_source_req
+type groupSourceReq C.struct_group_source_req
sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH
sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW
- sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
- sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
- sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
+ sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ sizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+ sizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
- sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ sizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
- sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+ sizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
)
-type sysSockaddrInet6 C.struct_sockaddr_in6
+type sockaddrInet6 C.struct_sockaddr_in6
-type sysInet6Pktinfo C.struct_in6_pktinfo
+type inet6Pktinfo C.struct_in6_pktinfo
-type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
+type ipv6Mtuinfo C.struct_ip6_mtuinfo
-type sysIPv6Mreq C.struct_ipv6_mreq
+type ipv6Mreq C.struct_ipv6_mreq
-type sysICMPv6Filter C.struct_icmp6_filter
+type icmpv6Filter C.struct_icmp6_filter
sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH
sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW
- sysSizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
- sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
- sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
- sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
+ sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+ sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ sizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+ sizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
- sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
- sysSizeofGroupReq = C.sizeof_struct_group_req
- sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req
+ sizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ sizeofGroupReq = C.sizeof_struct_group_req
+ sizeofGroupSourceReq = C.sizeof_struct_group_source_req
- sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+ sizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
)
-type sysSockaddrStorage C.struct_sockaddr_storage
+type sockaddrStorage C.struct_sockaddr_storage
-type sysSockaddrInet6 C.struct_sockaddr_in6
+type sockaddrInet6 C.struct_sockaddr_in6
-type sysInet6Pktinfo C.struct_in6_pktinfo
+type inet6Pktinfo C.struct_in6_pktinfo
-type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
+type ipv6Mtuinfo C.struct_ip6_mtuinfo
-type sysIPv6Mreq C.struct_ipv6_mreq
+type ipv6Mreq C.struct_ipv6_mreq
-type sysGroupReq C.struct_group_req
+type groupReq C.struct_group_req
-type sysGroupSourceReq C.struct_group_source_req
+type groupSourceReq C.struct_group_source_req
-type sysICMPv6Filter C.struct_icmp6_filter
+type icmpv6Filter C.struct_icmp6_filter
#include <linux/in6.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
+#include <linux/filter.h>
+#include <sys/socket.h>
*/
import "C"
sysICMPV6_FILTER_BLOCKOTHERS = C.ICMPV6_FILTER_BLOCKOTHERS
sysICMPV6_FILTER_PASSONLY = C.ICMPV6_FILTER_PASSONLY
- sysSizeofKernelSockaddrStorage = C.sizeof_struct___kernel_sockaddr_storage
- sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
- sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
- sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
- sysSizeofIPv6FlowlabelReq = C.sizeof_struct_in6_flowlabel_req
+ sysSOL_SOCKET = C.SOL_SOCKET
+ sysSO_ATTACH_FILTER = C.SO_ATTACH_FILTER
- sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
- sysSizeofGroupReq = C.sizeof_struct_group_req
- sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req
+ sizeofKernelSockaddrStorage = C.sizeof_struct___kernel_sockaddr_storage
+ sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ sizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+ sizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
+ sizeofIPv6FlowlabelReq = C.sizeof_struct_in6_flowlabel_req
- sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+ sizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ sizeofGroupReq = C.sizeof_struct_group_req
+ sizeofGroupSourceReq = C.sizeof_struct_group_source_req
+
+ sizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+
+ sizeofSockFprog = C.sizeof_struct_sock_fprog
)
-type sysKernelSockaddrStorage C.struct___kernel_sockaddr_storage
+type kernelSockaddrStorage C.struct___kernel_sockaddr_storage
+
+type sockaddrInet6 C.struct_sockaddr_in6
+
+type inet6Pktinfo C.struct_in6_pktinfo
-type sysSockaddrInet6 C.struct_sockaddr_in6
+type ipv6Mtuinfo C.struct_ip6_mtuinfo
-type sysInet6Pktinfo C.struct_in6_pktinfo
+type ipv6FlowlabelReq C.struct_in6_flowlabel_req
-type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
+type ipv6Mreq C.struct_ipv6_mreq
-type sysIPv6FlowlabelReq C.struct_in6_flowlabel_req
+type groupReq C.struct_group_req
-type sysIPv6Mreq C.struct_ipv6_mreq
+type groupSourceReq C.struct_group_source_req
-type sysGroupReq C.struct_group_req
+type icmpv6Filter C.struct_icmp6_filter
-type sysGroupSourceReq C.struct_group_source_req
+type sockFProg C.struct_sock_fprog
-type sysICMPv6Filter C.struct_icmp6_filter
+type sockFilter C.struct_sock_filter
sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH
sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW
- sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
- sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
- sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
+ sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ sizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+ sizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
- sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ sizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
- sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+ sizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
)
-type sysSockaddrInet6 C.struct_sockaddr_in6
+type sockaddrInet6 C.struct_sockaddr_in6
-type sysInet6Pktinfo C.struct_in6_pktinfo
+type inet6Pktinfo C.struct_in6_pktinfo
-type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
+type ipv6Mtuinfo C.struct_ip6_mtuinfo
-type sysIPv6Mreq C.struct_ipv6_mreq
+type ipv6Mreq C.struct_ipv6_mreq
-type sysICMPv6Filter C.struct_icmp6_filter
+type icmpv6Filter C.struct_icmp6_filter
sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH
sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW
- sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
- sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
- sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
+ sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ sizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+ sizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
- sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ sizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
- sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+ sizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
)
-type sysSockaddrInet6 C.struct_sockaddr_in6
+type sockaddrInet6 C.struct_sockaddr_in6
-type sysInet6Pktinfo C.struct_in6_pktinfo
+type inet6Pktinfo C.struct_in6_pktinfo
-type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
+type ipv6Mtuinfo C.struct_ip6_mtuinfo
-type sysIPv6Mreq C.struct_ipv6_mreq
+type ipv6Mreq C.struct_ipv6_mreq
-type sysICMPv6Filter C.struct_icmp6_filter
+type icmpv6Filter C.struct_icmp6_filter
package ipv6
/*
+#include <sys/socket.h>
+
#include <netinet/in.h>
#include <netinet/icmp6.h>
*/
sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS
+ sysMCAST_JOIN_GROUP = C.MCAST_JOIN_GROUP
+ sysMCAST_LEAVE_GROUP = C.MCAST_LEAVE_GROUP
+ sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE
+ sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE
+ sysMCAST_JOIN_SOURCE_GROUP = C.MCAST_JOIN_SOURCE_GROUP
+ sysMCAST_LEAVE_SOURCE_GROUP = C.MCAST_LEAVE_SOURCE_GROUP
+
sysIPV6_PREFER_SRC_HOME = C.IPV6_PREFER_SRC_HOME
sysIPV6_PREFER_SRC_COA = C.IPV6_PREFER_SRC_COA
sysIPV6_PREFER_SRC_PUBLIC = C.IPV6_PREFER_SRC_PUBLIC
sysICMP6_FILTER = C.ICMP6_FILTER
- sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
- sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
- sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
+ sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+ sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ sizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+ sizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
- sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ sizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ sizeofGroupReq = C.sizeof_struct_group_req
+ sizeofGroupSourceReq = C.sizeof_struct_group_source_req
- sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+ sizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
)
-type sysSockaddrInet6 C.struct_sockaddr_in6
+type sockaddrStorage C.struct_sockaddr_storage
+
+type sockaddrInet6 C.struct_sockaddr_in6
+
+type inet6Pktinfo C.struct_in6_pktinfo
+
+type ipv6Mtuinfo C.struct_ip6_mtuinfo
-type sysInet6Pktinfo C.struct_in6_pktinfo
+type ipv6Mreq C.struct_ipv6_mreq
-type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
+type groupReq C.struct_group_req
-type sysIPv6Mreq C.struct_ipv6_mreq
+type groupSourceReq C.struct_group_source_req
-type sysICMPv6Filter C.struct_icmp6_filter
+type icmpv6Filter C.struct_icmp6_filter
+++ /dev/null
-// Copyright 2013 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 windows
-
-package ipv6
-
-import (
- "net"
- "syscall"
-)
-
-// MulticastHopLimit returns the hop limit field value for outgoing
-// multicast packets.
-func (c *dgramOpt) MulticastHopLimit() (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return 0, err
- }
- return getInt(fd, &sockOpts[ssoMulticastHopLimit])
-}
-
-// SetMulticastHopLimit sets the hop limit field value for future
-// outgoing multicast packets.
-func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setInt(fd, &sockOpts[ssoMulticastHopLimit], hoplim)
-}
-
-// MulticastInterface returns the default interface for multicast
-// packet transmissions.
-func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
- if !c.ok() {
- return nil, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return nil, err
- }
- return getInterface(fd, &sockOpts[ssoMulticastInterface])
-}
-
-// SetMulticastInterface sets the default interface for future
-// multicast packet transmissions.
-func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setInterface(fd, &sockOpts[ssoMulticastInterface], ifi)
-}
-
-// MulticastLoopback reports whether transmitted multicast packets
-// should be copied and send back to the originator.
-func (c *dgramOpt) MulticastLoopback() (bool, error) {
- if !c.ok() {
- return false, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return false, err
- }
- on, err := getInt(fd, &sockOpts[ssoMulticastLoopback])
- if err != nil {
- return false, err
- }
- return on == 1, nil
-}
-
-// SetMulticastLoopback sets whether transmitted multicast packets
-// should be copied and send back to the originator.
-func (c *dgramOpt) SetMulticastLoopback(on bool) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setInt(fd, &sockOpts[ssoMulticastLoopback], boolint(on))
-}
-
-// JoinGroup joins the group address group on the interface ifi.
-// By default all sources that can cast data to group are accepted.
-// It's possible to mute and unmute data transmission from a specific
-// source by using ExcludeSourceSpecificGroup and
-// IncludeSourceSpecificGroup.
-// JoinGroup uses the system assigned multicast interface when ifi is
-// nil, although this is not recommended because the assignment
-// depends on platforms and sometimes it might require routing
-// configuration.
-func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP16(group)
- if grp == nil {
- return errMissingAddress
- }
- return setGroup(fd, &sockOpts[ssoJoinGroup], ifi, grp)
-}
-
-// LeaveGroup leaves the group address group on the interface ifi
-// regardless of whether the group is any-source group or
-// source-specific group.
-func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP16(group)
- if grp == nil {
- return errMissingAddress
- }
- return setGroup(fd, &sockOpts[ssoLeaveGroup], ifi, grp)
-}
-
-// JoinSourceSpecificGroup joins the source-specific group comprising
-// group and source on the interface ifi.
-// JoinSourceSpecificGroup uses the system assigned multicast
-// interface when ifi is nil, although this is not recommended because
-// the assignment depends on platforms and sometimes it might require
-// routing configuration.
-func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP16(group)
- if grp == nil {
- return errMissingAddress
- }
- src := netAddrToIP16(source)
- if src == nil {
- return errMissingAddress
- }
- return setSourceGroup(fd, &sockOpts[ssoJoinSourceGroup], ifi, grp, src)
-}
-
-// LeaveSourceSpecificGroup leaves the source-specific group on the
-// interface ifi.
-func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP16(group)
- if grp == nil {
- return errMissingAddress
- }
- src := netAddrToIP16(source)
- if src == nil {
- return errMissingAddress
- }
- return setSourceGroup(fd, &sockOpts[ssoLeaveSourceGroup], ifi, grp, src)
-}
-
-// ExcludeSourceSpecificGroup excludes the source-specific group from
-// the already joined any-source groups by JoinGroup on the interface
-// ifi.
-func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP16(group)
- if grp == nil {
- return errMissingAddress
- }
- src := netAddrToIP16(source)
- if src == nil {
- return errMissingAddress
- }
- return setSourceGroup(fd, &sockOpts[ssoBlockSourceGroup], ifi, grp, src)
-}
-
-// IncludeSourceSpecificGroup includes the excluded source-specific
-// group by ExcludeSourceSpecificGroup again on the interface ifi.
-func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- grp := netAddrToIP16(group)
- if grp == nil {
- return errMissingAddress
- }
- src := netAddrToIP16(source)
- if src == nil {
- return errMissingAddress
- }
- return setSourceGroup(fd, &sockOpts[ssoUnblockSourceGroup], ifi, grp, src)
-}
-
-// Checksum reports whether the kernel will compute, store or verify a
-// checksum for both incoming and outgoing packets. If on is true, it
-// returns an offset in bytes into the data of where the checksum
-// field is located.
-func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
- if !c.ok() {
- return false, 0, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return false, 0, err
- }
- offset, err = getInt(fd, &sockOpts[ssoChecksum])
- if err != nil {
- return false, 0, err
- }
- if offset < 0 {
- return false, 0, nil
- }
- return true, offset, nil
-}
-
-// SetChecksum enables the kernel checksum processing. If on is ture,
-// the offset should be an offset in bytes into the data of where the
-// checksum field is located.
-func (c *dgramOpt) SetChecksum(on bool, offset int) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- if !on {
- offset = -1
- }
- return setInt(fd, &sockOpts[ssoChecksum], offset)
-}
-
-// ICMPFilter returns an ICMP filter.
-func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
- if !c.ok() {
- return nil, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return nil, err
- }
- return getICMPFilter(fd, &sockOpts[ssoICMPFilter])
-}
-
-// SetICMPFilter deploys the ICMP filter.
-func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setICMPFilter(fd, &sockOpts[ssoICMPFilter], f)
-}
+++ /dev/null
-// Copyright 2013 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 nacl plan9 solaris
-
-package ipv6
-
-import "net"
-
-// MulticastHopLimit returns the hop limit field value for outgoing
-// multicast packets.
-func (c *dgramOpt) MulticastHopLimit() (int, error) {
- return 0, errOpNoSupport
-}
-
-// SetMulticastHopLimit sets the hop limit field value for future
-// outgoing multicast packets.
-func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
- return errOpNoSupport
-}
-
-// MulticastInterface returns the default interface for multicast
-// packet transmissions.
-func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
- return nil, errOpNoSupport
-}
-
-// SetMulticastInterface sets the default interface for future
-// multicast packet transmissions.
-func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
- return errOpNoSupport
-}
-
-// MulticastLoopback reports whether transmitted multicast packets
-// should be copied and send back to the originator.
-func (c *dgramOpt) MulticastLoopback() (bool, error) {
- return false, errOpNoSupport
-}
-
-// SetMulticastLoopback sets whether transmitted multicast packets
-// should be copied and send back to the originator.
-func (c *dgramOpt) SetMulticastLoopback(on bool) error {
- return errOpNoSupport
-}
-
-// JoinGroup joins the group address group on the interface ifi.
-// By default all sources that can cast data to group are accepted.
-// It's possible to mute and unmute data transmission from a specific
-// source by using ExcludeSourceSpecificGroup and
-// IncludeSourceSpecificGroup.
-// JoinGroup uses the system assigned multicast interface when ifi is
-// nil, although this is not recommended because the assignment
-// depends on platforms and sometimes it might require routing
-// configuration.
-func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
- return errOpNoSupport
-}
-
-// LeaveGroup leaves the group address group on the interface ifi
-// regardless of whether the group is any-source group or
-// source-specific group.
-func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
- return errOpNoSupport
-}
-
-// JoinSourceSpecificGroup joins the source-specific group comprising
-// group and source on the interface ifi.
-// JoinSourceSpecificGroup uses the system assigned multicast
-// interface when ifi is nil, although this is not recommended because
-// the assignment depends on platforms and sometimes it might require
-// routing configuration.
-func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- return errOpNoSupport
-}
-
-// LeaveSourceSpecificGroup leaves the source-specific group on the
-// interface ifi.
-func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- return errOpNoSupport
-}
-
-// ExcludeSourceSpecificGroup excludes the source-specific group from
-// the already joined any-source groups by JoinGroup on the interface
-// ifi.
-func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- return errOpNoSupport
-}
-
-// IncludeSourceSpecificGroup includes the excluded source-specific
-// group by ExcludeSourceSpecificGroup again on the interface ifi.
-func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
- return errOpNoSupport
-}
-
-// Checksum reports whether the kernel will compute, store or verify a
-// checksum for both incoming and outgoing packets. If on is true, it
-// returns an offset in bytes into the data of where the checksum
-// field is located.
-func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
- return false, 0, errOpNoSupport
-}
-
-// SetChecksum enables the kernel checksum processing. If on is ture,
-// the offset should be an offset in bytes into the data of where the
-// checksum field is located.
-func (c *dgramOpt) SetChecksum(on bool, offset int) error {
- return errOpNoSupport
-}
-
-// ICMPFilter returns an ICMP filter.
-func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
- return nil, errOpNoSupport
-}
-
-// SetICMPFilter deploys the ICMP filter.
-func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
- return errOpNoSupport
-}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
// The package provides IP-level socket options that allow
// manipulation of IPv6 facilities.
//
-// The IPv6 protocol is defined in RFC 2460.
-// Basic and advanced socket interface extensions are defined in RFC
-// 3493 and RFC 3542.
-// Socket interface extensions for multicast source filters are
-// defined in RFC 3678.
+// The IPv6 protocol is defined in RFC 8200.
+// Socket interface extensions are defined in RFC 3493, RFC 3542 and
+// RFC 3678.
// MLDv1 and MLDv2 are defined in RFC 2710 and RFC 3810.
// Source-specific multicast is defined in RFC 4607.
//
+// On Darwin, this package requires OS X Mavericks version 10.9 or
+// above, or equivalent.
+//
//
// Unicasting
//
// The options for unicasting are available for net.TCPConn,
// net.UDPConn and net.IPConn which are created as network connections
-// that use the IPv6 transport. When a single TCP connection carrying
+// that use the IPv6 transport. When a single TCP connection carrying
// a data flow of multiple packets needs to indicate the flow is
-// important, ipv6.Conn is used to set the traffic class field on the
-// IPv6 header for each packet.
+// important, Conn is used to set the traffic class field on the IPv6
+// header for each packet.
//
// ln, err := net.Listen("tcp6", "[::]:1024")
// if err != nil {
//
// The options for multicasting are available for net.UDPConn and
// net.IPconn which are created as network connections that use the
-// IPv6 transport. A few network facilities must be prepared before
+// IPv6 transport. A few network facilities must be prepared before
// you begin multicasting, at a minimum joining network interfaces and
// multicast groups.
//
// defer c.Close()
//
// Second, the application joins multicast groups, starts listening to
-// the groups on the specified network interfaces. Note that the
+// the groups on the specified network interfaces. Note that the
// service port for transport layer protocol does not matter with this
// operation as joining groups affects only network and link layer
// protocols, such as IPv6 and Ethernet.
// }
//
// The application might set per packet control message transmissions
-// between the protocol stack within the kernel. When the application
+// between the protocol stack within the kernel. When the application
// needs a destination address on an incoming packet,
-// SetControlMessage of ipv6.PacketConn is used to enable control
-// message transmissons.
+// SetControlMessage of PacketConn is used to enable control message
+// transmissions.
//
// if err := p.SetControlMessage(ipv6.FlagDst, true); err != nil {
// // error handling
// More multicasting
//
// An application that uses PacketConn may join multiple multicast
-// groups. For example, a UDP listener with port 1024 might join two
+// groups. For example, a UDP listener with port 1024 might join two
// different groups across over two different network interfaces by
// using:
//
// }
//
// It is possible for multiple UDP listeners that listen on the same
-// UDP port to join the same multicast group. The net package will
+// UDP port to join the same multicast group. The net package will
// provide a socket that listens to a wildcard address with reusable
// UDP port when an appropriate multicast address prefix is passed to
// the net.ListenPacket or net.ListenUDP.
// In the fallback case, ExcludeSourceSpecificGroup and
// IncludeSourceSpecificGroup may return an error.
package ipv6 // import "golang.org/x/net/ipv6"
+
+// BUG(mikio): This package is not implemented on NaCl and Plan 9.
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
"net"
"syscall"
"time"
+
+ "golang.org/x/net/internal/socket"
)
+// BUG(mikio): On Windows, the JoinSourceSpecificGroup,
+// LeaveSourceSpecificGroup, ExcludeSourceSpecificGroup and
+// IncludeSourceSpecificGroup methods of PacketConn are not
+// implemented.
+
// A Conn represents a network endpoint that uses IPv6 transport.
// It allows to set basic IP-level socket options such as traffic
// class and hop limit.
}
type genericOpt struct {
- net.Conn
+ *socket.Conn
}
func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil }
// PathMTU returns a path MTU value for the destination associated
// with the endpoint.
func (c *Conn) PathMTU() (int, error) {
- if !c.genericOpt.ok() {
+ if !c.ok() {
return 0, syscall.EINVAL
}
- fd, err := c.genericOpt.sysfd()
- if err != nil {
- return 0, err
+ so, ok := sockOpts[ssoPathMTU]
+ if !ok {
+ return 0, errOpNoSupport
}
- _, mtu, err := getMTUInfo(fd, &sockOpts[ssoPathMTU])
+ _, mtu, err := so.getMTUInfo(c.Conn)
if err != nil {
return 0, err
}
// NewConn returns a new Conn.
func NewConn(c net.Conn) *Conn {
+ cc, _ := socket.NewConn(c)
return &Conn{
- genericOpt: genericOpt{Conn: c},
+ genericOpt: genericOpt{Conn: cc},
}
}
// A PacketConn represents a packet network endpoint that uses IPv6
-// transport. It is used to control several IP-level socket options
-// including IPv6 header manipulation. It also provides datagram
+// transport. It is used to control several IP-level socket options
+// including IPv6 header manipulation. It also provides datagram
// based network I/O methods specific to the IPv6 and higher layer
// protocols such as OSPF, GRE, and UDP.
type PacketConn struct {
}
type dgramOpt struct {
- net.PacketConn
+ *socket.Conn
}
-func (c *dgramOpt) ok() bool { return c != nil && c.PacketConn != nil }
+func (c *dgramOpt) ok() bool { return c != nil && c.Conn != nil }
// SetControlMessage allows to receive the per packet basis IP-level
// socket options.
if !c.payloadHandler.ok() {
return syscall.EINVAL
}
- fd, err := c.payloadHandler.sysfd()
- if err != nil {
- return err
- }
- return setControlMessage(fd, &c.payloadHandler.rawOpt, cf, on)
+ return setControlMessage(c.dgramOpt.Conn, &c.payloadHandler.rawOpt, cf, on)
}
// SetDeadline sets the read and write deadlines associated with the
// NewPacketConn returns a new PacketConn using c as its underlying
// transport.
func NewPacketConn(c net.PacketConn) *PacketConn {
+ cc, _ := socket.NewConn(c.(net.Conn))
return &PacketConn{
- genericOpt: genericOpt{Conn: c.(net.Conn)},
- dgramOpt: dgramOpt{PacketConn: c},
- payloadHandler: payloadHandler{PacketConn: c},
+ genericOpt: genericOpt{Conn: cc},
+ dgramOpt: dgramOpt{Conn: cc},
+ payloadHandler: payloadHandler{PacketConn: c, Conn: cc},
}
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
if err != nil {
return err
}
- // The ipv6 pacakge still supports go1.2, and so we need to
- // take care of additional platforms in go1.3 and above for
- // working with go1.2.
- switch {
- case runtime.GOOS == "dragonfly" || runtime.GOOS == "solaris":
- b = bytes.Replace(b, []byte("package ipv6\n"), []byte("// +build "+runtime.GOOS+"\n\npackage ipv6\n"), 1)
- case runtime.GOOS == "linux" && (runtime.GOARCH == "arm64" || runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le"):
- b = bytes.Replace(b, []byte("package ipv6\n"), []byte("// +build "+runtime.GOOS+","+runtime.GOARCH+"\n\npackage ipv6\n"), 1)
- }
b, err = format.Source(b)
if err != nil {
return err
+++ /dev/null
-// Copyright 2013 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 windows
-
-package ipv6
-
-import "syscall"
-
-// TrafficClass returns the traffic class field value for outgoing
-// packets.
-func (c *genericOpt) TrafficClass() (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return 0, err
- }
- return getInt(fd, &sockOpts[ssoTrafficClass])
-}
-
-// SetTrafficClass sets the traffic class field value for future
-// outgoing packets.
-func (c *genericOpt) SetTrafficClass(tclass int) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setInt(fd, &sockOpts[ssoTrafficClass], tclass)
-}
-
-// HopLimit returns the hop limit field value for outgoing packets.
-func (c *genericOpt) HopLimit() (int, error) {
- if !c.ok() {
- return 0, syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return 0, err
- }
- return getInt(fd, &sockOpts[ssoHopLimit])
-}
-
-// SetHopLimit sets the hop limit field value for future outgoing
-// packets.
-func (c *genericOpt) SetHopLimit(hoplim int) error {
- if !c.ok() {
- return syscall.EINVAL
- }
- fd, err := c.sysfd()
- if err != nil {
- return err
- }
- return setInt(fd, &sockOpts[ssoHopLimit], hoplim)
-}
+++ /dev/null
-// Copyright 2013 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 nacl plan9 solaris
-
-package ipv6
-
-// TrafficClass returns the traffic class field value for outgoing
-// packets.
-func (c *genericOpt) TrafficClass() (int, error) {
- return 0, errOpNoSupport
-}
-
-// SetTrafficClass sets the traffic class field value for future
-// outgoing packets.
-func (c *genericOpt) SetTrafficClass(tclass int) error {
- return errOpNoSupport
-}
-
-// HopLimit returns the hop limit field value for outgoing packets.
-func (c *genericOpt) HopLimit() (int, error) {
- return 0, errOpNoSupport
-}
-
-// SetHopLimit sets the hop limit field value for future outgoing
-// packets.
-func (c *genericOpt) SetHopLimit(hoplim int) error {
- return errOpNoSupport
-}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 ipv6
import (
- "encoding/binary"
"errors"
"net"
- "unsafe"
)
var (
errInvalidConnType = errors.New("invalid conn type")
errOpNoSupport = errors.New("operation not supported")
errNoSuchInterface = errors.New("no such interface")
-
- nativeEndian binary.ByteOrder
)
-func init() {
- i := uint32(1)
- b := (*[4]byte)(unsafe.Pointer(&i))
- if b[0] == 1 {
- nativeEndian = binary.LittleEndian
- } else {
- nativeEndian = binary.BigEndian
- }
-}
-
func boolint(b bool) int {
if b {
return 1
}
return nil
}
+
+func opAddr(a net.Addr) net.Addr {
+ switch a.(type) {
+ case *net.TCPAddr:
+ if a == nil {
+ return nil
+ }
+ case *net.UDPAddr:
+ if a == nil {
+ return nil
+ }
+ case *net.IPAddr:
+ if a == nil {
+ return nil
+ }
+ }
+ return a
+}
+++ /dev/null
-// Copyright 2013 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 nacl plan9 solaris
-
-package ipv6
-
-func (c *genericOpt) sysfd() (int, error) {
- return 0, errOpNoSupport
-}
-
-func (c *dgramOpt) sysfd() (int, error) {
- return 0, errOpNoSupport
-}
-
-func (c *payloadHandler) sysfd() (int, error) {
- return 0, errOpNoSupport
-}
+++ /dev/null
-// Copyright 2013 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
-
-package ipv6
-
-import (
- "net"
- "reflect"
-)
-
-func (c *genericOpt) sysfd() (int, error) {
- switch p := c.Conn.(type) {
- case *net.TCPConn, *net.UDPConn, *net.IPConn:
- return sysfd(p)
- }
- return 0, errInvalidConnType
-}
-
-func (c *dgramOpt) sysfd() (int, error) {
- switch p := c.PacketConn.(type) {
- case *net.UDPConn, *net.IPConn:
- return sysfd(p.(net.Conn))
- }
- return 0, errInvalidConnType
-}
-
-func (c *payloadHandler) sysfd() (int, error) {
- return sysfd(c.PacketConn.(net.Conn))
-}
-
-func sysfd(c net.Conn) (int, error) {
- cv := reflect.ValueOf(c)
- switch ce := cv.Elem(); ce.Kind() {
- case reflect.Struct:
- nfd := ce.FieldByName("conn").FieldByName("fd")
- switch fe := nfd.Elem(); fe.Kind() {
- case reflect.Struct:
- fd := fe.FieldByName("sysfd")
- return int(fd.Int()), nil
- }
- }
- return 0, errInvalidConnType
-}
+++ /dev/null
-// Copyright 2013 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 ipv6
-
-import (
- "net"
- "reflect"
- "syscall"
-)
-
-func (c *genericOpt) sysfd() (syscall.Handle, error) {
- switch p := c.Conn.(type) {
- case *net.TCPConn, *net.UDPConn, *net.IPConn:
- return sysfd(p)
- }
- return syscall.InvalidHandle, errInvalidConnType
-}
-
-func (c *dgramOpt) sysfd() (syscall.Handle, error) {
- switch p := c.PacketConn.(type) {
- case *net.UDPConn, *net.IPConn:
- return sysfd(p.(net.Conn))
- }
- return syscall.InvalidHandle, errInvalidConnType
-}
-
-func (c *payloadHandler) sysfd() (syscall.Handle, error) {
- return sysfd(c.PacketConn.(net.Conn))
-}
-
-func sysfd(c net.Conn) (syscall.Handle, error) {
- cv := reflect.ValueOf(c)
- switch ce := cv.Elem(); ce.Kind() {
- case reflect.Struct:
- netfd := ce.FieldByName("conn").FieldByName("fd")
- switch fe := netfd.Elem(); fe.Kind() {
- case reflect.Struct:
- fd := fe.FieldByName("sysfd")
- return syscall.Handle(fd.Uint()), nil
- }
- }
- return syscall.InvalidHandle, errInvalidConnType
-}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
import "golang.org/x/net/internal/iana"
+// BUG(mikio): On Windows, methods related to ICMPFilter are not
+// implemented.
+
// An ICMPType represents a type of ICMP message.
type ICMPType int
// packets. The filter belongs to a packet delivery path on a host and
// it cannot interact with forwarding packets or tunnel-outer packets.
//
-// Note: RFC 2460 defines a reasonable role model. A node means a
+// Note: RFC 8200 defines a reasonable role model. A node means a
// device that implements IP. A router means a node that forwards IP
// packets not explicitly addressed to itself, and a host means a node
// that is not a router.
type ICMPFilter struct {
- sysICMPv6Filter
+ icmpv6Filter
}
// Accept accepts incoming ICMP packets including the type field value
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 ipv6
-func (f *sysICMPv6Filter) accept(typ ICMPType) {
+func (f *icmpv6Filter) accept(typ ICMPType) {
f.Filt[typ>>5] |= 1 << (uint32(typ) & 31)
}
-func (f *sysICMPv6Filter) block(typ ICMPType) {
+func (f *icmpv6Filter) block(typ ICMPType) {
f.Filt[typ>>5] &^= 1 << (uint32(typ) & 31)
}
-func (f *sysICMPv6Filter) setAll(block bool) {
+func (f *icmpv6Filter) setAll(block bool) {
for i := range f.Filt {
if block {
f.Filt[i] = 0
}
}
-func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool {
+func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
return f.Filt[typ>>5]&(1<<(uint32(typ)&31)) == 0
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 ipv6
-func (f *sysICMPv6Filter) accept(typ ICMPType) {
+func (f *icmpv6Filter) accept(typ ICMPType) {
f.Data[typ>>5] &^= 1 << (uint32(typ) & 31)
}
-func (f *sysICMPv6Filter) block(typ ICMPType) {
+func (f *icmpv6Filter) block(typ ICMPType) {
f.Data[typ>>5] |= 1 << (uint32(typ) & 31)
}
-func (f *sysICMPv6Filter) setAll(block bool) {
+func (f *icmpv6Filter) setAll(block bool) {
for i := range f.Data {
if block {
f.Data[i] = 1<<32 - 1
}
}
-func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool {
+func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
return f.Data[typ>>5]&(1<<(uint32(typ)&31)) != 0
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 solaris
-
package ipv6
-func (f *sysICMPv6Filter) accept(typ ICMPType) {
- // TODO(mikio): implement this
+func (f *icmpv6Filter) accept(typ ICMPType) {
+ f.X__icmp6_filt[typ>>5] |= 1 << (uint32(typ) & 31)
}
-func (f *sysICMPv6Filter) block(typ ICMPType) {
- // TODO(mikio): implement this
+func (f *icmpv6Filter) block(typ ICMPType) {
+ f.X__icmp6_filt[typ>>5] &^= 1 << (uint32(typ) & 31)
}
-func (f *sysICMPv6Filter) setAll(block bool) {
- // TODO(mikio): implement this
+func (f *icmpv6Filter) setAll(block bool) {
+ for i := range f.X__icmp6_filt {
+ if block {
+ f.X__icmp6_filt[i] = 0
+ } else {
+ f.X__icmp6_filt[i] = 1<<32 - 1
+ }
+ }
}
-func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool {
- // TODO(mikio): implement this
- return false
+func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
+ return f.X__icmp6_filt[typ>>5]&(1<<(uint32(typ)&31)) == 0
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 nacl plan9
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
package ipv6
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
}
-func (f *sysICMPv6Filter) accept(typ ICMPType) {
+func (f *icmpv6Filter) accept(typ ICMPType) {
}
-func (f *sysICMPv6Filter) block(typ ICMPType) {
+func (f *icmpv6Filter) block(typ ICMPType) {
}
-func (f *sysICMPv6Filter) setAll(block bool) {
+func (f *icmpv6Filter) setAll(block bool) {
}
-func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool {
+func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
return false
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 ipv6
-type sysICMPv6Filter struct {
+func (f *icmpv6Filter) accept(typ ICMPType) {
// TODO(mikio): implement this
}
-func (f *sysICMPv6Filter) accept(typ ICMPType) {
+func (f *icmpv6Filter) block(typ ICMPType) {
// TODO(mikio): implement this
}
-func (f *sysICMPv6Filter) block(typ ICMPType) {
+func (f *icmpv6Filter) setAll(block bool) {
// TODO(mikio): implement this
}
-func (f *sysICMPv6Filter) setAll(block bool) {
- // TODO(mikio): implement this
-}
-
-func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool {
+func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
// TODO(mikio): implement this
return false
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 ipv6
-import "net"
+import (
+ "net"
+
+ "golang.org/x/net/internal/socket"
+)
+
+// BUG(mikio): On Windows, the ControlMessage for ReadFrom and WriteTo
+// methods of PacketConn is not implemented.
// A payloadHandler represents the IPv6 datagram payload handler.
type payloadHandler struct {
net.PacketConn
+ *socket.Conn
rawOpt
}
-func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil }
+func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil && c.Conn != nil }
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
)
// ReadFrom reads a payload of the received IPv6 datagram, from the
-// endpoint c, copying the payload into b. It returns the number of
+// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, syscall.EINVAL
}
- oob := newControlMessage(&c.rawOpt)
- var oobn int
- switch c := c.PacketConn.(type) {
- case *net.UDPConn:
- if n, oobn, _, src, err = c.ReadMsgUDP(b, oob); err != nil {
- return 0, nil, nil, err
- }
- case *net.IPConn:
- if n, oobn, _, src, err = c.ReadMsgIP(b, oob); err != nil {
- return 0, nil, nil, err
- }
- default:
- return 0, nil, nil, errInvalidConnType
- }
- if cm, err = parseControlMessage(oob[:oobn]); err != nil {
- return 0, nil, nil, err
- }
- if cm != nil {
- cm.Src = netAddrToIP16(src)
- }
- return
+ return c.readFrom(b)
}
// WriteTo writes a payload of the IPv6 datagram, to the destination
-// address dst through the endpoint c, copying the payload from b. It
-// returns the number of bytes written. The control message cm allows
-// the IPv6 header fields and the datagram path to be specified. The
+// address dst through the endpoint c, copying the payload from b. It
+// returns the number of bytes written. The control message cm allows
+// the IPv6 header fields and the datagram path to be specified. The
// cm may be nil if control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, syscall.EINVAL
}
- oob := marshalControlMessage(cm)
- if dst == nil {
- return 0, errMissingAddress
- }
- switch c := c.PacketConn.(type) {
- case *net.UDPConn:
- n, _, err = c.WriteMsgUDP(b, oob, dst.(*net.UDPAddr))
- case *net.IPConn:
- n, _, err = c.WriteMsgIP(b, oob, dst.(*net.IPAddr))
- default:
- return 0, errInvalidConnType
- }
- if err != nil {
- return 0, err
- }
- return
+ return c.writeTo(b, cm, dst)
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
)
// ReadFrom reads a payload of the received IPv6 datagram, from the
-// endpoint c, copying the payload into b. It returns the number of
+// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
}
// WriteTo writes a payload of the IPv6 datagram, to the destination
-// address dst through the endpoint c, copying the payload from b. It
-// returns the number of bytes written. The control message cm allows
-// the IPv6 header fields and the datagram path to be specified. The
+// address dst through the endpoint c, copying the payload from b. It
+// returns the number of bytes written. The control message cm allows
+// the IPv6 header fields and the datagram path to be specified. The
// cm may be nil if control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
package ipv6
+import "golang.org/x/net/internal/socket"
+
// Sticky socket options
const (
ssoTrafficClass = iota // header field for unicast packet, RFC 3542
ssoLeaveSourceGroup // source-specific multicast
ssoBlockSourceGroup // any-source or source-specific multicast
ssoUnblockSourceGroup // any-source or source-specific multicast
- ssoMax
+ ssoAttachFilter // attach BPF for filtering inbound traffic
)
// Sticky socket option value types
const (
- ssoTypeInt = iota + 1
- ssoTypeInterface
- ssoTypeICMPFilter
- ssoTypeMTUInfo
- ssoTypeIPMreq
+ ssoTypeIPMreq = iota + 1
ssoTypeGroupReq
ssoTypeGroupSourceReq
)
// A sockOpt represents a binding for sticky socket option.
type sockOpt struct {
- level int // option level
- name int // option name, must be equal or greater than 1
- typ int // option value type, must be equal or greater than 1
+ socket.Option
+ typ int // hint for option value type; optional
}
+++ /dev/null
-// Copyright 2013 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
-
-package ipv6
-
-import (
- "net"
- "os"
- "unsafe"
-)
-
-func setsockoptIPMreq(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
- var mreq sysIPv6Mreq
- copy(mreq.Multiaddr[:], grp)
- if ifi != nil {
- mreq.setIfindex(ifi.Index)
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&mreq), sysSizeofIPv6Mreq))
-}
+++ /dev/null
-// Copyright 2013 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 ipv6
-
-import (
- "net"
- "os"
- "syscall"
- "unsafe"
-)
-
-func setsockoptIPMreq(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
- var mreq sysIPv6Mreq
- copy(mreq.Multiaddr[:], grp)
- if ifi != nil {
- mreq.setIfindex(ifi.Index)
- }
- return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&mreq)), sysSizeofIPv6Mreq))
-}
+++ /dev/null
-// Copyright 2014 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,!freebsd,!linux
-
-package ipv6
-
-import "net"
-
-func setsockoptGroupReq(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
- return errOpNoSupport
-}
-
-func setsockoptGroupSourceReq(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
- return errOpNoSupport
-}
+++ /dev/null
-// Copyright 2014 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 freebsd linux
-
-package ipv6
-
-import (
- "net"
- "os"
- "unsafe"
-)
-
-var freebsd32o64 bool
-
-func setsockoptGroupReq(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
- var gr sysGroupReq
- if ifi != nil {
- gr.Interface = uint32(ifi.Index)
- }
- gr.setGroup(grp)
- var p unsafe.Pointer
- var l sysSockoptLen
- if freebsd32o64 {
- var d [sysSizeofGroupReq + 4]byte
- s := (*[sysSizeofGroupReq]byte)(unsafe.Pointer(&gr))
- copy(d[:4], s[:4])
- copy(d[8:], s[4:])
- p = unsafe.Pointer(&d[0])
- l = sysSizeofGroupReq + 4
- } else {
- p = unsafe.Pointer(&gr)
- l = sysSizeofGroupReq
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, p, l))
-}
-
-func setsockoptGroupSourceReq(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
- var gsr sysGroupSourceReq
- if ifi != nil {
- gsr.Interface = uint32(ifi.Index)
- }
- gsr.setSourceGroup(grp, src)
- var p unsafe.Pointer
- var l sysSockoptLen
- if freebsd32o64 {
- var d [sysSizeofGroupSourceReq + 4]byte
- s := (*[sysSizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))
- copy(d[:4], s[:4])
- copy(d[8:], s[4:])
- p = unsafe.Pointer(&d[0])
- l = sysSizeofGroupSourceReq + 4
- } else {
- p = unsafe.Pointer(&gsr)
- l = sysSizeofGroupSourceReq
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, p, l))
-}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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 nacl plan9 solaris
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
package ipv6
-import "net"
+import (
+ "net"
-func getMTUInfo(fd int, opt *sockOpt) (*net.Interface, int, error) {
+ "golang.org/x/net/bpf"
+ "golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
+ return nil, errOpNoSupport
+}
+
+func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
+ return errOpNoSupport
+}
+
+func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
+ return nil, errOpNoSupport
+}
+
+func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
+ return errOpNoSupport
+}
+
+func (so *sockOpt) getMTUInfo(c *socket.Conn) (*net.Interface, int, error) {
return nil, 0, errOpNoSupport
}
+
+func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
+ return errOpNoSupport
+}
+
+func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
+ return errOpNoSupport
+}
+
+func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
+ return errOpNoSupport
+}
+++ /dev/null
-// Copyright 2013 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
-
-package ipv6
-
-import (
- "net"
- "os"
- "unsafe"
-)
-
-func getInt(fd int, opt *sockOpt) (int, error) {
- if opt.name < 1 || opt.typ != ssoTypeInt {
- return 0, errOpNoSupport
- }
- var i int32
- l := sysSockoptLen(4)
- if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), &l); err != nil {
- return 0, os.NewSyscallError("getsockopt", err)
- }
- return int(i), nil
-}
-
-func setInt(fd int, opt *sockOpt, v int) error {
- if opt.name < 1 || opt.typ != ssoTypeInt {
- return errOpNoSupport
- }
- i := int32(v)
- return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), sysSockoptLen(4)))
-}
-
-func getInterface(fd int, opt *sockOpt) (*net.Interface, error) {
- if opt.name < 1 || opt.typ != ssoTypeInterface {
- return nil, errOpNoSupport
- }
- var i int32
- l := sysSockoptLen(4)
- if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), &l); err != nil {
- return nil, os.NewSyscallError("getsockopt", err)
- }
- if i == 0 {
- return nil, nil
- }
- ifi, err := net.InterfaceByIndex(int(i))
- if err != nil {
- return nil, err
- }
- return ifi, nil
-}
-
-func setInterface(fd int, opt *sockOpt, ifi *net.Interface) error {
- if opt.name < 1 || opt.typ != ssoTypeInterface {
- return errOpNoSupport
- }
- var i int32
- if ifi != nil {
- i = int32(ifi.Index)
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), sysSockoptLen(4)))
-}
-
-func getICMPFilter(fd int, opt *sockOpt) (*ICMPFilter, error) {
- if opt.name < 1 || opt.typ != ssoTypeICMPFilter {
- return nil, errOpNoSupport
- }
- var f ICMPFilter
- l := sysSockoptLen(sysSizeofICMPv6Filter)
- if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&f.sysICMPv6Filter), &l); err != nil {
- return nil, os.NewSyscallError("getsockopt", err)
- }
- return &f, nil
-}
-
-func setICMPFilter(fd int, opt *sockOpt, f *ICMPFilter) error {
- if opt.name < 1 || opt.typ != ssoTypeICMPFilter {
- return errOpNoSupport
- }
- return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&f.sysICMPv6Filter), sysSizeofICMPv6Filter))
-}
-
-func getMTUInfo(fd int, opt *sockOpt) (*net.Interface, int, error) {
- if opt.name < 1 || opt.typ != ssoTypeMTUInfo {
- return nil, 0, errOpNoSupport
- }
- var mi sysIPv6Mtuinfo
- l := sysSockoptLen(sysSizeofIPv6Mtuinfo)
- if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&mi), &l); err != nil {
- return nil, 0, os.NewSyscallError("getsockopt", err)
- }
- if mi.Addr.Scope_id == 0 {
- return nil, int(mi.Mtu), nil
- }
- ifi, err := net.InterfaceByIndex(int(mi.Addr.Scope_id))
- if err != nil {
- return nil, 0, err
- }
- return ifi, int(mi.Mtu), nil
-}
-
-func setGroup(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
- if opt.name < 1 {
- return errOpNoSupport
- }
- switch opt.typ {
- case ssoTypeIPMreq:
- return setsockoptIPMreq(fd, opt, ifi, grp)
- case ssoTypeGroupReq:
- return setsockoptGroupReq(fd, opt, ifi, grp)
- default:
- return errOpNoSupport
- }
-}
-
-func setSourceGroup(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
- if opt.name < 1 || opt.typ != ssoTypeGroupSourceReq {
- return errOpNoSupport
- }
- return setsockoptGroupSourceReq(fd, opt, ifi, grp, src)
-}
+++ /dev/null
-// Copyright 2013 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 ipv6
-
-import (
- "net"
- "os"
- "syscall"
- "unsafe"
-)
-
-func getInt(fd syscall.Handle, opt *sockOpt) (int, error) {
- if opt.name < 1 || opt.typ != ssoTypeInt {
- return 0, errOpNoSupport
- }
- var i int32
- l := int32(4)
- if err := syscall.Getsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), &l); err != nil {
- return 0, os.NewSyscallError("getsockopt", err)
- }
- return int(i), nil
-}
-
-func setInt(fd syscall.Handle, opt *sockOpt, v int) error {
- if opt.name < 1 || opt.typ != ssoTypeInt {
- return errOpNoSupport
- }
- i := int32(v)
- return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), 4))
-}
-
-func getInterface(fd syscall.Handle, opt *sockOpt) (*net.Interface, error) {
- if opt.name < 1 || opt.typ != ssoTypeInterface {
- return nil, errOpNoSupport
- }
- var i int32
- l := int32(4)
- if err := syscall.Getsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), &l); err != nil {
- return nil, os.NewSyscallError("getsockopt", err)
- }
- if i == 0 {
- return nil, nil
- }
- ifi, err := net.InterfaceByIndex(int(i))
- if err != nil {
- return nil, err
- }
- return ifi, nil
-}
-
-func setInterface(fd syscall.Handle, opt *sockOpt, ifi *net.Interface) error {
- if opt.name < 1 || opt.typ != ssoTypeInterface {
- return errOpNoSupport
- }
- var i int32
- if ifi != nil {
- i = int32(ifi.Index)
- }
- return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), 4))
-}
-
-func getICMPFilter(fd syscall.Handle, opt *sockOpt) (*ICMPFilter, error) {
- return nil, errOpNoSupport
-}
-
-func setICMPFilter(fd syscall.Handle, opt *sockOpt, f *ICMPFilter) error {
- return errOpNoSupport
-}
-
-func getMTUInfo(fd syscall.Handle, opt *sockOpt) (*net.Interface, int, error) {
- return nil, 0, errOpNoSupport
-}
-
-func setGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
- if opt.name < 1 || opt.typ != ssoTypeIPMreq {
- return errOpNoSupport
- }
- return setsockoptIPMreq(fd, opt, ifi, grp)
-}
-
-func setSourceGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
- // TODO(mikio): implement this
- return errOpNoSupport
-}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
"syscall"
"golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
-type sysSockoptLen int32
-
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {sysIPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {sysIPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
- ctlPacketInfo: {sysIPV6_PKTINFO, sysSizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
- ctlNextHop: {sysIPV6_NEXTHOP, sysSizeofSockaddrInet6, marshalNextHop, parseNextHop},
- ctlPathMTU: {sysIPV6_PATHMTU, sysSizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
+ ctlPacketInfo: {sysIPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
+ ctlNextHop: {sysIPV6_NEXTHOP, sizeofSockaddrInet6, marshalNextHop, parseNextHop},
+ ctlPathMTU: {sysIPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
- sockOpts = [ssoMax]sockOpt{
- ssoTrafficClass: {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
- ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
- ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
- ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
- ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
- ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
- ssoReceiveHopLimit: {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
- ssoReceivePacketInfo: {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
- ssoReceivePathMTU: {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
- ssoPathMTU: {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
- ssoChecksum: {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
- ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
- ssoJoinGroup: {iana.ProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq},
- ssoLeaveGroup: {iana.ProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq},
+ sockOpts = map[int]*sockOpt{
+ ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_TCLASS, Len: 4}},
+ ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+ ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+ ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+ ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+ ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVTCLASS, Len: 4}},
+ ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVHOPLIMIT, Len: 4}},
+ ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPKTINFO, Len: 4}},
+ ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPATHMTU, Len: 4}},
+ ssoPathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
+ ssoChecksum: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_CHECKSUM, Len: 4}},
+ ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: sysICMP6_FILTER, Len: sizeofICMPv6Filter}},
+ ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_JOIN_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
+ ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_LEAVE_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
}
)
-func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
- sa.Len = sysSizeofSockaddrInet6
+func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
+ sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
-func (pi *sysInet6Pktinfo) setIfindex(i int) {
+func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
-func (mreq *sysIPv6Mreq) setIfindex(i int) {
+func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
import (
"net"
+ "strconv"
+ "strings"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
-type sysSockoptLen int32
-
var (
ctlOpts = [ctlMax]ctlOpt{
ctlHopLimit: {sysIPV6_2292HOPLIMIT, 4, marshal2292HopLimit, parseHopLimit},
- ctlPacketInfo: {sysIPV6_2292PKTINFO, sysSizeofInet6Pktinfo, marshal2292PacketInfo, parsePacketInfo},
+ ctlPacketInfo: {sysIPV6_2292PKTINFO, sizeofInet6Pktinfo, marshal2292PacketInfo, parsePacketInfo},
}
- sockOpts = [ssoMax]sockOpt{
- ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
- ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
- ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
- ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
- ssoReceiveHopLimit: {iana.ProtocolIPv6, sysIPV6_2292HOPLIMIT, ssoTypeInt},
- ssoReceivePacketInfo: {iana.ProtocolIPv6, sysIPV6_2292PKTINFO, ssoTypeInt},
- ssoChecksum: {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
- ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
- ssoJoinGroup: {iana.ProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq},
- ssoLeaveGroup: {iana.ProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq},
+ sockOpts = map[int]*sockOpt{
+ ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+ ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+ ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+ ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+ ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_2292HOPLIMIT, Len: 4}},
+ ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_2292PKTINFO, Len: 4}},
+ ssoChecksum: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_CHECKSUM, Len: 4}},
+ ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: sysICMP6_FILTER, Len: sizeofICMPv6Filter}},
+ ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_JOIN_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
+ ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_LEAVE_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
}
)
func init() {
// Seems like kern.osreldate is veiled on latest OS X. We use
// kern.osrelease instead.
- osver, err := syscall.Sysctl("kern.osrelease")
+ s, err := syscall.Sysctl("kern.osrelease")
if err != nil {
return
}
- var i int
- for i = range osver {
- if osver[i] == '.' {
- break
- }
+ ss := strings.Split(s, ".")
+ if len(ss) == 0 {
+ return
}
// The IP_PKTINFO and protocol-independent multicast API were
- // introduced in OS X 10.7 (Darwin 11.0.0). But it looks like
- // those features require OS X 10.8 (Darwin 12.0.0) and above.
+ // introduced in OS X 10.7 (Darwin 11). But it looks like
+ // those features require OS X 10.8 (Darwin 12) or above.
// See http://support.apple.com/kb/HT1633.
- if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '2' {
- ctlOpts[ctlTrafficClass].name = sysIPV6_TCLASS
- ctlOpts[ctlTrafficClass].length = 4
- ctlOpts[ctlTrafficClass].marshal = marshalTrafficClass
- ctlOpts[ctlTrafficClass].parse = parseTrafficClass
- ctlOpts[ctlHopLimit].name = sysIPV6_HOPLIMIT
- ctlOpts[ctlHopLimit].marshal = marshalHopLimit
- ctlOpts[ctlPacketInfo].name = sysIPV6_PKTINFO
- ctlOpts[ctlPacketInfo].marshal = marshalPacketInfo
- ctlOpts[ctlNextHop].name = sysIPV6_NEXTHOP
- ctlOpts[ctlNextHop].length = sysSizeofSockaddrInet6
- ctlOpts[ctlNextHop].marshal = marshalNextHop
- ctlOpts[ctlNextHop].parse = parseNextHop
- ctlOpts[ctlPathMTU].name = sysIPV6_PATHMTU
- ctlOpts[ctlPathMTU].length = sysSizeofIPv6Mtuinfo
- ctlOpts[ctlPathMTU].marshal = marshalPathMTU
- ctlOpts[ctlPathMTU].parse = parsePathMTU
- sockOpts[ssoTrafficClass].level = iana.ProtocolIPv6
- sockOpts[ssoTrafficClass].name = sysIPV6_TCLASS
- sockOpts[ssoTrafficClass].typ = ssoTypeInt
- sockOpts[ssoReceiveTrafficClass].level = iana.ProtocolIPv6
- sockOpts[ssoReceiveTrafficClass].name = sysIPV6_RECVTCLASS
- sockOpts[ssoReceiveTrafficClass].typ = ssoTypeInt
- sockOpts[ssoReceiveHopLimit].name = sysIPV6_RECVHOPLIMIT
- sockOpts[ssoReceivePacketInfo].name = sysIPV6_RECVPKTINFO
- sockOpts[ssoReceivePathMTU].level = iana.ProtocolIPv6
- sockOpts[ssoReceivePathMTU].name = sysIPV6_RECVPATHMTU
- sockOpts[ssoReceivePathMTU].typ = ssoTypeInt
- sockOpts[ssoPathMTU].level = iana.ProtocolIPv6
- sockOpts[ssoPathMTU].name = sysIPV6_PATHMTU
- sockOpts[ssoPathMTU].typ = ssoTypeMTUInfo
- sockOpts[ssoJoinGroup].name = sysMCAST_JOIN_GROUP
- sockOpts[ssoJoinGroup].typ = ssoTypeGroupReq
- sockOpts[ssoLeaveGroup].name = sysMCAST_LEAVE_GROUP
- sockOpts[ssoLeaveGroup].typ = ssoTypeGroupReq
- sockOpts[ssoJoinSourceGroup].level = iana.ProtocolIPv6
- sockOpts[ssoJoinSourceGroup].name = sysMCAST_JOIN_SOURCE_GROUP
- sockOpts[ssoJoinSourceGroup].typ = ssoTypeGroupSourceReq
- sockOpts[ssoLeaveSourceGroup].level = iana.ProtocolIPv6
- sockOpts[ssoLeaveSourceGroup].name = sysMCAST_LEAVE_SOURCE_GROUP
- sockOpts[ssoLeaveSourceGroup].typ = ssoTypeGroupSourceReq
- sockOpts[ssoBlockSourceGroup].level = iana.ProtocolIPv6
- sockOpts[ssoBlockSourceGroup].name = sysMCAST_BLOCK_SOURCE
- sockOpts[ssoBlockSourceGroup].typ = ssoTypeGroupSourceReq
- sockOpts[ssoUnblockSourceGroup].level = iana.ProtocolIPv6
- sockOpts[ssoUnblockSourceGroup].name = sysMCAST_UNBLOCK_SOURCE
- sockOpts[ssoUnblockSourceGroup].typ = ssoTypeGroupSourceReq
+ if mjver, err := strconv.Atoi(ss[0]); err != nil || mjver < 12 {
+ return
}
+ ctlOpts[ctlTrafficClass] = ctlOpt{sysIPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass}
+ ctlOpts[ctlHopLimit] = ctlOpt{sysIPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit}
+ ctlOpts[ctlPacketInfo] = ctlOpt{sysIPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo}
+ ctlOpts[ctlNextHop] = ctlOpt{sysIPV6_NEXTHOP, sizeofSockaddrInet6, marshalNextHop, parseNextHop}
+ ctlOpts[ctlPathMTU] = ctlOpt{sysIPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU}
+ sockOpts[ssoTrafficClass] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_TCLASS, Len: 4}}
+ sockOpts[ssoReceiveTrafficClass] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVTCLASS, Len: 4}}
+ sockOpts[ssoReceiveHopLimit] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVHOPLIMIT, Len: 4}}
+ sockOpts[ssoReceivePacketInfo] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPKTINFO, Len: 4}}
+ sockOpts[ssoReceivePathMTU] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPATHMTU, Len: 4}}
+ sockOpts[ssoPathMTU] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}}
+ sockOpts[ssoJoinGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq}
+ sockOpts[ssoLeaveGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq}
+ sockOpts[ssoJoinSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+ sockOpts[ssoLeaveSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+ sockOpts[ssoBlockSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+ sockOpts[ssoUnblockSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
}
-func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
- sa.Len = sysSizeofSockaddrInet6
+func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
+ sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
-func (pi *sysInet6Pktinfo) setIfindex(i int) {
+func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
-func (mreq *sysIPv6Mreq) setIfindex(i int) {
+func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}
-func (gr *sysGroupReq) setGroup(grp net.IP) {
- sa := (*sysSockaddrInet6)(unsafe.Pointer(&gr.Pad_cgo_0[0]))
- sa.Len = sysSizeofSockaddrInet6
+func (gr *groupReq) setGroup(grp net.IP) {
+ sa := (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gr)) + 4))
+ sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
}
-func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
- sa := (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Pad_cgo_0[0]))
- sa.Len = sysSizeofSockaddrInet6
+func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
+ sa := (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 4))
+ sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
- sa = (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Pad_cgo_1[0]))
- sa.Len = sysSizeofSockaddrInet6
+ sa = (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 132))
+ sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], src)
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
"unsafe"
"golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
-type sysSockoptLen int32
-
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {sysIPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {sysIPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
- ctlPacketInfo: {sysIPV6_PKTINFO, sysSizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
- ctlNextHop: {sysIPV6_NEXTHOP, sysSizeofSockaddrInet6, marshalNextHop, parseNextHop},
- ctlPathMTU: {sysIPV6_PATHMTU, sysSizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
+ ctlPacketInfo: {sysIPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
+ ctlNextHop: {sysIPV6_NEXTHOP, sizeofSockaddrInet6, marshalNextHop, parseNextHop},
+ ctlPathMTU: {sysIPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
- sockOpts = [ssoMax]sockOpt{
- ssoTrafficClass: {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
- ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
- ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
- ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
- ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
- ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
- ssoReceiveHopLimit: {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
- ssoReceivePacketInfo: {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
- ssoReceivePathMTU: {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
- ssoPathMTU: {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
- ssoChecksum: {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
- ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
- ssoJoinGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
- ssoLeaveGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
- ssoJoinSourceGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
- ssoLeaveSourceGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
- ssoBlockSourceGroup: {iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
- ssoUnblockSourceGroup: {iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
+ sockOpts = map[int]sockOpt{
+ ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_TCLASS, Len: 4}},
+ ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+ ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+ ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+ ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+ ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVTCLASS, Len: 4}},
+ ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVHOPLIMIT, Len: 4}},
+ ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPKTINFO, Len: 4}},
+ ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPATHMTU, Len: 4}},
+ ssoPathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
+ ssoChecksum: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_CHECKSUM, Len: 4}},
+ ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: sysICMP6_FILTER, Len: sizeofICMPv6Filter}},
+ ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+ ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+ ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
}
)
}
}
-func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
- sa.Len = sysSizeofSockaddrInet6
+func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
+ sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
-func (pi *sysInet6Pktinfo) setIfindex(i int) {
+func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
-func (mreq *sysIPv6Mreq) setIfindex(i int) {
+func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}
-func (gr *sysGroupReq) setGroup(grp net.IP) {
- sa := (*sysSockaddrInet6)(unsafe.Pointer(&gr.Group))
- sa.Len = sysSizeofSockaddrInet6
+func (gr *groupReq) setGroup(grp net.IP) {
+ sa := (*sockaddrInet6)(unsafe.Pointer(&gr.Group))
+ sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
}
-func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
- sa := (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Group))
- sa.Len = sysSizeofSockaddrInet6
+func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
+ sa := (*sockaddrInet6)(unsafe.Pointer(&gsr.Group))
+ sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
- sa = (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Source))
- sa.Len = sysSizeofSockaddrInet6
+ sa = (*sockaddrInet6)(unsafe.Pointer(&gsr.Source))
+ sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], src)
}
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
"unsafe"
"golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
-type sysSockoptLen int32
-
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {sysIPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {sysIPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
- ctlPacketInfo: {sysIPV6_PKTINFO, sysSizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
- ctlPathMTU: {sysIPV6_PATHMTU, sysSizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
+ ctlPacketInfo: {sysIPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
+ ctlPathMTU: {sysIPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
- sockOpts = [ssoMax]sockOpt{
- ssoTrafficClass: {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
- ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
- ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
- ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
- ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
- ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
- ssoReceiveHopLimit: {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
- ssoReceivePacketInfo: {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
- ssoReceivePathMTU: {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
- ssoPathMTU: {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
- ssoChecksum: {iana.ProtocolReserved, sysIPV6_CHECKSUM, ssoTypeInt},
- ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMPV6_FILTER, ssoTypeICMPFilter},
- ssoJoinGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
- ssoLeaveGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
- ssoJoinSourceGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
- ssoLeaveSourceGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
- ssoBlockSourceGroup: {iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
- ssoUnblockSourceGroup: {iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
+ sockOpts = map[int]*sockOpt{
+ ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_TCLASS, Len: 4}},
+ ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+ ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+ ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+ ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+ ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVTCLASS, Len: 4}},
+ ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVHOPLIMIT, Len: 4}},
+ ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPKTINFO, Len: 4}},
+ ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPATHMTU, Len: 4}},
+ ssoPathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
+ ssoChecksum: {Option: socket.Option{Level: iana.ProtocolReserved, Name: sysIPV6_CHECKSUM, Len: 4}},
+ ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: sysICMPV6_FILTER, Len: sizeofICMPv6Filter}},
+ ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+ ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+ ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+ ssoAttachFilter: {Option: socket.Option{Level: sysSOL_SOCKET, Name: sysSO_ATTACH_FILTER, Len: sizeofSockFprog}},
}
)
-func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
+func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
-func (pi *sysInet6Pktinfo) setIfindex(i int) {
+func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = int32(i)
}
-func (mreq *sysIPv6Mreq) setIfindex(i int) {
+func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Ifindex = int32(i)
}
-func (gr *sysGroupReq) setGroup(grp net.IP) {
- sa := (*sysSockaddrInet6)(unsafe.Pointer(&gr.Group))
+func (gr *groupReq) setGroup(grp net.IP) {
+ sa := (*sockaddrInet6)(unsafe.Pointer(&gr.Group))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
}
-func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
- sa := (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Group))
+func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
+ sa := (*sockaddrInet6)(unsafe.Pointer(&gsr.Group))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
- sa = (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Source))
+ sa = (*sockaddrInet6)(unsafe.Pointer(&gsr.Source))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], src)
}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nacl plan9 solaris
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
package ipv6
-type sysSockoptLen int32
-
var (
ctlOpts = [ctlMax]ctlOpt{}
- sockOpts = [ssoMax]sockOpt{}
+ sockOpts = map[int]*sockOpt{}
)
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
"syscall"
"golang.org/x/net/internal/iana"
+ "golang.org/x/net/internal/socket"
)
const (
sysIPV6_LEAVE_GROUP = 0xd
sysIPV6_PKTINFO = 0x13
- sysSizeofSockaddrInet6 = 0x1c
+ sizeofSockaddrInet6 = 0x1c
- sysSizeofIPv6Mreq = 0x14
+ sizeofIPv6Mreq = 0x14
+ sizeofIPv6Mtuinfo = 0x20
+ sizeofICMPv6Filter = 0
)
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Scope_id uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
+ Mtu uint32
+}
+
+type icmpv6Filter struct {
+ // TODO(mikio): implement this
+}
+
var (
ctlOpts = [ctlMax]ctlOpt{}
- sockOpts = [ssoMax]sockOpt{
- ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
- ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
- ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
- ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
- ssoJoinGroup: {iana.ProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq},
- ssoLeaveGroup: {iana.ProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq},
+ sockOpts = map[int]*sockOpt{
+ ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+ ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+ ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+ ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+ ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_JOIN_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
+ ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_LEAVE_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
}
)
-func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
+func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
-func (mreq *sysIPv6Mreq) setIfindex(i int) {
+func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}
+++ /dev/null
-// Copyright 2009 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 ipv6
-
-import (
- "syscall"
- "unsafe"
-)
-
-const (
- sysGETSOCKOPT = 0xf
- sysSETSOCKOPT = 0xe
-)
-
-func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
-
-func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error {
- if _, errno := socketcall(sysGETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
- return error(errno)
- }
- return nil
-}
-
-func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error {
- if _, errno := socketcall(sysSETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
- return error(errno)
- }
- return nil
-}
+++ /dev/null
-// Copyright 2013 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,!386 netbsd openbsd
-
-package ipv6
-
-import (
- "syscall"
- "unsafe"
-)
-
-func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error {
- if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
- return error(errno)
- }
- return nil
-}
-
-func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error {
- if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
- return error(errno)
- }
- return nil
-}
+++ /dev/null
-// Copyright 2014 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 go1.2
-
-TEXT ·socketcall(SB),4,$0-36
- JMP syscall·socketcall(SB)
sysIPV6_PORTRANGE_HIGH = 0x1
sysIPV6_PORTRANGE_LOW = 0x2
- sysSizeofSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
+ sizeofSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x84
- sysSizeofGroupSourceReq = 0x104
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x84
+ sizeofGroupSourceReq = 0x104
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
)
-type sysSockaddrStorage struct {
+type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_pad2 [112]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Filt [8]uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [128]byte
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [128]byte
Pad_cgo_1 [128]byte
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_dragonfly.go
-// +build dragonfly
-
package ipv6
const (
sysIPV6_PORTRANGE_HIGH = 0x1
sysIPV6_PORTRANGE_LOW = 0x2
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6Mreq = 0x14
+ sizeofIPv6Mreq = 0x14
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
)
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Filt [8]uint32
}
sysIPV6_PORTRANGE_HIGH = 0x1
sysIPV6_PORTRANGE_LOW = 0x2
- sysSizeofSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
+ sizeofSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x84
- sysSizeofGroupSourceReq = 0x104
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x84
+ sizeofGroupSourceReq = 0x104
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
)
-type sysSockaddrStorage struct {
+type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_pad2 [112]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
- Group sysSockaddrStorage
+ Group sockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
- Group sysSockaddrStorage
- Source sysSockaddrStorage
+ Group sockaddrStorage
+ Source sockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Filt [8]uint32
}
sysIPV6_PORTRANGE_HIGH = 0x1
sysIPV6_PORTRANGE_LOW = 0x2
- sysSizeofSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
+ sizeofSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
)
-type sysSockaddrStorage struct {
+type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_pad2 [112]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysSockaddrStorage
+ Group sockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysSockaddrStorage
- Source sysSockaddrStorage
+ Group sockaddrStorage
+ Source sockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Filt [8]uint32
}
sysIPV6_PORTRANGE_HIGH = 0x1
sysIPV6_PORTRANGE_LOW = 0x2
- sysSizeofSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
+ sizeofSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
)
-type sysSockaddrStorage struct {
+type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_pad2 [112]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysSockaddrStorage
+ Group sockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysSockaddrStorage
- Source sysSockaddrStorage
+ Group sockaddrStorage
+ Source sockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Filt [8]uint32
}
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
sysICMPV6_FILTER_PASSONLY = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6FlowlabelReq = 0x20
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x84
- sysSizeofGroupSourceReq = 0x104
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
+ sizeofIPv6FlowlabelReq = 0x20
- sysSizeofICMPv6Filter = 0x20
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x84
+ sizeofGroupSourceReq = 0x104
+
+ sizeofICMPv6Filter = 0x20
+
+ sizeofSockFprog = 0x8
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6FlowlabelReq struct {
+type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
X__flr_pad uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Data [8]uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [2]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
sysICMPV6_FILTER_PASSONLY = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6FlowlabelReq = 0x20
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
+ sizeofIPv6FlowlabelReq = 0x20
- sysSizeofICMPv6Filter = 0x20
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
+
+ sizeofICMPv6Filter = 0x20
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6FlowlabelReq struct {
+type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
X__flr_pad uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Data [8]uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
sysICMPV6_FILTER_PASSONLY = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6FlowlabelReq = 0x20
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x84
- sysSizeofGroupSourceReq = 0x104
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
+ sizeofIPv6FlowlabelReq = 0x20
- sysSizeofICMPv6Filter = 0x20
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x84
+ sizeofGroupSourceReq = 0x104
+
+ sizeofICMPv6Filter = 0x20
+
+ sizeofSockFprog = 0x8
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6FlowlabelReq struct {
+type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
X__flr_pad uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Data [8]uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [2]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_linux.go
-// +build linux,arm64
-
package ipv6
const (
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
sysICMPV6_FILTER_PASSONLY = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6FlowlabelReq = 0x20
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
+ sizeofIPv6FlowlabelReq = 0x20
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6FlowlabelReq struct {
+type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
X__flr_pad uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Data [8]uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_linux.go
-// +build linux,mips64
-
package ipv6
const (
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
sysICMPV6_FILTER_PASSONLY = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6FlowlabelReq = 0x20
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
+ sizeofIPv6FlowlabelReq = 0x20
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6FlowlabelReq struct {
+type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
X__flr_pad uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Data [8]uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_linux.go
-// +build linux,mips64le
-
package ipv6
const (
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
sysICMPV6_FILTER_PASSONLY = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6FlowlabelReq = 0x20
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
+ sizeofIPv6FlowlabelReq = 0x20
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6FlowlabelReq struct {
+type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
X__flr_pad uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Data [8]uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_linux.go
-// +build linux,ppc64
-
package ipv6
const (
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
sysICMPV6_FILTER_PASSONLY = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6FlowlabelReq = 0x20
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
+ sizeofIPv6FlowlabelReq = 0x20
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6FlowlabelReq struct {
+type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
X__flr_pad uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Data [8]uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_linux.go
-// +build linux,ppc64le
-
package ipv6
const (
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
sysICMPV6_FILTER_PASSONLY = 0x4
- sysSizeofKernelSockaddrStorage = 0x80
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6FlowlabelReq = 0x20
+ sysSOL_SOCKET = 0x1
+ sysSO_ATTACH_FILTER = 0x1a
+
+ sizeofKernelSockaddrStorage = 0x80
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
+ sizeofIPv6FlowlabelReq = 0x20
- sysSizeofIPv6Mreq = 0x14
- sysSizeofGroupReq = 0x88
- sysSizeofGroupSourceReq = 0x108
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x88
+ sizeofGroupSourceReq = 0x108
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
+
+ sizeofSockFprog = 0x10
)
-type sysKernelSockaddrStorage struct {
+type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6FlowlabelReq struct {
+type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
X__flr_pad uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
-type sysGroupReq struct {
+type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
}
-type sysGroupSourceReq struct {
+type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
- Group sysKernelSockaddrStorage
- Source sysKernelSockaddrStorage
+ Group kernelSockaddrStorage
+ Source kernelSockaddrStorage
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Data [8]uint32
}
+
+type sockFProg struct {
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *sockFilter
+}
+
+type sockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
sysIPV6_PORTRANGE_HIGH = 0x1
sysIPV6_PORTRANGE_LOW = 0x2
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6Mreq = 0x14
+ sizeofIPv6Mreq = 0x14
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
)
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Filt [8]uint32
}
sysIPV6_PORTRANGE_HIGH = 0x1
sysIPV6_PORTRANGE_LOW = 0x2
- sysSizeofSockaddrInet6 = 0x1c
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x20
+ sizeofSockaddrInet6 = 0x1c
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x20
- sysSizeofIPv6Mreq = 0x14
+ sizeofIPv6Mreq = 0x14
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
)
-type sysSockaddrInet6 struct {
+type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Scope_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
-type sysICMPv6Filter struct {
+type icmpv6Filter struct {
Filt [8]uint32
}
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs defs_solaris.go
-// +build solaris
-
package ipv6
const (
sysIPV6_RECVDSTOPTS = 0x28
+ sysMCAST_JOIN_GROUP = 0x29
+ sysMCAST_LEAVE_GROUP = 0x2a
+ sysMCAST_BLOCK_SOURCE = 0x2b
+ sysMCAST_UNBLOCK_SOURCE = 0x2c
+ sysMCAST_JOIN_SOURCE_GROUP = 0x2d
+ sysMCAST_LEAVE_SOURCE_GROUP = 0x2e
+
sysIPV6_PREFER_SRC_HOME = 0x1
sysIPV6_PREFER_SRC_COA = 0x2
sysIPV6_PREFER_SRC_PUBLIC = 0x4
sysICMP6_FILTER = 0x1
- sysSizeofSockaddrInet6 = 0x20
- sysSizeofInet6Pktinfo = 0x14
- sysSizeofIPv6Mtuinfo = 0x24
+ sizeofSockaddrStorage = 0x100
+ sizeofSockaddrInet6 = 0x20
+ sizeofInet6Pktinfo = 0x14
+ sizeofIPv6Mtuinfo = 0x24
- sysSizeofIPv6Mreq = 0x14
+ sizeofIPv6Mreq = 0x14
+ sizeofGroupReq = 0x104
+ sizeofGroupSourceReq = 0x204
- sysSizeofICMPv6Filter = 0x20
+ sizeofICMPv6Filter = 0x20
)
-type sysSockaddrInet6 struct {
+type sockaddrStorage struct {
+ Family uint16
+ X_ss_pad1 [6]int8
+ X_ss_align float64
+ X_ss_pad2 [240]int8
+}
+
+type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
X__sin6_src_id uint32
}
-type sysInet6Pktinfo struct {
+type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
-type sysIPv6Mtuinfo struct {
- Addr sysSockaddrInet6
+type ipv6Mtuinfo struct {
+ Addr sockaddrInet6
Mtu uint32
}
-type sysIPv6Mreq struct {
+type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
-type sysICMPv6Filter struct {
+type groupReq struct {
+ Interface uint32
+ Pad_cgo_0 [256]byte
+}
+
+type groupSourceReq struct {
+ Interface uint32
+ Pad_cgo_0 [256]byte
+ Pad_cgo_1 [256]byte
+}
+
+type icmpv6Filter struct {
X__icmp6_filt [8]uint32
}
provide suggestions. You can dynamically generate the options
```
-func listHosts(args []string) []string {
+func listHosts() []string {
// Provide a dynamic list of hosts from a hosts file or otherwise
// for bash completion. In this example we simply return static slice.
return &Token{p.argi, TokenError, err.Error()}
}
if len(p.args) == 0 {
- p.args = append(p.args, expanded...)
- } else if p.argi >= len(p.args) {
- p.args = append(p.args[:p.argi-1], expanded...)
+ p.args = expanded
} else {
- p.args = append(p.args[:p.argi-1], append(expanded, p.args[p.argi+1:]...)...)
+ p.args = append(expanded, p.args...)
}
return p.Next()
}
func (f *boolValue) Get() interface{} { return (bool)(*f.v) }
-func (f *boolValue) String() string { return fmt.Sprintf("%v", *f) }
+func (f *boolValue) String() string { return fmt.Sprintf("%v", *f.v) }
// Bool parses the next command-line value as bool.
func (p *parserMixin) Bool() (target *bool) {
func (f *uintValue) Get() interface{} { return (uint)(*f.v) }
-func (f *uintValue) String() string { return fmt.Sprintf("%v", *f) }
+func (f *uintValue) String() string { return fmt.Sprintf("%v", *f.v) }
// Uint parses the next command-line value as uint.
func (p *parserMixin) Uint() (target *uint) {
func (f *uint8Value) Get() interface{} { return (uint8)(*f.v) }
-func (f *uint8Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *uint8Value) String() string { return fmt.Sprintf("%v", *f.v) }
// Uint8 parses the next command-line value as uint8.
func (p *parserMixin) Uint8() (target *uint8) {
func (f *uint16Value) Get() interface{} { return (uint16)(*f.v) }
-func (f *uint16Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *uint16Value) String() string { return fmt.Sprintf("%v", *f.v) }
// Uint16 parses the next command-line value as uint16.
func (p *parserMixin) Uint16() (target *uint16) {
func (f *uint32Value) Get() interface{} { return (uint32)(*f.v) }
-func (f *uint32Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *uint32Value) String() string { return fmt.Sprintf("%v", *f.v) }
// Uint32 parses the next command-line value as uint32.
func (p *parserMixin) Uint32() (target *uint32) {
func (f *uint64Value) Get() interface{} { return (uint64)(*f.v) }
-func (f *uint64Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *uint64Value) String() string { return fmt.Sprintf("%v", *f.v) }
// Uint64 parses the next command-line value as uint64.
func (p *parserMixin) Uint64() (target *uint64) {
func (f *intValue) Get() interface{} { return (int)(*f.v) }
-func (f *intValue) String() string { return fmt.Sprintf("%v", *f) }
+func (f *intValue) String() string { return fmt.Sprintf("%v", *f.v) }
// Int parses the next command-line value as int.
func (p *parserMixin) Int() (target *int) {
func (f *int8Value) Get() interface{} { return (int8)(*f.v) }
-func (f *int8Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *int8Value) String() string { return fmt.Sprintf("%v", *f.v) }
// Int8 parses the next command-line value as int8.
func (p *parserMixin) Int8() (target *int8) {
func (f *int16Value) Get() interface{} { return (int16)(*f.v) }
-func (f *int16Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *int16Value) String() string { return fmt.Sprintf("%v", *f.v) }
// Int16 parses the next command-line value as int16.
func (p *parserMixin) Int16() (target *int16) {
func (f *int32Value) Get() interface{} { return (int32)(*f.v) }
-func (f *int32Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *int32Value) String() string { return fmt.Sprintf("%v", *f.v) }
// Int32 parses the next command-line value as int32.
func (p *parserMixin) Int32() (target *int32) {
func (f *int64Value) Get() interface{} { return (int64)(*f.v) }
-func (f *int64Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *int64Value) String() string { return fmt.Sprintf("%v", *f.v) }
// Int64 parses the next command-line value as int64.
func (p *parserMixin) Int64() (target *int64) {
func (f *float64Value) Get() interface{} { return (float64)(*f.v) }
-func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *float64Value) String() string { return fmt.Sprintf("%v", *f.v) }
// Float64 parses the next command-line value as float64.
func (p *parserMixin) Float64() (target *float64) {
func (f *float32Value) Get() interface{} { return (float32)(*f.v) }
-func (f *float32Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *float32Value) String() string { return fmt.Sprintf("%v", *f.v) }
// Float32 parses the next command-line value as float32.
func (p *parserMixin) Float32() (target *float32) {
func (f *regexpValue) Get() interface{} { return (*regexp.Regexp)(*f.v) }
-func (f *regexpValue) String() string { return fmt.Sprintf("%v", *f) }
+func (f *regexpValue) String() string { return fmt.Sprintf("%v", *f.v) }
// Regexp parses the next command-line value as *regexp.Regexp.
func (p *parserMixin) Regexp() (target **regexp.Regexp) {
func (f *resolvedIPValue) Get() interface{} { return (net.IP)(*f.v) }
-func (f *resolvedIPValue) String() string { return fmt.Sprintf("%v", *f) }
+func (f *resolvedIPValue) String() string { return fmt.Sprintf("%v", *f.v) }
// Resolve a hostname or IP to an IP.
func (p *parserMixin) ResolvedIP() (target *net.IP) {
func (f *hexBytesValue) Get() interface{} { return ([]byte)(*f.v) }
-func (f *hexBytesValue) String() string { return fmt.Sprintf("%v", *f) }
+func (f *hexBytesValue) String() string { return fmt.Sprintf("%v", *f.v) }
// Bytes as a hex string.
func (p *parserMixin) HexBytes() (target *[]byte) {
-
-Copyright (c) 2011-2014 - Canonical Inc.
-
-This software is licensed under the LGPLv3, included below.
-
-As a special exception to the GNU Lesser General Public License version 3
-("LGPL3"), the copyright holders of this Library give you permission to
-convey to a third party a Combined Work that links statically or dynamically
-to this Library without providing any Minimal Corresponding Source or
-Minimal Application Code as set out in 4d or providing the installation
-information set out in section 4e, provided that you comply with the other
-provisions of LGPL3 and provided that you meet, for the Application the
-terms and conditions of the license(s) which apply to the Application.
-
-Except as stated in this special exception, the provisions of LGPL3 will
-continue to comply in full to this Library. If you modify this Library, you
-may apply this exception to your version of this Library, but you are not
-obliged to do so. If you do not wish to do so, delete this exception
-statement from your version. This exception does not (and cannot) modify any
-license terms which apply to the Application, with which you must still
-comply.
-
-
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-
- This version of the GNU Lesser General Public License incorporates
-the terms and conditions of version 3 of the GNU General Public
-License, supplemented by the additional permissions listed below.
-
- 0. Additional Definitions.
-
- As used herein, "this License" refers to version 3 of the GNU Lesser
-General Public License, and the "GNU GPL" refers to version 3 of the GNU
-General Public License.
-
- "The Library" refers to a covered work governed by this License,
-other than an Application or a Combined Work as defined below.
-
- An "Application" is any work that makes use of an interface provided
-by the Library, but which is not otherwise based on the Library.
-Defining a subclass of a class defined by the Library is deemed a mode
-of using an interface provided by the Library.
-
- A "Combined Work" is a work produced by combining or linking an
-Application with the Library. The particular version of the Library
-with which the Combined Work was made is also called the "Linked
-Version".
-
- The "Minimal Corresponding Source" for a Combined Work means the
-Corresponding Source for the Combined Work, excluding any source code
-for portions of the Combined Work that, considered in isolation, are
-based on the Application, and not on the Linked Version.
-
- The "Corresponding Application Code" for a Combined Work means the
-object code and/or source code for the Application, including any data
-and utility programs needed for reproducing the Combined Work from the
-Application, but excluding the System Libraries of the Combined Work.
-
- 1. Exception to Section 3 of the GNU GPL.
-
- You may convey a covered work under sections 3 and 4 of this License
-without being bound by section 3 of the GNU GPL.
-
- 2. Conveying Modified Versions.
-
- If you modify a copy of the Library, and, in your modifications, a
-facility refers to a function or data to be supplied by an Application
-that uses the facility (other than as an argument passed when the
-facility is invoked), then you may convey a copy of the modified
-version:
-
- a) under this License, provided that you make a good faith effort to
- ensure that, in the event an Application does not supply the
- function or data, the facility still operates, and performs
- whatever part of its purpose remains meaningful, or
-
- b) under the GNU GPL, with none of the additional permissions of
- this License applicable to that copy.
-
- 3. Object Code Incorporating Material from Library Header Files.
-
- The object code form of an Application may incorporate material from
-a header file that is part of the Library. You may convey such object
-code under terms of your choice, provided that, if the incorporated
-material is not limited to numerical parameters, data structure
-layouts and accessors, or small macros, inline functions and templates
-(ten or fewer lines in length), you do both of the following:
-
- a) Give prominent notice with each copy of the object code that the
- Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the object code with a copy of the GNU GPL and this license
- document.
-
- 4. Combined Works.
-
- You may convey a Combined Work under terms of your choice that,
-taken together, effectively do not restrict modification of the
-portions of the Library contained in the Combined Work and reverse
-engineering for debugging such modifications, if you also do each of
-the following:
-
- a) Give prominent notice with each copy of the Combined Work that
- the Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the Combined Work with a copy of the GNU GPL and this license
- document.
-
- c) For a Combined Work that displays copyright notices during
- execution, include the copyright notice for the Library among
- these notices, as well as a reference directing the user to the
- copies of the GNU GPL and this license document.
-
- d) Do one of the following:
-
- 0) Convey the Minimal Corresponding Source under the terms of this
- License, and the Corresponding Application Code in a form
- suitable for, and under terms that permit, the user to
- recombine or relink the Application with a modified version of
- the Linked Version to produce a modified Combined Work, in the
- manner specified by section 6 of the GNU GPL for conveying
- Corresponding Source.
-
- 1) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (a) uses at run time
- a copy of the Library already present on the user's computer
- system, and (b) will operate properly with a modified version
- of the Library that is interface-compatible with the Linked
- Version.
-
- e) Provide Installation Information, but only if you would otherwise
- be required to provide such information under section 6 of the
- GNU GPL, and only to the extent that such information is
- necessary to install and execute a modified version of the
- Combined Work produced by recombining or relinking the
- Application with a modified version of the Linked Version. (If
- you use option 4d0, the Installation Information must accompany
- the Minimal Corresponding Source and Corresponding Application
- Code. If you use option 4d1, you must provide the Installation
- Information in the manner specified by section 6 of the GNU GPL
- for conveying Corresponding Source.)
-
- 5. Combined Libraries.
-
- You may place library facilities that are a work based on the
-Library side by side in a single library together with other library
-facilities that are not Applications and are not covered by this
-License, and convey such a combined library under terms of your
-choice, if you do both of the following:
-
- a) Accompany the combined library with a copy of the same work based
- on the Library, uncombined with any other library facilities,
- conveyed under the terms of this License.
-
- b) Give prominent notice with the combined library that part of it
- is a work based on the Library, and explaining where to find the
- accompanying uncombined form of the same work.
-
- 6. Revised Versions of the GNU Lesser General Public License.
-
- The Free Software Foundation may publish revised and/or new versions
-of the GNU Lesser General Public License from time to time. Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Library as you received it specifies that a certain numbered version
-of the GNU Lesser General Public License "or any later version"
-applies to it, you have the option of following the terms and
-conditions either of that published version or of any later version
-published by the Free Software Foundation. If the Library as you
-received it does not specify a version number of the GNU Lesser
-General Public License, you may choose any version of the GNU Lesser
-General Public License ever published by the Free Software Foundation.
-
- If the Library as you received it specifies that a proxy can decide
-whether future versions of the GNU Lesser General Public License shall
-apply, that proxy's public statement of acceptance of any version is
-permanent authorization for you to choose that version for the
-Library.
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
License
-------
-The yaml package is licensed under the LGPL with an exception that allows it to be linked statically. Please see the LICENSE file for details.
+The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details.
Example
-------
+Some more examples can be found in the "examples" folder.
+
```Go
package main
default:
panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ)))
}
- panic("unreachable")
}
func (p *parser) node(kind int) *node {
aliases map[string]bool
mapType reflect.Type
terrors []string
+ strict bool
}
var (
ifaceType = defaultMapType.Elem()
)
-func newDecoder() *decoder {
- d := &decoder{mapType: defaultMapType}
+func newDecoder(strict bool) *decoder {
+ d := &decoder{mapType: defaultMapType, strict: strict}
d.aliases = make(map[string]bool)
return d
}
//
// If n holds a null value, prepare returns before doing anything.
func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
- if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "") {
+ if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "" && n.implicit) {
return out, false, false
}
again := true
value := reflect.New(elemType).Elem()
d.unmarshal(n.children[i+1], value)
inlineMap.SetMapIndex(name, value)
+ } else if d.strict {
+ d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in struct %s", n.line+1, name.String(), out.Type()))
}
}
return true
return yaml_emitter_set_emitter_error(emitter,
"expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS")
}
- return false
}
// Expect ALIAS.
break_space = false
space_break = false
- preceeded_by_whitespace = false
+ preceded_by_whitespace = false
followed_by_whitespace = false
previous_space = false
previous_break = false
flow_indicators = true
}
- preceeded_by_whitespace = true
+ preceded_by_whitespace = true
for i, w := 0, 0; i < len(value); i += w {
w = width(value[i])
followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
block_indicators = true
}
case '#':
- if preceeded_by_whitespace {
+ if preceded_by_whitespace {
flow_indicators = true
block_indicators = true
}
}
// [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
- preceeded_by_whitespace = is_blankz(value, i)
+ preceded_by_whitespace = is_blankz(value, i)
}
emitter.scalar_data.multiline = line_breaks
default:
panic("invalid parser state")
}
- return false
}
// Parse the production:
import (
"encoding/base64"
"math"
+ "regexp"
"strconv"
"strings"
"unicode/utf8"
return false
}
+var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`)
+
func resolve(tag string, in string) (rtag string, out interface{}) {
if !resolvableTag(tag) {
return tag, in
if err == nil {
return yaml_INT_TAG, uintv
}
- floatv, err := strconv.ParseFloat(plain, 64)
- if err == nil {
- return yaml_FLOAT_TAG, floatv
+ if yamlStyleFloat.MatchString(plain) {
+ floatv, err := strconv.ParseFloat(plain, 64)
+ if err == nil {
+ return yaml_FLOAT_TAG, floatv
+ }
}
if strings.HasPrefix(plain, "0b") {
intv, err := strconv.ParseInt(plain[2:], 2, 64)
// ************
//
// The following notes assume that you are familiar with the YAML specification
-// (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in
+// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in
// some cases we are less restrictive that it requires.
//
// The process of transforming a YAML stream into a sequence of events is
if directive {
context = "while parsing a %TAG directive"
}
- return yaml_parser_set_scanner_error(parser, context, context_mark, "did not find URI escaped octet")
+ return yaml_parser_set_scanner_error(parser, context, context_mark, problem)
}
func trace(args ...interface{}) func() {
} else {
// It's either the '!' tag or not really a tag handle. If it's a %TAG
// directive, it's an error. If it's a tag token, it must be a part of URI.
- if directive && !(s[0] == '!' && s[1] == 0) {
+ if directive && string(s) != "!" {
yaml_parser_set_scanner_tag_error(parser, directive,
start_mark, "did not find expected '!'")
return false
func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
//size_t length = head ? strlen((char *)head) : 0
var s []byte
+ hasTag := len(head) > 0
// Copy the head if needed.
//
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
return false
}
+ hasTag = true
}
- // Check if the tag is non-empty.
- if len(s) == 0 {
+ if !hasTag {
yaml_parser_set_scanner_tag_error(parser, directive,
start_mark, "did not find expected tag URI")
return false
// supported tag options.
//
func Unmarshal(in []byte, out interface{}) (err error) {
+ return unmarshal(in, out, false)
+}
+
+// UnmarshalStrict is like Unmarshal except that any fields that are found
+// in the data that do not have corresponding struct members will result in
+// an error.
+func UnmarshalStrict(in []byte, out interface{}) (err error) {
+ return unmarshal(in, out, true)
+}
+
+func unmarshal(in []byte, out interface{}, strict bool) (err error) {
defer handleErr(&err)
- d := newDecoder()
+ d := newDecoder(strict)
p := newParser(in)
defer p.destroy()
node := p.parse()
problem string // Error description.
- // The byte about which the problem occured.
+ // The byte about which the problem occurred.
problem_offset int
problem_value int
problem_mark yaml_mark_t
"revisionTime": "2015-10-22T06:55:26Z"
},
{
- "checksumSHA1": "4QnLdmB1kG3N+KlDd1N+G9TWAGQ=",
+ "checksumSHA1": "spyv5/YFBjYyZLZa1U2LBfDR8PM=",
"path": "github.com/beorn7/perks/quantile",
- "revision": "3ac7bf7a47d159a033b107610db8a1b6575507a4",
- "revisionTime": "2016-02-29T22:34:45+01:00"
+ "revision": "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9",
+ "revisionTime": "2016-08-04T10:47:26Z"
},
{
- "checksumSHA1": "bzCBeQrZ+LxbYyJbp7uDILX6t7c=",
+ "checksumSHA1": "KrIRJ4p3nRze4NcxfgX5+N9+D1M=",
"path": "github.com/go-kit/kit/log",
- "revision": "bc4df5b6d8156c977195a8b9637ecea5f1187a0d",
- "revisionTime": "2017-04-20T00:59:06Z"
+ "revision": "0d313fb5fb3a94d87d61e6434785264e87a5d740",
+ "revisionTime": "2017-09-17T20:27:34Z"
},
{
"checksumSHA1": "t7aTpDH0h4BZcGU0KkUr14QQG2w=",
"path": "github.com/go-kit/kit/log/level",
- "revision": "bc4df5b6d8156c977195a8b9637ecea5f1187a0d",
- "revisionTime": "2017-04-20T00:59:06Z"
+ "revision": "0d313fb5fb3a94d87d61e6434785264e87a5d740",
+ "revisionTime": "2017-09-17T20:27:34Z"
},
{
"checksumSHA1": "KxX/Drph+byPXBFIXaCZaCOAnrU=",
"revisionTime": "2016-11-15T14:25:13Z"
},
{
- "checksumSHA1": "2sj/DbXoXdnPAfjAEyhS0Jj5QL0=",
+ "checksumSHA1": "j6vhe49MX+dyHR9rU91P6vMx55o=",
"path": "github.com/go-stack/stack",
- "revision": "100eb0c0a9c5b306ca2fb4f165df21d80ada4b82",
- "revisionTime": "2016-05-14T03:44:11Z"
+ "revision": "817915b46b97fd7bb80e8ab6b69f01a53ac3eebf",
+ "revisionTime": "2017-07-24T01:23:01Z"
},
{
- "checksumSHA1": "UQtJP2n/HEBhHaq6a9R2hCHgy+8=",
+ "checksumSHA1": "yqF125xVSkmfLpIVGrLlfE05IUk=",
"path": "github.com/golang/protobuf/proto",
- "revision": "8d92cf5fc15a4382f8964b08e1f42a75c0591aa3",
- "revisionTime": "2016-03-19T05:57:00+11:00"
+ "revision": "ae59567b9aab61b50b2590679a62c3c044030b61",
+ "revisionTime": "2017-09-19T00:21:09Z"
},
{
"checksumSHA1": "abKzFXAn0KDr5U+JON1ZgJ2lUtU=",
"revisionTime": "2016-04-24T11:30:07Z"
},
{
- "checksumSHA1": "Y89CHl2URaBbobeyCOr4kzbLwYE=",
+ "checksumSHA1": "Ewgc6lPiuDZVOf1407rxzSgAOag=",
"path": "github.com/miekg/dns",
- "revision": "5d001d020961ae1c184f9f8152fdc73810481677",
- "revisionTime": "2016-06-14T16:21:01Z"
+ "revision": "e4205768578dc90c2669e75a2f8a8bf77e3083a4",
+ "revisionTime": "2017-08-18T13:14:42Z"
},
{
- "checksumSHA1": "ynJSWoF6v+3zMnh9R0QmmG6iGV8=",
+ "checksumSHA1": "rJab1YdNhQooDiBWNnt7TLWPyBU=",
"path": "github.com/pkg/errors",
- "revision": "ff09b135c25aae272398c51a07235b90a75aa4f0",
- "revisionTime": "2017-03-16T20:15:38Z"
+ "revision": "2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb",
+ "revisionTime": "2017-09-10T13:46:14Z"
},
{
- "checksumSHA1": "X5E2qzbDix710dxoN9Qu0qeHGqU=",
+ "checksumSHA1": "ty3Y0hPtRphsqcykY9ihV6F02Fk=",
"path": "github.com/prometheus/client_golang/prometheus",
- "revision": "7d9484283ebefa862b5b7727d4344cfdf9a0d138",
- "revisionTime": "2017-04-25T21:35:58Z"
+ "revision": "50b3332fd63be43e38472600ec187ceec39d26d6",
+ "revisionTime": "2017-09-13T10:48:29Z"
},
{
- "checksumSHA1": "tqpiUpHWFso3wcHDAPXoEhT2CoM=",
+ "checksumSHA1": "wsAkYlRRUNx+OAuUOIqdjO7dICM=",
"path": "github.com/prometheus/client_golang/prometheus/promhttp",
- "revision": "7d9484283ebefa862b5b7727d4344cfdf9a0d138",
- "revisionTime": "2017-04-25T21:35:58Z"
+ "revision": "50b3332fd63be43e38472600ec187ceec39d26d6",
+ "revisionTime": "2017-09-13T10:48:29Z"
},
{
"checksumSHA1": "DvwvOlPNAgRntBzt3b3OSRMS2N4=",
"path": "github.com/prometheus/client_model/go",
- "revision": "fa8ad6fec33561be4280a8f0514318c79d7f6cb6",
- "revisionTime": "2015-02-12T10:17:44Z"
+ "revision": "6f3806018612930941127f2a7c6c453ba2c527d2",
+ "revisionTime": "2017-02-16T18:52:47Z"
},
{
"checksumSHA1": "4TLgSCgJZuS5gtytxNvcVk4h8/g=",
"path": "github.com/prometheus/common/config",
- "revision": "bc8b88226a1210b016e9993b1d75f858c9c8f778",
- "revisionTime": "2017-08-30T19:05:55Z"
+ "revision": "2f17f4a9d485bf34b4bfaccc273805040e4f86c8",
+ "revisionTime": "2017-09-08T16:18:22Z"
},
{
"checksumSHA1": "xfnn0THnqNwjwimeTClsxahYrIo=",
"path": "github.com/prometheus/common/expfmt",
- "revision": "bc8b88226a1210b016e9993b1d75f858c9c8f778",
- "revisionTime": "2017-08-30T19:05:55Z"
+ "revision": "2f17f4a9d485bf34b4bfaccc273805040e4f86c8",
+ "revisionTime": "2017-09-08T16:18:22Z"
},
{
"checksumSHA1": "GWlM3d2vPYyNATtTFgftS10/A9w=",
"path": "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg",
- "revision": "bc8b88226a1210b016e9993b1d75f858c9c8f778",
- "revisionTime": "2017-08-30T19:05:55Z"
+ "revision": "2f17f4a9d485bf34b4bfaccc273805040e4f86c8",
+ "revisionTime": "2017-09-08T16:18:22Z"
},
{
"checksumSHA1": "3VoqH7TFfzA6Ds0zFzIbKCUvBmw=",
"path": "github.com/prometheus/common/model",
- "revision": "bc8b88226a1210b016e9993b1d75f858c9c8f778",
- "revisionTime": "2017-08-30T19:05:55Z"
+ "revision": "2f17f4a9d485bf34b4bfaccc273805040e4f86c8",
+ "revisionTime": "2017-09-08T16:18:22Z"
},
{
- "checksumSHA1": "Nj8QI/QKAWEY8F5d0h/kdxzh4SM=",
+ "checksumSHA1": "Yseprf8kAFr/s7wztkQnrFuFN+8=",
"path": "github.com/prometheus/common/promlog",
- "revision": "bc8b88226a1210b016e9993b1d75f858c9c8f778",
- "revisionTime": "2017-08-30T19:05:55Z"
+ "revision": "2f17f4a9d485bf34b4bfaccc273805040e4f86c8",
+ "revisionTime": "2017-09-08T16:18:22Z"
},
{
"checksumSHA1": "1H28FCxsaAIm6kvue+Wfdd8Lq6M=",
"path": "github.com/prometheus/common/promlog/flag",
- "revision": "bc8b88226a1210b016e9993b1d75f858c9c8f778",
- "revisionTime": "2017-08-30T19:05:55Z"
+ "revision": "2f17f4a9d485bf34b4bfaccc273805040e4f86c8",
+ "revisionTime": "2017-09-08T16:18:22Z"
},
{
"checksumSHA1": "91KYK0SpvkaMJJA2+BcxbVnyRO0=",
"path": "github.com/prometheus/common/version",
- "revision": "bc8b88226a1210b016e9993b1d75f858c9c8f778",
- "revisionTime": "2017-08-30T19:05:55Z"
+ "revision": "2f17f4a9d485bf34b4bfaccc273805040e4f86c8",
+ "revisionTime": "2017-09-08T16:18:22Z"
},
{
- "checksumSHA1": "kO2MAzPuortudABaRd7fY+7EaoM=",
+ "checksumSHA1": "ihxJIjxtbEYdQKwA0D0nRipj95I=",
"path": "github.com/prometheus/procfs",
- "revision": "406e5b7bfd8201a36e2bb5f7bdae0b03380c2ce8",
- "revisionTime": "2015-10-29T15:50:50-04:00"
+ "revision": "e645f4e5aaa8506fc71d6edbc5c4ff02c04c46f2",
+ "revisionTime": "2017-07-03T10:12:42Z"
},
{
- "checksumSHA1": "11zFB6NFMfY7R7pwOhDCurgIjJY=",
+ "checksumSHA1": "xCiFAAwVTrjsfZT1BIJQ3DgeNCY=",
+ "path": "github.com/prometheus/procfs/xfs",
+ "revision": "e645f4e5aaa8506fc71d6edbc5c4ff02c04c46f2",
+ "revisionTime": "2017-07-03T10:12:42Z"
+ },
+ {
+ "checksumSHA1": "uX2McdP4VcQ6zkAF0Q4oyd0rFtU=",
+ "path": "golang.org/x/net/bpf",
+ "revision": "8351a756f30f1297fe94bbf4b767ec589c6ea6d0",
+ "revisionTime": "2017-09-15T01:39:56Z"
+ },
+ {
+ "checksumSHA1": "DqdFGWbLLyVFeDvzvXyf1Y678uA=",
"path": "golang.org/x/net/icmp",
- "revision": "31df19d69da8728e9220def59b80ee577c3e48bf",
- "revisionTime": "2016-03-29T10:16:23+11:00"
+ "revision": "8351a756f30f1297fe94bbf4b767ec589c6ea6d0",
+ "revisionTime": "2017-09-15T01:39:56Z"
},
{
- "checksumSHA1": "yRuyntx9a59ugMi5NlN4ST0XRcI=",
+ "checksumSHA1": "YoSf+PgTWvHmFVaF3MrtZz3kX38=",
"path": "golang.org/x/net/internal/iana",
- "revision": "31df19d69da8728e9220def59b80ee577c3e48bf",
- "revisionTime": "2016-03-29T10:16:23+11:00"
+ "revision": "8351a756f30f1297fe94bbf4b767ec589c6ea6d0",
+ "revisionTime": "2017-09-15T01:39:56Z"
+ },
+ {
+ "checksumSHA1": "5eWwtQVHJ0Lp2/538Kve2KuE8gQ=",
+ "path": "golang.org/x/net/internal/socket",
+ "revision": "8351a756f30f1297fe94bbf4b767ec589c6ea6d0",
+ "revisionTime": "2017-09-15T01:39:56Z"
},
{
- "checksumSHA1": "5Um0EwFCpweaWXfaslYqSfoWhV8=",
+ "checksumSHA1": "ZGMENpNTj2hojdJMcrUO+UPKVgE=",
"path": "golang.org/x/net/ipv4",
- "revision": "31df19d69da8728e9220def59b80ee577c3e48bf",
- "revisionTime": "2016-03-29T10:16:23+11:00"
+ "revision": "8351a756f30f1297fe94bbf4b767ec589c6ea6d0",
+ "revisionTime": "2017-09-15T01:39:56Z"
},
{
- "checksumSHA1": "8iCMTIfuxZ2KU2dyb6hJmzm4CeA=",
+ "checksumSHA1": "QUvByKIVmIy9c+8+O1XGyh9ynoY=",
"path": "golang.org/x/net/ipv6",
- "revision": "31df19d69da8728e9220def59b80ee577c3e48bf",
- "revisionTime": "2016-03-29T10:16:23+11:00"
+ "revision": "8351a756f30f1297fe94bbf4b767ec589c6ea6d0",
+ "revisionTime": "2017-09-15T01:39:56Z"
},
{
- "checksumSHA1": "ZvPW/nSYs/UeoZejaV2ZSm9+2Do=",
+ "checksumSHA1": "3SZTatHIy9OTKc95YlVfXKnoySg=",
"path": "gopkg.in/alecthomas/kingpin.v2",
- "revision": "7f0871f2e17818990e4eed73f9b5c2f429501228",
- "revisionTime": "2017-03-28T23:38:35Z"
+ "revision": "1087e65c9441605df944fb12c33f0fe7072d18ca",
+ "revisionTime": "2017-07-27T04:22:29Z"
},
{
- "checksumSHA1": "+OgOXBoiQ+X+C2dsAeiOHwBIEH0=",
+ "checksumSHA1": "RDJpJQwkF012L6m/2BJizyOksNw=",
"path": "gopkg.in/yaml.v2",
- "revision": "a83829b6f1293c91addabc89d0571c246397bbf4",
- "revisionTime": "2016-03-01T17:40:22-03:00"
+ "revision": "eb3733d160e74a9c7e442f435eb3bea458e1d19f",
+ "revisionTime": "2017-08-12T16:00:11Z"
}
],
"rootPath": "github.com/prometheus/blackbox_exporter"