Implement support for RFC 3514 (The Security Flag in the IPv4 Header).
(See: ftp://ftp.rfc-editor.org/in-notes/rfc3514.txt) This fulfills the host requirements for userland support by way of the setsockopt() IP_EVIL_INTENT message. There are three sysctl tunables provided to govern system behavior. net.inet.ip.rfc3514: Enables support for rfc3514. As this is an Informational RFC and support is not yet widespread this option is disabled by default. net.inet.ip.hear_no_evil If set the host will discard all received evil packets. net.inet.ip.speak_no_evil If set the host will discard all transmitted evil packets. The IP statistics counter 'ips_evil' (available via 'netstat') provides information on the number of 'evil' packets recieved. For reference, the '-E' option to 'ping' has been provided to demonstrate and test the implementation.
This commit is contained in:
parent
c8d01707ba
commit
09139a4537
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=112929
@ -42,7 +42,7 @@
|
|||||||
packets to network hosts
|
packets to network hosts
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl AaDdfnoQqRrv
|
.Op Fl AaDdEfnoQqRrv
|
||||||
.Op Fl c Ar count
|
.Op Fl c Ar count
|
||||||
.Op Fl i Ar wait
|
.Op Fl i Ar wait
|
||||||
.Op Fl l Ar preload
|
.Op Fl l Ar preload
|
||||||
@ -56,7 +56,7 @@ packets to network hosts
|
|||||||
.Op Fl z Ar tos
|
.Op Fl z Ar tos
|
||||||
.Ar host
|
.Ar host
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl AaDdfLnoQqRrv
|
.Op Fl AaDdEfLnoQqRrv
|
||||||
.Op Fl c Ar count
|
.Op Fl c Ar count
|
||||||
.Op Fl I Ar iface
|
.Op Fl I Ar iface
|
||||||
.Op Fl i Ar wait
|
.Op Fl i Ar wait
|
||||||
@ -122,6 +122,8 @@ If this option is not specified,
|
|||||||
will operate until interrupted.
|
will operate until interrupted.
|
||||||
.It Fl D
|
.It Fl D
|
||||||
Set the Don't Fragment bit.
|
Set the Don't Fragment bit.
|
||||||
|
.It Fl E
|
||||||
|
Set the EVIL bit.
|
||||||
.It Fl d
|
.It Fl d
|
||||||
Set the
|
Set the
|
||||||
.Dv SO_DEBUG
|
.Dv SO_DEBUG
|
||||||
|
@ -143,6 +143,7 @@ int options;
|
|||||||
#define F_HDRINCL 0x40000
|
#define F_HDRINCL 0x40000
|
||||||
#define F_MASK 0x80000
|
#define F_MASK 0x80000
|
||||||
#define F_TIME 0x100000
|
#define F_TIME 0x100000
|
||||||
|
#define F_SO_EVIL 0x200000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
|
* MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
|
||||||
@ -256,7 +257,7 @@ main(argc, argv)
|
|||||||
|
|
||||||
outpack = outpackhdr + sizeof(struct ip);
|
outpack = outpackhdr + sizeof(struct ip);
|
||||||
while ((ch = getopt(argc, argv,
|
while ((ch = getopt(argc, argv,
|
||||||
"Aac:DdfI:i:Ll:M:m:nop:QqRrS:s:T:t:vz:"
|
"Aac:DdEfI:i:Ll:M:m:nop:QqRrS:s:T:t:vz:"
|
||||||
#ifdef IPSEC
|
#ifdef IPSEC
|
||||||
#ifdef IPSEC_POLICY_IPSEC
|
#ifdef IPSEC_POLICY_IPSEC
|
||||||
"P:"
|
"P:"
|
||||||
@ -286,6 +287,9 @@ main(argc, argv)
|
|||||||
case 'd':
|
case 'd':
|
||||||
options |= F_SO_DEBUG;
|
options |= F_SO_DEBUG;
|
||||||
break;
|
break;
|
||||||
|
case 'E':
|
||||||
|
options |= F_SO_EVIL;
|
||||||
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
if (uid) {
|
if (uid) {
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
@ -547,6 +551,10 @@ main(argc, argv)
|
|||||||
if (options & F_SO_DONTROUTE)
|
if (options & F_SO_DONTROUTE)
|
||||||
(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
|
(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
|
||||||
sizeof(hold));
|
sizeof(hold));
|
||||||
|
if (options & F_SO_EVIL)
|
||||||
|
if (setsockopt(s, IPPROTO_IP, IP_EVIL_INTENT, (char *)&hold,
|
||||||
|
sizeof(hold)) != 0)
|
||||||
|
err(EX_OSERR, "setsockopt(s, IPPROTO_IP, IP_EVIL_INTENT, ...)");
|
||||||
#ifdef IPSEC
|
#ifdef IPSEC
|
||||||
#ifdef IPSEC_POLICY_IPSEC
|
#ifdef IPSEC_POLICY_IPSEC
|
||||||
if (options & F_POLICY) {
|
if (options & F_POLICY) {
|
||||||
@ -593,6 +601,8 @@ main(argc, argv)
|
|||||||
ip->ip_tos = tos;
|
ip->ip_tos = tos;
|
||||||
ip->ip_id = 0;
|
ip->ip_id = 0;
|
||||||
ip->ip_off = df ? IP_DF : 0;
|
ip->ip_off = df ? IP_DF : 0;
|
||||||
|
if (options & F_SO_EVIL)
|
||||||
|
ip->ip_off |= IP_EVIL;
|
||||||
ip->ip_ttl = ttl;
|
ip->ip_ttl = ttl;
|
||||||
ip->ip_p = IPPROTO_ICMP;
|
ip->ip_p = IPPROTO_ICMP;
|
||||||
ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY;
|
ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY;
|
||||||
@ -991,6 +1001,8 @@ pr_pack(buf, cc, from, tv)
|
|||||||
(void)printf(" ttl=%d", ip->ip_ttl);
|
(void)printf(" ttl=%d", ip->ip_ttl);
|
||||||
if (timing)
|
if (timing)
|
||||||
(void)printf(" time=%.3f ms", triptime);
|
(void)printf(" time=%.3f ms", triptime);
|
||||||
|
if (ip->ip_off & IP_EVIL)
|
||||||
|
(void)printf(" (EVIL)");
|
||||||
if (dupflag)
|
if (dupflag)
|
||||||
(void)printf(" (DUP!)");
|
(void)printf(" (DUP!)");
|
||||||
if (options & F_AUDIBLE)
|
if (options & F_AUDIBLE)
|
||||||
|
@ -261,6 +261,17 @@ adaptation described above.
|
|||||||
.Pq ip.rtmaxcache
|
.Pq ip.rtmaxcache
|
||||||
Integer: trigger level of cached, unreferenced, protocol-cloned routes
|
Integer: trigger level of cached, unreferenced, protocol-cloned routes
|
||||||
which initiates dynamic adaptation (default 128).
|
which initiates dynamic adaptation (default 128).
|
||||||
|
.It Dv IPCTL_RFC3514
|
||||||
|
.Pq ip.rfc3514
|
||||||
|
Boolean: Enable support for RFC3514. Defaults to off.
|
||||||
|
.It Dv IPCTL_SPEAK_NO_EVIL
|
||||||
|
.Pq ip.speak_no_evil
|
||||||
|
Boolean: Prevent the transmission of RFC3514 (EVIL) packets.
|
||||||
|
Defaults to off.
|
||||||
|
.It Dv IPCTL_HEAR_NO_EVIL
|
||||||
|
.Pq ip.hear_no_evil
|
||||||
|
Boolean: Prevent the reception of RFC3514 (EVIL) packets.
|
||||||
|
Defaults to off.
|
||||||
.El
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr ioctl 2 ,
|
.Xr ioctl 2 ,
|
||||||
|
@ -164,6 +164,15 @@ control message from
|
|||||||
can be used directly as a control message for
|
can be used directly as a control message for
|
||||||
.Xr sendmsg 2 .
|
.Xr sendmsg 2 .
|
||||||
.Pp
|
.Pp
|
||||||
|
.Dv IP_EVIL_INTENT can be used to specify that IP packets should have their
|
||||||
|
EVIL option set as per RFC3514.
|
||||||
|
The cmsghdr fields should have the following values:
|
||||||
|
.Bd -literal
|
||||||
|
cmsg_len = sizeof(struct in_addr)
|
||||||
|
cmsg_level = IPPROTO_IP
|
||||||
|
cmsg_type = IP_EVIL_INTENT
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
.Dv IP_PORTRANGE
|
.Dv IP_PORTRANGE
|
||||||
may be used to set the port range used for selecting a local port number
|
may be used to set the port range used for selecting a local port number
|
||||||
on a socket with an unspecified (zero) port number.
|
on a socket with an unspecified (zero) port number.
|
||||||
|
@ -399,6 +399,8 @@ __END_DECLS
|
|||||||
#define IP_DUMMYNET_FLUSH 62 /* flush dummynet */
|
#define IP_DUMMYNET_FLUSH 62 /* flush dummynet */
|
||||||
#define IP_DUMMYNET_GET 64 /* get entire dummynet pipes */
|
#define IP_DUMMYNET_GET 64 /* get entire dummynet pipes */
|
||||||
|
|
||||||
|
#define IP_EVIL_INTENT 65 /* RFC3514 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Defaults and limits for options
|
* Defaults and limits for options
|
||||||
*/
|
*/
|
||||||
|
@ -276,6 +276,7 @@ struct inpcbinfo { /* XXX documentation, prefixes */
|
|||||||
#define INP_RECVIF 0x80 /* receive incoming interface */
|
#define INP_RECVIF 0x80 /* receive incoming interface */
|
||||||
#define INP_MTUDISC 0x100 /* user can do MTU discovery */
|
#define INP_MTUDISC 0x100 /* user can do MTU discovery */
|
||||||
#define INP_FAITH 0x200 /* accept FAITH'ed connections */
|
#define INP_FAITH 0x200 /* accept FAITH'ed connections */
|
||||||
|
#define INP_EVIL 0x400 /* Packet has evil intentions */
|
||||||
|
|
||||||
#define IN6P_IPV6_V6ONLY 0x008000 /* restrict AF_INET6 socket for v6 */
|
#define IN6P_IPV6_V6ONLY 0x008000 /* restrict AF_INET6 socket for v6 */
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ struct ip {
|
|||||||
u_short ip_id; /* identification */
|
u_short ip_id; /* identification */
|
||||||
u_short ip_off; /* fragment offset field */
|
u_short ip_off; /* fragment offset field */
|
||||||
#define IP_RF 0x8000 /* reserved fragment flag */
|
#define IP_RF 0x8000 /* reserved fragment flag */
|
||||||
|
#define IP_EVIL 0x8000 /* packet is evil */
|
||||||
#define IP_DF 0x4000 /* dont fragment flag */
|
#define IP_DF 0x4000 /* dont fragment flag */
|
||||||
#define IP_MF 0x2000 /* more fragments flag */
|
#define IP_MF 0x2000 /* more fragments flag */
|
||||||
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
||||||
|
@ -134,6 +134,11 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, sendsourcequench, CTLFLAG_RW,
|
|||||||
&ip_sendsourcequench, 0,
|
&ip_sendsourcequench, 0,
|
||||||
"Enable the transmission of source quench packets");
|
"Enable the transmission of source quench packets");
|
||||||
|
|
||||||
|
static int hear_no_evil = 0;
|
||||||
|
SYSCTL_INT(_net_inet_ip, OID_AUTO, hear_no_evil, CTLFLAG_RW,
|
||||||
|
&hear_no_evil, 0,
|
||||||
|
"Drop all received EVIL packets.");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX - Setting ip_checkinterface mostly implements the receive side of
|
* XXX - Setting ip_checkinterface mostly implements the receive side of
|
||||||
* the Strong ES model described in RFC 1122, but since the routing table
|
* the Strong ES model described in RFC 1122, but since the routing table
|
||||||
@ -406,6 +411,15 @@ ip_input(struct mbuf *m)
|
|||||||
}
|
}
|
||||||
ip->ip_off = ntohs(ip->ip_off);
|
ip->ip_off = ntohs(ip->ip_off);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for RFC3514 (EVIL) packets.
|
||||||
|
*/
|
||||||
|
if (ip->ip_off & IP_EVIL) {
|
||||||
|
ipstat.ips_evil++;
|
||||||
|
if (hear_no_evil)
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that the amount of data in the buffers
|
* Check that the amount of data in the buffers
|
||||||
* is as at least much as the IP header would have us expect.
|
* is as at least much as the IP header would have us expect.
|
||||||
|
@ -101,6 +101,13 @@ int mbuf_frag_size = 0;
|
|||||||
SYSCTL_INT(_net_inet_ip, OID_AUTO, mbuf_frag_size, CTLFLAG_RW,
|
SYSCTL_INT(_net_inet_ip, OID_AUTO, mbuf_frag_size, CTLFLAG_RW,
|
||||||
&mbuf_frag_size, 0, "Fragment outgoing mbufs to this size");
|
&mbuf_frag_size, 0, "Fragment outgoing mbufs to this size");
|
||||||
#endif
|
#endif
|
||||||
|
static int ip_do_rfc3514 = 0;
|
||||||
|
SYSCTL_INT(_net_inet_ip, OID_AUTO, rfc3514, CTLFLAG_RW,
|
||||||
|
&ip_do_rfc3514, 0, "IPv4 Header Security Flag Support");
|
||||||
|
|
||||||
|
static int speak_no_evil = 0;
|
||||||
|
SYSCTL_INT(_net_inet_ip, OID_AUTO, speak_no_evil, CTLFLAG_RW,
|
||||||
|
&speak_no_evil, 0, "Drop all EVIL packets before output.");
|
||||||
|
|
||||||
static struct mbuf *ip_insertoptions(struct mbuf *, struct mbuf *, int *);
|
static struct mbuf *ip_insertoptions(struct mbuf *, struct mbuf *, int *);
|
||||||
static struct ifnet *ip_multicast_if(struct in_addr *, int *);
|
static struct ifnet *ip_multicast_if(struct in_addr *, int *);
|
||||||
@ -228,7 +235,7 @@ ip_output(m0, opt, ro, flags, imo, inp)
|
|||||||
if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
|
if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
|
||||||
ip->ip_v = IPVERSION;
|
ip->ip_v = IPVERSION;
|
||||||
ip->ip_hl = hlen >> 2;
|
ip->ip_hl = hlen >> 2;
|
||||||
ip->ip_off &= IP_DF;
|
ip->ip_off &= IP_DF|IP_EVIL;
|
||||||
#ifdef RANDOM_IP_ID
|
#ifdef RANDOM_IP_ID
|
||||||
ip->ip_id = ip_randomid();
|
ip->ip_id = ip_randomid();
|
||||||
#else
|
#else
|
||||||
@ -239,6 +246,17 @@ ip_output(m0, opt, ro, flags, imo, inp)
|
|||||||
hlen = ip->ip_hl << 2;
|
hlen = ip->ip_hl << 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RFC3514 */
|
||||||
|
if ((inp != NULL) && /* Originated */
|
||||||
|
ip_do_rfc3514 && /* Supported */
|
||||||
|
((inp->inp_flags & INP_EVIL) == INP_EVIL)) /* Optioned */
|
||||||
|
ip->ip_off |= IP_EVIL;
|
||||||
|
|
||||||
|
if (speak_no_evil && (ip->ip_off & IP_EVIL)) {
|
||||||
|
error = EACCES;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef FAST_IPSEC
|
#ifdef FAST_IPSEC
|
||||||
if (ro == NULL) {
|
if (ro == NULL) {
|
||||||
ro = &iproute;
|
ro = &iproute;
|
||||||
@ -1426,6 +1444,7 @@ ip_ctloutput(so, sopt)
|
|||||||
case IP_RECVDSTADDR:
|
case IP_RECVDSTADDR:
|
||||||
case IP_RECVIF:
|
case IP_RECVIF:
|
||||||
case IP_FAITH:
|
case IP_FAITH:
|
||||||
|
case IP_EVIL_INTENT:
|
||||||
error = sooptcopyin(sopt, &optval, sizeof optval,
|
error = sooptcopyin(sopt, &optval, sizeof optval,
|
||||||
sizeof optval);
|
sizeof optval);
|
||||||
if (error)
|
if (error)
|
||||||
@ -1464,6 +1483,12 @@ ip_ctloutput(so, sopt)
|
|||||||
case IP_FAITH:
|
case IP_FAITH:
|
||||||
OPTSET(INP_FAITH);
|
OPTSET(INP_FAITH);
|
||||||
break;
|
break;
|
||||||
|
case IP_EVIL_INTENT:
|
||||||
|
if (ip_do_rfc3514) {
|
||||||
|
OPTSET(INP_EVIL);
|
||||||
|
} else
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#undef OPTSET
|
#undef OPTSET
|
||||||
@ -1596,6 +1621,8 @@ ip_ctloutput(so, sopt)
|
|||||||
case IP_FAITH:
|
case IP_FAITH:
|
||||||
optval = OPTBIT(INP_FAITH);
|
optval = OPTBIT(INP_FAITH);
|
||||||
break;
|
break;
|
||||||
|
case IP_EVIL:
|
||||||
|
optval = OPTBIT(INP_EVIL);
|
||||||
}
|
}
|
||||||
error = sooptcopyout(sopt, &optval, sizeof optval);
|
error = sooptcopyout(sopt, &optval, sizeof optval);
|
||||||
break;
|
break;
|
||||||
|
@ -132,6 +132,7 @@ struct ipstat {
|
|||||||
u_long ips_notmember; /* multicasts for unregistered grps */
|
u_long ips_notmember; /* multicasts for unregistered grps */
|
||||||
u_long ips_nogif; /* no match gif found */
|
u_long ips_nogif; /* no match gif found */
|
||||||
u_long ips_badaddr; /* invalid address on header */
|
u_long ips_badaddr; /* invalid address on header */
|
||||||
|
u_long ips_evil; /* EVIL packets received */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
|
@ -568,6 +568,7 @@ ip_stats(u_long off __unused, const char *name, int af1 __unused)
|
|||||||
p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
|
p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
|
||||||
p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
|
p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
|
||||||
p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
|
p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
|
||||||
|
p(ips_evil, "\t%lu EVIL datagram%s received.\n");
|
||||||
#undef p
|
#undef p
|
||||||
#undef p1a
|
#undef p1a
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user