0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-17 08:38:42 +00:00

Implements TTL security for OSPF and RIP.

Interfaces for OSPF and RIP could be configured to use (and request)
TTL 255 for traffic to direct neighbors.

Thanks to Simon Dickhoven for the original patch for RIPng.
This commit is contained in:
Ondrej Zajicek 2013-06-25 15:33:00 +02:00
parent ef4a50be10
commit 70e212f913
11 changed files with 141 additions and 60 deletions

View File

@ -89,6 +89,7 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shoul
#define SKF_V6ONLY 1 /* Use IPV6_V6ONLY socket option */
#define SKF_LADDR_RX 2 /* Report local address for RX packets */
#define SKF_LADDR_TX 4 /* Allow to specify local address for TX packets */
#define SKF_TTL_RX 8 /* Report TTL / Hop Limit for RX packets */
/*

View File

@ -127,8 +127,8 @@ CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
CF_KEYWORDS(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, COST2, RETRANSMIT)
CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST)
CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP)
CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC)
CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK)
CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC, TTL, SECURITY)
CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY)
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY)
@ -307,6 +307,8 @@ ospf_iface_item:
| RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if (($3 < OSPF_RXBUF_MINSIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
| TX tos { OSPF_PATT->tx_tos = $2; }
| TX PRIORITY expr { OSPF_PATT->tx_priority = $3; }
| TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
| password_list
;

View File

@ -86,7 +86,7 @@ ospf_sk_open(struct ospf_iface *ifa)
sk->rbsize = rxbufsize(ifa);
sk->tbsize = rxbufsize(ifa);
sk->data = (void *) ifa;
sk->flags = SKF_LADDR_RX;
sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0);
if (sk_open(sk) != 0)
goto err;
@ -131,7 +131,7 @@ ospf_sk_open(struct ospf_iface *ifa)
else
{
ifa->all_routers = AllSPFRouters;
sk->ttl = 1; /* Hack, this will affect just multicast packets */
sk->ttl = ifa->cf->ttl_security ? 255 : 1;
if (sk_setup_multicast(sk) < 0)
goto err;
@ -534,6 +534,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->rxbuf = ip->rxbuf;
ifa->check_link = ip->check_link;
ifa->ecmp_weight = ip->ecmp_weight;
ifa->check_ttl = (ip->ttl_security == 1);
#ifdef OSPFv2
ifa->autype = ip->autype;

View File

@ -275,6 +275,7 @@ struct ospf_iface
u8 check_link; /* Whether iface link change is used */
u8 ecmp_weight; /* Weight used for ECMP */
u8 ptp_netmask; /* Send real netmask for P2P */
u8 check_ttl; /* Check incoming packets for TTL 255 */
};
struct ospf_md5
@ -815,7 +816,8 @@ struct ospf_iface_patt
u8 check_link;
u8 ecmp_weight;
u8 real_bcast; /* Not really used in OSPFv3 */
u8 ptp_netmask; /* bool but 2 for unspecified */
u8 ptp_netmask; /* bool + 2 for unspecified */
u8 ttl_security; /* bool + 2 for TX only */
#ifdef OSPFv2
list *passwords;

View File

@ -309,6 +309,12 @@ ospf_rx_hook(sock *sk, int size)
return 1;
}
if (ifa->check_ttl && (sk->ttl < 255))
{
log(L_ERR "%s%I - TTL %d (< 255)", mesg, sk->faddr, sk->ttl);
return 1;
}
if ((unsigned) size < sizeof(struct ospf_packet))
{
log(L_ERR "%s%I - too short (%u bytes)", mesg, sk->faddr, size);

View File

@ -22,12 +22,18 @@ CF_DEFINES
#define RIP_CFG ((struct rip_proto_config *) this_proto)
#define RIP_IPATT ((struct rip_patt *) this_ipatt)
#ifdef IPV6
#define RIP_DEFAULT_TTL_SECURITY 2
#else
#define RIP_DEFAULT_TTL_SECURITY 0
#endif
CF_DECLS
CF_KEYWORDS(RIP, INFINITY, METRIC, PORT, PERIOD, GARBAGE, TIMEOUT,
MODE, BROADCAST, MULTICAST, QUIET, NOLISTEN, VERSION1,
AUTHENTICATION, NONE, PLAINTEXT, MD5,
HONOR, NEVER, NEIGHBOR, ALWAYS, TX, PRIORITY,
AUTHENTICATION, NONE, PLAINTEXT, MD5, TTL, SECURITY,
HONOR, NEVER, NEIGHBOR, ALWAYS, TX, PRIORITY, ONLY,
RIP_METRIC, RIP_TAG)
%type <i> rip_mode rip_auth
@ -78,6 +84,8 @@ rip_iface_item:
| MODE rip_mode { RIP_IPATT->mode |= $2; }
| TX tos { RIP_IPATT->tx_tos = $2; }
| TX PRIORITY expr { RIP_IPATT->tx_priority = $3; }
| TTL SECURITY bool { RIP_IPATT->ttl_security = $3; }
| TTL SECURITY TX ONLY { RIP_IPATT->ttl_security = 2; }
;
rip_iface_opts:
@ -98,6 +106,7 @@ rip_iface_init:
RIP_IPATT->metric = 1;
RIP_IPATT->tx_tos = IP_PREC_INTERNET_CONTROL;
RIP_IPATT->tx_priority = sk_priority_control;
RIP_IPATT->ttl_security = RIP_DEFAULT_TTL_SECURITY;
}
;

