mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 09:41:57 +00:00
Vendor github.com/typetypetype/conntrack
This commit is contained in:
22
vendor/github.com/typetypetype/conntrack/LICENSE
generated
vendored
Normal file
22
vendor/github.com/typetypetype/conntrack/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 typetypetype
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
33
vendor/github.com/typetypetype/conntrack/cli/main.go
generated
vendored
Normal file
33
vendor/github.com/typetypetype/conntrack/cli/main.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
// Example usage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/typetypetype/conntrack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cs, err := conntrack.Established()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Established: %s", err))
|
||||
}
|
||||
fmt.Printf("Established on start:\n")
|
||||
for _, cn := range cs {
|
||||
fmt.Printf(" - %s\n", cn)
|
||||
}
|
||||
fmt.Println("")
|
||||
|
||||
c, err := conntrack.New()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for range time.Tick(1 * time.Second) {
|
||||
fmt.Printf("Connections:\n")
|
||||
for _, cn := range c.Connections() {
|
||||
fmt.Printf(" - %s\n", cn)
|
||||
}
|
||||
}
|
||||
}
|
||||
461
vendor/github.com/typetypetype/conntrack/client.go
generated
vendored
Normal file
461
vendor/github.com/typetypetype/conntrack/client.go
generated
vendored
Normal file
@@ -0,0 +1,461 @@
|
||||
package conntrack
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
sizeofGenmsg = uint32(unsafe.Sizeof(unix.Nfgenmsg{})) // TODO
|
||||
)
|
||||
|
||||
type ConntrackListReq struct {
|
||||
Header syscall.NlMsghdr
|
||||
Body unix.Nfgenmsg
|
||||
}
|
||||
|
||||
func (c *ConntrackListReq) toWireFormat() []byte {
|
||||
// adapted from syscall/NetlinkRouteRequest.toWireFormat
|
||||
b := make([]byte, c.Header.Len)
|
||||
*(*uint32)(unsafe.Pointer(&b[0:4][0])) = c.Header.Len
|
||||
*(*uint16)(unsafe.Pointer(&b[4:6][0])) = c.Header.Type
|
||||
*(*uint16)(unsafe.Pointer(&b[6:8][0])) = c.Header.Flags
|
||||
*(*uint32)(unsafe.Pointer(&b[8:12][0])) = c.Header.Seq
|
||||
*(*uint32)(unsafe.Pointer(&b[12:16][0])) = c.Header.Pid
|
||||
b[16] = byte(c.Body.Nfgen_family)
|
||||
b[17] = byte(c.Body.Version)
|
||||
*(*uint16)(unsafe.Pointer(&b[18:20][0])) = c.Body.Res_id
|
||||
return b
|
||||
}
|
||||
|
||||
func connectNetfilter(bufferSize int, groups uint32) (int, *syscall.SockaddrNetlink, error) {
|
||||
s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_NETFILTER)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
lsa := &syscall.SockaddrNetlink{
|
||||
Family: syscall.AF_NETLINK,
|
||||
Groups: groups,
|
||||
}
|
||||
if err := syscall.Bind(s, lsa); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if bufferSize > 0 {
|
||||
// Speculatively try SO_RCVBUFFORCE which needs CAP_NET_ADMIN
|
||||
if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_RCVBUFFORCE, bufferSize); err != nil {
|
||||
// and if that doesn't work fall back to the ordinary SO_RCVBUF
|
||||
if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bufferSize); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s, lsa, nil
|
||||
}
|
||||
|
||||
// Make syscall asking for all connections. Invoke 'cb' for each connection.
|
||||
func queryAllConnections(bufferSize int, cb func(Conn)) error {
|
||||
s, lsa, err := connectNetfilter(bufferSize, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Close(s)
|
||||
|
||||
msg := ConntrackListReq{
|
||||
Header: syscall.NlMsghdr{
|
||||
Len: syscall.NLMSG_HDRLEN + sizeofGenmsg,
|
||||
Type: (NFNL_SUBSYS_CTNETLINK << 8) | uint16(IpctnlMsgCtGet),
|
||||
Flags: syscall.NLM_F_REQUEST | syscall.NLM_F_DUMP,
|
||||
Pid: 0,
|
||||
Seq: 0,
|
||||
},
|
||||
Body: unix.Nfgenmsg{
|
||||
Nfgen_family: syscall.AF_INET,
|
||||
Version: NFNETLINK_V0,
|
||||
Res_id: 0,
|
||||
},
|
||||
}
|
||||
wb := msg.toWireFormat()
|
||||
// fmt.Printf("msg bytes: %q\n", wb)
|
||||
if err := syscall.Sendto(s, wb, 0, lsa); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return readMsgs(s, cb)
|
||||
}
|
||||
|
||||
// Stream all connections instead of query for all of them at once.
|
||||
func StreamAllConnections() chan Conn {
|
||||
ch := make(chan Conn, 1)
|
||||
go func() {
|
||||
queryAllConnections(0, func(c Conn) {
|
||||
ch <- c
|
||||
})
|
||||
close(ch)
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// Lists all the connections that conntrack is tracking.
|
||||
func Connections() ([]Conn, error) {
|
||||
return ConnectionsSize(0)
|
||||
}
|
||||
|
||||
// Lists all the connections that conntrack is tracking, using specified netlink buffer size.
|
||||
func ConnectionsSize(bufferSize int) ([]Conn, error) {
|
||||
var conns []Conn
|
||||
queryAllConnections(bufferSize, func(c Conn) {
|
||||
conns = append(conns, c)
|
||||
})
|
||||
return conns, nil
|
||||
}
|
||||
|
||||
// Established lists all established TCP connections.
|
||||
func Established() ([]ConnTCP, error) {
|
||||
var conns []ConnTCP
|
||||
local := localIPs()
|
||||
err := queryAllConnections(0, func(c Conn) {
|
||||
if c.MsgType != NfctMsgUpdate {
|
||||
fmt.Printf("msg isn't an update: %d\n", c.MsgType)
|
||||
return
|
||||
}
|
||||
if c.TCPState != "ESTABLISHED" {
|
||||
// fmt.Printf("state isn't ESTABLISHED: %s\n", c.TCPState)
|
||||
return
|
||||
}
|
||||
if tc := c.ConnTCP(local); tc != nil {
|
||||
conns = append(conns, *tc)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conns, nil
|
||||
}
|
||||
|
||||
// Follow gives a channel with all changes.
|
||||
func Follow(flags uint32) (<-chan Conn, func(), error) {
|
||||
return FollowSize(0, flags)
|
||||
}
|
||||
|
||||
// Follow gives a channel with all changes, , using specified netlink buffer size.
|
||||
func FollowSize(bufferSize int, flags uint32) (<-chan Conn, func(), error) {
|
||||
s, _, err := connectNetfilter(bufferSize, flags)
|
||||
stop := func() {
|
||||
syscall.Close(s)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, stop, err
|
||||
}
|
||||
|
||||
res := make(chan Conn, 1)
|
||||
go func() {
|
||||
defer syscall.Close(s)
|
||||
if err := readMsgs(s, func(c Conn) {
|
||||
// if conn.TCPState != 3 {
|
||||
// // 3 is TCP established.
|
||||
// continue
|
||||
// }
|
||||
res <- c
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
return res, stop, nil
|
||||
}
|
||||
|
||||
func readMsgs(s int, cb func(Conn)) error {
|
||||
rb := make([]byte, 2*syscall.Getpagesize())
|
||||
loop:
|
||||
for {
|
||||
nr, _, err := syscall.Recvfrom(s, rb, 0)
|
||||
if err == syscall.ENOBUFS {
|
||||
// ENOBUF means we miss some events here. No way around it. That's life.
|
||||
cb(Conn{Err: syscall.ENOBUFS})
|
||||
continue
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgs, err := syscall.ParseNetlinkMessage(rb[:nr])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, msg := range msgs {
|
||||
if msg.Header.Type == unix.NLMSG_ERROR {
|
||||
return errors.New("NLMSG_ERROR")
|
||||
}
|
||||
if msg.Header.Type == unix.NLMSG_DONE {
|
||||
break loop
|
||||
}
|
||||
|
||||
if nflnSubsysID(msg.Header.Type) != NFNL_SUBSYS_CTNETLINK {
|
||||
return fmt.Errorf(
|
||||
"unexpected subsys_id: %d\n",
|
||||
nflnSubsysID(msg.Header.Type),
|
||||
)
|
||||
}
|
||||
conn, err := parsePayload(msg.Data[sizeofGenmsg:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Taken from conntrack/parse.c:__parse_message_type
|
||||
switch CntlMsgTypes(nflnMsgType(msg.Header.Type)) {
|
||||
case IpctnlMsgCtNew:
|
||||
conn.MsgType = NfctMsgUpdate
|
||||
if msg.Header.Flags&(syscall.NLM_F_CREATE|syscall.NLM_F_EXCL) > 0 {
|
||||
conn.MsgType = NfctMsgNew
|
||||
}
|
||||
case IpctnlMsgCtDelete:
|
||||
conn.MsgType = NfctMsgDestroy
|
||||
}
|
||||
|
||||
cb(*conn)
|
||||
|
||||
if msg.Header.Flags&unix.NLM_F_MULTI > 0 {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Tuple struct {
|
||||
Proto int
|
||||
Src net.IP
|
||||
SrcPort uint16
|
||||
Dst net.IP
|
||||
DstPort uint16
|
||||
|
||||
// ICMP stuff.
|
||||
IcmpId uint16
|
||||
IcmpType uint8
|
||||
IcmpCode uint8
|
||||
}
|
||||
|
||||
type Conn struct {
|
||||
MsgType NfConntrackMsg
|
||||
TCPState string
|
||||
Status CtStatus
|
||||
Orig Tuple
|
||||
Reply Tuple
|
||||
|
||||
// ct.mark, used to set permission type of the flow.
|
||||
CtMark uint32
|
||||
|
||||
// ct.id, used to identify connections.
|
||||
CtId uint32
|
||||
|
||||
// For multitenancy.
|
||||
Zone uint16
|
||||
|
||||
// Flow stats.
|
||||
ReplyPktLen uint64
|
||||
ReplyPktCount uint64
|
||||
OrigPktLen uint64
|
||||
OrigPktCount uint64
|
||||
|
||||
// Error, if any.
|
||||
Err error
|
||||
}
|
||||
|
||||
// ConnTCP decides which way this connection is going and makes a ConnTCP.
|
||||
func (c Conn) ConnTCP(local map[string]struct{}) *ConnTCP {
|
||||
// conntrack gives us all connections, even things passing through, but it
|
||||
// doesn't tell us what the local IP is. So we use `local` as a guide
|
||||
// what's local.
|
||||
src := c.Orig.Src.String()
|
||||
dst := c.Orig.Dst.String()
|
||||
_, srcLocal := local[src]
|
||||
_, dstLocal := local[dst]
|
||||
// If both are local we must just order things predictably.
|
||||
if srcLocal && dstLocal {
|
||||
srcLocal = c.Orig.SrcPort < c.Orig.DstPort
|
||||
}
|
||||
if srcLocal {
|
||||
return &ConnTCP{
|
||||
Local: src,
|
||||
LocalPort: strconv.Itoa(int(c.Orig.SrcPort)),
|
||||
Remote: dst,
|
||||
RemotePort: strconv.Itoa(int(c.Orig.DstPort)),
|
||||
}
|
||||
}
|
||||
if dstLocal {
|
||||
return &ConnTCP{
|
||||
Local: dst,
|
||||
LocalPort: strconv.Itoa(int(c.Orig.DstPort)),
|
||||
Remote: src,
|
||||
RemotePort: strconv.Itoa(int(c.Orig.SrcPort)),
|
||||
}
|
||||
}
|
||||
// Neither is local. conntrack also reports NAT connections.
|
||||
return nil
|
||||
}
|
||||
|
||||
func parsePayload(b []byte) (*Conn, error) {
|
||||
// Most of this comes from libnetfilter_conntrack/src/conntrack/parse_mnl.c
|
||||
conn := &Conn{}
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return conn, err
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
switch CtattrType(attr.Typ) {
|
||||
case CtaTupleOrig:
|
||||
parseTuple(attr.Msg, &conn.Orig)
|
||||
case CtaTupleReply:
|
||||
parseTuple(attr.Msg, &conn.Reply)
|
||||
case CtaCountersOrig:
|
||||
conn.OrigPktLen, conn.OrigPktCount, _ = parseCounters(attr.Msg)
|
||||
case CtaCountersReply:
|
||||
conn.ReplyPktLen, conn.ReplyPktCount, _ = parseCounters(attr.Msg)
|
||||
case CtaStatus:
|
||||
conn.Status = CtStatus(binary.BigEndian.Uint32(attr.Msg))
|
||||
case CtaProtoinfo:
|
||||
parseProtoinfo(attr.Msg, conn)
|
||||
case CtaMark:
|
||||
conn.CtMark = binary.BigEndian.Uint32(attr.Msg)
|
||||
case CtaZone:
|
||||
conn.Zone = binary.BigEndian.Uint16(attr.Msg)
|
||||
case CtaId:
|
||||
conn.CtId = binary.BigEndian.Uint32(attr.Msg)
|
||||
}
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func parseTuple(b []byte, tuple *Tuple) error {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
// fmt.Printf("pl: %d, type: %d, multi: %t, bigend: %t\n", len(attr.Msg), attr.Typ, attr.IsNested, attr.IsNetByteorder)
|
||||
switch CtattrTuple(attr.Typ) {
|
||||
case CtaTupleUnspec:
|
||||
// fmt.Printf("It's a tuple unspec\n")
|
||||
case CtaTupleIp:
|
||||
// fmt.Printf("It's a tuple IP\n")
|
||||
if err := parseIP(attr.Msg, tuple); err != nil {
|
||||
return err
|
||||
}
|
||||
case CtaTupleProto:
|
||||
// fmt.Printf("It's a tuple proto\n")
|
||||
parseProto(attr.Msg, tuple)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseCounters(b []byte) (uint64, uint64, error) {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
packets := uint64(0)
|
||||
bytes := uint64(0)
|
||||
for _, attr := range attrs {
|
||||
switch CtattrCounters(attr.Typ) {
|
||||
case CtaCountersPackets:
|
||||
packets = binary.BigEndian.Uint64(attr.Msg)
|
||||
case CtaCountersBytes:
|
||||
bytes = binary.BigEndian.Uint64(attr.Msg)
|
||||
}
|
||||
}
|
||||
return packets, bytes, nil
|
||||
}
|
||||
|
||||
func parseIP(b []byte, tuple *Tuple) error {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
switch CtattrIp(attr.Typ) {
|
||||
case CtaIpV4Src:
|
||||
tuple.Src = make(net.IP, len(attr.Msg))
|
||||
copy(tuple.Src, attr.Msg)
|
||||
case CtaIpV4Dst:
|
||||
tuple.Dst = make(net.IP, len(attr.Msg))
|
||||
copy(tuple.Dst, attr.Msg)
|
||||
case CtaIpV6Src:
|
||||
// TODO
|
||||
case CtaIpV6Dst:
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseProto(b []byte, tuple *Tuple) error {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
switch CtattrL4proto(attr.Typ) {
|
||||
// Protocol number.
|
||||
case CtaProtoNum:
|
||||
tuple.Proto = int(uint8(attr.Msg[0]))
|
||||
|
||||
// TCP stuff.
|
||||
case CtaProtoSrcPort:
|
||||
tuple.SrcPort = binary.BigEndian.Uint16(attr.Msg)
|
||||
case CtaProtoDstPort:
|
||||
tuple.DstPort = binary.BigEndian.Uint16(attr.Msg)
|
||||
|
||||
// ICMP stuff.
|
||||
case CtaProtoIcmpId:
|
||||
tuple.IcmpId = binary.BigEndian.Uint16(attr.Msg)
|
||||
case CtaProtoIcmpType:
|
||||
tuple.IcmpType = attr.Msg[0]
|
||||
case CtaProtoIcmpCode:
|
||||
tuple.IcmpCode = attr.Msg[0]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseProtoinfo(b []byte, conn *Conn) error {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
switch CtattrProtoinfo(attr.Typ) {
|
||||
case CtaProtoinfoTcp:
|
||||
if err := parseProtoinfoTCP(attr.Msg, conn); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
// we're not interested in other protocols
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseProtoinfoTCP(b []byte, conn *Conn) error {
|
||||
attrs, err := parseAttrs(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tuple attr: %s", err)
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
switch CtattrProtoinfoTcp(attr.Typ) {
|
||||
case CtaProtoinfoTcpState:
|
||||
conn.TCPState = tcpState[uint8(attr.Msg[0])]
|
||||
default:
|
||||
// not interested
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
145
vendor/github.com/typetypetype/conntrack/conntrack.go
generated
vendored
Normal file
145
vendor/github.com/typetypetype/conntrack/conntrack.go
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
package conntrack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ConnTCP is a connection
|
||||
type ConnTCP struct {
|
||||
Local string // net.IP
|
||||
LocalPort string // int
|
||||
Remote string // net.IP
|
||||
RemotePort string // int
|
||||
}
|
||||
|
||||
func (c ConnTCP) String() string {
|
||||
return fmt.Sprintf("%s:%s->%s:%s", c.Local, c.LocalPort, c.Remote, c.RemotePort)
|
||||
}
|
||||
|
||||
// ConnTrack monitors the connections. It is build with Established() and
|
||||
// Follow().
|
||||
type ConnTrack struct {
|
||||
connReq chan chan []ConnTCP
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
// New returns a ConnTrack.
|
||||
func New() (*ConnTrack, error) {
|
||||
c := ConnTrack{
|
||||
connReq: make(chan chan []ConnTCP),
|
||||
quit: make(chan struct{}),
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
err := c.track()
|
||||
select {
|
||||
case <-c.quit:
|
||||
return
|
||||
default:
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("conntrack: %s\n", err)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// Close stops all monitoring and executables.
|
||||
func (c ConnTrack) Close() {
|
||||
close(c.quit)
|
||||
}
|
||||
|
||||
// Connections returns the list of all connections seen since last time you
|
||||
// called it.
|
||||
func (c *ConnTrack) Connections() []ConnTCP {
|
||||
r := make(chan []ConnTCP)
|
||||
c.connReq <- r
|
||||
return <-r
|
||||
}
|
||||
|
||||
// track is the main loop
|
||||
func (c *ConnTrack) track() error {
|
||||
// We use Follow() to keep track of conn state changes, but it doesn't give
|
||||
// us the initial state. If we first look at the established connections
|
||||
// and then start the follow process we might miss events.
|
||||
var flags uint32 = NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_UPDATE |
|
||||
NF_NETLINK_CONNTRACK_DESTROY
|
||||
events, stop, err := Follow(flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
established := map[ConnTCP]struct{}{}
|
||||
cs, err := Established()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, c := range cs {
|
||||
established[c] = struct{}{}
|
||||
}
|
||||
// we keep track of deleted so we can report them
|
||||
deleted := map[ConnTCP]struct{}{}
|
||||
|
||||
local := localIPs()
|
||||
updateLocalIPs := time.Tick(time.Minute)
|
||||
|
||||
for {
|
||||
select {
|
||||
|
||||
case <-c.quit:
|
||||
stop()
|
||||
return nil
|
||||
|
||||
case <-updateLocalIPs:
|
||||
local = localIPs()
|
||||
|
||||
case e, ok := <-events:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
switch {
|
||||
|
||||
default:
|
||||
// not interested
|
||||
|
||||
case e.TCPState == "ESTABLISHED":
|
||||
cn := e.ConnTCP(local)
|
||||
if cn == nil {
|
||||
// log.Printf("not a local connection: %+v\n", e)
|
||||
continue
|
||||
}
|
||||
established[*cn] = struct{}{}
|
||||
|
||||
case e.MsgType == NfctMsgDestroy, e.TCPState == "TIME_WAIT", e.TCPState == "CLOSE":
|
||||
cn := e.ConnTCP(local)
|
||||
if cn == nil {
|
||||
// log.Printf("not a local connection: %+v\n", e)
|
||||
continue
|
||||
}
|
||||
if _, ok := established[*cn]; !ok {
|
||||
continue
|
||||
}
|
||||
delete(established, *cn)
|
||||
deleted[*cn] = struct{}{}
|
||||
|
||||
}
|
||||
|
||||
case r := <-c.connReq:
|
||||
cs := make([]ConnTCP, 0, len(established)+len(deleted))
|
||||
for c := range established {
|
||||
cs = append(cs, c)
|
||||
}
|
||||
for c := range deleted {
|
||||
cs = append(cs, c)
|
||||
}
|
||||
r <- cs
|
||||
deleted = map[ConnTCP]struct{}{}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
69
vendor/github.com/typetypetype/conntrack/const.go
generated
vendored
Normal file
69
vendor/github.com/typetypetype/conntrack/const.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package conntrack
|
||||
|
||||
const (
|
||||
// #defined in libnfnetlink/include/libnfnetlink/linux_nfnetlink.h
|
||||
NFNL_SUBSYS_CTNETLINK = 1
|
||||
NFNETLINK_V0 = 0
|
||||
|
||||
// #defined in libnfnetlink/include/libnfnetlink/linux_nfnetlink_compat.h
|
||||
NF_NETLINK_CONNTRACK_NEW = 0x00000001
|
||||
NF_NETLINK_CONNTRACK_UPDATE = 0x00000002
|
||||
NF_NETLINK_CONNTRACK_DESTROY = 0x00000004
|
||||
NF_NETLINK_CONNTRACK_EXP_NEW = 0x00000008
|
||||
NF_NETLINK_CONNTRACK_EXP_UPDATE = 0x00000010
|
||||
NF_NETLINK_CONNTRACK_EXP_DESTROY = 0x00000020
|
||||
|
||||
// #defined in libnfnetlink/include/libnfnetlink/libnfnetlink.h
|
||||
NLA_F_NESTED = uint16(1 << 15)
|
||||
NLA_F_NET_BYTEORDER = uint16(1 << 14)
|
||||
NLA_TYPE_MASK = ^(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
|
||||
)
|
||||
|
||||
type NfConntrackMsg int
|
||||
|
||||
const (
|
||||
NfctMsgUnknown NfConntrackMsg = 0
|
||||
NfctMsgNew NfConntrackMsg = 1 << 0
|
||||
NfctMsgUpdate NfConntrackMsg = 1 << 1
|
||||
NfctMsgDestroy NfConntrackMsg = 1 << 2
|
||||
)
|
||||
|
||||
// taken from libnetfilter_conntrack/src/conntrack/snprintf.c
|
||||
var tcpState = []string{
|
||||
"NONE",
|
||||
"SYN_SENT",
|
||||
"SYN_RECV",
|
||||
"ESTABLISHED",
|
||||
"FIN_WAIT",
|
||||
"CLOSE_WAIT",
|
||||
"LAST_ACK",
|
||||
"TIME_WAIT",
|
||||
"CLOSE",
|
||||
"LISTEN",
|
||||
"MAX",
|
||||
"IGNORE",
|
||||
}
|
||||
|
||||
// Taken from include/uapi/linux/netfilter/nf_conntrack_common.h
|
||||
type CtStatus uint32
|
||||
|
||||
const (
|
||||
IPS_EXPECTED CtStatus = 1 << iota
|
||||
IPS_SEEN_REPLY
|
||||
IPS_ASSURED
|
||||
IPS_CONFIRMED
|
||||
IPS_SRC_NAT
|
||||
IPS_DST_NAT
|
||||
IPS_SEQ_ADJUST
|
||||
IPS_SRC_NAT_DONE
|
||||
IPS_DST_NAT_DONE
|
||||
IPS_DYING
|
||||
IPS_FIXED_TIMEOUT
|
||||
IPS_TEMPLATE
|
||||
IPS_UNTRACKED
|
||||
IPS_HELPER
|
||||
IPS_OFFLOAD
|
||||
|
||||
IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT)
|
||||
IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE)
|
||||
)
|
||||
131
vendor/github.com/typetypetype/conntrack/headers.go
generated
vendored
Normal file
131
vendor/github.com/typetypetype/conntrack/headers.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
package conntrack
|
||||
|
||||
// code generated by enum2go.
|
||||
|
||||
type CtattrType int
|
||||
const (
|
||||
CtaUnspec CtattrType = 0
|
||||
CtaTupleOrig CtattrType = 1
|
||||
CtaTupleReply CtattrType = 2
|
||||
CtaStatus CtattrType = 3
|
||||
CtaProtoinfo CtattrType = 4
|
||||
CtaHelp CtattrType = 5
|
||||
CtaNatSrc CtattrType = 6
|
||||
CtaTimeout CtattrType = 7
|
||||
CtaMark CtattrType = 8
|
||||
CtaCountersOrig CtattrType = 9
|
||||
CtaCountersReply CtattrType = 10
|
||||
CtaUse CtattrType = 11
|
||||
CtaId CtattrType = 12
|
||||
CtaNatDst CtattrType = 13
|
||||
CtaTupleMaster CtattrType = 14
|
||||
CtaNatSeqAdjOrig CtattrType = 15
|
||||
CtaNatSeqAdjReply CtattrType = 16
|
||||
CtaSecmark CtattrType = 17
|
||||
CtaZone CtattrType = 18
|
||||
CtaSecctx CtattrType = 19
|
||||
CtaTimestamp CtattrType = 20
|
||||
CtaMarkMask CtattrType = 21
|
||||
CtaLabels CtattrType = 22
|
||||
CtaLabelsMask CtattrType = 23
|
||||
CtaMax CtattrType = 24
|
||||
)
|
||||
|
||||
type CtattrTuple int
|
||||
const (
|
||||
CtaTupleUnspec CtattrTuple = 0
|
||||
CtaTupleIp CtattrTuple = 1
|
||||
CtaTupleProto CtattrTuple = 2
|
||||
CtaTupleMax CtattrTuple = 3
|
||||
)
|
||||
|
||||
type CtattrCounters int
|
||||
const (
|
||||
CtaCountersUnspec CtattrCounters = 0
|
||||
CtaCountersPackets CtattrCounters = 1 /* 64bit counters */
|
||||
CtaCountersBytes CtattrCounters = 2 /* 64bit counters */
|
||||
CtaCounters32Packets CtattrCounters = 3 /* old 32bit counters, unused */
|
||||
CtaCounters32Bytes CtattrCounters = 4 /* old 32bit counters, unused */
|
||||
CtaCountersMax CtattrCounters = 5
|
||||
)
|
||||
|
||||
type CtattrIp int
|
||||
const (
|
||||
CtaIpUnspec CtattrIp = 0
|
||||
CtaIpV4Src CtattrIp = 1
|
||||
CtaIpV4Dst CtattrIp = 2
|
||||
CtaIpV6Src CtattrIp = 3
|
||||
CtaIpV6Dst CtattrIp = 4
|
||||
CtaIpMax CtattrIp = 5
|
||||
)
|
||||
|
||||
type CtattrL4proto int
|
||||
const (
|
||||
CtaProtoUnspec CtattrL4proto = 0
|
||||
CtaProtoNum CtattrL4proto = 1
|
||||
CtaProtoSrcPort CtattrL4proto = 2
|
||||
CtaProtoDstPort CtattrL4proto = 3
|
||||
CtaProtoIcmpId CtattrL4proto = 4
|
||||
CtaProtoIcmpType CtattrL4proto = 5
|
||||
CtaProtoIcmpCode CtattrL4proto = 6
|
||||
CtaProtoIcmpv6Id CtattrL4proto = 7
|
||||
CtaProtoIcmpv6Type CtattrL4proto = 8
|
||||
CtaProtoIcmpv6Code CtattrL4proto = 9
|
||||
CtaProtoMax CtattrL4proto = 10
|
||||
)
|
||||
|
||||
type CtattrProtoinfo int
|
||||
const (
|
||||
CtaProtoinfoUnspec CtattrProtoinfo = 0
|
||||
CtaProtoinfoTcp CtattrProtoinfo = 1
|
||||
CtaProtoinfoDccp CtattrProtoinfo = 2
|
||||
CtaProtoinfoSctp CtattrProtoinfo = 3
|
||||
CtaProtoinfoMax CtattrProtoinfo = 4
|
||||
)
|
||||
|
||||
type CtattrProtoinfoTcp int
|
||||
const (
|
||||
CtaProtoinfoTcpUnspec CtattrProtoinfoTcp = 0
|
||||
CtaProtoinfoTcpState CtattrProtoinfoTcp = 1
|
||||
CtaProtoinfoTcpWscaleOriginal CtattrProtoinfoTcp = 2
|
||||
CtaProtoinfoTcpWscaleReply CtattrProtoinfoTcp = 3
|
||||
CtaProtoinfoTcpFlagsOriginal CtattrProtoinfoTcp = 4
|
||||
CtaProtoinfoTcpFlagsReply CtattrProtoinfoTcp = 5
|
||||
CtaProtoinfoTcpMax CtattrProtoinfoTcp = 6
|
||||
)
|
||||
|
||||
type NfConntrackAttrGrp int
|
||||
const (
|
||||
AttrGrpOrigIpv4 NfConntrackAttrGrp = 0
|
||||
AttrGrpReplIpv4 NfConntrackAttrGrp = 1
|
||||
AttrGrpOrigIpv6 NfConntrackAttrGrp = 2
|
||||
AttrGrpReplIpv6 NfConntrackAttrGrp = 3
|
||||
AttrGrpOrigPort NfConntrackAttrGrp = 4
|
||||
AttrGrpReplPort NfConntrackAttrGrp = 5
|
||||
AttrGrpIcmp NfConntrackAttrGrp = 6
|
||||
AttrGrpMasterIpv4 NfConntrackAttrGrp = 7
|
||||
AttrGrpMasterIpv6 NfConntrackAttrGrp = 8
|
||||
AttrGrpMasterPort NfConntrackAttrGrp = 9
|
||||
AttrGrpOrigCounters NfConntrackAttrGrp = 10
|
||||
AttrGrpReplCounters NfConntrackAttrGrp = 11
|
||||
AttrGrpOrigAddrSrc NfConntrackAttrGrp = 12
|
||||
AttrGrpOrigAddrDst NfConntrackAttrGrp = 13
|
||||
AttrGrpReplAddrSrc NfConntrackAttrGrp = 14
|
||||
AttrGrpReplAddrDst NfConntrackAttrGrp = 15
|
||||
AttrGrpMax NfConntrackAttrGrp = 16
|
||||
)
|
||||
|
||||
type NfConntrackQuery int
|
||||
const (
|
||||
NfctQCreate NfConntrackQuery = 0
|
||||
NfctQUpdate NfConntrackQuery = 1
|
||||
NfctQDestroy NfConntrackQuery = 2
|
||||
NfctQGet NfConntrackQuery = 3
|
||||
NfctQFlush NfConntrackQuery = 4
|
||||
NfctQDump NfConntrackQuery = 5
|
||||
NfctQDumpReset NfConntrackQuery = 6
|
||||
NfctQCreateUpdate NfConntrackQuery = 7
|
||||
NfctQDumpFilter NfConntrackQuery = 8
|
||||
NfctQDumpFilterReset NfConntrackQuery = 9
|
||||
)
|
||||
|
||||
16
vendor/github.com/typetypetype/conntrack/linux_headers.go
generated
vendored
Normal file
16
vendor/github.com/typetypetype/conntrack/linux_headers.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package conntrack
|
||||
|
||||
// code generated by enum2go, from file "linux_nfnetlink_conntrack.h".
|
||||
|
||||
type CntlMsgTypes int
|
||||
const (
|
||||
IpctnlMsgCtNew CntlMsgTypes = 0
|
||||
IpctnlMsgCtGet CntlMsgTypes = 1
|
||||
IpctnlMsgCtDelete CntlMsgTypes = 2
|
||||
IpctnlMsgCtGetCtrzero CntlMsgTypes = 3
|
||||
IpctnlMsgCtGetStatsCpu CntlMsgTypes = 4
|
||||
IpctnlMsgCtGetStats CntlMsgTypes = 5
|
||||
IpctnlMsgCtGetDying CntlMsgTypes = 6
|
||||
IpctnlMsgCtGetUnconfirmed CntlMsgTypes = 7
|
||||
IpctnlMsgMax CntlMsgTypes = 8
|
||||
)
|
||||
19
vendor/github.com/typetypetype/conntrack/net.go
generated
vendored
Normal file
19
vendor/github.com/typetypetype/conntrack/net.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package conntrack
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// localIPs gives all IPs we consider local.
|
||||
func localIPs() map[string]struct{} {
|
||||
var l = map[string]struct{}{}
|
||||
if localNets, err := net.InterfaceAddrs(); err == nil {
|
||||
// Not all networks are IP networks.
|
||||
for _, localNet := range localNets {
|
||||
if net, ok := localNet.(*net.IPNet); ok {
|
||||
l[net.IP.String()] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
return l
|
||||
}
|
||||
21
vendor/github.com/typetypetype/conntrack/netlink.go
generated
vendored
Normal file
21
vendor/github.com/typetypetype/conntrack/netlink.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package conntrack
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// NFNL_MSG_TYPE
|
||||
func nflnMsgType(x uint16) uint8 {
|
||||
return uint8(x & 0x00ff)
|
||||
}
|
||||
|
||||
// NFNL_SUBSYS_ID
|
||||
func nflnSubsysID(x uint16) uint8 {
|
||||
return uint8((x & 0xff00) >> 8)
|
||||
}
|
||||
|
||||
// Round the length of a netlink route attribute up to align it
|
||||
// properly.
|
||||
func rtaAlignOf(attrlen int) int {
|
||||
return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
|
||||
}
|
||||
45
vendor/github.com/typetypetype/conntrack/netlink_attr.go
generated
vendored
Normal file
45
vendor/github.com/typetypetype/conntrack/netlink_attr.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
package conntrack
|
||||
|
||||
// Netlink attr parsing.
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const attrHdrLength = 4
|
||||
|
||||
type Attr struct {
|
||||
Msg []byte
|
||||
Typ int
|
||||
IsNested bool
|
||||
IsNetByteorder bool
|
||||
}
|
||||
|
||||
func parseAttrs(b []byte) ([]Attr, error) {
|
||||
var attrs []Attr
|
||||
for len(b) >= attrHdrLength {
|
||||
var attr Attr
|
||||
attr, b = parseAttr(b)
|
||||
attrs = append(attrs, attr)
|
||||
}
|
||||
if len(b) != 0 {
|
||||
return nil, errors.New("leftover attr bytes")
|
||||
}
|
||||
return attrs, nil
|
||||
}
|
||||
|
||||
func parseAttr(b []byte) (Attr, []byte) {
|
||||
l := binary.LittleEndian.Uint16(b[0:2])
|
||||
// length is header + payload
|
||||
l -= uint16(attrHdrLength)
|
||||
|
||||
typ := binary.LittleEndian.Uint16(b[2:4])
|
||||
attr := Attr{
|
||||
Msg: b[attrHdrLength : attrHdrLength+int(l)],
|
||||
Typ: int(typ & NLA_TYPE_MASK),
|
||||
IsNested: typ&NLA_F_NESTED > 0,
|
||||
IsNetByteorder: typ&NLA_F_NET_BYTEORDER > 0,
|
||||
}
|
||||
return attr, b[rtaAlignOf(attrHdrLength+int(l)):]
|
||||
}
|
||||
Reference in New Issue
Block a user