new dhclient.conf option: host-route

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

new dhclient.conf option: host-route

Stefan Sperling-8
In some networks (e.g. at public events using open wifi) I want
traffic not destined for the local network to go through a VPN.

If the local network uses DHCP, I usually end up killing dhclient
because it's impossible to renew the lease without changing the
default route.

To be clear, I end up with a command sequence like:

 dhclient wpi0  # get a local address
 netstat -rn -finet | grep ^default  # figure out local router
 route delete default # don't use local router for everything
 route add -host $VPN_SERVER_IP $LOCAL_ROUTER # just for this host
 openvpn config-file # start VPN, i am too dumb for ipsec
 route add default $ROUTER_BEHIND_VPN # use my trusted router as default
 pkill -x dhclient # kill dhclient to avoid default route change later

The problem is that the lease expires at some point and things
usually stop working until I perform the same tedious configuration
dance again.

The patch below adds a new option to dhclient.conf (the VPN server is
at 10.1.1.1 in this example):

  interface "wpi0" {
          host-route 10.1.1.1;
  }

Instead of adding a default route dhclient will add a host route
to the specified address. So the above sequence becomes:

 dhclient wpi0  # get a local address, add route to VPN server
 openvpn config-file # start VPN
 route add default $ROUTER_BEHIND_VPN # use my trusted router as default

And the configuration remains stable.

Is this a good approach?
Does anyone else think this is useful?


Index: clparse.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/clparse.c,v
retrieving revision 1.37
diff -u -p -r1.37 clparse.c
--- clparse.c 4 Apr 2011 11:14:52 -0000 1.37
+++ clparse.c 12 Aug 2011 18:04:02 -0000
@@ -151,7 +151,8 @@ read_client_leases(void)
  * interface-declaration |
  * TOK_LEASE client-lease-statement |
  * TOK_ALIAS client-lease-statement |
- * TOK_REJECT reject-statement
+ * TOK_REJECT reject-statement |
+ * TOK_HOST_ROUTE host-route-statement
  */
 void
 parse_client_statement(FILE *cfile)
@@ -234,6 +235,9 @@ parse_client_statement(FILE *cfile)
  case TOK_REJECT:
  parse_reject_statement(cfile);
  return;
+ case TOK_HOST_ROUTE:
+ parse_host_route_statement(cfile);
+ return;
  default:
  parse_warn("expecting a statement.");
  skip_to_semi(cfile);
@@ -739,6 +743,25 @@ parse_reject_statement(FILE *cfile)
  token = next_token(&val, cfile);
  } while (token == ',');
 