View File

@ -480,6 +480,14 @@ rip_rx(sock *s, int size)
iface = i->iface;
#endif
if (i->check_ttl && (s->ttl < 255))
{
log( L_REMOTE "%s: Discarding packet with TTL %d (< 255) from %I on %s",
p->name, s->ttl, s->faddr, i->iface->name);
return 1;
}
CHK_MAGIC;
DBG( "RIP: message came: %d bytes from %I via %s\n", size, s->faddr, i->iface ? i->iface->name : "(dummy)" );
size -= sizeof( struct rip_packet_heading );
@ -686,6 +694,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
rif->mode = PATT->mode;
rif->metric = PATT->metric;
rif->multicast = (!(PATT->mode & IM_BROADCAST)) && (flags & IF_MULTICAST);
rif->check_ttl = (PATT->ttl_security == 1);
}
/* lookup multicasts over unnumbered links - no: rip is not defined over unnumbered links */
@ -706,10 +715,10 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
rif->sock->dport = P_CF->port;
if (new)
{
rif->sock->ttl = 1;
rif->sock->tos = PATT->tx_tos;
rif->sock->priority = PATT->tx_priority;
rif->sock->flags = SKF_LADDR_RX;
rif->sock->ttl = PATT->ttl_security ? 255 : 1;
rif->sock->flags = SKF_LADDR_RX | (rif->check_ttl ? SKF_TTL_RX : 0);
}
if (new) {

View File

@ -114,6 +114,7 @@ struct rip_interface {
struct rip_connection *busy;
int metric; /* You don't want to put struct rip_patt *patt here -- think about reconfigure */
int mode;
int check_ttl; /* Check incoming packets for TTL 255 */
int triggered;
struct object_lock *lock;
int multicast;
@ -130,6 +131,7 @@ struct rip_patt {
#define IM_VERSION1 16
int tx_tos;
int tx_priority;
int ttl_security; /* bool + 2 for TX only (send, but do not check on RX) */
};
struct rip_proto_config {

View File

@ -113,7 +113,9 @@ sysio_leave_group(sock *s, ip_addr maddr)
/* BSD RX/TX packet info handling for IPv4 */
/* it uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */
#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_addr)) + CMSG_SPACE(sizeof(struct sockaddr_dl)))
#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_addr)) + \
CMSG_SPACE(sizeof(struct sockaddr_dl)) + \
CMSG_SPACE(sizeof(char)))
#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_addr))
static char *
@ -129,6 +131,11 @@ sysio_register_cmsgs(sock *s)
return "IP_RECVIF";
}
if ((s->flags & SKF_TTL_RX) &&
(setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
return "IP_RECVTTL";
return NULL;
}
@ -136,27 +143,35 @@ static void
sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
{
struct cmsghdr *cm;
if (!(s->flags & SKF_LADDR_RX))
return;
s->laddr = IPA_NONE;
s->lifindex = 0;
struct in_addr *ra = NULL;
struct sockaddr_dl *ri = NULL;
unsigned char *ttl = NULL;
for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
{
if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR)
{
struct in_addr *ra = (struct in_addr *) CMSG_DATA(cm);
get_inaddr(&s->laddr, ra);
}
ra = (struct in_addr *) CMSG_DATA(cm);
if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF)
ri = (struct sockaddr_dl *) CMSG_DATA(cm);
if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVTTL)
ttl = (unsigned char *) CMSG_DATA(cm);
}
if (s->flags & SKF_LADDR_RX)
{
struct sockaddr_dl *ri = (struct sockaddr_dl *) CMSG_DATA(cm);
s->laddr = IPA_NONE;
s->lifindex = 0;
if (ra)
get_inaddr(&s->laddr, ra);
if (ri)
s->lifindex = ri->sdl_index;
}
}
if (s->flags & SKF_TTL_RX)
s->ttl = ttl ? *ttl : -1;
// log(L_WARN "RX %I %d", s->laddr, s->lifindex);
}

View File

@ -194,17 +194,22 @@ sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd)
/* RX/TX packet info handling for IPv4 */
/* Mostly similar to standardized IPv6 code */
#define CMSG_RX_SPACE CMSG_SPACE(sizeof(struct in_pktinfo))
#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(int)))
#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_pktinfo))
static char *
sysio_register_cmsgs(sock *s)
{
int ok = 1;
if ((s->flags & SKF_LADDR_RX) &&
setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0)
(setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0))
return "IP_PKTINFO";
if ((s->flags & SKF_TTL_RX) &&
(setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
return "IP_RECVTTL";
return NULL;
}
@ -213,25 +218,34 @@ sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
{
struct cmsghdr *cm;
struct in_pktinfo *pi = NULL;
if (!(s->flags & SKF_LADDR_RX))
return;
int *ttl = NULL;
for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
{
if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_PKTINFO)
pi = (struct in_pktinfo *) CMSG_DATA(cm);
if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_TTL)
ttl = (int *) CMSG_DATA(cm);
}
if (!pi)
if (s->flags & SKF_LADDR_RX)
{
if (pi)
{
get_inaddr(&s->laddr, &pi->ipi_addr);
s->lifindex = pi->ipi_ifindex;
}
else
{
s->laddr = IPA_NONE;
s->lifindex = 0;
return;
}
}
get_inaddr(&s->laddr, &pi->ipi_addr);
s->lifindex = pi->ipi_ifindex;
if (s->flags & SKF_TTL_RX)
s->ttl = ttl ? *ttl : -1;
return;
}

View File

@ -673,7 +673,7 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, struct iface **ifa, unsigned *p
#ifdef IPV6
/* PKTINFO handling is also standardized in IPv6 */
#define CMSG_RX_SPACE CMSG_SPACE(sizeof(struct in6_pktinfo))
#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)))
#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in6_pktinfo))
/*
@ -685,15 +685,26 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, struct iface **ifa, unsigned *p
#ifndef IPV6_RECVPKTINFO
#define IPV6_RECVPKTINFO IPV6_PKTINFO
#endif
/*
* Same goes for IPV6_HOPLIMIT -> IPV6_RECVHOPLIMIT.
*/
#ifndef IPV6_RECVHOPLIMIT
#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
#endif
static char *
sysio_register_cmsgs(sock *s)
{
int ok = 1;
if ((s->flags & SKF_LADDR_RX) &&
setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0)
(setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0))
return "IPV6_RECVPKTINFO";
if ((s->flags & SKF_TTL_RX) &&
(setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &ok, sizeof(ok)) < 0))
return "IPV6_RECVHOPLIMIT";
return NULL;
}
@ -702,25 +713,34 @@ sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
{
struct cmsghdr *cm;
struct in6_pktinfo *pi = NULL;
if (!(s->flags & SKF_LADDR_RX))
return;
int *hlim = NULL;
for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
{
if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
pi = (struct in6_pktinfo *) CMSG_DATA(cm);
if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_HOPLIMIT)
hlim = (int *) CMSG_DATA(cm);
}
if (!pi)
if (s->flags & SKF_LADDR_RX)
{
if (pi)
{
get_inaddr(&s->laddr, &pi->ipi6_addr);
s->lifindex = pi->ipi6_ifindex;
}
else
{
s->laddr = IPA_NONE;
s->lifindex = 0;
return;
}
}
get_inaddr(&s->laddr, &pi->ipi6_addr);
s->lifindex = pi->ipi6_ifindex;
if (s->flags & SKF_TTL_RX)
s->ttl = hlim ? *hlim : -1;
return;
}