tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

sysctl to disable protocol stack



What follows is (just for your info and discussion for now)
a patch that adds sysctls that disable network protocol stacks.

This includes both IPv4 and IPv6 (though just as you cannot successfully
compile a kernel with no IPv4, it turns out to really be a pretty bad
idea, though not instantly fatal, to disable IPv4 currently...)

The sysctls are net.inet.ip.disabled and net.inet6.ip6.disabled
Set those to 1 to disable the relevant protocol (or other values
as described in the patch to sysctl.7).

Normally, you'd set (one) of those at most in /etc/sysctl.conf,
of that happens, for most purposes, the protocol should (amost)
not exist (some of the sysctl tree needs to remain, and in this
patch, all of it remains, fixing that is still to be added here)
much the same as if you compiled without INET6 (or if it were
possible, without INET, setting net.inet.ip.disabled=1 is a good
way to start discovering some of the problems that remain to be fixed
for when we do want IPv4 to be (optionally) removed).

First question to answer - why the sysctl names?  Surely
net.inet.disabled (and net.inet6.disabled) would be better?
Yes - they would, but the next sysctl name field under inet,
or inet6, is a protocol name (number, really), from a number
space that isn't under our control, and I didn't want to usurp
anyone's protocol number (I guess, using 256 or something outside
the possible range of protocol numbers would have worked).

This is trivial to change to whatever people like...

Next, why just inet and inet6 ... the original code I'm taking
this from had sysctl trees added for netiso and netatalk as well,
to allow them to be disabled - I'm not sure that was ever tested
(even compile tested...) so I decided to omit that for now - NetBSD
currently has no net.atalk or net.iso sysctl trees that I'm aware
of, so aything in this area would be total invention.   The kernel
support for disabling (at least sockets) in those protocols is there,
and adding support for dropping packets for them is trivial, so
we can add that later once the general mechanism is in place.