+ if (token != ';') {
+ parse_warn("expecting semicolon.");
+ skip_to_semi(cfile);
+ }
+}
+
+void
+parse_host_route_statement(FILE *cfile)
+{
+ char *val;
+ int token;
+
+ if (!parse_ip_addr(cfile, &config->host_route)) {
+ parse_warn("expecting IP address.");
+ skip_to_semi(cfile);
+ return;
+ }
+
+ token = next_token(&val, cfile);
  if (token != ';') {
  parse_warn("expecting semicolon.");
  skip_to_semi(cfile);
Index: conflex.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/conflex.c,v
retrieving revision 1.13
diff -u -p -r1.13 conflex.c
--- conflex.c 17 Dec 2006 17:41:56 -0000 1.13
+++ conflex.c 12 Aug 2011 18:00:51 -0000
@@ -324,6 +324,7 @@ static const struct keywords {
  { "filename", TOK_FILENAME },
  { "fixed-address", TOK_FIXED_ADDR },
  { "hardware", TOK_HARDWARE },
+ { "host-route", TOK_HOST_ROUTE },
  { "initial-interval", TOK_INITIAL_INTERVAL },
  { "interface", TOK_INTERFACE },
  { "lease", TOK_LEASE },
Index: dhclient-script
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhclient-script,v
retrieving revision 1.22
diff -u -p -r1.22 dhclient-script
--- dhclient-script 9 Apr 2011 19:53:00 -0000 1.22
+++ dhclient-script 12 Aug 2011 18:06:00 -0000
@@ -60,11 +60,16 @@ delete_old_routes() {
 add_new_routes() {
  route -q $rdomain -n flush -inet -iface $interface
  for router in $new_routers; do
- if [ "$new_ip_address" = "$router" ]; then
- route -q $rdomain add default -iface $router
+ if [ -n "$host_route" -a "$host_route" != "0.0.0.0" ]; then
+ new_route="-host $host_route $router"
  else
- route -q $rdomain add default $router
+ if [ "$new_ip_address" = "$router" ]; then
+ new_route="default -iface $router"
+ else
+ new_route="default $router"
+ fi
  fi
+ route -q $rdomain add $new_route
  # 2nd and subsequent default routers error out, so explicitly
  # stop processing the list after the first one.
  break
Index: dhclient.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.141
diff -u -p -r1.141 dhclient.c
--- dhclient.c 11 May 2011 14:38:36 -0000 1.141
+++ dhclient.c 12 Aug 2011 18:06:57 -0000
@@ -1604,6 +1604,9 @@ supersede:
  }
  snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
  script_set_env(prefix, "expiry", tbuf);
+
+ if (config->host_route.len)
+ script_set_env("", "host_route", piaddr(config->host_route));
 }
 
 void
Index: dhclient.conf.5
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhclient.conf.5,v
retrieving revision 1.21
diff -u -p -r1.21 dhclient.conf.5
--- dhclient.conf.5 9 Apr 2011 19:53:00 -0000 1.21
+++ dhclient.conf.5 13 Aug 2011 19:18:56 -0000
@@ -430,6 +430,13 @@ If no lease is acquired, the script is u
 any, and also called once if no valid lease can be identified.
 For more information, see
 .Xr dhclient.leases 5 .
+.It Ic host-route Ar ip-address ;
+The
+.Ic host-route
+statement causes the DHCP client to install a host route to the specified
+IP address instead of installing a default route.
+This is useful if the default route points to a VPN tunnel terminated
+at the specified IP address instead of a router on the local network.
 .El
 .Sh EXAMPLES
 The following configuration file is used on a laptop
Index: dhcpd.h
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhcpd.h,v
retrieving revision 1.73
diff -u -p -r1.73 dhcpd.h
--- dhcpd.h 11 May 2011 14:38:36 -0000 1.73
+++ dhcpd.h 12 Aug 2011 18:03:23 -0000
@@ -150,6 +150,7 @@ struct client_config {
  enum { IGNORE, ACCEPT, PREFER }
  bootp_policy;
  struct iaddrlist *reject_list;
+ struct iaddr host_route;
 };
 
 struct client_state {
@@ -344,3 +345,4 @@ void parse_client_lease_declaration(FILE
 int parse_option_decl(FILE *, struct option_data *);
 void parse_string_list(FILE *, struct string_list **, int);
 void parse_reject_statement(FILE *);
+void parse_host_route_statement(FILE *);
Index: dhctoken.h
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhctoken.h,v
retrieving revision 1.5
diff -u -p -r1.5 dhctoken.h
--- dhctoken.h 15 May 2006 08:10:57 -0000 1.5
+++ dhctoken.h 12 Aug 2011 18:03:38 -0000
@@ -79,6 +79,7 @@
 #define TOK_REJECT 292
 #define TOK_FDDI 293
 #define TOK_LINK_TIMEOUT 294
+#define TOK_HOST_ROUTE 295
 
 #define is_identifier(x) ((x) >= TOK_FIRST_TOKEN && \
  (x) != TOK_STRING && \

Reply | Threaded
Open this post in threaded view
|

Re: new dhclient.conf option: host-route

Stuart Henderson
On 2011/08/16 12:08, Stefan Sperling wrote:

> In some networks (e.g. at public events using open wifi) I want
> traffic not destined for the local network to go through a VPN.
>
> If the local network uses DHCP, I usually end up killing dhclient
> because it's impossible to renew the lease without changing the
> default route.
>
> To be clear, I end up with a command sequence like:
>
>  dhclient wpi0  # get a local address
>  netstat -rn -finet | grep ^default  # figure out local router
>  route delete default # don't use local router for everything
>  route add -host $VPN_SERVER_IP $LOCAL_ROUTER # just for this host
>  openvpn config-file # start VPN, i am too dumb for ipsec

For OpenVPN you should be able to do '--redirect-gateway def1'
assuming you have sbin/route/route.c r1.153 or newer. (though for
an OpenBSD-OpenBSD connection, I find IPsec much easier to
configure than OpenVPN).

>  route add default $ROUTER_BEHIND_VPN # use my trusted router as default
>  pkill -x dhclient # kill dhclient to avoid default route change later
>
> The problem is that the lease expires at some point and things
> usually stop working until I perform the same tedious configuration
> dance again.
>
> The patch below adds a new option to dhclient.conf (the VPN server is
> at 10.1.1.1 in this example):
>
>   interface "wpi0" {
>           host-route 10.1.1.1;
>   }

If it's not considered of enough general use to change dhclient
itself, I think this might be something you could achieve by using
an alternative dhclient-script via 'script "/path/to/script";' e.g.
copy new_router to another var, unset new_router, call the original
dhclient-script, and add the host-route afterwards.

Either way (your patch or with a wrapper script) if a new IP address
is assigned you might have some problems with delete_old_routes
flushing all routes including the route over the tunnel; not sure
how important this is in practice in your case, but I think it
would be generally useful to be able to prevent this from occurring
(this would also let you fetch an address on an interface via DHCP
without changing routes, sometimes it can be rather useful to do
this on a machine where changing the default route will cause
disruption..)

Reply | Threaded
Open this post in threaded view
|

Re: new dhclient.conf option: host-route

Todd T. Fries-2
In reply to this post by Stefan Sperling-8
I have done this in a different way, namely by 'filtering' the variables
that are passed to /sbin/dhclient-script by using the
'script "/path/to/my/script"' option to run my own script, act on variables
I care about (dns and default gateway) and then calling /sbin/dhclient-script
in the event it still has something to do.

Honestly I think your approach is cleaner, and more likely to survive the
ever eminent promise from krw@ to remove the script entirely.

Thanks,

Penned by Stefan Sperling on 20110816  5:08.37, we have:
| In some networks (e.g. at public events using open wifi) I want
| traffic not destined for the local network to go through a VPN.
|
| If the local network uses DHCP, I usually end up killing dhclient
| because it's impossible to renew the lease without changing the
| default route.
|
| To be clear, I end up with a command sequence like:
|
|  dhclient wpi0  # get a local address
|  netstat -rn -finet | grep ^default  # figure out local router
|  route delete default # don't use local router for everything
|  route add -host $VPN_SERVER_IP $LOCAL_ROUTER # just for this host
|  openvpn config-file # start VPN, i am too dumb for ipsec
|  route add default $ROUTER_BEHIND_VPN # use my trusted router as default
|  pkill -x dhclient # kill dhclient to avoid default route change later
|
| The problem is that the lease expires at some point and things
| usually stop working until I perform the same tedious configuration
| dance again.
|
| The patch below adds a new option to dhclient.conf (the VPN server is
| at 10.1.1.1 in this example):
|
|   interface "wpi0" {
|           host-route 10.1.1.1;
|   }
|
| Instead of adding a default route dhclient will add a host route
| to the specified address. So the above sequence becomes:
|
|  dhclient wpi0  # get a local address, add route to VPN server
|  openvpn config-file # start VPN
|  route add default $ROUTER_BEHIND_VPN # use my trusted router as default
|
| And the configuration remains stable.
|
| Is this a good approach?
| Does anyone else think this is useful?
|
|
| Index: clparse.c
| ===================================================================
| RCS file: /cvs/src/sbin/dhclient/clparse.c,v
| retrieving revision 1.37
| diff -u -p -r1.37 clparse.c
| --- clparse.c 4 Apr 2011 11:14:52 -0000 1.37
| +++ clparse.c 12 Aug 2011 18:04:02 -0000
| @@ -151,7 +151,8 @@ read_client_leases(void)
|   * interface-declaration |
|   * TOK_LEASE client-lease-statement |
|   * TOK_ALIAS client-lease-statement |
| - * TOK_REJECT reject-statement
| + * TOK_REJECT reject-statement |
| + * TOK_HOST_ROUTE host-route-statement
|   */
|  void
|  parse_client_statement(FILE *cfile)
| @@ -234,6 +235,9 @@ parse_client_statement(FILE *cfile)
|   case TOK_REJECT:
|   parse_reject_statement(cfile);
|   return;
| + case TOK_HOST_ROUTE:
| + parse_host_route_statement(cfile);
| + return;
|   default:
|   parse_warn("expecting a statement.");
|   skip_to_semi(cfile);
| @@ -739,6 +743,25 @@ parse_reject_statement(FILE *cfile)
|   token = next_token(&val, cfile);
|   } while (token == ',');
|  
| + if (token != ';') {
| + parse_warn("expecting semicolon.");
| + skip_to_semi(cfile);
| + }
| +}
| +
| +void
| +parse_host_route_statement(FILE *cfile)
| +{
| + char *val;
| + int token;
| +
| + if (!parse_ip_addr(cfile, &config->host_route)) {
| + parse_warn("expecting IP address.");
| + skip_to_semi(cfile);
| + return;
| + }
| +
| + token = next_token(&val, cfile);
|   if (token != ';') {
|   parse_warn("expecting semicolon.");
|   skip_to_semi(cfile);
| Index: conflex.c
| ===================================================================
| RCS file: /cvs/src/sbin/dhclient/conflex.c,v
| retrieving revision 1.13
| diff -u -p -r1.13 conflex.c
| --- conflex.c 17 Dec 2006 17:41:56 -0000 1.13
| +++ conflex.c 12 Aug 2011 18:00:51 -0000
| @@ -324,6 +324,7 @@ static const struct keywords {
|   { "filename", TOK_FILENAME },
|   { "fixed-address", TOK_FIXED_ADDR },
|   { "hardware", TOK_HARDWARE },
| + { "host-route", TOK_HOST_ROUTE },
|   { "initial-interval", TOK_INITIAL_INTERVAL },
|   { "interface", TOK_INTERFACE },
|   { "lease", TOK_LEASE },
| Index: dhclient-script
| ===================================================================
| RCS file: /cvs/src/sbin/dhclient/dhclient-script,v
| retrieving revision 1.22
| diff -u -p -r1.22 dhclient-script
| --- dhclient-script 9 Apr 2011 19:53:00 -0000 1.22
| +++ dhclient-script 12 Aug 2011 18:06:00 -0000
| @@ -60,11 +60,16 @@ delete_old_routes() {
|  add_new_routes() {
|   route -q $rdomain -n flush -inet -iface $interface
|   for router in $new_routers; do
| - if [ "$new_ip_address" = "$router" ]; then
| - route -q $rdomain add default -iface $router
| + if [ -n "$host_route" -a "$host_route" != "0.0.0.0" ]; then
| + new_route="-host $host_route $router"
|   else
| - route -q $rdomain add default $router
| + if [ "$new_ip_address" = "$router" ]; then
| + new_route="default -iface $router"
| + else
| + new_route="default $router"
| + fi
|   fi
| + route -q $rdomain add $new_route
|   # 2nd and subsequent default routers error out, so explicitly
|   # stop processing the list after the first one.
|   break
| Index: dhclient.c
| ===================================================================
| RCS file: /cvs/src/sbin/dhclient/dhclient.c,v
| retrieving revision 1.141
| diff -u -p -r1.141 dhclient.c
| --- dhclient.c 11 May 2011 14:38:36 -0000 1.141
| +++ dhclient.c 12 Aug 2011 18:06:57 -0000
| @@ -1604,6 +1604,9 @@ supersede:
|   }
|   snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
|   script_set_env(prefix, "expiry", tbuf);
| +
| + if (config->host_route.len)
| + script_set_env("", "host_route", piaddr(config->host_route));
|  }
|  
|  void
| Index: dhclient.conf.5
| ===================================================================
| RCS file: /cvs/src/sbin/dhclient/dhclient.conf.5,v
| retrieving revision 1.21
| diff -u -p -r1.21 dhclient.conf.5
| --- dhclient.conf.5 9 Apr 2011 19:53:00 -0000 1.21
| +++ dhclient.conf.5 13 Aug 2011 19:18:56 -0000
| @@ -430,6 +430,13 @@ If no lease is acquired, the script is u
|  any, and also called once if no valid lease can be identified.
|  For more information, see
|  .Xr dhclient.leases 5 .
| +.It Ic host-route Ar ip-address ;
| +The
| +.Ic host-route
| +statement causes the DHCP client to install a host route to the specified
| +IP address instead of installing a default route.
| +This is useful if the default route points to a VPN tunnel terminated
| +at the specified IP address instead of a router on the local network.
|  .El
|  .Sh EXAMPLES
|  The following configuration file is used on a laptop
| Index: dhcpd.h
| ===================================================================
| RCS file: /cvs/src/sbin/dhclient/dhcpd.h,v
| retrieving revision 1.73
| diff -u -p -r1.73 dhcpd.h
| --- dhcpd.h 11 May 2011 14:38:36 -0000 1.73
| +++ dhcpd.h 12 Aug 2011 18:03:23 -0000
| @@ -150,6 +150,7 @@ struct client_config {
|   enum { IGNORE, ACCEPT, PREFER }
|   bootp_policy;
|   struct iaddrlist *reject_list;
| + struct iaddr host_route;
|  };
|  
|  struct client_state {
| @@ -344,3 +345,4 @@ void parse_client_lease_declaration(FILE
|  int parse_option_decl(FILE *, struct option_data *);
|  void parse_string_list(FILE *, struct string_list **, int);
|  void parse_reject_statement(FILE *);
| +void parse_host_route_statement(FILE *);
| Index: dhctoken.h
| ===================================================================
| RCS file: /cvs/src/sbin/dhclient/dhctoken.h,v
| retrieving revision 1.5
| diff -u -p -r1.5 dhctoken.h
| --- dhctoken.h 15 May 2006 08:10:57 -0000 1.5
| +++ dhctoken.h 12 Aug 2011 18:03:38 -0000
| @@ -79,6 +79,7 @@
|  #define TOK_REJECT 292
|  #define TOK_FDDI 293
|  #define TOK_LINK_TIMEOUT 294
| +#define TOK_HOST_ROUTE 295
|  
|  #define is_identifier(x) ((x) >= TOK_FIRST_TOKEN && \
|   (x) != TOK_STRING && \

--
Todd Fries .. [hidden email]

 _____________________________________________
|                                             \  1.636.410.0632 (voice)
| Free Daemon Consulting, LLC                 \  1.405.227.9094 (voice)
| http://FreeDaemonConsulting.com             \  1.866.792.3418 (FAX)
| 2525 NW Expy #525, Oklahoma City, OK 73112  \  sip:[hidden email]
| "..in support of free software solutions."  \  sip:[hidden email]
 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
                                                 
              37E7 D3EB 74D0 8D66 A68D  B866 0326 204E 3F42 004A
                        http://todd.fries.net/pgp.txt

Reply | Threaded
Open this post in threaded view
|

Re: new dhclient.conf option: host-route

Stefan Sperling-8
In reply to this post by Stuart Henderson
On Tue, Aug 16, 2011 at 12:09:36PM +0100, Stuart Henderson wrote:
> For OpenVPN you should be able to do '--redirect-gateway def1'

My VPN is layer2 so openvpn doesn't care about routing.
And I have openvpn drop root privs so it cannot change any routes.

> > The patch below adds a new option to dhclient.conf (the VPN server is
> > at 10.1.1.1 in this example):
> >
> >   interface "wpi0" {
> >           host-route 10.1.1.1;
> >   }
>
> If it's not considered of enough general use to change dhclient
> itself, I think this might be something you could achieve by using
> an alternative dhclient-script via 'script "/path/to/script";'

Indeed, a custom script would solve my use case, too, thanks.

Todd raised the question of what happens when support for the script
goes away. Not sure if that matters now. We can still revisit this
problem when script support is removed.

> Either way (your patch or with a wrapper script) if a new IP address
> is assigned you might have some problems with delete_old_routes
> flushing all routes including the route over the tunnel; not sure
> how important this is in practice in your case,

It is not important. The route is restored quickly and no packets
are misrouted after routes are deleted. My only problem are live
routes that point the wrong way.

> (this would also let you fetch an address on an interface via DHCP
> without changing routes, sometimes it can be rather useful to do
> this on a machine where changing the default route will cause
> disruption..)

Not sure why you would want this. If the new address is on a different
subnet the old routes are of no use.

Reply | Threaded
Open this post in threaded view
|

Re: new dhclient.conf option: host-route

Henning Brauer-5
* Stefan Sperling <[hidden email]> [2011-08-16 17:06]:
> Todd raised the question of what happens when support for the script
> goes away. Not sure if that matters now. We can still revisit this
> problem when script support is removed.

wait. my (and ifaik that is also where krw's wish comes from) desire
to replace the script comes from the routehandler. dhclient exits when
something else sets an address on the interface in question. right now
we have a hack there. if dhclient itself set the address its pid would
show up in the message on the route socket and we could easily ignore
those. right now it is the pid of the ifconfig process spawned by the
script. and dhclient doesn't know that pid.
so the idea is to have dhclient set the address itself instead of
having the script do it. just that task. not everything else the
script does. aka the script stays, just not setting the address any
more.

--
Henning Brauer, [hidden email], [hidden email]
BS Web Services, http://bsws.de
Full-Service ISP - Secure Hosting, Mail and DNS Services
Dedicated Servers, Rootservers, Application Hosting

Reply | Threaded
Open this post in threaded view
|

Re: new dhclient.conf option: host-route

Stuart Henderson
In reply to this post by Stefan Sperling-8
On 2011/08/16 16:24, Stefan Sperling wrote:
> > Either way (your patch or with a wrapper script) if a new IP address
> > is assigned you might have some problems with delete_old_routes
> > flushing all routes including the route over the tunnel; not sure
> > how important this is in practice in your case,
>
> It is not important. The route is restored quickly and no packets
> are misrouted after routes are deleted. My only problem are live
> routes that point the wrong way.

The scenario I was considering is if you have packets actively
sent while the route is missing; I think there are some circumstances
(probably involving pmtu) where you can end up with cloned host routes
which would point to the wrong gateway.

> > (this would also let you fetch an address on an interface via DHCP
> > without changing routes, sometimes it can be rather useful to do
> > this on a machine where changing the default route will cause
> > disruption..)
>
> Not sure why you would want this. If the new address is on a different
> subnet the old routes are of no use.

I've wanted this when I've been remotely doing an initial
configuration of gear which has its own DHCP server, e.g. adsl
routers. So I might get someone to connect it up to a spare nic
or switch port which I then attach to a vlan interface, then
grab an address via DHCP, and configure it up.

This can of course be done via a script too but would mean a
lot more to write, as it has to replace rather than wrap
the current script.

On 2011/08/16 17:48, Henning Brauer wrote:

> wait. my (and ifaik that is also where krw's wish comes from) desire
> to replace the script comes from the routehandler. dhclient exits when
> something else sets an address on the interface in question. right now
> we have a hack there. if dhclient itself set the address its pid would
> show up in the message on the route socket and we could easily ignore
> those. right now it is the pid of the ifconfig process spawned by the
> script. and dhclient doesn't know that pid.
> so the idea is to have dhclient set the address itself instead of
> having the script do it. just that task. not everything else the
> script does. aka the script stays, just not setting the address any
> more.

IMO this makes a lot more sense than removing the script.

Reply | Threaded
Open this post in threaded view
|

Re: new dhclient.conf option: host-route

Kenneth R Westerback
In reply to this post by Todd T. Fries-2
On Tue, Aug 16, 2011 at 06:53:01AM -0500, Todd T. Fries wrote:
> I have done this in a different way, namely by 'filtering' the variables
> that are passed to /sbin/dhclient-script by using the
> 'script "/path/to/my/script"' option to run my own script, act on variables
> I care about (dns and default gateway) and then calling /sbin/dhclient-script
> in the event it still has something to do.
>
> Honestly I think your approach is cleaner, and more likely to survive the
> ever eminent promise from krw@ to remove the script entirely.

ouch. and I think you mean imminent. :-)

.... Ken

>
> Thanks,
>
> Penned by Stefan Sperling on 20110816  5:08.37, we have:
> | In some networks (e.g. at public events using open wifi) I want
> | traffic not destined for the local network to go through a VPN.
> |
> | If the local network uses DHCP, I usually end up killing dhclient
> | because it's impossible to renew the lease without changing the
> | default route.
> |
> | To be clear, I end up with a command sequence like:
> |
> |  dhclient wpi0  # get a local address
> |  netstat -rn -finet | grep ^default  # figure out local router
> |  route delete default # don't use local router for everything
> |  route add -host $VPN_SERVER_IP $LOCAL_ROUTER # just for this host
> |  openvpn config-file # start VPN, i am too dumb for ipsec
> |  route add default $ROUTER_BEHIND_VPN # use my trusted router as default
> |  pkill -x dhclient # kill dhclient to avoid default route change later
> |
> | The problem is that the lease expires at some point and things
> | usually stop working until I perform the same tedious configuration
> | dance again.
> |
> | The patch below adds a new option to dhclient.conf (the VPN server is
> | at 10.1.1.1 in this example):
> |
> |   interface "wpi0" {
> |           host-route 10.1.1.1;
> |   }
> |
> | Instead of adding a default route dhclient will add a host route
> | to the specified address. So the above sequence becomes:
> |
> |  dhclient wpi0  # get a local address, add route to VPN server
> |  openvpn config-file # start VPN
> |  route add default $ROUTER_BEHIND_VPN # use my trusted router as default
> |
> | And the configuration remains stable.
> |
> | Is this a good approach?
> | Does anyone else think this is useful?
> |
> |
> | Index: clparse.c
> | ===================================================================
> | RCS file: /cvs/src/sbin/dhclient/clparse.c,v
> | retrieving revision 1.37
> | diff -u -p -r1.37 clparse.c
> | --- clparse.c 4 Apr 2011 11:14:52 -0000 1.37
> | +++ clparse.c 12 Aug 2011 18:04:02 -0000
> | @@ -151,7 +151,8 @@ read_client_leases(void)
> |   * interface-declaration |
> |   * TOK_LEASE client-lease-statement |
> |   * TOK_ALIAS client-lease-statement |
> | - * TOK_REJECT reject-statement
> | + * TOK_REJECT reject-statement |
> | + * TOK_HOST_ROUTE host-route-statement
> |   */
> |  void
> |  parse_client_statement(FILE *cfile)
> | @@ -234,6 +235,9 @@ parse_client_statement(FILE *cfile)
> |   case TOK_REJECT:
> |   parse_reject_statement(cfile);
> |   return;
> | + case TOK_HOST_ROUTE:
> | + parse_host_route_statement(cfile);
> | + return;
> |   default:
> |   parse_warn("expecting a statement.");
> |   skip_to_semi(cfile);
> | @@ -739,6 +743,25 @@ parse_reject_statement(FILE *cfile)
> |   token = next_token(&val, cfile);
> |   } while (token == ',');
> |  
> | + if (token != ';') {
> | + parse_warn("expecting semicolon.");
> | + skip_to_semi(cfile);
> | + }
> | +}
> | +
> | +void
> | +parse_host_route_statement(FILE *cfile)
> | +{
> | + char *val;
> | + int token;
> | +
> | + if (!parse_ip_addr(cfile, &config->host_route)) {
> | + parse_warn("expecting IP address.");
> | + skip_to_semi(cfile);
> | + return;
> | + }
> | +
> | + token = next_token(&val, cfile);
> |   if (token != ';') {
> |   parse_warn("expecting semicolon.");
> |   skip_to_semi(cfile);
> | Index: conflex.c
> | ===================================================================
> | RCS file: /cvs/src/sbin/dhclient/conflex.c,v
> | retrieving revision 1.13
> | diff -u -p -r1.13 conflex.c
> | --- conflex.c 17 Dec 2006 17:41:56 -0000 1.13
> | +++ conflex.c 12 Aug 2011 18:00:51 -0000
> | @@ -324,6 +324,7 @@ static const struct keywords {
> |   { "filename", TOK_FILENAME },
> |   { "fixed-address", TOK_FIXED_ADDR },
> |   { "hardware", TOK_HARDWARE },
> | + { "host-route", TOK_HOST_ROUTE },
> |   { "initial-interval", TOK_INITIAL_INTERVAL },
> |   { "interface", TOK_INTERFACE },
> |   { "lease", TOK_LEASE },
> | Index: dhclient-script
> | ===================================================================
> | RCS file: /cvs/src/sbin/dhclient/dhclient-script,v
> | retrieving revision 1.22
> | diff -u -p -r1.22 dhclient-script
> | --- dhclient-script 9 Apr 2011 19:53:00 -0000 1.22
> | +++ dhclient-script 12 Aug 2011 18:06:00 -0000
> | @@ -60,11 +60,16 @@ delete_old_routes() {
> |  add_new_routes() {
> |   route -q $rdomain -n flush -inet -iface $interface
> |   for router in $new_routers; do
> | - if [ "$new_ip_address" = "$router" ]; then
> | - route -q $rdomain add default -iface $router
> | + if [ -n "$host_route" -a "$host_route" != "0.0.0.0" ]; then
> | + new_route="-host $host_route $router"
> |   else
> | - route -q $rdomain add default $router
> | + if [ "$new_ip_address" = "$router" ]; then
> | + new_route="default -iface $router"
> | + else
> | + new_route="default $router"
> | + fi
> |   fi
> | + route -q $rdomain add $new_route
> |   # 2nd and subsequent default routers error out, so explicitly
> |   # stop processing the list after the first one.
> |   break
> | Index: dhclient.c
> | ===================================================================
> | RCS file: /cvs/src/sbin/dhclient/dhclient.c,v
> | retrieving revision 1.141
> | diff -u -p -r1.141 dhclient.c
> | --- dhclient.c 11 May 2011 14:38:36 -0000 1.141
> | +++ dhclient.c 12 Aug 2011 18:06:57 -0000
> | @@ -1604,6 +1604,9 @@ supersede:
> |   }
> |   snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
> |   script_set_env(prefix, "expiry", tbuf);
> | +
> | + if (config->host_route.len)
> | + script_set_env("", "host_route", piaddr(config->host_route));
> |  }
> |  
> |  void
> | Index: dhclient.conf.5
> | ===================================================================
> | RCS file: /cvs/src/sbin/dhclient/dhclient.conf.5,v
> | retrieving revision 1.21
> | diff -u -p -r1.21 dhclient.conf.5
> | --- dhclient.conf.5 9 Apr 2011 19:53:00 -0000 1.21
> | +++ dhclient.conf.5 13 Aug 2011 19:18:56 -0000
> | @@ -430,6 +430,13 @@ If no lease is acquired, the script is u
> |  any, and also called once if no valid lease can be identified.
> |  For more information, see
> |  .Xr dhclient.leases 5 .
> | +.It Ic host-route Ar ip-address ;
> | +The
> | +.Ic host-route
> | +statement causes the DHCP client to install a host route to the specified
> | +IP address instead of installing a default route.
> | +This is useful if the default route points to a VPN tunnel terminated
> | +at the specified IP address instead of a router on the local network.
> |  .El
> |  .Sh EXAMPLES
> |  The following configuration file is used on a laptop
> | Index: dhcpd.h
> | ===================================================================
> | RCS file: /cvs/src/sbin/dhclient/dhcpd.h,v
> | retrieving revision 1.73
> | diff -u -p -r1.73 dhcpd.h
> | --- dhcpd.h 11 May 2011 14:38:36 -0000 1.73
> | +++ dhcpd.h 12 Aug 2011 18:03:23 -0000
> | @@ -150,6 +150,7 @@ struct client_config {
> |   enum { IGNORE, ACCEPT, PREFER }
> |   bootp_policy;
> |   struct iaddrlist *reject_list;
> | + struct iaddr host_route;
> |  };
> |  
> |  struct client_state {
> | @@ -344,3 +345,4 @@ void parse_client_lease_declaration(FILE
> |  int parse_option_decl(FILE *, struct option_data *);
> |  void parse_string_list(FILE *, struct string_list **, int);
> |  void parse_reject_statement(FILE *);
> | +void parse_host_route_statement(FILE *);
> | Index: dhctoken.h
> | ===================================================================
> | RCS file: /cvs/src/sbin/dhclient/dhctoken.h,v
> | retrieving revision 1.5
> | diff -u -p -r1.5 dhctoken.h
> | --- dhctoken.h 15 May 2006 08:10:57 -0000 1.5
> | +++ dhctoken.h 12 Aug 2011 18:03:38 -0000
> | @@ -79,6 +79,7 @@
> |  #define TOK_REJECT 292
> |  #define TOK_FDDI 293
> |  #define TOK_LINK_TIMEOUT 294
> | +#define TOK_HOST_ROUTE 295
> |  
> |  #define is_identifier(x) ((x) >= TOK_FIRST_TOKEN && \
> |   (x) != TOK_STRING && \
>
> --
> Todd Fries .. [hidden email]
>
>  _____________________________________________
> |                                             \  1.636.410.0632 (voice)
> | Free Daemon Consulting, LLC                 \  1.405.227.9094 (voice)
> | http://FreeDaemonConsulting.com             \  1.866.792.3418 (FAX)
> | 2525 NW Expy #525, Oklahoma City, OK 73112  \  sip:[hidden email]
> | "..in support of free software solutions."  \  sip:[hidden email]
>  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
>                                                  
>               37E7 D3EB 74D0 8D66 A68D  B866 0326 204E 3F42 004A
>                         http://todd.fries.net/pgp.txt