aboutsummaryrefslogtreecommitdiffstats
path: root/src/if_wg.c (follow)
Commit message (Collapse)AuthorAgeFilesLines
* if_wg: don't double increment error counterJason A. Donenfeld2021-05-021-3/+1
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: ensure packet is not shared before writingJason A. Donenfeld2021-05-021-1/+16
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: don't memcpy data for no reasonJason A. Donenfeld2021-05-021-4/+2
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: pad packets properlyJason A. Donenfeld2021-05-021-11/+22
| | | | | | | This takes into account mismatched MTUs. Borrows the "calculate_skb_padding" function from Linux. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: return to m temporary variable styleJason A. Donenfeld2021-04-301-13/+18
| | | | | | | | | | | The rest of the code uses this, so go with it for now. Maybe later ncon will want to clean up everything to be this way, but for now keep it consistent. This partially reverts commit a1fdf6646b16ec26c741089102346f5455dc5fed, but doesn't reintroduce the bug that it had fixed. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: defragment mbufs early onJason A. Donenfeld2021-04-301-0/+16
| | | | | | | | | This makes the crypto a *lot* faster. We might later revert this if we use opencrypto's fancy page table mapping scheme. But for now, it's useful. We do it early, rather than before calling decrypt/encrypt, so that the various other m_pullups that we have wind up being no-ops. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: allocate entire mbuf all at onceJason A. Donenfeld2021-04-281-2/+1
| | | | | | | | Rather than making a tiny mbuf and then allocating another one in m_copyback, just make one larger one. These packets are generally pretty small anyway. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: do not double-free after m_pullupJason A. Donenfeld2021-04-281-18/+13
| | | | | | | | | Either m_pullup reallocates, in which case wg_packet_free winds up freeing something that's already been freed, or it fails and frees m, and then wg_packet_free tries to free it again. In both cases, massive memory corruption ensues. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: enter net epoch for isr dispatchJason A. Donenfeld2021-04-281-0/+3
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: write data header directlyJason A. Donenfeld2021-04-281-6/+5
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: do not block for memory when sending bufferJason A. Donenfeld2021-04-281-6/+11
| | | | | | | This can be called when locks are held in upper parts of the stack, resulting in witness splats. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: use proper bool for is_retryJason A. Donenfeld2021-04-281-5/+5
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: simplify state setting flowJason A. Donenfeld2021-04-281-26/+22
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: pull up packet before checking aip on inputJason A. Donenfeld2021-04-281-21/+16
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: unify xmit error pathJason A. Donenfeld2021-04-281-46/+54
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: do not assume that IP header is pulled upJason A. Donenfeld2021-04-271-17/+40
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: handle if_transmit and if_output properlyJason A. Donenfeld2021-04-271-23/+62
| | | | | | | | | | | | | | | | | The netmap code goes directly to if_transmit, which means it'll bypass if_output, in which case, there's no packet allocated. Also, we're relying on if_output's sockaddr structure to be legit, but who knows what types of userspace hijynxes can forge this. Rather than relying on that kind of black magic, determine the AF from the actual packet contents. But still insist that it agrees with the sockaddr. The extraction of the type from AF_UNSPEC follows the same pattern as if_gif and if_gre. We also use this as an opportunity to send icmp error messages in the right place. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: do not increment error counter when sc is nullJason A. Donenfeld2021-04-251-4/+7
| | | | | | If sc is null, jumping to increment the counter means crash. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: count on peers always having a remoteJason A. Donenfeld2021-04-241-5/+1
| | | | | | | We do a pretty nasty hack in the allowedips selftest to avoid having to allocate more memory. Seems to work. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: ensure peer lifetimeMatt Dunwoodie2021-04-251-39/+86
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The peer (and keypair and local) lifecycle are managed through EPOCH and refcounts. Primarily this is used in wg_noise to keep track of active keypairs, however we can also use it to be sure no more peer references exist. The structures are linked as such, so noise_remote cannot be freed until all noise_keypairs are freed, and noise_local cannot be freed until all noise_remotes are freed. noise_keypair -> noise_remote -> noise_local Therefore, if you hold a keypair reference you can be sure that remote and local will still be around. There are three main ways peers are referenced: 1) Incoming packets 1.a) Incoming handshake packets are passed to noise_consume_*, which will (on success) return a refcounted remote which is dropped at the end of wg_handshake. 1.b) Incoming cookie packets will have their index looked which will (on success) return a refcounted remote, which is also dropped at the end of wg_handshake. 1.c) Incoming data packets will have their index looked up which will (on success) return a refcounted keypair. This keypair will be dropped after the packet has been passed up the network stack, or otherwise freed. 2) Outgoing data packets 2.a) Outgoing data packets are first looked up by wg_aip_lookup, which returns a peer pointer, with an incremented remote refcount. This is then dropped in wg_transmit after adding the packet to the staged queue and sending the staged queue. 2.b) Packets in the staged queue do not hold any refcount for the remote or keypair, because they do not reference the peer in any way, they are just in the queue. 2.c) Packets finally get a refcoutned keypair in wg_peer_send_staged, which is dropped after the packet is sent out the UDP socket, or otherwise freed. 3) wg_timers system 3.a) The wg_timers system holds a reference to the peer whenever a callout is scheduled. Instead of holding a refcount, we instead disable the peer's timers, such that no callouts can be scheduled. Some rationale for changes here: We move the p_{send,recv} taskqgroup_detach into peer_free_deferred as they will NULL fields in p_{send,recv}. If there are packets being processed in wg_{en,de}crypt, then a call tou GROUPTASK_ENQUEUE will dereference a NULL pointer. In general, we remove all references to the peer in wg_peer_destroy, and free/deinit all the peer members once no more references to the remote exist, in wg_peer_free_deferred. Currently we take a refcount in wg_aip_lookup, which is to be sure that the peer reference is valid for the entirety of wg_transmit. We do not care about the refcount in wg_decrypt. It might be worth considering storing the remote pointer in the allowedip entry, but it could be argued both ways. For the time being, this is still correct. We don't have a refcount for the peer stored in the allowedip table, as it is protected by the table lock. One note here is the NULL p_remote check is necessary to support selftest/allowedips.c, which does not specify a p_remote. If we update the tests, then we may remove this check. There are two added p_enabled checks, in run_retry_handshake and run_send_keepalive. This is to align them with the other callout_reset calls. In the case of p_zero_key_material, if we have set p_enabled = false, then we subsequently clear keypairs and handshakes (on wg_down), or we free the peer which will clear the keypairs for us. We want to hold a refcount of remote in wg_{en,de}crypt to ensure that the peer is still valid in the call to GROUPTASK_ENQUEUE. If we don't then peer may become invalid after setting p_state. Another thread may take the packet, put the keypair refcount and free the peer prior to the call to GROUPTASK_ENQUEUE. We no longer need to hold (haven't for a while) the EPOCH in wg_send_initiation and wg_send_response, as we hold valid references for the duration. This could be either a refcount of a remote or through the wg_timers system as described above. We also fix some refcount leaks in wgc_set. Notes: We may want to pull NET_EPOCH_WAIT out of wg_timers_disable, to improve performance. However, we can destroy 20000 peers in less than 20ms so the performance is not critical for this snapshot and can be addressed later. Finally, there is the special case of noise_remote_arg, which stores the corresponding peer pointer. The peer is not refcounted however it will have the same scope as the remote. In otherwords it is valid until we call noise_remote_put on the remote. Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* if_wg: zero out remaining mallocsJason A. Donenfeld2021-04-221-4/+4
| | | | | | | We might add locks and things later. Mainly it doesn't cost much and makes things easier/safer to reason about. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: remove M_WAITOK, check return codes on initMatt Dunwoodie2021-04-231-67/+90
| | | | | | | | | | | | | | | Here we remove all M_WAITOK checks, because we don't want to hang while trying to allocate memory. It is better to return an error so the user can try again later. We also make sure to check all the return codes in peer and interface allocation. The structure of those functions is: 1) Allocate all memory 2) Initialise fields in order of the struct 3) Cleanup gotos Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* if_wg: check wg_module_init succeededMatt Dunwoodie2021-04-231-9/+15
| | | | Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* if_wg: set snd_tag to NULL after releasingJason A. Donenfeld2021-04-221-1/+3
| | | | | | The rest of the stack does this. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: destroy interfaces on module unloadJason A. Donenfeld2021-04-221-10/+4
| | | | | | This is already done anyway by if_clone_detach, so let that happen. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* wg_cookie: hash vnet into ratelimiter entryJason A. Donenfeld2021-04-221-2/+4
| | | | | | IPs mean different things per-vnet. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: properly use rn_inithead and rn_detachheadJason A. Donenfeld2021-04-221-21/+22
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* wg_cookie: make ratelimiter globalMatt Dunwoodie2021-04-231-6/+4
| | | | Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* if_wg: add more usual string concat spacingJason A. Donenfeld2021-04-221-14/+14
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: correct logic in tag clearingJason A. Donenfeld2021-04-221-1/+1
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* global: add missing bracketsJason A. Donenfeld2021-04-221-1/+2
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: more thorough wg_mbuf_resetMatt Dunwoodie2021-04-221-6/+36
| | | | Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* if_wg: better loop detectionMatt Dunwoodie2021-04-221-3/+4
| | | | | | | | | | | | | While it was nice to have per peer loop detection, it was not meant to be. The loop tag has a tag type == 0, which conflicts with other tags. Therefore we want to at least be a little bit more sure that the tag cookie is unique to the loop tag. I guess the peer address was also quite hacky so on the other side, I'm glad to be rid of that. Now we have a loop of 8 (to any peer) which should be good enough for an edge case operation. Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* wg_noise: add selftestMatt Dunwoodie2021-04-221-0/+1
| | | | Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* wg_cookie: add selftestMatt Dunwoodie2021-04-221-0/+1
| | | | Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* if_wg: port allowedips selftest from Linux code and fix bugsJason A. Donenfeld2021-04-221-64/+65
| | | | | | | And then fix broken allowedips implementation for the static unit tests to pass. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* global: update timer-type commentsJason A. Donenfeld2021-04-201-1/+1
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* global: use ck for loads/stores, rather than macro mazeJason A. Donenfeld2021-04-201-23/+23
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* global: use sbintime_t consistentlyJason A. Donenfeld2021-04-201-11/+9
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: minor code cleanup, improve readabilityMatt Dunwoodie2021-04-211-69/+75
| | | | | | | | | | | Nothing serious here, just use a goto in wg_deliver_{in,out} rather than another if/else indentation. The code should have no functional change, just improve readability. Additionally, use a local `sc` variable rather than `peer->p_sc` in spots. Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* global: use proper boolean typesJason A. Donenfeld2021-04-201-18/+21
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* wg_noise: ensure we check peer count on hashtable insertMatt Dunwoodie2021-04-211-1/+2
| | | | Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* wg_noise: avoid handshake/keypair type confusionMatt Dunwoodie2021-04-201-1/+1
| | | | | | | | | | | | | | | | | | | | So the last change broke consuming responses, as it may return an invalid remote pointer. Thanks for the catch zx2c4. We just pass a flag "lookup_keypair" which will lookup the keypair when we want (for cookie) and will not when we don't (for consuming responses). It would be possible to merge both noise_remote_index_lookup and noise_keypair_lookup, but the result would probably need to return a void * (for both keypair and remote) or a noise_index * which would need to be cast to the relevant type somewhere. The trickiest thing here would be for if_wg to "put" the result of the function, as it may be a remote or a keypair (which store their refcount in different locations). Perhaps it would return a noise_index * which could contain the refcount for both keypair and remote. It all seems easier to leave them separate. The only argument for combining them would be to reduce duplication of (similar) functions. Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* wg_noise: insert/remove peer independent of alloc/destroyMatt Dunwoodie2021-04-201-13/+16
| | | | | | | | | This is needed, to remove the peer from the public key hashtable before calling noise_remote_destroy. This will prevent any incoming handshakes from starting in that time. It also cleans up the insert path to make it more like it was before the wg_noise EPOCH changes. Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* if_wg: remove unused loadMatt Dunwoodie2021-04-201-1/+0
| | | | Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* wg_noise: check keypair recvwith after nonceMatt Dunwoodie2021-04-201-9/+5
| | | | Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* wg_noise: lookup both keypair and handshake index at onceMatt Dunwoodie2021-04-201-7/+2
| | | | Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
* if_wg: add missing return parens to follow style(9)Jason A. Donenfeld2021-04-191-25/+25
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: allow v4 xor v6 socket binding to fail with EADDRNOTAVAILJason A. Donenfeld2021-04-191-21/+40
| | | | | | | | | | | This happens if a jail does not have an interface with a configured v4 or v6 address. In that case, we just fall back to only having one socket for the address family that does exist. In the case that neither socket can be created, fail as before. Closes: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254212 Reported-by: Mark Johnston <markj@FreeBSD.org> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* if_wg: fixup wg_mbuf_resetMatt Dunwoodie2021-04-191-2/+0
| | | | | | | Zeroing these values broke TCP recv, so not great, just remove them and hope they don't store anything secret. Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>