summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/socket.h1
-rw-r--r--proto/ospf/config.Y6
-rw-r--r--proto/ospf/iface.c5
-rw-r--r--proto/ospf/ospf.h4
-rw-r--r--proto/ospf/packet.c6
-rw-r--r--proto/rip/config.Y13
-rw-r--r--proto/rip/rip.c13
-rw-r--r--proto/rip/rip.h2
-rw-r--r--sysdep/bsd/sysio.h63
-rw-r--r--sysdep/linux/sysio.h38
-rw-r--r--sysdep/unix/io.c44
11 files changed, 138 insertions, 57 deletions
diff --git a/lib/socket.h b/lib/socket.h
index fbddfb4c..6e0a769b 100644
--- a/lib/socket.h
+++ b/lib/socket.h
@@ -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 */
/*
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index d9379a7c..f042e1aa 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -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
;
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index bc3b1ef6..698ef620 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -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;
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 56ebcd31..f1409af3 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -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;
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 241a58f7..4338bc1a 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -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);
diff --git a/proto/rip/config.Y b/proto/rip/config.Y
index ec82aa3d..791c43a2 100644
--- a/proto/rip/config.Y
+++ b/proto/rip/config.Y
@@ -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;
}
;
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index c09eae79..3ec070b3 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -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) {
diff --git a/proto/rip/rip.h b/proto/rip/rip.h
index 2cce8c81..6e0d5aad 100644
--- a/proto/rip/rip.h
+++ b/proto/rip/rip.h
@@ -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 {
diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h
index 085f16fa..031eac9a 100644
--- a/sysdep/bsd/sysio.h
+++ b/sysdep/bsd/sysio.h
@@ -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 *
@@ -121,13 +123,18 @@ sysio_register_cmsgs(sock *s)
{
int ok = 1;
if (s->flags & SKF_LADDR_RX)
- {
- if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &ok, sizeof(ok)) < 0)
- return "IP_RECVDSTADDR";
+ {
+ if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &ok, sizeof(ok)) < 0)
+ return "IP_RECVDSTADDR";
+
+ if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0)
+ return "IP_RECVIF";
+ }
+
+ if ((s->flags & SKF_TTL_RX) &&
+ (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
+ return "IP_RECVTTL";
- if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0)
- return "IP_RECVIF";
- }
return NULL;
}
@@ -136,27 +143,35 @@ static void
sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
{
struct cmsghdr *cm;
+ struct in_addr *ra = NULL;
+ struct sockaddr_dl *ri = NULL;
+ unsigned char *ttl = NULL;
- if (!(s->flags & SKF_LADDR_RX))
- return;
+ for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
+ {
+ if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR)
+ ra = (struct in_addr *) CMSG_DATA(cm);
- s->laddr = IPA_NONE;
- s->lifindex = 0;
+ if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF)
+ ri = (struct sockaddr_dl *) CMSG_DATA(cm);
- 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);
- }
+ if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVTTL)
+ ttl = (unsigned char *) CMSG_DATA(cm);
+ }
- if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF)
- {
- struct sockaddr_dl *ri = (struct sockaddr_dl *) CMSG_DATA(cm);
- s->lifindex = ri->sdl_index;
- }
- }
+ if (s->flags & SKF_LADDR_RX)
+ {
+ 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);
}
diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h
index 41287e71..250ed586 100644
--- a/sysdep/linux/sysio.h
+++ b/sysdep/linux/sysio.h
@@ -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 (s->flags & SKF_LADDR_RX)
+ {
+ if (pi)
{
- if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_PKTINFO)
- pi = (struct in_pktinfo *) CMSG_DATA(cm);
+ get_inaddr(&s->laddr, &pi->ipi_addr);
+ s->lifindex = pi->ipi_ifindex;
}
-
- if (!pi)
+ else
{
s->laddr = IPA_NONE;
s->lifindex = 0;
- return;
}
+ }
+
+ if (s->flags & SKF_TTL_RX)
+ s->ttl = ttl ? *ttl : -1;
- get_inaddr(&s->laddr, &pi->ipi_addr);
- s->lifindex = pi->ipi_ifindex;
return;
}
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index 434a05be..93863885 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -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 (s->flags & SKF_LADDR_RX)
+ {
+ if (pi)
{
- if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
- pi = (struct in6_pktinfo *) CMSG_DATA(cm);
+ get_inaddr(&s->laddr, &pi->ipi6_addr);
+ s->lifindex = pi->ipi6_ifindex;
}
-
- if (!pi)
+ else
{
s->laddr = IPA_NONE;
s->lifindex = 0;
- return;
}
+ }
+
+ if (s->flags & SKF_TTL_RX)
+ s->ttl = hlim ? *hlim : -1;
- get_inaddr(&s->laddr, &pi->ipi6_addr);
- s->lifindex = pi->ipi6_ifindex;
return;
}