TUN-1615: revert miekg/dns to last known working revision
The last known good commit is 6da3249dfb57fbaa16efafcd8744cee8809d80cd before the first release tag.
This commit is contained in:
parent
541cf68608
commit
781e1fef7b
|
@ -281,12 +281,14 @@
|
||||||
revision = "d3b731e9255b72d4571a5aac125634cf1b6031dc"
|
revision = "d3b731e9255b72d4571a5aac125634cf1b6031dc"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:463e4140189f8194f9121ca1c7fe3b8e9e9a2ab3d949b43c835c21034927dc62"
|
digest = "1:73f788f2df39614dd7d9e75c8ca5fb8b4a68937b5e6d4a15e4c3a596f6f8c07b"
|
||||||
name = "github.com/miekg/dns"
|
name = "github.com/miekg/dns"
|
||||||
packages = ["."]
|
packages = [
|
||||||
|
".",
|
||||||
|
"internal/socket",
|
||||||
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "5a2b9fab83ff0f8bfc99684bd5f43a37abe560f1"
|
revision = "6da3249dfb57fbaa16efafcd8744cee8809d80cd"
|
||||||
version = "v1.0.8"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -412,20 +414,15 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:011ee76ffb757c7c91a3e61cf5d6f367d1fd5dd08e16a4e6ae688e7759f8509a"
|
digest = "1:9513f8a0f1f6918181b7d744225b1931ffacafeb57067a1c26893a51058afb80"
|
||||||
name = "golang.org/x/net"
|
name = "golang.org/x/net"
|
||||||
packages = [
|
packages = [
|
||||||
"bpf",
|
|
||||||
"context",
|
"context",
|
||||||
"http/httpguts",
|
"http/httpguts",
|
||||||
"http2",
|
"http2",
|
||||||
"http2/hpack",
|
"http2/hpack",
|
||||||
"idna",
|
"idna",
|
||||||
"internal/iana",
|
|
||||||
"internal/socket",
|
|
||||||
"internal/timeseries",
|
"internal/timeseries",
|
||||||
"ipv4",
|
|
||||||
"ipv6",
|
|
||||||
"trace",
|
"trace",
|
||||||
"websocket",
|
"websocket",
|
||||||
]
|
]
|
||||||
|
|
|
@ -58,6 +58,10 @@
|
||||||
name = "github.com/coredns/coredns"
|
name = "github.com/coredns/coredns"
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/miekg/dns"
|
||||||
|
revision = "6da3249dfb57fbaa16efafcd8744cee8809d80cd"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/cloudflare/brotli-go"
|
name = "github.com/cloudflare/brotli-go"
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
coverage:
|
|
||||||
status:
|
|
||||||
project:
|
|
||||||
default:
|
|
||||||
target: 40%
|
|
||||||
threshold: null
|
|
||||||
patch: false
|
|
||||||
changes: false
|
|
|
@ -7,15 +7,9 @@
|
||||||
packages = ["ed25519","ed25519/internal/edwards25519"]
|
packages = ["ed25519","ed25519/internal/edwards25519"]
|
||||||
revision = "b080dc9a8c480b08e698fb1219160d598526310f"
|
revision = "b080dc9a8c480b08e698fb1219160d598526310f"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "golang.org/x/net"
|
|
||||||
packages = ["bpf","internal/iana","internal/socket","ipv4","ipv6"]
|
|
||||||
revision = "894f8ed5849b15b810ae41e9590a0d05395bba27"
|
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "c4abc38abaeeeeb9be92455c9c02cae32841122b8982aaa067ef25bb8e86ff9d"
|
inputs-digest = "5046e265393bd5e54f570ce29ae8bc6fa3f30ef5110e922996540400f287c64a"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
# Makefile for releasing.
|
|
||||||
#
|
|
||||||
# The release is controlled from version.go. The version found there is
|
|
||||||
# used to tag the git repo, we're not building any artifects so there is nothing
|
|
||||||
# to upload to github.
|
|
||||||
#
|
|
||||||
# * Up the version in version.go
|
|
||||||
# * Run: make -f Makefile.release release
|
|
||||||
# * will *commit* your change with 'Release $VERSION'
|
|
||||||
# * push to github
|
|
||||||
#
|
|
||||||
|
|
||||||
define GO
|
|
||||||
//+build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fmt.Println(dns.Version.String())
|
|
||||||
}
|
|
||||||
endef
|
|
||||||
|
|
||||||
$(file > version_release.go,$(GO))
|
|
||||||
VERSION:=$(shell go run version_release.go)
|
|
||||||
TAG="v$(VERSION)"
|
|
||||||
|
|
||||||
all:
|
|
||||||
@echo Use the \'release\' target to start a release $(VERSION)
|
|
||||||
rm -f version_release.go
|
|
||||||
|
|
||||||
.PHONY: release
|
|
||||||
release: commit push
|
|
||||||
@echo Released $(VERSION)
|
|
||||||
rm -f version_release.go
|
|
||||||
|
|
||||||
.PHONY: commit
|
|
||||||
commit:
|
|
||||||
@echo Committing release $(VERSION)
|
|
||||||
git commit -am"Release $(VERSION)"
|
|
||||||
git tag $(TAG)
|
|
||||||
|
|
||||||
.PHONY: push
|
|
||||||
push:
|
|
||||||
@echo Pushing release $(VERSION) to master
|
|
||||||
git push --tags
|
|
||||||
git push
|
|
|
@ -62,8 +62,6 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
||||||
* https://dnssectest.net/
|
* https://dnssectest.net/
|
||||||
* https://dns.apebits.com
|
* https://dns.apebits.com
|
||||||
* https://github.com/oif/apex
|
* https://github.com/oif/apex
|
||||||
* https://github.com/jedisct1/dnscrypt-proxy
|
|
||||||
* https://github.com/jedisct1/rpdns
|
|
||||||
|
|
||||||
Send pull request if you want to be listed here.
|
Send pull request if you want to be listed here.
|
||||||
|
|
||||||
|
|
|
@ -7,27 +7,22 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const dnsTimeout time.Duration = 2 * time.Second
|
||||||
dnsTimeout time.Duration = 2 * time.Second
|
const tcpIdleTimeout time.Duration = 8 * time.Second
|
||||||
tcpIdleTimeout time.Duration = 8 * time.Second
|
|
||||||
|
|
||||||
dohMimeType = "application/dns-message"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Conn represents a connection to a DNS server.
|
// A Conn represents a connection to a DNS server.
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
net.Conn // a net.Conn holding the connection
|
net.Conn // a net.Conn holding the connection
|
||||||
UDPSize uint16 // minimum receive buffer for UDP messages
|
UDPSize uint16 // minimum receive buffer for UDP messages
|
||||||
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
|
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
|
||||||
|
rtt time.Duration
|
||||||
|
t time.Time
|
||||||
tsigRequestMAC string
|
tsigRequestMAC string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +39,6 @@ type Client struct {
|
||||||
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds, or net.Dialer.Timeout if expiring earlier - overridden by Timeout when that value is non-zero
|
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds, or net.Dialer.Timeout if expiring earlier - overridden by Timeout when that value is non-zero
|
||||||
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
|
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
|
||||||
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
|
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
|
||||||
HTTPClient *http.Client // The http.Client to use for DNS-over-HTTPS
|
|
||||||
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
|
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
|
||||||
SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
|
SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
|
||||||
group singleflight
|
group singleflight
|
||||||
|
@ -89,10 +83,11 @@ func (c *Client) Dial(address string) (conn *Conn, err error) {
|
||||||
// create a new dialer with the appropriate timeout
|
// create a new dialer with the appropriate timeout
|
||||||
var d net.Dialer
|
var d net.Dialer
|
||||||
if c.Dialer == nil {
|
if c.Dialer == nil {
|
||||||
d = net.Dialer{Timeout:c.getTimeoutForRequest(c.dialTimeout())}
|
d = net.Dialer{}
|
||||||
} else {
|
} else {
|
||||||
d = net.Dialer(*c.Dialer)
|
d = net.Dialer(*c.Dialer)
|
||||||
}
|
}
|
||||||
|
d.Timeout = c.getTimeoutForRequest(c.writeTimeout())
|
||||||
|
|
||||||
network := "udp"
|
network := "udp"
|
||||||
useTLS := false
|
useTLS := false
|
||||||
|
@ -141,11 +136,6 @@ func (c *Client) Dial(address string) (conn *Conn, err error) {
|
||||||
// attribute appropriately
|
// attribute appropriately
|
||||||
func (c *Client) Exchange(m *Msg, address string) (r *Msg, rtt time.Duration, err error) {
|
func (c *Client) Exchange(m *Msg, address string) (r *Msg, rtt time.Duration, err error) {
|
||||||
if !c.SingleInflight {
|
if !c.SingleInflight {
|
||||||
if c.Net == "https" {
|
|
||||||
// TODO(tmthrgd): pipe timeouts into exchangeDOH
|
|
||||||
return c.exchangeDOH(context.TODO(), m, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.exchange(m, address)
|
return c.exchange(m, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,11 +148,6 @@ func (c *Client) Exchange(m *Msg, address string) (r *Msg, rtt time.Duration, er
|
||||||
cl = cl1
|
cl = cl1
|
||||||
}
|
}
|
||||||
r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
|
r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
|
||||||
if c.Net == "https" {
|
|
||||||
// TODO(tmthrgd): pipe timeouts into exchangeDOH
|
|
||||||
return c.exchangeDOH(context.TODO(), m, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.exchange(m, address)
|
return c.exchange(m, address)
|
||||||
})
|
})
|
||||||
if r != nil && shared {
|
if r != nil && shared {
|
||||||
|
@ -192,9 +177,8 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
co.TsigSecret = c.TsigSecret
|
co.TsigSecret = c.TsigSecret
|
||||||
t := time.Now()
|
|
||||||
// write with the appropriate write timeout
|
// write with the appropriate write timeout
|
||||||
co.SetWriteDeadline(t.Add(c.getTimeoutForRequest(c.writeTimeout())))
|
co.SetWriteDeadline(time.Now().Add(c.getTimeoutForRequest(c.writeTimeout())))
|
||||||
if err = co.WriteMsg(m); err != nil {
|
if err = co.WriteMsg(m); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
@ -204,76 +188,12 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
||||||
if err == nil && r.Id != m.Id {
|
if err == nil && r.Id != m.Id {
|
||||||
err = ErrId
|
err = ErrId
|
||||||
}
|
}
|
||||||
rtt = time.Since(t)
|
return r, co.rtt, err
|
||||||
return r, rtt, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) exchangeDOH(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
|
||||||
p, err := m.Pack()
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodPost, a, bytes.NewReader(p))
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Content-Type", dohMimeType)
|
|
||||||
req.Header.Set("Accept", dohMimeType)
|
|
||||||
|
|
||||||
hc := http.DefaultClient
|
|
||||||
if c.HTTPClient != nil {
|
|
||||||
hc = c.HTTPClient
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx != context.Background() && ctx != context.TODO() {
|
|
||||||
req = req.WithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
t := time.Now()
|
|
||||||
|
|
||||||
resp, err := hc.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
defer closeHTTPBody(resp.Body)
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return nil, 0, fmt.Errorf("dns: server returned HTTP %d error: %q", resp.StatusCode, resp.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ct := resp.Header.Get("Content-Type"); ct != dohMimeType {
|
|
||||||
return nil, 0, fmt.Errorf("dns: unexpected Content-Type %q; expected %q", ct, dohMimeType)
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err = ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rtt = time.Since(t)
|
|
||||||
|
|
||||||
r = new(Msg)
|
|
||||||
if err := r.Unpack(p); err != nil {
|
|
||||||
return r, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: TSIG? Is it even supported over DoH?
|
|
||||||
|
|
||||||
return r, rtt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func closeHTTPBody(r io.ReadCloser) error {
|
|
||||||
io.Copy(ioutil.Discard, io.LimitReader(r, 8<<20))
|
|
||||||
return r.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadMsg reads a message from the connection co.
|
// ReadMsg reads a message from the connection co.
|
||||||
// If the received message contains a TSIG record the transaction signature
|
// If the received message contains a TSIG record the transaction
|
||||||
// is verified. This method always tries to return the message, however if an
|
// signature is verified.
|
||||||
// error is returned there are no guarantees that the returned message is a
|
|
||||||
// valid representation of the packet read.
|
|
||||||
func (co *Conn) ReadMsg() (*Msg, error) {
|
func (co *Conn) ReadMsg() (*Msg, error) {
|
||||||
p, err := co.ReadMsgHeader(nil)
|
p, err := co.ReadMsgHeader(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -282,11 +202,14 @@ func (co *Conn) ReadMsg() (*Msg, error) {
|
||||||
|
|
||||||
m := new(Msg)
|
m := new(Msg)
|
||||||
if err := m.Unpack(p); err != nil {
|
if err := m.Unpack(p); err != nil {
|
||||||
// If an error was returned, we still want to allow the user to use
|
// If ErrTruncated was returned, we still want to allow the user to use
|
||||||
// the message, but naively they can just check err if they don't want
|
// the message, but naively they can just check err if they don't want
|
||||||
// to use an erroneous message
|
// to use a truncated message
|
||||||
|
if err == ErrTruncated {
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if t := m.IsTsig(); t != nil {
|
if t := m.IsTsig(); t != nil {
|
||||||
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
|
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
|
||||||
return m, ErrSecret
|
return m, ErrSecret
|
||||||
|
@ -318,6 +241,7 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
|
||||||
}
|
}
|
||||||
p = make([]byte, l)
|
p = make([]byte, l)
|
||||||
n, err = tcpRead(r, p)
|
n, err = tcpRead(r, p)
|
||||||
|
co.rtt = time.Since(co.t)
|
||||||
default:
|
default:
|
||||||
if co.UDPSize > MinMsgSize {
|
if co.UDPSize > MinMsgSize {
|
||||||
p = make([]byte, co.UDPSize)
|
p = make([]byte, co.UDPSize)
|
||||||
|
@ -325,6 +249,7 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
|
||||||
p = make([]byte, MinMsgSize)
|
p = make([]byte, MinMsgSize)
|
||||||
}
|
}
|
||||||
n, err = co.Read(p)
|
n, err = co.Read(p)
|
||||||
|
co.rtt = time.Since(co.t)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -437,6 +362,7 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
co.t = time.Now()
|
||||||
if _, err = co.Write(out); err != nil {
|
if _, err = co.Write(out); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -568,10 +494,6 @@ func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout
|
||||||
// context, if present. If there is both a context deadline and a configured
|
// context, if present. If there is both a context deadline and a configured
|
||||||
// timeout on the client, the earliest of the two takes effect.
|
// 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) {
|
func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||||
if !c.SingleInflight && c.Net == "https" {
|
|
||||||
return c.exchangeDOH(ctx, m, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
var timeout time.Duration
|
var timeout time.Duration
|
||||||
if deadline, ok := ctx.Deadline(); !ok {
|
if deadline, ok := ctx.Deadline(); !ok {
|
||||||
timeout = 0
|
timeout = 0
|
||||||
|
@ -580,7 +502,6 @@ func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg,
|
||||||
}
|
}
|
||||||
// not passing the context to the underlying calls, as the API does not support
|
// not passing the context to the underlying calls, as the API does not support
|
||||||
// context. For timeouts you should set up Client.Dialer and call Client.Exchange.
|
// context. For timeouts you should set up Client.Dialer and call Client.Exchange.
|
||||||
// TODO(tmthrgd): this is a race condition
|
|
||||||
c.Dialer = &net.Dialer{Timeout: timeout}
|
c.Dialer = &net.Dialer{Timeout: timeout}
|
||||||
return c.Exchange(m, a)
|
return c.Exchange(m, a)
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ func ClientConfigFromReader(resolvconf io.Reader) (*ClientConfig, error) {
|
||||||
n = 1
|
n = 1
|
||||||
}
|
}
|
||||||
c.Timeout = n
|
c.Timeout = n
|
||||||
case len(s) >= 9 && s[:9] == "attempts:":
|
case len(s) >= 8 && s[:9] == "attempts:":
|
||||||
n, _ := strconv.Atoi(s[9:])
|
n, _ := strconv.Atoi(s[9:])
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
n = 1
|
n = 1
|
||||||
|
|
|
@ -18,7 +18,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var packageHdr = `
|
var packageHdr = `
|
||||||
// Code generated by "go run compress_generate.go"; DO NOT EDIT.
|
// *** DO NOT MODIFY ***
|
||||||
|
// AUTOGENERATED BY go generate from compress_generate.go
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
@ -101,8 +102,7 @@ Names:
|
||||||
|
|
||||||
// compressionLenHelperType - all types that have domain-name/cdomain-name can be used for compressing names
|
// compressionLenHelperType - all types that have domain-name/cdomain-name can be used for compressing names
|
||||||
|
|
||||||
fmt.Fprint(b, "func compressionLenHelperType(c map[string]int, r RR, initLen int) int {\n")
|
fmt.Fprint(b, "func compressionLenHelperType(c map[string]int, r RR) {\n")
|
||||||
fmt.Fprint(b, "currentLen := initLen\n")
|
|
||||||
fmt.Fprint(b, "switch x := r.(type) {\n")
|
fmt.Fprint(b, "switch x := r.(type) {\n")
|
||||||
for _, name := range domainTypes {
|
for _, name := range domainTypes {
|
||||||
o := scope.Lookup(name)
|
o := scope.Lookup(name)
|
||||||
|
@ -110,10 +110,7 @@ Names:
|
||||||
|
|
||||||
fmt.Fprintf(b, "case *%s:\n", name)
|
fmt.Fprintf(b, "case *%s:\n", name)
|
||||||
for i := 1; i < st.NumFields(); i++ {
|
for i := 1; i < st.NumFields(); i++ {
|
||||||
out := func(s string) {
|
out := func(s string) { fmt.Fprintf(b, "compressionLenHelper(c, x.%s)\n", st.Field(i).Name()) }
|
||||||
fmt.Fprintf(b, "currentLen -= len(x.%s) + 1\n", st.Field(i).Name())
|
|
||||||
fmt.Fprintf(b, "currentLen += compressionLenHelper(c, x.%s, currentLen)\n", st.Field(i).Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||||
switch st.Tag(i) {
|
switch st.Tag(i) {
|
||||||
|
@ -122,12 +119,8 @@ Names:
|
||||||
case `dns:"cdomain-name"`:
|
case `dns:"cdomain-name"`:
|
||||||
// For HIP we need to slice over the elements in this slice.
|
// For HIP we need to slice over the elements in this slice.
|
||||||
fmt.Fprintf(b, `for i := range x.%s {
|
fmt.Fprintf(b, `for i := range x.%s {
|
||||||
currentLen -= len(x.%s[i]) + 1
|
compressionLenHelper(c, x.%s[i])
|
||||||
}
|
}
|
||||||
`, st.Field(i).Name(), st.Field(i).Name())
|
|
||||||
fmt.Fprintf(b, `for i := range x.%s {
|
|
||||||
currentLen += compressionLenHelper(c, x.%s[i], currentLen)
|
|
||||||
}
|
|
||||||
`, st.Field(i).Name(), st.Field(i).Name())
|
`, st.Field(i).Name(), st.Field(i).Name())
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
@ -141,11 +134,11 @@ Names:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintln(b, "}\nreturn currentLen - initLen\n}\n\n")
|
fmt.Fprintln(b, "}\n}\n\n")
|
||||||
|
|
||||||
// compressionLenSearchType - search cdomain-tags types for compressible names.
|
// compressionLenSearchType - search cdomain-tags types for compressible names.
|
||||||
|
|
||||||
fmt.Fprint(b, "func compressionLenSearchType(c map[string]int, r RR) (int, bool, int) {\n")
|
fmt.Fprint(b, "func compressionLenSearchType(c map[string]int, r RR) (int, bool) {\n")
|
||||||
fmt.Fprint(b, "switch x := r.(type) {\n")
|
fmt.Fprint(b, "switch x := r.(type) {\n")
|
||||||
for _, name := range cdomainTypes {
|
for _, name := range cdomainTypes {
|
||||||
o := scope.Lookup(name)
|
o := scope.Lookup(name)
|
||||||
|
@ -155,7 +148,7 @@ Names:
|
||||||
j := 1
|
j := 1
|
||||||
for i := 1; i < st.NumFields(); i++ {
|
for i := 1; i < st.NumFields(); i++ {
|
||||||
out := func(s string, j int) {
|
out := func(s string, j int) {
|
||||||
fmt.Fprintf(b, "k%d, ok%d, sz%d := compressionLenSearch(c, x.%s)\n", j, j, j, st.Field(i).Name())
|
fmt.Fprintf(b, "k%d, ok%d := compressionLenSearch(c, x.%s)\n", j, j, st.Field(i).Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are no slice types with names that can be compressed.
|
// There are no slice types with names that can be compressed.
|
||||||
|
@ -168,15 +161,13 @@ Names:
|
||||||
}
|
}
|
||||||
k := "k1"
|
k := "k1"
|
||||||
ok := "ok1"
|
ok := "ok1"
|
||||||
sz := "sz1"
|
|
||||||
for i := 2; i < j; i++ {
|
for i := 2; i < j; i++ {
|
||||||
k += fmt.Sprintf(" + k%d", i)
|
k += fmt.Sprintf(" + k%d", i)
|
||||||
ok += fmt.Sprintf(" && ok%d", i)
|
ok += fmt.Sprintf(" && ok%d", i)
|
||||||
sz += fmt.Sprintf(" + sz%d", i)
|
|
||||||
}
|
}
|
||||||
fmt.Fprintf(b, "return %s, %s, %s\n", k, ok, sz)
|
fmt.Fprintf(b, "return %s, %s\n", k, ok)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(b, "}\nreturn 0, false, 0\n}\n\n")
|
fmt.Fprintln(b, "}\nreturn 0, false\n}\n\n")
|
||||||
|
|
||||||
// gofmt
|
// gofmt
|
||||||
res, err := format.Source(b.Bytes())
|
res, err := format.Source(b.Bytes())
|
||||||
|
|
|
@ -273,11 +273,8 @@ func (t Type) String() string {
|
||||||
|
|
||||||
// String returns the string representation for the class c.
|
// String returns the string representation for the class c.
|
||||||
func (c Class) String() string {
|
func (c Class) String() string {
|
||||||
if s, ok := ClassToString[uint16(c)]; ok {
|
if c1, ok := ClassToString[uint16(c)]; ok {
|
||||||
// Only emit mnemonics when they are unambiguous, specically ANY is in both.
|
return c1
|
||||||
if _, ok := StringToType[s]; !ok {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return "CLASS" + strconv.Itoa(int(c))
|
return "CLASS" + strconv.Itoa(int(c))
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,16 @@ func (h *RR_Header) Header() *RR_Header { return h }
|
||||||
// Just to implement the RR interface.
|
// Just to implement the RR interface.
|
||||||
func (h *RR_Header) copy() RR { return nil }
|
func (h *RR_Header) copy() RR { return nil }
|
||||||
|
|
||||||
|
func (h *RR_Header) copyHeader() *RR_Header {
|
||||||
|
r := new(RR_Header)
|
||||||
|
r.Name = h.Name
|
||||||
|
r.Rrtype = h.Rrtype
|
||||||
|
r.Class = h.Class
|
||||||
|
r.Ttl = h.Ttl
|
||||||
|
r.Rdlength = h.Rdlength
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
func (h *RR_Header) String() string {
|
func (h *RR_Header) String() string {
|
||||||
var s string
|
var s string
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,6 @@ var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
||||||
// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
|
// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
|
||||||
var AlgorithmToHash = map[uint8]crypto.Hash{
|
var AlgorithmToHash = map[uint8]crypto.Hash{
|
||||||
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
|
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
|
||||||
DSA: crypto.SHA1,
|
|
||||||
RSASHA1: crypto.SHA1,
|
RSASHA1: crypto.SHA1,
|
||||||
RSASHA1NSEC3SHA1: crypto.SHA1,
|
RSASHA1NSEC3SHA1: crypto.SHA1,
|
||||||
RSASHA256: crypto.SHA256,
|
RSASHA256: crypto.SHA256,
|
||||||
|
@ -240,7 +239,7 @@ func (k *DNSKEY) ToDS(h uint8) *DS {
|
||||||
// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
|
// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
|
||||||
func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
|
func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
|
||||||
c := &CDNSKEY{DNSKEY: *k}
|
c := &CDNSKEY{DNSKEY: *k}
|
||||||
c.Hdr = k.Hdr
|
c.Hdr = *k.Hdr.copyHeader()
|
||||||
c.Hdr.Rrtype = TypeCDNSKEY
|
c.Hdr.Rrtype = TypeCDNSKEY
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -248,7 +247,7 @@ func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
|
||||||
// ToCDS converts a DS record to a CDS record.
|
// ToCDS converts a DS record to a CDS record.
|
||||||
func (d *DS) ToCDS() *CDS {
|
func (d *DS) ToCDS() *CDS {
|
||||||
c := &CDS{DS: *d}
|
c := &CDS{DS: *d}
|
||||||
c.Hdr = d.Hdr
|
c.Hdr = *d.Hdr.copyHeader()
|
||||||
c.Hdr.Rrtype = TypeCDS
|
c.Hdr.Rrtype = TypeCDS
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -542,20 +541,20 @@ func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
|
||||||
explen = uint16(keybuf[1])<<8 | uint16(keybuf[2])
|
explen = uint16(keybuf[1])<<8 | uint16(keybuf[2])
|
||||||
keyoff = 3
|
keyoff = 3
|
||||||
}
|
}
|
||||||
if explen > 4 {
|
|
||||||
// Larger exponent than supported by the crypto package.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
pubkey := new(rsa.PublicKey)
|
pubkey := new(rsa.PublicKey)
|
||||||
|
|
||||||
pubkey.N = big.NewInt(0)
|
pubkey.N = big.NewInt(0)
|
||||||
|
shift := uint64((explen - 1) * 8)
|
||||||
expo := uint64(0)
|
expo := uint64(0)
|
||||||
for i := 0; i < int(explen); i++ {
|
for i := int(explen - 1); i > 0; i-- {
|
||||||
expo <<= 8
|
expo += uint64(keybuf[keyoff+i]) << shift
|
||||||
expo |= uint64(keybuf[keyoff+i])
|
shift -= 8
|
||||||
}
|
}
|
||||||
if expo > 1<<31-1 {
|
// Remainder
|
||||||
// Larger exponent than supported by the crypto package.
|
expo += uint64(keybuf[keyoff])
|
||||||
|
if expo > (2<<31)+1 {
|
||||||
|
// Larger expo than supported.
|
||||||
|
// println("dns: F5 primes (or larger) are not supported")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pubkey.E = int(expo)
|
pubkey.E = int(expo)
|
||||||
|
|
|
@ -73,11 +73,11 @@ and port to use for the connection:
|
||||||
Port: 12345,
|
Port: 12345,
|
||||||
Zone: "",
|
Zone: "",
|
||||||
}
|
}
|
||||||
c.Dialer := &net.Dialer{
|
d := net.Dialer{
|
||||||
Timeout: 200 * time.Millisecond,
|
Timeout: 200 * time.Millisecond,
|
||||||
LocalAddr: &laddr,
|
LocalAddr: &laddr,
|
||||||
}
|
}
|
||||||
in, rtt, err := c.Exchange(m1, "8.8.8.8:53")
|
in, rtt, err := c.ExchangeWithDialer(&d, m1, "8.8.8.8:53")
|
||||||
|
|
||||||
If these "advanced" features are not needed, a simple UDP query can be sent,
|
If these "advanced" features are not needed, a simple UDP query can be sent,
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -102,15 +102,12 @@ func (rr *OPT) SetVersion(v uint8) {
|
||||||
|
|
||||||
// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
|
// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
|
||||||
func (rr *OPT) ExtendedRcode() int {
|
func (rr *OPT) ExtendedRcode() int {
|
||||||
return int((rr.Hdr.Ttl&0xFF000000)>>24) + 15
|
return int((rr.Hdr.Ttl & 0xFF000000) >> 24)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExtendedRcode sets the EDNS extended RCODE field.
|
// SetExtendedRcode sets the EDNS extended RCODE field.
|
||||||
func (rr *OPT) SetExtendedRcode(v uint8) {
|
func (rr *OPT) SetExtendedRcode(v uint8) {
|
||||||
if v < RcodeBadVers { // Smaller than 16.. Use the 4 bits you have!
|
rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v) << 24)
|
||||||
return
|
|
||||||
}
|
|
||||||
rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v-15) << 24)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UDPSize returns the UDP buffer size.
|
// UDPSize returns the UDP buffer size.
|
||||||
|
@ -423,7 +420,6 @@ func (e *EDNS0_LLQ) String() string {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// EDNS0_DUA implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975.
|
|
||||||
type EDNS0_DAU struct {
|
type EDNS0_DAU struct {
|
||||||
Code uint16 // Always EDNS0DAU
|
Code uint16 // Always EDNS0DAU
|
||||||
AlgCode []uint8
|
AlgCode []uint8
|
||||||
|
@ -446,7 +442,6 @@ func (e *EDNS0_DAU) String() string {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975.
|
|
||||||
type EDNS0_DHU struct {
|
type EDNS0_DHU struct {
|
||||||
Code uint16 // Always EDNS0DHU
|
Code uint16 // Always EDNS0DHU
|
||||||
AlgCode []uint8
|
AlgCode []uint8
|
||||||
|
@ -469,7 +464,6 @@ func (e *EDNS0_DHU) String() string {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975.
|
|
||||||
type EDNS0_N3U struct {
|
type EDNS0_N3U struct {
|
||||||
Code uint16 // Always EDNS0N3U
|
Code uint16 // Always EDNS0N3U
|
||||||
AlgCode []uint8
|
AlgCode []uint8
|
||||||
|
@ -493,7 +487,6 @@ func (e *EDNS0_N3U) String() string {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// EDNS0_EXPIRE implementes the EDNS0 option as described in RFC 7314.
|
|
||||||
type EDNS0_EXPIRE struct {
|
type EDNS0_EXPIRE struct {
|
||||||
Code uint16 // Always EDNS0EXPIRE
|
Code uint16 // Always EDNS0EXPIRE
|
||||||
Expire uint32
|
Expire uint32
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package socket
|
||||||
|
|
||||||
|
func (h *cmsghdr) len() int { return int(h.Len) }
|
||||||
|
func (h *cmsghdr) lvl() int { return int(h.Level) }
|
||||||
|
func (h *cmsghdr) typ() int { return int(h.Type) }
|
|
@ -1,12 +1,18 @@
|
||||||
// Copyright 2017 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 arm mips mipsle 386
|
// +build arm mips mipsle 386
|
||||||
// +build linux
|
// +build linux
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
|
type cmsghdr struct {
|
||||||
|
Len uint32
|
||||||
|
Level int32
|
||||||
|
Type int32
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
sizeofCmsghdr = 0xc
|
||||||
|
)
|
||||||
|
|
||||||
func (h *cmsghdr) set(l, lvl, typ int) {
|
func (h *cmsghdr) set(l, lvl, typ int) {
|
||||||
h.Len = uint32(l)
|
h.Len = uint32(l)
|
||||||
h.Level = int32(lvl)
|
h.Level = int32(lvl)
|
|
@ -1,12 +1,18 @@
|
||||||
// Copyright 2017 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 arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
|
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
|
||||||
// +build linux
|
// +build linux
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
|
type cmsghdr struct {
|
||||||
|
Len uint64
|
||||||
|
Level int32
|
||||||
|
Type int32
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
sizeofCmsghdr = 0x10
|
||||||
|
)
|
||||||
|
|
||||||
func (h *cmsghdr) set(l, lvl, typ int) {
|
func (h *cmsghdr) set(l, lvl, typ int) {
|
||||||
h.Len = uint64(l)
|
h.Len = uint64(l)
|
||||||
h.Level = int32(lvl)
|
h.Level = int32(lvl)
|
|
@ -1,8 +1,4 @@
|
||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
// +build !linux
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
|
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
package socket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func controlHeaderLen() int {
|
||||||
|
return roundup(sizeofCmsghdr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func controlMessageLen(dataLen int) int {
|
||||||
|
return roundup(sizeofCmsghdr) + dataLen
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the whole length of control message.
|
||||||
|
func ControlMessageSpace(dataLen int) int {
|
||||||
|
return roundup(sizeofCmsghdr) + roundup(dataLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A ControlMessage represents the head message in a stream of control
|
||||||
|
// messages.
|
||||||
|
//
|
||||||
|
// A control message comprises of a header, data and a few padding
|
||||||
|
// fields to conform to the interface to the kernel.
|
||||||
|
//
|
||||||
|
// See RFC 3542 for further information.
|
||||||
|
type ControlMessage []byte
|
||||||
|
|
||||||
|
// Data returns the data field of the control message at the head.
|
||||||
|
func (m ControlMessage) Data(dataLen int) []byte {
|
||||||
|
l := controlHeaderLen()
|
||||||
|
if len(m) < l || len(m) < l+dataLen {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return m[l : l+dataLen]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseHeader parses and returns the header fields of the control
|
||||||
|
// message at the head.
|
||||||
|
func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) {
|
||||||
|
l := controlHeaderLen()
|
||||||
|
if len(m) < l {
|
||||||
|
return 0, 0, 0, errors.New("short message")
|
||||||
|
}
|
||||||
|
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
||||||
|
return h.lvl(), h.typ(), int(uint64(h.len()) - uint64(l)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the control message at the next.
|
||||||
|
func (m ControlMessage) Next(dataLen int) ControlMessage {
|
||||||
|
l := ControlMessageSpace(dataLen)
|
||||||
|
if len(m) < l {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return m[l:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalHeader marshals the header fields of the control message at
|
||||||
|
// the head.
|
||||||
|
func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error {
|
||||||
|
if len(m) < controlHeaderLen() {
|
||||||
|
return errors.New("short message")
|
||||||
|
}
|
||||||
|
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
||||||
|
h.set(controlMessageLen(dataLen), lvl, typ)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal marshals the control message at the head, and returns the next
|
||||||
|
// control message.
|
||||||
|
func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, error) {
|
||||||
|
l := len(data)
|
||||||
|
if len(m) < ControlMessageSpace(l) {
|
||||||
|
return nil, errors.New("short message")
|
||||||
|
}
|
||||||
|
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
||||||
|
h.set(controlMessageLen(l), lvl, typ)
|
||||||
|
if l > 0 {
|
||||||
|
copy(m.Data(l), data)
|
||||||
|
}
|
||||||
|
return m.Next(l), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses as a single or multiple control messages.
|
||||||
|
func (m ControlMessage) Parse() ([]ControlMessage, error) {
|
||||||
|
var ms []ControlMessage
|
||||||
|
for len(m) >= controlHeaderLen() {
|
||||||
|
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
||||||
|
l := h.len()
|
||||||
|
if l <= 0 {
|
||||||
|
return nil, errors.New("invalid header length")
|
||||||
|
}
|
||||||
|
if uint64(l) < uint64(controlHeaderLen()) {
|
||||||
|
return nil, errors.New("invalid message length")
|
||||||
|
}
|
||||||
|
if uint64(l) > uint64(len(m)) {
|
||||||
|
return nil, errors.New("short buffer")
|
||||||
|
}
|
||||||
|
ms = append(ms, ControlMessage(m[:l]))
|
||||||
|
ll := l - controlHeaderLen()
|
||||||
|
if len(m) >= ControlMessageSpace(ll) {
|
||||||
|
m = m[ControlMessageSpace(ll):]
|
||||||
|
} else {
|
||||||
|
m = m[controlMessageLen(ll):]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ms, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewControlMessage returns a new stream of control messages.
|
||||||
|
func NewControlMessage(dataLen []int) ControlMessage {
|
||||||
|
var l int
|
||||||
|
for i := range dataLen {
|
||||||
|
l += ControlMessageSpace(dataLen[i])
|
||||||
|
}
|
||||||
|
return make([]byte, l)
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
// Package socket contains ControlMessage parsing code from
|
||||||
|
// golang.org/x/net/internal/socket. Instead of supporting all possible
|
||||||
|
// architectures, we're only supporting linux 32/64 bit.
|
||||||
|
package socket
|
|
@ -0,0 +1,14 @@
|
||||||
|
package socket
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernelAlign = func() int {
|
||||||
|
var p uintptr
|
||||||
|
return int(unsafe.Sizeof(p))
|
||||||
|
}()
|
||||||
|
)
|
||||||
|
|
||||||
|
func roundup(l int) int {
|
||||||
|
return (l + kernelAlign - 1) & ^(kernelAlign - 1)
|
||||||
|
}
|
|
@ -595,13 +595,6 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, len(msg), err
|
return nil, len(msg), err
|
||||||
}
|
}
|
||||||
|
|
||||||
return UnpackRRWithHeader(h, msg, off)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnpackRRWithHeader unpacks the record type specific payload given an existing
|
|
||||||
// RR_Header.
|
|
||||||
func UnpackRRWithHeader(h RR_Header, msg []byte, off int) (rr RR, off1 int, err error) {
|
|
||||||
end := off + int(h.Rdlength)
|
end := off + int(h.Rdlength)
|
||||||
|
|
||||||
if fn, known := typeToUnpack[h.Rrtype]; !known {
|
if fn, known := typeToUnpack[h.Rrtype]; !known {
|
||||||
|
@ -619,8 +612,8 @@ func UnpackRRWithHeader(h RR_Header, msg []byte, off int) (rr RR, off1 int, err
|
||||||
// If we cannot unpack the whole array, then it will return nil
|
// If we cannot unpack the whole array, then it will return nil
|
||||||
func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) {
|
func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) {
|
||||||
var r RR
|
var r RR
|
||||||
// Don't pre-allocate, l may be under attacker control
|
// Optimistically make dst be the length that was sent
|
||||||
var dst []RR
|
dst := make([]RR, 0, l)
|
||||||
for i := 0; i < l; i++ {
|
for i := 0; i < l; i++ {
|
||||||
off1 := off
|
off1 := off
|
||||||
r, off, err = UnpackRR(msg, off)
|
r, off, err = UnpackRR(msg, off)
|
||||||
|
@ -691,20 +684,18 @@ func (dns *Msg) Pack() (msg []byte, err error) {
|
||||||
return dns.PackBuffer(nil)
|
return dns.PackBuffer(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PackBuffer packs a Msg, using the given buffer buf. If buf is too small a new buffer is allocated.
|
// PackBuffer packs a Msg, using the given buffer buf. If buf is too small
|
||||||
|
// a new buffer is allocated.
|
||||||
func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
|
func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
|
||||||
var compression map[string]int
|
|
||||||
if dns.Compress {
|
|
||||||
compression = make(map[string]int) // Compression pointer mappings.
|
|
||||||
}
|
|
||||||
return dns.packBufferWithCompressionMap(buf, compression)
|
|
||||||
}
|
|
||||||
|
|
||||||
// packBufferWithCompressionMap packs a Msg, using the given buffer buf.
|
|
||||||
func (dns *Msg) packBufferWithCompressionMap(buf []byte, compression map[string]int) (msg []byte, err error) {
|
|
||||||
// We use a similar function in tsig.go's stripTsig.
|
// We use a similar function in tsig.go's stripTsig.
|
||||||
|
var (
|
||||||
|
dh Header
|
||||||
|
compression map[string]int
|
||||||
|
)
|
||||||
|
|
||||||
var dh Header
|
if dns.Compress {
|
||||||
|
compression = make(map[string]int) // Compression pointer mappings
|
||||||
|
}
|
||||||
|
|
||||||
if dns.Rcode < 0 || dns.Rcode > 0xFFF {
|
if dns.Rcode < 0 || dns.Rcode > 0xFFF {
|
||||||
return nil, ErrRcode
|
return nil, ErrRcode
|
||||||
|
@ -716,11 +707,12 @@ func (dns *Msg) packBufferWithCompressionMap(buf []byte, compression map[string]
|
||||||
return nil, ErrExtendedRcode
|
return nil, ErrExtendedRcode
|
||||||
}
|
}
|
||||||
opt.SetExtendedRcode(uint8(dns.Rcode >> 4))
|
opt.SetExtendedRcode(uint8(dns.Rcode >> 4))
|
||||||
|
dns.Rcode &= 0xF
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert convenient Msg into wire-like Header.
|
// Convert convenient Msg into wire-like Header.
|
||||||
dh.Id = dns.Id
|
dh.Id = dns.Id
|
||||||
dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode&0xF)
|
dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode)
|
||||||
if dns.Response {
|
if dns.Response {
|
||||||
dh.Bits |= _QR
|
dh.Bits |= _QR
|
||||||
}
|
}
|
||||||
|
@ -819,19 +811,13 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
|
||||||
dns.CheckingDisabled = (dh.Bits & _CD) != 0
|
dns.CheckingDisabled = (dh.Bits & _CD) != 0
|
||||||
dns.Rcode = int(dh.Bits & 0xF)
|
dns.Rcode = int(dh.Bits & 0xF)
|
||||||
|
|
||||||
// If we are at the end of the message we should return *just* the
|
|
||||||
// header. This can still be useful to the caller. 9.9.9.9 sends these
|
|
||||||
// when responding with REFUSED for instance.
|
|
||||||
if off == len(msg) {
|
if off == len(msg) {
|
||||||
// reset sections before returning
|
return ErrTruncated
|
||||||
dns.Question, dns.Answer, dns.Ns, dns.Extra = nil, nil, nil, nil
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Qdcount, Ancount, Nscount, Arcount can't be trusted, as they are
|
// Optimistically use the count given to us in the header
|
||||||
// attacker controlled. This means we can't use them to pre-allocate
|
dns.Question = make([]Question, 0, int(dh.Qdcount))
|
||||||
// slices.
|
|
||||||
dns.Question = nil
|
|
||||||
for i := 0; i < int(dh.Qdcount); i++ {
|
for i := 0; i < int(dh.Qdcount); i++ {
|
||||||
off1 := off
|
off1 := off
|
||||||
var q Question
|
var q Question
|
||||||
|
@ -923,28 +909,21 @@ func (dns *Msg) String() string {
|
||||||
// than packing it, measuring the size and discarding the buffer.
|
// than packing it, measuring the size and discarding the buffer.
|
||||||
func (dns *Msg) Len() int { return compressedLen(dns, dns.Compress) }
|
func (dns *Msg) Len() int { return compressedLen(dns, dns.Compress) }
|
||||||
|
|
||||||
func compressedLenWithCompressionMap(dns *Msg, compression map[string]int) int {
|
|
||||||
l := 12 // Message header is always 12 bytes
|
|
||||||
for _, r := range dns.Question {
|
|
||||||
compressionLenHelper(compression, r.Name, l)
|
|
||||||
l += r.len()
|
|
||||||
}
|
|
||||||
l += compressionLenSlice(l, compression, dns.Answer)
|
|
||||||
l += compressionLenSlice(l, compression, dns.Ns)
|
|
||||||
l += compressionLenSlice(l, compression, dns.Extra)
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// compressedLen returns the message length when in compressed wire format
|
// compressedLen returns the message length when in compressed wire format
|
||||||
// when compress is true, otherwise the uncompressed length is returned.
|
// when compress is true, otherwise the uncompressed length is returned.
|
||||||
func compressedLen(dns *Msg, compress bool) int {
|
func compressedLen(dns *Msg, compress bool) int {
|
||||||
// We always return one more than needed.
|
// We always return one more than needed.
|
||||||
|
l := 12 // Message header is always 12 bytes
|
||||||
if compress {
|
if compress {
|
||||||
compression := map[string]int{}
|
compression := map[string]int{}
|
||||||
return compressedLenWithCompressionMap(dns, compression)
|
for _, r := range dns.Question {
|
||||||
|
l += r.len()
|
||||||
|
compressionLenHelper(compression, r.Name)
|
||||||
}
|
}
|
||||||
l := 12 // Message header is always 12 bytes
|
l += compressionLenSlice(compression, dns.Answer)
|
||||||
|
l += compressionLenSlice(compression, dns.Ns)
|
||||||
|
l += compressionLenSlice(compression, dns.Extra)
|
||||||
|
} else {
|
||||||
for _, r := range dns.Question {
|
for _, r := range dns.Question {
|
||||||
l += r.len()
|
l += r.len()
|
||||||
}
|
}
|
||||||
|
@ -963,98 +942,61 @@ func compressedLen(dns *Msg, compress bool) int {
|
||||||
l += r.len()
|
l += r.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func compressionLenSlice(lenp int, c map[string]int, rs []RR) int {
|
func compressionLenSlice(c map[string]int, rs []RR) int {
|
||||||
initLen := lenp
|
var l int
|
||||||
for _, r := range rs {
|
for _, r := range rs {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// TmpLen is to track len of record at 14bits boudaries
|
l += r.len()
|
||||||
tmpLen := lenp
|
k, ok := compressionLenSearch(c, r.Header().Name)
|
||||||
|
|
||||||
x := r.len()
|
|
||||||
// track this length, and the global length in len, while taking compression into account for both.
|
|
||||||
k, ok, _ := compressionLenSearch(c, r.Header().Name)
|
|
||||||
if ok {
|
if ok {
|
||||||
// Size of x is reduced by k, but we add 1 since k includes the '.' and label descriptor take 2 bytes
|
l += 1 - k
|
||||||
// so, basically x:= x - k - 1 + 2
|
|
||||||
x += 1 - k
|
|
||||||
}
|
}
|
||||||
|
compressionLenHelper(c, r.Header().Name)
|
||||||
tmpLen += compressionLenHelper(c, r.Header().Name, tmpLen)
|
k, ok = compressionLenSearchType(c, r)
|
||||||
k, ok, _ = compressionLenSearchType(c, r)
|
|
||||||
if ok {
|
if ok {
|
||||||
x += 1 - k
|
l += 1 - k
|
||||||
}
|
}
|
||||||
lenp += x
|
compressionLenHelperType(c, r)
|
||||||
tmpLen = lenp
|
|
||||||
tmpLen += compressionLenHelperType(c, r, tmpLen)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return lenp - initLen
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put the parts of the name in the compression map, return the size in bytes added in payload
|
// Put the parts of the name in the compression map.
|
||||||
func compressionLenHelper(c map[string]int, s string, currentLen int) int {
|
func compressionLenHelper(c map[string]int, s string) {
|
||||||
if currentLen > maxCompressionOffset {
|
|
||||||
// We won't be able to add any label that could be re-used later anyway
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if _, ok := c[s]; ok {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
initLen := currentLen
|
|
||||||
pref := ""
|
pref := ""
|
||||||
prev := s
|
|
||||||
lbs := Split(s)
|
lbs := Split(s)
|
||||||
for j := 0; j < len(lbs); j++ {
|
for j := len(lbs) - 1; j >= 0; j-- {
|
||||||
pref = s[lbs[j]:]
|
pref = s[lbs[j]:]
|
||||||
currentLen += len(prev) - len(pref)
|
|
||||||
prev = pref
|
|
||||||
if _, ok := c[pref]; !ok {
|
if _, ok := c[pref]; !ok {
|
||||||
// If first byte label is within the first 14bits, it might be re-used later
|
c[pref] = len(pref)
|
||||||
if currentLen < maxCompressionOffset {
|
|
||||||
c[pref] = currentLen
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
added := currentLen - initLen
|
|
||||||
if j > 0 {
|
|
||||||
// We added a new PTR
|
|
||||||
added += 2
|
|
||||||
}
|
|
||||||
return added
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return currentLen - initLen
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for each part in the compression map and returns its length,
|
// Look for each part in the compression map and returns its length,
|
||||||
// keep on searching so we get the longest match.
|
// keep on searching so we get the longest match.
|
||||||
// Will return the size of compression found, whether a match has been
|
func compressionLenSearch(c map[string]int, s string) (int, bool) {
|
||||||
// found and the size of record if added in payload
|
|
||||||
func compressionLenSearch(c map[string]int, s string) (int, bool, int) {
|
|
||||||
off := 0
|
off := 0
|
||||||
end := false
|
end := false
|
||||||
if s == "" { // don't bork on bogus data
|
if s == "" { // don't bork on bogus data
|
||||||
return 0, false, 0
|
return 0, false
|
||||||
}
|
}
|
||||||
fullSize := 0
|
|
||||||
for {
|
for {
|
||||||
if _, ok := c[s[off:]]; ok {
|
if _, ok := c[s[off:]]; ok {
|
||||||
return len(s[off:]), true, fullSize + off
|
return len(s[off:]), true
|
||||||
}
|
}
|
||||||
if end {
|
if end {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Each label descriptor takes 2 bytes, add it
|
|
||||||
fullSize += 2
|
|
||||||
off, end = NextLabel(s, off)
|
off, end = NextLabel(s, off)
|
||||||
}
|
}
|
||||||
return 0, false, fullSize + len(s)
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy returns a new RR which is a deep-copy of r.
|
// Copy returns a new RR which is a deep-copy of r.
|
||||||
|
|
|
@ -18,7 +18,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var packageHdr = `
|
var packageHdr = `
|
||||||
// Code generated by "go run msg_generate.go"; DO NOT EDIT.
|
// *** DO NOT MODIFY ***
|
||||||
|
// AUTOGENERATED BY go generate from msg_generate.go
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
|
|
@ -141,24 +141,20 @@ func truncateMsgFromRdlength(msg []byte, off int, rdlength uint16) (truncmsg []b
|
||||||
return msg[:lenrd], nil
|
return msg[:lenrd], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var base32HexNoPadEncoding = base32.HexEncoding.WithPadding(base32.NoPadding)
|
|
||||||
|
|
||||||
func fromBase32(s []byte) (buf []byte, err error) {
|
func fromBase32(s []byte) (buf []byte, err error) {
|
||||||
for i, b := range s {
|
for i, b := range s {
|
||||||
if b >= 'a' && b <= 'z' {
|
if b >= 'a' && b <= 'z' {
|
||||||
s[i] = b - 32
|
s[i] = b - 32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buflen := base32HexNoPadEncoding.DecodedLen(len(s))
|
buflen := base32.HexEncoding.DecodedLen(len(s))
|
||||||
buf = make([]byte, buflen)
|
buf = make([]byte, buflen)
|
||||||
n, err := base32HexNoPadEncoding.Decode(buf, s)
|
n, err := base32.HexEncoding.Decode(buf, s)
|
||||||
buf = buf[:n]
|
buf = buf[:n]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func toBase32(b []byte) string {
|
func toBase32(b []byte) string { return base32.HexEncoding.EncodeToString(b) }
|
||||||
return base32HexNoPadEncoding.EncodeToString(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fromBase64(s []byte) (buf []byte, err error) {
|
func fromBase64(s []byte) (buf []byte, err error) {
|
||||||
buflen := base64.StdEncoding.DecodedLen(len(s))
|
buflen := base64.StdEncoding.DecodedLen(len(s))
|
||||||
|
|
|
@ -56,7 +56,8 @@ func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() }
|
||||||
func (r *PrivateRR) copy() RR {
|
func (r *PrivateRR) copy() RR {
|
||||||
// make new RR like this:
|
// make new RR like this:
|
||||||
rr := mkPrivateRR(r.Hdr.Rrtype)
|
rr := mkPrivateRR(r.Hdr.Rrtype)
|
||||||
rr.Hdr = r.Hdr
|
newh := r.Hdr.copyHeader()
|
||||||
|
rr.Hdr = *newh
|
||||||
|
|
||||||
err := r.Data.Copy(rr.Data)
|
err := r.Data.Copy(rr.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package dns
|
||||||
// Dedup removes identical RRs from rrs. It preserves the original ordering.
|
// Dedup removes identical RRs from rrs. It preserves the original ordering.
|
||||||
// The lowest TTL of any duplicates is used in the remaining one. Dedup modifies
|
// The lowest TTL of any duplicates is used in the remaining one. Dedup modifies
|
||||||
// rrs.
|
// rrs.
|
||||||
// m is used to store the RRs temporary. If it is nil a new map will be allocated.
|
// m is used to store the RRs temporay. If it is nil a new map will be allocated.
|
||||||
func Dedup(rrs []RR, m map[string]RR) []RR {
|
func Dedup(rrs []RR, m map[string]RR) []RR {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
m = make(map[string]RR)
|
m = make(map[string]RR)
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -299,24 +297,16 @@ func parseZone(r io.Reader, origin, f string, defttl *ttlState, t chan *Token, i
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Start with the new file
|
// Start with the new file
|
||||||
includePath := l.token
|
r1, e1 := os.Open(l.token)
|
||||||
if !filepath.IsAbs(includePath) {
|
|
||||||
includePath = filepath.Join(filepath.Dir(f), includePath)
|
|
||||||
}
|
|
||||||
r1, e1 := os.Open(includePath)
|
|
||||||
if e1 != nil {
|
if e1 != nil {
|
||||||
msg := fmt.Sprintf("failed to open `%s'", l.token)
|
t <- &Token{Error: &ParseError{f, "failed to open `" + l.token + "'", l}}
|
||||||
if !filepath.IsAbs(l.token) {
|
|
||||||
msg += fmt.Sprintf(" as `%s'", includePath)
|
|
||||||
}
|
|
||||||
t <- &Token{Error: &ParseError{f, msg, l}}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if include+1 > 7 {
|
if include+1 > 7 {
|
||||||
t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
|
t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
parseZone(r1, neworigin, includePath, defttl, t, include+1)
|
parseZone(r1, neworigin, l.token, defttl, t, include+1)
|
||||||
st = zExpectOwnerDir
|
st = zExpectOwnerDir
|
||||||
case zExpectDirTTLBl:
|
case zExpectDirTTLBl:
|
||||||
if l.value != zBlank {
|
if l.value != zBlank {
|
||||||
|
@ -577,7 +567,6 @@ func zlexer(s *scan, c chan lex) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l.value = zRrtpe
|
l.value = zRrtpe
|
||||||
rrtype = true
|
|
||||||
l.torc = t
|
l.torc = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -601,7 +590,7 @@ func zlexer(s *scan, c chan lex) {
|
||||||
c <- l
|
c <- l
|
||||||
}
|
}
|
||||||
stri = 0
|
stri = 0
|
||||||
|
// I reverse space stuff here
|
||||||
if !space && !commt {
|
if !space && !commt {
|
||||||
l.value = zBlank
|
l.value = zBlank
|
||||||
l.token = " "
|
l.token = " "
|
||||||
|
|
|
@ -1255,10 +1255,8 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
if len(l.token) == 0 || l.err {
|
if len(l.token) == 0 || l.err {
|
||||||
return nil, &ParseError{f, "bad NSEC3 Salt", l}, ""
|
return nil, &ParseError{f, "bad NSEC3 Salt", l}, ""
|
||||||
}
|
}
|
||||||
if l.token != "-" {
|
|
||||||
rr.SaltLength = uint8(len(l.token)) / 2
|
rr.SaltLength = uint8(len(l.token)) / 2
|
||||||
rr.Salt = l.token
|
rr.Salt = l.token
|
||||||
}
|
|
||||||
|
|
||||||
<-c
|
<-c
|
||||||
l = <-c
|
l = <-c
|
||||||
|
@ -1323,10 +1321,8 @@ func setNSEC3PARAM(h RR_Header, c chan lex, o, f string) (RR, *ParseError, strin
|
||||||
rr.Iterations = uint16(i)
|
rr.Iterations = uint16(i)
|
||||||
<-c
|
<-c
|
||||||
l = <-c
|
l = <-c
|
||||||
if l.token != "-" {
|
|
||||||
rr.SaltLength = uint8(len(l.token))
|
rr.SaltLength = uint8(len(l.token))
|
||||||
rr.Salt = l.token
|
rr.Salt = l.token
|
||||||
}
|
|
||||||
return rr, nil, ""
|
return rr, nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,19 +9,12 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default maximum number of TCP queries before we close the socket.
|
// Maximum number of TCP queries before we close the socket.
|
||||||
const maxTCPQueries = 128
|
const maxTCPQueries = 128
|
||||||
|
|
||||||
// Interval for stop worker if no load
|
|
||||||
const idleWorkerTimeout = 10 * time.Second
|
|
||||||
|
|
||||||
// Maximum number of workers
|
|
||||||
const maxWorkersCount = 10000
|
|
||||||
|
|
||||||
// Handler is implemented by any value that implements ServeDNS.
|
// Handler is implemented by any value that implements ServeDNS.
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
ServeDNS(w ResponseWriter, r *Msg)
|
ServeDNS(w ResponseWriter, r *Msg)
|
||||||
|
@ -50,7 +43,6 @@ type ResponseWriter interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type response struct {
|
type response struct {
|
||||||
msg []byte
|
|
||||||
hijacked bool // connection has been hijacked by handler
|
hijacked bool // connection has been hijacked by handler
|
||||||
tsigStatus error
|
tsigStatus error
|
||||||
tsigTimersOnly bool
|
tsigTimersOnly bool
|
||||||
|
@ -59,6 +51,7 @@ type response struct {
|
||||||
udp *net.UDPConn // i/o connection if UDP was used
|
udp *net.UDPConn // i/o connection if UDP was used
|
||||||
tcp net.Conn // i/o connection if TCP was used
|
tcp net.Conn // i/o connection if TCP was used
|
||||||
udpSession *SessionUDP // oob data to get egress interface right
|
udpSession *SessionUDP // oob data to get egress interface right
|
||||||
|
remoteAddr net.Addr // address of the client
|
||||||
writer Writer // writer to output the raw DNS bits
|
writer Writer // writer to output the raw DNS bits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,63 +296,12 @@ type Server struct {
|
||||||
DecorateReader DecorateReader
|
DecorateReader DecorateReader
|
||||||
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
|
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
|
||||||
DecorateWriter DecorateWriter
|
DecorateWriter DecorateWriter
|
||||||
// Maximum number of TCP queries before we close the socket. Default is maxTCPQueries (unlimited if -1).
|
|
||||||
MaxTCPQueries int
|
|
||||||
|
|
||||||
// UDP packet or TCP connection queue
|
|
||||||
queue chan *response
|
|
||||||
// Workers count
|
|
||||||
workersCount int32
|
|
||||||
// Shutdown handling
|
// Shutdown handling
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
started bool
|
started bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) worker(w *response) {
|
|
||||||
srv.serve(w)
|
|
||||||
|
|
||||||
for {
|
|
||||||
count := atomic.LoadInt32(&srv.workersCount)
|
|
||||||
if count > maxWorkersCount {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if atomic.CompareAndSwapInt32(&srv.workersCount, count, count+1) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defer atomic.AddInt32(&srv.workersCount, -1)
|
|
||||||
|
|
||||||
inUse := false
|
|
||||||
timeout := time.NewTimer(idleWorkerTimeout)
|
|
||||||
defer timeout.Stop()
|
|
||||||
LOOP:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case w, ok := <-srv.queue:
|
|
||||||
if !ok {
|
|
||||||
break LOOP
|
|
||||||
}
|
|
||||||
inUse = true
|
|
||||||
srv.serve(w)
|
|
||||||
case <-timeout.C:
|
|
||||||
if !inUse {
|
|
||||||
break LOOP
|
|
||||||
}
|
|
||||||
inUse = false
|
|
||||||
timeout.Reset(idleWorkerTimeout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (srv *Server) spawnWorker(w *response) {
|
|
||||||
select {
|
|
||||||
case srv.queue <- w:
|
|
||||||
default:
|
|
||||||
go srv.worker(w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenAndServe starts a nameserver on the configured address in *Server.
|
// ListenAndServe starts a nameserver on the configured address in *Server.
|
||||||
func (srv *Server) ListenAndServe() error {
|
func (srv *Server) ListenAndServe() error {
|
||||||
srv.lock.Lock()
|
srv.lock.Lock()
|
||||||
|
@ -367,7 +309,6 @@ func (srv *Server) ListenAndServe() error {
|
||||||
if srv.started {
|
if srv.started {
|
||||||
return &Error{err: "server already started"}
|
return &Error{err: "server already started"}
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := srv.Addr
|
addr := srv.Addr
|
||||||
if addr == "" {
|
if addr == "" {
|
||||||
addr = ":domain"
|
addr = ":domain"
|
||||||
|
@ -375,8 +316,6 @@ func (srv *Server) ListenAndServe() error {
|
||||||
if srv.UDPSize == 0 {
|
if srv.UDPSize == 0 {
|
||||||
srv.UDPSize = MinMsgSize
|
srv.UDPSize = MinMsgSize
|
||||||
}
|
}
|
||||||
srv.queue = make(chan *response)
|
|
||||||
defer close(srv.queue)
|
|
||||||
switch srv.Net {
|
switch srv.Net {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
a, err := net.ResolveTCPAddr(srv.Net, addr)
|
a, err := net.ResolveTCPAddr(srv.Net, addr)
|
||||||
|
@ -441,11 +380,8 @@ func (srv *Server) ActivateAndServe() error {
|
||||||
if srv.started {
|
if srv.started {
|
||||||
return &Error{err: "server already started"}
|
return &Error{err: "server already started"}
|
||||||
}
|
}
|
||||||
|
|
||||||
pConn := srv.PacketConn
|
pConn := srv.PacketConn
|
||||||
l := srv.Listener
|
l := srv.Listener
|
||||||
srv.queue = make(chan *response)
|
|
||||||
defer close(srv.queue)
|
|
||||||
if pConn != nil {
|
if pConn != nil {
|
||||||
if srv.UDPSize == 0 {
|
if srv.UDPSize == 0 {
|
||||||
srv.UDPSize = MinMsgSize
|
srv.UDPSize = MinMsgSize
|
||||||
|
@ -503,6 +439,7 @@ func (srv *Server) getReadTimeout() time.Duration {
|
||||||
}
|
}
|
||||||
|
|
||||||
// serveTCP starts a TCP listener for the server.
|
// serveTCP starts a TCP listener for the server.
|
||||||
|
// Each request is handled in a separate goroutine.
|
||||||
func (srv *Server) serveTCP(l net.Listener) error {
|
func (srv *Server) serveTCP(l net.Listener) error {
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
||||||
|
@ -510,8 +447,26 @@ func (srv *Server) serveTCP(l net.Listener) error {
|
||||||
srv.NotifyStartedFunc()
|
srv.NotifyStartedFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader := Reader(&defaultReader{srv})
|
||||||
|
if srv.DecorateReader != nil {
|
||||||
|
reader = srv.DecorateReader(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
handler := srv.Handler
|
||||||
|
if handler == nil {
|
||||||
|
handler = DefaultServeMux
|
||||||
|
}
|
||||||
|
rtimeout := srv.getReadTimeout()
|
||||||
|
// deadline is not used here
|
||||||
for {
|
for {
|
||||||
rw, err := l.Accept()
|
rw, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
if neterr, ok := err.(net.Error); ok && neterr.Temporary() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m, err := reader.ReadTCP(rw, rtimeout)
|
||||||
srv.lock.RLock()
|
srv.lock.RLock()
|
||||||
if !srv.started {
|
if !srv.started {
|
||||||
srv.lock.RUnlock()
|
srv.lock.RUnlock()
|
||||||
|
@ -519,16 +474,14 @@ func (srv *Server) serveTCP(l net.Listener) error {
|
||||||
}
|
}
|
||||||
srv.lock.RUnlock()
|
srv.lock.RUnlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if neterr, ok := err.(net.Error); ok && neterr.Temporary() {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return err
|
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
|
||||||
}
|
|
||||||
srv.spawnWorker(&response{tsigSecret: srv.TsigSecret, tcp: rw})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// serveUDP starts a UDP listener for the server.
|
// serveUDP starts a UDP listener for the server.
|
||||||
|
// Each request is handled in a separate goroutine.
|
||||||
func (srv *Server) serveUDP(l *net.UDPConn) error {
|
func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
||||||
|
@ -541,6 +494,10 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||||
reader = srv.DecorateReader(reader)
|
reader = srv.DecorateReader(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handler := srv.Handler
|
||||||
|
if handler == nil {
|
||||||
|
handler = DefaultServeMux
|
||||||
|
}
|
||||||
rtimeout := srv.getReadTimeout()
|
rtimeout := srv.getReadTimeout()
|
||||||
// deadline is not used here
|
// deadline is not used here
|
||||||
for {
|
for {
|
||||||
|
@ -552,106 +509,82 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||||
}
|
}
|
||||||
srv.lock.RUnlock()
|
srv.lock.RUnlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return err
|
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
|
||||||
}
|
|
||||||
if len(m) < headerSize {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
srv.spawnWorker(&response{msg: m, tsigSecret: srv.TsigSecret, udp: l, udpSession: s})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) serve(w *response) {
|
// Serve a new connection.
|
||||||
|
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t net.Conn) {
|
||||||
|
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
||||||
if srv.DecorateWriter != nil {
|
if srv.DecorateWriter != nil {
|
||||||
w.writer = srv.DecorateWriter(w)
|
w.writer = srv.DecorateWriter(w)
|
||||||
} else {
|
} else {
|
||||||
w.writer = w
|
w.writer = w
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.udp != nil {
|
q := 0 // counter for the amount of TCP queries we get
|
||||||
// serve UDP
|
|
||||||
srv.serveDNS(w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
reader := Reader(&defaultReader{srv})
|
reader := Reader(&defaultReader{srv})
|
||||||
if srv.DecorateReader != nil {
|
if srv.DecorateReader != nil {
|
||||||
reader = srv.DecorateReader(reader)
|
reader = srv.DecorateReader(reader)
|
||||||
}
|
}
|
||||||
|
Redo:
|
||||||
defer func() {
|
|
||||||
if !w.hijacked {
|
|
||||||
w.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
idleTimeout := tcpIdleTimeout
|
|
||||||
if srv.IdleTimeout != nil {
|
|
||||||
idleTimeout = srv.IdleTimeout()
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout := srv.getReadTimeout()
|
|
||||||
|
|
||||||
limit := srv.MaxTCPQueries
|
|
||||||
if limit == 0 {
|
|
||||||
limit = maxTCPQueries
|
|
||||||
}
|
|
||||||
|
|
||||||
for q := 0; q < limit || limit == -1; q++ {
|
|
||||||
var err error
|
|
||||||
w.msg, err = reader.ReadTCP(w.tcp, timeout)
|
|
||||||
if err != nil {
|
|
||||||
// TODO(tmthrgd): handle error
|
|
||||||
break
|
|
||||||
}
|
|
||||||
srv.serveDNS(w)
|
|
||||||
if w.tcp == nil {
|
|
||||||
break // Close() was called
|
|
||||||
}
|
|
||||||
if w.hijacked {
|
|
||||||
break // client will call Close() themselves
|
|
||||||
}
|
|
||||||
// The first read uses the read timeout, the rest use the
|
|
||||||
// idle timeout.
|
|
||||||
timeout = idleTimeout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (srv *Server) serveDNS(w *response) {
|
|
||||||
req := new(Msg)
|
req := new(Msg)
|
||||||
err := req.Unpack(w.msg)
|
err := req.Unpack(m)
|
||||||
if err != nil { // Send a FormatError back
|
if err != nil { // Send a FormatError back
|
||||||
x := new(Msg)
|
x := new(Msg)
|
||||||
x.SetRcodeFormatError(req)
|
x.SetRcodeFormatError(req)
|
||||||
w.WriteMsg(x)
|
w.WriteMsg(x)
|
||||||
return
|
goto Exit
|
||||||
}
|
}
|
||||||
if !srv.Unsafe && req.Response {
|
if !srv.Unsafe && req.Response {
|
||||||
return
|
goto Exit
|
||||||
}
|
}
|
||||||
|
|
||||||
w.tsigStatus = nil
|
w.tsigStatus = nil
|
||||||
if w.tsigSecret != nil {
|
if w.tsigSecret != nil {
|
||||||
if t := req.IsTsig(); t != nil {
|
if t := req.IsTsig(); t != nil {
|
||||||
if secret, ok := w.tsigSecret[t.Hdr.Name]; ok {
|
secret := t.Hdr.Name
|
||||||
w.tsigStatus = TsigVerify(w.msg, secret, "", false)
|
if _, ok := w.tsigSecret[secret]; !ok {
|
||||||
} else {
|
w.tsigStatus = ErrKeyAlg
|
||||||
w.tsigStatus = ErrSecret
|
|
||||||
}
|
}
|
||||||
|
w.tsigStatus = TsigVerify(m, w.tsigSecret[secret], "", false)
|
||||||
w.tsigTimersOnly = false
|
w.tsigTimersOnly = false
|
||||||
w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC
|
w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
h.ServeDNS(w, req) // Writes back to the client
|
||||||
|
|
||||||
handler := srv.Handler
|
Exit:
|
||||||
if handler == nil {
|
if w.tcp == nil {
|
||||||
handler = DefaultServeMux
|
return
|
||||||
|
}
|
||||||
|
// TODO(miek): make this number configurable?
|
||||||
|
if q > maxTCPQueries { // close socket after this many queries
|
||||||
|
w.Close()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.ServeDNS(w, req) // Writes back to the client
|
if w.hijacked {
|
||||||
|
return // client calls Close()
|
||||||
|
}
|
||||||
|
if u != nil { // UDP, "close" and return
|
||||||
|
w.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
idleTimeout := tcpIdleTimeout
|
||||||
|
if srv.IdleTimeout != nil {
|
||||||
|
idleTimeout = srv.IdleTimeout()
|
||||||
|
}
|
||||||
|
m, err = reader.ReadTCP(w.tcp, idleTimeout)
|
||||||
|
if err == nil {
|
||||||
|
q++
|
||||||
|
goto Redo
|
||||||
|
}
|
||||||
|
w.Close()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
|
func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
|
||||||
|
@ -693,9 +626,12 @@ func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *S
|
||||||
conn.SetReadDeadline(time.Now().Add(timeout))
|
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
m := make([]byte, srv.UDPSize)
|
m := make([]byte, srv.UDPSize)
|
||||||
n, s, err := ReadFromSessionUDP(conn, m)
|
n, s, err := ReadFromSessionUDP(conn, m)
|
||||||
|
if err != nil || n == 0 {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
return nil, nil, ErrShortRead
|
||||||
|
}
|
||||||
m = m[:n]
|
m = m[:n]
|
||||||
return m, s, nil
|
return m, s, nil
|
||||||
}
|
}
|
||||||
|
@ -754,12 +690,7 @@ func (w *response) LocalAddr() net.Addr {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoteAddr implements the ResponseWriter.RemoteAddr method.
|
// RemoteAddr implements the ResponseWriter.RemoteAddr method.
|
||||||
func (w *response) RemoteAddr() net.Addr {
|
func (w *response) RemoteAddr() net.Addr { return w.remoteAddr }
|
||||||
if w.tcp != nil {
|
|
||||||
return w.tcp.RemoteAddr()
|
|
||||||
}
|
|
||||||
return w.udpSession.RemoteAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TsigStatus implements the ResponseWriter.TsigStatus method.
|
// TsigStatus implements the ResponseWriter.TsigStatus method.
|
||||||
func (w *response) TsigStatus() error { return w.tsigStatus }
|
func (w *response) TsigStatus() error { return w.tsigStatus }
|
||||||
|
|
|
@ -27,7 +27,8 @@ var skipLen = map[string]struct{}{
|
||||||
}
|
}
|
||||||
|
|
||||||
var packageHdr = `
|
var packageHdr = `
|
||||||
// Code generated by "go run types_generate.go"; DO NOT EDIT.
|
// *** DO NOT MODIFY ***
|
||||||
|
// AUTOGENERATED BY go generate from types_generate.go
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
@ -181,8 +182,6 @@ func main() {
|
||||||
fallthrough
|
fallthrough
|
||||||
case st.Tag(i) == `dns:"base64"`:
|
case st.Tag(i) == `dns:"base64"`:
|
||||||
o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n")
|
o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n")
|
||||||
case strings.HasPrefix(st.Tag(i), `dns:"size-hex:`): // this has an extra field where the length is stored
|
|
||||||
o("l += len(rr.%s)/2\n")
|
|
||||||
case strings.HasPrefix(st.Tag(i), `dns:"size-hex`):
|
case strings.HasPrefix(st.Tag(i), `dns:"size-hex`):
|
||||||
fallthrough
|
fallthrough
|
||||||
case st.Tag(i) == `dns:"hex"`:
|
case st.Tag(i) == `dns:"hex"`:
|
||||||
|
@ -226,7 +225,7 @@ func main() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name)
|
fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name)
|
||||||
fields := []string{"rr.Hdr"}
|
fields := []string{"*rr.Hdr.copyHeader()"}
|
||||||
for i := 1; i < st.NumFields(); i++ {
|
for i := 1; i < st.NumFields(); i++ {
|
||||||
f := st.Field(i).Name()
|
f := st.Field(i).Name()
|
||||||
if sl, ok := st.Field(i).Type().(*types.Slice); ok {
|
if sl, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||||
|
|
|
@ -4,27 +4,8 @@ package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"golang.org/x/net/ipv4"
|
|
||||||
"golang.org/x/net/ipv6"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is the required size of the OOB buffer to pass to ReadMsgUDP.
|
|
||||||
var udpOOBSize = func() int {
|
|
||||||
// We can't know whether we'll get an IPv4 control message or an
|
|
||||||
// IPv6 control message ahead of time. To get around this, we size
|
|
||||||
// the buffer equal to the largest of the two.
|
|
||||||
|
|
||||||
oob4 := ipv4.NewControlMessage(ipv4.FlagDst | ipv4.FlagInterface)
|
|
||||||
oob6 := ipv6.NewControlMessage(ipv6.FlagDst | ipv6.FlagInterface)
|
|
||||||
|
|
||||||
if len(oob4) > len(oob6) {
|
|
||||||
return len(oob4)
|
|
||||||
}
|
|
||||||
|
|
||||||
return len(oob6)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// SessionUDP holds the remote address and the associated
|
// SessionUDP holds the remote address and the associated
|
||||||
// out-of-band data.
|
// out-of-band data.
|
||||||
type SessionUDP struct {
|
type SessionUDP struct {
|
||||||
|
@ -38,7 +19,7 @@ func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
||||||
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
||||||
// net.UDPAddr.
|
// net.UDPAddr.
|
||||||
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
||||||
oob := make([]byte, udpOOBSize)
|
oob := make([]byte, 40)
|
||||||
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, nil, err
|
return n, nil, err
|
||||||
|
@ -53,50 +34,12 @@ func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, e
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func setUDPSocketOptions(conn *net.UDPConn) error {
|
|
||||||
// Try setting the flags for both families and ignore the errors unless they
|
|
||||||
// both error.
|
|
||||||
err6 := ipv6.NewPacketConn(conn).SetControlMessage(ipv6.FlagDst|ipv6.FlagInterface, true)
|
|
||||||
err4 := ipv4.NewPacketConn(conn).SetControlMessage(ipv4.FlagDst|ipv4.FlagInterface, true)
|
|
||||||
if err6 != nil && err4 != nil {
|
|
||||||
return err4
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseDstFromOOB takes oob data and returns the destination IP.
|
|
||||||
func parseDstFromOOB(oob []byte) net.IP {
|
|
||||||
// Start with IPv6 and then fallback to IPv4
|
|
||||||
// TODO(fastest963): Figure out a way to prefer one or the other. Looking at
|
|
||||||
// the lvl of the header for a 0 or 41 isn't cross-platform.
|
|
||||||
cm6 := new(ipv6.ControlMessage)
|
|
||||||
if cm6.Parse(oob) == nil && cm6.Dst != nil {
|
|
||||||
return cm6.Dst
|
|
||||||
}
|
|
||||||
cm4 := new(ipv4.ControlMessage)
|
|
||||||
if cm4.Parse(oob) == nil && cm4.Dst != nil {
|
|
||||||
return cm4.Dst
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// correctSource takes oob data and returns new oob data with the Src equal to the Dst
|
// correctSource takes oob data and returns new oob data with the Src equal to the Dst
|
||||||
func correctSource(oob []byte) []byte {
|
func correctSource(oob []byte) []byte {
|
||||||
dst := parseDstFromOOB(oob)
|
dst, err := parseUDPSocketDst(oob)
|
||||||
if dst == nil {
|
// If the destination could not be determined, ignore.
|
||||||
|
if err != nil || dst == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// If the dst is definitely an IPv6, then use ipv6's ControlMessage to
|
return marshalUDPSocketSrc(dst)
|
||||||
// respond otherwise use ipv4's because ipv6's marshal ignores ipv4
|
|
||||||
// addresses.
|
|
||||||
if dst.To4() == nil {
|
|
||||||
cm := new(ipv6.ControlMessage)
|
|
||||||
cm.Src = dst
|
|
||||||
oob = cm.Marshal()
|
|
||||||
} else {
|
|
||||||
cm := new(ipv4.ControlMessage)
|
|
||||||
cm.Src = dst
|
|
||||||
oob = cm.Marshal()
|
|
||||||
}
|
|
||||||
return oob
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
// +build linux,!appengine
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
// See:
|
||||||
|
// * http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket and
|
||||||
|
// * http://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/
|
||||||
|
//
|
||||||
|
// Why do we need this: When listening on 0.0.0.0 with UDP so kernel decides what is the outgoing
|
||||||
|
// interface, this might not always be the correct one. This code will make sure the egress
|
||||||
|
// packet's interface matched the ingress' one.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/miekg/dns/internal/socket"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
sizeofInet6Pktinfo = 0x14
|
||||||
|
sizeofInetPktinfo = 0xc
|
||||||
|
protocolIP = 0
|
||||||
|
protocolIPv6 = 41
|
||||||
|
)
|
||||||
|
|
||||||
|
type inetPktinfo struct {
|
||||||
|
Ifindex int32
|
||||||
|
Spec_dst [4]byte /* in_addr */
|
||||||
|
Addr [4]byte /* in_addr */
|
||||||
|
}
|
||||||
|
|
||||||
|
type inet6Pktinfo struct {
|
||||||
|
Addr [16]byte /* in6_addr */
|
||||||
|
Ifindex int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type inetControlMessage struct {
|
||||||
|
Src net.IP // source address, specifying only
|
||||||
|
Dst net.IP // destination address, receiving only
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
if err != nil {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// setUDPSocketOptions6 prepares the v6 socket for sessions.
|
||||||
|
func setUDPSocketOptions6(conn *net.UDPConn) error {
|
||||||
|
file, err := conn.File()
|
||||||
|
if err != 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// getUDPSocketOption6Only return true if the socket is v6 only and false when it is v4/v6 combined
|
||||||
|
// (dualstack).
|
||||||
|
func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) {
|
||||||
|
file, err := conn.File()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) {
|
||||||
|
file, err := conn.File()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return syscall.Getsockname(int(file.Fd()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshalInetPacketInfo marshals a ipv4 control message, returning
|
||||||
|
// the byte slice for the next marshal, if any
|
||||||
|
func marshalInetPacketInfo(b []byte, cm *inetControlMessage) []byte {
|
||||||
|
m := socket.ControlMessage(b)
|
||||||
|
m.MarshalHeader(protocolIP, syscall.IP_PKTINFO, sizeofInetPktinfo)
|
||||||
|
if cm != nil {
|
||||||
|
pi := (*inetPktinfo)(unsafe.Pointer(&m.Data(sizeofInetPktinfo)[0]))
|
||||||
|
if ip := cm.Src.To4(); ip != nil {
|
||||||
|
copy(pi.Spec_dst[:], ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.Next(sizeofInetPktinfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshalInet6PacketInfo marshals a ipv6 control message, returning
|
||||||
|
// the byte slice for the next marshal, if any
|
||||||
|
func marshalInet6PacketInfo(b []byte, cm *inetControlMessage) []byte {
|
||||||
|
m := socket.ControlMessage(b)
|
||||||
|
m.MarshalHeader(protocolIPv6, syscall.IPV6_PKTINFO, sizeofInet6Pktinfo)
|
||||||
|
if cm != nil {
|
||||||
|
pi := (*inet6Pktinfo)(unsafe.Pointer(&m.Data(sizeofInet6Pktinfo)[0]))
|
||||||
|
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
|
||||||
|
copy(pi.Addr[:], ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.Next(sizeofInet6Pktinfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInetPacketInfo(cm *inetControlMessage, b []byte) {
|
||||||
|
pi := (*inetPktinfo)(unsafe.Pointer(&b[0]))
|
||||||
|
if len(cm.Dst) < net.IPv4len {
|
||||||
|
cm.Dst = make(net.IP, net.IPv4len)
|
||||||
|
}
|
||||||
|
copy(cm.Dst, pi.Addr[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInet6PacketInfo(cm *inetControlMessage, b []byte) {
|
||||||
|
pi := (*inet6Pktinfo)(unsafe.Pointer(&b[0]))
|
||||||
|
if len(cm.Dst) < net.IPv6len {
|
||||||
|
cm.Dst = make(net.IP, net.IPv6len)
|
||||||
|
}
|
||||||
|
copy(cm.Dst, pi.Addr[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseUDPSocketDst takes out-of-band data from ReadMsgUDP and parses it for
|
||||||
|
// the Dst address
|
||||||
|
func parseUDPSocketDst(oob []byte) (net.IP, error) {
|
||||||
|
cm := new(inetControlMessage)
|
||||||
|
ms, err := socket.ControlMessage(oob).Parse()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, m := range ms {
|
||||||
|
lvl, typ, l, err := m.ParseHeader()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if lvl == protocolIPv6 { // IPv6
|
||||||
|
if typ == syscall.IPV6_PKTINFO && l >= sizeofInet6Pktinfo {
|
||||||
|
parseInet6PacketInfo(cm, m.Data(l))
|
||||||
|
}
|
||||||
|
} else if lvl == protocolIP { // IPv4
|
||||||
|
if typ == syscall.IP_PKTINFO && l >= sizeofInetPktinfo {
|
||||||
|
parseInetPacketInfo(cm, m.Data(l))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cm.Dst, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshalUDPSocketSrc takes the given src address and returns out-of-band data
|
||||||
|
// to give to WriteMsgUDP
|
||||||
|
func marshalUDPSocketSrc(src net.IP) []byte {
|
||||||
|
var oob []byte
|
||||||
|
// If the dst is definitely an ipv6, then use ipv6 control to respond
|
||||||
|
// otherwise use ipv4 because the ipv6 marshal ignores ipv4 messages.
|
||||||
|
// See marshalInet6PacketInfo
|
||||||
|
cm := new(inetControlMessage)
|
||||||
|
cm.Src = src
|
||||||
|
if src.To4() == nil {
|
||||||
|
oob = make([]byte, socket.ControlMessageSpace(sizeofInet6Pktinfo))
|
||||||
|
marshalInet6PacketInfo(oob, cm)
|
||||||
|
} else {
|
||||||
|
oob = make([]byte, socket.ControlMessageSpace(sizeofInetPktinfo))
|
||||||
|
marshalInetPacketInfo(oob, cm)
|
||||||
|
}
|
||||||
|
return oob
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
// +build !linux appengine
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 parseUDPSocketDst(oob []byte) (net.IP, error) { return nil, nil }
|
||||||
|
func marshalUDPSocketSrc(src net.IP) []byte { return nil }
|
|
@ -14,7 +14,6 @@ func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
||||||
|
|
||||||
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
||||||
// net.UDPAddr.
|
// net.UDPAddr.
|
||||||
// TODO(fastest963): Once go1.10 is released, use ReadMsgUDP.
|
|
||||||
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
||||||
n, raddr, err := conn.ReadFrom(b)
|
n, raddr, err := conn.ReadFrom(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -25,13 +24,7 @@ func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteToSessionUDP acts just like net.UDPConn.WriteTo(), but uses a *SessionUDP instead of a net.Addr.
|
// WriteToSessionUDP acts just like net.UDPConn.WriteTo(), but uses a *SessionUDP instead of a net.Addr.
|
||||||
// TODO(fastest963): Once go1.10 is released, use WriteMsgUDP.
|
|
||||||
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
|
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
|
||||||
n, err := conn.WriteTo(b, session.raddr)
|
n, err := conn.WriteTo(b, session.raddr)
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(fastest963): Once go1.10 is released and we can use *MsgUDP methods
|
|
||||||
// use the standard method in udp.go for these.
|
|
||||||
func setUDPSocketOptions(*net.UDPConn) error { return nil }
|
|
||||||
func parseDstFromOOB([]byte, net.IP) net.IP { return nil }
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
package dns
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// Version is current version of this library.
|
|
||||||
var Version = V{1, 0, 8}
|
|
||||||
|
|
||||||
// V holds the version of this library.
|
|
||||||
type V struct {
|
|
||||||
Major, Minor, Patch int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v V) String() string {
|
|
||||||
return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
|
|
||||||
}
|
|
|
@ -1,155 +1,119 @@
|
||||||
// Code generated by "go run compress_generate.go"; DO NOT EDIT.
|
// *** DO NOT MODIFY ***
|
||||||
|
// AUTOGENERATED BY go generate from compress_generate.go
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
func compressionLenHelperType(c map[string]int, r RR, initLen int) int {
|
func compressionLenHelperType(c map[string]int, r RR) {
|
||||||
currentLen := initLen
|
|
||||||
switch x := r.(type) {
|
switch x := r.(type) {
|
||||||
case *AFSDB:
|
case *AFSDB:
|
||||||
currentLen -= len(x.Hostname) + 1
|
compressionLenHelper(c, x.Hostname)
|
||||||
currentLen += compressionLenHelper(c, x.Hostname, currentLen)
|
|
||||||
case *CNAME:
|
case *CNAME:
|
||||||
currentLen -= len(x.Target) + 1
|
compressionLenHelper(c, x.Target)
|
||||||
currentLen += compressionLenHelper(c, x.Target, currentLen)
|
|
||||||
case *DNAME:
|
case *DNAME:
|
||||||
currentLen -= len(x.Target) + 1
|
compressionLenHelper(c, x.Target)
|
||||||
currentLen += compressionLenHelper(c, x.Target, currentLen)
|
|
||||||
case *HIP:
|
case *HIP:
|
||||||
for i := range x.RendezvousServers {
|
for i := range x.RendezvousServers {
|
||||||
currentLen -= len(x.RendezvousServers[i]) + 1
|
compressionLenHelper(c, x.RendezvousServers[i])
|
||||||
}
|
|
||||||
for i := range x.RendezvousServers {
|
|
||||||
currentLen += compressionLenHelper(c, x.RendezvousServers[i], currentLen)
|
|
||||||
}
|
}
|
||||||
case *KX:
|
case *KX:
|
||||||
currentLen -= len(x.Exchanger) + 1
|
compressionLenHelper(c, x.Exchanger)
|
||||||
currentLen += compressionLenHelper(c, x.Exchanger, currentLen)
|
|
||||||
case *LP:
|
case *LP:
|
||||||
currentLen -= len(x.Fqdn) + 1
|
compressionLenHelper(c, x.Fqdn)
|
||||||
currentLen += compressionLenHelper(c, x.Fqdn, currentLen)
|
|
||||||
case *MB:
|
case *MB:
|
||||||
currentLen -= len(x.Mb) + 1
|
compressionLenHelper(c, x.Mb)
|
||||||
currentLen += compressionLenHelper(c, x.Mb, currentLen)
|
|
||||||
case *MD:
|
case *MD:
|
||||||
currentLen -= len(x.Md) + 1
|
compressionLenHelper(c, x.Md)
|
||||||
currentLen += compressionLenHelper(c, x.Md, currentLen)
|
|
||||||
case *MF:
|
case *MF:
|
||||||
currentLen -= len(x.Mf) + 1
|
compressionLenHelper(c, x.Mf)
|
||||||
currentLen += compressionLenHelper(c, x.Mf, currentLen)
|
|
||||||
case *MG:
|
case *MG:
|
||||||
currentLen -= len(x.Mg) + 1
|
compressionLenHelper(c, x.Mg)
|
||||||
currentLen += compressionLenHelper(c, x.Mg, currentLen)
|
|
||||||
case *MINFO:
|
case *MINFO:
|
||||||
currentLen -= len(x.Rmail) + 1
|
compressionLenHelper(c, x.Rmail)
|
||||||
currentLen += compressionLenHelper(c, x.Rmail, currentLen)
|
compressionLenHelper(c, x.Email)
|
||||||
currentLen -= len(x.Email) + 1
|
|
||||||
currentLen += compressionLenHelper(c, x.Email, currentLen)
|
|
||||||
case *MR:
|
case *MR:
|
||||||
currentLen -= len(x.Mr) + 1
|
compressionLenHelper(c, x.Mr)
|
||||||
currentLen += compressionLenHelper(c, x.Mr, currentLen)
|
|
||||||
case *MX:
|
case *MX:
|
||||||
currentLen -= len(x.Mx) + 1
|
compressionLenHelper(c, x.Mx)
|
||||||
currentLen += compressionLenHelper(c, x.Mx, currentLen)
|
|
||||||
case *NAPTR:
|
case *NAPTR:
|
||||||
currentLen -= len(x.Replacement) + 1
|
compressionLenHelper(c, x.Replacement)
|
||||||
currentLen += compressionLenHelper(c, x.Replacement, currentLen)
|
|
||||||
case *NS:
|
case *NS:
|
||||||
currentLen -= len(x.Ns) + 1
|
compressionLenHelper(c, x.Ns)
|
||||||
currentLen += compressionLenHelper(c, x.Ns, currentLen)
|
|
||||||
case *NSAPPTR:
|
case *NSAPPTR:
|
||||||
currentLen -= len(x.Ptr) + 1
|
compressionLenHelper(c, x.Ptr)
|
||||||
currentLen += compressionLenHelper(c, x.Ptr, currentLen)
|
|
||||||
case *NSEC:
|
case *NSEC:
|
||||||
currentLen -= len(x.NextDomain) + 1
|
compressionLenHelper(c, x.NextDomain)
|
||||||
currentLen += compressionLenHelper(c, x.NextDomain, currentLen)
|
|
||||||
case *PTR:
|
case *PTR:
|
||||||
currentLen -= len(x.Ptr) + 1
|
compressionLenHelper(c, x.Ptr)
|
||||||
currentLen += compressionLenHelper(c, x.Ptr, currentLen)
|
|
||||||
case *PX:
|
case *PX:
|
||||||
currentLen -= len(x.Map822) + 1
|
compressionLenHelper(c, x.Map822)
|
||||||
currentLen += compressionLenHelper(c, x.Map822, currentLen)
|
compressionLenHelper(c, x.Mapx400)
|
||||||
currentLen -= len(x.Mapx400) + 1
|
|
||||||
currentLen += compressionLenHelper(c, x.Mapx400, currentLen)
|
|
||||||
case *RP:
|
case *RP:
|
||||||
currentLen -= len(x.Mbox) + 1
|
compressionLenHelper(c, x.Mbox)
|
||||||
currentLen += compressionLenHelper(c, x.Mbox, currentLen)
|
compressionLenHelper(c, x.Txt)
|
||||||
currentLen -= len(x.Txt) + 1
|
|
||||||
currentLen += compressionLenHelper(c, x.Txt, currentLen)
|
|
||||||
case *RRSIG:
|
case *RRSIG:
|
||||||
currentLen -= len(x.SignerName) + 1
|
compressionLenHelper(c, x.SignerName)
|
||||||
currentLen += compressionLenHelper(c, x.SignerName, currentLen)
|
|
||||||
case *RT:
|
case *RT:
|
||||||
currentLen -= len(x.Host) + 1
|
compressionLenHelper(c, x.Host)
|
||||||
currentLen += compressionLenHelper(c, x.Host, currentLen)
|
|
||||||
case *SIG:
|
case *SIG:
|
||||||
currentLen -= len(x.SignerName) + 1
|
compressionLenHelper(c, x.SignerName)
|
||||||
currentLen += compressionLenHelper(c, x.SignerName, currentLen)
|
|
||||||
case *SOA:
|
case *SOA:
|
||||||
currentLen -= len(x.Ns) + 1
|
compressionLenHelper(c, x.Ns)
|
||||||
currentLen += compressionLenHelper(c, x.Ns, currentLen)
|
compressionLenHelper(c, x.Mbox)
|
||||||
currentLen -= len(x.Mbox) + 1
|
|
||||||
currentLen += compressionLenHelper(c, x.Mbox, currentLen)
|
|
||||||
case *SRV:
|
case *SRV:
|
||||||
currentLen -= len(x.Target) + 1
|
compressionLenHelper(c, x.Target)
|
||||||
currentLen += compressionLenHelper(c, x.Target, currentLen)
|
|
||||||
case *TALINK:
|
case *TALINK:
|
||||||
currentLen -= len(x.PreviousName) + 1
|
compressionLenHelper(c, x.PreviousName)
|
||||||
currentLen += compressionLenHelper(c, x.PreviousName, currentLen)
|
compressionLenHelper(c, x.NextName)
|
||||||
currentLen -= len(x.NextName) + 1
|
|
||||||
currentLen += compressionLenHelper(c, x.NextName, currentLen)
|
|
||||||
case *TKEY:
|
case *TKEY:
|
||||||
currentLen -= len(x.Algorithm) + 1
|
compressionLenHelper(c, x.Algorithm)
|
||||||
currentLen += compressionLenHelper(c, x.Algorithm, currentLen)
|
|
||||||
case *TSIG:
|
case *TSIG:
|
||||||
currentLen -= len(x.Algorithm) + 1
|
compressionLenHelper(c, x.Algorithm)
|
||||||
currentLen += compressionLenHelper(c, x.Algorithm, currentLen)
|
|
||||||
}
|
}
|
||||||
return currentLen - initLen
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func compressionLenSearchType(c map[string]int, r RR) (int, bool, int) {
|
func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
|
||||||
switch x := r.(type) {
|
switch x := r.(type) {
|
||||||
case *AFSDB:
|
case *AFSDB:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Hostname)
|
k1, ok1 := compressionLenSearch(c, x.Hostname)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *CNAME:
|
case *CNAME:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Target)
|
k1, ok1 := compressionLenSearch(c, x.Target)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *MB:
|
case *MB:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Mb)
|
k1, ok1 := compressionLenSearch(c, x.Mb)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *MD:
|
case *MD:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Md)
|
k1, ok1 := compressionLenSearch(c, x.Md)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *MF:
|
case *MF:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Mf)
|
k1, ok1 := compressionLenSearch(c, x.Mf)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *MG:
|
case *MG:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Mg)
|
k1, ok1 := compressionLenSearch(c, x.Mg)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *MINFO:
|
case *MINFO:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Rmail)
|
k1, ok1 := compressionLenSearch(c, x.Rmail)
|
||||||
k2, ok2, sz2 := compressionLenSearch(c, x.Email)
|
k2, ok2 := compressionLenSearch(c, x.Email)
|
||||||
return k1 + k2, ok1 && ok2, sz1 + sz2
|
return k1 + k2, ok1 && ok2
|
||||||
case *MR:
|
case *MR:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Mr)
|
k1, ok1 := compressionLenSearch(c, x.Mr)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *MX:
|
case *MX:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Mx)
|
k1, ok1 := compressionLenSearch(c, x.Mx)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *NS:
|
case *NS:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Ns)
|
k1, ok1 := compressionLenSearch(c, x.Ns)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *PTR:
|
case *PTR:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Ptr)
|
k1, ok1 := compressionLenSearch(c, x.Ptr)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *RT:
|
case *RT:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Host)
|
k1, ok1 := compressionLenSearch(c, x.Host)
|
||||||
return k1, ok1, sz1
|
return k1, ok1
|
||||||
case *SOA:
|
case *SOA:
|
||||||
k1, ok1, sz1 := compressionLenSearch(c, x.Ns)
|
k1, ok1 := compressionLenSearch(c, x.Ns)
|
||||||
k2, ok2, sz2 := compressionLenSearch(c, x.Mbox)
|
k2, ok2 := compressionLenSearch(c, x.Mbox)
|
||||||
return k1 + k2, ok1 && ok2, sz1 + sz2
|
return k1 + k2, ok1 && ok2
|
||||||
}
|
}
|
||||||
return 0, false, 0
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Code generated by "go run msg_generate.go"; DO NOT EDIT.
|
// *** DO NOT MODIFY ***
|
||||||
|
// AUTOGENERATED BY go generate from msg_generate.go
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Code generated by "go run types_generate.go"; DO NOT EDIT.
|
// *** DO NOT MODIFY ***
|
||||||
|
// AUTOGENERATED BY go generate from types_generate.go
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
@ -347,7 +348,7 @@ func (rr *HIP) len() int {
|
||||||
l++ // HitLength
|
l++ // HitLength
|
||||||
l++ // PublicKeyAlgorithm
|
l++ // PublicKeyAlgorithm
|
||||||
l += 2 // PublicKeyLength
|
l += 2 // PublicKeyLength
|
||||||
l += len(rr.Hit) / 2
|
l += len(rr.Hit)/2 + 1
|
||||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||||
for _, x := range rr.RendezvousServers {
|
for _, x := range rr.RendezvousServers {
|
||||||
l += len(x) + 1
|
l += len(x) + 1
|
||||||
|
@ -470,7 +471,7 @@ func (rr *NSEC3PARAM) len() int {
|
||||||
l++ // Flags
|
l++ // Flags
|
||||||
l += 2 // Iterations
|
l += 2 // Iterations
|
||||||
l++ // SaltLength
|
l++ // SaltLength
|
||||||
l += len(rr.Salt) / 2
|
l += len(rr.Salt)/2 + 1
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
func (rr *OPENPGPKEY) len() int {
|
func (rr *OPENPGPKEY) len() int {
|
||||||
|
@ -591,9 +592,9 @@ func (rr *TKEY) len() int {
|
||||||
l += 2 // Mode
|
l += 2 // Mode
|
||||||
l += 2 // Error
|
l += 2 // Error
|
||||||
l += 2 // KeySize
|
l += 2 // KeySize
|
||||||
l += len(rr.Key) / 2
|
l += len(rr.Key) + 1
|
||||||
l += 2 // OtherLen
|
l += 2 // OtherLen
|
||||||
l += len(rr.OtherData) / 2
|
l += len(rr.OtherData) + 1
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
func (rr *TLSA) len() int {
|
func (rr *TLSA) len() int {
|
||||||
|
@ -610,11 +611,11 @@ func (rr *TSIG) len() int {
|
||||||
l += 6 // TimeSigned
|
l += 6 // TimeSigned
|
||||||
l += 2 // Fudge
|
l += 2 // Fudge
|
||||||
l += 2 // MACSize
|
l += 2 // MACSize
|
||||||
l += len(rr.MAC) / 2
|
l += len(rr.MAC)/2 + 1
|
||||||
l += 2 // OrigId
|
l += 2 // OrigId
|
||||||
l += 2 // Error
|
l += 2 // Error
|
||||||
l += 2 // OtherLen
|
l += 2 // OtherLen
|
||||||
l += len(rr.OtherData) / 2
|
l += len(rr.OtherData)/2 + 1
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
func (rr *TXT) len() int {
|
func (rr *TXT) len() int {
|
||||||
|
@ -649,215 +650,215 @@ func (rr *X25) len() int {
|
||||||
|
|
||||||
// copy() functions
|
// copy() functions
|
||||||
func (rr *A) copy() RR {
|
func (rr *A) copy() RR {
|
||||||
return &A{rr.Hdr, copyIP(rr.A)}
|
return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)}
|
||||||
}
|
}
|
||||||
func (rr *AAAA) copy() RR {
|
func (rr *AAAA) copy() RR {
|
||||||
return &AAAA{rr.Hdr, copyIP(rr.AAAA)}
|
return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)}
|
||||||
}
|
}
|
||||||
func (rr *AFSDB) copy() RR {
|
func (rr *AFSDB) copy() RR {
|
||||||
return &AFSDB{rr.Hdr, rr.Subtype, rr.Hostname}
|
return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname}
|
||||||
}
|
}
|
||||||
func (rr *ANY) copy() RR {
|
func (rr *ANY) copy() RR {
|
||||||
return &ANY{rr.Hdr}
|
return &ANY{*rr.Hdr.copyHeader()}
|
||||||
}
|
}
|
||||||
func (rr *AVC) copy() RR {
|
func (rr *AVC) copy() RR {
|
||||||
Txt := make([]string, len(rr.Txt))
|
Txt := make([]string, len(rr.Txt))
|
||||||
copy(Txt, rr.Txt)
|
copy(Txt, rr.Txt)
|
||||||
return &AVC{rr.Hdr, Txt}
|
return &AVC{*rr.Hdr.copyHeader(), Txt}
|
||||||
}
|
}
|
||||||
func (rr *CAA) copy() RR {
|
func (rr *CAA) copy() RR {
|
||||||
return &CAA{rr.Hdr, rr.Flag, rr.Tag, rr.Value}
|
return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value}
|
||||||
}
|
}
|
||||||
func (rr *CERT) copy() RR {
|
func (rr *CERT) copy() RR {
|
||||||
return &CERT{rr.Hdr, rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
|
return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
|
||||||
}
|
}
|
||||||
func (rr *CNAME) copy() RR {
|
func (rr *CNAME) copy() RR {
|
||||||
return &CNAME{rr.Hdr, rr.Target}
|
return &CNAME{*rr.Hdr.copyHeader(), rr.Target}
|
||||||
}
|
}
|
||||||
func (rr *CSYNC) copy() RR {
|
func (rr *CSYNC) copy() RR {
|
||||||
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
||||||
copy(TypeBitMap, rr.TypeBitMap)
|
copy(TypeBitMap, rr.TypeBitMap)
|
||||||
return &CSYNC{rr.Hdr, rr.Serial, rr.Flags, TypeBitMap}
|
return &CSYNC{*rr.Hdr.copyHeader(), rr.Serial, rr.Flags, TypeBitMap}
|
||||||
}
|
}
|
||||||
func (rr *DHCID) copy() RR {
|
func (rr *DHCID) copy() RR {
|
||||||
return &DHCID{rr.Hdr, rr.Digest}
|
return &DHCID{*rr.Hdr.copyHeader(), rr.Digest}
|
||||||
}
|
}
|
||||||
func (rr *DNAME) copy() RR {
|
func (rr *DNAME) copy() RR {
|
||||||
return &DNAME{rr.Hdr, rr.Target}
|
return &DNAME{*rr.Hdr.copyHeader(), rr.Target}
|
||||||
}
|
}
|
||||||
func (rr *DNSKEY) copy() RR {
|
func (rr *DNSKEY) copy() RR {
|
||||||
return &DNSKEY{rr.Hdr, rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||||
}
|
}
|
||||||
func (rr *DS) copy() RR {
|
func (rr *DS) copy() RR {
|
||||||
return &DS{rr.Hdr, rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||||
}
|
}
|
||||||
func (rr *EID) copy() RR {
|
func (rr *EID) copy() RR {
|
||||||
return &EID{rr.Hdr, rr.Endpoint}
|
return &EID{*rr.Hdr.copyHeader(), rr.Endpoint}
|
||||||
}
|
}
|
||||||
func (rr *EUI48) copy() RR {
|
func (rr *EUI48) copy() RR {
|
||||||
return &EUI48{rr.Hdr, rr.Address}
|
return &EUI48{*rr.Hdr.copyHeader(), rr.Address}
|
||||||
}
|
}
|
||||||
func (rr *EUI64) copy() RR {
|
func (rr *EUI64) copy() RR {
|
||||||
return &EUI64{rr.Hdr, rr.Address}
|
return &EUI64{*rr.Hdr.copyHeader(), rr.Address}
|
||||||
}
|
}
|
||||||
func (rr *GID) copy() RR {
|
func (rr *GID) copy() RR {
|
||||||
return &GID{rr.Hdr, rr.Gid}
|
return &GID{*rr.Hdr.copyHeader(), rr.Gid}
|
||||||
}
|
}
|
||||||
func (rr *GPOS) copy() RR {
|
func (rr *GPOS) copy() RR {
|
||||||
return &GPOS{rr.Hdr, rr.Longitude, rr.Latitude, rr.Altitude}
|
return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude}
|
||||||
}
|
}
|
||||||
func (rr *HINFO) copy() RR {
|
func (rr *HINFO) copy() RR {
|
||||||
return &HINFO{rr.Hdr, rr.Cpu, rr.Os}
|
return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os}
|
||||||
}
|
}
|
||||||
func (rr *HIP) copy() RR {
|
func (rr *HIP) copy() RR {
|
||||||
RendezvousServers := make([]string, len(rr.RendezvousServers))
|
RendezvousServers := make([]string, len(rr.RendezvousServers))
|
||||||
copy(RendezvousServers, rr.RendezvousServers)
|
copy(RendezvousServers, rr.RendezvousServers)
|
||||||
return &HIP{rr.Hdr, rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
|
return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
|
||||||
}
|
}
|
||||||
func (rr *KX) copy() RR {
|
func (rr *KX) copy() RR {
|
||||||
return &KX{rr.Hdr, rr.Preference, rr.Exchanger}
|
return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger}
|
||||||
}
|
}
|
||||||
func (rr *L32) copy() RR {
|
func (rr *L32) copy() RR {
|
||||||
return &L32{rr.Hdr, rr.Preference, copyIP(rr.Locator32)}
|
return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)}
|
||||||
}
|
}
|
||||||
func (rr *L64) copy() RR {
|
func (rr *L64) copy() RR {
|
||||||
return &L64{rr.Hdr, rr.Preference, rr.Locator64}
|
return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64}
|
||||||
}
|
}
|
||||||
func (rr *LOC) copy() RR {
|
func (rr *LOC) copy() RR {
|
||||||
return &LOC{rr.Hdr, rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
|
return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
|
||||||
}
|
}
|
||||||
func (rr *LP) copy() RR {
|
func (rr *LP) copy() RR {
|
||||||
return &LP{rr.Hdr, rr.Preference, rr.Fqdn}
|
return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn}
|
||||||
}
|
}
|
||||||
func (rr *MB) copy() RR {
|
func (rr *MB) copy() RR {
|
||||||
return &MB{rr.Hdr, rr.Mb}
|
return &MB{*rr.Hdr.copyHeader(), rr.Mb}
|
||||||
}
|
}
|
||||||
func (rr *MD) copy() RR {
|
func (rr *MD) copy() RR {
|
||||||
return &MD{rr.Hdr, rr.Md}
|
return &MD{*rr.Hdr.copyHeader(), rr.Md}
|
||||||
}
|
}
|
||||||
func (rr *MF) copy() RR {
|
func (rr *MF) copy() RR {
|
||||||
return &MF{rr.Hdr, rr.Mf}
|
return &MF{*rr.Hdr.copyHeader(), rr.Mf}
|
||||||
}
|
}
|
||||||
func (rr *MG) copy() RR {
|
func (rr *MG) copy() RR {
|
||||||
return &MG{rr.Hdr, rr.Mg}
|
return &MG{*rr.Hdr.copyHeader(), rr.Mg}
|
||||||
}
|
}
|
||||||
func (rr *MINFO) copy() RR {
|
func (rr *MINFO) copy() RR {
|
||||||
return &MINFO{rr.Hdr, rr.Rmail, rr.Email}
|
return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email}
|
||||||
}
|
}
|
||||||
func (rr *MR) copy() RR {
|
func (rr *MR) copy() RR {
|
||||||
return &MR{rr.Hdr, rr.Mr}
|
return &MR{*rr.Hdr.copyHeader(), rr.Mr}
|
||||||
}
|
}
|
||||||
func (rr *MX) copy() RR {
|
func (rr *MX) copy() RR {
|
||||||
return &MX{rr.Hdr, rr.Preference, rr.Mx}
|
return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx}
|
||||||
}
|
}
|
||||||
func (rr *NAPTR) copy() RR {
|
func (rr *NAPTR) copy() RR {
|
||||||
return &NAPTR{rr.Hdr, rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
|
return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
|
||||||
}
|
}
|
||||||
func (rr *NID) copy() RR {
|
func (rr *NID) copy() RR {
|
||||||
return &NID{rr.Hdr, rr.Preference, rr.NodeID}
|
return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID}
|
||||||
}
|
}
|
||||||
func (rr *NIMLOC) copy() RR {
|
func (rr *NIMLOC) copy() RR {
|
||||||
return &NIMLOC{rr.Hdr, rr.Locator}
|
return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator}
|
||||||
}
|
}
|
||||||
func (rr *NINFO) copy() RR {
|
func (rr *NINFO) copy() RR {
|
||||||
ZSData := make([]string, len(rr.ZSData))
|
ZSData := make([]string, len(rr.ZSData))
|
||||||
copy(ZSData, rr.ZSData)
|
copy(ZSData, rr.ZSData)
|
||||||
return &NINFO{rr.Hdr, ZSData}
|
return &NINFO{*rr.Hdr.copyHeader(), ZSData}
|
||||||
}
|
}
|
||||||
func (rr *NS) copy() RR {
|
func (rr *NS) copy() RR {
|
||||||
return &NS{rr.Hdr, rr.Ns}
|
return &NS{*rr.Hdr.copyHeader(), rr.Ns}
|
||||||
}
|
}
|
||||||
func (rr *NSAPPTR) copy() RR {
|
func (rr *NSAPPTR) copy() RR {
|
||||||
return &NSAPPTR{rr.Hdr, rr.Ptr}
|
return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr}
|
||||||
}
|
}
|
||||||
func (rr *NSEC) copy() RR {
|
func (rr *NSEC) copy() RR {
|
||||||
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
||||||
copy(TypeBitMap, rr.TypeBitMap)
|
copy(TypeBitMap, rr.TypeBitMap)
|
||||||
return &NSEC{rr.Hdr, rr.NextDomain, TypeBitMap}
|
return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, TypeBitMap}
|
||||||
}
|
}
|
||||||
func (rr *NSEC3) copy() RR {
|
func (rr *NSEC3) copy() RR {
|
||||||
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
||||||
copy(TypeBitMap, rr.TypeBitMap)
|
copy(TypeBitMap, rr.TypeBitMap)
|
||||||
return &NSEC3{rr.Hdr, rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, TypeBitMap}
|
return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, TypeBitMap}
|
||||||
}
|
}
|
||||||
func (rr *NSEC3PARAM) copy() RR {
|
func (rr *NSEC3PARAM) copy() RR {
|
||||||
return &NSEC3PARAM{rr.Hdr, rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
|
return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
|
||||||
}
|
}
|
||||||
func (rr *OPENPGPKEY) copy() RR {
|
func (rr *OPENPGPKEY) copy() RR {
|
||||||
return &OPENPGPKEY{rr.Hdr, rr.PublicKey}
|
return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey}
|
||||||
}
|
}
|
||||||
func (rr *OPT) copy() RR {
|
func (rr *OPT) copy() RR {
|
||||||
Option := make([]EDNS0, len(rr.Option))
|
Option := make([]EDNS0, len(rr.Option))
|
||||||
copy(Option, rr.Option)
|
copy(Option, rr.Option)
|
||||||
return &OPT{rr.Hdr, Option}
|
return &OPT{*rr.Hdr.copyHeader(), Option}
|
||||||
}
|
}
|
||||||
func (rr *PTR) copy() RR {
|
func (rr *PTR) copy() RR {
|
||||||
return &PTR{rr.Hdr, rr.Ptr}
|
return &PTR{*rr.Hdr.copyHeader(), rr.Ptr}
|
||||||
}
|
}
|
||||||
func (rr *PX) copy() RR {
|
func (rr *PX) copy() RR {
|
||||||
return &PX{rr.Hdr, rr.Preference, rr.Map822, rr.Mapx400}
|
return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400}
|
||||||
}
|
}
|
||||||
func (rr *RFC3597) copy() RR {
|
func (rr *RFC3597) copy() RR {
|
||||||
return &RFC3597{rr.Hdr, rr.Rdata}
|
return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata}
|
||||||
}
|
}
|
||||||
func (rr *RKEY) copy() RR {
|
func (rr *RKEY) copy() RR {
|
||||||
return &RKEY{rr.Hdr, rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||||
}
|
}
|
||||||
func (rr *RP) copy() RR {
|
func (rr *RP) copy() RR {
|
||||||
return &RP{rr.Hdr, rr.Mbox, rr.Txt}
|
return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt}
|
||||||
}
|
}
|
||||||
func (rr *RRSIG) copy() RR {
|
func (rr *RRSIG) copy() RR {
|
||||||
return &RRSIG{rr.Hdr, rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
|
return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
|
||||||
}
|
}
|
||||||
func (rr *RT) copy() RR {
|
func (rr *RT) copy() RR {
|
||||||
return &RT{rr.Hdr, rr.Preference, rr.Host}
|
return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host}
|
||||||
}
|
}
|
||||||
func (rr *SMIMEA) copy() RR {
|
func (rr *SMIMEA) copy() RR {
|
||||||
return &SMIMEA{rr.Hdr, rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
|
return &SMIMEA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
|
||||||
}
|
}
|
||||||
func (rr *SOA) copy() RR {
|
func (rr *SOA) copy() RR {
|
||||||
return &SOA{rr.Hdr, rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
|
return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
|
||||||
}
|
}
|
||||||
func (rr *SPF) copy() RR {
|
func (rr *SPF) copy() RR {
|
||||||
Txt := make([]string, len(rr.Txt))
|
Txt := make([]string, len(rr.Txt))
|
||||||
copy(Txt, rr.Txt)
|
copy(Txt, rr.Txt)
|
||||||
return &SPF{rr.Hdr, Txt}
|
return &SPF{*rr.Hdr.copyHeader(), Txt}
|
||||||
}
|
}
|
||||||
func (rr *SRV) copy() RR {
|
func (rr *SRV) copy() RR {
|
||||||
return &SRV{rr.Hdr, rr.Priority, rr.Weight, rr.Port, rr.Target}
|
return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target}
|
||||||
}
|
}
|
||||||
func (rr *SSHFP) copy() RR {
|
func (rr *SSHFP) copy() RR {
|
||||||
return &SSHFP{rr.Hdr, rr.Algorithm, rr.Type, rr.FingerPrint}
|
return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint}
|
||||||
}
|
}
|
||||||
func (rr *TA) copy() RR {
|
func (rr *TA) copy() RR {
|
||||||
return &TA{rr.Hdr, rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||||
}
|
}
|
||||||
func (rr *TALINK) copy() RR {
|
func (rr *TALINK) copy() RR {
|
||||||
return &TALINK{rr.Hdr, rr.PreviousName, rr.NextName}
|
return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName}
|
||||||
}
|
}
|
||||||
func (rr *TKEY) copy() RR {
|
func (rr *TKEY) copy() RR {
|
||||||
return &TKEY{rr.Hdr, rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
|
return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
|
||||||
}
|
}
|
||||||
func (rr *TLSA) copy() RR {
|
func (rr *TLSA) copy() RR {
|
||||||
return &TLSA{rr.Hdr, rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
|
return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
|
||||||
}
|
}
|
||||||
func (rr *TSIG) copy() RR {
|
func (rr *TSIG) copy() RR {
|
||||||
return &TSIG{rr.Hdr, rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
|
return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
|
||||||
}
|
}
|
||||||
func (rr *TXT) copy() RR {
|
func (rr *TXT) copy() RR {
|
||||||
Txt := make([]string, len(rr.Txt))
|
Txt := make([]string, len(rr.Txt))
|
||||||
copy(Txt, rr.Txt)
|
copy(Txt, rr.Txt)
|
||||||
return &TXT{rr.Hdr, Txt}
|
return &TXT{*rr.Hdr.copyHeader(), Txt}
|
||||||
}
|
}
|
||||||
func (rr *UID) copy() RR {
|
func (rr *UID) copy() RR {
|
||||||
return &UID{rr.Hdr, rr.Uid}
|
return &UID{*rr.Hdr.copyHeader(), rr.Uid}
|
||||||
}
|
}
|
||||||
func (rr *UINFO) copy() RR {
|
func (rr *UINFO) copy() RR {
|
||||||
return &UINFO{rr.Hdr, rr.Uinfo}
|
return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo}
|
||||||
}
|
}
|
||||||
func (rr *URI) copy() RR {
|
func (rr *URI) copy() RR {
|
||||||
return &URI{rr.Hdr, rr.Priority, rr.Weight, rr.Target}
|
return &URI{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Target}
|
||||||
}
|
}
|
||||||
func (rr *X25) copy() RR {
|
func (rr *X25) copy() RR {
|
||||||
return &X25{rr.Hdr, rr.PSDNAddress}
|
return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
// 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 bpf
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// Assemble converts insts into raw instructions suitable for loading
|
|
||||||
// into a BPF virtual machine.
|
|
||||||
//
|
|
||||||
// Currently, no optimization is attempted, the assembled program flow
|
|
||||||
// is exactly as provided.
|
|
||||||
func Assemble(insts []Instruction) ([]RawInstruction, error) {
|
|
||||||
ret := make([]RawInstruction, len(insts))
|
|
||||||
var err error
|
|
||||||
for i, inst := range insts {
|
|
||||||
ret[i], err = inst.Assemble()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("assembling instruction %d: %s", i+1, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disassemble attempts to parse raw back into
|
|
||||||
// Instructions. Unrecognized RawInstructions are assumed to be an
|
|
||||||
// extension not implemented by this package, and are passed through
|
|
||||||
// unchanged to the output. The allDecoded value reports whether insts
|
|
||||||
// contains no RawInstructions.
|
|
||||||
func Disassemble(raw []RawInstruction) (insts []Instruction, allDecoded bool) {
|
|
||||||
insts = make([]Instruction, len(raw))
|
|
||||||
allDecoded = true
|
|
||||||
for i, r := range raw {
|
|
||||||
insts[i] = r.Disassemble()
|
|
||||||
if _, ok := insts[i].(RawInstruction); ok {
|
|
||||||
allDecoded = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return insts, allDecoded
|
|
||||||
}
|
|
|
@ -1,218 +0,0 @@
|
||||||
// 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 bpf
|
|
||||||
|
|
||||||
// A Register is a register of the BPF virtual machine.
|
|
||||||
type Register uint16
|
|
||||||
|
|
||||||
const (
|
|
||||||
// RegA is the accumulator register. RegA is always the
|
|
||||||
// destination register of ALU operations.
|
|
||||||
RegA Register = iota
|
|
||||||
// RegX is the indirection register, used by LoadIndirect
|
|
||||||
// operations.
|
|
||||||
RegX
|
|
||||||
)
|
|
||||||
|
|
||||||
// An ALUOp is an arithmetic or logic operation.
|
|
||||||
type ALUOp uint16
|
|
||||||
|
|
||||||
// ALU binary operation types.
|
|
||||||
const (
|
|
||||||
ALUOpAdd ALUOp = iota << 4
|
|
||||||
ALUOpSub
|
|
||||||
ALUOpMul
|
|
||||||
ALUOpDiv
|
|
||||||
ALUOpOr
|
|
||||||
ALUOpAnd
|
|
||||||
ALUOpShiftLeft
|
|
||||||
ALUOpShiftRight
|
|
||||||
aluOpNeg // Not exported because it's the only unary ALU operation, and gets its own instruction type.
|
|
||||||
ALUOpMod
|
|
||||||
ALUOpXor
|
|
||||||
)
|
|
||||||
|
|
||||||
// A JumpTest is a comparison operator used in conditional jumps.
|
|
||||||
type JumpTest uint16
|
|
||||||
|
|
||||||
// Supported operators for conditional jumps.
|
|
||||||
const (
|
|
||||||
// K == A
|
|
||||||
JumpEqual JumpTest = iota
|
|
||||||
// K != A
|
|
||||||
JumpNotEqual
|
|
||||||
// K > A
|
|
||||||
JumpGreaterThan
|
|
||||||
// K < A
|
|
||||||
JumpLessThan
|
|
||||||
// K >= A
|
|
||||||
JumpGreaterOrEqual
|
|
||||||
// K <= A
|
|
||||||
JumpLessOrEqual
|
|
||||||
// K & A != 0
|
|
||||||
JumpBitsSet
|
|
||||||
// K & A == 0
|
|
||||||
JumpBitsNotSet
|
|
||||||
)
|
|
||||||
|
|
||||||
// An Extension is a function call provided by the kernel that
|
|
||||||
// performs advanced operations that are expensive or impossible
|
|
||||||
// within the BPF virtual machine.
|
|
||||||
//
|
|
||||||
// Extensions are only implemented by the Linux kernel.
|
|
||||||
//
|
|
||||||
// TODO: should we prune this list? Some of these extensions seem
|
|
||||||
// either broken or near-impossible to use correctly, whereas other
|
|
||||||
// (len, random, ifindex) are quite useful.
|
|
||||||
type Extension int
|
|
||||||
|
|
||||||
// Extension functions available in the Linux kernel.
|
|
||||||
const (
|
|
||||||
// extOffset is the negative maximum number of instructions used
|
|
||||||
// to load instructions by overloading the K argument.
|
|
||||||
extOffset = -0x1000
|
|
||||||
// ExtLen returns the length of the packet.
|
|
||||||
ExtLen Extension = 1
|
|
||||||
// ExtProto returns the packet's L3 protocol type.
|
|
||||||
ExtProto Extension = 0
|
|
||||||
// ExtType returns the packet's type (skb->pkt_type in the kernel)
|
|
||||||
//
|
|
||||||
// TODO: better documentation. How nice an API do we want to
|
|
||||||
// provide for these esoteric extensions?
|
|
||||||
ExtType Extension = 4
|
|
||||||
// ExtPayloadOffset returns the offset of the packet payload, or
|
|
||||||
// the first protocol header that the kernel does not know how to
|
|
||||||
// parse.
|
|
||||||
ExtPayloadOffset Extension = 52
|
|
||||||
// ExtInterfaceIndex returns the index of the interface on which
|
|
||||||
// the packet was received.
|
|
||||||
ExtInterfaceIndex Extension = 8
|
|
||||||
// ExtNetlinkAttr returns the netlink attribute of type X at
|
|
||||||
// offset A.
|
|
||||||
ExtNetlinkAttr Extension = 12
|
|
||||||
// ExtNetlinkAttrNested returns the nested netlink attribute of
|
|
||||||
// type X at offset A.
|
|
||||||
ExtNetlinkAttrNested Extension = 16
|
|
||||||
// ExtMark returns the packet's mark value.
|
|
||||||
ExtMark Extension = 20
|
|
||||||
// ExtQueue returns the packet's assigned hardware queue.
|
|
||||||
ExtQueue Extension = 24
|
|
||||||
// ExtLinkLayerType returns the packet's hardware address type
|
|
||||||
// (e.g. Ethernet, Infiniband).
|
|
||||||
ExtLinkLayerType Extension = 28
|
|
||||||
// ExtRXHash returns the packets receive hash.
|
|
||||||
//
|
|
||||||
// TODO: figure out what this rxhash actually is.
|
|
||||||
ExtRXHash Extension = 32
|
|
||||||
// ExtCPUID returns the ID of the CPU processing the current
|
|
||||||
// packet.
|
|
||||||
ExtCPUID Extension = 36
|
|
||||||
// ExtVLANTag returns the packet's VLAN tag.
|
|
||||||
ExtVLANTag Extension = 44
|
|
||||||
// ExtVLANTagPresent returns non-zero if the packet has a VLAN
|
|
||||||
// tag.
|
|
||||||
//
|
|
||||||
// TODO: I think this might be a lie: it reads bit 0x1000 of the
|
|
||||||
// VLAN header, which changed meaning in recent revisions of the
|
|
||||||
// spec - this extension may now return meaningless information.
|
|
||||||
ExtVLANTagPresent Extension = 48
|
|
||||||
// ExtVLANProto returns 0x8100 if the frame has a VLAN header,
|
|
||||||
// 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some
|
|
||||||
// other value if no VLAN information is present.
|
|
||||||
ExtVLANProto Extension = 60
|
|
||||||
// ExtRand returns a uniformly random uint32.
|
|
||||||
ExtRand Extension = 56
|
|
||||||
)
|
|
||||||
|
|
||||||
// The following gives names to various bit patterns used in opcode construction.
|
|
||||||
|
|
||||||
const (
|
|
||||||
opMaskCls uint16 = 0x7
|
|
||||||
// opClsLoad masks
|
|
||||||
opMaskLoadDest = 0x01
|
|
||||||
opMaskLoadWidth = 0x18
|
|
||||||
opMaskLoadMode = 0xe0
|
|
||||||
// opClsALU
|
|
||||||
opMaskOperandSrc = 0x08
|
|
||||||
opMaskOperator = 0xf0
|
|
||||||
// opClsJump
|
|
||||||
opMaskJumpConst = 0x0f
|
|
||||||
opMaskJumpCond = 0xf0
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// +---------------+-----------------+---+---+---+
|
|
||||||
// | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 0 |
|
|
||||||
// +---------------+-----------------+---+---+---+
|
|
||||||
opClsLoadA uint16 = iota
|
|
||||||
// +---------------+-----------------+---+---+---+
|
|
||||||
// | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 1 |
|
|
||||||
// +---------------+-----------------+---+---+---+
|
|
||||||
opClsLoadX
|
|
||||||
// +---+---+---+---+---+---+---+---+
|
|
||||||
// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
|
|
||||||
// +---+---+---+---+---+---+---+---+
|
|
||||||
opClsStoreA
|
|
||||||
// +---+---+---+---+---+---+---+---+
|
|
||||||
// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
|
|
||||||
// +---+---+---+---+---+---+---+---+
|
|
||||||
opClsStoreX
|
|
||||||
// +---------------+-----------------+---+---+---+
|
|
||||||
// | Operator (4b) | OperandSrc (1b) | 1 | 0 | 0 |
|
|
||||||
// +---------------+-----------------+---+---+---+
|
|
||||||
opClsALU
|
|
||||||
// +-----------------------------+---+---+---+---+
|
|
||||||
// | TestOperator (4b) | 0 | 1 | 0 | 1 |
|
|
||||||
// +-----------------------------+---+---+---+---+
|
|
||||||
opClsJump
|
|
||||||
// +---+-------------------------+---+---+---+---+
|
|
||||||
// | 0 | 0 | 0 | RetSrc (1b) | 0 | 1 | 1 | 0 |
|
|
||||||
// +---+-------------------------+---+---+---+---+
|
|
||||||
opClsReturn
|
|
||||||
// +---+-------------------------+---+---+---+---+
|
|
||||||
// | 0 | 0 | 0 | TXAorTAX (1b) | 0 | 1 | 1 | 1 |
|
|
||||||
// +---+-------------------------+---+---+---+---+
|
|
||||||
opClsMisc
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
opAddrModeImmediate uint16 = iota << 5
|
|
||||||
opAddrModeAbsolute
|
|
||||||
opAddrModeIndirect
|
|
||||||
opAddrModeScratch
|
|
||||||
opAddrModePacketLen // actually an extension, not an addressing mode.
|
|
||||||
opAddrModeMemShift
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
opLoadWidth4 uint16 = iota << 3
|
|
||||||
opLoadWidth2
|
|
||||||
opLoadWidth1
|
|
||||||
)
|
|
||||||
|
|
||||||
// Operator defined by ALUOp*
|
|
||||||
|
|
||||||
const (
|
|
||||||
opALUSrcConstant uint16 = iota << 3
|
|
||||||
opALUSrcX
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
opJumpAlways = iota << 4
|
|
||||||
opJumpEqual
|
|
||||||
opJumpGT
|
|
||||||
opJumpGE
|
|
||||||
opJumpSet
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
opRetSrcConstant uint16 = iota << 4
|
|
||||||
opRetSrcA
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
opMiscTAX = 0x00
|
|
||||||
opMiscTXA = 0x80
|
|
||||||
)
|
|
|
@ -1,82 +0,0 @@
|
||||||
// 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 bpf implements marshaling and unmarshaling of programs for the
|
|
||||||
Berkeley Packet Filter virtual machine, and provides a Go implementation
|
|
||||||
of the virtual machine.
|
|
||||||
|
|
||||||
BPF's main use is to specify a packet filter for network taps, so that
|
|
||||||
the kernel doesn't have to expensively copy every packet it sees to
|
|
||||||
userspace. However, it's been repurposed to other areas where running
|
|
||||||
user code in-kernel is needed. For example, Linux's seccomp uses BPF
|
|
||||||
to apply security policies to system calls. For simplicity, this
|
|
||||||
documentation refers only to packets, but other uses of BPF have their
|
|
||||||
own data payloads.
|
|
||||||
|
|
||||||
BPF programs run in a restricted virtual machine. It has almost no
|
|
||||||
access to kernel functions, and while conditional branches are
|
|
||||||
allowed, they can only jump forwards, to guarantee that there are no
|
|
||||||
infinite loops.
|
|
||||||
|
|
||||||
The virtual machine
|
|
||||||
|
|
||||||
The BPF VM is an accumulator machine. Its main register, called
|
|
||||||
register A, is an implicit source and destination in all arithmetic
|
|
||||||
and logic operations. The machine also has 16 scratch registers for
|
|
||||||
temporary storage, and an indirection register (register X) for
|
|
||||||
indirect memory access. All registers are 32 bits wide.
|
|
||||||
|
|
||||||
Each run of a BPF program is given one packet, which is placed in the
|
|
||||||
VM's read-only "main memory". LoadAbsolute and LoadIndirect
|
|
||||||
instructions can fetch up to 32 bits at a time into register A for
|
|
||||||
examination.
|
|
||||||
|
|
||||||
The goal of a BPF program is to produce and return a verdict (uint32),
|
|
||||||
which tells the kernel what to do with the packet. In the context of
|
|
||||||
packet filtering, the returned value is the number of bytes of the
|
|
||||||
packet to forward to userspace, or 0 to ignore the packet. Other
|
|
||||||
contexts like seccomp define their own return values.
|
|
||||||
|
|
||||||
In order to simplify programs, attempts to read past the end of the
|
|
||||||
packet terminate the program execution with a verdict of 0 (ignore
|
|
||||||
packet). This means that the vast majority of BPF programs don't need
|
|
||||||
to do any explicit bounds checking.
|
|
||||||
|
|
||||||
In addition to the bytes of the packet, some BPF programs have access
|
|
||||||
to extensions, which are essentially calls to kernel utility
|
|
||||||
functions. Currently, the only extensions supported by this package
|
|
||||||
are the Linux packet filter extensions.
|
|
||||||
|
|
||||||
Examples
|
|
||||||
|
|
||||||
This packet filter selects all ARP packets.
|
|
||||||
|
|
||||||
bpf.Assemble([]bpf.Instruction{
|
|
||||||
// Load "EtherType" field from the ethernet header.
|
|
||||||
bpf.LoadAbsolute{Off: 12, Size: 2},
|
|
||||||
// Skip over the next instruction if EtherType is not ARP.
|
|
||||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x0806, SkipTrue: 1},
|
|
||||||
// Verdict is "send up to 4k of the packet to userspace."
|
|
||||||
bpf.RetConstant{Val: 4096},
|
|
||||||
// Verdict is "ignore packet."
|
|
||||||
bpf.RetConstant{Val: 0},
|
|
||||||
})
|
|
||||||
|
|
||||||
This packet filter captures a random 1% sample of traffic.
|
|
||||||
|
|
||||||
bpf.Assemble([]bpf.Instruction{
|
|
||||||
// Get a 32-bit random number from the Linux kernel.
|
|
||||||
bpf.LoadExtension{Num: bpf.ExtRand},
|
|
||||||
// 1% dice roll?
|
|
||||||
bpf.JumpIf{Cond: bpf.JumpLessThan, Val: 2^32/100, SkipFalse: 1},
|
|
||||||
// Capture.
|
|
||||||
bpf.RetConstant{Val: 4096},
|
|
||||||
// Ignore.
|
|
||||||
bpf.RetConstant{Val: 0},
|
|
||||||
})
|
|
||||||
|
|
||||||
*/
|
|
||||||
package bpf // import "golang.org/x/net/bpf"
|
|
|
@ -1,704 +0,0 @@
|
||||||
// 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 bpf
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// An Instruction is one instruction executed by the BPF virtual
|
|
||||||
// machine.
|
|
||||||
type Instruction interface {
|
|
||||||
// Assemble assembles the Instruction into a RawInstruction.
|
|
||||||
Assemble() (RawInstruction, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A RawInstruction is a raw BPF virtual machine instruction.
|
|
||||||
type RawInstruction struct {
|
|
||||||
// Operation to execute.
|
|
||||||
Op uint16
|
|
||||||
// For conditional jump instructions, the number of instructions
|
|
||||||
// to skip if the condition is true/false.
|
|
||||||
Jt uint8
|
|
||||||
Jf uint8
|
|
||||||
// Constant parameter. The meaning depends on the Op.
|
|
||||||
K uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
|
|
||||||
|
|
||||||
// Disassemble parses ri into an Instruction and returns it. If ri is
|
|
||||||
// not recognized by this package, ri itself is returned.
|
|
||||||
func (ri RawInstruction) Disassemble() Instruction {
|
|
||||||
switch ri.Op & opMaskCls {
|
|
||||||
case opClsLoadA, opClsLoadX:
|
|
||||||
reg := Register(ri.Op & opMaskLoadDest)
|
|
||||||
sz := 0
|
|
||||||
switch ri.Op & opMaskLoadWidth {
|
|
||||||
case opLoadWidth4:
|
|
||||||
sz = 4
|
|
||||||
case opLoadWidth2:
|
|
||||||
sz = 2
|
|
||||||
case opLoadWidth1:
|
|
||||||
sz = 1
|
|
||||||
default:
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
switch ri.Op & opMaskLoadMode {
|
|
||||||
case opAddrModeImmediate:
|
|
||||||
if sz != 4 {
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
return LoadConstant{Dst: reg, Val: ri.K}
|
|
||||||
case opAddrModeScratch:
|
|
||||||
if sz != 4 || ri.K > 15 {
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
return LoadScratch{Dst: reg, N: int(ri.K)}
|
|
||||||
case opAddrModeAbsolute:
|
|
||||||
if ri.K > extOffset+0xffffffff {
|
|
||||||
return LoadExtension{Num: Extension(-extOffset + ri.K)}
|
|
||||||
}
|
|
||||||
return LoadAbsolute{Size: sz, Off: ri.K}
|
|
||||||
case opAddrModeIndirect:
|
|
||||||
return LoadIndirect{Size: sz, Off: ri.K}
|
|
||||||
case opAddrModePacketLen:
|
|
||||||
if sz != 4 {
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
return LoadExtension{Num: ExtLen}
|
|
||||||
case opAddrModeMemShift:
|
|
||||||
return LoadMemShift{Off: ri.K}
|
|
||||||
default:
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
|
|
||||||
case opClsStoreA:
|
|
||||||
if ri.Op != opClsStoreA || ri.K > 15 {
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
return StoreScratch{Src: RegA, N: int(ri.K)}
|
|
||||||
|
|
||||||
case opClsStoreX:
|
|
||||||
if ri.Op != opClsStoreX || ri.K > 15 {
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
return StoreScratch{Src: RegX, N: int(ri.K)}
|
|
||||||
|
|
||||||
case opClsALU:
|
|
||||||
switch op := ALUOp(ri.Op & opMaskOperator); op {
|
|
||||||
case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
|
|
||||||
if ri.Op&opMaskOperandSrc != 0 {
|
|
||||||
return ALUOpX{Op: op}
|
|
||||||
}
|
|
||||||
return ALUOpConstant{Op: op, Val: ri.K}
|
|
||||||
case aluOpNeg:
|
|
||||||
return NegateA{}
|
|
||||||
default:
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
|
|
||||||
case opClsJump:
|
|
||||||
if ri.Op&opMaskJumpConst != opClsJump {
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
switch ri.Op & opMaskJumpCond {
|
|
||||||
case opJumpAlways:
|
|
||||||
return Jump{Skip: ri.K}
|
|
||||||
case opJumpEqual:
|
|
||||||
if ri.Jt == 0 {
|
|
||||||
return JumpIf{
|
|
||||||
Cond: JumpNotEqual,
|
|
||||||
Val: ri.K,
|
|
||||||
SkipTrue: ri.Jf,
|
|
||||||
SkipFalse: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return JumpIf{
|
|
||||||
Cond: JumpEqual,
|
|
||||||
Val: ri.K,
|
|
||||||
SkipTrue: ri.Jt,
|
|
||||||
SkipFalse: ri.Jf,
|
|
||||||
}
|
|
||||||
case opJumpGT:
|
|
||||||
if ri.Jt == 0 {
|
|
||||||
return JumpIf{
|
|
||||||
Cond: JumpLessOrEqual,
|
|
||||||
Val: ri.K,
|
|
||||||
SkipTrue: ri.Jf,
|
|
||||||
SkipFalse: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return JumpIf{
|
|
||||||
Cond: JumpGreaterThan,
|
|
||||||
Val: ri.K,
|
|
||||||
SkipTrue: ri.Jt,
|
|
||||||
SkipFalse: ri.Jf,
|
|
||||||
}
|
|
||||||
case opJumpGE:
|
|
||||||
if ri.Jt == 0 {
|
|
||||||
return JumpIf{
|
|
||||||
Cond: JumpLessThan,
|
|
||||||
Val: ri.K,
|
|
||||||
SkipTrue: ri.Jf,
|
|
||||||
SkipFalse: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return JumpIf{
|
|
||||||
Cond: JumpGreaterOrEqual,
|
|
||||||
Val: ri.K,
|
|
||||||
SkipTrue: ri.Jt,
|
|
||||||
SkipFalse: ri.Jf,
|
|
||||||
}
|
|
||||||
case opJumpSet:
|
|
||||||
return JumpIf{
|
|
||||||
Cond: JumpBitsSet,
|
|
||||||
Val: ri.K,
|
|
||||||
SkipTrue: ri.Jt,
|
|
||||||
SkipFalse: ri.Jf,
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
|
|
||||||
case opClsReturn:
|
|
||||||
switch ri.Op {
|
|
||||||
case opClsReturn | opRetSrcA:
|
|
||||||
return RetA{}
|
|
||||||
case opClsReturn | opRetSrcConstant:
|
|
||||||
return RetConstant{Val: ri.K}
|
|
||||||
default:
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
|
|
||||||
case opClsMisc:
|
|
||||||
switch ri.Op {
|
|
||||||
case opClsMisc | opMiscTAX:
|
|
||||||
return TAX{}
|
|
||||||
case opClsMisc | opMiscTXA:
|
|
||||||
return TXA{}
|
|
||||||
default:
|
|
||||||
return ri
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic("unreachable") // switch is exhaustive on the bit pattern
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadConstant loads Val into register Dst.
|
|
||||||
type LoadConstant struct {
|
|
||||||
Dst Register
|
|
||||||
Val uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a LoadConstant) Assemble() (RawInstruction, error) {
|
|
||||||
return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a LoadConstant) String() string {
|
|
||||||
switch a.Dst {
|
|
||||||
case RegA:
|
|
||||||
return fmt.Sprintf("ld #%d", a.Val)
|
|
||||||
case RegX:
|
|
||||||
return fmt.Sprintf("ldx #%d", a.Val)
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadScratch loads scratch[N] into register Dst.
|
|
||||||
type LoadScratch struct {
|
|
||||||
Dst Register
|
|
||||||
N int // 0-15
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a LoadScratch) Assemble() (RawInstruction, error) {
|
|
||||||
if a.N < 0 || a.N > 15 {
|
|
||||||
return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
|
|
||||||
}
|
|
||||||
return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a LoadScratch) String() string {
|
|
||||||
switch a.Dst {
|
|
||||||
case RegA:
|
|
||||||
return fmt.Sprintf("ld M[%d]", a.N)
|
|
||||||
case RegX:
|
|
||||||
return fmt.Sprintf("ldx M[%d]", a.N)
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadAbsolute loads packet[Off:Off+Size] as an integer value into
|
|
||||||
// register A.
|
|
||||||
type LoadAbsolute struct {
|
|
||||||
Off uint32
|
|
||||||
Size int // 1, 2 or 4
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a LoadAbsolute) Assemble() (RawInstruction, error) {
|
|
||||||
return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a LoadAbsolute) String() string {
|
|
||||||
switch a.Size {
|
|
||||||
case 1: // byte
|
|
||||||
return fmt.Sprintf("ldb [%d]", a.Off)
|
|
||||||
case 2: // half word
|
|
||||||
return fmt.Sprintf("ldh [%d]", a.Off)
|
|
||||||
case 4: // word
|
|
||||||
if a.Off > extOffset+0xffffffff {
|
|
||||||
return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("ld [%d]", a.Off)
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
|
|
||||||
// into register A.
|
|
||||||
type LoadIndirect struct {
|
|
||||||
Off uint32
|
|
||||||
Size int // 1, 2 or 4
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a LoadIndirect) Assemble() (RawInstruction, error) {
|
|
||||||
return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a LoadIndirect) String() string {
|
|
||||||
switch a.Size {
|
|
||||||
case 1: // byte
|
|
||||||
return fmt.Sprintf("ldb [x + %d]", a.Off)
|
|
||||||
case 2: // half word
|
|
||||||
return fmt.Sprintf("ldh [x + %d]", a.Off)
|
|
||||||
case 4: // word
|
|
||||||
return fmt.Sprintf("ld [x + %d]", a.Off)
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
|
|
||||||
// by 4 and stores the result in register X.
|
|
||||||
//
|
|
||||||
// This instruction is mainly useful to load into X the length of an
|
|
||||||
// IPv4 packet header in a single instruction, rather than have to do
|
|
||||||
// the arithmetic on the header's first byte by hand.
|
|
||||||
type LoadMemShift struct {
|
|
||||||
Off uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a LoadMemShift) Assemble() (RawInstruction, error) {
|
|
||||||
return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a LoadMemShift) String() string {
|
|
||||||
return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadExtension invokes a linux-specific extension and stores the
|
|
||||||
// result in register A.
|
|
||||||
type LoadExtension struct {
|
|
||||||
Num Extension
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a LoadExtension) Assemble() (RawInstruction, error) {
|
|
||||||
if a.Num == ExtLen {
|
|
||||||
return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
|
|
||||||
}
|
|
||||||
return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a LoadExtension) String() string {
|
|
||||||
switch a.Num {
|
|
||||||
case ExtLen:
|
|
||||||
return "ld #len"
|
|
||||||
case ExtProto:
|
|
||||||
return "ld #proto"
|
|
||||||
case ExtType:
|
|
||||||
return "ld #type"
|
|
||||||
case ExtPayloadOffset:
|
|
||||||
return "ld #poff"
|
|
||||||
case ExtInterfaceIndex:
|
|
||||||
return "ld #ifidx"
|
|
||||||
case ExtNetlinkAttr:
|
|
||||||
return "ld #nla"
|
|
||||||
case ExtNetlinkAttrNested:
|
|
||||||
return "ld #nlan"
|
|
||||||
case ExtMark:
|
|
||||||
return "ld #mark"
|
|
||||||
case ExtQueue:
|
|
||||||
return "ld #queue"
|
|
||||||
case ExtLinkLayerType:
|
|
||||||
return "ld #hatype"
|
|
||||||
case ExtRXHash:
|
|
||||||
return "ld #rxhash"
|
|
||||||
case ExtCPUID:
|
|
||||||
return "ld #cpu"
|
|
||||||
case ExtVLANTag:
|
|
||||||
return "ld #vlan_tci"
|
|
||||||
case ExtVLANTagPresent:
|
|
||||||
return "ld #vlan_avail"
|
|
||||||
case ExtVLANProto:
|
|
||||||
return "ld #vlan_tpid"
|
|
||||||
case ExtRand:
|
|
||||||
return "ld #rand"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StoreScratch stores register Src into scratch[N].
|
|
||||||
type StoreScratch struct {
|
|
||||||
Src Register
|
|
||||||
N int // 0-15
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a StoreScratch) Assemble() (RawInstruction, error) {
|
|
||||||
if a.N < 0 || a.N > 15 {
|
|
||||||
return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
|
|
||||||
}
|
|
||||||
var op uint16
|
|
||||||
switch a.Src {
|
|
||||||
case RegA:
|
|
||||||
op = opClsStoreA
|
|
||||||
case RegX:
|
|
||||||
op = opClsStoreX
|
|
||||||
default:
|
|
||||||
return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
|
|
||||||
}
|
|
||||||
|
|
||||||
return RawInstruction{
|
|
||||||
Op: op,
|
|
||||||
K: uint32(a.N),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a StoreScratch) String() string {
|
|
||||||
switch a.Src {
|
|
||||||
case RegA:
|
|
||||||
return fmt.Sprintf("st M[%d]", a.N)
|
|
||||||
case RegX:
|
|
||||||
return fmt.Sprintf("stx M[%d]", a.N)
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ALUOpConstant executes A = A <Op> Val.
|
|
||||||
type ALUOpConstant struct {
|
|
||||||
Op ALUOp
|
|
||||||
Val uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a ALUOpConstant) Assemble() (RawInstruction, error) {
|
|
||||||
return RawInstruction{
|
|
||||||
Op: opClsALU | opALUSrcConstant | uint16(a.Op),
|
|
||||||
K: a.Val,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a ALUOpConstant) String() string {
|
|
||||||
switch a.Op {
|
|
||||||
case ALUOpAdd:
|
|
||||||
return fmt.Sprintf("add #%d", a.Val)
|
|
||||||
case ALUOpSub:
|
|
||||||
return fmt.Sprintf("sub #%d", a.Val)
|
|
||||||
case ALUOpMul:
|
|
||||||
return fmt.Sprintf("mul #%d", a.Val)
|
|
||||||
case ALUOpDiv:
|
|
||||||
return fmt.Sprintf("div #%d", a.Val)
|
|
||||||
case ALUOpMod:
|
|
||||||
return fmt.Sprintf("mod #%d", a.Val)
|
|
||||||
case ALUOpAnd:
|
|
||||||
return fmt.Sprintf("and #%d", a.Val)
|
|
||||||
case ALUOpOr:
|
|
||||||
return fmt.Sprintf("or #%d", a.Val)
|
|
||||||
case ALUOpXor:
|
|
||||||
return fmt.Sprintf("xor #%d", a.Val)
|
|
||||||
case ALUOpShiftLeft:
|
|
||||||
return fmt.Sprintf("lsh #%d", a.Val)
|
|
||||||
case ALUOpShiftRight:
|
|
||||||
return fmt.Sprintf("rsh #%d", a.Val)
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ALUOpX executes A = A <Op> X
|
|
||||||
type ALUOpX struct {
|
|
||||||
Op ALUOp
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a ALUOpX) Assemble() (RawInstruction, error) {
|
|
||||||
return RawInstruction{
|
|
||||||
Op: opClsALU | opALUSrcX | uint16(a.Op),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a ALUOpX) String() string {
|
|
||||||
switch a.Op {
|
|
||||||
case ALUOpAdd:
|
|
||||||
return "add x"
|
|
||||||
case ALUOpSub:
|
|
||||||
return "sub x"
|
|
||||||
case ALUOpMul:
|
|
||||||
return "mul x"
|
|
||||||
case ALUOpDiv:
|
|
||||||
return "div x"
|
|
||||||
case ALUOpMod:
|
|
||||||
return "mod x"
|
|
||||||
case ALUOpAnd:
|
|
||||||
return "and x"
|
|
||||||
case ALUOpOr:
|
|
||||||
return "or x"
|
|
||||||
case ALUOpXor:
|
|
||||||
return "xor x"
|
|
||||||
case ALUOpShiftLeft:
|
|
||||||
return "lsh x"
|
|
||||||
case ALUOpShiftRight:
|
|
||||||
return "rsh x"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NegateA executes A = -A.
|
|
||||||
type NegateA struct{}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a NegateA) Assemble() (RawInstruction, error) {
|
|
||||||
return RawInstruction{
|
|
||||||
Op: opClsALU | uint16(aluOpNeg),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a NegateA) String() string {
|
|
||||||
return fmt.Sprintf("neg")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jump skips the following Skip instructions in the program.
|
|
||||||
type Jump struct {
|
|
||||||
Skip uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a Jump) Assemble() (RawInstruction, error) {
|
|
||||||
return RawInstruction{
|
|
||||||
Op: opClsJump | opJumpAlways,
|
|
||||||
K: a.Skip,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a Jump) String() string {
|
|
||||||
return fmt.Sprintf("ja %d", a.Skip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// JumpIf skips the following Skip instructions in the program if A
|
|
||||||
// <Cond> Val is true.
|
|
||||||
type JumpIf struct {
|
|
||||||
Cond JumpTest
|
|
||||||
Val uint32
|
|
||||||
SkipTrue uint8
|
|
||||||
SkipFalse uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a JumpIf) Assemble() (RawInstruction, error) {
|
|
||||||
var (
|
|
||||||
cond uint16
|
|
||||||
flip bool
|
|
||||||
)
|
|
||||||
switch a.Cond {
|
|
||||||
case JumpEqual:
|
|
||||||
cond = opJumpEqual
|
|
||||||
case JumpNotEqual:
|
|
||||||
cond, flip = opJumpEqual, true
|
|
||||||
case JumpGreaterThan:
|
|
||||||
cond = opJumpGT
|
|
||||||
case JumpLessThan:
|
|
||||||
cond, flip = opJumpGE, true
|
|
||||||
case JumpGreaterOrEqual:
|
|
||||||
cond = opJumpGE
|
|
||||||
case JumpLessOrEqual:
|
|
||||||
cond, flip = opJumpGT, true
|
|
||||||
case JumpBitsSet:
|
|
||||||
cond = opJumpSet
|
|
||||||
case JumpBitsNotSet:
|
|
||||||
cond, flip = opJumpSet, true
|
|
||||||
default:
|
|
||||||
return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", a.Cond)
|
|
||||||
}
|
|
||||||
jt, jf := a.SkipTrue, a.SkipFalse
|
|
||||||
if flip {
|
|
||||||
jt, jf = jf, jt
|
|
||||||
}
|
|
||||||
return RawInstruction{
|
|
||||||
Op: opClsJump | cond,
|
|
||||||
Jt: jt,
|
|
||||||
Jf: jf,
|
|
||||||
K: a.Val,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a JumpIf) String() string {
|
|
||||||
switch a.Cond {
|
|
||||||
// K == A
|
|
||||||
case JumpEqual:
|
|
||||||
return conditionalJump(a, "jeq", "jneq")
|
|
||||||
// K != A
|
|
||||||
case JumpNotEqual:
|
|
||||||
return fmt.Sprintf("jneq #%d,%d", a.Val, a.SkipTrue)
|
|
||||||
// K > A
|
|
||||||
case JumpGreaterThan:
|
|
||||||
return conditionalJump(a, "jgt", "jle")
|
|
||||||
// K < A
|
|
||||||
case JumpLessThan:
|
|
||||||
return fmt.Sprintf("jlt #%d,%d", a.Val, a.SkipTrue)
|
|
||||||
// K >= A
|
|
||||||
case JumpGreaterOrEqual:
|
|
||||||
return conditionalJump(a, "jge", "jlt")
|
|
||||||
// K <= A
|
|
||||||
case JumpLessOrEqual:
|
|
||||||
return fmt.Sprintf("jle #%d,%d", a.Val, a.SkipTrue)
|
|
||||||
// K & A != 0
|
|
||||||
case JumpBitsSet:
|
|
||||||
if a.SkipFalse > 0 {
|
|
||||||
return fmt.Sprintf("jset #%d,%d,%d", a.Val, a.SkipTrue, a.SkipFalse)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("jset #%d,%d", a.Val, a.SkipTrue)
|
|
||||||
// K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
|
|
||||||
case JumpBitsNotSet:
|
|
||||||
return JumpIf{Cond: JumpBitsSet, SkipTrue: a.SkipFalse, SkipFalse: a.SkipTrue, Val: a.Val}.String()
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func conditionalJump(inst JumpIf, positiveJump, negativeJump string) string {
|
|
||||||
if inst.SkipTrue > 0 {
|
|
||||||
if inst.SkipFalse > 0 {
|
|
||||||
return fmt.Sprintf("%s #%d,%d,%d", positiveJump, inst.Val, inst.SkipTrue, inst.SkipFalse)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s #%d,%d", positiveJump, inst.Val, inst.SkipTrue)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s #%d,%d", negativeJump, inst.Val, inst.SkipFalse)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetA exits the BPF program, returning the value of register A.
|
|
||||||
type RetA struct{}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a RetA) Assemble() (RawInstruction, error) {
|
|
||||||
return RawInstruction{
|
|
||||||
Op: opClsReturn | opRetSrcA,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a RetA) String() string {
|
|
||||||
return fmt.Sprintf("ret a")
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetConstant exits the BPF program, returning a constant value.
|
|
||||||
type RetConstant struct {
|
|
||||||
Val uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a RetConstant) Assemble() (RawInstruction, error) {
|
|
||||||
return RawInstruction{
|
|
||||||
Op: opClsReturn | opRetSrcConstant,
|
|
||||||
K: a.Val,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a RetConstant) String() string {
|
|
||||||
return fmt.Sprintf("ret #%d", a.Val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TXA copies the value of register X to register A.
|
|
||||||
type TXA struct{}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a TXA) Assemble() (RawInstruction, error) {
|
|
||||||
return RawInstruction{
|
|
||||||
Op: opClsMisc | opMiscTXA,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a TXA) String() string {
|
|
||||||
return fmt.Sprintf("txa")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TAX copies the value of register A to register X.
|
|
||||||
type TAX struct{}
|
|
||||||
|
|
||||||
// Assemble implements the Instruction Assemble method.
|
|
||||||
func (a TAX) Assemble() (RawInstruction, error) {
|
|
||||||
return RawInstruction{
|
|
||||||
Op: opClsMisc | opMiscTAX,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the instruction in assembler notation.
|
|
||||||
func (a TAX) String() string {
|
|
||||||
return fmt.Sprintf("tax")
|
|
||||||
}
|
|
||||||
|
|
||||||
func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
|
|
||||||
var (
|
|
||||||
cls uint16
|
|
||||||
sz uint16
|
|
||||||
)
|
|
||||||
switch dst {
|
|
||||||
case RegA:
|
|
||||||
cls = opClsLoadA
|
|
||||||
case RegX:
|
|
||||||
cls = opClsLoadX
|
|
||||||
default:
|
|
||||||
return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
|
|
||||||
}
|
|
||||||
switch loadSize {
|
|
||||||
case 1:
|
|
||||||
sz = opLoadWidth1
|
|
||||||
case 2:
|
|
||||||
sz = opLoadWidth2
|
|
||||||
case 4:
|
|
||||||
sz = opLoadWidth4
|
|
||||||
default:
|
|
||||||
return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
|
|
||||||
}
|
|
||||||
return RawInstruction{
|
|
||||||
Op: cls | sz | mode,
|
|
||||||
K: k,
|
|
||||||
}, nil
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 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 bpf
|
|
||||||
|
|
||||||
// A Setter is a type which can attach a compiled BPF filter to itself.
|
|
||||||
type Setter interface {
|
|
||||||
SetBPF(filter []RawInstruction) error
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
// 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 bpf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A VM is an emulated BPF virtual machine.
|
|
||||||
type VM struct {
|
|
||||||
filter []Instruction
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVM returns a new VM using the input BPF program.
|
|
||||||
func NewVM(filter []Instruction) (*VM, error) {
|
|
||||||
if len(filter) == 0 {
|
|
||||||
return nil, errors.New("one or more Instructions must be specified")
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, ins := range filter {
|
|
||||||
check := len(filter) - (i + 1)
|
|
||||||
switch ins := ins.(type) {
|
|
||||||
// Check for out-of-bounds jumps in instructions
|
|
||||||
case Jump:
|
|
||||||
if check <= int(ins.Skip) {
|
|
||||||
return nil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", ins.Skip)
|
|
||||||
}
|
|
||||||
case JumpIf:
|
|
||||||
if check <= int(ins.SkipTrue) {
|
|
||||||
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
|
|
||||||
}
|
|
||||||
if check <= int(ins.SkipFalse) {
|
|
||||||
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
|
|
||||||
}
|
|
||||||
// Check for division or modulus by zero
|
|
||||||
case ALUOpConstant:
|
|
||||||
if ins.Val != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ins.Op {
|
|
||||||
case ALUOpDiv, ALUOpMod:
|
|
||||||
return nil, errors.New("cannot divide by zero using ALUOpConstant")
|
|
||||||
}
|
|
||||||
// Check for unknown extensions
|
|
||||||
case LoadExtension:
|
|
||||||
switch ins.Num {
|
|
||||||
case ExtLen:
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("extension %d not implemented", ins.Num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure last instruction is a return instruction
|
|
||||||
switch filter[len(filter)-1].(type) {
|
|
||||||
case RetA, RetConstant:
|
|
||||||
default:
|
|
||||||
return nil, errors.New("BPF program must end with RetA or RetConstant")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Though our VM works using disassembled instructions, we
|
|
||||||
// attempt to assemble the input filter anyway to ensure it is compatible
|
|
||||||
// with an operating system VM.
|
|
||||||
_, err := Assemble(filter)
|
|
||||||
|
|
||||||
return &VM{
|
|
||||||
filter: filter,
|
|
||||||
}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run runs the VM's BPF program against the input bytes.
|
|
||||||
// Run returns the number of bytes accepted by the BPF program, and any errors
|
|
||||||
// which occurred while processing the program.
|
|
||||||
func (v *VM) Run(in []byte) (int, error) {
|
|
||||||
var (
|
|
||||||
// Registers of the virtual machine
|
|
||||||
regA uint32
|
|
||||||
regX uint32
|
|
||||||
regScratch [16]uint32
|
|
||||||
|
|
||||||
// OK is true if the program should continue processing the next
|
|
||||||
// instruction, or false if not, causing the loop to break
|
|
||||||
ok = true
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO(mdlayher): implement:
|
|
||||||
// - NegateA:
|
|
||||||
// - would require a change from uint32 registers to int32
|
|
||||||
// registers
|
|
||||||
|
|
||||||
// TODO(mdlayher): add interop tests that check signedness of ALU
|
|
||||||
// operations against kernel implementation, and make sure Go
|
|
||||||
// implementation matches behavior
|
|
||||||
|
|
||||||
for i := 0; i < len(v.filter) && ok; i++ {
|
|
||||||
ins := v.filter[i]
|
|
||||||
|
|
||||||
switch ins := ins.(type) {
|
|
||||||
case ALUOpConstant:
|
|
||||||
regA = aluOpConstant(ins, regA)
|
|
||||||
case ALUOpX:
|
|
||||||
regA, ok = aluOpX(ins, regA, regX)
|
|
||||||
case Jump:
|
|
||||||
i += int(ins.Skip)
|
|
||||||
case JumpIf:
|
|
||||||
jump := jumpIf(ins, regA)
|
|
||||||
i += jump
|
|
||||||
case LoadAbsolute:
|
|
||||||
regA, ok = loadAbsolute(ins, in)
|
|
||||||
case LoadConstant:
|
|
||||||
regA, regX = loadConstant(ins, regA, regX)
|
|
||||||
case LoadExtension:
|
|
||||||
regA = loadExtension(ins, in)
|
|
||||||
case LoadIndirect:
|
|
||||||
regA, ok = loadIndirect(ins, in, regX)
|
|
||||||
case LoadMemShift:
|
|
||||||
regX, ok = loadMemShift(ins, in)
|
|
||||||
case LoadScratch:
|
|
||||||
regA, regX = loadScratch(ins, regScratch, regA, regX)
|
|
||||||
case RetA:
|
|
||||||
return int(regA), nil
|
|
||||||
case RetConstant:
|
|
||||||
return int(ins.Val), nil
|
|
||||||
case StoreScratch:
|
|
||||||
regScratch = storeScratch(ins, regScratch, regA, regX)
|
|
||||||
case TAX:
|
|
||||||
regX = regA
|
|
||||||
case TXA:
|
|
||||||
regA = regX
|
|
||||||
default:
|
|
||||||
return 0, fmt.Errorf("unknown Instruction at index %d: %T", i, ins)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
|
@ -1,174 +0,0 @@
|
||||||
// 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 bpf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 {
|
|
||||||
return aluOpCommon(ins.Op, regA, ins.Val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) {
|
|
||||||
// Guard against division or modulus by zero by terminating
|
|
||||||
// the program, as the OS BPF VM does
|
|
||||||
if regX == 0 {
|
|
||||||
switch ins.Op {
|
|
||||||
case ALUOpDiv, ALUOpMod:
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return aluOpCommon(ins.Op, regA, regX), true
|
|
||||||
}
|
|
||||||
|
|
||||||
func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 {
|
|
||||||
switch op {
|
|
||||||
case ALUOpAdd:
|
|
||||||
return regA + value
|
|
||||||
case ALUOpSub:
|
|
||||||
return regA - value
|
|
||||||
case ALUOpMul:
|
|
||||||
return regA * value
|
|
||||||
case ALUOpDiv:
|
|
||||||
// Division by zero not permitted by NewVM and aluOpX checks
|
|
||||||
return regA / value
|
|
||||||
case ALUOpOr:
|
|
||||||
return regA | value
|
|
||||||
case ALUOpAnd:
|
|
||||||
return regA & value
|
|
||||||
case ALUOpShiftLeft:
|
|
||||||
return regA << value
|
|
||||||
case ALUOpShiftRight:
|
|
||||||
return regA >> value
|
|
||||||
case ALUOpMod:
|
|
||||||
// Modulus by zero not permitted by NewVM and aluOpX checks
|
|
||||||
return regA % value
|
|
||||||
case ALUOpXor:
|
|
||||||
return regA ^ value
|
|
||||||
default:
|
|
||||||
return regA
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func jumpIf(ins JumpIf, value uint32) int {
|
|
||||||
var ok bool
|
|
||||||
inV := uint32(ins.Val)
|
|
||||||
|
|
||||||
switch ins.Cond {
|
|
||||||
case JumpEqual:
|
|
||||||
ok = value == inV
|
|
||||||
case JumpNotEqual:
|
|
||||||
ok = value != inV
|
|
||||||
case JumpGreaterThan:
|
|
||||||
ok = value > inV
|
|
||||||
case JumpLessThan:
|
|
||||||
ok = value < inV
|
|
||||||
case JumpGreaterOrEqual:
|
|
||||||
ok = value >= inV
|
|
||||||
case JumpLessOrEqual:
|
|
||||||
ok = value <= inV
|
|
||||||
case JumpBitsSet:
|
|
||||||
ok = (value & inV) != 0
|
|
||||||
case JumpBitsNotSet:
|
|
||||||
ok = (value & inV) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if ok {
|
|
||||||
return int(ins.SkipTrue)
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(ins.SkipFalse)
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
|
|
||||||
offset := int(ins.Off)
|
|
||||||
size := int(ins.Size)
|
|
||||||
|
|
||||||
return loadCommon(in, offset, size)
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
|
|
||||||
switch ins.Dst {
|
|
||||||
case RegA:
|
|
||||||
regA = ins.Val
|
|
||||||
case RegX:
|
|
||||||
regX = ins.Val
|
|
||||||
}
|
|
||||||
|
|
||||||
return regA, regX
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadExtension(ins LoadExtension, in []byte) uint32 {
|
|
||||||
switch ins.Num {
|
|
||||||
case ExtLen:
|
|
||||||
return uint32(len(in))
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
|
|
||||||
offset := int(ins.Off) + int(regX)
|
|
||||||
size := int(ins.Size)
|
|
||||||
|
|
||||||
return loadCommon(in, offset, size)
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
|
|
||||||
offset := int(ins.Off)
|
|
||||||
|
|
||||||
if !inBounds(len(in), offset, 0) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mask off high 4 bits and multiply low 4 bits by 4
|
|
||||||
return uint32(in[offset]&0x0f) * 4, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func inBounds(inLen int, offset int, size int) bool {
|
|
||||||
return offset+size <= inLen
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadCommon(in []byte, offset int, size int) (uint32, bool) {
|
|
||||||
if !inBounds(len(in), offset, size) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch size {
|
|
||||||
case 1:
|
|
||||||
return uint32(in[offset]), true
|
|
||||||
case 2:
|
|
||||||
return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
|
|
||||||
case 4:
|
|
||||||
return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("invalid load size: %d", size))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) {
|
|
||||||
switch ins.Dst {
|
|
||||||
case RegA:
|
|
||||||
regA = regScratch[ins.N]
|
|
||||||
case RegX:
|
|
||||||
regX = regScratch[ins.N]
|
|
||||||
}
|
|
||||||
|
|
||||||
return regA, regX
|
|
||||||
}
|
|
||||||
|
|
||||||
func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 {
|
|
||||||
switch ins.Src {
|
|
||||||
case RegA:
|
|
||||||
regScratch[ins.N] = regA
|
|
||||||
case RegX:
|
|
||||||
regScratch[ins.N] = regX
|
|
||||||
}
|
|
||||||
|
|
||||||
return regScratch
|
|
||||||
}
|
|
|
@ -1,223 +0,0 @@
|
||||||
// go generate gen.go
|
|
||||||
// Code generated by the command above; DO NOT EDIT.
|
|
||||||
|
|
||||||
// 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: 2018-05-04
|
|
||||||
const (
|
|
||||||
DiffServCS0 = 0x00 // CS0
|
|
||||||
DiffServCS1 = 0x20 // CS1
|
|
||||||
DiffServCS2 = 0x40 // CS2
|
|
||||||
DiffServCS3 = 0x60 // CS3
|
|
||||||
DiffServCS4 = 0x80 // CS4
|
|
||||||
DiffServCS5 = 0xa0 // CS5
|
|
||||||
DiffServCS6 = 0xc0 // CS6
|
|
||||||
DiffServCS7 = 0xe0 // CS7
|
|
||||||
DiffServAF11 = 0x28 // AF11
|
|
||||||
DiffServAF12 = 0x30 // AF12
|
|
||||||
DiffServAF13 = 0x38 // AF13
|
|
||||||
DiffServAF21 = 0x48 // AF21
|
|
||||||
DiffServAF22 = 0x50 // AF22
|
|
||||||
DiffServAF23 = 0x58 // AF23
|
|
||||||
DiffServAF31 = 0x68 // AF31
|
|
||||||
DiffServAF32 = 0x70 // AF32
|
|
||||||
DiffServAF33 = 0x78 // AF33
|
|
||||||
DiffServAF41 = 0x88 // AF41
|
|
||||||
DiffServAF42 = 0x90 // AF42
|
|
||||||
DiffServAF43 = 0x98 // AF43
|
|
||||||
DiffServEF = 0xb8 // EF
|
|
||||||
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
|
|
||||||
NotECNTransport = 0x00 // Not-ECT (Not ECN-Capable Transport)
|
|
||||||
ECNTransport1 = 0x01 // ECT(1) (ECN-Capable Transport(1))
|
|
||||||
ECNTransport0 = 0x02 // ECT(0) (ECN-Capable Transport(0))
|
|
||||||
CongestionExperienced = 0x03 // CE (Congestion Experienced)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Protocol Numbers, Updated: 2017-10-13
|
|
||||||
const (
|
|
||||||
ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number
|
|
||||||
ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option
|
|
||||||
ProtocolICMP = 1 // Internet Control Message
|
|
||||||
ProtocolIGMP = 2 // Internet Group Management
|
|
||||||
ProtocolGGP = 3 // Gateway-to-Gateway
|
|
||||||
ProtocolIPv4 = 4 // IPv4 encapsulation
|
|
||||||
ProtocolST = 5 // Stream
|
|
||||||
ProtocolTCP = 6 // Transmission Control
|
|
||||||
ProtocolCBT = 7 // CBT
|
|
||||||
ProtocolEGP = 8 // Exterior Gateway Protocol
|
|
||||||
ProtocolIGP = 9 // any private interior gateway (used by Cisco for their IGRP)
|
|
||||||
ProtocolBBNRCCMON = 10 // BBN RCC Monitoring
|
|
||||||
ProtocolNVPII = 11 // Network Voice Protocol
|
|
||||||
ProtocolPUP = 12 // PUP
|
|
||||||
ProtocolEMCON = 14 // EMCON
|
|
||||||
ProtocolXNET = 15 // Cross Net Debugger
|
|
||||||
ProtocolCHAOS = 16 // Chaos
|
|
||||||
ProtocolUDP = 17 // User Datagram
|
|
||||||
ProtocolMUX = 18 // Multiplexing
|
|
||||||
ProtocolDCNMEAS = 19 // DCN Measurement Subsystems
|
|
||||||
ProtocolHMP = 20 // Host Monitoring
|
|
||||||
ProtocolPRM = 21 // Packet Radio Measurement
|
|
||||||
ProtocolXNSIDP = 22 // XEROX NS IDP
|
|
||||||
ProtocolTRUNK1 = 23 // Trunk-1
|
|
||||||
ProtocolTRUNK2 = 24 // Trunk-2
|
|
||||||
ProtocolLEAF1 = 25 // Leaf-1
|
|
||||||
ProtocolLEAF2 = 26 // Leaf-2
|
|
||||||
ProtocolRDP = 27 // Reliable Data Protocol
|
|
||||||
ProtocolIRTP = 28 // Internet Reliable Transaction
|
|
||||||
ProtocolISOTP4 = 29 // ISO Transport Protocol Class 4
|
|
||||||
ProtocolNETBLT = 30 // Bulk Data Transfer Protocol
|
|
||||||
ProtocolMFENSP = 31 // MFE Network Services Protocol
|
|
||||||
ProtocolMERITINP = 32 // MERIT Internodal Protocol
|
|
||||||
ProtocolDCCP = 33 // Datagram Congestion Control Protocol
|
|
||||||
Protocol3PC = 34 // Third Party Connect Protocol
|
|
||||||
ProtocolIDPR = 35 // Inter-Domain Policy Routing Protocol
|
|
||||||
ProtocolXTP = 36 // XTP
|
|
||||||
ProtocolDDP = 37 // Datagram Delivery Protocol
|
|
||||||
ProtocolIDPRCMTP = 38 // IDPR Control Message Transport Proto
|
|
||||||
ProtocolTPPP = 39 // TP++ Transport Protocol
|
|
||||||
ProtocolIL = 40 // IL Transport Protocol
|
|
||||||
ProtocolIPv6 = 41 // IPv6 encapsulation
|
|
||||||
ProtocolSDRP = 42 // Source Demand Routing Protocol
|
|
||||||
ProtocolIPv6Route = 43 // Routing Header for IPv6
|
|
||||||
ProtocolIPv6Frag = 44 // Fragment Header for IPv6
|
|
||||||
ProtocolIDRP = 45 // Inter-Domain Routing Protocol
|
|
||||||
ProtocolRSVP = 46 // Reservation Protocol
|
|
||||||
ProtocolGRE = 47 // Generic Routing Encapsulation
|
|
||||||
ProtocolDSR = 48 // Dynamic Source Routing Protocol
|
|
||||||
ProtocolBNA = 49 // BNA
|
|
||||||
ProtocolESP = 50 // Encap Security Payload
|
|
||||||
ProtocolAH = 51 // Authentication Header
|
|
||||||
ProtocolINLSP = 52 // Integrated Net Layer Security TUBA
|
|
||||||
ProtocolNARP = 54 // NBMA Address Resolution Protocol
|
|
||||||
ProtocolMOBILE = 55 // IP Mobility
|
|
||||||
ProtocolTLSP = 56 // Transport Layer Security Protocol using Kryptonet key management
|
|
||||||
ProtocolSKIP = 57 // SKIP
|
|
||||||
ProtocolIPv6ICMP = 58 // ICMP for IPv6
|
|
||||||
ProtocolIPv6NoNxt = 59 // No Next Header for IPv6
|
|
||||||
ProtocolIPv6Opts = 60 // Destination Options for IPv6
|
|
||||||
ProtocolCFTP = 62 // CFTP
|
|
||||||
ProtocolSATEXPAK = 64 // SATNET and Backroom EXPAK
|
|
||||||
ProtocolKRYPTOLAN = 65 // Kryptolan
|
|
||||||
ProtocolRVD = 66 // MIT Remote Virtual Disk Protocol
|
|
||||||
ProtocolIPPC = 67 // Internet Pluribus Packet Core
|
|
||||||
ProtocolSATMON = 69 // SATNET Monitoring
|
|
||||||
ProtocolVISA = 70 // VISA Protocol
|
|
||||||
ProtocolIPCV = 71 // Internet Packet Core Utility
|
|
||||||
ProtocolCPNX = 72 // Computer Protocol Network Executive
|
|
||||||
ProtocolCPHB = 73 // Computer Protocol Heart Beat
|
|
||||||
ProtocolWSN = 74 // Wang Span Network
|
|
||||||
ProtocolPVP = 75 // Packet Video Protocol
|
|
||||||
ProtocolBRSATMON = 76 // Backroom SATNET Monitoring
|
|
||||||
ProtocolSUNND = 77 // SUN ND PROTOCOL-Temporary
|
|
||||||
ProtocolWBMON = 78 // WIDEBAND Monitoring
|
|
||||||
ProtocolWBEXPAK = 79 // WIDEBAND EXPAK
|
|
||||||
ProtocolISOIP = 80 // ISO Internet Protocol
|
|
||||||
ProtocolVMTP = 81 // VMTP
|
|
||||||
ProtocolSECUREVMTP = 82 // SECURE-VMTP
|
|
||||||
ProtocolVINES = 83 // VINES
|
|
||||||
ProtocolTTP = 84 // Transaction Transport Protocol
|
|
||||||
ProtocolIPTM = 84 // Internet Protocol Traffic Manager
|
|
||||||
ProtocolNSFNETIGP = 85 // NSFNET-IGP
|
|
||||||
ProtocolDGP = 86 // Dissimilar Gateway Protocol
|
|
||||||
ProtocolTCF = 87 // TCF
|
|
||||||
ProtocolEIGRP = 88 // EIGRP
|
|
||||||
ProtocolOSPFIGP = 89 // OSPFIGP
|
|
||||||
ProtocolSpriteRPC = 90 // Sprite RPC Protocol
|
|
||||||
ProtocolLARP = 91 // Locus Address Resolution Protocol
|
|
||||||
ProtocolMTP = 92 // Multicast Transport Protocol
|
|
||||||
ProtocolAX25 = 93 // AX.25 Frames
|
|
||||||
ProtocolIPIP = 94 // IP-within-IP Encapsulation Protocol
|
|
||||||
ProtocolSCCSP = 96 // Semaphore Communications Sec. Pro.
|
|
||||||
ProtocolETHERIP = 97 // Ethernet-within-IP Encapsulation
|
|
||||||
ProtocolENCAP = 98 // Encapsulation Header
|
|
||||||
ProtocolGMTP = 100 // GMTP
|
|
||||||
ProtocolIFMP = 101 // Ipsilon Flow Management Protocol
|
|
||||||
ProtocolPNNI = 102 // PNNI over IP
|
|
||||||
ProtocolPIM = 103 // Protocol Independent Multicast
|
|
||||||
ProtocolARIS = 104 // ARIS
|
|
||||||
ProtocolSCPS = 105 // SCPS
|
|
||||||
ProtocolQNX = 106 // QNX
|
|
||||||
ProtocolAN = 107 // Active Networks
|
|
||||||
ProtocolIPComp = 108 // IP Payload Compression Protocol
|
|
||||||
ProtocolSNP = 109 // Sitara Networks Protocol
|
|
||||||
ProtocolCompaqPeer = 110 // Compaq Peer Protocol
|
|
||||||
ProtocolIPXinIP = 111 // IPX in IP
|
|
||||||
ProtocolVRRP = 112 // Virtual Router Redundancy Protocol
|
|
||||||
ProtocolPGM = 113 // PGM Reliable Transport Protocol
|
|
||||||
ProtocolL2TP = 115 // Layer Two Tunneling Protocol
|
|
||||||
ProtocolDDX = 116 // D-II Data Exchange (DDX)
|
|
||||||
ProtocolIATP = 117 // Interactive Agent Transfer Protocol
|
|
||||||
ProtocolSTP = 118 // Schedule Transfer Protocol
|
|
||||||
ProtocolSRP = 119 // SpectraLink Radio Protocol
|
|
||||||
ProtocolUTI = 120 // UTI
|
|
||||||
ProtocolSMP = 121 // Simple Message Protocol
|
|
||||||
ProtocolPTP = 123 // Performance Transparency Protocol
|
|
||||||
ProtocolISIS = 124 // ISIS over IPv4
|
|
||||||
ProtocolFIRE = 125 // FIRE
|
|
||||||
ProtocolCRTP = 126 // Combat Radio Transport Protocol
|
|
||||||
ProtocolCRUDP = 127 // Combat Radio User Datagram
|
|
||||||
ProtocolSSCOPMCE = 128 // SSCOPMCE
|
|
||||||
ProtocolIPLT = 129 // IPLT
|
|
||||||
ProtocolSPS = 130 // Secure Packet Shield
|
|
||||||
ProtocolPIPE = 131 // Private IP Encapsulation within IP
|
|
||||||
ProtocolSCTP = 132 // Stream Control Transmission Protocol
|
|
||||||
ProtocolFC = 133 // Fibre Channel
|
|
||||||
ProtocolRSVPE2EIGNORE = 134 // RSVP-E2E-IGNORE
|
|
||||||
ProtocolMobilityHeader = 135 // Mobility Header
|
|
||||||
ProtocolUDPLite = 136 // UDPLite
|
|
||||||
ProtocolMPLSinIP = 137 // MPLS-in-IP
|
|
||||||
ProtocolMANET = 138 // MANET Protocols
|
|
||||||
ProtocolHIP = 139 // Host Identity Protocol
|
|
||||||
ProtocolShim6 = 140 // Shim6 Protocol
|
|
||||||
ProtocolWESP = 141 // Wrapped Encapsulating Security Payload
|
|
||||||
ProtocolROHC = 142 // Robust Header Compression
|
|
||||||
ProtocolReserved = 255 // Reserved
|
|
||||||
)
|
|
||||||
|
|
||||||
// Address Family Numbers, Updated: 2018-04-02
|
|
||||||
const (
|
|
||||||
AddrFamilyIPv4 = 1 // IP (IP version 4)
|
|
||||||
AddrFamilyIPv6 = 2 // IP6 (IP version 6)
|
|
||||||
AddrFamilyNSAP = 3 // NSAP
|
|
||||||
AddrFamilyHDLC = 4 // HDLC (8-bit multidrop)
|
|
||||||
AddrFamilyBBN1822 = 5 // BBN 1822
|
|
||||||
AddrFamily802 = 6 // 802 (includes all 802 media plus Ethernet "canonical format")
|
|
||||||
AddrFamilyE163 = 7 // E.163
|
|
||||||
AddrFamilyE164 = 8 // E.164 (SMDS, Frame Relay, ATM)
|
|
||||||
AddrFamilyF69 = 9 // F.69 (Telex)
|
|
||||||
AddrFamilyX121 = 10 // X.121 (X.25, Frame Relay)
|
|
||||||
AddrFamilyIPX = 11 // IPX
|
|
||||||
AddrFamilyAppletalk = 12 // Appletalk
|
|
||||||
AddrFamilyDecnetIV = 13 // Decnet IV
|
|
||||||
AddrFamilyBanyanVines = 14 // Banyan Vines
|
|
||||||
AddrFamilyE164withSubaddress = 15 // E.164 with NSAP format subaddress
|
|
||||||
AddrFamilyDNS = 16 // DNS (Domain Name System)
|
|
||||||
AddrFamilyDistinguishedName = 17 // Distinguished Name
|
|
||||||
AddrFamilyASNumber = 18 // AS Number
|
|
||||||
AddrFamilyXTPoverIPv4 = 19 // XTP over IP version 4
|
|
||||||
AddrFamilyXTPoverIPv6 = 20 // XTP over IP version 6
|
|
||||||
AddrFamilyXTPnativemodeXTP = 21 // XTP native mode XTP
|
|
||||||
AddrFamilyFibreChannelWorldWidePortName = 22 // Fibre Channel World-Wide Port Name
|
|
||||||
AddrFamilyFibreChannelWorldWideNodeName = 23 // Fibre Channel World-Wide Node Name
|
|
||||||
AddrFamilyGWID = 24 // GWID
|
|
||||||
AddrFamilyL2VPN = 25 // AFI for L2VPN information
|
|
||||||
AddrFamilyMPLSTPSectionEndpointID = 26 // MPLS-TP Section Endpoint Identifier
|
|
||||||
AddrFamilyMPLSTPLSPEndpointID = 27 // MPLS-TP LSP Endpoint Identifier
|
|
||||||
AddrFamilyMPLSTPPseudowireEndpointID = 28 // MPLS-TP Pseudowire Endpoint Identifier
|
|
||||||
AddrFamilyMTIPv4 = 29 // MT IP: Multi-Topology IP version 4
|
|
||||||
AddrFamilyMTIPv6 = 30 // MT IPv6: Multi-Topology IP version 6
|
|
||||||
AddrFamilyEIGRPCommonServiceFamily = 16384 // EIGRP Common Service Family
|
|
||||||
AddrFamilyEIGRPIPv4ServiceFamily = 16385 // EIGRP IPv4 Service Family
|
|
||||||
AddrFamilyEIGRPIPv6ServiceFamily = 16386 // EIGRP IPv6 Service Family
|
|
||||||
AddrFamilyLISPCanonicalAddressFormat = 16387 // LISP Canonical Address Format (LCAF)
|
|
||||||
AddrFamilyBGPLS = 16388 // BGP-LS
|
|
||||||
AddrFamily48bitMAC = 16389 // 48-bit MAC
|
|
||||||
AddrFamily64bitMAC = 16390 // 64-bit MAC
|
|
||||||
AddrFamilyOUI = 16391 // OUI
|
|
||||||
AddrFamilyMACFinal24bits = 16392 // MAC/24
|
|
||||||
AddrFamilyMACFinal40bits = 16393 // MAC/40
|
|
||||||
AddrFamilyIPv6Initial64bits = 16394 // IPv6/64
|
|
||||||
AddrFamilyRBridgePortID = 16395 // RBridge Port ID
|
|
||||||
AddrFamilyTRILLNickname = 16396 // TRILL Nickname
|
|
||||||
)
|
|
|
@ -1,383 +0,0 @@
|
||||||
// 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 ignore
|
|
||||||
|
|
||||||
//go:generate go run gen.go
|
|
||||||
|
|
||||||
// This program generates internet protocol constants and tables by
|
|
||||||
// reading IANA protocol registries.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/xml"
|
|
||||||
"fmt"
|
|
||||||
"go/format"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var registries = []struct {
|
|
||||||
url string
|
|
||||||
parse func(io.Writer, io.Reader) error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"https://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
|
|
||||||
parseDSCPRegistry,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
|
|
||||||
parseProtocolNumbers,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml",
|
|
||||||
parseAddrFamilyNumbers,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var bb bytes.Buffer
|
|
||||||
fmt.Fprintf(&bb, "// go generate gen.go\n")
|
|
||||||
fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
|
|
||||||
fmt.Fprintf(&bb, "// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).\n")
|
|
||||||
fmt.Fprintf(&bb, `package iana // import "golang.org/x/net/internal/iana"`+"\n\n")
|
|
||||||
for _, r := range registries {
|
|
||||||
resp, err := http.Get(r.url)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if err := r.parse(&bb, resp.Body); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(&bb, "\n")
|
|
||||||
}
|
|
||||||
b, err := format.Source(bb.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if err := ioutil.WriteFile("const.go", b, 0644); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseDSCPRegistry(w io.Writer, r io.Reader) error {
|
|
||||||
dec := xml.NewDecoder(r)
|
|
||||||
var dr dscpRegistry
|
|
||||||
if err := dec.Decode(&dr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated)
|
|
||||||
fmt.Fprintf(w, "const (\n")
|
|
||||||
for _, dr := range dr.escapeDSCP() {
|
|
||||||
fmt.Fprintf(w, "DiffServ%s = %#02x", dr.Name, dr.Value)
|
|
||||||
fmt.Fprintf(w, "// %s\n", dr.OrigName)
|
|
||||||
}
|
|
||||||
for _, er := range dr.escapeECN() {
|
|
||||||
fmt.Fprintf(w, "%s = %#02x", er.Descr, er.Value)
|
|
||||||
fmt.Fprintf(w, "// %s\n", er.OrigDescr)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, ")\n")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type dscpRegistry struct {
|
|
||||||
XMLName xml.Name `xml:"registry"`
|
|
||||||
Title string `xml:"title"`
|
|
||||||
Updated string `xml:"updated"`
|
|
||||||
Note string `xml:"note"`
|
|
||||||
Registries []struct {
|
|
||||||
Title string `xml:"title"`
|
|
||||||
Registries []struct {
|
|
||||||
Title string `xml:"title"`
|
|
||||||
Records []struct {
|
|
||||||
Name string `xml:"name"`
|
|
||||||
Space string `xml:"space"`
|
|
||||||
} `xml:"record"`
|
|
||||||
} `xml:"registry"`
|
|
||||||
Records []struct {
|
|
||||||
Value string `xml:"value"`
|
|
||||||
Descr string `xml:"description"`
|
|
||||||
} `xml:"record"`
|
|
||||||
} `xml:"registry"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type canonDSCPRecord struct {
|
|
||||||
OrigName string
|
|
||||||
Name string
|
|
||||||
Value int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (drr *dscpRegistry) escapeDSCP() []canonDSCPRecord {
|
|
||||||
var drs []canonDSCPRecord
|
|
||||||
for _, preg := range drr.Registries {
|
|
||||||
if !strings.Contains(preg.Title, "Differentiated Services Field Codepoints") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, reg := range preg.Registries {
|
|
||||||
if !strings.Contains(reg.Title, "Pool 1 Codepoints") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
drs = make([]canonDSCPRecord, len(reg.Records))
|
|
||||||
sr := strings.NewReplacer(
|
|
||||||
"+", "",
|
|
||||||
"-", "",
|
|
||||||
"/", "",
|
|
||||||
".", "",
|
|
||||||
" ", "",
|
|
||||||
)
|
|
||||||
for i, dr := range reg.Records {
|
|
||||||
s := strings.TrimSpace(dr.Name)
|
|
||||||
drs[i].OrigName = s
|
|
||||||
drs[i].Name = sr.Replace(s)
|
|
||||||
n, err := strconv.ParseUint(dr.Space, 2, 8)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
drs[i].Value = int(n) << 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return drs
|
|
||||||
}
|
|
||||||
|
|
||||||
type canonECNRecord struct {
|
|
||||||
OrigDescr string
|
|
||||||
Descr string
|
|
||||||
Value int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (drr *dscpRegistry) escapeECN() []canonECNRecord {
|
|
||||||
var ers []canonECNRecord
|
|
||||||
for _, reg := range drr.Registries {
|
|
||||||
if !strings.Contains(reg.Title, "ECN Field") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ers = make([]canonECNRecord, len(reg.Records))
|
|
||||||
sr := strings.NewReplacer(
|
|
||||||
"Capable", "",
|
|
||||||
"Not-ECT", "",
|
|
||||||
"ECT(1)", "",
|
|
||||||
"ECT(0)", "",
|
|
||||||
"CE", "",
|
|
||||||
"(", "",
|
|
||||||
")", "",
|
|
||||||
"+", "",
|
|
||||||
"-", "",
|
|
||||||
"/", "",
|
|
||||||
".", "",
|
|
||||||
" ", "",
|
|
||||||
)
|
|
||||||
for i, er := range reg.Records {
|
|
||||||
s := strings.TrimSpace(er.Descr)
|
|
||||||
ers[i].OrigDescr = s
|
|
||||||
ss := strings.Split(s, " ")
|
|
||||||
if len(ss) > 1 {
|
|
||||||
ers[i].Descr = strings.Join(ss[1:], " ")
|
|
||||||
} else {
|
|
||||||
ers[i].Descr = ss[0]
|
|
||||||
}
|
|
||||||
ers[i].Descr = sr.Replace(er.Descr)
|
|
||||||
n, err := strconv.ParseUint(er.Value, 2, 8)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ers[i].Value = int(n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ers
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseProtocolNumbers(w io.Writer, r io.Reader) error {
|
|
||||||
dec := xml.NewDecoder(r)
|
|
||||||
var pn protocolNumbers
|
|
||||||
if err := dec.Decode(&pn); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
prs := pn.escape()
|
|
||||||
prs = append([]canonProtocolRecord{{
|
|
||||||
Name: "IP",
|
|
||||||
Descr: "IPv4 encapsulation, pseudo protocol number",
|
|
||||||
Value: 0,
|
|
||||||
}}, prs...)
|
|
||||||
fmt.Fprintf(w, "// %s, Updated: %s\n", pn.Title, pn.Updated)
|
|
||||||
fmt.Fprintf(w, "const (\n")
|
|
||||||
for _, pr := range prs {
|
|
||||||
if pr.Name == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "Protocol%s = %d", pr.Name, pr.Value)
|
|
||||||
s := pr.Descr
|
|
||||||
if s == "" {
|
|
||||||
s = pr.OrigName
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "// %s\n", s)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, ")\n")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type protocolNumbers struct {
|
|
||||||
XMLName xml.Name `xml:"registry"`
|
|
||||||
Title string `xml:"title"`
|
|
||||||
Updated string `xml:"updated"`
|
|
||||||
RegTitle string `xml:"registry>title"`
|
|
||||||
Note string `xml:"registry>note"`
|
|
||||||
Records []struct {
|
|
||||||
Value string `xml:"value"`
|
|
||||||
Name string `xml:"name"`
|
|
||||||
Descr string `xml:"description"`
|
|
||||||
} `xml:"registry>record"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type canonProtocolRecord struct {
|
|
||||||
OrigName string
|
|
||||||
Name string
|
|
||||||
Descr string
|
|
||||||
Value int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pn *protocolNumbers) escape() []canonProtocolRecord {
|
|
||||||
prs := make([]canonProtocolRecord, len(pn.Records))
|
|
||||||
sr := strings.NewReplacer(
|
|
||||||
"-in-", "in",
|
|
||||||
"-within-", "within",
|
|
||||||
"-over-", "over",
|
|
||||||
"+", "P",
|
|
||||||
"-", "",
|
|
||||||
"/", "",
|
|
||||||
".", "",
|
|
||||||
" ", "",
|
|
||||||
)
|
|
||||||
for i, pr := range pn.Records {
|
|
||||||
if strings.Contains(pr.Name, "Deprecated") ||
|
|
||||||
strings.Contains(pr.Name, "deprecated") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
prs[i].OrigName = pr.Name
|
|
||||||
s := strings.TrimSpace(pr.Name)
|
|
||||||
switch pr.Name {
|
|
||||||
case "ISIS over IPv4":
|
|
||||||
prs[i].Name = "ISIS"
|
|
||||||
case "manet":
|
|
||||||
prs[i].Name = "MANET"
|
|
||||||
default:
|
|
||||||
prs[i].Name = sr.Replace(s)
|
|
||||||
}
|
|
||||||
ss := strings.Split(pr.Descr, "\n")
|
|
||||||
for i := range ss {
|
|
||||||
ss[i] = strings.TrimSpace(ss[i])
|
|
||||||
}
|
|
||||||
if len(ss) > 1 {
|
|
||||||
prs[i].Descr = strings.Join(ss, " ")
|
|
||||||
} else {
|
|
||||||
prs[i].Descr = ss[0]
|
|
||||||
}
|
|
||||||
prs[i].Value, _ = strconv.Atoi(pr.Value)
|
|
||||||
}
|
|
||||||
return prs
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseAddrFamilyNumbers(w io.Writer, r io.Reader) error {
|
|
||||||
dec := xml.NewDecoder(r)
|
|
||||||
var afn addrFamilylNumbers
|
|
||||||
if err := dec.Decode(&afn); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
afrs := afn.escape()
|
|
||||||
fmt.Fprintf(w, "// %s, Updated: %s\n", afn.Title, afn.Updated)
|
|
||||||
fmt.Fprintf(w, "const (\n")
|
|
||||||
for _, afr := range afrs {
|
|
||||||
if afr.Name == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "AddrFamily%s = %d", afr.Name, afr.Value)
|
|
||||||
fmt.Fprintf(w, "// %s\n", afr.Descr)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, ")\n")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type addrFamilylNumbers struct {
|
|
||||||
XMLName xml.Name `xml:"registry"`
|
|
||||||
Title string `xml:"title"`
|
|
||||||
Updated string `xml:"updated"`
|
|
||||||
RegTitle string `xml:"registry>title"`
|
|
||||||
Note string `xml:"registry>note"`
|
|
||||||
Records []struct {
|
|
||||||
Value string `xml:"value"`
|
|
||||||
Descr string `xml:"description"`
|
|
||||||
} `xml:"registry>record"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type canonAddrFamilyRecord struct {
|
|
||||||
Name string
|
|
||||||
Descr string
|
|
||||||
Value int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (afn *addrFamilylNumbers) escape() []canonAddrFamilyRecord {
|
|
||||||
afrs := make([]canonAddrFamilyRecord, len(afn.Records))
|
|
||||||
sr := strings.NewReplacer(
|
|
||||||
"IP version 4", "IPv4",
|
|
||||||
"IP version 6", "IPv6",
|
|
||||||
"Identifier", "ID",
|
|
||||||
"-", "",
|
|
||||||
"-", "",
|
|
||||||
"/", "",
|
|
||||||
".", "",
|
|
||||||
" ", "",
|
|
||||||
)
|
|
||||||
for i, afr := range afn.Records {
|
|
||||||
if strings.Contains(afr.Descr, "Unassigned") ||
|
|
||||||
strings.Contains(afr.Descr, "Reserved") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
afrs[i].Descr = afr.Descr
|
|
||||||
s := strings.TrimSpace(afr.Descr)
|
|
||||||
switch s {
|
|
||||||
case "IP (IP version 4)":
|
|
||||||
afrs[i].Name = "IPv4"
|
|
||||||
case "IP6 (IP version 6)":
|
|
||||||
afrs[i].Name = "IPv6"
|
|
||||||
case "AFI for L2VPN information":
|
|
||||||
afrs[i].Name = "L2VPN"
|
|
||||||
case "E.164 with NSAP format subaddress":
|
|
||||||
afrs[i].Name = "E164withSubaddress"
|
|
||||||
case "MT IP: Multi-Topology IP version 4":
|
|
||||||
afrs[i].Name = "MTIPv4"
|
|
||||||
case "MAC/24":
|
|
||||||
afrs[i].Name = "MACFinal24bits"
|
|
||||||
case "MAC/40":
|
|
||||||
afrs[i].Name = "MACFinal40bits"
|
|
||||||
case "IPv6/64":
|
|
||||||
afrs[i].Name = "IPv6Initial64bits"
|
|
||||||
default:
|
|
||||||
n := strings.Index(s, "(")
|
|
||||||
if n > 0 {
|
|
||||||
s = s[:n]
|
|
||||||
}
|
|
||||||
n = strings.Index(s, ":")
|
|
||||||
if n > 0 {
|
|
||||||
s = s[:n]
|
|
||||||
}
|
|
||||||
afrs[i].Name = sr.Replace(s)
|
|
||||||
}
|
|
||||||
afrs[i].Value, _ = strconv.Atoi(afr.Value)
|
|
||||||
}
|
|
||||||
return afrs
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
func (h *cmsghdr) len() int { return int(h.Len) }
|
|
||||||
func (h *cmsghdr) lvl() int { return int(h.Level) }
|
|
||||||
func (h *cmsghdr) typ() int { return int(h.Type) }
|
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
func (h *cmsghdr) set(l, lvl, typ int) {
|
|
||||||
h.Len = uint32(l)
|
|
||||||
h.Level = int32(lvl)
|
|
||||||
h.Type = int32(typ)
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright 2017 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 amd64
|
|
||||||
// +build solaris
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
func (h *cmsghdr) set(l, lvl, typ int) {
|
|
||||||
h.Len = uint32(l)
|
|
||||||
h.Level = int32(lvl)
|
|
||||||
h.Type = int32(typ)
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright 2017 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 ignore
|
|
||||||
|
|
||||||
// +godefs map struct_in_addr [4]byte /* in_addr */
|
|
||||||
// +godefs map struct_in6_addr [16]byte /* in6_addr */
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysAF_UNSPEC = C.AF_UNSPEC
|
|
||||||
sysAF_INET = C.AF_INET
|
|
||||||
sysAF_INET6 = C.AF_INET6
|
|
||||||
|
|
||||||
sysSOCK_RAW = C.SOCK_RAW
|
|
||||||
)
|
|
||||||
|
|
||||||
type iovec C.struct_iovec
|
|
||||||
|
|
||||||
type msghdr C.struct_msghdr
|
|
||||||
|
|
||||||
type cmsghdr C.struct_cmsghdr
|
|
||||||
|
|
||||||
type sockaddrInet C.struct_sockaddr_in
|
|
||||||
|
|
||||||
type sockaddrInet6 C.struct_sockaddr_in6
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofIovec = C.sizeof_struct_iovec
|
|
||||||
sizeofMsghdr = C.sizeof_struct_msghdr
|
|
||||||
sizeofCmsghdr = C.sizeof_struct_cmsghdr
|
|
||||||
|
|
||||||
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
|
|
||||||
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
|
|
||||||
)
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright 2017 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 ignore
|
|
||||||
|
|
||||||
// +godefs map struct_in_addr [4]byte /* in_addr */
|
|
||||||
// +godefs map struct_in6_addr [16]byte /* in6_addr */
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysAF_UNSPEC = C.AF_UNSPEC
|
|
||||||
sysAF_INET = C.AF_INET
|
|
||||||
sysAF_INET6 = C.AF_INET6
|
|
||||||
|
|
||||||
sysSOCK_RAW = C.SOCK_RAW
|
|
||||||
)
|
|
||||||
|
|
||||||
type iovec C.struct_iovec
|
|
||||||
|
|
||||||
type msghdr C.struct_msghdr
|
|
||||||
|
|
||||||
type cmsghdr C.struct_cmsghdr
|
|
||||||
|
|
||||||
type sockaddrInet C.struct_sockaddr_in
|
|
||||||
|
|
||||||
type sockaddrInet6 C.struct_sockaddr_in6
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofIovec = C.sizeof_struct_iovec
|
|
||||||
sizeofMsghdr = C.sizeof_struct_msghdr
|
|
||||||
sizeofCmsghdr = C.sizeof_struct_cmsghdr
|
|
||||||
|
|
||||||
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
|
|
||||||
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
|
|
||||||
)
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright 2017 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 ignore
|
|
||||||
|
|
||||||
// +godefs map struct_in_addr [4]byte /* in_addr */
|
|
||||||
// +godefs map struct_in6_addr [16]byte /* in6_addr */
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysAF_UNSPEC = C.AF_UNSPEC
|
|
||||||
sysAF_INET = C.AF_INET
|
|
||||||
sysAF_INET6 = C.AF_INET6
|
|
||||||
|
|
||||||
sysSOCK_RAW = C.SOCK_RAW
|
|
||||||
)
|
|
||||||
|
|
||||||
type iovec C.struct_iovec
|
|
||||||
|
|
||||||
type msghdr C.struct_msghdr
|
|
||||||
|
|
||||||
type cmsghdr C.struct_cmsghdr
|
|
||||||
|
|
||||||
type sockaddrInet C.struct_sockaddr_in
|
|
||||||
|
|
||||||
type sockaddrInet6 C.struct_sockaddr_in6
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofIovec = C.sizeof_struct_iovec
|
|
||||||
sizeofMsghdr = C.sizeof_struct_msghdr
|
|
||||||
sizeofCmsghdr = C.sizeof_struct_cmsghdr
|
|
||||||
|
|
||||||
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
|
|
||||||
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
|
|
||||||
)
|
|
|
@ -1,49 +0,0 @@
|
||||||
// Copyright 2017 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 ignore
|
|
||||||
|
|
||||||
// +godefs map struct_in_addr [4]byte /* in_addr */
|
|
||||||
// +godefs map struct_in6_addr [16]byte /* in6_addr */
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <linux/in.h>
|
|
||||||
#include <linux/in6.h>
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <sys/socket.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysAF_UNSPEC = C.AF_UNSPEC
|
|
||||||
sysAF_INET = C.AF_INET
|
|
||||||
sysAF_INET6 = C.AF_INET6
|
|
||||||
|
|
||||||
sysSOCK_RAW = C.SOCK_RAW
|
|
||||||
)
|
|
||||||
|
|
||||||
type iovec C.struct_iovec
|
|
||||||
|
|
||||||
type msghdr C.struct_msghdr
|
|
||||||
|
|
||||||
type mmsghdr C.struct_mmsghdr
|
|
||||||
|
|
||||||
type cmsghdr C.struct_cmsghdr
|
|
||||||
|
|
||||||
type sockaddrInet C.struct_sockaddr_in
|
|
||||||
|
|
||||||
type sockaddrInet6 C.struct_sockaddr_in6
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofIovec = C.sizeof_struct_iovec
|
|
||||||
sizeofMsghdr = C.sizeof_struct_msghdr
|
|
||||||
sizeofMmsghdr = C.sizeof_struct_mmsghdr
|
|
||||||
sizeofCmsghdr = C.sizeof_struct_cmsghdr
|
|
||||||
|
|
||||||
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
|
|
||||||
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
|
|
||||||
)
|
|
|
@ -1,47 +0,0 @@
|
||||||
// Copyright 2017 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 ignore
|
|
||||||
|
|
||||||
// +godefs map struct_in_addr [4]byte /* in_addr */
|
|
||||||
// +godefs map struct_in6_addr [16]byte /* in6_addr */
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysAF_UNSPEC = C.AF_UNSPEC
|
|
||||||
sysAF_INET = C.AF_INET
|
|
||||||
sysAF_INET6 = C.AF_INET6
|
|
||||||
|
|
||||||
sysSOCK_RAW = C.SOCK_RAW
|
|
||||||
)
|
|
||||||
|
|
||||||
type iovec C.struct_iovec
|
|
||||||
|
|
||||||
type msghdr C.struct_msghdr
|
|
||||||
|
|
||||||
type mmsghdr C.struct_mmsghdr
|
|
||||||
|
|
||||||
type cmsghdr C.struct_cmsghdr
|
|
||||||
|
|
||||||
type sockaddrInet C.struct_sockaddr_in
|
|
||||||
|
|
||||||
type sockaddrInet6 C.struct_sockaddr_in6
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofIovec = C.sizeof_struct_iovec
|
|
||||||
sizeofMsghdr = C.sizeof_struct_msghdr
|
|
||||||
sizeofMmsghdr = C.sizeof_struct_mmsghdr
|
|
||||||
sizeofCmsghdr = C.sizeof_struct_cmsghdr
|
|
||||||
|
|
||||||
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
|
|
||||||
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
|
|
||||||
)
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright 2017 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 ignore
|
|
||||||
|
|
||||||
// +godefs map struct_in_addr [4]byte /* in_addr */
|
|
||||||
// +godefs map struct_in6_addr [16]byte /* in6_addr */
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysAF_UNSPEC = C.AF_UNSPEC
|
|
||||||
sysAF_INET = C.AF_INET
|
|
||||||
sysAF_INET6 = C.AF_INET6
|
|
||||||
|
|
||||||
sysSOCK_RAW = C.SOCK_RAW
|
|
||||||
)
|
|
||||||
|
|
||||||
type iovec C.struct_iovec
|
|
||||||
|
|
||||||
type msghdr C.struct_msghdr
|
|
||||||
|
|
||||||
type cmsghdr C.struct_cmsghdr
|
|
||||||
|
|
||||||
type sockaddrInet C.struct_sockaddr_in
|
|
||||||
|
|
||||||
type sockaddrInet6 C.struct_sockaddr_in6
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofIovec = C.sizeof_struct_iovec
|
|
||||||
sizeofMsghdr = C.sizeof_struct_msghdr
|
|
||||||
sizeofCmsghdr = C.sizeof_struct_cmsghdr
|
|
||||||
|
|
||||||
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
|
|
||||||
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
|
|
||||||
)
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright 2017 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 ignore
|
|
||||||
|
|
||||||
// +godefs map struct_in_addr [4]byte /* in_addr */
|
|
||||||
// +godefs map struct_in6_addr [16]byte /* in6_addr */
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysAF_UNSPEC = C.AF_UNSPEC
|
|
||||||
sysAF_INET = C.AF_INET
|
|
||||||
sysAF_INET6 = C.AF_INET6
|
|
||||||
|
|
||||||
sysSOCK_RAW = C.SOCK_RAW
|
|
||||||
)
|
|
||||||
|
|
||||||
type iovec C.struct_iovec
|
|
||||||
|
|
||||||
type msghdr C.struct_msghdr
|
|
||||||
|
|
||||||
type cmsghdr C.struct_cmsghdr
|
|
||||||
|
|
||||||
type sockaddrInet C.struct_sockaddr_in
|
|
||||||
|
|
||||||
type sockaddrInet6 C.struct_sockaddr_in6
|
|
||||||
|
|
||||||
const (
|
|
||||||
sizeofIovec = C.sizeof_struct_iovec
|
|
||||||
sizeofMsghdr = C.sizeof_struct_msghdr
|
|
||||||
sizeofCmsghdr = C.sizeof_struct_cmsghdr
|
|
||||||
|
|
||||||
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
|
|
||||||
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
|
|
||||||
)
|
|
|
@ -1,31 +0,0 @@
|
||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
var (
|
|
||||||
errEAGAIN error = syscall.EAGAIN
|
|
||||||
errEINVAL error = syscall.EINVAL
|
|
||||||
errENOENT error = syscall.ENOENT
|
|
||||||
)
|
|
||||||
|
|
||||||
// errnoErr returns common boxed Errno values, to prevent allocations
|
|
||||||
// at runtime.
|
|
||||||
func errnoErr(errno syscall.Errno) error {
|
|
||||||
switch errno {
|
|
||||||
case 0:
|
|
||||||
return nil
|
|
||||||
case syscall.EAGAIN:
|
|
||||||
return errEAGAIN
|
|
||||||
case syscall.EINVAL:
|
|
||||||
return errEINVAL
|
|
||||||
case syscall.ENOENT:
|
|
||||||
return errENOENT
|
|
||||||
}
|
|
||||||
return errno
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
var (
|
|
||||||
errERROR_IO_PENDING error = syscall.ERROR_IO_PENDING
|
|
||||||
errEINVAL error = syscall.EINVAL
|
|
||||||
)
|
|
||||||
|
|
||||||
// errnoErr returns common boxed Errno values, to prevent allocations
|
|
||||||
// at runtime.
|
|
||||||
func errnoErr(errno syscall.Errno) error {
|
|
||||||
switch errno {
|
|
||||||
case 0:
|
|
||||||
return nil
|
|
||||||
case syscall.ERROR_IO_PENDING:
|
|
||||||
return errERROR_IO_PENDING
|
|
||||||
case syscall.EINVAL:
|
|
||||||
return errEINVAL
|
|
||||||
}
|
|
||||||
return errno
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
// Copyright 2017 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 arm mips mipsle 386
|
|
||||||
// +build darwin dragonfly freebsd linux netbsd openbsd
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func (v *iovec) set(b []byte) {
|
|
||||||
l := len(b)
|
|
||||||
if l == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v.Base = (*byte)(unsafe.Pointer(&b[0]))
|
|
||||||
v.Len = uint32(l)
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
// Copyright 2017 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 arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
|
|
||||||
// +build darwin dragonfly freebsd linux netbsd openbsd
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func (v *iovec) set(b []byte) {
|
|
||||||
l := len(b)
|
|
||||||
if l == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v.Base = (*byte)(unsafe.Pointer(&b[0]))
|
|
||||||
v.Len = uint64(l)
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
// Copyright 2017 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 amd64
|
|
||||||
// +build solaris
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func (v *iovec) set(b []byte) {
|
|
||||||
l := len(b)
|
|
||||||
if l == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v.Base = (*int8)(unsafe.Pointer(&b[0]))
|
|
||||||
v.Len = uint64(l)
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
type iovec struct{}
|
|
||||||
|
|
||||||
func (v *iovec) set(b []byte) {}
|
|
|
@ -1,21 +0,0 @@
|
||||||
// Copyright 2017 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 !linux,!netbsd
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "net"
|
|
||||||
|
|
||||||
type mmsghdr struct{}
|
|
||||||
|
|
||||||
type mmsghdrs []mmsghdr
|
|
||||||
|
|
||||||
func (hs mmsghdrs) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr) []byte) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
// Copyright 2017 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 linux netbsd
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "net"
|
|
||||||
|
|
||||||
type mmsghdrs []mmsghdr
|
|
||||||
|
|
||||||
func (hs mmsghdrs) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr) []byte) error {
|
|
||||||
for i := range hs {
|
|
||||||
vs := make([]iovec, len(ms[i].Buffers))
|
|
||||||
var sa []byte
|
|
||||||
if parseFn != nil {
|
|
||||||
sa = make([]byte, sizeofSockaddrInet6)
|
|
||||||
}
|
|
||||||
if marshalFn != nil {
|
|
||||||
sa = marshalFn(ms[i].Addr)
|
|
||||||
}
|
|
||||||
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
|
|
||||||
for i := range hs {
|
|
||||||
ms[i].N = int(hs[i].Len)
|
|
||||||
ms[i].NN = hs[i].Hdr.controllen()
|
|
||||||
ms[i].Flags = hs[i].Hdr.flags()
|
|
||||||
if parseFn != nil {
|
|
||||||
var err error
|
|
||||||
ms[i].Addr, err = parseFn(hs[i].Hdr.name(), hint)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
|
|
||||||
for i := range vs {
|
|
||||||
vs[i].set(bs[i])
|
|
||||||
}
|
|
||||||
h.setIov(vs)
|
|
||||||
if len(oob) > 0 {
|
|
||||||
h.Control = (*byte)(unsafe.Pointer(&oob[0]))
|
|
||||||
h.Controllen = uint32(len(oob))
|
|
||||||
}
|
|
||||||
if sa != nil {
|
|
||||||
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
|
|
||||||
h.Namelen = uint32(len(sa))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *msghdr) name() []byte {
|
|
||||||
if h.Name != nil && h.Namelen > 0 {
|
|
||||||
return (*[sizeofSockaddrInet6]byte)(unsafe.Pointer(h.Name))[:h.Namelen]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *msghdr) controllen() int {
|
|
||||||
return int(h.Controllen)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *msghdr) flags() int {
|
|
||||||
return int(h.Flags)
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
// Copyright 2017 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
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
func (h *msghdr) setIov(vs []iovec) {
|
|
||||||
l := len(vs)
|
|
||||||
if l == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h.Iov = &vs[0]
|
|
||||||
h.Iovlen = int32(l)
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
|
|
||||||
for i := range vs {
|
|
||||||
vs[i].set(bs[i])
|
|
||||||
}
|
|
||||||
h.setIov(vs)
|
|
||||||
if len(oob) > 0 {
|
|
||||||
h.setControl(oob)
|
|
||||||
}
|
|
||||||
if sa != nil {
|
|
||||||
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
|
|
||||||
h.Namelen = uint32(len(sa))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *msghdr) name() []byte {
|
|
||||||
if h.Name != nil && h.Namelen > 0 {
|
|
||||||
return (*[sizeofSockaddrInet6]byte)(unsafe.Pointer(h.Name))[:h.Namelen]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *msghdr) controllen() int {
|
|
||||||
return int(h.Controllen)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *msghdr) flags() int {
|
|
||||||
return int(h.Flags)
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright 2017 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 arm mips mipsle 386
|
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func (h *msghdr) setIov(vs []iovec) {
|
|
||||||
l := len(vs)
|
|
||||||
if l == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h.Iov = &vs[0]
|
|
||||||
h.Iovlen = uint32(l)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *msghdr) setControl(b []byte) {
|
|
||||||
h.Control = (*byte)(unsafe.Pointer(&b[0]))
|
|
||||||
h.Controllen = uint32(len(b))
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright 2017 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 arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
|
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func (h *msghdr) setIov(vs []iovec) {
|
|
||||||
l := len(vs)
|
|
||||||
if l == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h.Iov = &vs[0]
|
|
||||||
h.Iovlen = uint64(l)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *msghdr) setControl(b []byte) {
|
|
||||||
h.Control = (*byte)(unsafe.Pointer(&b[0]))
|
|
||||||
h.Controllen = uint64(len(b))
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
func (h *msghdr) setIov(vs []iovec) {
|
|
||||||
l := len(vs)
|
|
||||||
if l == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h.Iov = &vs[0]
|
|
||||||
h.Iovlen = uint32(l)
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
// Copyright 2017 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 amd64
|
|
||||||
// +build solaris
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
|
|
||||||
for i := range vs {
|
|
||||||
vs[i].set(bs[i])
|
|
||||||
}
|
|
||||||
if len(vs) > 0 {
|
|
||||||
h.Iov = &vs[0]
|
|
||||||
h.Iovlen = int32(len(vs))
|
|
||||||
}
|
|
||||||
if len(oob) > 0 {
|
|
||||||
h.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
|
|
||||||
h.Accrightslen = int32(len(oob))
|
|
||||||
}
|
|
||||||
if sa != nil {
|
|
||||||
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
|
|
||||||
h.Namelen = uint32(len(sa))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *msghdr) controllen() int {
|
|
||||||
return int(h.Accrightslen)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *msghdr) flags() int {
|
|
||||||
return int(NativeEndian.Uint32(h.Pad_cgo_2[:]))
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
type msghdr struct{}
|
|
||||||
|
|
||||||
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {}
|
|
||||||
func (h *msghdr) name() []byte { return nil }
|
|
||||||
func (h *msghdr) controllen() int { return 0 }
|
|
||||||
func (h *msghdr) flags() int { return 0 }
|
|
|
@ -1,66 +0,0 @@
|
||||||
// Copyright 2017 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.9
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Conn represents a raw connection.
|
|
||||||
type Conn struct {
|
|
||||||
network string
|
|
||||||
c syscall.RawConn
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConn returns a new raw connection.
|
|
||||||
func NewConn(c net.Conn) (*Conn, error) {
|
|
||||||
var err error
|
|
||||||
var cc Conn
|
|
||||||
switch c := c.(type) {
|
|
||||||
case *net.TCPConn:
|
|
||||||
cc.network = "tcp"
|
|
||||||
cc.c, err = c.SyscallConn()
|
|
||||||
case *net.UDPConn:
|
|
||||||
cc.network = "udp"
|
|
||||||
cc.c, err = c.SyscallConn()
|
|
||||||
case *net.IPConn:
|
|
||||||
cc.network = "ip"
|
|
||||||
cc.c, err = c.SyscallConn()
|
|
||||||
default:
|
|
||||||
return nil, errors.New("unknown connection type")
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &cc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Option) get(c *Conn, b []byte) (int, error) {
|
|
||||||
var operr error
|
|
||||||
var n int
|
|
||||||
fn := func(s uintptr) {
|
|
||||||
n, operr = getsockopt(s, o.Level, o.Name, b)
|
|
||||||
}
|
|
||||||
if err := c.c.Control(fn); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return n, os.NewSyscallError("getsockopt", operr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Option) set(c *Conn, b []byte) error {
|
|
||||||
var operr error
|
|
||||||
fn := func(s uintptr) {
|
|
||||||
operr = setsockopt(s, o.Level, o.Name, b)
|
|
||||||
}
|
|
||||||
if err := c.c.Control(fn); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return os.NewSyscallError("setsockopt", operr)
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
// Copyright 2017 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.9
|
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
|
|
||||||
hs := make(mmsghdrs, len(ms))
|
|
||||||
var parseFn func([]byte, string) (net.Addr, error)
|
|
||||||
if c.network != "tcp" {
|
|
||||||
parseFn = parseInetAddr
|
|
||||||
}
|
|
||||||
if err := hs.pack(ms, parseFn, nil); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
var operr error
|
|
||||||
var n int
|
|
||||||
fn := func(s uintptr) bool {
|
|
||||||
n, operr = recvmmsg(s, hs, flags)
|
|
||||||
if operr == syscall.EAGAIN {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if err := c.c.Read(fn); err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
if operr != nil {
|
|
||||||
return n, os.NewSyscallError("recvmmsg", operr)
|
|
||||||
}
|
|
||||||
if err := hs[:n].unpack(ms[:n], parseFn, c.network); err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
|
|
||||||
hs := make(mmsghdrs, len(ms))
|
|
||||||
var marshalFn func(net.Addr) []byte
|
|
||||||
if c.network != "tcp" {
|
|
||||||
marshalFn = marshalInetAddr
|
|
||||||
}
|
|
||||||
if err := hs.pack(ms, nil, marshalFn); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
var operr error
|
|
||||||
var n int
|
|
||||||
fn := func(s uintptr) bool {
|
|
||||||
n, operr = sendmmsg(s, hs, flags)
|
|
||||||
if operr == syscall.EAGAIN {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if err := c.c.Write(fn); err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
if operr != nil {
|
|
||||||
return n, os.NewSyscallError("sendmmsg", operr)
|
|
||||||
}
|
|
||||||
if err := hs[:n].unpack(ms[:n], nil, ""); err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
// Copyright 2017 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.9
|
|
||||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Conn) recvMsg(m *Message, flags int) error {
|
|
||||||
var h msghdr
|
|
||||||
vs := make([]iovec, len(m.Buffers))
|
|
||||||
var sa []byte
|
|
||||||
if c.network != "tcp" {
|
|
||||||
sa = make([]byte, sizeofSockaddrInet6)
|
|
||||||
}
|
|
||||||
h.pack(vs, m.Buffers, m.OOB, sa)
|
|
||||||
var operr error
|
|
||||||
var n int
|
|
||||||
fn := func(s uintptr) bool {
|
|
||||||
n, operr = recvmsg(s, &h, flags)
|
|
||||||
if operr == syscall.EAGAIN {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if err := c.c.Read(fn); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if operr != nil {
|
|
||||||
return os.NewSyscallError("recvmsg", operr)
|
|
||||||
}
|
|
||||||
if c.network != "tcp" {
|
|
||||||
var err error
|
|
||||||
m.Addr, err = parseInetAddr(sa[:], c.network)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.N = n
|
|
||||||
m.NN = h.controllen()
|
|
||||||
m.Flags = h.flags()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) sendMsg(m *Message, flags int) error {
|
|
||||||
var h msghdr
|
|
||||||
vs := make([]iovec, len(m.Buffers))
|
|
||||||
var sa []byte
|
|
||||||
if m.Addr != nil {
|
|
||||||
sa = marshalInetAddr(m.Addr)
|
|
||||||
}
|
|
||||||
h.pack(vs, m.Buffers, m.OOB, sa)
|
|
||||||
var operr error
|
|
||||||
var n int
|
|
||||||
fn := func(s uintptr) bool {
|
|
||||||
n, operr = sendmsg(s, &h, flags)
|
|
||||||
if operr == syscall.EAGAIN {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if err := c.c.Write(fn); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if operr != nil {
|
|
||||||
return os.NewSyscallError("sendmsg", operr)
|
|
||||||
}
|
|
||||||
m.N = n
|
|
||||||
m.NN = len(m.OOB)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// Copyright 2017 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.9
|
|
||||||
// +build !linux
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
|
|
||||||
return 0, errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
|
|
||||||
return 0, errors.New("not implemented")
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// Copyright 2017 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.9
|
|
||||||
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func (c *Conn) recvMsg(m *Message, flags int) error {
|
|
||||||
return errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) sendMsg(m *Message, flags int) error {
|
|
||||||
return errors.New("not implemented")
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
// Copyright 2017 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.9
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func (c *Conn) recvMsg(m *Message, flags int) error {
|
|
||||||
return errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) sendMsg(m *Message, flags int) error {
|
|
||||||
return errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
|
|
||||||
return 0, errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
|
|
||||||
return 0, errors.New("not implemented")
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
// Copyright 2017 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.9
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Conn represents a raw connection.
|
|
||||||
type Conn struct {
|
|
||||||
c net.Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConn returns a new raw connection.
|
|
||||||
func NewConn(c net.Conn) (*Conn, error) {
|
|
||||||
return &Conn{c: c}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Option) get(c *Conn, b []byte) (int, error) {
|
|
||||||
s, err := socketOf(c.c)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
n, err := getsockopt(s, o.Level, o.Name, b)
|
|
||||||
return n, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Option) set(c *Conn, b []byte) error {
|
|
||||||
s, err := socketOf(c.c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return os.NewSyscallError("setsockopt", setsockopt(s, o.Level, o.Name, b))
|
|
||||||
}
|
|
||||||
|
|
||||||
func socketOf(c net.Conn) (uintptr, error) {
|
|
||||||
switch c.(type) {
|
|
||||||
case *net.TCPConn, *net.UDPConn, *net.IPConn:
|
|
||||||
v := reflect.ValueOf(c)
|
|
||||||
switch e := v.Elem(); e.Kind() {
|
|
||||||
case reflect.Struct:
|
|
||||||
fd := e.FieldByName("conn").FieldByName("fd")
|
|
||||||
switch e := fd.Elem(); e.Kind() {
|
|
||||||
case reflect.Struct:
|
|
||||||
sysfd := e.FieldByName("sysfd")
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
return uintptr(sysfd.Uint()), nil
|
|
||||||
}
|
|
||||||
return uintptr(sysfd.Int()), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0, errors.New("invalid type")
|
|
||||||
}
|
|
|
@ -1,285 +0,0 @@
|
||||||
// Copyright 2017 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 socket provides a portable interface for socket system
|
|
||||||
// calls.
|
|
||||||
package socket // import "golang.org/x/net/internal/socket"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An Option represents a sticky socket option.
|
|
||||||
type Option struct {
|
|
||||||
Level int // level
|
|
||||||
Name int // name; must be equal or greater than 1
|
|
||||||
Len int // length of value in bytes; must be equal or greater than 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get reads a value for the option from the kernel.
|
|
||||||
// It returns the number of bytes written into b.
|
|
||||||
func (o *Option) Get(c *Conn, b []byte) (int, error) {
|
|
||||||
if o.Name < 1 || o.Len < 1 {
|
|
||||||
return 0, errors.New("invalid option")
|
|
||||||
}
|
|
||||||
if len(b) < o.Len {
|
|
||||||
return 0, errors.New("short buffer")
|
|
||||||
}
|
|
||||||
return o.get(c, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInt returns an integer value for the option.
|
|
||||||
//
|
|
||||||
// The Len field of Option must be either 1 or 4.
|
|
||||||
func (o *Option) GetInt(c *Conn) (int, error) {
|
|
||||||
if o.Len != 1 && o.Len != 4 {
|
|
||||||
return 0, errors.New("invalid option")
|
|
||||||
}
|
|
||||||
var b []byte
|
|
||||||
var bb [4]byte
|
|
||||||
if o.Len == 1 {
|
|
||||||
b = bb[:1]
|
|
||||||
} else {
|
|
||||||
b = bb[:4]
|
|
||||||
}
|
|
||||||
n, err := o.get(c, b)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if n != o.Len {
|
|
||||||
return 0, errors.New("invalid option length")
|
|
||||||
}
|
|
||||||
if o.Len == 1 {
|
|
||||||
return int(b[0]), nil
|
|
||||||
}
|
|
||||||
return int(NativeEndian.Uint32(b[:4])), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set writes the option and value to the kernel.
|
|
||||||
func (o *Option) Set(c *Conn, b []byte) error {
|
|
||||||
if o.Name < 1 || o.Len < 1 {
|
|
||||||
return errors.New("invalid option")
|
|
||||||
}
|
|
||||||
if len(b) < o.Len {
|
|
||||||
return errors.New("short buffer")
|
|
||||||
}
|
|
||||||
return o.set(c, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetInt writes the option and value to the kernel.
|
|
||||||
//
|
|
||||||
// The Len field of Option must be either 1 or 4.
|
|
||||||
func (o *Option) SetInt(c *Conn, v int) error {
|
|
||||||
if o.Len != 1 && o.Len != 4 {
|
|
||||||
return errors.New("invalid option")
|
|
||||||
}
|
|
||||||
var b []byte
|
|
||||||
if o.Len == 1 {
|
|
||||||
b = []byte{byte(v)}
|
|
||||||
} else {
|
|
||||||
var bb [4]byte
|
|
||||||
NativeEndian.PutUint32(bb[:o.Len], uint32(v))
|
|
||||||
b = bb[:4]
|
|
||||||
}
|
|
||||||
return o.set(c, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func controlHeaderLen() int {
|
|
||||||
return roundup(sizeofCmsghdr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func controlMessageLen(dataLen int) int {
|
|
||||||
return roundup(sizeofCmsghdr) + dataLen
|
|
||||||
}
|
|
||||||
|
|
||||||
// ControlMessageSpace returns the whole length of control message.
|
|
||||||
func ControlMessageSpace(dataLen int) int {
|
|
||||||
return roundup(sizeofCmsghdr) + roundup(dataLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A ControlMessage represents the head message in a stream of control
|
|
||||||
// messages.
|
|
||||||
//
|
|
||||||
// A control message comprises of a header, data and a few padding
|
|
||||||
// fields to conform to the interface to the kernel.
|
|
||||||
//
|
|
||||||
// See RFC 3542 for further information.
|
|
||||||
type ControlMessage []byte
|
|
||||||
|
|
||||||
// Data returns the data field of the control message at the head on
|
|
||||||
// m.
|
|
||||||
func (m ControlMessage) Data(dataLen int) []byte {
|
|
||||||
l := controlHeaderLen()
|
|
||||||
if len(m) < l || len(m) < l+dataLen {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return m[l : l+dataLen]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next returns the control message at the next on m.
|
|
||||||
//
|
|
||||||
// Next works only for standard control messages.
|
|
||||||
func (m ControlMessage) Next(dataLen int) ControlMessage {
|
|
||||||
l := ControlMessageSpace(dataLen)
|
|
||||||
if len(m) < l {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return m[l:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalHeader marshals the header fields of the control message at
|
|
||||||
// the head on m.
|
|
||||||
func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error {
|
|
||||||
if len(m) < controlHeaderLen() {
|
|
||||||
return errors.New("short message")
|
|
||||||
}
|
|
||||||
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
|
||||||
h.set(controlMessageLen(dataLen), lvl, typ)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseHeader parses and returns the header fields of the control
|
|
||||||
// message at the head on m.
|
|
||||||
func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) {
|
|
||||||
l := controlHeaderLen()
|
|
||||||
if len(m) < l {
|
|
||||||
return 0, 0, 0, errors.New("short message")
|
|
||||||
}
|
|
||||||
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
|
||||||
return h.lvl(), h.typ(), int(uint64(h.len()) - uint64(l)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal marshals the control message at the head on m, and returns
|
|
||||||
// the next control message.
|
|
||||||
func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, error) {
|
|
||||||
l := len(data)
|
|
||||||
if len(m) < ControlMessageSpace(l) {
|
|
||||||
return nil, errors.New("short message")
|
|
||||||
}
|
|
||||||
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
|
||||||
h.set(controlMessageLen(l), lvl, typ)
|
|
||||||
if l > 0 {
|
|
||||||
copy(m.Data(l), data)
|
|
||||||
}
|
|
||||||
return m.Next(l), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse parses m as a single or multiple control messages.
|
|
||||||
//
|
|
||||||
// Parse works for both standard and compatible messages.
|
|
||||||
func (m ControlMessage) Parse() ([]ControlMessage, error) {
|
|
||||||
var ms []ControlMessage
|
|
||||||
for len(m) >= controlHeaderLen() {
|
|
||||||
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
|
||||||
l := h.len()
|
|
||||||
if l <= 0 {
|
|
||||||
return nil, errors.New("invalid header length")
|
|
||||||
}
|
|
||||||
if uint64(l) < uint64(controlHeaderLen()) {
|
|
||||||
return nil, errors.New("invalid message length")
|
|
||||||
}
|
|
||||||
if uint64(l) > uint64(len(m)) {
|
|
||||||
return nil, errors.New("short buffer")
|
|
||||||
}
|
|
||||||
// On message reception:
|
|
||||||
//
|
|
||||||
// |<- ControlMessageSpace --------------->|
|
|
||||||
// |<- controlMessageLen ---------->| |
|
|
||||||
// |<- controlHeaderLen ->| | |
|
|
||||||
// +---------------+------+---------+------+
|
|
||||||
// | Header | PadH | Data | PadD |
|
|
||||||
// +---------------+------+---------+------+
|
|
||||||
//
|
|
||||||
// On compatible message reception:
|
|
||||||
//
|
|
||||||
// | ... |<- controlMessageLen ----------->|
|
|
||||||
// | ... |<- controlHeaderLen ->| |
|
|
||||||
// +-----+---------------+------+----------+
|
|
||||||
// | ... | Header | PadH | Data |
|
|
||||||
// +-----+---------------+------+----------+
|
|
||||||
ms = append(ms, ControlMessage(m[:l]))
|
|
||||||
ll := l - controlHeaderLen()
|
|
||||||
if len(m) >= ControlMessageSpace(ll) {
|
|
||||||
m = m[ControlMessageSpace(ll):]
|
|
||||||
} else {
|
|
||||||
m = m[controlMessageLen(ll):]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ms, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewControlMessage returns a new stream of control messages.
|
|
||||||
func NewControlMessage(dataLen []int) ControlMessage {
|
|
||||||
var l int
|
|
||||||
for i := range dataLen {
|
|
||||||
l += ControlMessageSpace(dataLen[i])
|
|
||||||
}
|
|
||||||
return make([]byte, l)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Message represents an IO message.
|
|
||||||
type Message struct {
|
|
||||||
// When writing, the Buffers field must contain at least one
|
|
||||||
// byte to write.
|
|
||||||
// When reading, the Buffers field will always contain a byte
|
|
||||||
// to read.
|
|
||||||
Buffers [][]byte
|
|
||||||
|
|
||||||
// OOB contains protocol-specific control or miscellaneous
|
|
||||||
// ancillary data known as out-of-band data.
|
|
||||||
OOB []byte
|
|
||||||
|
|
||||||
// Addr specifies a destination address when writing.
|
|
||||||
// It can be nil when the underlying protocol of the raw
|
|
||||||
// connection uses connection-oriented communication.
|
|
||||||
// After a successful read, it may contain the source address
|
|
||||||
// on the received packet.
|
|
||||||
Addr net.Addr
|
|
||||||
|
|
||||||
N int // # of bytes read or written from/to Buffers
|
|
||||||
NN int // # of bytes read or written from/to OOB
|
|
||||||
Flags int // protocol-specific information on the received message
|
|
||||||
}
|
|
||||||
|
|
||||||
// RecvMsg wraps recvmsg system call.
|
|
||||||
//
|
|
||||||
// The provided flags is a set of platform-dependent flags, such as
|
|
||||||
// syscall.MSG_PEEK.
|
|
||||||
func (c *Conn) RecvMsg(m *Message, flags int) error {
|
|
||||||
return c.recvMsg(m, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendMsg wraps sendmsg system call.
|
|
||||||
//
|
|
||||||
// The provided flags is a set of platform-dependent flags, such as
|
|
||||||
// syscall.MSG_DONTROUTE.
|
|
||||||
func (c *Conn) SendMsg(m *Message, flags int) error {
|
|
||||||
return c.sendMsg(m, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RecvMsgs wraps recvmmsg system call.
|
|
||||||
//
|
|
||||||
// It returns the number of processed messages.
|
|
||||||
//
|
|
||||||
// The provided flags is a set of platform-dependent flags, such as
|
|
||||||
// syscall.MSG_PEEK.
|
|
||||||
//
|
|
||||||
// Only Linux supports this.
|
|
||||||
func (c *Conn) RecvMsgs(ms []Message, flags int) (int, error) {
|
|
||||||
return c.recvMsgs(ms, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendMsgs wraps sendmmsg system call.
|
|
||||||
//
|
|
||||||
// It returns the number of processed messages.
|
|
||||||
//
|
|
||||||
// The provided flags is a set of platform-dependent flags, such as
|
|
||||||
// syscall.MSG_DONTROUTE.
|
|
||||||
//
|
|
||||||
// Only Linux supports this.
|
|
||||||
func (c *Conn) SendMsgs(ms []Message, flags int) (int, error) {
|
|
||||||
return c.sendMsgs(ms, flags)
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// NativeEndian is the machine native endian implementation of
|
|
||||||
// ByteOrder.
|
|
||||||
NativeEndian binary.ByteOrder
|
|
||||||
|
|
||||||
kernelAlign int
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
i := uint32(1)
|
|
||||||
b := (*[4]byte)(unsafe.Pointer(&i))
|
|
||||||
if b[0] == 1 {
|
|
||||||
NativeEndian = binary.LittleEndian
|
|
||||||
} else {
|
|
||||||
NativeEndian = binary.BigEndian
|
|
||||||
}
|
|
||||||
kernelAlign = probeProtocolStack()
|
|
||||||
}
|
|
||||||
|
|
||||||
func roundup(l int) int {
|
|
||||||
return (l + kernelAlign - 1) & ^(kernelAlign - 1)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright 2017 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 openbsd
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
|
||||||
return 0, errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
|
||||||
return 0, errors.New("not implemented")
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright 2017 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 freebsd netbsd openbsd
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func probeProtocolStack() int {
|
|
||||||
var p uintptr
|
|
||||||
return int(unsafe.Sizeof(p))
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
func probeProtocolStack() int { return 4 }
|
|
|
@ -1,7 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
func probeProtocolStack() int { return 4 }
|
|
|
@ -1,27 +0,0 @@
|
||||||
// Copyright 2017 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 linux,!s390x,!386
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
func probeProtocolStack() int {
|
|
||||||
var p uintptr
|
|
||||||
return int(unsafe.Sizeof(p))
|
|
||||||
}
|
|
||||||
|
|
||||||
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
|
||||||
n, _, errno := syscall.Syscall6(sysRECVMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
|
|
||||||
return int(n), errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
|
||||||
n, _, errno := syscall.Syscall6(sysSENDMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
|
|
||||||
return int(n), errnoErr(errno)
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
func probeProtocolStack() int { return 4 }
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysSETSOCKOPT = 0xe
|
|
||||||
sysGETSOCKOPT = 0xf
|
|
||||||
sysSENDMSG = 0x10
|
|
||||||
sysRECVMSG = 0x11
|
|
||||||
sysRECVMMSG = 0x13
|
|
||||||
sysSENDMMSG = 0x14
|
|
||||||
)
|
|
||||||
|
|
||||||
func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) (uintptr, syscall.Errno)
|
|
||||||
func rawsocketcall(call, a0, a1, a2, a3, a4, a5 uintptr) (uintptr, syscall.Errno)
|
|
||||||
|
|
||||||
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
|
|
||||||
l := uint32(len(b))
|
|
||||||
_, errno := socketcall(sysGETSOCKOPT, s, uintptr(level), uintptr(name), uintptr(unsafe.Pointer(&b[0])), uintptr(unsafe.Pointer(&l)), 0)
|
|
||||||
return int(l), errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setsockopt(s uintptr, level, name int, b []byte) error {
|
|
||||||
_, errno := socketcall(sysSETSOCKOPT, s, uintptr(level), uintptr(name), uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), 0)
|
|
||||||
return errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func recvmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
|
||||||
n, errno := socketcall(sysRECVMSG, s, uintptr(unsafe.Pointer(h)), uintptr(flags), 0, 0, 0)
|
|
||||||
return int(n), errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
|
||||||
n, errno := socketcall(sysSENDMSG, s, uintptr(unsafe.Pointer(h)), uintptr(flags), 0, 0, 0)
|
|
||||||
return int(n), errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
|
||||||
n, errno := socketcall(sysRECVMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
|
|
||||||
return int(n), errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
|
||||||
n, errno := socketcall(sysSENDMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
|
|
||||||
return int(n), errnoErr(errno)
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// 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.
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
TEXT ·socketcall(SB),NOSPLIT,$0-36
|
|
||||||
JMP syscall·socketcall(SB)
|
|
||||||
|
|
||||||
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
|
|
||||||
JMP syscall·rawsocketcall(SB)
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysRECVMMSG = 0x12b
|
|
||||||
sysSENDMMSG = 0x133
|
|
||||||
)
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysRECVMMSG = 0x16d
|
|
||||||
sysSENDMMSG = 0x176
|
|
||||||
)
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysRECVMMSG = 0xf3
|
|
||||||
sysSENDMMSG = 0x10d
|
|
||||||
)
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysRECVMMSG = 0x10ef
|
|
||||||
sysSENDMMSG = 0x10f7
|
|
||||||
)
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysRECVMMSG = 0x14ae
|
|
||||||
sysSENDMMSG = 0x14b6
|
|
||||||
)
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysRECVMMSG = 0x14ae
|
|
||||||
sysSENDMMSG = 0x14b6
|
|
||||||
)
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysRECVMMSG = 0x10ef
|
|
||||||
sysSENDMMSG = 0x10f7
|
|
||||||
)
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysRECVMMSG = 0x157
|
|
||||||
sysSENDMMSG = 0x15d
|
|
||||||
)
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysRECVMMSG = 0x157
|
|
||||||
sysSENDMMSG = 0x15d
|
|
||||||
)
|
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright 2017 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 socket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
func probeProtocolStack() int { return 8 }
|
|
||||||
|
|
||||||
const (
|
|
||||||
sysSETSOCKOPT = 0xe
|
|
||||||
sysGETSOCKOPT = 0xf
|
|
||||||
sysSENDMSG = 0x10
|
|
||||||
sysRECVMSG = 0x11
|
|
||||||
sysRECVMMSG = 0x13
|
|
||||||
sysSENDMMSG = 0x14
|
|
||||||
)
|
|
||||||
|
|
||||||
func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) (uintptr, syscall.Errno)
|
|
||||||
func rawsocketcall(call, a0, a1, a2, a3, a4, a5 uintptr) (uintptr, syscall.Errno)
|
|
||||||
|
|
||||||
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
|
|
||||||
l := uint32(len(b))
|
|
||||||
_, errno := socketcall(sysGETSOCKOPT, s, uintptr(level), uintptr(name), uintptr(unsafe.Pointer(&b[0])), uintptr(unsafe.Pointer(&l)), 0)
|
|
||||||
return int(l), errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setsockopt(s uintptr, level, name int, b []byte) error {
|
|
||||||
_, errno := socketcall(sysSETSOCKOPT, s, uintptr(level), uintptr(name), uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), 0)
|
|
||||||
return errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func recvmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
|
||||||
n, errno := socketcall(sysRECVMSG, s, uintptr(unsafe.Pointer(h)), uintptr(flags), 0, 0, 0)
|
|
||||||
return int(n), errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
|
||||||
n, errno := socketcall(sysSENDMSG, s, uintptr(unsafe.Pointer(h)), uintptr(flags), 0, 0, 0)
|
|
||||||
return int(n), errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
|
||||||
n, errno := socketcall(sysRECVMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
|
|
||||||
return int(n), errnoErr(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
|
||||||
n, errno := socketcall(sysSENDMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
|
|
||||||
return int(n), errnoErr(errno)
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// Copyright 2017 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.
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
TEXT ·socketcall(SB),NOSPLIT,$0-72
|
|
||||||
JMP syscall·socketcall(SB)
|
|
||||||
|
|
||||||
TEXT ·rawsocketcall(SB),NOSPLIT,$0-72
|
|
||||||
JMP syscall·rawsocketcall(SB)
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue