Live with Predictable Network Interface Name - linux

I'm facing for the first time with the new name scheme of network interfaces: Predictable Network Interface Name.
My question is NOT related if this scheme is better or worse... I'm just trying to understand how to use it correcly.
Here I read:
When changing the interface naming scheme, do not forget to update all network-related configuration files and custom systemd unit files to reflect the change.
So I have to write in all the configuration files the actual interface name. In the previous scheme it was i.e. eth0 and it just means the first ethernet card, with the known caveats if there are multiple interfaces.
Now, instead, I have to write the predictable name, that is composed of some easy parts (i.e. type of the interface) and other un-predictable ones like the MAC address. As far as I understand each card will have a different name.
I admit my question might appear fool, but I don't understand how to prepare a configuration file. Let's see an example, /etc/dhcpcd.conf:
profile static_eth0
static ip_address=192.168.1.23/24
static routers=192.168.1.1
static domain_name_servers=192.168.1.1
interface eth0
fallback static_eth0
What should I put instead of eth0 in the o.s. image?
Only when I run the target machine I can retreive the actual name of the ethernet interface.
100% of my systems are headless, and I never connect a keyboard and display to them. Furthermore, if I have to send a spare part of the SBC do I need to reconfigure all?
Would you please help me to understand the correct usage?
ps. I know I can revert back to the old naming scheme... but that's not the point of my question.

See https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/
it explains how the names are assigned
Names incorporating Firmware/BIOS provided index numbers for on-board devices (example: eno1)
Names incorporating Firmware/BIOS provided PCI Express hotplug slot index numbers (example: ens1)
Names incorporating physical/geographical location of the connector of the hardware (example: enp2s0)
Names incorporating the interfaces's MAC address (example: enx78e7d1ea46da)
Classic, unpredictable kernel-native ethX naming (example: eth0)
By default, systemd v197 will now name interfaces following policy 1) if that
information from the firmware is applicable and available, falling back to 2) if
that information from the firmware is applicable and available, falling back to 3)
if applicable, falling back to 5) in all other cases. Policy 4) is not used by
default, but is available if the user chooses so.
So you could opt for a different approach, likely in your setup its easiest to take the mac, just reboot once an image that tries pxe/dhcp requests and note down the sended mac.
Another way, that may work, depending on your setup, would be interface groupings.
From "man interfaces"
auto /eth*
If the kernel knows about the interfaces with names lo, eth0 and eth1, then the above line is then interpreted as:
auto eth0 eth1
Note that there must still be valid "iface" stanzas for each matching interface. However, it is possible to combine a pattern with a mapping to a logical interface, like so:
auto /eth*=eth
iface eth inet dhcp
So maybe if you only have one interface, but can't tell where it will be assigned, you could write "auto /e*=eth" to catch all interfaces starting with e and address them inside the configuration file as "eth".

Related

c - using nl80211 without libnl or libnl-genl?

I'm hoping to just use the header in the kernel, linux/nl80211.h to get the channel my network device is on. I'm on a very restricted system where building has to happen with a minimum number of extra packages. It feels strange that SIOCGIWFREQ would be so easy to get, but I'd need a library to just get a frequency via nl80211.
Are there any examples of how to use the nl80211 interface directly in Linux? I'm just hoping to get NL80211_FREQUENCY_ATTR_FREQ
After a lot of struggling, I found out! It's actually easier to use netlink without libnl, as long as you're not doing anything complicated.
I wrote up an example here that prints all your wireless devices, what networks and channels they're connected to: https://github.com/cnlohr/netlink_without_libnl/blob/master/without_libnl.c

Linux: Get "user-friendly" network interface name

