Restrict export of device routes to the kernel protocol.
In usual configuration, such export is already restricted with the aid of the direct protocol but there are some races that can circumvent it. This makes it harder to break kernel device routes. Also adds an option to disable this restriction.
This commit is contained in:
parent
d2d2b5d2ae
commit
c429d4a4ba
7 changed files with 70 additions and 41 deletions
|
@ -95,7 +95,7 @@ Czech Republic as a student project. It can be freely distributed under the term
|
||||||
Public License.
|
Public License.
|
||||||
|
|
||||||
<p>BIRD has been designed to work on all UNIX-like systems. It has been developed and
|
<p>BIRD has been designed to work on all UNIX-like systems. It has been developed and
|
||||||
tested under Linux 2.0 to 2.4, and then ported to FreeBSD and NetBSD, porting to other
|
tested under Linux 2.0 to 2.6, and then ported to FreeBSD, NetBSD and OpenBSD, porting to other
|
||||||
systems (even non-UNIX ones) should be relatively easy due to its highly modular architecture.
|
systems (even non-UNIX ones) should be relatively easy due to its highly modular architecture.
|
||||||
|
|
||||||
<sect>Installing BIRD
|
<sect>Installing BIRD
|
||||||
|
@ -454,16 +454,19 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
|
||||||
<chapt>Remote control
|
<chapt>Remote control
|
||||||
|
|
||||||
<p>You can use the command-line client <file>birdc</file> to talk with
|
<p>You can use the command-line client <file>birdc</file> to talk with
|
||||||
a running BIRD. Communication is done using a <file/bird.ctl/ UNIX domain
|
a running BIRD. Communication is done using a <file/bird.ctl/ UNIX
|
||||||
socket (unless changed with the <tt/-s/ option given to both the server and
|
domain socket (unless changed with the <tt/-s/ option given to both
|
||||||
the client). The commands can perform simple actions such as enabling/disabling
|
the server and the client). The commands can perform simple actions
|
||||||
of protocols, telling BIRD to show various information, telling it to
|
such as enabling/disabling of protocols, telling BIRD to show various
|
||||||
show routing table filtered by filter, or asking BIRD to
|
information, telling it to show routing table filtered by filter, or
|
||||||
reconfigure. Press <tt/?/ at any time to get online help. Option
|
asking BIRD to reconfigure. Press <tt/?/ at any time to get online
|
||||||
|
help. Option <tt/-r/ can be used to enable a restricted mode of BIRD
|
||||||
|
client, which allows just read-only commands (<cf/show .../). Option
|
||||||
<tt/-v/ can be passed to the client, to make it dump numeric return
|
<tt/-v/ can be passed to the client, to make it dump numeric return
|
||||||
codes along with the messages. You do not necessarily need to use <file/birdc/ to talk to BIRD, your
|
codes along with the messages. You do not necessarily need to use
|
||||||
own applications could do that, too -- the format of communication between
|
<file/birdc/ to talk to BIRD, your own applications could do that, too
|
||||||
BIRD and <file/birdc/ is stable (see the programmer's documentation).
|
-- the format of communication between BIRD and <file/birdc/ is stable
|
||||||
|
(see the programmer's documentation).
|
||||||
|
|
||||||
Many commands have the <m/name/ of the protocol instance as an argument.
|
Many commands have the <m/name/ of the protocol instance as an argument.
|
||||||
This argument can be omitted if there exists only a single instance.
|
This argument can be omitted if there exists only a single instance.
|
||||||
|
@ -864,7 +867,7 @@ undefined value is regarded as empty clist for most purposes.
|
||||||
routes). Read-only.
|
routes). Read-only.
|
||||||
|
|
||||||
<tag><m/enum/ dest</tag>
|
<tag><m/enum/ dest</tag>
|
||||||
Type of destination the packets should be sent to (<cf/RTD_ROUTER/ for forwarding to a neighboring router, <cf/RTD_NETWORK/ for routing to a directly-connected network, <cf/RTD_BLACKHOLE/ for packets to be silently discarded, <cf/RTD_UNREACHABLE/, <cf/RTD_PROHIBIT/ for packets that should be returned with ICMP host unreachable / ICMP administratively prohibited messages). Read-only.
|
Type of destination the packets should be sent to (<cf/RTD_ROUTER/ for forwarding to a neighboring router, <cf/RTD_DEVICE/ for routing to a directly-connected network, <cf/RTD_BLACKHOLE/ for packets to be silently discarded, <cf/RTD_UNREACHABLE/, <cf/RTD_PROHIBIT/ for packets that should be returned with ICMP host unreachable / ICMP administratively prohibited messages). Read-only.
|
||||||
</descrip>
|
</descrip>
|
||||||
|
|
||||||
<p>There also exist some protocol-specific attributes which are described in the corresponding protocol sections.
|
<p>There also exist some protocol-specific attributes which are described in the corresponding protocol sections.
|
||||||
|
@ -1273,10 +1276,15 @@ protocol device {
|
||||||
directly connected networks according to the list of interfaces provided
|
directly connected networks according to the list of interfaces provided
|
||||||
by the kernel via the Device protocol.
|
by the kernel via the Device protocol.
|
||||||
|
|
||||||
<p>It's highly recommended to include this protocol in your configuration
|
<p>The question is whether it is a good idea to have such device
|
||||||
unless you want to use BIRD as a route server or a route reflector, that is
|
routes in BIRD routing table. OS kernel usually handles device routes
|
||||||
on a machine which doesn't forward packets itself and only participates in
|
for directly connected networks by itself so we don't need (and don't
|
||||||
distribution of routing information.
|
want) to export these routes to the kernel protocol. OSPF protocol
|
||||||
|
creates device routes for its interfaces itself and BGP protocol is
|
||||||
|
usually used for exporting aggregate routes. Although there are some
|
||||||
|
use cases that use the direct protocol (like abusing eBGP as an IGP
|
||||||
|
routing protocol), in most cases it is not needed to have these device
|
||||||
|
routes in BIRD routing table and to use the direct protocol.
|
||||||
|
|
||||||
<p>The only configurable thing about direct is what interfaces it watches:
|
<p>The only configurable thing about direct is what interfaces it watches:
|
||||||
|
|
||||||
|
@ -1302,14 +1310,24 @@ protocol direct {
|
||||||
<sect>Kernel
|
<sect>Kernel
|
||||||
|
|
||||||
<p>The Kernel protocol is not a real routing protocol. Instead of communicating
|
<p>The Kernel protocol is not a real routing protocol. Instead of communicating
|
||||||
the with other routers in the network, it performs synchronization of BIRD's routing
|
with other routers in the network, it performs synchronization of BIRD's routing
|
||||||
tables with the OS kernel. Basically, it sends all routing table updates to the kernel
|
tables with the OS kernel. Basically, it sends all routing table updates to the kernel
|
||||||
and from time to time it scans the kernel tables to see whether some routes have
|
and from time to time it scans the kernel tables to see whether some routes have
|
||||||
disappeared (for example due to unnoticed up/down transition of an interface)
|
disappeared (for example due to unnoticed up/down transition of an interface)
|
||||||
or whether an `alien' route has been added by someone else (depending on the
|
or whether an `alien' route has been added by someone else (depending on the
|
||||||
<cf/learn/ switch, such routes are either deleted or accepted to our
|
<cf/learn/ switch, such routes are either ignored or accepted to our
|
||||||
table).
|
table).
|
||||||
|
|
||||||
|
<p>Unfortunately, there is one thing that makes the routing table
|
||||||
|
synchronization a bit more complicated. In the kernel routing table
|
||||||
|
there are also device routes for directly connected networks. These
|
||||||
|
routes are usually managed by OS itself (as a part of IP address
|
||||||
|
configuration) and we don't want to touch that. They are completely
|
||||||
|
ignored during the scan of the kernel tables and also the export of
|
||||||
|
device routes from BIRD tables to kernel routing tables is restricted
|
||||||
|
to prevent accidental interference. This restriction can be disabled using
|
||||||
|
<cf/device routes/ switch.
|
||||||
|
|
||||||
<p>If your OS supports only a single routing table, you can configure only one
|
<p>If your OS supports only a single routing table, you can configure only one
|
||||||
instance of the Kernel protocol. If it supports multiple tables (in order to
|
instance of the Kernel protocol. If it supports multiple tables (in order to
|
||||||
allow policy routing; such an OS is for example Linux 2.2), you can run as many instances as you want, but each of
|
allow policy routing; such an OS is for example Linux 2.2), you can run as many instances as you want, but each of
|
||||||
|
@ -1327,6 +1345,14 @@ kernel table.
|
||||||
routing tables by other routing daemons or by the system administrator.
|
routing tables by other routing daemons or by the system administrator.
|
||||||
This is possible only on systems which support identification of route
|
This is possible only on systems which support identification of route
|
||||||
authorship.
|
authorship.
|
||||||
|
|
||||||
|
<tag>device routes <m/switch/</tag> Enable export of device
|
||||||
|
routes to the kernel routing table. By default, such routes
|
||||||
|
are rejected (with the exception of explicitly configured
|
||||||
|
device routes from the static protocol) regardless of the
|
||||||
|
export filter to protect device routes in kernel routing table
|
||||||
|
(managed by OS itself) from accidental overwriting or erasing.
|
||||||
|
|
||||||
<tag>kernel table <m/number/</tag> Select which kernel table should
|
<tag>kernel table <m/number/</tag> Select which kernel table should
|
||||||
this particular instance of the Kernel protocol work with. Available
|
this particular instance of the Kernel protocol work with. Available
|
||||||
only on systems supporting multiple routing tables.
|
only on systems supporting multiple routing tables.
|
||||||
|
|
|
@ -167,8 +167,6 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt
|
||||||
rte *old0 = old;
|
rte *old0 = old;
|
||||||
int ok;
|
int ok;
|
||||||
|
|
||||||
int fast_exit_hack = 0;
|
|
||||||
|
|
||||||
#ifdef CONFIG_PIPE
|
#ifdef CONFIG_PIPE
|
||||||
/* The secondary direction of the pipe */
|
/* The secondary direction of the pipe */
|
||||||
if (proto_is_pipe(p) && (p->table != a->table))
|
if (proto_is_pipe(p) && (p->table != a->table))
|
||||||
|
@ -207,11 +205,6 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt
|
||||||
else
|
else
|
||||||
stats->exp_withdraws_received++;
|
stats->exp_withdraws_received++;
|
||||||
|
|
||||||
/* Hack: This is here to prevent 'spurious withdraws'
|
|
||||||
for loopback addresses during reload. */
|
|
||||||
if (fast_exit_hack)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a tricky part - we don't know whether route 'old' was
|
* This is a tricky part - we don't know whether route 'old' was
|
||||||
* exported to protocol 'p' or was filtered by the export filter.
|
* exported to protocol 'p' or was filtered by the export filter.
|
||||||
|
|
|
@ -40,10 +40,6 @@ krt_capable(rte *e)
|
||||||
{
|
{
|
||||||
rta *a = e->attrs;
|
rta *a = e->attrs;
|
||||||
|
|
||||||
#ifdef CONFIG_AUTO_ROUTES
|
|
||||||
if (a->source == RTS_DEVICE)
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
return
|
return
|
||||||
a->cast == RTC_UNICAST &&
|
a->cast == RTC_UNICAST &&
|
||||||
(a->dest == RTD_ROUTER
|
(a->dest == RTD_ROUTER
|
||||||
|
@ -163,7 +159,7 @@ krt_sock_send(int cmd, rte *e)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!i->addr) {
|
if(!i->addr) {
|
||||||
log(L_ERR "KIF: interface \"%s\" has no IP addess", i->name);
|
log(L_ERR "KRT: interface %s has no IP addess", i->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +181,7 @@ krt_sock_send(int cmd, rte *e)
|
||||||
msg.rtm.rtm_msglen = l;
|
msg.rtm.rtm_msglen = l;
|
||||||
|
|
||||||
if ((l = write(rt_sock, (char *)&msg, l)) < 0) {
|
if ((l = write(rt_sock, (char *)&msg, l)) < 0) {
|
||||||
log(L_ERR "KIF: Error sending route %I/%d to kernel", net->n.prefix, net->n.pxlen);
|
log(L_ERR "KRT: Error sending route %I/%d to kernel", net->n.prefix, net->n.pxlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -460,20 +460,14 @@ krt_capable(rte *e)
|
||||||
{
|
{
|
||||||
rta *a = e->attrs;
|
rta *a = e->attrs;
|
||||||
|
|
||||||
if (a->cast != RTC_UNICAST
|
if (a->cast != RTC_UNICAST)
|
||||||
#if 0
|
|
||||||
&& a->cast != RTC_ANYCAST
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
return 0;
|
|
||||||
if (a->source == RTS_DEVICE) /* Kernel takes care of device routes itself */
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch (a->dest)
|
switch (a->dest)
|
||||||
{
|
{
|
||||||
case RTD_ROUTER:
|
case RTD_ROUTER:
|
||||||
if (ipa_has_link_scope(a->gw) && (a->iface == NULL))
|
if (ipa_has_link_scope(a->gw) && (a->iface == NULL))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case RTD_DEVICE:
|
case RTD_DEVICE:
|
||||||
case RTD_BLACKHOLE:
|
case RTD_BLACKHOLE:
|
||||||
case RTD_UNREACHABLE:
|
case RTD_UNREACHABLE:
|
||||||
|
|
|
@ -17,7 +17,7 @@ CF_DEFINES
|
||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE)
|
CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES)
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ kern_item:
|
||||||
cf_error("Learning of kernel routes not supported in this configuration");
|
cf_error("Learning of kernel routes not supported in this configuration");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
| DEVICE ROUTES bool { THIS_KRT->devroutes = $3; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Kernel interface protocol */
|
/* Kernel interface protocol */
|
||||||
|
|
|
@ -734,6 +734,25 @@ krt_scan(timer *t UNUSED)
|
||||||
/*
|
/*
|
||||||
* Updates
|
* Updates
|
||||||
*/
|
*/
|
||||||
|
static int
|
||||||
|
krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
|
||||||
|
{
|
||||||
|
struct krt_proto *p = (struct krt_proto *) P;
|
||||||
|
rte *e = *new;
|
||||||
|
|
||||||
|
if (e->attrs->proto == P)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!KRT_CF->devroutes &&
|
||||||
|
(e->attrs->dest == RTD_DEVICE) &&
|
||||||
|
(e->attrs->source != RTS_STATIC_DEVICE))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!krt_capable(e))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
|
krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
|
||||||
|
@ -743,8 +762,6 @@ krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
|
||||||
|
|
||||||
if (shutting_down)
|
if (shutting_down)
|
||||||
return;
|
return;
|
||||||
if (new && (!krt_capable(new) || new->attrs->source == RTS_INHERIT))
|
|
||||||
new = NULL;
|
|
||||||
if (!(net->n.flags & KRF_INSTALLED))
|
if (!(net->n.flags & KRF_INSTALLED))
|
||||||
old = NULL;
|
old = NULL;
|
||||||
if (new)
|
if (new)
|
||||||
|
@ -871,6 +888,7 @@ krt_init(struct proto_config *c)
|
||||||
struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
|
struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
|
||||||
|
|
||||||
p->p.accept_ra_types = RA_OPTIMAL;
|
p->p.accept_ra_types = RA_OPTIMAL;
|
||||||
|
p->p.import_control = krt_import_control;
|
||||||
p->p.rt_notify = krt_notify;
|
p->p.rt_notify = krt_notify;
|
||||||
return &p->p;
|
return &p->p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ struct krt_config {
|
||||||
int persist; /* Keep routes when we exit */
|
int persist; /* Keep routes when we exit */
|
||||||
int scan_time; /* How often we re-scan routes */
|
int scan_time; /* How often we re-scan routes */
|
||||||
int learn; /* Learn routes from other sources */
|
int learn; /* Learn routes from other sources */
|
||||||
|
int devroutes; /* Allow export of device routes */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct krt_proto {
|
struct krt_proto {
|
||||||
|
|
Loading…
Reference in a new issue