On Mon, Nov 21, 2022 at 04:56:07PM +0100, Martijn van Duren wrote:
> On Sun, 2022-11-20 at 19:35 -0700, Theo de Raadt wrote:
> > Steve Litt <sl...@troubleshooters.com> wrote:
> > 
> > > Vitaliy Makkoveev said on Mon, 21 Nov 2022 03:48:21 +0300
> > > 
> > > > > On 20 Nov 2022, at 18:06, Odd Martin Baanrud <mar...@lb7ye.net>
> > > > > wrote:
> > > > > 
> > > > > Hello,
> > > > > 
> > > > > I have a Raspberry Pi 4 with 2 USB NIC’s attached.
> > > > > One via USB3 (ure0), and the other via USB2 (ure1).
> > > > > Since they are connected to different USB interfaces, I thaught they
> > > > > would get configured the same way on reboot. But that’s not the case.
> > > > > They became swapped on reboot.
> > > > > Is there a way to “lock” the configuration I want?
> > > > > So the USB3 NIC always become ure0, and the USB2 ure1.
> > > > > 
> > > > > Regards, Martin
> > > > >   
> > > > 
> > > > You could parse ifconfig(8) output to determine which names network
> > > > interfaces received. But unfortunately, you can’t rename interfaces.
> > > 
> > > During your parsing you could assign each one to an environment
> > > variable such that, for instance, $lan contains the network card name
> > > of the LAN one, and $wan contains the network name of the one going to
> > > the Internet. Unfortunately, this would probably mean changing a lot of
> > > existing shellscripts, but it's doable.
> > 
> > But that is not the problem.
> > 
> > hostname.* installs addresses on an interface, based upon the name of that
> > interface.
> > 
> > So it is too late for what you suggest.
> > 
> > Unless the suggestion is have each hostname.* do a !command to a script 
> > which
> > does the assigning.  That is pretty crazy.
> > 
> > pf.conf is not the problem either, because that can be entirely written 
> > using
> > egress and groups.
> > 
> > 
> > 
> > There is a problem with device attachment -> naming a device at that
> > moment -> using that name in netstart.. but I am not sure how we could
> > solve this without creating bigger problems for everyone else in the
> > other non-hot-plug configurations, which is the majority of users with
> > > 1 network device.
> > 
> > We also hit this problem with disks, and we worked around it with the
> > DUID subsystem.
> > 
> > 
> > I suppose there is some argument that we should support hostname.MAC
> > files
> > 
> I don't have a usecase for this myself, but it seemed like a nice
> exercise and might get the ball rolling. I also don't have much
> experience with our rc/netstart shellcode, so I'm expecting this diff
> should be taken as a starting-point iff we want something like this.
> 
> I've chosen to error out on missing lladdr, duplicate lladdr and when
> there's a hostname.if for both the lladdr and the if variant. This means
> that there's smaller chance for order confusion or doubly applied
> configs. Downside is that if someone decided to backup their hostname.if
> to hostname.lladdr that will break their setup. However, I don't expect
> people to backup their config files in this manner, but you never know.
> 
> Errors:
> On duplicate lladdr (in this case em0 and iwx0 in trunk0):
> $ doas sh /usr/src/etc/netstart 88:a4:c2:fb:84:77 
> netstart: /etc/hostname.88:a4:c2:fb:84:77: unique if for lladdr not found.
> 
> On missing lladdr:
> $ doas sh /usr/src/etc/netstart 88:a4:c2:fb:84:76 
> netstart: /etc/hostname.88:a4:c2:fb:84:76: unique if for lladdr not found.
> 
> And having both hostname.if and hostname.lladdr installed:
> $ doas sh ./netstart 00:11:22:33:44:55
> netstart: /etc/hostname.00:11:22:33:44:55: duplicate config found in 
> /etc/hostname.vio0.
> $ doas sh ./netstart vio0             
> netstart: /etc/hostname.vio0: duplicate config found in 
> /etc/hostname.00:11:22:33:44:55.
> 
> Two omissions I considered but didn't implement:
> 1) I didn't test if the lladdr is owned by one of `ifconfig -C`
>    interfaces. Not sure if this is an upside or downside.
> 2) Allowing /etc/netstart if1 and parsing the hostname.lladdr1 and vice
>    versa.
 

I got interested in this, and looked at it a bit.  My diff is also a bit
preliminary, but a couple of things.

First, I only parse ifconfig output once and save the LLADDR_MAP to look
up later.  This makes the lookup functions a bit simpler.  Also, the
glob now uses xdigit, which seems more correct, unless there's something
I am missing about mac addresses.