I'm writing a program where the user shall select some network interface under Linux like shown here:
Please select a network card:
1) enp2s0
2) wlan3
3) ppp2
Up to this point I have no problem.
However, I'd like the users to see more "descriptive" names like shown here:
Please select a network card:
1) PCI Ethernet (enp2s0)
2) Wireless LAN (wlan3)
3) Dial-up connection (ppp2)
Questions:
Does Linux know such descriptive names for network interfaces at all?
If yes: How can I get these names?
If no: Is there a way to guess the user-friendly name from the interface name with a quite high reliability?
Example: "ppp*" => "Dial-up connection"; "wl*" => "Wireless network"
Maybe in combination with the code from /sys/class/net/.../type?
If yes: Where can I find a list of possible interface names?
I know that Gnome desktop lists network interface names like "PCI Ethernet" in the network status drop-down menu. So there must be some method to get a "descriptive" name of some network interface.
Does Linux know "friendly" names for network interfaces at all?
No.
If no: Is there a way to guess the user-friendly name from the interface name with a quite high reliability?
You can probably make the generalizations you have suggested. If you are on a systemd based systems, take a look at the systemd net naming scheme, which shows the prefixes used for different interface types:
+--------+------------------------------------+
| Prefix | Description |
+--------+------------------------------------+
| en | Ethernet |
| ib | InfiniBand |
| sl | serial line IP (slip) |
| wl | Wireless local area network (WLAN) |
| ww | Wireless wide area network (WWAN |
+--------+------------------------------------+
Maybe in combination with the code from /sys/class/net/.../type?
I'm not sure that type information is going to be helpful. E.g., both ethernet and wireless interfaces show type of 1. On the other hand, you can positively identify ppp interfaces, for example, using this value.
The possible values for type are available in if_arp.h.
these are native naming policies systemd uses. with the old naming (eth0,wlan0,...) an interface name was not predictable (for example, your first eth card could get a name other than eth0) and this caused all sorts of problems. new naming standard assigns name to the interface according to one of the following:
Names incorporating Firmware/BIOS provided index numbers for on-board devices (example: eno1)
Names incorporating Firmware/BIOS provided PCI Express hotplug slot index numbers (example: ens1)
Names incorporating physical/geographical location of the connector of the hardware (example: enp2s0)
Names incorporating the interfaces's MAC address (example: enx78e7d1ea46da)
Classic, unpredictable kernel-native ethX naming (example: eth0)
systemd will start by 1, falling back to 2,3,...
Source
EDIT:
I should add, if you read the link which I posted, you can use your own names!
You create your own manual naming scheme, for example by naming your interfaces "internet0", "dmz0" or "lan0". For that create your own .link files in /etc/systemd/network/, that choose an explicit name or a better naming scheme for one, some, or all of your interfaces. See systemd.link(5) for more information.

What is the difference between NETLINK_FIREWALL and NETLINK_NETFILTER?

Both of the Netlink protocols NETLINK_FIREWALL (and NETLINK_IP6_FW) and NETLINK_NETFILTER are used to manupilate the Linux firewall.
So, is there a diffrence? If yes, which Netlink protocol serves which purpose?
A quick grep through the code shows that NETLINK_FIREWALL only occurs twice in the kernel:
include/uapi/linux/netlink.h
11:#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */
security/selinux/hooks.c
1184: case NETLINK_FIREWALL:
1185: return SECCLASS_NETLINK_FIREWALL_SOCKET;
So, it's defined and the comment claims that it's unused, and it's only mentioned once, in type conversion code for selinux. There's never a call to netlink_kernel_create(), so NETLINK_FIREWALL is never hooked up. It won't do anything.
NETLINK_NETFILTER does have a netlink_kernel_create() call associated with it, so that's the interface you want to look at.
It's been a while, but I once implemented (partial) code for configuratin netfilter rules and I remember doing that through a setsockopt() call, rather than through netlink sockets. I'm not sure what NETLINK_NETFILTER actually does.
A quick look through git log seems to suggest that NETLINK_NETFILTER is used to interface with thinks like connection tracking, not actually configuring firewall rules (which the iptables userspace command does).
If you actually want to create firewall rules (i.e. do what iptables does) you should be looking at libiptc (which is part of the iptables source tree). The interface for configuring these rules is complicated and undocumented.

tcpdump: capture outgoing packets on virtual interfaces that has an unknown link type to libpcap?

In the system I am testing right now, it has a couple of virtual L2 devices chained together to add our own L2.5 headers between Eth headers and IP headers. Now when I use
tcpdump -xx -i vir_device_1
, it actually shows the SLL header with IP header. How do I capture the full packet that is actually going out of the vir_device_1, i.e. after the ndo_start_xmit() device call?
How do I capture the full packet that is actually going out of the vir_device_1, i.e. after the ndo_start_xmit() device call?
Either by writing your own code to directly use a PF_PACKET/SOCK_RAW socket (you say "SLL header", so this is presumably Linux), or by:
making sure you've assigned a special ARPHRD_ value for your virtual interface;
using one of the DLT_USERn values for your special set of headers, or asking tcpdump-workers#lists.tcpdump.org for an official DLT_ value to be assigned for them;
modifying libpcap to map that ARPHRD_ value to the DLT_ value you're using;
modifying tcpdump to handle that DLT_ value;
if necessary, modifying other programs that would capture on that interface or read capture files as written by tcpdump on that interface to handle that value as well.
Note that the DLT_USERn values are specifically reserved for private use, and no official versions of libpcap, tcpdump, or Wireshark will ever assign them for their own use (i.e., if you use a DLT_USERn value, don't bother contributing patches to assign that value to your type of headers, as they won't be accepted; other people may already be using it for their own special headers, and that must continue to be supported), so you'll have to maintain the modified versions of libpcap, tcpdump, etc. yourself if you use one of those values rather than getting an official value assigned.
Thanks Guy Harris for providing very helpful answers to my original question!
I am adding this as an answer/note to a follow up question I asked in the comments.
Basically my question was what is the status of the packet received by PF_PACKET/SOCK_RAW.
For an software device(no queue), dev_queue_xmit() will call dev_hard_start_xmit(skb, dev) to start transmitting skb buffer. This function calls dev_queue_xmit_nit() before it calls dev->ops->ndo_start_xmit(skb,dev), which means the packet PF_PACKET sees is at the state before any changes made in ndo_start_xmit().

Identifying the preferred IPv6 source address for an adapter

If you have a IPv6 enabled host that has more than one global-scope address, how can you programmatically identify the preferred address for bind()?
Example address list:
eth0 Link encap:Ethernet HWaddr 00:14:5e:bd:6d:da
inet addr:10.6.28.31 Bcast:10.6.28.255 Mask:255.255.255.0
inet6 addr: 2002:dce8:d28e:0:214:5eff:febd:6dda/64 Scope:Global
inet6 addr: fe80::214:5eff:febd:6dda/64 Scope:Link
inet6 addr: 2002:dce8:d28e::31/64 Scope:Global
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
On Solaris you can indicate a preferred address with an interface flag and it is available programmatically via SIOCGLIFCONF:
/usr/include/net/if.h:
#define IFF_PREFERRED 0x0400000000 /* Prefer as source address */
As listed in the interface list:
eri0: flags=2104841<UP,RUNNING,MULTICAST,DHCP,ROUTER,IPv6> mtu 1500 index 2
inet6 fe80::203:baff:fe4e:6cc8/10
eri0:1: flags=402100841<UP,RUNNING,MULTICAST,ROUTER,IPv6,PREFERRED> mtu 1500 index 2
inet6 2002:dce8:d28e::36/64
This is not portable to OSX, Linux, FreeBSD, or Windows though. Windows is let off easy though as it has completely useless, from an administrators perspective, UUID based adapter names (depending upon the Windows version).
For Linux this article details how the parameter preferred_lft, where lft is short for "lifetime", can be altered to weight the selection process by the kernel. This setting doesn't appear conveniently available in the results of SIOCGIFCONF or getifaddrs() though.
So I want to bind to eth0, eri0, or whatever available interface name. The choices are a bit stark:
Fail on adapter names resolving to multiple interfaces. I take this approach for handling multicast transports (OpenPGM) as the protocol MUST have one-only sending address.
Bind to everything. This is a cop out and would be unexpected to users.
Bind to the adapter with SO_BINDTODEVICE. This requires CAP_NET_RAW system capability on Linux which can be quite a cumbersome overhead for administrators.
Bind to the first IPv6 interface on the adapter. The ordering tends to be completely bogus.
Bind to the last interface. David Croft's article implies Linux does this, but is also a bit bogus.
Enumerate over every interface and create a new socket explicitly for each.
With option #6 I would expect you could usually be smarter and take the approach that if only a link-local scope address is available bind to that, otherwise bind to just the available global-link scope addresses.
When connecting to another host then RFC 3484 can be used, but as you can see all the choices are dependent upon matching the destination address:
Prefer same address. (i.e. destination is local machine)
Prefer appropriate scope. (i.e. smallest scope shared with the destination)
Avoid deprecated addresses.
Prefer home addresses. Prefer outgoing
interface. (i.e. prefer an address on the interface we're sending
out of)
Prefer matching label.
Prefer public addresses.
Use longest matching prefix.
In some circumstances we can use #7 here, but in the interface example above both global-scope interfaces have a 64-bit prefix length.
RFC 3484 has the following pertinent lines:
The IPv6 addressing architecture 5 allows multiple unicast
addresses to be assigned to interfaces. These addresses may have
different reachability scopes (link-local, site-local, or global).
These addresses may also be "preferred" or "deprecated" 6.
The link being to RFC 2462, similarly expanded:
preferred address - an address assigned to an interface whose use
by
upper layer protocols is unrestricted. Preferred addresses may
be used as the source (or destination) address of packets sent
from (or to) the interface.
But no methods to programmatically acquire this detail.
Props to Win32 API that exposes an ioctl SIO_ADDRESS_LIST_SORT that allows a developer to use not only RFC 3484 sorting but to take into consideration any system administrator overrides. Linux has /etc/gai.conf as used for RFC 3484 sorting in getaddrinfo() but no API for directly accessing the sorting. Solaris has the ipaddrsel command. OSX is following FreeBSD by adding ip6addrctl in 10.7.
edit: Some concerns with RFC 3484 sorting are listed and referred to in this additional IETF draft document:
https://datatracker.ietf.org/doc/html/draft-axu-addr-sel-01
Solaris, for example, creates new alias-interfaces for each new
address assigned to a physical interface. So if_index could also be
used to uniquely identify a source address specific routing table on
that platform. Other operating systems do not work the same way.
The author likes Solaris's approach of giving each additional IPv6 interface a new alias, so that eri0 would become the link-local scope address, and eri0:1 or eri0:2, etc, must be specified to use a global-scope address.
Clearly whilst a nice idea one couldn't expect to see other OS change for quite some time.
I'm not sure this is in the direction you're seeking, but...
Poking around in the iproute bundle's ip code (ip/ipaddress.c) under linux shows that the ip command digs up interface flags like primary and secondary from a struct ifaddrmsg, member ifa_flags. The ifaddmsg seems to be acquired through a struct nlmsghdr which is documented in man 7 netlink, and used via sendmsg and recvmsg interaction with the kernel, which overall sounds like a royal pain but it's at least programmatic. Whether primary and secondary would be enough to be useful is a separate question.

Resources