The original version of this was done to NetBSD 3-beta I think
(all I can see is that __NetBSD_Version__ is 3.0 - but some of
the files are older than in my 3.0 release source tree (so I
am guessing that 3.0 beta was probably the currently available
"recent" version fr the students who did the work initially.
(You can get some idea how long I've had this sitting in a cupboard...)

Lots of NetBSD has changed since then, so this isn't yet well tested
(I ran a current kernel for 20 minutes to play with it, and the
basics look OK, but there is more than needs doing).   I can't run
current for long periods yet, so I need to go stick this same code
into NetBSD 5, so I can test it properly - but I thought that some
of you mightlike to take a look and see just how simple this really
all is.

The shar file appended has two patches, one to sysctl.7 (the only
file outside src/sys that's touched by this .. of course, that didn't
exist in NetBSD 3, so it's content is all just recently invented...)
and the other a patch to the kernel (a half dozen or so files have
minor changes).

Opinions, testing, enhancements, all gratefully received...

kre

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#       kernel.patch
#       sysctl.patch
#
echo x - kernel.patch
sed 's/^X//' >kernel.patch << 'END-of-kernel.patch'
Xdiff -ur sys/kern/uipc_domain.c tsys/kern/uipc_domain.c
X--- sys/kern/uipc_domain.c     2009-10-04 06:02:52.000000000 +0700
X+++ tsys/kern/uipc_domain.c    2009-12-07 20:48:04.000000000 +0700
X@@ -159,6 +159,9 @@
X       if (dp == NULL)
X               return NULL;
X 
X+      if (dom_disabled(dp, DOMAIN_NO_SOCKETS))
X+              return NULL;
X+
X       for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
X               if (pr->pr_type && pr->pr_type == type)
X                       return pr;
X@@ -180,6 +183,9 @@
X       if (dp == NULL)
X               return NULL;
X 
X+      if (dom_disabled(dp, DOMAIN_NO_SOCKETS))
X+              return NULL;
X+
X       for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
X               if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
X                       return pr;
Xdiff -ur sys/kern/uipc_socket.c tsys/kern/uipc_socket.c
X--- sys/kern/uipc_socket.c     2009-11-07 23:05:37.000000000 +0700
X+++ tsys/kern/uipc_socket.c    2009-12-07 20:47:01.000000000 +0700
X@@ -538,9 +538,14 @@
X       else
X               prp = pffindtype(dom, type);
X       if (prp == NULL) {
X+              struct domain *dp;
X+
X               /* no support for domain */
X-              if (pffinddomain(dom) == 0)
X+              if ((dp = pffinddomain(dom)) == 0)
X+                      return EAFNOSUPPORT;
X+              if (dom_disabled(dp, DOMAIN_NO_SOCKETS))
X                       return EAFNOSUPPORT;
X+
X               /* no support for socket type */
X               if (proto == 0 && type != 0)
X                       return EPROTOTYPE;
Xdiff -ur sys/net/rtsock.c tsys/net/rtsock.c
X--- sys/net/rtsock.c   2009-09-17 00:48:19.000000000 +0700
X+++ tsys/net/rtsock.c  2009-12-07 20:45:59.000000000 +0700
X@@ -1063,8 +1063,16 @@
X                       }
X               }
X               IFADDR_FOREACH(ifa, ifp) {
X+                      struct domain *dp;
X+
X                       if (af && af != ifa->ifa_addr->sa_family)
X                               continue;
X+
X+                      dp = pffinddomain(ifa->ifa_addr->sa_family);
X+                      if (dp == NULL  /* panic! */ ||
X+                          dom_disabled(dp, DOMAIN_NO_ADDRESSES))
X+                              continue;
X+
X                       info.rti_info[RTAX_IFA] = ifa->ifa_addr;
X                       info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
X                       info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
Xdiff -ur sys/netinet/if_arp.c tsys/netinet/if_arp.c
X--- sys/netinet/if_arp.c       2009-11-20 16:03:50.000000000 +0700
X+++ tsys/netinet/if_arp.c      2009-12-09 12:25:03.000000000 +0700
X@@ -927,6 +927,10 @@
X       void *tha;
X       int s;
X       uint64_t *arps;
X+      extern struct domain inetdomain;
X+
X+      if (__predict_false(dom_disabled(&inetdomain, DOMAIN_NO_INPUT)))
X+              goto out;
X 
X       if (__predict_false(m_makewritable(&m, 0, m->m_pkthdr.len, M_DONTWAIT)))
X               goto out;
Xdiff -ur sys/netinet/in.h tsys/netinet/in.h
X--- sys/netinet/in.h   2009-09-14 17:36:50.000000000 +0700
X+++ tsys/netinet/in.h  2009-12-07 20:55:20.000000000 +0700
X@@ -454,7 +454,8 @@
X #define       IPCTL_RANDOMID         22       /* use random IP ids (if 
configured) */
X #define       IPCTL_LOOPBACKCKSUM    23       /* do IP checksum on loopback */
X #define       IPCTL_STATS             24      /* IP statistics */
X-#define       IPCTL_MAXID            25
X+#define       IPCTL_DISABLE          25       /* IPv4 disabled! */
X+#define       IPCTL_MAXID            26
X 
X #define       IPCTL_NAMES { \
X       { 0, 0 }, \
X@@ -482,6 +483,7 @@
X       { "random_id", CTLTYPE_INT }, \
X       { "do_loopback_cksum", CTLTYPE_INT }, \
X       { "stats", CTLTYPE_STRUCT }, \
X+      { "disabled", CTLTYPE_INT }, \
X }
X #endif /* _NETBSD_SOURCE */
X 
Xdiff -ur sys/netinet/ip_input.c tsys/netinet/ip_input.c
X--- sys/netinet/ip_input.c     2009-09-17 06:09:00.000000000 +0700
X+++ tsys/netinet/ip_input.c    2009-12-07 22:17:40.000000000 +0700
X@@ -521,6 +521,13 @@
X #endif
X 
X       /*
X+       * If IPv4 has been disabled, then anything that arrives
X+       * is simply dropped.
X+       */
X+      if (__predict_false(dom_disabled(&inetdomain, DOMAIN_NO_INPUT)))
X+              goto bad;
X+
X+      /*
X        * If no IP addresses have been set yet but the interfaces
X        * are receiving, can't do anything with incoming packets yet.
X        */
X@@ -2277,6 +2284,13 @@
X 
X       sysctl_createv(clog, 0, NULL, NULL,
X                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
X+                     CTLTYPE_INT, "disabled",
X+                     SYSCTL_DESCR("Remove support for INET (IPv4)"),
X+                     NULL, 0, &inetdomain.dom_disable, 0,
X+                     CTL_NET, PF_INET, IPPROTO_IP,
X+                     IPCTL_DISABLE, CTL_EOL);
X+      sysctl_createv(clog, 0, NULL, NULL,
X+                     CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
X                      CTLTYPE_INT, "forwarding",
X                      SYSCTL_DESCR("Enable forwarding of INET datagrams"),
X                      NULL, 0, &ipforwarding, 0,
Xdiff -ur sys/netinet/tcp_input.c tsys/netinet/tcp_input.c
X--- sys/netinet/tcp_input.c    2009-09-10 05:41:28.000000000 +0700
X+++ tsys/netinet/tcp_input.c   2009-12-07 21:18:39.000000000 +0700
X@@ -1490,6 +1490,8 @@
X                                       goto badsyn;
X                               }
X                       } else {
X+                              struct domain *dp;
X+
X                               /*
X                                * Received a SYN.
X                                *
X@@ -1512,6 +1514,21 @@
X                               break;
X                               }
X 
X+                              /*
X+                               * if the network protocol has been disabled,
X+                               * then refuse incoming connection attempts
X+                               * (with a RST for politeness, unless we're
X+                               * really pretending to be an ignorant oaf)
X+                               */
X+                              dp = pffinddomain(af);
X+                              if (dp == NULL)
X+                                      goto drop;      /* or panic() */
X+                              if (dom_disabled(dp, DOMAIN_NO_CONNECT)) {
X+                                      if (dp->dom_disable & DOMAIN_IGNORE)
X+                                              goto drop;
X+                                      goto dropwithreset;
X+                              }
X+
X #ifdef INET6
X                               /*
X                                * If deprecated address is forbidden, we do
Xdiff -ur sys/netinet6/in6.h tsys/netinet6/in6.h
X--- sys/netinet6/in6.h 2009-09-12 05:06:29.000000000 +0700
X+++ tsys/netinet6/in6.h        2009-12-07 21:57:56.000000000 +0700
X@@ -577,7 +577,8 @@
X #define IPV6CTL_IFQ           42      /* ip6intrq node */
X /* New entries should be added here from current IPV6CTL_MAXID value. */
X /* to define items, should talk with KAME guys first, for *BSD compatibility 
*/
X-#define IPV6CTL_MAXID         43
X+#define       IPV6CTL_DISABLED        43      /* remove support for INET6 */
X+#define IPV6CTL_MAXID         44
X 
X #define IPV6CTL_NAMES { \
X       { 0, 0 }, \
X@@ -623,6 +624,7 @@
X       { 0, 0 }, \
X       { "maxfrags", CTLTYPE_INT }, \
X       { "ifq", CTLTYPE_NODE }, \
X+      { "disabled", CTLTYPE_INT }, \
X }
X 
X #endif /* _NETBSD_SOURCE */
Xdiff -ur sys/netinet6/ip6_input.c tsys/netinet6/ip6_input.c
X--- sys/netinet6/ip6_input.c   2009-09-17 06:09:01.000000000 +0700
X+++ tsys/netinet6/ip6_input.c  2009-12-07 22:18:54.000000000 +0700
X@@ -287,6 +287,13 @@
X #endif
X 
X       /*
X+       * If support for IPv6 has been removed,
X+       * IPv6 packets that arrive are always trash
X+       */
X+      if (__predict_false(dom_disabled(&inet6domain, DOMAIN_NO_INPUT)))
X+              goto bad;
X+
X+      /*
X        * make sure we don't have onion peering information into m_tag.
X        */
X       ip6_delaux(m);
X@@ -1714,6 +1721,13 @@
X 
X       sysctl_createv(clog, 0, NULL, NULL,
X                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
X+                     CTLTYPE_INT, "disabled",
X+                     SYSCTL_DESCR("Remove support for INET6 (IPv6)"),
X+                     NULL, 0, &inet6domain.dom_disable, 0,
X+                     CTL_NET, PF_INET6, IPPROTO_IPV6,
X+                     IPV6CTL_DISABLED, CTL_EOL);
X+      sysctl_createv(clog, 0, NULL, NULL,
X+                     CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
X                      CTLTYPE_INT, "forwarding",
X                      SYSCTL_DESCR("Enable forwarding of INET6 datagrams"),
X                      NULL, 0, &ip6_forwarding, 0,
Xdiff -ur sys/sys/domain.h tsys/sys/domain.h
X--- sys/sys/domain.h   2009-09-12 05:06:29.000000000 +0700
X+++ tsys/sys/domain.h  2009-12-07 21:06:20.000000000 +0700
X@@ -85,6 +85,7 @@
X       uint_fast8_t    dom_sa_cmpofs;
X       uint_fast8_t    dom_sa_cmplen;
X       struct dom_rtlist dom_rtcache;
X+      int             dom_disable;
X };
X 
X STAILQ_HEAD(domainhead,domain);
X@@ -98,6 +99,15 @@
X extern struct domainhead domains;
X void domain_attach(struct domain *);
X void domaininit(bool);
X+
X+#define       DOMAIN_DISABLED         0x00000001      /* disable everything */
X+#define       DOMAIN_IGNORE           0x00000002      /* act as if unknown */
X+#define       DOMAIN_NO_SOCKETS       0x00000010      /* no new sockets */
X+#define       DOMAIN_NO_ADDRESSES     0x00000020      /* no addresses visible 
*/
X+#define       DOMAIN_NO_CONNECT       0x00000040      /* no new conections */
X+#define       DOMAIN_NO_INPUT         0x00000080      /* input rejected */
X+
X+#define       dom_disabled(dp, flag)  ((dp)->dom_disable & (DOMAIN_DISABLED | 
(flag)))
X #endif
X 
X #endif /* !_SYS_DOMAIN_H_ */
END-of-kernel.patch
echo x - sysctl.patch
sed 's/^X//' >sysctl.patch << 'END-of-sysctl.patch'
X--- /release/current/usr/src/share/man/man7/sysctl.7   2009-12-08 
15:57:32.000000000 +0700
X+++ sysctl.7   2009-12-09 12:59:19.000000000 +0700
X@@ -989,6 +989,7 @@
X .It ip        anonportmin     integer yes
X .It ip        checkinterface  integer yes
X .It ip        directed-broadcast      integer yes
X+.It ip        disabled        integer yes
X .It ip        do_loopback_cksum       integer yes
X .It ip        forwarding      integer yes
X .It ip        forwsrcrt       integer yes
X@@ -1104,6 +1105,17 @@
X the packets for those packets are received.
X .It Li ip.directed-broadcast
X If set to 1, enables directed broadcast behavior for the host.
X+.It Li ip.disabled
X+If set to 1, or any odd number, support for IPv4 is (approximately)
X+removed from the system.
X+Even non-zero values remove support for selected parts of the protocol.
X+The value set should be the sum of those the following constants to
X+achieve the desired effect.
X+To prevent new PF_INET sockets being created: 16.
X+To prevent configuring addresses, and hide any already configured: 32.
X+To refuse incoming TCP connections: 64, and to not send a reset
X+while doing so: 2.
X+To drop all incoming IPv4 datagrams: 128.
X .It Li ip.do_loopback_cksum
X Perform IP checksum on loopback.
X .It Li ip.forwarding
X@@ -1358,6 +1370,7 @@
X .It ip6       auto_flowlabel  integer yes
X .It ip6       dad_count       integer yes
X .It ip6       defmcasthlim    integer yes
X+.It ip6       disabled        integer yes
X .It ip6       forwarding      integer yes
X .It ip6       gifhlim integer yes
X .It ip6       hashsize        integer yes
X@@ -1409,6 +1422,12 @@
X This value applies to all the transport protocols on top of IPv6.
X There are APIs to override the value, as documented in
X .Xr ip6 4 .
X+.It Li ip6.disabled
X+If set to 1, or any odd number, support for IPv6 is (approximately)
X+removed from the system.
X+See the description of
X+.Li ip.disabled
X+for a description of the various even values possible.
X .It Li ip6.forwarding
X If set to 1, enables IPv6 forwarding for the node,
X meaning that the node is acting as a router.
END-of-sysctl.patch
exit



Home | Main Index | Thread Index | Old Index