[Top] [All Lists]

Re: How to determine source ip address

To: Julian Anastasov <ja@xxxxxx>
Subject: Re: How to determine source ip address
From: Padraig Brady <padraig@xxxxxxxxxxxxx>
Date: Tue, 11 Sep 2001 18:47:07 +0100
Cc: Christopher Friesen <cfriesen@xxxxxxxxxxxxxxxxxx>, netdev@xxxxxxxxxxx
References: <Pine.LNX.4.33.0109102359080.1850-100000@xxxxxxxxxxxx>
Sender: owner-netdev@xxxxxxxxxxx
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.3) Gecko/20010808
Julian Anastasov wrote:


On Mon, 10 Sep 2001, Christopher Friesen wrote:

Padraig Brady wrote:

I'm writing a network app (currently on linux 2.2.18,
but soon moving to 2.4) that needs to build up ip &
tcp packets manually. So my question is how do I determine
the source ip address to use for a given destination
ip address. I.E. take account of multiple interfaces/routes/

How low in the protocol stack are you going?  If you use an IP raw socket with
IP_HDRINCL and just leave the sending address filled with zeros, then it will be
filled in with the default address for the link used to send to the destination
address.  See the man page on raw(4) for more details.

Chris, I'm only filling in the TCP header, and I realise the IP header will be
filled appropriately when sent. However I need to calculate the checksum for
the TCP header which is actually calculated for the pseudo header:

struct pseudo_header {
   unsigned int src_address; /* <==-- */
   unsigned int dest_address;
   unsigned char placeholder;
   unsigned char protocol;
   unsigned short tcp_length;
   struct tcphdr tcp;
}  pseudo_header;

So I need to determine the source address before sending...

        Looking in udp_sendmsg and raw_sendmsg() I don't see the
saddr argument in the route lookup call to depend on the IP_HDRINCL
option (which is an raw socket option only). The same mistake (as your
assumption) you can see in the (latest?) traceroute-1.4a12 where bind()
is surrounded in #ifndef IP_HDRINCL. As result bind() is not called and
the packets go to wrong route.

        As for the question from Padraig: you have to create SOCK_DGRAM
socket, then to connect() it to the target address (any port), then to
get the generated source address from the kernel by calling getsockname().
Now you have the source that the kernel usually uses to talk with the
specified target.

Cool. I was unsure that would work, and forgot about getsockname(). Thanks!

Then you have to create the actual data socket and to
call bind() for the source address from the previous step and then to
connect()/sendto() to the newly created socket. Without bind() your
data will not be routed considering the source address in the IP
header. Such routing problem is usually noticed when you have two or more
routes to the universe. If you send with different source addresses
from one socket then the handling will be more complex. May be then you
have to play with IP_PKTINFO. My man page is incorrect here, it claims that
ipi_spec_dst contains the destination address but raw_sendmsg uses it as
source address. The oif value is correctly used. The only problem may be
is that IP_PKTINFO should be called before sending each packet. So, may be
there is no way to specify different source address (for the routing call)
in sendmsg(). You have to change it with IP_PKTINFO call each time.

I don't have to worry about source routing, but thanks for the info. I don't think
I have to call connect() so, do I?

I'm still unsure how to get a source port that will never clash with
existing connections, but that's not a major problem.


<Prev in Thread] Current Thread [Next in Thread>