Re: GRE datagram socket support

2020-01-21 Thread Theo de Raadt
David Gwynne  wrote:

> > On 22 Jan 2020, at 8:54 am, Damien Miller  wrote:
> > 
> > On Wed, 22 Jan 2020, David Gwynne wrote:
> > 
> >>> Index: sys/kern/kern_pledge.c
> >>> ===
> >>> RCS file: /cvs/src/sys/kern/kern_pledge.c,v
> >>> retrieving revision 1.255
> >>> diff -u -p -r1.255 kern_pledge.c
> >>> --- sys/kern/kern_pledge.c25 Aug 2019 18:46:40 -  1.255
> >>> +++ sys/kern/kern_pledge.c29 Oct 2019 07:57:58 -
> >>> @@ -666,7 +666,7 @@ pledge_namei(struct proc *p, struct name
> >>>   }
> >>>   }
> >>> 
> >>> - /* DNS needs /etc/{resolv.conf,hosts,services}. */
> >>> + /* DNS needs /etc/{resolv.conf,hosts,services,protocols}. */
> >>>   if ((ni->ni_pledge == PLEDGE_RPATH) &&
> >>>   (p->p_p->ps_pledge & PLEDGE_DNS)) {
> >>>   if (strcmp(path, "/etc/resolv.conf") == 0) {
> >>> @@ -678,6 +678,10 @@ pledge_namei(struct proc *p, struct name
> >>>   return (0);
> >>>   }
> >>>   if (strcmp(path, "/etc/services") == 0) {
> >>> + ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
> >>> + return (0);
> >>> + }
> >>> + if (strcmp(path, "/etc/protocols") == 0) {
> >>>   ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
> >>>   return (0);
> > 
> > This looks like it is fixing a real, separate bug in pledge vs
> > getaddrinfo, no? (specifically: that lookups for named ports will fail
> > currently).
> 
> no, our getaddrinfo currently hardcodes mapping of SOCK_STREAM, SOCK_DGRAM, 
> IPPROTO_TCP, and IPPROTO_UDP and maps them to "udp" and "tcp" for use when 
> looking up /etc/services via getservbyname_r. this is fine because they are 
> by far the most common case and worth optimising for.
> 
> the problem is if (when) i want to use getnameinfo to look up entries for 
> IPPROTO_GRE. i either hardcode IPPROTO_GRE in getnameinfo guts to "gre" for 
> it to pass to getservbyname_r, or i look up /etc/protocols via 
> getprotobynumber_r to get a name. i opted for the latter.

a number of people have expressed gaping-mouth horror that pledge knows
about some userland paths.  these specific paths are really part of what
libc does.  we could have hard-coded this info into libc and avoided the
horror, but that approach would have other downsides.

many programs hit libc interfaces which needed the /etc/services file
because of getaddrinfo_async/getnameinfo which are highly desired
interfaces.  protocols hadn't hit this situation yet, but will now rise
to the same level.

i want to *minimize* the number of recognized paths, since there are two
very subtle changes in behaviour.

one other thing needs mentioning:  this kind of translation won't work in
a chroot.



Re: GRE datagram socket support

2020-01-21 Thread David Gwynne



> On 22 Jan 2020, at 8:54 am, Damien Miller  wrote:
> 
> On Wed, 22 Jan 2020, David Gwynne wrote:
> 
>>> Index: sys/kern/kern_pledge.c
>>> ===
>>> RCS file: /cvs/src/sys/kern/kern_pledge.c,v
>>> retrieving revision 1.255
>>> diff -u -p -r1.255 kern_pledge.c
>>> --- sys/kern/kern_pledge.c  25 Aug 2019 18:46:40 -  1.255
>>> +++ sys/kern/kern_pledge.c  29 Oct 2019 07:57:58 -
>>> @@ -666,7 +666,7 @@ pledge_namei(struct proc *p, struct name
>>> }
>>> }
>>> 
>>> -   /* DNS needs /etc/{resolv.conf,hosts,services}. */
>>> +   /* DNS needs /etc/{resolv.conf,hosts,services,protocols}. */
>>> if ((ni->ni_pledge == PLEDGE_RPATH) &&
>>> (p->p_p->ps_pledge & PLEDGE_DNS)) {
>>> if (strcmp(path, "/etc/resolv.conf") == 0) {
>>> @@ -678,6 +678,10 @@ pledge_namei(struct proc *p, struct name
>>> return (0);
>>> }
>>> if (strcmp(path, "/etc/services") == 0) {
>>> +   ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
>>> +   return (0);
>>> +   }
>>> +   if (strcmp(path, "/etc/protocols") == 0) {
>>> ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
>>> return (0);
> 
> This looks like it is fixing a real, separate bug in pledge vs
> getaddrinfo, no? (specifically: that lookups for named ports will fail
> currently).

no, our getaddrinfo currently hardcodes mapping of SOCK_STREAM, SOCK_DGRAM, 
IPPROTO_TCP, and IPPROTO_UDP and maps them to "udp" and "tcp" for use when 
looking up /etc/services via getservbyname_r. this is fine because they are by 
far the most common case and worth optimising for.

the problem is if (when) i want to use getnameinfo to look up entries for 
IPPROTO_GRE. i either hardcode IPPROTO_GRE in getnameinfo guts to "gre" for it 
to pass to getservbyname_r, or i look up /etc/protocols via getprotobynumber_r 
to get a name. i opted for the latter.

dlg


Re: GRE datagram socket support

2020-01-21 Thread Theo de Raadt
I am a big grumpy about /etc/protocols becoming another file that
is bypassed (accepted transparently) in kernel pledge.  but dlg
has convinced me hardcoding would be worse.



Re: GRE datagram socket support

2020-01-21 Thread YASUOKA Masahiko
Hi,

I think that is a good idea.

On Wed, 22 Jan 2020 08:35:05 +1000
David Gwynne  wrote:
> Has anyone got an opinion on this? I am still interested in doing more
> packet capture things on OpenBSD using GRE as a transport, and the idea
> of maintaining this out of tree just makes me feel tired.
> 
> On Tue, Oct 29, 2019 at 06:34:50PM +1000, David Gwynne wrote:
>> i've been toying with this idea of implementing GRE as a datagram
>> protocol that userland can use just like UDP. the idea is to make it
>> easy to support the implementation of NHRP in userland for mgre(4),
>> and also for ERSPAN* support without going down the path linux took**.
>> 
>> so this is the result of having a go at implementing the idea. the diff
>> includes several independent parts, but they all work together to make
>> GRE as comfortable to use as UDP. the two main parts are the actual
>> protocol implementation in src/sys/netinet/ip_gre.c, and the tweaks to
>> getaddrinfo to allow the resolution of gre services. the /etc/services
>> chunk gets used by the getaddrinfo bits.
>> 
>> so, the first chunk lets you do this (as root in userland):
>> 
>>  int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_GRE);
>> 
>> that gives you a file descriptor you can then use with bind(),
>> connect(), sendto(), recvfrom(), etc. you write a message to the
>> kernel and it prepends the GRE and IP headers and pushes it out.
>> it is set up so the GRE protocol is handed to the kernel via the
>> sin_port or sin6_port member of struct sockaddr_in an sockaddr_in6
>> respectively. there's no source and destination protocol fields, just
>> one that both ends agree on, so if you connect then bind, your
>> sockaddrs have to agree on the proto. unfortunately there's no such
>> thing as a wildcard or reserved protocol in GRE, so 0 can't be used
>> as a wildcard like it can in udp and tcp.
>> 
>> the sockets support the configuration of optional GRE headers, as
>> defined in RFC 2890, using setsockopt. importantly you can enable
>> the key and sequence number headers, which again, the kernel offloads
>> for you.
>> 
>> the second chunk tweaks getaddrinfo so it lets you specify things other
>> than IPPROTO_UDP and IPPROTO_TCP. protocols other than those are now
>> looked up in /etc/protocols to get their name, which in turn is used to
>> look up entries in /etc/services. while i was there and reading rfcs, i
>> noted different behaviour for wildcarded socktypes and protocols, which
>> i've tried to implement. eric@ seems generally ok with this stuff, and
>> suggested the tweak to pledge to allow access to /etc/protocols using
>> the dns pledge. tcp and udp are still special though, and are still
>> omgoptimised.
>> 
>> all this together lets the program at
>> https://mild.embarrassm.net/~dlg/diff/egred.c work. it is a userland
>> reimplementation of a simplified egre(4) using tap(4) and a gre socket.
>> the io path is literally reading from one fd and writing it to the othe,
>> everything else is boilerplate.
>> 
>> i suspect the kernel stuff is a bit rough as i havent had to test every
>> path, but it supports common functionality.
>> 
>> thoughts? i am pretty pleased with this has turned out, and would be
>> keen to put it in the tree and work on it some more.
>> 
>> * https://tools.ietf.org/html/draft-foschiano-erspan-03
>> ** http://vger.kernel.org/lpc_net2018_talks/erspan-linux-presentation.pdf
>> 
>> Index: etc/services
>> ===
>> RCS file: /cvs/src/etc/services,v
>> retrieving revision 1.96
>> diff -u -p -r1.96 services
>> --- etc/services 27 Jan 2019 20:35:06 -  1.96
>> +++ etc/services 29 Oct 2019 07:57:44 -
>> @@ -332,6 +332,21 @@ spamd-cfg   8026/tcp# 
>> spamd(8) configur
>>  dhcpd-sync  8067/udp# dhcpd(8) synchronisation
>>  hunt26740/udp   # hunt(6)
>>  #
>> +# GRE Protocol Types
>> +#
>> +keepalive   0/gre   # 0x: IP tunnel keepalive
>> +ipv42048/gre# 0x0800: IPv4
>> +nhrp8193/gre# 0x2001: Next Hop 
>> Resolution Protocol
>> +erspan3 8939/gre# 0x22eb: ERSPAN III
>> +transether  25944/gre   ethernet# 0x6558: Trans Ether Bridging
>> +ipv634525/gre   # 0x86dd: IPv6
>> +wccp34878/gre   # 0x883e: Web Content 
>> Cache Protocol
>> +mpls34887/gre   # 0x8847: MPLS
>> +#mpls   34888/gre   # 0x8848: MPLS Multicast
>> +erspan  35006/gre   erspan2 # 0x88be: ERSPAN I/II
>> +nsh 35151/gre   # 0x894f: Network Service Header
>> +control 47082/gre   # 0xb7ea: RFC 8157
>> +#
>>  # Appletalk
>>  #
>>  rtmp1/ddp

Re: GRE datagram socket support

2020-01-21 Thread Damien Miller
On Wed, 22 Jan 2020, David Gwynne wrote:

> Has anyone got an opinion on this? I am still interested in doing more
> packet capture things on OpenBSD using GRE as a transport, and the idea
> of maintaining this out of tree just makes me feel tired.

This is cool. I don't spot any major problems with this, but I'm rusty on
kernel networking.

> > Index: sys/kern/kern_pledge.c
> > ===
> > RCS file: /cvs/src/sys/kern/kern_pledge.c,v
> > retrieving revision 1.255
> > diff -u -p -r1.255 kern_pledge.c
> > --- sys/kern/kern_pledge.c  25 Aug 2019 18:46:40 -  1.255
> > +++ sys/kern/kern_pledge.c  29 Oct 2019 07:57:58 -
> > @@ -666,7 +666,7 @@ pledge_namei(struct proc *p, struct name
> > }
> > }
> >  
> > -   /* DNS needs /etc/{resolv.conf,hosts,services}. */
> > +   /* DNS needs /etc/{resolv.conf,hosts,services,protocols}. */
> > if ((ni->ni_pledge == PLEDGE_RPATH) &&
> > (p->p_p->ps_pledge & PLEDGE_DNS)) {
> > if (strcmp(path, "/etc/resolv.conf") == 0) {
> > @@ -678,6 +678,10 @@ pledge_namei(struct proc *p, struct name
> > return (0);
> > }
> > if (strcmp(path, "/etc/services") == 0) {
> > +   ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
> > +   return (0);
> > +   }
> > +   if (strcmp(path, "/etc/protocols") == 0) {
> > ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
> > return (0);

This looks like it is fixing a real, separate bug in pledge vs
getaddrinfo, no? (specifically: that lookups for named ports will fail
currently).



Re: GRE datagram socket support

2020-01-21 Thread David Gwynne
Has anyone got an opinion on this? I am still interested in doing more
packet capture things on OpenBSD using GRE as a transport, and the idea
of maintaining this out of tree just makes me feel tired.

On Tue, Oct 29, 2019 at 06:34:50PM +1000, David Gwynne wrote:
> i've been toying with this idea of implementing GRE as a datagram
> protocol that userland can use just like UDP. the idea is to make it
> easy to support the implementation of NHRP in userland for mgre(4),
> and also for ERSPAN* support without going down the path linux took**.
> 
> so this is the result of having a go at implementing the idea. the diff
> includes several independent parts, but they all work together to make
> GRE as comfortable to use as UDP. the two main parts are the actual
> protocol implementation in src/sys/netinet/ip_gre.c, and the tweaks to
> getaddrinfo to allow the resolution of gre services. the /etc/services
> chunk gets used by the getaddrinfo bits.
> 
> so, the first chunk lets you do this (as root in userland):
> 
>   int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_GRE);
> 
> that gives you a file descriptor you can then use with bind(),
> connect(), sendto(), recvfrom(), etc. you write a message to the
> kernel and it prepends the GRE and IP headers and pushes it out.
> it is set up so the GRE protocol is handed to the kernel via the
> sin_port or sin6_port member of struct sockaddr_in an sockaddr_in6
> respectively. there's no source and destination protocol fields, just
> one that both ends agree on, so if you connect then bind, your
> sockaddrs have to agree on the proto. unfortunately there's no such
> thing as a wildcard or reserved protocol in GRE, so 0 can't be used
> as a wildcard like it can in udp and tcp.
> 
> the sockets support the configuration of optional GRE headers, as
> defined in RFC 2890, using setsockopt. importantly you can enable
> the key and sequence number headers, which again, the kernel offloads
> for you.
> 
> the second chunk tweaks getaddrinfo so it lets you specify things other
> than IPPROTO_UDP and IPPROTO_TCP. protocols other than those are now
> looked up in /etc/protocols to get their name, which in turn is used to
> look up entries in /etc/services. while i was there and reading rfcs, i
> noted different behaviour for wildcarded socktypes and protocols, which
> i've tried to implement. eric@ seems generally ok with this stuff, and
> suggested the tweak to pledge to allow access to /etc/protocols using
> the dns pledge. tcp and udp are still special though, and are still
> omgoptimised.
> 
> all this together lets the program at
> https://mild.embarrassm.net/~dlg/diff/egred.c work. it is a userland
> reimplementation of a simplified egre(4) using tap(4) and a gre socket.
> the io path is literally reading from one fd and writing it to the othe,
> everything else is boilerplate.
> 
> i suspect the kernel stuff is a bit rough as i havent had to test every
> path, but it supports common functionality.
> 
> thoughts? i am pretty pleased with this has turned out, and would be
> keen to put it in the tree and work on it some more.
> 
> * https://tools.ietf.org/html/draft-foschiano-erspan-03
> ** http://vger.kernel.org/lpc_net2018_talks/erspan-linux-presentation.pdf
> 
> Index: etc/services
> ===
> RCS file: /cvs/src/etc/services,v
> retrieving revision 1.96
> diff -u -p -r1.96 services
> --- etc/services  27 Jan 2019 20:35:06 -  1.96
> +++ etc/services  29 Oct 2019 07:57:44 -
> @@ -332,6 +332,21 @@ spamd-cfg8026/tcp# 
> spamd(8) configur
>  dhcpd-sync   8067/udp# dhcpd(8) synchronisation
>  hunt 26740/udp   # hunt(6)
>  #
> +# GRE Protocol Types
> +#
> +keepalive0/gre   # 0x: IP tunnel keepalive
> +ipv4 2048/gre# 0x0800: IPv4
> +nhrp 8193/gre# 0x2001: Next Hop Resolution 
> Protocol
> +erspan3  8939/gre# 0x22eb: ERSPAN III
> +transether   25944/gre   ethernet# 0x6558: Trans Ether Bridging
> +ipv6 34525/gre   # 0x86dd: IPv6
> +wccp 34878/gre   # 0x883e: Web Content Cache 
> Protocol
> +mpls 34887/gre   # 0x8847: MPLS
> +#mpls34888/gre   # 0x8848: MPLS Multicast
> +erspan   35006/gre   erspan2 # 0x88be: ERSPAN I/II
> +nsh  35151/gre   # 0x894f: Network Service Header
> +control  47082/gre   # 0xb7ea: RFC 8157
> +#
>  # Appletalk
>  #
>  rtmp 1/ddp   # Routing Table Maintenance 
> Protocol
> Index: lib/libc/asr/getaddrinfo_async.c
> ===
> RCS file: /cvs/src/lib/libc/asr/getaddrinfo_as

GRE datagram socket support

2019-10-29 Thread David Gwynne
i've been toying with this idea of implementing GRE as a datagram
protocol that userland can use just like UDP. the idea is to make it
easy to support the implementation of NHRP in userland for mgre(4),
and also for ERSPAN* support without going down the path linux took**.

so this is the result of having a go at implementing the idea. the diff
includes several independent parts, but they all work together to make
GRE as comfortable to use as UDP. the two main parts are the actual
protocol implementation in src/sys/netinet/ip_gre.c, and the tweaks to
getaddrinfo to allow the resolution of gre services. the /etc/services
chunk gets used by the getaddrinfo bits.

so, the first chunk lets you do this (as root in userland):

int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_GRE);

that gives you a file descriptor you can then use with bind(),
connect(), sendto(), recvfrom(), etc. you write a message to the
kernel and it prepends the GRE and IP headers and pushes it out.
it is set up so the GRE protocol is handed to the kernel via the
sin_port or sin6_port member of struct sockaddr_in an sockaddr_in6
respectively. there's no source and destination protocol fields, just
one that both ends agree on, so if you connect then bind, your
sockaddrs have to agree on the proto. unfortunately there's no such
thing as a wildcard or reserved protocol in GRE, so 0 can't be used
as a wildcard like it can in udp and tcp.

the sockets support the configuration of optional GRE headers, as
defined in RFC 2890, using setsockopt. importantly you can enable
the key and sequence number headers, which again, the kernel offloads
for you.

the second chunk tweaks getaddrinfo so it lets you specify things other
than IPPROTO_UDP and IPPROTO_TCP. protocols other than those are now
looked up in /etc/protocols to get their name, which in turn is used to
look up entries in /etc/services. while i was there and reading rfcs, i
noted different behaviour for wildcarded socktypes and protocols, which
i've tried to implement. eric@ seems generally ok with this stuff, and
suggested the tweak to pledge to allow access to /etc/protocols using
the dns pledge. tcp and udp are still special though, and are still
omgoptimised.

all this together lets the program at
https://mild.embarrassm.net/~dlg/diff/egred.c work. it is a userland
reimplementation of a simplified egre(4) using tap(4) and a gre socket.
the io path is literally reading from one fd and writing it to the othe,
everything else is boilerplate.

i suspect the kernel stuff is a bit rough as i havent had to test every
path, but it supports common functionality.

thoughts? i am pretty pleased with this has turned out, and would be
keen to put it in the tree and work on it some more.

* https://tools.ietf.org/html/draft-foschiano-erspan-03
** http://vger.kernel.org/lpc_net2018_talks/erspan-linux-presentation.pdf

Index: etc/services
===
RCS file: /cvs/src/etc/services,v
retrieving revision 1.96
diff -u -p -r1.96 services
--- etc/services27 Jan 2019 20:35:06 -  1.96
+++ etc/services29 Oct 2019 07:57:44 -
@@ -332,6 +332,21 @@ spamd-cfg  8026/tcp# spamd(8) 
configur
 dhcpd-sync 8067/udp# dhcpd(8) synchronisation
 hunt   26740/udp   # hunt(6)
 #
+# GRE Protocol Types
+#
+keepalive  0/gre   # 0x: IP tunnel keepalive
+ipv4   2048/gre# 0x0800: IPv4
+nhrp   8193/gre# 0x2001: Next Hop Resolution 
Protocol
+erspan38939/gre# 0x22eb: ERSPAN III
+transether 25944/gre   ethernet# 0x6558: Trans Ether Bridging
+ipv6   34525/gre   # 0x86dd: IPv6
+wccp   34878/gre   # 0x883e: Web Content Cache 
Protocol
+mpls   34887/gre   # 0x8847: MPLS
+#mpls  34888/gre   # 0x8848: MPLS Multicast
+erspan 35006/gre   erspan2 # 0x88be: ERSPAN I/II
+nsh35151/gre   # 0x894f: Network Service Header
+control47082/gre   # 0xb7ea: RFC 8157
+#
 # Appletalk
 #
 rtmp   1/ddp   # Routing Table Maintenance 
Protocol
Index: lib/libc/asr/getaddrinfo_async.c
===
RCS file: /cvs/src/lib/libc/asr/getaddrinfo_async.c,v
retrieving revision 1.56
diff -u -p -r1.56 getaddrinfo_async.c
--- lib/libc/asr/getaddrinfo_async.c3 Nov 2018 09:13:24 -   1.56
+++ lib/libc/asr/getaddrinfo_async.c29 Oct 2019 07:57:54 -
@@ -34,36 +34,15 @@
 
 #include "asr_private.h"
 
-struct match {
-   int family;
-   int socktype;
-   int protocol;
-};
-
 static int getaddrinfo_async_run(struct asr_query *, struct asr_result *);
 static i