summaryrefslogtreecommitdiff
path: root/sys/netinet6
AgeCommit message (Collapse)Author
2024-07-04Implement IPv6 forwarding IPsec only.Alexander Bluhm
IPsec gateways set the forwarding sysctl to 2. While this worked for IPv4 since a long time, adapt this feature for IPv6 now. Set sysctl net.inet6.ip6.forwarding=2 to forward only packets that have been processed by IPsec. Set IPV6_FORWARDING_IPSEC in ip6_input() and pass the flag down to the call stack. This provides consistent view on global variable ip6_forwarding. In ip6_output() or ip6_forward() drop packets that do not match the policy. OK denis@
2024-06-20Read IPv6 forwarding value only once while processing a packet.Alexander Bluhm
IPv4 uses IP_FORWARDING to pass down a consistent value of net.inet.ip.forwarding down the stack. This is needed for unlocking sysctl. Do the same for IPv6. Read ip6_forwarding once in ip6_input_if() and pass down IPV6_FORWARDING as flags to ip6_ours(), ip6_hbhchcheck(), ip6_forward(). Replace the srcrt value with IPV6_REDIRECT flag for consistency with IPv4. To have common syntax with IPv4, use ip6_forwarding == 0 checks instead of !ip6_forwarding. This will also make it easier to implement net.inet6.ip6.forwarding=2 for IPsec only forwarding later. In nd6_ns_input() and nd6_na_input() read ip6_forwarding once and store it in i_am_router. The variable name has been chosen to avoid confusion with is_router, which indicates router flag of the packet. Reading of ip6_forwarding is done independently from ip6_input_if(), consistency does not really matter. One is for ND router behavior the other for forwarding. Again use the ip6_forwarding != 0 check, so when ip6_forwarding IPsec only value 2 gets implemented, it will behave like a router. OK deraadt@ sashan@ florian@ claudio@
2024-06-07Read IP forwarding variables only once.Alexander Bluhm
Do not assume that ip_forwarding and ip_directedbcast cannot change while processing one packet. Read it once and pass down its value with a flag. This is necessary for unlocking the sysctl path. There are a few places where a consistent value does not really matter, they are unchanged. Use a proper ip_ prefix for the global variable. OK claudio@
2024-06-07Fix slaac on P2P interfacesFlorian Obser
slaacd(8) can work on P2P interfaces, it will just never configure the destination address. But this works fine on at least pppoe(4) and tun(4). To make this less confusing pull ifra_dstaddr into dst6 or gw6 depending on if we are doing autoconf or not. I accidentally broke this when implementing rule 5.5 of RFC 6724. reported by & testing naddy OK bluhm
2024-06-07remove unused definesJonathan Gray
2024-05-21Inform user land when vltime / pltime changes.Florian Obser
Do not send a RTM_CHGADDRATTR route message when the address is tentative because we will send one when DAD finishes. To be used by rad(8) shortly. OK bluhm
2024-05-13remove prototypes with no matching functionJonathan Gray
ok mpi@
2024-05-08Fix route leak in ip input.Alexander Bluhm
In previous commit when refactoring the route cache, a rtfree() has been forgotten. For each forwarded packet the reference counter of the route entry was increased. This eventually leads to an integer overflow and triggers kassert. reported by and OK jan@
2024-04-21Implement rule 5.5 of RFC 6724 (Default Address Selection for IPv6)Florian Obser
Rule 5.5: Prefer addresses in a prefix advertised by the next-hop. For this we have to track the (link-local) address of the advertising router per interface address and compare it with the selected route. Rule 5.5 is useful in multi-homing setups where we have more than one prefix and default router. We have to use the source address with the correct default gateway otherwise traffic is likely going to be dropped because of BCP 38. While here refactor in6_update_ifa() a bit to make the code clearer and consistently use (var & flag) instead of (var & flag) != 0. Patiently reviewed by & OK bluhm.
2024-04-17Use struct ipsec_level within inpcb.Alexander Bluhm
Instead of passing around u_char[4], introduce struct ipsec_level that contains 4 ipsec levels. This provides better type safety. The embedding struct inpcb is globally visible for netstat(1), so put struct ipsec_level outside of #ifdef _KERNEL. OK deraadt@ mvs@
2024-04-17Revert previous, it breaks IPv6 on loopback interfaces.Florian Obser
Reported by bket & anton
2024-04-16Destination addresses make no sense on loopback interfaces.Florian Obser
While here use (variable & FLAG) or !(variable & FLAG) consistently in in6_update_ifa(). Discussed with claudio OK denis
2024-04-16Use route cache function in IP input.Alexander Bluhm
Instaed of passing a struct rtentry from ip_input() to ip_forward() and then embed it into a struct route for ip_output(), start with struct route and pass it along. Then the route cache is used consistently. Also the route cache hit and missed counters should reflect reality after this commit. There is a small difference in the code. in_ouraddr() checks for NULL and not rtisvalid(). Previous discussion showed that the route RTF_UP flag should only be considered for multipath routing. Otherwise it does not mean anything. Especially the local and broadcast check in in_ouraddr() should not be affected by interface link status. When doing cache lookups, route must be valid, but after rtalloc_mpath() lookup, use any route that route_mpath() returns. OK claudio@
2024-04-16Run raw IPv6 input in parallel.Alexander Bluhm
Get rip6_input() in the same shape as rip_input(). Call soisdisconnected() from rip6_disconnect(). This means that the raw IP socket cannot be reconnected later. Now raw IPv6 behaves like IPv4 in this regard, KAME code is quite inconsistent here. Also make sure that there is no race between disconnect, input and wakeup. The inpcb fileds inp_icmp6filt and inp_cksum6 are protected by exclusive net lock in icmp6_ctloutput(). With all that, mark raw IPv6 sockets to handle input in parallel. OK mvs@
2024-04-14Run raw IP input in parallel.Alexander Bluhm
Running raw IPv4 input with shared net lock in parallel is less complex than UDP. Especially there is no socket splicing. New ip_deliver() may run with shared or exclusive net lock. The last parameter indicates the mode. If is is running with shared netlock and encounters a protocol that needs exclusive lock, the packet is queued. Old ip_ours() always queued the packet. Now it calls ip_deliver() with shared net lock, and if that cannot handle the packet completely, the packet is queued and later processed with exclusive net lock. In case of an IPv6 header chain, that switches from shared to exclusive processing, the next protocol and mbuf offset are stored in a mbuf tag. OK mvs@
2024-04-12Split single TCP inpcb table into IPv4 and IPv6 parts.Alexander Bluhm
With two separate TCP hash tables, each one becomes smaller. When we remove the exclusive net lock from TCP, contention on internet PCB table mutex will be reduced. UDP has been split earlier into IPv4 and IPv6. Replace branch conditions based on INP_IPV6 with assertions. OK mvs@
2024-04-09Plug route leak in IP output.Alexander Bluhm
If no struct route is passed to ip_output() or ip6_output(), it uses its own iproute on the stack. In that case any route entry in the local route cache has to be freed. After pf decides to reroute, struct route is reset to NULL. Then the route reference counter has to be released. Call rtfree() without needless NULL check. OK mvs@
2024-04-06IP multicast sysctl mrtmfc must not write outside of allocation.Alexander Bluhm
Reading sysctl mrt_sysctl_mfc() allocates memory to be copied back to user. Chunks of struct mfcinfo are copied from routing table to linear heap memory. If the allocated memory was not a multiple the struct size, a struct mfcinfo could be copied to a partially unallocated destination. Check that the end of the struct is within the allocation. From Alfredo Ortega; OK claudio@
2024-03-31Combine route_cache() and rtalloc_mpath() in new route_mpath().Alexander Bluhm
Fill and check the cache and call rtalloc_mpath() together. Then the caller of route_mpath() does not have to care about the uint32_t *src pointer and just pass struct in_addr. All the conversions are done inside the functions. A previous version of this diff was backed out. There was an additional rtisvalid() in rtalloc_mpath() that prevented packet output via interfaces that were not up. Now the route in the cache has to be valid, but after new lookup, rtalloc_mpath() may return invalid routes. This generates less errors in userland an preserves existing behavior. OK sashan@
2024-03-26Additional length check for IPv6 reassembled fragments.Alexander Bluhm
FreeBSD-SA-23:06.ipv6 security advisory has added an additional overflow check in frag6_input(). OpenBSD is not affected by that as the bug was introduced by another change in 2019. The existing code is complicated and NetBSD has taken the FreeBSD fix, although they were also not affected. The additional check makes the complicated code more robust. Length calculation taken from NetBSD. Discussed with FreeBSD. OK sashan@ mvs@
2024-03-22Make local port which is bound during connect(2) unique per laddr.Alexander Bluhm
in_pcbconnect() did not pass down the address it got from in_pcbselsrc() to in_pcbpickport(). As a consequence local port numbers selected during connect(2) were globally unique although they belong to different addresses. This strict uniqueness is not necessary and wastes usable ports for outgoing connections. To solve this, pass ina from in_pcbconnect() to in_pcbbind_locked(). This does not interfere how wildcard sockets are matched with specific sockets during bind(2). It only allows non-wildcard sockets to share a local port during connect(2). OK mvs@ deraadt@
2024-02-29revert "Combine route_cache() and rtalloc_mpath() in new route_mpath()"Christian Weisgerber
It breaks NFS. ok claudio@
2024-02-28Cleanup IP input, forward, output.Alexander Bluhm
Before changing the routing code, get IPv4 and IPv6 input, forward, and output in a similar shape. Remove inconsistencies. OK claudio@
2024-02-27Combine route_cache() and rtalloc_mpath() in new route_mpath().Alexander Bluhm
Fill and check the cache and call rtalloc_mpath() together. Then the caller of route_mpath() does not have to care about the uint32_t *src pointer and just pass struct in_addr. All the conversions are done inside the functions. ro->ro_rt is either valid or NULL. Note that some places have a stricter rtisvalid() now compared to the previous NULL check. OK claudio@
2024-02-22Make the route cache aware of multipath routing.Alexander Bluhm
Pass source address to route_cache() and store it in struct route. Cached multipath routes are only valid if source address matches. If sysctl multipath changes, increase route generation number. OK claudio@
2024-02-14Hide struct ip6q, struct ip6asfrag, struct ip6_moptions,Claudio Jeker
struct ip6po_rhinfo and struct ip6_pktopts behind _KERNEL. The only bit userland may want from netinet6/ip6_var.h is struct ip6stat. The recent change to struct ip6po_rhinfo to use struct route resulted in various build failures in ports because code included netinet6/ip6_var.h without net/route.h. OK tb@ sthen@
2024-02-13Merge struct route and struct route_in6.Alexander Bluhm
Use a common struct route for both inet and inet6. Unfortunately struct sockaddr is shorter than sockaddr_in6, so netinet/in.h has to be exposed from net/route.h. Struct route has to be bsd visible for userland as netstat kvm code inspects inp_route. Internet PCB and TCP SYN cache can use a plain struct route now. All specific sockaddr types for inet and inet6 are embeded there. OK claudio@
2024-02-11Use `sb_mtx' instead of `inp_mtx' in receive path for inet sockets.Vitaliy Makkoveev
In soreceve(), we only touch `so_rcv' socket buffer, which has it's own `sb_mtx' mutex(9) for protection. So, we can avoid solock() in this path - it's enough to hold `sb_mtx' in soreceive() and around corresponding sbappend*(). But not right now :) This time we use shared netlock for some inet sockets in the soreceive() path. To protect `so_rcv' buffer we use `inp_mtx' mutex(9) and the pru_lock() to acquire this mutex(9) in socket layer. But the `inp_mtx' mutex belongs to the PCB. We initialize socket before PCB, tcp(4) sockets could exist without PCB, so use `sb_mtx' mutex(9) to protect sockbuf stuff. This diff mechanically replaces `inp_mtx' by `sb_mtx' in the receive path. Only for sockets which already use `inp_mtx'. All other sockets left as is. They will be converted later. Since the `sb_mtx' is optional, the new SB_MTXLOCK flag introduced. If this flag is set on `sb_flags', the `sb_mtx' mutex(9) should be taken. New sb_mtx_lock() and sb_mtx_unlock() was introduced to hide this check. They are temporary and will be replaced by mtx_enter() when all this area will be converted to `sb_mtx' mutex(9). Also, the new sbmtxassertlocked() function introduced to throw corresponding assertion for SB_MTXLOCK marked buffers. This time only sbappendaddr() calls it. This function is also temporary and will be replaced by MTX_ASSERT_LOCKED() later. ok bluhm
2024-02-11Remove include netinet6/ip6_var.h from netinet/in_pcb.h.Alexander Bluhm
OK mvs@
2024-02-09Route cache function returns hit or miss.Alexander Bluhm
The route_cache() function can easily return whether it was a cache hit or miss. Then the logic to perform a route lookup gets a bit simpler. Some more complicated if (ro->ro_rt == NULL) checks still exist elsewhere. Also use route cache in in_pcbselsrc() instead of filling struct route manually. OK claudio@
2024-02-07Use the route generation number also for IPv6.Alexander Bluhm
Implement route6_cache() to check whether the cached route is still valid and otherwise fill caching parameter of struct route_in6. Also count cache hits and misses in netstat. in_pcbrtentry() uses route cache now. OK claudio@
2024-02-05Add netstat counter for route cache.Alexander Bluhm
To optimize route caching, count cache hits and misses. This is shown in netstat -s for both inet and inet6. Reuse the old IPv6 forward cache counter. Sort ip6s_wrongif consistently. For now only IPv4 cache counter has been implemented. OK mvs@
2024-02-03Rework socket buffers locking for shared netlock.Vitaliy Makkoveev
Shared netlock is not sufficient to call so{r,w}wakeup(). The following sowakeup() modifies `sb_flags' and knote(9) stuff. Unfortunately, we can't call so{r,w}wakeup() with `inp_mtx' mutex(9) because sowakeup() also calls pgsigio() which grabs kernel lock. However, `so*_filtops' callbacks only perform read-only access to the socket stuff, so it is enough to hold shared netlock only, but the klist stuff needs to be protected. This diff introduces `sb_mtx' mutex(9) to protect sockbuf. This time `sb_mtx' used to protect only `sb_flags' and `sb_klist'. Now we have soassertlocked_readonly() and soassertlocked(). The first one is happy if only shared netlock is held, meanwhile the second wants `so_lock' or pru_lock() be held together with shared netlock. To keep soassertlocked*() assertions soft, we need to know mutex(9) state, so new mtx_owned() macro was introduces. Also, the new optional (*pru_locked)() handler brings the state of pru_lock(). Tests and ok from bluhm.
2024-01-31Add route generation number to route cache.Alexander Bluhm
The outgoing route is cached at the inpcb. This cache was only invalidated when the socket closes or if the route gets invalid. More specific routes were not detected. Especially with dynamic routing protocols, sockets must be closed and reopened to use the correct route. Running ping during a route change shows the problem. To solve this, add a route generation number that is updated whenever the routing table changes. The lookup in struct route is put into the route_cache() function. If the generation number is too old, the cached route gets discarded. Implement route_cache() for ip_output() and ip_forward() first. IPv6 and more places will follow. OK claudio@
2024-01-31Split in_pcbrtentry() and in6_pcbrtentry() based on INP_IPV6.Alexander Bluhm
Splitting the IPv6 code into a separate function results in less #ifdef INET6. Also struct route_in6 *ro in in6_pcbrtentry() is of the correct type and in_pcbrtentry() does not rely on the fact that inp_route and inp_route6 are pointers to the same union. OK kn@ claudio@
2024-01-28Use more specific sockaddr type for inpcb notify.Alexander Bluhm
in_pcbnotifyall() is an IPv4 only function. All callers check that sockaddr dst is in fact a sockaddr_in. Pass the more spcific type and remove the runtime check at beginning of in_pcbnotifyall(). Use const sockaddr_in in in_pcbnotifyall() and const sockaddr_in6 in6_pcbnotify() as dst parameter. OK millert@
2024-01-27Declare address parameter in TCP SYN cache const.Alexander Bluhm
tcp6_ctlinput() casted a constant sockaddr_sin6 to non-const sockaddr. sa6_src may be &sa6_any which lives in read-only data section. Better pass down the const addresses to syn_cache_lookup(). They are needed for hash lookup and are not modified. OK mvs@
2024-01-21Assert that inpcb table has correct address family.Alexander Bluhm
Since inpcb tables for UDP and Raw IP have been split into IPv4 and IPv6, assert that INP_IPV6 flag is correct instead of checking it. While there, give the table variable a nicer name. OK sashan@ mvs@
2024-01-18Move the rtable_exists() check into in_pcbset_rtableid().Claudio Jeker
OK bluhm@ mvs@
2024-01-11Use domain name for socket lock.Alexander Bluhm
Syzkaller with witness complains about lock ordering of pf lock with socket lock. Socket lock for inet is taken before pf lock. Pf lock is taken before socket lock for route. This is a false positive as route and inet socket locks are distinct. Witness does not know this. Name the socket lock like the domain of the socket, then rwlock name is used in witness lo_name subtype. Make domain names more consistent for locking, they were not used anyway. Regardless of witness problem, unique lock name for each socket type make sense. Reported-by: syzbot+34d22dcbf20d76629c5a@syzkaller.appspotmail.com Reported-by: syzbot+fde8d07ba74b69d0adfe@syzkaller.appspotmail.com OK mvs@
2024-01-09Convert some struct inpcb parameter to const pointer.Alexander Bluhm
OK millert@
2024-01-01Reduce code duplication in ip6 divert.Alexander Bluhm
Protocols like UDP or TCP keep only functions in netinet6 that are essentially different. Remove divert6_detach(), divert6_lock(), divert6_unlock(), divert6_bind(), and divert6_shutdown(). Replace them with identical IPv4 functions. INP_HDRINCL is an IPv4 only option, remove it from divert6_attach(). OK mvs@ sashan@ kn@
2023-12-15Use inpcb table mutex to set addresses.Alexander Bluhm
Protect all remaining write access to inp_faddr and inp_laddr with inpcb table mutex. Document inpcb locking for foreign and local address and port and routing table id. Reading will be made MP safe by adding per socket rw-locks in a next step. OK sashan@ mvs@
2023-12-07Inpcb table mutex protects addr and port during bind(2) and connect(2).Alexander Bluhm
in_pcbbind(), in_pcbconnect(), and in6_pcbconnect() have to set addresses and ports within the same critical section as the inpcb hash table calculation. Also lookup and address selection have to be protected to avoid bindings and connections that are not unique. For that in_pcbpickport() and in_pcbbind_locked() expect that the table mutex is already taken. The functions in_pcblookup_lock(), in_pcblookup_local_lock(), and in_pcbaddrisavail_lock() grab the mutex iff the lock parameter is IN_PCBLOCK_GRAB. Otherwise the parameter is IN_PCBLOCK_HOLD has the lock has to be taken already. Note that in_pcblookup_lock() and in_pcblookup_local() return an inp with increased reference iff they take and release the lock. Otherwise the caller protects the life time of the inp. This gives enough flexibility that in_pcbbind() and in_pcbconnect() can hold the table mutex when they need it. The public inpcb API does not change. OK sashan@ mvs@
2023-12-06Protect socket receive buffer in IP multicast routing.Alexander Bluhm
Since soreceive() runs in parallel for raw sockets, sbappendaddr() has to be protected by inpcb mutex. This was missing in multicast forwarding which is running with a combination of shared net lock and kernel lock. soreceive() uses shared net lock and mutex per inpcb. Grab mutex before sbappendaddr() in socket_send() and socket6_send(). panic receive 1 reported by Jo Geraerts OK mvs@ claudio@
2023-12-03Rename all in6p local variables to inp.Alexander Bluhm
There exists no struct in6pcb in OpenBSD, this was an old kame idea. Calling the local variable in6p does not make sense, it is actually a struct inpcb. Also in6p is not used consistently in inet6 code. Having the same convention for IPv4 and IPv6 is less confusing. OK sashan@ mvs@
2023-12-03Use INP_IPV6 flag instead of sotopf().Alexander Bluhm
During initialization in_pcballoc() sets INP_IPV6 once to avoid reaching through inp_socket->so_proto->pr_domain->dom_family. Use this flag consistently. OK sashan@ mvs@
2023-12-01Set inp address, port and rtable together with inpcb hash.Alexander Bluhm
The inpcb hash table is protected by table->inpt_mtx. The hash is based on addresses, ports, and routing table. These fields were not sychronized with the hash. Put writes and hash update into the same critical section. Move the updates from ip_ctloutput(), ip6_ctloutput(), syn_cache_get(), tcp_connect(), udp_disconnect() to dedicated inpcb set functions. There they use the same table mutex as in_pcbrehash(). in_pcbbind(), in_pcbconnect(), and in6_pcbconnect() need more work and are not included yet. OK sashan@ mvs@
2023-12-01Make internet PCB connect more consistent.Alexander Bluhm
The public interface is in_pcbconnect(). It dispatches to in6_pcbconnect() if necessary. Call the former from tcp_connect() and udp_connect(). In in6_pcbconnect() initialization in6a = NULL is not necessary. in6_pcbselsrc() sets the pointer, but does not read the value. Pass a constant in6_addr pointer to in6_pcbselsrc() and in6_selectsrc(). It returns a reference to the address of some internal data structure. We want to be sure that in6_addr is not modified this way. IPv4 in_pcbselsrc() solves this by passing a copy of the address. OK kn@ sashan@ mvs@
2023-11-29Document inp_socket as immutable and remove NULL checks.Alexander Bluhm
Struct inpcb field inp_socket is initialized in in_pcballoc(). It is not NULL and never changed. OK mvs@