I also thought the error message for `netstart $lladdr` when
/etc/hostname.$lladdr doesn't exist, but /etc/hostname.$if does was poor
(it claimed duplicate configs which wasn't true) so I thought the
easiest solution was to implement your #2 there and allow it to start
the $if when you specify the $lladdr.

Unfortunately, I then looked at the clock and realized it's time for
bed, but I figured you might be interested in another take, even if it's
probably incomplete.  In any case, tomorrow is dinner with friends, so
it will be Wednesday before I again have a chance to think on this.


Index: etc/netstart
===================================================================
RCS file: /cvs/src/etc/netstart,v
retrieving revision 1.229
diff -u -p -r1.229 netstart
--- etc/netstart        5 Nov 2022 12:06:05 -0000       1.229
+++ etc/netstart        22 Nov 2022 05:55:40 -0000
@@ -92,6 +92,49 @@ parse_hn_line() {
        set +o noglob
 }
 
+LLGLOB='[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]'
+LLGLOB="$LLGLOB:$LLGLOB:$LLGLOB"
+
+set -A LLADDR_MAP -- $(
+       ifconfig | while IFS= read -- _line; do
+               if [[ "$_line" = +([[:alpha:]])+([[:digit:]]):* ]]; then
+                       _if=${_line%:*}
+               elif [[ -n "$_if"
+                    && "$_line" = +([[:space:]])lladdr\ $LLGLOB ]]; then
+                       print "$_if,${_line#*lladdr }"
+                       _if=
+               fi
+       done
+)
+
+# Find if for lladdr
+# Usage: lladdr2if xx:xx:xx:xx:xx:xx
+#   Duplicate lladdrs result in error.
+lladdr2if() {
+       local _lladdr=$1 _if=""
+       for m in "${LLADDR_MAP[@]}"; do
+               if [[ "$_lladdr" = "${m#*,}" ]]; then
+                       [[ -n "$_if" ]] && return 1
+                       _if="${m%,*}"
+               fi
+       done
+       print -- "$_if"
+       return 0
+}
+
+# Find lladdr for if
+# Usage: if2lladdr if1
+if2lladdr() {
+       local _if=$1
+       for m in "${LLADDR_MAP[@]}"; do
+               if [[ "$_if" = "${m%,*}" ]]; then
+                       print -- "${m#*,}"
+                       break
+               fi
+       done
+       return 0
+}
+
 # Create interface $1 if it does not yet exist.
 # Usage: ifcreate if1
 ifcreate() {
@@ -132,15 +175,37 @@ vifscreate() {
 # Start a single interface.
 # Usage: ifstart if1
 ifstart() {
-       local _if=$1 _hn=/etc/hostname.$1 _cmds _i=0 _line _stat
+       local _if=$1 _hn _cmds _i=0 _line _stat _lladdr
        set -A _cmds
 
+       if [[ "$_if" = $LLGLOB ]]; then
+               _lladdr=$_if
+               if ! _if="$(lladdr2if "$_if")"; then
+                       print -u2 "${0##*/}: unique if for lladdr $_lladdr not 
found."
+                       return
+               fi
+       else
+               _lladdr="$(if2lladdr "$_if")"
+       fi
+
        # Interface names must be alphanumeric only.  We check to avoid
        # configuring backup or temp files, and to catch the "*" case.
        [[ $_if != +([[:alpha:]])+([[:digit:]]) ]] && return
 
-       if [[ ! -f $_hn ]]; then
-               print -u2 "${0##*/}: $_hn: No such file or directory."
+       if [[ -n "$_if" && -e "/etc/hostname.$_if" ]]; then
+               _hn="/etc/hostname.$_if"
+       fi
+
+       if [[ -n "$_lladdr" && -e "/etc/hostname.$_lladdr" ]]; then
+               if [[ -n "$_hn" ]]; then
+                       print -u2 "${0##*/}: duplicate configs found in $_hn 
and /etc/hostname.$_lladdr."
+                       return
+               fi
+               _hn="/etc/hostname.$_lladdr"
+       fi
+
+       if [[ -z "$_hn" ]]; then
+               print -u2 "${0##*/}: /etc/hostname.$1: No such file or 
directory."
                return
        fi
 
@@ -180,7 +245,7 @@ ifstart() {
 #   Start "$1" interfaces in order or all interfaces if empty.
 #   Don't start "$2" interfaces. "$2" is optional.
 ifmstart() {
-       local _sifs=$1 _xifs=$2 _hn _if _sif _xif
+       local _sifs=$1 _xifs=$2 _hn _if _sif _xif _lladdr
 
        for _sif in ${_sifs:-ALL}; do
                for _hn in /etc/hostname.+([[:alpha:]])+([[:digit:]]); do
@@ -194,6 +259,13 @@ ifmstart() {
 
                        # Start wanted ifs.
                        [[ $_sif == @(ALL|${_if%%[0-9]*}) ]] && ifstart $_if
+               done
+               for _hn in /etc/hostname.$LLGLOB; do
+                       [[ -f $_hn ]] || continue
+                       _lladdr=${_hn#/etc/hostname.}
+
+                       # Start wanted ifs.
+                       [[ $_sif == @(ALL|${_lladdr}) ]] && ifstart $_lladdr
                done
        done
 }

Reply via email to