# [Solved] Source IP Selection

## jasealpers

I have a machine set up as my router.  It does masquerading and NAT, etc with a custom firewall built with iptables.  I also have my internal network card bridged with a tap device for OpenVPN.  This all works great.

/etc/conf.d/net

```

depend_br0() {

   need net.eth1 net.tap0

}

config_eth0="dhcp"

dhcp_eth0=( "nodns nontp" )

config_eth1=( "0.0.0.0 promisc" )

tuntap_tap0="tap"

config_tap0=( "0.0.0.0 promisc" )

bridge_br0="eth1 tap0"

config_br0=( "192.168.214.8 broadcast 192.168.214.255 netmask 255.255.255.0" )

brctl_br0=( "setfd 0" )

```

I also have some scripts accessing apache's server-status and MySQL that are also running on this machine.  Both of these resources are configured to allow connections from the internal network (192.168.214.xxx), but not from the external network.

For some reason, a request originating from this machine going to this machine uses the IP bound to eth0 (the external IP).  I ran tcpdump and can see that the traffic flows over the local interface (lo).  Why does it use the external IP?  

How can I get it to use a different source IP (either the one bound to lo or the one bound to br0)?

Thanks in advance for the help!

JaseLast edited by jasealpers on Wed Oct 29, 2008 9:15 pm; edited 1 time in total

----------

## Hu

 *jasealpers wrote:*   

> 
> 
> For some reason, a request originating from this machine going to this machine uses the IP bound to eth0 (the external IP).  I ran tcpdump and can see that the traffic flows over the local interface (lo).  Why does it use the external IP?

 

The short and unhelpful answer is: because you told it to do that.  If the destination is the IP address of eth0, then the source will be as well.  Similarly, if you set a destination of the loopback address, the source will also be loopback.

 *jasealpers wrote:*   

> 
> 
> How can I get it to use a different source IP (either the one bound to lo or the one bound to br0)?
> 
> 

 

Change the client to use a destination IP associated with the desired interface.  If you are not sure how to do this, please post what scripts you are using to access Apache / MySQL and how you configured those scripts.

----------

## jasealpers

Thanks for the response!

 *Quote:*   

> 
> 
> If the destination is the IP address of eth0, then the source will be as well. Similarly, if you set a destination of the loopback address, the source will also be loopback. 
> 
> 

 

This isn't quite what I observe.  If the destination is localhost (or 127.0.0.1), it will use 127.0.0.1 as the source IP.  However, if the destination is 192.168.214.8 (bound to br0), the source IP will still be the IP address of eth0.

The scripts I mentioned are used under the covers for cacti.  The apache one is in perl.  Here is the relevant part...

```

$RETRIEVER="/usr/bin/wget --user-agent=\"ApacheStats\/0.4 wget\/1.8\" -q -O - -t3 -T5";

delete $ENV{'HTTP_PROXY'};

delete $ENV{'http_proxy'};

my $hostname = $ARGV[0];

chomp $hostname;

if ($hostname eq 'go' | $hostname eq '192.168.214.8') {

        $hostname = "localhost";

}

# Set the query URL:

$URL = "http:\/\/".$hostname."\/server-status?auto";

# Run the query:

$output = `$RETRIEVER $URL`;

```

You can see I added a line to convert go or 192.168.214.8 (internal IPs) to localhost as a workaround in this script.  I also discovered there is a --bind-address option in wget to control the source address for wget only.

The MySQL script is written in php...

```

if (@mysql_connect($host, $username, $password)) {

...

}

```

The host that is passed in here is "go" which is the hostname for 192.168.214.8 in /etc/hosts.  I'm not that fluent in php.  I expect perhaps there is a similar option to --bind-address in php that could be used here.  Or, I could use the same workaround to modify $host on the fly to localhost.

However, I was hoping there was a more global option to force the source address to be the one bound to br0 anytime the destination was an IP address in the same subnet as br0.

Thanks again for the help!

----------

## Hu

 *jasealpers wrote:*   

> However, if the destination is 192.168.214.8 (bound to br0), the source IP will still be the IP address of eth0.

 

Interesting.  This is probably a side effect of how bridging works.  I had never noticed that before.

 *jasealpers wrote:*   

> 
> 
> ```
> 
> $URL = "http:\/\/".$hostname."\/server-status?auto";
> ...

 

You do not need to escape the slashes in this context.  They only need to be escaped when used in a context where they would terminate the expression, such as m// or s///.

 *jasealpers wrote:*   

> 
> 
> ```
> 
> $output = `$RETRIEVER $URL`;
> ...

 

You can get more precise control over receiving the output if you use open to open a pipe to the child process.

 *jasealpers wrote:*   

> You can see I added a line to convert go or 192.168.214.8 (internal IPs) to localhost as a workaround in this script.  I also discovered there is a --bind-address option in wget to control the source address for wget only.

 

That is a reasonable workaround, and I am not aware of a better alternative.

 *jasealpers wrote:*   

> However, I was hoping there was a more global option to force the source address to be the one bound to br0 anytime the destination was an IP address in the same subnet as br0.

 

I have never looked for such an option, so I cannot say whether it exists.  I can say that it is somewhat unusual to put an address on slave interfaces and also on the bridge interface.  The kernel may be selecting the undesirable address based on it being a better match according to the routing table.  What is the output of ip addr ; ip route?

