Subject: patch rfc: source-address selection policy
To: None <tech-net@netbsd.org>
From: David Young <dyoung@pobox.com>
List: tech-net
Date: 09/20/2005 18:43:56
I have a patch, <http://tinyurl.com/89hkx>, and a bundle of files,
<http://tinyurl.com/az9wh>, that add IPv4 source address-selection
policies to NetBSD.

Problem

  Today, an operator can assign two or more IPv4 addresses to a single
  network interface on his NetBSD host, but he cannot directly express
  his preference that NetBSD should choose one address over another
  as local address for a socket bound to the "don't care" address,
  INADDR_ANY.  For such a socket, NetBSD arbitrarily chooses the first
  address on the outgoing interface.  An arbitrary choice does not suit
  every application.  I will give some examples.

  One local address may be more suitable than another for connections to a
  particular remote address.  For example, on an interface with addresses
  169.254.3.7/16 and 10.0.3.2/24 assigned, an operator may prefer that
  packets with link-local destinations (169.254/16, 224.0.0/24) carry
  a link-local source address, 169.254.3.7, while packets with other
  destinations should use the source 10.0.3.2.

  An operator may likewise assign an interface both an address 10.1.2.3/24
  for the corporate WAN (10/8), and 64.233.167.147/28, which is assigned
  by the local ISP, preferring for connections to hosts on the corporate
  WAN to use the source 10.1.2.3, and connections to the Internet to
  use the source 64.233.167.147.

  An operator may assign three addresses to an interface---10.0.0.1/24,
  10.0.0.2/24, and 10.0.0.3/24---preferring that only 10.0.0.3/24 is
  used as a local address.

  None of these source address-selection preferences can be expressed
  to the NetBSD kernel, today.

Solution

  First, I add a facility for labeling addresses with "preference
  numbers".  Set preference numbers using ifconfig(8):

% ifconfig ath0 inet
ath0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
        inet 10.0.237.106 netmask 0xffffffff broadcast 10.0.237.106
        inet alias 169.254.237.106 netmask 0xffff0000 broadcast 169.254.255.255
% ifconfig ath0 inet alias 169.254.237.106/16 preference 10
% ifconfig ath0 inet
ath0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
        inet 10.0.237.106 netmask 0xffffffff broadcast 10.0.237.106 preference 0
        inet alias 169.254.237.106 netmask 0xffff0000 broadcast 169.254.255.255 preference 10

  I also add to each interface a "policy vector," a comma-delimited list
  of policies for source selection, which are evaluated in order:

% sysctl net.inet.ip.ath0.selectsrc
net.inet.ip.ath0.selectsrc = same-category,common-prefix-len,preference
% sysctl -w net.inet.ip.ath0.selectsrc=index
net.inet.ip.ath0.selectsrc: same-category,common-prefix-len,preference -> index

  The policies are in priority order, highest priority first.

  Evaluating a policy on a source address produces a score.  The
  highest-scoring source address is selected, with ties broken by choosing
  the address closest to the head of the interface's address list.

  I define four policies, 'index', 'common-prefix-len', 'preference',
  and 'same-category'.  'index' assigns higher scores to addresses
  near the head of an interface's address list.  'common-prefix-len'
  assigns a score equal to the length of the longest prefix the source
  and destination have in common.  'same-category' assigns a score of 1
  if the source and destination belong to the same "category" of address,
  one of "link-local" (224/8, 169.254/16), RFC1918 (10/8, 172.16/12,
  192.168/16) or "global" (all others); otherwise, 'same-category'
  assigns 0.  'preference' assigns a score equal to a source's preference
  number, negated; in this way, lower preference numbers are preferred.

  It is easy to add more policies to the four I already define.
  Using policy vectors, it is possible to express a large and useful
  set of policies.

Outstanding issues that I will fix before committing:

  1 The default policy ought to be 'index', since that is functionally
    identical to the status quo.

  2 The synchronization is not right, yet.

  3 It is not possible to set a global default policy.

  4 Negative preference numbers should be allowed, or else the default
    preference should be greater than 0, so that it is possible to
    preempt addresses assigned automatically by programs that do not
    grok preference numbers (dhclient, say).

  5 Needs a manual page.

Issues for further study:

  1 It is not an option to forbid a socket from binding a different
    address than the a socket can still be bound to an address on a
    different interface than the outgoing interface (NetBSD remains
    a Weak ES).  To correct this, modifications to in_pcbconnect will
    be necessary.

  2 There is no IPv6 implementation of address preferences or policy
    vectors.

  3 We cannot enforce different policies on different processes.

Dave

-- 
David Young             OJC Technologies
dyoung@ojctech.com      Urbana, IL * (217) 278-3933