mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 01:15:41 +08:00
ipset: use github.com/nadoo/ipset package
This commit is contained in:
parent
04c65fb444
commit
93a7677a94
@ -363,6 +363,7 @@ glider -config CONFIGPATH -listen :8080 -verbose
|
||||
|
||||
## Links
|
||||
|
||||
- [ipset](https://github.com/nadoo/ipset): ipset package for Go via netlink socket
|
||||
- [conflag](https://github.com/nadoo/conflag): command line and config file parse support
|
||||
- [ArchLinux](https://www.archlinux.org/packages/community/x86_64/glider): a great linux distribution with glider pre-built package
|
||||
- [urlencode](https://www.w3schools.com/tags/ref_urlencode.asp): you should encode special characters in scheme url. e.g: `@`->`%40`
|
||||
|
@ -13,8 +13,8 @@ import (
|
||||
"github.com/nadoo/glider/proxy"
|
||||
)
|
||||
|
||||
// HandleFunc function handles the dns TypeA or TypeAAAA answer.
|
||||
type HandleFunc func(domain, ip string) error
|
||||
// AnswerHandler function handles the dns TypeA or TypeAAAA answer.
|
||||
type AnswerHandler func(domain, ip string) error
|
||||
|
||||
// Config for dns.
|
||||
type Config struct {
|
||||
@ -33,7 +33,7 @@ type Client struct {
|
||||
config *Config
|
||||
upStream *UPStream
|
||||
upStreamMap map[string]*UPStream
|
||||
handlers []HandleFunc
|
||||
handlers []AnswerHandler
|
||||
}
|
||||
|
||||
// NewClient returns a new dns client.
|
||||
@ -249,7 +249,7 @@ func (c *Client) UpStream(domain string) *UPStream {
|
||||
}
|
||||
|
||||
// AddHandler adds a custom handler to handle the resolved result (A and AAAA).
|
||||
func (c *Client) AddHandler(h HandleFunc) {
|
||||
func (c *Client) AddHandler(h AnswerHandler) {
|
||||
c.handlers = append(c.handlers, h)
|
||||
}
|
||||
|
||||
|
5
go.mod
5
go.mod
@ -6,13 +6,14 @@ require (
|
||||
github.com/mzz2017/shadowsocksR v1.0.0
|
||||
github.com/nadoo/conflag v0.2.3
|
||||
github.com/nadoo/go-shadowsocks2 v0.1.2
|
||||
github.com/nadoo/ipset v0.2.0
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/xtaci/kcp-go/v5 v5.5.15
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
||||
golang.org/x/net v0.0.0-20200923182212-328152dc79b1 // indirect
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect
|
||||
golang.org/x/tools v0.0.0-20200923182640-463111b69878 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
golang.org/x/tools v0.0.0-20200924224222-8d73f17870ce // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||
)
|
||||
|
||||
// Replace dependency modules with local developing copy
|
||||
|
10
go.sum
10
go.sum
@ -38,6 +38,10 @@ github.com/nadoo/glider v0.9.2/go.mod h1:S/94KRJFNtgoNlyEm4+33f/DrEsj/uxvismOW4F
|
||||
github.com/nadoo/glider v0.10.0/go.mod h1:q5d4Q5yoGk3nLAhshDJalnl0NXJ8Xh4ODEgp+qbdAAg=
|
||||
github.com/nadoo/go-shadowsocks2 v0.1.2 h1:+tCSt65YAAMf24wj3tqv6a9oVBcqSGFYVsifBZwT9w8=
|
||||
github.com/nadoo/go-shadowsocks2 v0.1.2/go.mod h1:/E2kSkS0mqF/e79wcAA0PezoWXk4CY9HldJlzwWtbwU=
|
||||
github.com/nadoo/ipset v0.1.0 h1:z/rWPoIle8g9PjD/vlsL3h4c++zMRw+Qcq2wjxMZSkU=
|
||||
github.com/nadoo/ipset v0.1.0/go.mod h1:ugJe3mH5N1UNQbXayGJnLEMALeiwCJYo49Wg4MnZTHU=
|
||||
github.com/nadoo/ipset v0.2.0 h1:J5dXbW3ntSou3f5vkpnfk6S05u0KvLhzJwGHEiWEtl4=
|
||||
github.com/nadoo/ipset v0.2.0/go.mod h1:ugJe3mH5N1UNQbXayGJnLEMALeiwCJYo49Wg4MnZTHU=
|
||||
github.com/nadoo/shadowsocksR v0.1.0 h1:sYPxZi0l8F1nxDDcckzb0DHXxhe0LNW5iSeohqPw6Fg=
|
||||
github.com/nadoo/shadowsocksR v0.1.0/go.mod h1:nqcLRU7laARXdLLBrHP8odruT/6GIureicuRTs4R+RY=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
@ -127,8 +131,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU=
|
||||
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200923182640-463111b69878 h1:VUw1+Jf6KJPf82mbTQMia6HCnNMv2BbAipkEZ4KTcqQ=
|
||||
golang.org/x/tools v0.0.0-20200923182640-463111b69878/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20200924224222-8d73f17870ce h1:XRr763sMfaUSNR4EsxbddvVEqYFa9picrx6ks9pJkKw=
|
||||
golang.org/x/tools v0.0.0-20200924224222-8d73f17870ce/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
@ -139,6 +143,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
@ -1,102 +1,25 @@
|
||||
// Apache License 2.0
|
||||
// @mdlayher https://github.com/mdlayher/netlink
|
||||
// Ref: https://github.com/vishvananda/netlink/blob/master/nl/nl_linux.go
|
||||
|
||||
package ipset
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/nadoo/glider/common/log"
|
||||
ipsetlib "github.com/nadoo/ipset"
|
||||
|
||||
"github.com/nadoo/glider/rule"
|
||||
)
|
||||
|
||||
// NFNL_SUBSYS_IPSET netfilter netlink message types
|
||||
// https://github.com/torvalds/linux/blob/9e66317d3c92ddaab330c125dfe9d06eee268aff/include/uapi/linux/netfilter/nfnetlink.h#L56
|
||||
const NFNL_SUBSYS_IPSET = 6
|
||||
|
||||
// IPSET_PROTOCOL The protocol version
|
||||
// http://git.netfilter.org/ipset/tree/include/libipset/linux_ip_set.h
|
||||
const IPSET_PROTOCOL = 6
|
||||
|
||||
// IPSET_MAXNAMELEN The max length of strings including NUL: set and type identifiers
|
||||
const IPSET_MAXNAMELEN = 32
|
||||
|
||||
// Message types and commands
|
||||
const (
|
||||
IPSET_CMD_CREATE = 2
|
||||
IPSET_CMD_FLUSH = 4
|
||||
IPSET_CMD_ADD = 9
|
||||
IPSET_CMD_DEL = 10
|
||||
)
|
||||
|
||||
// Attributes at command level
|
||||
const (
|
||||
IPSET_ATTR_PROTOCOL = 1 /* 1: Protocol version */
|
||||
IPSET_ATTR_SETNAME = 2 /* 2: Name of the set */
|
||||
IPSET_ATTR_TYPENAME = 3 /* 3: Typename */
|
||||
IPSET_ATTR_REVISION = 4 /* 4: Settype revision */
|
||||
IPSET_ATTR_FAMILY = 5 /* 5: Settype family */
|
||||
IPSET_ATTR_DATA = 7 /* 7: Nested attributes */
|
||||
)
|
||||
|
||||
// CADT specific attributes
|
||||
const (
|
||||
IPSET_ATTR_IP = 1
|
||||
IPSET_ATTR_CIDR = 3
|
||||
)
|
||||
|
||||
// IP specific attributes
|
||||
const (
|
||||
IPSET_ATTR_IPADDR_IPV4 = 1
|
||||
IPSET_ATTR_IPADDR_IPV6 = 2
|
||||
)
|
||||
|
||||
// ATTR flags
|
||||
const (
|
||||
NLA_F_NESTED = (1 << 15)
|
||||
NLA_F_NET_BYTEORDER = (1 << 14)
|
||||
)
|
||||
|
||||
var nextSeqNr uint32
|
||||
var nativeEndian binary.ByteOrder
|
||||
|
||||
// Manager struct
|
||||
// Manager struct.
|
||||
type Manager struct {
|
||||
fd int
|
||||
lsa syscall.SockaddrNetlink
|
||||
|
||||
domainSet sync.Map
|
||||
}
|
||||
|
||||
// NewManager returns a Manager
|
||||
func NewManager(rules []*rule.Config) (*Manager, error) {
|
||||
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_NETFILTER)
|
||||
if err != nil {
|
||||
log.F("%s", err)
|
||||
if err := ipsetlib.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// defer syscall.Close(fd)
|
||||
|
||||
lsa := syscall.SockaddrNetlink{
|
||||
Family: syscall.AF_NETLINK,
|
||||
}
|
||||
|
||||
err = syscall.Bind(fd, &lsa)
|
||||
if err != nil {
|
||||
log.F("%s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := &Manager{fd: fd, lsa: lsa}
|
||||
|
||||
// create ipset, avoid redundant.
|
||||
sets := make(map[string]struct{})
|
||||
@ -107,20 +30,22 @@ func NewManager(rules []*rule.Config) (*Manager, error) {
|
||||
}
|
||||
|
||||
for set := range sets {
|
||||
CreateSet(fd, lsa, set)
|
||||
ipsetlib.Create(set)
|
||||
ipsetlib.Flush(set)
|
||||
}
|
||||
|
||||
// init ipset
|
||||
m := &Manager{}
|
||||
for _, r := range rules {
|
||||
if r.IPSet != "" {
|
||||
for _, domain := range r.Domain {
|
||||
m.domainSet.Store(domain, r.IPSet)
|
||||
}
|
||||
for _, ip := range r.IP {
|
||||
AddToSet(fd, lsa, r.IPSet, ip)
|
||||
ipsetlib.Add(r.IPSet, ip)
|
||||
}
|
||||
for _, cidr := range r.CIDR {
|
||||
AddToSet(fd, lsa, r.IPSet, cidr)
|
||||
ipsetlib.Add(r.IPSet, cidr)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,352 +53,19 @@ func NewManager(rules []*rule.Config) (*Manager, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// AddDomainIP implements the DNSAnswerHandler function, used to update ipset according to domainSet rule
|
||||
// AddDomainIP implements the dns AnswerHandler function, used to update ipset according to domainSet rule.
|
||||
func (m *Manager) AddDomainIP(domain, ip string) error {
|
||||
if domain == "" || ip == "" {
|
||||
return errors.New("please specify the domain and ip address")
|
||||
}
|
||||
|
||||
domain = strings.ToLower(domain)
|
||||
for i := len(domain); i != -1; {
|
||||
i = strings.LastIndexByte(domain[:i], '.')
|
||||
if ipset, ok := m.domainSet.Load(domain[i+1:]); ok {
|
||||
AddToSet(m.fd, m.lsa, ipset.(string), ip)
|
||||
ipsetlib.Add(ipset.(string), ip)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateSet create a ipset
|
||||
func CreateSet(fd int, lsa syscall.SockaddrNetlink, setName string) {
|
||||
if setName == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if len(setName) > IPSET_MAXNAMELEN {
|
||||
log.Fatal("ipset: name too long")
|
||||
}
|
||||
|
||||
log.F("ipset create %s hash:net", setName)
|
||||
|
||||
req := NewNetlinkRequest(IPSET_CMD_CREATE|(NFNL_SUBSYS_IPSET<<8), syscall.NLM_F_REQUEST)
|
||||
|
||||
// TODO: support AF_INET6
|
||||
req.AddData(NewNfGenMsg(syscall.AF_INET, 0, 0))
|
||||
req.AddData(NewRtAttr(IPSET_ATTR_PROTOCOL, Uint8Attr(IPSET_PROTOCOL)))
|
||||
req.AddData(NewRtAttr(IPSET_ATTR_SETNAME, ZeroTerminated(setName)))
|
||||
req.AddData(NewRtAttr(IPSET_ATTR_TYPENAME, ZeroTerminated("hash:net")))
|
||||
req.AddData(NewRtAttr(IPSET_ATTR_REVISION, Uint8Attr(1)))
|
||||
req.AddData(NewRtAttr(IPSET_ATTR_FAMILY, Uint8Attr(2)))
|
||||
req.AddData(NewRtAttr(IPSET_ATTR_DATA|NLA_F_NESTED, nil))
|
||||
|
||||
err := syscall.Sendto(fd, req.Serialize(), 0, &lsa)
|
||||
if err != nil {
|
||||
log.F("%s", err)
|
||||
}
|
||||
|
||||
FlushSet(fd, lsa, setName)
|
||||
}
|
||||
|
||||
// FlushSet flush a ipset
|
||||
func FlushSet(fd int, lsa syscall.SockaddrNetlink, setName string) {
|
||||
log.F("ipset flush %s", setName)
|
||||
|
||||
req := NewNetlinkRequest(IPSET_CMD_FLUSH|(NFNL_SUBSYS_IPSET<<8), syscall.NLM_F_REQUEST)
|
||||
|
||||
// TODO: support AF_INET6
|
||||
req.AddData(NewNfGenMsg(syscall.AF_INET, 0, 0))
|
||||
req.AddData(NewRtAttr(IPSET_ATTR_PROTOCOL, Uint8Attr(IPSET_PROTOCOL)))
|
||||
req.AddData(NewRtAttr(IPSET_ATTR_SETNAME, ZeroTerminated(setName)))
|
||||
|
||||
err := syscall.Sendto(fd, req.Serialize(), 0, &lsa)
|
||||
if err != nil {
|
||||
log.F("%s", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// AddToSet adds an entry to ipset
|
||||
func AddToSet(fd int, lsa syscall.SockaddrNetlink, setName, entry string) {
|
||||
if setName == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if len(setName) > IPSET_MAXNAMELEN {
|
||||
log.F("ipset: name too long")
|
||||
}
|
||||
|
||||
log.F("ipset add %s %s", setName, entry)
|
||||
|
||||
var ip net.IP
|
||||
var cidr *net.IPNet
|
||||
|
||||
ip, cidr, err := net.ParseCIDR(entry)
|
||||
if err != nil {
|
||||
ip = net.ParseIP(entry)
|
||||
}
|
||||
|
||||
if ip == nil {
|
||||
log.F("ipset: parse %s error", entry)
|
||||
return
|
||||
}
|
||||
|
||||
req := NewNetlinkRequest(IPSET_CMD_ADD|(NFNL_SUBSYS_IPSET<<8), syscall.NLM_F_REQUEST)
|
||||
|
||||
// TODO: support AF_INET6
|
||||
req.AddData(NewNfGenMsg(syscall.AF_INET, 0, 0))
|
||||
req.AddData(NewRtAttr(IPSET_ATTR_PROTOCOL, Uint8Attr(IPSET_PROTOCOL)))
|
||||
req.AddData(NewRtAttr(IPSET_ATTR_SETNAME, ZeroTerminated(setName)))
|
||||
|
||||
attrNested := NewRtAttr(IPSET_ATTR_DATA|NLA_F_NESTED, nil)
|
||||
attrIP := NewRtAttrChild(attrNested, IPSET_ATTR_IP|NLA_F_NESTED, nil)
|
||||
|
||||
// TODO: support ipV6
|
||||
NewRtAttrChild(attrIP, IPSET_ATTR_IPADDR_IPV4|NLA_F_NET_BYTEORDER, ip.To4())
|
||||
|
||||
// for cidr prefix
|
||||
if cidr != nil {
|
||||
cidrPrefix, _ := cidr.Mask.Size()
|
||||
NewRtAttrChild(attrNested, IPSET_ATTR_CIDR, Uint8Attr(uint8(cidrPrefix)))
|
||||
}
|
||||
|
||||
NewRtAttrChild(attrNested, 9|NLA_F_NET_BYTEORDER, Uint32Attr(0))
|
||||
req.AddData(attrNested)
|
||||
|
||||
err = syscall.Sendto(fd, req.Serialize(), 0, &lsa)
|
||||
if err != nil {
|
||||
log.F("%s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// NativeEndian get native endianness for the system
|
||||
func NativeEndian() binary.ByteOrder {
|
||||
if nativeEndian == nil {
|
||||
var x uint32 = 0x01020304
|
||||
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
||||
nativeEndian = binary.BigEndian
|
||||
} else {
|
||||
nativeEndian = binary.LittleEndian
|
||||
}
|
||||
}
|
||||
return nativeEndian
|
||||
}
|
||||
|
||||
func rtaAlignOf(attrlen int) int {
|
||||
return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
|
||||
}
|
||||
|
||||
// NetlinkRequestData .
|
||||
type NetlinkRequestData interface {
|
||||
Len() int
|
||||
Serialize() []byte
|
||||
}
|
||||
|
||||
// NfGenMsg .
|
||||
type NfGenMsg struct {
|
||||
nfgenFamily uint8
|
||||
version uint8
|
||||
resID uint16
|
||||
}
|
||||
|
||||
// NewNfGenMsg .
|
||||
func NewNfGenMsg(nfgenFamily, version, resID int) *NfGenMsg {
|
||||
return &NfGenMsg{
|
||||
nfgenFamily: uint8(nfgenFamily),
|
||||
version: uint8(version),
|
||||
resID: uint16(resID),
|
||||
}
|
||||
}
|
||||
|
||||
// Len .
|
||||
func (m *NfGenMsg) Len() int {
|
||||
return rtaAlignOf(4)
|
||||
}
|
||||
|
||||
// Serialize .
|
||||
func (m *NfGenMsg) Serialize() []byte {
|
||||
native := NativeEndian()
|
||||
|
||||
length := m.Len()
|
||||
buf := make([]byte, rtaAlignOf(length))
|
||||
buf[0] = m.nfgenFamily
|
||||
buf[1] = m.version
|
||||
native.PutUint16(buf[2:4], m.resID)
|
||||
return buf
|
||||
}
|
||||
|
||||
// RtAttr Extend RtAttr to handle data and children
|
||||
type RtAttr struct {
|
||||
syscall.RtAttr
|
||||
Data []byte
|
||||
children []NetlinkRequestData
|
||||
}
|
||||
|
||||
// NewRtAttr Create a new Extended RtAttr object
|
||||
func NewRtAttr(attrType int, data []byte) *RtAttr {
|
||||
return &RtAttr{
|
||||
RtAttr: syscall.RtAttr{
|
||||
Type: uint16(attrType),
|
||||
},
|
||||
children: []NetlinkRequestData{},
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// NewRtAttrChild Create a new RtAttr obj anc add it as a child of an existing object
|
||||
func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
|
||||
attr := NewRtAttr(attrType, data)
|
||||
parent.children = append(parent.children, attr)
|
||||
return attr
|
||||
}
|
||||
|
||||
// Len .
|
||||
func (a *RtAttr) Len() int {
|
||||
if len(a.children) == 0 {
|
||||
return (syscall.SizeofRtAttr + len(a.Data))
|
||||
}
|
||||
|
||||
l := 0
|
||||
for _, child := range a.children {
|
||||
l += rtaAlignOf(child.Len())
|
||||
}
|
||||
l += syscall.SizeofRtAttr
|
||||
return rtaAlignOf(l + len(a.Data))
|
||||
}
|
||||
|
||||
// Serialize the RtAttr into a byte array
|
||||
// This can't just unsafe.cast because it must iterate through children.
|
||||
func (a *RtAttr) Serialize() []byte {
|
||||
native := NativeEndian()
|
||||
|
||||
length := a.Len()
|
||||
buf := make([]byte, rtaAlignOf(length))
|
||||
|
||||
next := 4
|
||||
if a.Data != nil {
|
||||
copy(buf[next:], a.Data)
|
||||
next += rtaAlignOf(len(a.Data))
|
||||
}
|
||||
if len(a.children) > 0 {
|
||||
for _, child := range a.children {
|
||||
childBuf := child.Serialize()
|
||||
copy(buf[next:], childBuf)
|
||||
next += rtaAlignOf(len(childBuf))
|
||||
}
|
||||
}
|
||||
|
||||
if l := uint16(length); l != 0 {
|
||||
native.PutUint16(buf[0:2], l)
|
||||
}
|
||||
native.PutUint16(buf[2:4], a.Type)
|
||||
return buf
|
||||
}
|
||||
|
||||
// NetlinkRequest .
|
||||
type NetlinkRequest struct {
|
||||
syscall.NlMsghdr
|
||||
Data []NetlinkRequestData
|
||||
RawData []byte
|
||||
}
|
||||
|
||||
// NewNetlinkRequest create a new netlink request from proto and flags
|
||||
// Note the Len value will be inaccurate once data is added until
|
||||
// the message is serialized
|
||||
func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
|
||||
return &NetlinkRequest{
|
||||
NlMsghdr: syscall.NlMsghdr{
|
||||
Len: uint32(syscall.SizeofNlMsghdr),
|
||||
Type: uint16(proto),
|
||||
Flags: syscall.NLM_F_REQUEST | uint16(flags),
|
||||
Seq: atomic.AddUint32(&nextSeqNr, 1),
|
||||
// Pid: uint32(os.Getpid()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize the Netlink Request into a byte array
|
||||
func (req *NetlinkRequest) Serialize() []byte {
|
||||
length := syscall.SizeofNlMsghdr
|
||||
dataBytes := make([][]byte, len(req.Data))
|
||||
for i, data := range req.Data {
|
||||
dataBytes[i] = data.Serialize()
|
||||
length = length + len(dataBytes[i])
|
||||
}
|
||||
length += len(req.RawData)
|
||||
|
||||
req.Len = uint32(length)
|
||||
b := make([]byte, length)
|
||||
hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
|
||||
next := syscall.SizeofNlMsghdr
|
||||
copy(b[0:next], hdr)
|
||||
for _, data := range dataBytes {
|
||||
for _, dataByte := range data {
|
||||
b[next] = dataByte
|
||||
next = next + 1
|
||||
}
|
||||
}
|
||||
// Add the raw data if any
|
||||
if len(req.RawData) > 0 {
|
||||
copy(b[next:length], req.RawData)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// AddData add data to request
|
||||
func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
|
||||
if data != nil {
|
||||
req.Data = append(req.Data, data)
|
||||
}
|
||||
}
|
||||
|
||||
// AddRawData adds raw bytes to the end of the NetlinkRequest object during serialization
|
||||
func (req *NetlinkRequest) AddRawData(data []byte) {
|
||||
if data != nil {
|
||||
req.RawData = append(req.RawData, data...)
|
||||
}
|
||||
}
|
||||
|
||||
// Uint8Attr .
|
||||
func Uint8Attr(v uint8) []byte {
|
||||
return []byte{byte(v)}
|
||||
}
|
||||
|
||||
// Uint16Attr .
|
||||
func Uint16Attr(v uint16) []byte {
|
||||
native := NativeEndian()
|
||||
bytes := make([]byte, 2)
|
||||
native.PutUint16(bytes, v)
|
||||
return bytes
|
||||
}
|
||||
|
||||
// Uint32Attr .
|
||||
func Uint32Attr(v uint32) []byte {
|
||||
native := NativeEndian()
|
||||
bytes := make([]byte, 4)
|
||||
native.PutUint32(bytes, v)
|
||||
return bytes
|
||||
}
|
||||
|
||||
// ZeroTerminated .
|
||||
func ZeroTerminated(s string) []byte {
|
||||
bytes := make([]byte, len(s)+1)
|
||||
for i := 0; i < len(s); i++ {
|
||||
bytes[i] = s[i]
|
||||
}
|
||||
bytes[len(s)] = 0
|
||||
return bytes
|
||||
}
|
||||
|
||||
// NonZeroTerminated .
|
||||
func NonZeroTerminated(s string) []byte {
|
||||
bytes := make([]byte, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
bytes[i] = s[i]
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
// BytesToString .
|
||||
func BytesToString(b []byte) string {
|
||||
n := bytes.Index(b, []byte{0})
|
||||
return string(b[:n])
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user