Code Monkey home page Code Monkey logo

netlink's Introduction

Build Status

This repository has been deprecated. Subsequent development will take place @rust-netlink.

Netlink

This project aims at providing building blocks for netlink (see man 7 netlink).

Organization

Altnernatives

Credits

My main resource so far has been the source code of pyroute2 (python) and netlink (golang) a lot. These two projects are great, and very nicely written. As someone who does not read C fluently, and that does not know much about netlink, they have been invaluable.

I'd also like to praise libnl for its documentation. It helped me a lot in understanding the protocol basics.

The whole packet parsing logic is inspired by @whitequark excellent blog posts (part 1, part 2 and part 3, although I've only really used the concepts described in the first blog post).

Thanks also to the people behind tokio for the amazing tool they are building, and the support they provide.

netlink's People

Contributors

benjumanji avatar cathay4t avatar dequbed avatar dvc94ch avatar dxfgg17 avatar dzamlo avatar ffmancera avatar flouthoc avatar gabrik avatar george-hopkins avatar gilnaa avatar hermantolim avatar idanski avatar inemajo avatar johntitor avatar leo1003 avatar little-dude avatar mcginty avatar mcr avatar mhristache avatar mxpv avatar pinkisemils avatar rshearman avatar stbuehler avatar svart avatar tethyssvensson avatar tim-zhang avatar tuetuopay avatar wgh- avatar wllenyj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

netlink's Issues

Question: Changing frequency of interface

Is it possible to change the frequency (aka channel) of a given interface using this library? I am trying to port some C code:

NLA_PUT_U32(m, NL80211_ATTR_IFINDEX, ifindex);
NLA_PUT_U32(m, NL80211_ATTR_WIPHY_FREQ, freq);
NLA_PUT_U32(m, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);

I couldn't really find an example or methods/struct that re similar named.

LinkGetRequest never returns any links in new network namespace

Hi,

I'm trying to use the rtnetlink crate in libvopono to handle what are currently ip addr and ip link calls inside the created network namespaces in vopono.

Specifically I want to do the equivalent of:

ip netns exec netns ip addr add 127.0.0.1/8 dev lo
ip netns exec netns ip link set lo up

in the new network namespace.

I followed this example code, to write the following code (in a closure running on a new process inside the created network namespace):

https://github.com/jamesmcm/libvopono/blob/master/src/lib.rs#L136-L180

    /// Create loopback and set up
    /// Equivalent of:
    /// ip netns exec netns ip addr add 127.0.0.1/8 dev lo
    /// ip netns exec netns ip link set lo up
    pub fn add_loopback(&mut self) {
        self.run_in_namespace(
            || {
                let mut rt =
                    tokio::runtime::Runtime::new().expect("Failed to construct Tokio runtime");
                let x = rt.block_on(async {
                    let (connection, handle, _) = rtnetlink::new_connection().unwrap();


                    // Debug code: test if we ever get any links returned
                    let mut links = handle.link().get().execute();
                    println!("async closure runs but links are None");
                    while let Some(l) = links.try_next().await.expect("fail link") {
                        println!("{:?}", l);
                    }
                    // End debug code


                    let mut links = handle
                        .link()
                        .get()
                        .set_name_filter("lo".to_string())
                        .execute();
                    let ip = ipnetwork::IpNetwork::new(
                        std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)),
                        8,
                    )
                    .expect("Failed to construct IP");
                    if let Some(link) = links.try_next().await.expect("Failed to get link") {
                        handle
                            .address()
                            .add(link.header.index, ip.ip(), ip.prefix())
                            .execute()
                            .await
                            .expect("Failed to add address");


                        println!("ip: {:?}", ip);
                        std::thread::sleep(std::time::Duration::from_secs(2));
                        handle
                            .link()
                            .set(link.header.index)
                            .up()
                            .execute()
                            .await
                            .expect("Failed to set link up");
                    }
                });

This is then called with this code:

https://github.com/jamesmcm/libvopono/blob/master/src/bin.rs#L4-L12

    // Create netns
    let mut netns = RawNetworkNamespace::new("testlobin");
    // ip addr before
    let handle = netns.exec_no_block(&["ip", "addr"], false);
    std::thread::sleep(std::time::Duration::from_secs(2));
    kill(handle, SIGKILL).expect("kill failed");
 
    netns.add_loopback();
    std::thread::sleep(std::time::Duration::from_secs(5));
    // ip addr after
    let handle = netns.exec_no_block(&["ip", "addr"], false);
    std::thread::sleep(std::time::Duration::from_secs(2));

Giving the following output:

1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
async closure runs but links are None
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

Note the address is not added and the link is not set UP. It seems the LinkGetRequest only ever returns None (even without filtering the links by name) so the requests are never made.

Is there any reason why LinkGetRequest would "fail" like this in a new network namespace?

benchmark message parsing and serialization

Benchmarking is an unknown territory for me, so I'm not sure how to proceed with this, but it would be really useful to have some numbers and compare them to other implementations like libnl.

Adding VXLAN Support

Hi,

First, thank you for this very useful crate.

I noticed that in rtnetlink only some types of interfaces can be created.
And I also see that the VxLAN info is not yet defined:

As this is very interesting for me to have if you can point me to some references I can try to add it and do a PR with the code.

Should I follow libnl for the definition of the attributes? https://www.infradead.org/~tgr/libnl/doc/api/vxlan_8c_source.html

Thanks

Broadcast address is incorrect after executing handle.address().add()

After running
handle
.address()
.add(index, IpAddr::V4(Ipv4Addr::new(10, 0, 0, 20)), 24)
.execute()
.wait()
.unwrap();

ip addr show:
inet 10.0.0.20/24 brd 255.255.255.0 scope global secondary enp7s0

But the correct brd should be 10.0.0.255, maybe it is wrong to make the subnet mask a broadcast address.

[Question] RT_NETLINK route delete packet spec

Hello, I have a project that is very similar to this project. In fact, I refer to a lot of your code :).
I am currently trying to implement a ip route del/add function ( used by a VPN application), but it doesn't seem to work. I think it should be caused by the wrong format of the data packet.
I would be very grateful if you could share the relevant details.

From Google Translate

Code:

https://github.com/ExodusVPN/exodus/blob/rewrite/crates/netlink/src/route/mod.rs#L228
https://github.com/ExodusVPN/exodus/blob/rewrite/crates/netlink/examples/route.rs

Avoid defining kernel dependent data structures.

Currently, netlink-packet::rtnl::link::inet6::dev_conf::LinkInet6DevConfBuffer is trying to mirror the kernel's ipv6_devconf struct as defined in /lib/modules/$(uname -r)/build/include/linux/ipv6.h. Since certain fields in ipv6_devconf are dependent on the kernel config, it'll be hard to ensure that this crate is ever 100% compatible with the machine it's running on. For instance, the dump_links example will not work on Debian 9. I'm unsure if there are any other structs that are kernel config dependent, but there might be.

Whilst I cannot envision nice and fluffy solution to this issue immediately, treating the device config (or any structure that can change from kernel to kernel) NLA as an opaque byte buffer would be a solution. Then a different crate can be used to try and deal with the multiplicity of different ipv6_devconf definitions.

For anyone looking for a patchy solution, there's this branch which hacks around the expectation of a specific length of ipv6_devconf, but there might be other kernel-dependent structs.

Improve documentation

I think that it's impossible to extensively document all the possible netlink messages and attributes of every single protocol, but it would be nice to improve the overall documentation, because it's one of the biggest netlink pain points. I've started with netlink-sys already but if anyone wants to pick up some other crates, be my guest :)

  • netlink-sys
  • netlink-packet-core
  • netlink-packet-route
  • netlink-packet-sock-diag
  • netlink-packet-audit
  • netlink-proto
  • rtnetlink
  • audit

netlink-proto: handle `ENOBUFS` errors

To quote the man(7):

However, reliable transmissions from kernel to user are impossible in any case. The kernel can't send a netlink message if the socket buffer is full: the message will be dropped and the kernel and the user-space process will no longer have the same view of kernel state. It is up to the application to detect when this happens (via the ENOBUFS error returned by recvmsg(2)) and resynchronize.

Currently NetlinkFramed will just Poll::Ready(None), which we interpret as the socket shutting down in Connection:

    pub fn poll_read_messages(&mut self, cx: &mut Context) {
        trace!("poll_read_messages called");
        let mut socket = Pin::new(&mut self.socket);

        loop {
            trace!("polling socket");
            match socket.as_mut().poll_next(cx) {
                Poll::Ready(Some((message, addr))) => {
                    trace!("read datagram from socket");
                    self.protocol.handle_message(message, addr);
                }
                Poll::Ready(None) => {
                    warn!("netlink socket stream shut down");
                    self.socket_closed = true;
                    return;
                }
                Poll::Pending => {
                    trace!("no datagram read from socket");
                    return;
                }
            }
        }
    }

How to get the IP addresses

Hi

I am looking for a way to retrieve the IP addresses for a link but could not find anything related to it in the iproute2 crate so I guess I need to use rtnetlink which seems a bit more lower level.

Do you happen to have an example for this?

Thanks

Extended ifa flags

Thanks for rtnetlink!

Currently the ifa_flags are hardcoded to u8. Newer kernels support u32 flags, to allow e.g. setting IFA_F_MANAGETEMPADDR.

Just changing to u32 might not be desired since older kernels don't support that. iproute2 worked around it by dynamically switching to u32.

I'd be happy to work on a PR if you plan to support extended ifa flags and be interested in how you would like to see support being implemented.

have `unsafe` uses reviewed.

This is the first project where I use unsafe, it would probably be a good idea to have someone a bit more experienced review these pieces of code. There are not that many occurences:

  • most of them for ffi in netlink-sys
  • 2 are in netlink-proto

Implement FromRawFd for Socket in netlink-sys

Motivation

There doesn't appear to be any way to create a new socket with netlink_sys::Socket::new() that conforms to this signature:

libc::socket(libc::PF_NETLINK, libc::SOCK_RAW | libc::SOCK_CLOEXEC, libc::NETLINK_ROUTE);

Apparently, the flags used in the constructor are hard-coded to SOCK_DGRAM with no option to specify something else. If Socket implemented FromRawFd, I could call libc::socket() directly, convert it to a Socket, and then use the API as normal.

Alternatives

Another option could be to add another constructor besides Socket::new() with a higher-level API that allows you to specify flags without the user needing to resort to direct libc calls nor use of unsafe.

netlink-proto: refactor

This is just a couple notes to myself regarding some netlink-proto simplifications I've been contemplating for a while:

  • have a distinct codec for the audit protocol, instead of using feature flags
  • don't use the tokio codec trait? They force us to copy the data in intermediate buffers, which most of the time we don't need (unless we read multiple datagrams at once, like with the audit protocol).
  • have NetlinkFramed return a Result instead of an Option
  • rename NetlinkFramed into Transport maybe?
  • don't use unbounded channels? But then we have to handle errors when they get full. Not sure how to do that

Also:

Missing items for route query

  • RTA_NH_ID
  • netlink_packet_route::rtnl::nlas::route::MultiPath
  • CacheInfo, Metric should be parsed instead of showing as Vec.
  • The RTA_PREF is u8, not a Vec.

Removing interface from bridge

Hi,

It is possible to remove an interface from a bridge after we have assigned it?

Nowadays I can easily assign an interface to a bridge by doing like this:

let (connection, handle, _) = new_connection().unwrap();
            tokio::spawn(connection);
            let mut links = handle.link().get().set_name_filter(iface).execute();
            if let Some(link) = links
                .try_next()
                .await
                .map_err(|e| FError::NetworkingError(format!("{}", e)))?
            {
                let mut masters = handle.link().get().set_name_filter(master).execute();
                if let Some(master) = masters
                    .try_next()
                    .await
                    .map_err(|e| FError::NetworkingError(format!("{}", e)))?
                {
                    handle
                        .link()
                        .set(link.header.index)
                        .master(master.header.index)
                        .execute()
                        .await
                        .map_err(|e| FError::NetworkingError(format!("{}", e)))
                } else {
                    log::error!("set_iface_master master not found");
                    Err(FError::NotFound)
                }
            } else {
                log::error!("set_iface_master iface not found");
                Err(FError::NotFound)
            }

But I see that in set there is nothing like no_master() that would be similar to ip link set IFACE nomaster.

So it is possible or it is something actually missing?

Missing VXLAN properties and wrong type for IP addresses

As reported in nispor/nispor#95, I've found out that some VXLAN properties are missing, then we cannot report them from Nispor anymore. In order to fix this I am implementing the support. About the IP address on VXLAN (Local, Local6..) they are being reported as u32 and u128 which seems wrong in my opinion. To keep consistency with the whole project they should be Vec<u8> like netlink_packet_route::rtnl::address::nlas::Nla::Address. What do you think? @little-dude @gabrik

In addition, MAC VTAP support is missing and since MAC VLAN is supported we cannot re-use code anymore.

I am doing all the work, no worries for that. This issue is for tracking and discussing the issue. Thanks!

Looking for co-maintener(s)

Hello,

I have had less time to work on my personal projects lately (it took me two weeks to get to review #65 for example), so if anyone is interested in helping please let me know.

async_std support?

This is a well crafted crate. Thanks for implementing it!
Is there a plan to make it work with async_std instead of tokio?

Nla does not emit nested and byte order flags

I was recently experimenting with implementing certain Netfilter IP Set messages and attributes, using the tools in these crates. I noticed that while NlaBuffer supports reading and writing the nested (NLA_F_NESTED) and network byte order (NLA_F_NET_BYTEORDER) flags, the Emitable implementation for the Nla trait does not provide any way for an Nla implementation to supply these flags, so they are always emitted as 0. Also, DefaultNla, which I assume is meant to represent any unrecognized/unhandled attributes, will clear these flags when parsed and later emitted:

use netlink_packet_utils::nla::{DefaultNla, NlaBuffer};
use netlink_packet_utils::traits::{Emitable, Parseable};

// The IPSET_ATTR_TIMEOUT attribute should have the network byte order flag set.
// IPSET_ATTR_TIMEOUT(3600)
static TEST_ATTRIBUTE: &[u8] = &[0x08, 0x00, 0x06, 0x40, 0x00, 0x00, 0x0e, 0x10];

fn main() {
    let buffer = NlaBuffer::new(TEST_ATTRIBUTE);
    assert!(buffer.network_byte_order_flag());
    let attribute = DefaultNla::parse(&buffer).unwrap();
    let mut emitted_buffer = vec![0; attribute.buffer_len()];
    attribute.emit(&mut emitted_buffer);
    assert!(NlaBuffer::new(emitted_buffer).network_byte_order_flag()); // FAILS
}

Since I can't override this impl<T: Nla> Emitable for T, my solution was to use a separate trait (with Emitable as a supertrait) to serialize attributes, making sure that any needed flags are included. I also implemented my own UnrecognizedAttribute struct which preserves flags.

I wonder if it would be useful to support emitting flags in Nla. (Or maybe I'm just failing to see some technique to emit flags while taking advantage of the Nla trait.)

Unsound unsafe in netlink-packet

Clippy does not like the way we implemented netlink_packet::audit::status::StatusMessage::{to_bytes,from_bytes}:

    fn from_bytes(buf: &[u8]) -> Result<Self, DecodeError> {
        if buf.len() != size_of::<Self>() {
            return Err(format!(
                "invalid status message, expected length {}, got {}",
                size_of::<Self>(),
                buf.len()
            )
            .into());
        }
        Ok(unsafe { ptr::read(buf.as_ptr() as *const Self) })
    }

    fn to_bytes(&self, buf: &mut [u8]) {
        unsafe { ptr::write(buf.as_mut_ptr() as *mut Self, self.clone()) }
    }

I'm not familiar enough with unsafe to tell whether this is really UB (we do check the buffer length before casting, normally), so I think it's best to just avoid unsafe and rewrite this withouth it... We did the same for NativeNla though and there are lots of attributes that implement it, so it may add a significant amount of code... Maybe a macro could help here.

Split netlink-packet into smaller crates

As suggested by @flier it may be a good idea to split netlink-packet into smaller crates for each netlink protocol (at the moment: audit, route, and sock_diag). Then, netlink-packet would just expose a generic NetlinkMessage type.

I'm not 100% sure I want to do this though. The main reason would be that netlink-packet is getting big, maybe to big. But is that a good enough reason? Are there other reasons I'm not seeing?

I also see one downside: there is some stuff that could (and probably should) be re-used for all these new crates: error types, traits (Parseable, Emitable, etc.), code related to the netlink attributes (aka NLAs). That means we'll have another crate, that contains this boilerplate as a dependency of all the new crates. That seems like to much fragmentation to me.

But if we chose to do that, remains the question of naming these crates: I'd like to have a common prefix to indicate that they all provide netlink messages. Something like: netlink-packet-route, netlink-packet-audit, netlink-packet-sock-diag (and netlink-packet-common for the crate that contains the common code)?

Edit: I had not fully understood what @flier meant. See this comment:

the netlink-packet should only depend on netlink-sys, and only handle the raw netlink message. All the typed message should be moved to netlink-packet-audit or others, and we can chain the decoding process (&[u8] -> raw NetlinkMessage -> typed AuditMessage) with Iterator or Stream.

Generic netlink support?

I'm looking for support for generic netlink messages; do you have any plans to support genl?

(Or, is it already supported and I managed to miss the crate supporting it?)

Bug in NLA emitting code (somewhere)

I am currently trying to generate add neighbour messages for ipv6 hosts. I have noticed that if I create a message with just the header and zero nlas, the header is emitted just fine. If I add any nlas then they overwrite part of the nlm header, resulting in a malformed packet. I've added some test code for nlm header set / get, it's all fine. I haven't figured out the rest, but I thought it worth opening an issue to track, and also get any pointers on where I should be looking.

Get neighbour information is giving back an error message

Hello again,
I'm trying to pull neighbor information from netlink and I get an error message back. How do I debug what this error message means? This is the error that I'm seeing

root@ubuntu-bionic:/opt/netlink/target/debug/examples# ./dump_links
>>> NetlinkMessage { header: NetlinkHeader { length: 28, message_type: 30, flags: NetlinkFlags(1), sequence_number: 1, port_number: 0 }, payload: InnerMessage(GetNeighbour(NeighbourMessage { header: NeighbourHeader { family: 0, ifindex: 0, state: Incomplete, flags: NeighbourFlags(0), ntype: 0 }, nlas: [] })) }
<<< NetlinkMessage { header: NetlinkHeader { length: 48, message_type: 2, flags: NetlinkFlags(0), sequence_number: 1, port_number: 5364 }, payload: Error(ErrorMessage { code: -95, header: [28, 0, 0, 0, 30, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0] }) }

What I've basically done is modify the dump_links example to call GetNeighbor and pull the neighbor information. However, to construct a NeighborMessage, I have to construct the object and pass in the neighbor state which is undesirable. I want to pull back any neighbor where the neighbor flag = ROUTER and neighbor state can be anything i.e. REACHABLE, STALE, etc.

fn main() {
    let mut socket = Socket::new(Protocol::Route).unwrap();
    let _port_number = socket.bind_auto().unwrap().port_number();
    socket.connect(&SocketAddr::new(0, 0)).unwrap();

    let header = NetlinkHeader::new();
    let neighbor_message = NeighbourMessage {
        header: NeighbourHeader {
            family: 0,
            ifindex: 0,
            state: NeighbourState::Reachable,
            flags: NeighbourFlags::new(),
            ntype: 0
        },
        nlas: vec![]
    };

    let rtnl_message = RtnlMessage::GetNeighbour(neighbor_message);
    let mut packet = NetlinkMessage::new(header, NetlinkPayload::from(rtnl_message));

    packet.header.flags = NetlinkFlags::from(NLM_F_REQUEST);
    packet.header.sequence_number = 1;
    packet.finalize();
    let mut buf = vec![0; packet.header.length as usize];

    // Before calling serialize, it is important to check that the buffer in which we're emitting is big
    // enough for the packet, other `serialize()` panics.
    assert!(buf.len() == packet.buffer_len());
    packet.serialize(&mut buf[..]);

    println!(">>> {:?}", packet);
    socket.send(&buf[..], 0).unwrap();

    let mut receive_buffer = vec![0; 4096];
    let mut offset = 0;

    // we set the NLM_F_DUMP flag so we expect a multipart rx_packet in response.
    loop {
        let size = socket.recv(&mut receive_buffer[..], 0).unwrap();

        loop {
            let bytes = &receive_buffer[offset..];
            // Note that we're parsing a NetlinkBuffer<&&[u8]>, NOT a NetlinkBuffer<&[u8]> here.
            // This is important because Parseable<NetlinkMessage> is only implemented for
            // NetlinkBuffer<&'buffer T>, where T implements AsRef<[u8] + 'buffer. This is not
            // particularly user friendly, but this is a low level library anyway.
            //
            // Note also that the same could be written more explicitely with:
            //
            // let rx_packet =
            //     <NetlinkBuffer<_> as Parseable<NetlinkMessage>>::parse(NetlinkBuffer::new(&bytes))
            //         .unwrap();
            //
            let rx_packet: NetlinkMessage<RtnlMessage> =
                NetlinkMessage::deserialize(bytes).unwrap();

            println!("<<< {:?}", rx_packet);

            if rx_packet.payload == NetlinkPayload::Done {
                println!("Done!");
                return;
            }

            offset += rx_packet.header.length as usize;
            if offset == size || rx_packet.header.length == 0 {
                offset = 0;
                break;
            }
        }
    }
}

Sorry for pasting the entire thing but can you tell me if I'm going about this the right way and possibly what that error message means. I'm looking to do this by not using async/await which seems possible. Thanks

printing names of messages without full contents

I have a loop where I'm processing some things from netlink:

        while let Some((message, _)) = messages.next().await {
            let payload = message.payload;
            match payload {
                InnerMessage(NewLink(stuff)) => {
                    dump_link_info(stuff);
                }
                _ => { println!("generic message type: {} skipped", payload.message_type()); }
            }
        }

If I {:?} print "payload", I get a full, deep decode of the message. Which is cool, and I will probably want that, but for now I mostly just want to know what I'm missing. If I print it like above, then I get the numeric message type that I'm skipping.
I'd like to get "InnerMessage(DelRoute(RouteMessage))" or some such, but not the whole thing.
I think that I'd have to implement strings of some kind of each message type; or maybe it's possible to derive Display?

Cant build crate or examples

Hello,
I'm trying to build netlink and I'm running into lifetime parameter errors. I was trying to build the examples by running cargo build --examples and got the following error

   Compiling syn v1.0.7
   Compiling futures-io-preview v0.3.0-alpha.19
   Compiling smallvec v0.6.11
   Compiling serde v1.0.102
error[E0106]: missing lifetime specifier
   --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-io-preview-0.3.0-alpha.19/src/lib.rs:292:28
    |
292 |             -> Poll<Result<&[u8]>>;
    |                            ^ expected lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 2's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
   --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-io-preview-0.3.0-alpha.19/src/lib.rs:559:32
    |
559 |                 -> Poll<Result<&[u8]>>
    |                                ^ expected lifetime parameter
...
571 |         deref_async_buf_read!();
    |         ------------------------ in this macro invocation
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `cx`'s 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
   --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-io-preview-0.3.0-alpha.19/src/lib.rs:559:32
    |
559 |                 -> Poll<Result<&[u8]>>
    |                                ^ expected lifetime parameter
...
575 |         deref_async_buf_read!();
    |         ------------------------ in this macro invocation
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `cx`'s 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
   --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-io-preview-0.3.0-alpha.19/src/lib.rs:584:28
    |
584 |             -> Poll<Result<&[u8]>>
    |                            ^ expected lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `cx`'s 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
   --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-io-preview-0.3.0-alpha.19/src/lib.rs:597:32
    |
597 |                 -> Poll<Result<&[u8]>>
    |                                ^ expected lifetime parameter
...
609 |         delegate_async_buf_read_to_stdio!();
    |         ------------------------------------ in this macro invocation
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 2's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
   --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-io-preview-0.3.0-alpha.19/src/lib.rs:597:32
    |
597 |                 -> Poll<Result<&[u8]>>
    |                                ^ expected lifetime parameter
...
613 |         delegate_async_buf_read_to_stdio!();
    |         ------------------------------------ in this macro invocation
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 2's 2 lifetimes it is borrowed from

error: aborting due to 6 previous errors

I'm running the following versions of rustc and cargo

root@ubuntu-bionic:/opt/netlink# cargo --version
cargo 1.37.0-nightly (4c1fa54d1 2019-06-24)
root@ubuntu-bionic:/opt/netlink# rustc --version
rustc 1.37.0-nightly (0beb2ba16 2019-07-02)

MalformedNlaValue error

Hi,

Thanks for the great work!

I've received the MalformedNlaValue on the example case

handle.link().get().execute().and_then(|links| {
            println!("{:#?}", links);
            Ok(())
 });

The reason is that the size doesn't match in NativeNla from_bytes check here
I was getting this error on LinkStats<u32> (92 bytes vs. required 96 bytes).

It seems like, structs may have the different size depending on the Linux version (?).

test compile failure

cargo test --all on RHEL7 kernel 3.10.0-1127 rustc 1.46.0 fails with the following error: https://gist.github.com/dmitris/072a5b8cd6ef90d7d7a1777790121483

   Compiling netlink-packet-route v0.5.0 (/home/dsavints/dev/hack/github.com/little-dude/netlink/netlink-packet-route)
error[E0061]: this function takes 1 argument but 2 arguments were supplied
  --> netlink-packet-route/examples/dump_links.rs:28:12
   |
28 |     socket.send(&buf[..], 0).unwrap();
   |            ^^^^ --------  - supplied 2 arguments
   |            |
   |            expected 1 argument

error[E0599]: no method named `unwrap` found for opaque type `impl std::future::Future` in the current scope
  --> netlink-packet-route/examples/dump_links.rs:28:30
   |
28 |     socket.send(&buf[..], 0).unwrap();
   |                              ^^^^^^ method not found in `impl std::future::Future`

error[E0061]: this function takes 1 argument but 2 arguments were supplied
  --> netlink-packet-route/examples/dump_links.rs:35:27
   |
35 |         let size = socket.recv(&mut receive_buffer[..], 0).unwrap();
   |                           ^^^^ -----------------------  - supplied 2 arguments
   |                           |
   |                           expected 1 argument
`

tracking issue for missing netlink-packet message types for the route protocol

Two big pieces are missing in netlink-packet:

Support ip rule

Hi

I am looking for a netlink library in rust with support for ip rule manipulations. I checked the src code for this lib and it doesn't seem to support ip rules.

Do you plan to add such support?

Thanks

Does not work with new kernels

The newer version of linux kernel have added support for direct broadcast forwarding and that is causing the rtnetlink parsing of LinkAfInetNla to fail:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: MalformedNlaValue', libcore/result.rs:1009:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

The LinkInetDevConf struct is basically missing the newly added field (IPV4_DEVCONF_BC_FORWARDING) and so it cannot be created from the received NLA

impl<'buffer, T: AsRef<[u8]> + ?Sized> Parseable<LinkAfInetNla> for NlaBuffer<&'buffer T> {
    fn parse(&self) -> Result<LinkAfInetNla> {
        use self::LinkAfInetNla::*;
        let payload = self.value();
        Ok(match self.kind() {
            IFLA_INET_UNSPEC => Unspec(payload.to_vec()),
            IFLA_INET_CONF => DevConf(LinkInetDevConf::from_bytes(payload)?),
            _ => Other(<Self as Parseable<DefaultNla>>::parse(self)?),
        })
    }
}

pub(crate) trait NativeNla
where
    Self: Copy,
{
    fn from_bytes(buf: &[u8]) -> Result<Self> {
        if buf.len() != size_of::<Self>() {
            return Err(Error::MalformedNlaValue);
        }
        Ok(unsafe { ptr::read(buf.as_ptr() as *const Self) })
    }

This is how an strace of the NLA looks like:

{{nla_len=136, nla_type=AF_INET}, {{nla_len=132, nla_type=IF    LA_INET_CONF}, [[IPV4_DEVCONF_FORWARDING-1] = 1, [IPV4_DEVCONF_MC_FORWARDING-1] = 0, [IPV4_DEVCONF_PROXY_ARP-1] = 0, [IPV4_DEVCONF_ACCEPT_REDIRECTS-1] = 1, [IPV4_DEVCONF_SECURE_REDIRECTS-1] = 1, [IPV4_DEVCON    F_SEND_REDIRECTS-1] = 1, [IPV4_DEVCONF_SHARED_MEDIA-1] = 1, [IPV4_DEVCONF_RP_FILTER-1] = 0, [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE-1] = 1, [IPV4_DEVCONF_BOOTP_RELAY-1] = 0, [IPV4_DEVCONF_LOG_MARTIANS-1] = 0, [IPV    4_DEVCONF_TAG-1] = 0, [IPV4_DEVCONF_ARPFILTER-1] = 0, [IPV4_DEVCONF_MEDIUM_ID-1] = 0, [IPV4_DEVCONF_NOXFRM-1] = 0, [IPV4_DEVCONF_NOPOLICY-1] = 0, [IPV4_DEVCONF_FORCE_IGMP_VERSION-1] = 0, [IPV4_DEVCONF_ARP_AN    NOUNCE-1] = 0, [IPV4_DEVCONF_ARP_IGNORE-1] = 0, [IPV4_DEVCONF_PROMOTE_SECONDARIES-1] = 0, [IPV4_DEVCONF_ARP_ACCEPT-1] = 0, [IPV4_DEVCONF_ARP_NOTIFY-1] = 0, [IPV4_DEVCONF_ACCEPT_LOCAL-1] = 0, [IPV4_DEVCONF_SR    C_VMARK-1] = 0, [IPV4_DEVCONF_PROXY_ARP_PVLAN-1] = 0, [IPV4_DEVCONF_ROUTE_LOCALNET-1] = 0, [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL-1] = 10000, [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL-1] = 1    000, [IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN-1] = 0, [IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST-1] = 0, [IPV4_DEVCONF_DROP_GRATUITOUS_ARP-1] = 0, [IPV4_DEVCONF_BC_FORWARDING-1] = 0]}}

I guess we need a bit more fancy parsing logic here.

I see the same parsing approach is used all over the code so I think these kind of issues will continuously pop up if the parsing logic is not improved to accept unknown fields.

abandon rtnetlink

I'm not satisfied with rtnetlink API, and as shown in #39, there are fundamental design issues when it comes to namespaces, which I have no idea how to fix.

examples: dump_links does not compile

Heads-up, there are some compile errors with dump_links example

steps:

  • git clone [email protected]:little-dude/netlink
  • cargo build
  • cargo build --example dump_links

It looks like it might be a sync example , but the crates default to async?

image

rtnetlink seems to fail if used with non-stock tokio::main

I am getting complaints from deep inside rtnetlink when I started my tokio runtime manually rather than with the tokio::main macro.
Based upon the tokio::main macros and a variety of feedback on discord and github, I changes rtnetlink/examples/get_links.rs as shown in branch: https://github.com/mcr/netlink/tree/get_links_crashes

I duplicated get_links.rs into get_links0.rs where I initialize tokio::main runtime manually.
This causes a crash:

obiwan-[connect/netlink/rtnetlink](2.6.6) mcr 18322 %../target/debug/examples/get_links0 
blocking in main
thread 'main' panicked at 'there is no reactor running, must be called from the context of Tokio runtime', /home/mcr/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.22/src/io/driver/mod.rs:202:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

I will attach backtrace in next comment.

I hope that this is simplest way to demonstrate this.
I struggled a lot to make sure that my tokio::main initialisation was really correct.
I do not use the macro because I need to do some things before starting the runtime. (I need to fork to create a child to own the network namespace I am creating. I create a socketpair(2) between parent/child for IPC).

Many possibilities:

  1. rtnetlink is doing some check for a runtime, and not finding the default, failing to find it.
  2. maybe I need to poke that default somehow
  3. maybe the way that I'm starting tokio runtime is just wrong.
  4. something else boneheaded.

Implement network namespace creation a la iproute2

Some workflows with the route protocol involve configuring interfaces in other network namespaces. However, the namespace creation itself is not part of the netlink protocol. One must use the unshare() or clone() syscalls for that.

Another problem is keeping such namespaces alive even if no process uses them: if no entry in /proc points to a given namespace, the kernel deletes it. iproute2 solves this by creating another mount point under /var/run/ and mounting the namespace filesystem there to keep it alive (see https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/ipnetns.c#n661).

We could try to do the same, but I'm not sure to fully understand all the details of the code yet especially this specific loop:

	/* Make it possible for network namespace mounts to propagate between
	 * mount namespaces.  This makes it likely that a unmounting a network
	 * namespace file in one namespace will unmount the network namespace
	 * file in all namespaces allowing the network namespace to be freed
	 * sooner.
	 */
	while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
		/* Fail unless we need to make the mount point */
		if (errno != EINVAL || made_netns_run_dir_mount) {
			fprintf(stderr, "mount --make-shared %s failed: %s\n",
				NETNS_RUN_DIR, strerror(errno));
			return -1;
		}

		/* Upgrade NETNS_RUN_DIR to a mount point */
		if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
			fprintf(stderr, "mount --bind %s %s failed: %s\n",
				NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
			return -1;
		}
		made_netns_run_dir_mount = 1;
	}

A second issue would be to integrate this with Tokio: mount is blocking (not sure if it blocks the whole process or just the thread), so it will block the entire tokio event loop, so we should maybe use a separate thread for that.

All the code for this should probably be put in a separate crate.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.