Commit 53cb0995 authored by David S. Miller's avatar David S. Miller

Merge branch 'wireguard-fixes'

Jason A. Donenfeld says:

====================
wireguard fixes for 5.7-rc7

Hopefully these are the last fixes for 5.7:

1) A trivial bump in the selftest harness to support gcc-10.
   build.wireguard.com is still on gcc-9 but I'll probably switch to
   gcc-10 in the coming weeks.

2) A concurrency fix regarding userspace modifying the pre-shared key at
   the same time as packets are being processed, reported by Matt
   Dunwoodie.

3) We were previously clearing skb->hash on egress, which broke
   fq_codel, cake, and other things that actually make use of the flow
   hash for queueing, reported by Dave Taht and Toke Høiland-Jørgensen.

4) A fix for the increased memory usage caused by (3). This can be
   thought of as part of patch (3), but because of the separate
   reasoning and breadth of it I thought made it a bit cleaner to put in
   a standalone commit.

Fixes (2), (3), and (4) are -stable material.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 20a785aa a9e90d99
...@@ -32,7 +32,7 @@ enum cookie_values { ...@@ -32,7 +32,7 @@ enum cookie_values {
}; };
enum counter_values { enum counter_values {
COUNTER_BITS_TOTAL = 2048, COUNTER_BITS_TOTAL = 8192,
COUNTER_REDUNDANT_BITS = BITS_PER_LONG, COUNTER_REDUNDANT_BITS = BITS_PER_LONG,
COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS
}; };
......
...@@ -104,6 +104,7 @@ static struct noise_keypair *keypair_create(struct wg_peer *peer) ...@@ -104,6 +104,7 @@ static struct noise_keypair *keypair_create(struct wg_peer *peer)
if (unlikely(!keypair)) if (unlikely(!keypair))
return NULL; return NULL;
spin_lock_init(&keypair->receiving_counter.lock);
keypair->internal_id = atomic64_inc_return(&keypair_counter); keypair->internal_id = atomic64_inc_return(&keypair_counter);
keypair->entry.type = INDEX_HASHTABLE_KEYPAIR; keypair->entry.type = INDEX_HASHTABLE_KEYPAIR;
keypair->entry.peer = peer; keypair->entry.peer = peer;
...@@ -358,25 +359,16 @@ static void kdf(u8 *first_dst, u8 *second_dst, u8 *third_dst, const u8 *data, ...@@ -358,25 +359,16 @@ static void kdf(u8 *first_dst, u8 *second_dst, u8 *third_dst, const u8 *data,
memzero_explicit(output, BLAKE2S_HASH_SIZE + 1); memzero_explicit(output, BLAKE2S_HASH_SIZE + 1);
} }
static void symmetric_key_init(struct noise_symmetric_key *key)
{
spin_lock_init(&key->counter.receive.lock);
atomic64_set(&key->counter.counter, 0);
memset(key->counter.receive.backtrack, 0,
sizeof(key->counter.receive.backtrack));
key->birthdate = ktime_get_coarse_boottime_ns();
key->is_valid = true;
}
static void derive_keys(struct noise_symmetric_key *first_dst, static void derive_keys(struct noise_symmetric_key *first_dst,
struct noise_symmetric_key *second_dst, struct noise_symmetric_key *second_dst,
const u8 chaining_key[NOISE_HASH_LEN]) const u8 chaining_key[NOISE_HASH_LEN])
{ {
u64 birthdate = ktime_get_coarse_boottime_ns();
kdf(first_dst->key, second_dst->key, NULL, NULL, kdf(first_dst->key, second_dst->key, NULL, NULL,
NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0, NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0,
chaining_key); chaining_key);
symmetric_key_init(first_dst); first_dst->birthdate = second_dst->birthdate = birthdate;
symmetric_key_init(second_dst); first_dst->is_valid = second_dst->is_valid = true;
} }
static bool __must_check mix_dh(u8 chaining_key[NOISE_HASH_LEN], static bool __must_check mix_dh(u8 chaining_key[NOISE_HASH_LEN],
...@@ -715,6 +707,7 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src, ...@@ -715,6 +707,7 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src,
u8 e[NOISE_PUBLIC_KEY_LEN]; u8 e[NOISE_PUBLIC_KEY_LEN];
u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN]; u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN];
u8 static_private[NOISE_PUBLIC_KEY_LEN]; u8 static_private[NOISE_PUBLIC_KEY_LEN];
u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN];
down_read(&wg->static_identity.lock); down_read(&wg->static_identity.lock);
...@@ -733,6 +726,8 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src, ...@@ -733,6 +726,8 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src,
memcpy(chaining_key, handshake->chaining_key, NOISE_HASH_LEN); memcpy(chaining_key, handshake->chaining_key, NOISE_HASH_LEN);
memcpy(ephemeral_private, handshake->ephemeral_private, memcpy(ephemeral_private, handshake->ephemeral_private,
NOISE_PUBLIC_KEY_LEN); NOISE_PUBLIC_KEY_LEN);
memcpy(preshared_key, handshake->preshared_key,
NOISE_SYMMETRIC_KEY_LEN);
up_read(&handshake->lock); up_read(&handshake->lock);
if (state != HANDSHAKE_CREATED_INITIATION) if (state != HANDSHAKE_CREATED_INITIATION)
...@@ -750,7 +745,7 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src, ...@@ -750,7 +745,7 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src,
goto fail; goto fail;
/* psk */ /* psk */
mix_psk(chaining_key, hash, key, handshake->preshared_key); mix_psk(chaining_key, hash, key, preshared_key);
/* {} */ /* {} */
if (!message_decrypt(NULL, src->encrypted_nothing, if (!message_decrypt(NULL, src->encrypted_nothing,
...@@ -783,6 +778,7 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src, ...@@ -783,6 +778,7 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src,
memzero_explicit(chaining_key, NOISE_HASH_LEN); memzero_explicit(chaining_key, NOISE_HASH_LEN);
memzero_explicit(ephemeral_private, NOISE_PUBLIC_KEY_LEN); memzero_explicit(ephemeral_private, NOISE_PUBLIC_KEY_LEN);
memzero_explicit(static_private, NOISE_PUBLIC_KEY_LEN); memzero_explicit(static_private, NOISE_PUBLIC_KEY_LEN);
memzero_explicit(preshared_key, NOISE_SYMMETRIC_KEY_LEN);
up_read(&wg->static_identity.lock); up_read(&wg->static_identity.lock);
return ret_peer; return ret_peer;
} }
......
...@@ -15,18 +15,14 @@ ...@@ -15,18 +15,14 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/kref.h> #include <linux/kref.h>
union noise_counter { struct noise_replay_counter {
struct {
u64 counter; u64 counter;
unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG];
spinlock_t lock; spinlock_t lock;
} receive; unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG];
atomic64_t counter;
}; };
struct noise_symmetric_key { struct noise_symmetric_key {
u8 key[NOISE_SYMMETRIC_KEY_LEN]; u8 key[NOISE_SYMMETRIC_KEY_LEN];
union noise_counter counter;
u64 birthdate; u64 birthdate;
bool is_valid; bool is_valid;
}; };
...@@ -34,7 +30,9 @@ struct noise_symmetric_key { ...@@ -34,7 +30,9 @@ struct noise_symmetric_key {
struct noise_keypair { struct noise_keypair {
struct index_hashtable_entry entry; struct index_hashtable_entry entry;
struct noise_symmetric_key sending; struct noise_symmetric_key sending;
atomic64_t sending_counter;
struct noise_symmetric_key receiving; struct noise_symmetric_key receiving;
struct noise_replay_counter receiving_counter;
__le32 remote_index; __le32 remote_index;
bool i_am_the_initiator; bool i_am_the_initiator;
struct kref refcount; struct kref refcount;
......
...@@ -87,12 +87,20 @@ static inline bool wg_check_packet_protocol(struct sk_buff *skb) ...@@ -87,12 +87,20 @@ static inline bool wg_check_packet_protocol(struct sk_buff *skb)
return real_protocol && skb->protocol == real_protocol; return real_protocol && skb->protocol == real_protocol;
} }
static inline void wg_reset_packet(struct sk_buff *skb) static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating)
{ {
u8 l4_hash = skb->l4_hash;
u8 sw_hash = skb->sw_hash;
u32 hash = skb->hash;
skb_scrub_packet(skb, true); skb_scrub_packet(skb, true);
memset(&skb->headers_start, 0, memset(&skb->headers_start, 0,
offsetof(struct sk_buff, headers_end) - offsetof(struct sk_buff, headers_end) -
offsetof(struct sk_buff, headers_start)); offsetof(struct sk_buff, headers_start));
if (encapsulating) {
skb->l4_hash = l4_hash;
skb->sw_hash = sw_hash;
skb->hash = hash;
}
skb->queue_mapping = 0; skb->queue_mapping = 0;
skb->nohdr = 0; skb->nohdr = 0;
skb->peeked = 0; skb->peeked = 0;
......
...@@ -245,20 +245,20 @@ static void keep_key_fresh(struct wg_peer *peer) ...@@ -245,20 +245,20 @@ static void keep_key_fresh(struct wg_peer *peer)
} }
} }
static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key) static bool decrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair)
{ {
struct scatterlist sg[MAX_SKB_FRAGS + 8]; struct scatterlist sg[MAX_SKB_FRAGS + 8];
struct sk_buff *trailer; struct sk_buff *trailer;
unsigned int offset; unsigned int offset;
int num_frags; int num_frags;
if (unlikely(!key)) if (unlikely(!keypair))
return false; return false;
if (unlikely(!READ_ONCE(key->is_valid) || if (unlikely(!READ_ONCE(keypair->receiving.is_valid) ||
wg_birthdate_has_expired(key->birthdate, REJECT_AFTER_TIME) || wg_birthdate_has_expired(keypair->receiving.birthdate, REJECT_AFTER_TIME) ||
key->counter.receive.counter >= REJECT_AFTER_MESSAGES)) { keypair->receiving_counter.counter >= REJECT_AFTER_MESSAGES)) {
WRITE_ONCE(key->is_valid, false); WRITE_ONCE(keypair->receiving.is_valid, false);
return false; return false;
} }
...@@ -283,7 +283,7 @@ static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key) ...@@ -283,7 +283,7 @@ static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key)
if (!chacha20poly1305_decrypt_sg_inplace(sg, skb->len, NULL, 0, if (!chacha20poly1305_decrypt_sg_inplace(sg, skb->len, NULL, 0,
PACKET_CB(skb)->nonce, PACKET_CB(skb)->nonce,
key->key)) keypair->receiving.key))
return false; return false;
/* Another ugly situation of pushing and pulling the header so as to /* Another ugly situation of pushing and pulling the header so as to
...@@ -298,41 +298,41 @@ static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key) ...@@ -298,41 +298,41 @@ static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key)
} }
/* This is RFC6479, a replay detection bitmap algorithm that avoids bitshifts */ /* This is RFC6479, a replay detection bitmap algorithm that avoids bitshifts */
static bool counter_validate(union noise_counter *counter, u64 their_counter) static bool counter_validate(struct noise_replay_counter *counter, u64 their_counter)
{ {
unsigned long index, index_current, top, i; unsigned long index, index_current, top, i;
bool ret = false; bool ret = false;
spin_lock_bh(&counter->receive.lock); spin_lock_bh(&counter->lock);
if (unlikely(counter->receive.counter >= REJECT_AFTER_MESSAGES + 1 || if (unlikely(counter->counter >= REJECT_AFTER_MESSAGES + 1 ||
their_counter >= REJECT_AFTER_MESSAGES)) their_counter >= REJECT_AFTER_MESSAGES))
goto out; goto out;
++their_counter; ++their_counter;
if (unlikely((COUNTER_WINDOW_SIZE + their_counter) < if (unlikely((COUNTER_WINDOW_SIZE + their_counter) <
counter->receive.counter)) counter->counter))
goto out; goto out;
index = their_counter >> ilog2(BITS_PER_LONG); index = their_counter >> ilog2(BITS_PER_LONG);
if (likely(their_counter > counter->receive.counter)) { if (likely(their_counter > counter->counter)) {
index_current = counter->receive.counter >> ilog2(BITS_PER_LONG); index_current = counter->counter >> ilog2(BITS_PER_LONG);
top = min_t(unsigned long, index - index_current, top = min_t(unsigned long, index - index_current,
COUNTER_BITS_TOTAL / BITS_PER_LONG); COUNTER_BITS_TOTAL / BITS_PER_LONG);
for (i = 1; i <= top; ++i) for (i = 1; i <= top; ++i)
counter->receive.backtrack[(i + index_current) & counter->backtrack[(i + index_current) &
((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0; ((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0;
counter->receive.counter = their_counter; counter->counter = their_counter;
} }
index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1; index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1;
ret = !test_and_set_bit(their_counter & (BITS_PER_LONG - 1), ret = !test_and_set_bit(their_counter & (BITS_PER_LONG - 1),
&counter->receive.backtrack[index]); &counter->backtrack[index]);
out: out:
spin_unlock_bh(&counter->receive.lock); spin_unlock_bh(&counter->lock);
return ret; return ret;
} }
...@@ -472,19 +472,19 @@ int wg_packet_rx_poll(struct napi_struct *napi, int budget) ...@@ -472,19 +472,19 @@ int wg_packet_rx_poll(struct napi_struct *napi, int budget)
if (unlikely(state != PACKET_STATE_CRYPTED)) if (unlikely(state != PACKET_STATE_CRYPTED))
goto next; goto next;
if (unlikely(!counter_validate(&keypair->receiving.counter, if (unlikely(!counter_validate(&keypair->receiving_counter,
PACKET_CB(skb)->nonce))) { PACKET_CB(skb)->nonce))) {
net_dbg_ratelimited("%s: Packet has invalid nonce %llu (max %llu)\n", net_dbg_ratelimited("%s: Packet has invalid nonce %llu (max %llu)\n",
peer->device->dev->name, peer->device->dev->name,
PACKET_CB(skb)->nonce, PACKET_CB(skb)->nonce,
keypair->receiving.counter.receive.counter); keypair->receiving_counter.counter);
goto next; goto next;
} }
if (unlikely(wg_socket_endpoint_from_skb(&endpoint, skb))) if (unlikely(wg_socket_endpoint_from_skb(&endpoint, skb)))
goto next; goto next;
wg_reset_packet(skb); wg_reset_packet(skb, false);
wg_packet_consume_data_done(peer, skb, &endpoint); wg_packet_consume_data_done(peer, skb, &endpoint);
free = false; free = false;
...@@ -511,8 +511,8 @@ void wg_packet_decrypt_worker(struct work_struct *work) ...@@ -511,8 +511,8 @@ void wg_packet_decrypt_worker(struct work_struct *work)
struct sk_buff *skb; struct sk_buff *skb;
while ((skb = ptr_ring_consume_bh(&queue->ring)) != NULL) { while ((skb = ptr_ring_consume_bh(&queue->ring)) != NULL) {
enum packet_state state = likely(decrypt_packet(skb, enum packet_state state =
&PACKET_CB(skb)->keypair->receiving)) ? likely(decrypt_packet(skb, PACKET_CB(skb)->keypair)) ?
PACKET_STATE_CRYPTED : PACKET_STATE_DEAD; PACKET_STATE_CRYPTED : PACKET_STATE_DEAD;
wg_queue_enqueue_per_peer_napi(skb, state); wg_queue_enqueue_per_peer_napi(skb, state);
if (need_resched()) if (need_resched())
......
...@@ -6,18 +6,24 @@ ...@@ -6,18 +6,24 @@
#ifdef DEBUG #ifdef DEBUG
bool __init wg_packet_counter_selftest(void) bool __init wg_packet_counter_selftest(void)
{ {
struct noise_replay_counter *counter;
unsigned int test_num = 0, i; unsigned int test_num = 0, i;
union noise_counter counter;
bool success = true; bool success = true;
counter = kmalloc(sizeof(*counter), GFP_KERNEL);
if (unlikely(!counter)) {
pr_err("nonce counter self-test malloc: FAIL\n");
return false;
}
#define T_INIT do { \ #define T_INIT do { \
memset(&counter, 0, sizeof(union noise_counter)); \ memset(counter, 0, sizeof(*counter)); \
spin_lock_init(&counter.receive.lock); \ spin_lock_init(&counter->lock); \
} while (0) } while (0)
#define T_LIM (COUNTER_WINDOW_SIZE + 1) #define T_LIM (COUNTER_WINDOW_SIZE + 1)
#define T(n, v) do { \ #define T(n, v) do { \
++test_num; \ ++test_num; \
if (counter_validate(&counter, n) != (v)) { \ if (counter_validate(counter, n) != (v)) { \
pr_err("nonce counter self-test %u: FAIL\n", \ pr_err("nonce counter self-test %u: FAIL\n", \
test_num); \ test_num); \
success = false; \ success = false; \
...@@ -99,6 +105,7 @@ bool __init wg_packet_counter_selftest(void) ...@@ -99,6 +105,7 @@ bool __init wg_packet_counter_selftest(void)
if (success) if (success)
pr_info("nonce counter self-tests: pass\n"); pr_info("nonce counter self-tests: pass\n");
kfree(counter);
return success; return success;
} }
#endif #endif
...@@ -129,7 +129,7 @@ static void keep_key_fresh(struct wg_peer *peer) ...@@ -129,7 +129,7 @@ static void keep_key_fresh(struct wg_peer *peer)
rcu_read_lock_bh(); rcu_read_lock_bh();
keypair = rcu_dereference_bh(peer->keypairs.current_keypair); keypair = rcu_dereference_bh(peer->keypairs.current_keypair);
send = keypair && READ_ONCE(keypair->sending.is_valid) && send = keypair && READ_ONCE(keypair->sending.is_valid) &&
(atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES || (atomic64_read(&keypair->sending_counter) > REKEY_AFTER_MESSAGES ||
(keypair->i_am_the_initiator && (keypair->i_am_the_initiator &&
wg_birthdate_has_expired(keypair->sending.birthdate, REKEY_AFTER_TIME))); wg_birthdate_has_expired(keypair->sending.birthdate, REKEY_AFTER_TIME)));
rcu_read_unlock_bh(); rcu_read_unlock_bh();
...@@ -167,6 +167,11 @@ static bool encrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair) ...@@ -167,6 +167,11 @@ static bool encrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair)
struct sk_buff *trailer; struct sk_buff *trailer;
int num_frags; int num_frags;
/* Force hash calculation before encryption so that flow analysis is
* consistent over the inner packet.
*/
skb_get_hash(skb);
/* Calculate lengths. */ /* Calculate lengths. */
padding_len = calculate_skb_padding(skb); padding_len = calculate_skb_padding(skb);
trailer_len = padding_len + noise_encrypted_len(0); trailer_len = padding_len + noise_encrypted_len(0);
...@@ -295,7 +300,7 @@ void wg_packet_encrypt_worker(struct work_struct *work) ...@@ -295,7 +300,7 @@ void wg_packet_encrypt_worker(struct work_struct *work)
skb_list_walk_safe(first, skb, next) { skb_list_walk_safe(first, skb, next) {
if (likely(encrypt_packet(skb, if (likely(encrypt_packet(skb,
PACKET_CB(first)->keypair))) { PACKET_CB(first)->keypair))) {
wg_reset_packet(skb); wg_reset_packet(skb, true);
} else { } else {
state = PACKET_STATE_DEAD; state = PACKET_STATE_DEAD;
break; break;
...@@ -344,7 +349,6 @@ void wg_packet_purge_staged_packets(struct wg_peer *peer) ...@@ -344,7 +349,6 @@ void wg_packet_purge_staged_packets(struct wg_peer *peer)
void wg_packet_send_staged_packets(struct wg_peer *peer) void wg_packet_send_staged_packets(struct wg_peer *peer)
{ {
struct noise_symmetric_key *key;
struct noise_keypair *keypair; struct noise_keypair *keypair;
struct sk_buff_head packets; struct sk_buff_head packets;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -364,10 +368,9 @@ void wg_packet_send_staged_packets(struct wg_peer *peer) ...@@ -364,10 +368,9 @@ void wg_packet_send_staged_packets(struct wg_peer *peer)
rcu_read_unlock_bh(); rcu_read_unlock_bh();
if (unlikely(!keypair)) if (unlikely(!keypair))
goto out_nokey; goto out_nokey;
key = &keypair->sending; if (unlikely(!READ_ONCE(keypair->sending.is_valid)))
if (unlikely(!READ_ONCE(key->is_valid)))
goto out_nokey; goto out_nokey;
if (unlikely(wg_birthdate_has_expired(key->birthdate, if (unlikely(wg_birthdate_has_expired(keypair->sending.birthdate,
REJECT_AFTER_TIME))) REJECT_AFTER_TIME)))
goto out_invalid; goto out_invalid;
...@@ -382,7 +385,7 @@ void wg_packet_send_staged_packets(struct wg_peer *peer) ...@@ -382,7 +385,7 @@ void wg_packet_send_staged_packets(struct wg_peer *peer)
*/ */
PACKET_CB(skb)->ds = ip_tunnel_ecn_encap(0, ip_hdr(skb), skb); PACKET_CB(skb)->ds = ip_tunnel_ecn_encap(0, ip_hdr(skb), skb);
PACKET_CB(skb)->nonce = PACKET_CB(skb)->nonce =
atomic64_inc_return(&key->counter.counter) - 1; atomic64_inc_return(&keypair->sending_counter) - 1;
if (unlikely(PACKET_CB(skb)->nonce >= REJECT_AFTER_MESSAGES)) if (unlikely(PACKET_CB(skb)->nonce >= REJECT_AFTER_MESSAGES))
goto out_invalid; goto out_invalid;
} }
...@@ -394,7 +397,7 @@ void wg_packet_send_staged_packets(struct wg_peer *peer) ...@@ -394,7 +397,7 @@ void wg_packet_send_staged_packets(struct wg_peer *peer)
return; return;
out_invalid: out_invalid:
WRITE_ONCE(key->is_valid, false); WRITE_ONCE(keypair->sending.is_valid, false);
out_nokey: out_nokey:
wg_noise_keypair_put(keypair, false); wg_noise_keypair_put(keypair, false);
......
...@@ -44,7 +44,7 @@ endef ...@@ -44,7 +44,7 @@ endef
$(eval $(call tar_download,MUSL,musl,1.2.0,.tar.gz,https://musl.libc.org/releases/,c6de7b191139142d3f9a7b5b702c9cae1b5ee6e7f57e582da9328629408fd4e8)) $(eval $(call tar_download,MUSL,musl,1.2.0,.tar.gz,https://musl.libc.org/releases/,c6de7b191139142d3f9a7b5b702c9cae1b5ee6e7f57e582da9328629408fd4e8))
$(eval $(call tar_download,IPERF,iperf,3.7,.tar.gz,https://downloads.es.net/pub/iperf/,d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c)) $(eval $(call tar_download,IPERF,iperf,3.7,.tar.gz,https://downloads.es.net/pub/iperf/,d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c))
$(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d)) $(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d))
$(eval $(call tar_download,IPROUTE2,iproute2,5.4.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,fe97aa60a0d4c5ac830be18937e18dc3400ca713a33a89ad896ff1e3d46086ae)) $(eval $(call tar_download,IPROUTE2,iproute2,5.6.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,1b5b0e25ce6e23da7526ea1da044e814ad85ba761b10dd29c2b027c056b04692))
$(eval $(call tar_download,IPTABLES,iptables,1.8.4,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,993a3a5490a544c2cbf2ef15cf7e7ed21af1845baf228318d5c36ef8827e157c)) $(eval $(call tar_download,IPTABLES,iptables,1.8.4,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,993a3a5490a544c2cbf2ef15cf7e7ed21af1845baf228318d5c36ef8827e157c))
$(eval $(call tar_download,NMAP,nmap,7.80,.tar.bz2,https://nmap.org/dist/,fcfa5a0e42099e12e4bf7a68ebe6fde05553383a682e816a7ec9256ab4773faa)) $(eval $(call tar_download,NMAP,nmap,7.80,.tar.bz2,https://nmap.org/dist/,fcfa5a0e42099e12e4bf7a68ebe6fde05553383a682e816a7ec9256ab4773faa))
$(eval $(call tar_download,IPUTILS,iputils,s20190709,.tar.gz,https://github.com/iputils/iputils/archive/s20190709.tar.gz/#,a15720dd741d7538dd2645f9f516d193636ae4300ff7dbc8bfca757bf166490a)) $(eval $(call tar_download,IPUTILS,iputils,s20190709,.tar.gz,https://github.com/iputils/iputils/archive/s20190709.tar.gz/#,a15720dd741d7538dd2645f9f516d193636ae4300ff7dbc8bfca757bf166490a))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment