Subject: [Hipsec] Issue 16: Details of LSI handling

From: [email-masked] (Henderson, Thomas R)
Date: Mon Sep 29 12:00:01 2003

PN> A clarifying question:  How do you make sure that the two
PN> communicating hosts have the same idea of their IP addresses?
PN> That is, if you use IP addresses (instead of LSIs) in the IPv4
PN> API, how do you make e.g. FTP or SIP to work?
PN>=20
PN> I am not saying that it is impossible, I am just stating that
PN> I don't understand how you do it.
PN>=20
PN> There are a number of current protocols that carry IP(v4)
PN> addresses in the payload.  One of the reasons for using LSIs
PN> is to make these work.

I have not seen a perfect solution to this problem.  In our=20
discussions in SF, there were two schools of thought, if I recall=20
correctly:

i) have resolver return an LSI in place of an actual IP address,=20
and have applications use the LSI instead of the IP address in=20
socket calls.  By making LSI fall into an unassigned IP address=20
space, the kernel could distinguish between calls made with an LSI=20
and calls made with an IP address.  Now some complications with=20
this approach are:
  - one probably does not want to invoke a HIP exchange just because=20
    someone did a DNS lookup on a hostname (applications use resolver=20
    for other reasons than just prior to initiating a flow).  Since
    we made the LSIs a subset of the HIT bits, we could avoid having
    to do the HIP exchange to find the LSIs, if it weren't for the
    possibility of collision (the problem with which Pekka started=20
    this thread).  So this approach seems to be pointing us
    towards doing HIP exchanges prior to the application's initial
    socket calls.  Note that this would also break the opportunity
    to piggyback data on the I2/R2.
  - what happens if kernel is presented with an LSI for which it=20
    has no HIP or IP address information cached?
  - some applications might actually want IP addresses explicitly,
    such as diagnostic applcations.
  - some applications likely will obtain addresses out-of-band, so
    even in this scenario, the kernel may be faced with a case where
    it would like to use HIP from a policy standpoint, but the=20
    invoking application called connect() with an IP address.
One way around might be to have a separate resolver call that
returns an LSI, or enhance the data structure returned by resolver
to include LSI in addition to IP address, but this then throws the=20
burden on applications to be HIP-aware.

ii) have HIP be kept in kernel land, with the kernel doing the=20
right housekeeping.  Unless the application is HIP aware and
can explicitly signal that it wants to use HIP (such as with
a setsockopt() flag), the use of HIP is coordinated by a policy
table that temporarily traps packets going to particular IP
addresses until a HIP exchange completes and the security=20
association is set up.  In this case, the kernel does the right
checksum munging and handles readdressing, in a manner transparent
to the applications, which just think that they have connected
to an IP address as before.  This essentially means that the
kernel is responsible for managing the association between=20
IP address (as perceived by an application) and actual destination
identity.  Although this is similar to the way that opportunistic
IPsec works today, this solution has the following drawbacks:
  - one is architecturally forced back into the mode of using IP
    addresses to indirectly identify hosts, at least initially. =20
    The IP stack has to maintain tables that say things like "if=20
    a socket call comes in for address X, do a HIP exchange to that=20
    address." (note that this may require an opportunistic exchange)
    This constrains the kinds of mobility that the system can handle. =20
  - one can construct scenarios for which the kernel and applications
    are out of sync with respect to IP addresses, and flows may
    escape their intended IPsec envelope.  Example:  I open FTP
    control connection to address X.  That host moves to address Y.
    Some other host takes up address X.  I next receive a connect()
    to address X.  Which host does that process want to connect to?

Long term, I'd like to see host identity information exposed to=20
applications and explicitly used in socket calls, together with IP
addresses if need be, rather than the workarounds described above. =20
If the applications and sockets API are not HIP-aware, then it seems=20
to lead to problems whether one spoofs the IP address to the=20
applications or whether one tries to keep HIP under the hood
at all times.=20

For the time being (without changing applications), I favor approach=20
ii) above, because I haven't seen anyone effectively solve all of the=20
issues associated with i), and because ii) basically works without=20
changes to the applications except for some corner cases that we=20
haven't encountered.  Whichever solution we adopt, we probably should
document the various limitations or restrictions on use.=20

Tom

---

From: [email-masked] (Miika Komu)
Date: Tue Sep 30 05:49:00 2003

> PN> is to make these work.
TH> I have not seen a perfect solution to this problem.  In our
TH> discussions in SF, there were two schools of thought, if I recall
TH> correctly:

I think we need to take the best of the two schools of thought and avoid
the worst. We also may want an extra layer of indirection.

I begun doing my thesis on the HIP native API in the beginning of the
summer, but I haven't progressed very far yet because I have been swamped
with other work. I have to present some of the ideas from my thesis
related to the discussion before I can quote Thomas more. Many of the
ideas are from Jukka and Pekka (= my instructors). The mistakes, however,
are my own.

What is needed?

  In the HIP world, we want the applications to be independent of the IP
  layer in the HIP world. "Independent" here means that the applications
  _can_ use IP addresses directly if they want to but they can do just
  fine without.

Why is it needed?

  a) To ease up the transition from IPv4 to IPv6. Later on we could have
     even IPvX but if we keep mangling the applications to specific
     versions of IP, we will never learn. Surely, there are some
     applications that should be aware of IP addresses but most network
     applications can do just fine without them.

  b) HIP requires something else than just the IP addresses to be _fully_
     functional. If we feed the socket interface just IP addresses, we
     will  get into trouble with mobility (see the bullet points in the
     "ii" alternative from Thomas).

How can it be done?

  The IP addresses are hidden from the applications that do not explicitly
  want them. This is accomplished by introducing a new socket address
  family "AF_HIP" (for use with socket(2)) and the corresponding socket
  structure "sockaddr_hip". The socket structure does not contain any IP
  addresses but instead contains a file descriptor (Host Identity
  Descriptor, HID) which is effectively a "virtual" pointer to a host
  identity (sockaddr_hip should probably contain the port number
  redundantly for backwards compatibility, but that is a bit
  off-the-topic).

  A totally new resolver function is probably needed because the resolver
  needs to do more things than a standard resolver. Typically the new HIP
  resolver inputs a FQDN name of the peer to be resolved and outputs a HID
  into a sockaddr_hip. The identities of the localhost can be queried with
  a separate function. The locahost/remote socket addresses can then be
  fed to the bind(2), connect(2), send(2), recv(2), etc.

  Under the hood of the resolver, the resolver queries the DNS for the
  Host Identity and the locators (IP addresses) of the peer. It sends the
  Host Identity and the locators to the HIP module and in return, receives
  a HID.  It must send the HI and the locators to the HIP module or
  otherwise HIP module won't be able to identify and locate the peer.

  The lower layer details are hidden in the interface. This does not mean
  that they cannot be revealed at all to the application: there is
  another interface (a set of functions) for tweaking, for example, the IP
  addresses under the hood.

  (This was my current view of thinking about the API and it may be out of
  sync with the current views of Pekka or Jukka because the API has been
  frozen  for a while. Back to quoting Thomas.)

TH> i) have resolver return an LSI in place of an actual IP address,
TH> and have applications use the LSI instead of the IP address in
TH> socket calls.  By making LSI fall into an unassigned IP address
TH> space, the kernel could distinguish between calls made with an LSI
TH> and calls made with an IP address.  Now some complications with
TH> this approach are:

This not part of the native API I just described. This is a "legacy"
API, that is, we do not want to change application code.

TH>   - one probably does not want to invoke a HIP exchange just because
TH>     someone did a DNS lookup on a hostname (applications use resolver
TH>     for other reasons than just prior to initiating a flow).

This is correct.

TH>     Since we made the LSIs a subset of the HIT bits, we could avoid
TH>     having to do the HIP exchange to find the LSIs, if it weren't for
TH>     the possibility of collision (the problem with which Pekka started
TH>     this thread).  So this approach seems to be pointing us
TH>     towards doing HIP exchanges prior to the application's initial
TH>     socket calls.  Note that this would also break the opportunity
TH>     to piggyback data on the I2/R2.

Breaking the piggypacking option is a performance drawback and thereby it
should be avoided. I think that the LSI collision problem can be overcome
with some method (Julien Laganier posted a solution for it) so that the
base exchange can be triggered on socket calls.

Anyway, that is a very good point you made! I haven't really thought about
that about triggering the base exchange before the socket calls...

TH>   - what happens if kernel is presented with an LSI for which it
TH>     has no HIP or IP address information cached?

Houston, we have a problem!) Currently, the LSI is just a partial,
temporary identifier and there is no guarantee that it can be resolved to
anything reasonable. One should use full identifiers, and most preferably
FQDNs because currently only they can be resolved to any of the other
forms (HIT, IP, LSI). The best thing would be to use the native API to
hide the LSI details :)

TH>   - some applications might actually want IP addresses explicitly,
TH>     such as diagnostic applcations.
TH>   - some applications likely will obtain addresses out-of-band, so
TH>     even in this scenario, the kernel may be faced with a case where
TH>     it would like to use HIP from a policy standpoint, but the
TH>     invoking application called connect() with an IP address.

Yes, there is a minor conflict here: should the legacy resolver return
LSIs or IP addresses by default? This is not an issue in the HIP native
resolver because the application using it is assumed to want HIP anyway.

TH> One way around might be to have a separate resolver call that
TH> returns an LSI, or enhance the data structure returned by resolver
TH> to include LSI in addition to IP address, but this then throws the
TH> burden on applications to be HIP-aware.

In this way of thinking, the resolver should return also a HIT. I would
prefer that the new resolver communicates the LSIs and HITs directly to
the HIP module. This way the application can even be non-HIP-aware if that
is wanted.

I don't think it is a bad idea to make the network applications HIP-aware,
or at least some of them. The applications may gain a better control of
the extra HIP layer by using the native API. The applications using the
native HIP API may even have their own application specific identities,
but that is a bit off-the-topic...

TH> ii) have HIP be kept in kernel land, with the kernel doing the
TH> right housekeeping.  Unless the application is HIP aware and
TH> can explicitly signal that it wants to use HIP (such as with
TH> a setsockopt() flag), the use of HIP is coordinated by a policy
TH> table that temporarily traps packets going to particular IP
TH> addresses until a HIP exchange completes and the security
TH> association is set up.  In this case, the kernel does the right
TH> checksum munging and handles readdressing, in a manner transparent
TH> to the applications, which just think that they have connected
TH> to an IP address as before.  This essentially means that the
TH> kernel is responsible for managing the association between
TH> IP address (as perceived by an application) and actual destination
TH> identity.  Although this is similar to the way that opportunistic
TH> IPsec works today, this solution has the following drawbacks:
TH>   - one is architecturally forced back into the mode of using IP
TH>     addresses to indirectly identify hosts, at least initially.
TH>     The IP stack has to maintain tables that say things like "if
TH>     a socket call comes in for address X, do a HIP exchange to that
TH>     address." (note that this may require an opportunistic exchange)
TH>     This constrains the kinds of mobility that the system can handle.
TH>   - one can construct scenarios for which the kernel and applications
TH>     are out of sync with respect to IP addresses, and flows may
TH>     escape their intended IPsec envelope.  Example:  I open FTP
TH>     control connection to address X.  That host moves to address Y.
TH>     Some other host takes up address X.  I next receive a connect()
TH>     to address X.  Which host does that process want to connect to?

This is correct. Don't do this unless you are ready to accept a lower
level of security and mobility support.

TH> Long term, I'd like to see host identity information exposed to
TH> applications and explicitly used in socket calls, together with IP
TH> addresses if need be, rather than the workarounds described above.
TH> If the applications and sockets API are not HIP-aware, then it seems
TH> to lead to problems whether one spoofs the IP address to the
TH> applications or whether one tries to keep HIP under the hood
TH> at all times.

I'd like to keep HIP under the hood but make there a button the
applications can push to pop the hood for twiddling with the engine. There
is no need for the most of the application to see under the hood, they
just need to drive the network car ;)

TH> For the time being (without changing applications), I favor approach
TH> ii) above, because I haven't seen anyone effectively solve all of the
TH> issues associated with i), and because ii) basically works without
TH> changes to the applications except for some corner cases that we
TH> haven't encountered.  Whichever solution we adopt, we probably should
TH> document the various limitations or restrictions on use.

I will try out the option iii and see how it goes (I am open to any
suggestions and feedback). And yes, we need to document the API whatever
it is going to be. Hopefully my thesis will serve as a background work
for writing later on a official HIP socket API draft...

P.S. Sorry for bloated answer, I just could not squeeze it any shorter ;)

-- 
Miika Komu              [email-masked]          http://www.iki.fi/miika/