----------

## jasealpers

 *Hu wrote:*   

> 
> 
> I can say that it is somewhat unusual to put an address on slave interfaces and also on the bridge interface.  The kernel may be selecting the undesirable address based on it being a better match according to the routing table.
> 
> 

 

I'm not sure I follow this.  I think the IP address is only assigned to br0 (although I do see the same inet6 addr for br0, eth1 and tap0 - I'm not using inet6).  I'm assuming you are referring to eth1 and/or tap0 when you say "slave interface"?

Here is the output of ifconfig:

```

br0       Link encap:Ethernet  HWaddr {scrubbed}

          inet addr:192.168.214.8  Bcast:192.168.214.255  Mask:255.255.255.0

          inet6 addr: {scrubbed} Scope:Link

          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

          RX packets:1728842 errors:0 dropped:0 overruns:0 frame:0

          TX packets:2207069 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:490167102 (467.4 MiB)  TX bytes:1490255026 (1.3 GiB)

eth0      Link encap:Ethernet  HWaddr {scrubbed}

          inet addr:xxx.xxx.xxx.xxx  Bcast:255.255.255.255  Mask:255.255.240.0

          inet6 addr: {scrubbed} Scope:Link

          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

          RX packets:10158571 errors:0 dropped:0 overruns:1 frame:0

          TX packets:905657 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:1000

          RX bytes:1364146860 (1.2 GiB)  TX bytes:172903282 (164.8 MiB)

          Interrupt:11 Base address:0xe800

eth1      Link encap:Ethernet  HWaddr {scrubbed}

          inet6 addr: {scrubbed} Scope:Link

          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1

          RX packets:1788986 errors:0 dropped:0 overruns:0 frame:0

          TX packets:2206981 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:1000

          RX bytes:524310098 (500.0 MiB)  TX bytes:1491607779 (1.3 GiB)

          Interrupt:9 Base address:0x4c00

lo        Link encap:Local Loopback

          inet addr:127.0.0.1  Mask:255.0.0.0

          inet6 addr: ::1/128 Scope:Host

          UP LOOPBACK RUNNING  MTU:16436  Metric:1

          RX packets:522147 errors:0 dropped:0 overruns:0 frame:0

          TX packets:522147 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:43548854 (41.5 MiB)  TX bytes:43548854 (41.5 MiB)

tap0      Link encap:Ethernet  HWaddr {scrubbed}

          inet6 addr: {scrubbed} Scope:Link

          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1

          RX packets:20918 errors:0 dropped:0 overruns:0 frame:0

          TX packets:103811 errors:0 dropped:22 overruns:0 carrier:0

          collisions:0 txqueuelen:100

          RX bytes:1384541 (1.3 MiB)  TX bytes:9199634 (8.7 MiB)

```

 *Hu wrote:*   

> 
> 
> What is the output of ip addr ; ip route?
> 
> 

 

I don't have the ip command.  I guess I don't have some package emerged?  Here is the output of route:

```

Kernel IP routing table

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface

192.168.214.0   *               255.255.255.0   U     0      0        0 br0

{external host} *               255.255.240.0   U     0      0        0 eth0

loopback        *               255.0.0.0       U     0      0        0 lo

default         {external host} 0.0.0.0         UG    0      0        0 eth0

```

Thanks again for the help!

----------

## Hu

 *jasealpers wrote:*   

> 
> 
> I'm not sure I follow this.  I think the IP address is only assigned to br0 (although I do see the same inet6 addr for br0, eth1 and tap0 - I'm not using inet6).  I'm assuming you are referring to eth1 and/or tap0 when you say "slave interface"?

 

Yes.  Your external interface, eth0, is configured via DHCP.  I mistakenly thought it was involved in the bridge.  Looking more closely, I think you have it set correctly.

 *jasealpers wrote:*   

> 
> 
> I don't have the ip command.  I guess I don't have some package emerged?  Here is the output of route:
> 
> 

 

/sbin/ip is part of sys-apps/iproute2.  Although sys-apps/net-tools works, the commands in sys-apps/iproute2 are often preferred for more complex network configurations.

I see nothing in the output that would explain the cause or suggest a remedy for your observed behavior of using the eth0 IP address when connecting to the br0 IP address.

----------

## jasealpers

Hu, thanks again for the help.  

I guess unless there are any other suggestions, I'll just implement the workaround script by script to specify the localhost as the destination IP.  :Sad: 

----------

## jasealpers

I figured out my problem.  I am using masquerading and had this as the first rule in my nat table's POSTROUTING chain.

```

target     prot opt in     out     source               destination

MASQUERADE  all  --  any    any     192.168.214.0/24     anywhere

```

So, iptables was altering the internal IP to the external IP before handing it over to my local process (Apache, MySQL, etc).  I added an ACCEPT of any internal traffic to avoid the masquerading for these cases and voila ... problem solved.

```

target     prot opt in     out     source               destination

ACCEPT     all  --  any    any     go                   anywhere

MASQUERADE  all  --  any    any     192.168.214.0/24     anywhere

```

Thanks again for the help, Hu.  

Chalk this up to a user error  :Smile: 

----------

