All checks were successful
Test / Create distribution (push) Successful in 1m2s
Test / Sandbox (push) Successful in 2m41s
Test / ShareFS (push) Successful in 3m42s
Test / Hakurei (push) Successful in 3m46s
Test / Sandbox (race detector) (push) Successful in 5m3s
Test / Hakurei (race detector) (push) Successful in 6m8s
Test / Flake checks (push) Successful in 1m23s
This is useful for uevent implementation. Signed-off-by: Ophestra <cat@gensokyo.uk>
133 lines
3.0 KiB
Go
133 lines
3.0 KiB
Go
package netlink
|
|
|
|
import (
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
// RouteConn represents a NETLINK_ROUTE socket.
|
|
type RouteConn struct{ *conn }
|
|
|
|
// DialRoute returns the address of a newly connected [RouteConn].
|
|
func DialRoute() (*RouteConn, error) {
|
|
c, err := dial(syscall.NETLINK_ROUTE)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &RouteConn{c}, nil
|
|
}
|
|
|
|
// rtnlConsume consumes a message from rtnetlink.
|
|
func rtnlConsume(msg *syscall.NetlinkMessage) error {
|
|
switch msg.Header.Type {
|
|
case syscall.NLMSG_DONE:
|
|
return Complete{}
|
|
|
|
case syscall.NLMSG_ERROR:
|
|
if e := As[syscall.NlMsgerr](msg.Data); e != nil {
|
|
if e.Error == 0 {
|
|
return Complete{}
|
|
}
|
|
return syscall.Errno(-e.Error)
|
|
}
|
|
return syscall.EBADE
|
|
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// InAddr is equivalent to struct in_addr.
|
|
type InAddr [4]byte
|
|
|
|
// RtAttrMsg holds syscall.RtAttr alongside its payload.
|
|
type RtAttrMsg[D any] struct {
|
|
syscall.RtAttr
|
|
Data D
|
|
}
|
|
|
|
// populate populates the Len field of the embedded syscall.RtAttr.
|
|
func (attr *RtAttrMsg[M]) populate() {
|
|
attr.Len = syscall.SizeofRtAttr + uint16(unsafe.Sizeof(attr.Data))
|
|
}
|
|
|
|
// writeIfAddrmsg writes an ifaddrmsg structure to conn.
|
|
func (c *RouteConn) writeIfAddrmsg(
|
|
typ, flags uint16,
|
|
msg *syscall.IfAddrmsg,
|
|
attrs ...RtAttrMsg[InAddr],
|
|
) bool {
|
|
c.typ, c.flags = typ, syscall.NLM_F_REQUEST|syscall.NLM_F_ACK|flags
|
|
if !add(c.conn, msg) {
|
|
return false
|
|
}
|
|
for _, attr := range attrs {
|
|
attr.populate()
|
|
if !add(c.conn, &attr) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// SendIfAddrmsg sends an ifaddrmsg structure to rtnetlink.
|
|
func (c *RouteConn) SendIfAddrmsg(
|
|
typ, flags uint16,
|
|
msg *syscall.IfAddrmsg,
|
|
attrs ...RtAttrMsg[InAddr],
|
|
) error {
|
|
if !c.writeIfAddrmsg(typ, flags, msg, attrs...) {
|
|
return syscall.ENOMEM
|
|
}
|
|
return c.Roundtrip(rtnlConsume)
|
|
}
|
|
|
|
// writeNewaddrLo writes a RTM_NEWADDR message for the loopback address.
|
|
func (c *RouteConn) writeNewaddrLo(lo uint32) bool {
|
|
return c.writeIfAddrmsg(
|
|
syscall.RTM_NEWADDR,
|
|
syscall.NLM_F_CREATE|syscall.NLM_F_EXCL,
|
|
&syscall.IfAddrmsg{
|
|
Family: syscall.AF_INET,
|
|
Prefixlen: 8,
|
|
Flags: syscall.IFA_F_PERMANENT,
|
|
Scope: syscall.RT_SCOPE_HOST,
|
|
Index: lo,
|
|
},
|
|
RtAttrMsg[InAddr]{syscall.RtAttr{
|
|
Type: syscall.IFA_LOCAL,
|
|
}, InAddr{127, 0, 0, 1}},
|
|
RtAttrMsg[InAddr]{syscall.RtAttr{
|
|
Type: syscall.IFA_ADDRESS,
|
|
}, InAddr{127, 0, 0, 1}},
|
|
)
|
|
}
|
|
|
|
// SendNewaddrLo sends a RTM_NEWADDR message for the loopback address to the kernel.
|
|
func (c *RouteConn) SendNewaddrLo(lo uint32) error {
|
|
if !c.writeNewaddrLo(lo) {
|
|
return syscall.ENOMEM
|
|
}
|
|
return c.Roundtrip(rtnlConsume)
|
|
}
|
|
|
|
// writeIfInfomsg writes an ifinfomsg structure to conn.
|
|
func (c *RouteConn) writeIfInfomsg(
|
|
typ, flags uint16,
|
|
msg *syscall.IfInfomsg,
|
|
) bool {
|
|
c.typ, c.flags = typ, syscall.NLM_F_REQUEST|syscall.NLM_F_ACK|flags
|
|
return add(c.conn, msg)
|
|
}
|
|
|
|
// SendIfInfomsg sends an ifinfomsg structure to rtnetlink.
|
|
func (c *RouteConn) SendIfInfomsg(
|
|
typ, flags uint16,
|
|
msg *syscall.IfInfomsg,
|
|
) error {
|
|
if !c.writeIfInfomsg(typ, flags, msg) {
|
|
return syscall.ENOMEM
|
|
}
|
|
return c.Roundtrip(rtnlConsume)
|
|
}
|