# Selecting the preferred source IP address



## pl (Feb 23, 2018)

My ISP's DHCP assigns me a private, dynamic IP address (10.151.105.106/26), and in this subnet I have my default gateway. Then I have a static, public IP address assigned, let's say 2.234.35.29/32. I can't connect to the Internet using my _private_ ip address (get an ISP redirection to an error page), but if my outgoing packets have the src address set to 2.234.35.29, the gateway accepts them and everything works. I managed to add 2.234.35.29 as a secondary address to my Ethernet interface, so the situation is more or less:


```
em0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=4209b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC,VLAN_HWTSO>
        ether d0:d4:12:xx:xx:xx
        hwaddr 00:00:24:xx:xx:xx
        inet6 fe80::xxxx:xxxx:xxxx:xxxx%em0 prefixlen 64 scopeid 0x1
        inet 10.151.105.106 netmask 0xffffffc0 broadcast 10.151.105.127     # dhcp assigned
        inet 2.234.35.29 netmask 0xffffffff broadcast 2.234.35.29           # manually added
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
```

The point is, FreeBSD chooses 10.151.105.106 as _source_ address for the locally generated outgoing packets, as this is address is in the same subnet of the default gateway, I guess. I want it to set it to generate packets with src=2.234.35.29. This seems to be easily doable in Linux (`route ... src ...`), but apparently the `src` option is not available in FreeBSD's `route` command.

I dug deep into this forum, and other people asked similar questions in the past. They were pointed towards policy based routing or to setfib. I read about policy based routing, but it seems to me that it is helpful in setting for example the next hop of a package (`ipfw add fwd ...`, that is _source based routing_), but I couldn't find a way to change the default source address. On the other side, setfib seems conceived to set routing tables per-process, not system wide.

Again: I don't want to do source based routing, but somehow the contrary: *route based source selection*.

Changing the src address with a NAT rule does the job, but I don't think it's the best thing to do.
I would like the packets to be generated with the correct address in the first place.

What could I try?

Thank you


----------



## asteriskRoss (Feb 23, 2018)

Welcome to the forums, pl. Can you link to the old posts that you found?

I also thought of NAT as I was reading your post.  It certainly feels clumsy but would get the job done.

Rather than solve the problem, can you avoid it?  Do you actually need your dynamically assigned address?  Could you turn off DHCP and set up your public address and default_gateway="10.151.105.whatever" in rc.conf(5)?

I see that your public IP address is configured as an alias, with the private IP address configured as a primary address for the interface.  Does the behaviour change if you reverse the order to make the public IP address the primary one?  I suggest trying this by hand first, disabling dhclient on the interface.  It might (or might not _[Edit: I tried it and it's not possible]_ as it is a bit topsy-turvy) be possible to make a permanent change a combination of the fixed-address and alias options in dhclient.conf(5).  Your routing table (`netstat -rn`) likely includes a route for the 10.151.105.106/26 network.  Even with your public IP as your primary address, it _might_ (I would need to test by experimenting) be necessary to delete this route to have the primary IP address assigned.


----------



## pl (Feb 23, 2018)

Thanks for your reply. This is the old post:

https://forums.freebsd.org/threads/how-to-change-default-source-address.6479/

and indeed NAT works but feels clumsy. On your first suggestion: I will try, but in order to set a gateway, shouldn't I have an IP address on the same subnet of the gateway? Otherwise, I wonder, how is the gateway itself reached?

I will also try to reverse the order of the primary and secondary IP addresses on em0 and get back.


----------



## asteriskRoss (Feb 24, 2018)

You make a good point regarding the default router being on the same subnet -- I feel foolish for not thinking it through properly.  It is possible to specify a static route using route(8), using the -interface switch to specify a directly reachable destination.  Perhaps you could set up a static route to the default gateway?

I also see it is possible to add a static route with the -link switch.  It is possible to add static ARP table entries with arp(8) using the -s option.  This can be preserved across reboots using the static_arp_pairs option in rc.conf(5).  This would allow you to specify the MAC address of the default gateway without the need for ARP, though if the gateway's MAC address changes it will require a manual update.

Perhaps one or a combination of these may allow the machine to use a default gateway that is on a different subnet?


----------



## asteriskRoss (Feb 24, 2018)

It's probably also worth pointing out that with the possible exception of assigning the static public IP as primary and the DHCP assigned private address as an alias by configuring dhclient.conf(5), which may or may not be possible _[Edit: I tried it and it's not possible]_ and may or may not work _[Edit: As per pl's post below, it doesn't work]_, all my suggestions are feeling more clumsy than a NAT solution.


----------



## pl (Feb 25, 2018)

Thanks asteriskRoss, all good things to try, but unfortunately none did work around my problem. More in detail:

Setting the public IP as primary, and the 10.x.x.x IP as an alias doesn't work: the 10.x.x.x IP is still chosen as the default source. I expected this, as it is the IP in the subnet of the default gw, but I still tried.
Manually configuring the interface with the public IP and then using `route -interface` to set up a remote gateway did work, great idea! But after a while the provider kills the connection. Apparently they check if the private IP is alive every few minutes, so I still need to keep it configured.
I did not try `ip -link`, but the same problem of using `-interface` will occur.
Any further suggestion or idea is welcome...


----------



## asteriskRoss (Feb 26, 2018)

I found an old post seeking to solve the same issue: Thread ipv4-source-address-selection.1425.

I tried to find what the logic is in FreeBSD to choose a source IP address but couldn't find it documented (I was hoping for something like this, which details rules for source IP address selection for two versions of Microsoft Windows) and a quick delve into the FreeBSD source code (I thought /usr/src/sys/inet/ip_output.c looked likely) didn't enlighten me either.  That said if you want to talk to a machine with an address that is in the same subnet as one of your own addresses, then using that source address makes most sense.

For me, any solution that it may or may not be possible to hack together that involves multiple routing tables and cloned interfaces would be inferior to a solution using NAT.


----------



## pl (Feb 26, 2018)

I also tried to find the source address selection rules for FreeBSD, but I wasn't able to. I assume they are basically the same Linux uses, but without the "src" part (that is exactly what I'm looking for).

In the end I think that FreeBSD just lacks the support for manually selecting the preferred source address, and a NAT seems the cleanest solution.

Thanks for your help, asteriskRoss.


----------

