mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-30 06:55:13 +08:00
⛅ Sync 2026-07-22 03:00:29
This commit is contained in:
1 parent
473d483fb6
commit
408cef6151
28 files changed
+15055
-1
No files matched your search
@@ -0,0 +1,310 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* mwan3ct - targeted conntrack flush helper for mwan3
|
||||
*
|
||||
* Uses libnetfilter_conntrack's NFCT_Q_FLUSH_FILTER to perform
|
||||
* kernel-side filtered conntrack entry deletion by mark and/or
|
||||
* status bits.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
||||
|
||||
/*
|
||||
* id2mask - expand a sequential bit index into a sparse mask
|
||||
*
|
||||
* Maps each set bit in 'id' (counting from bit 0) to the
|
||||
* corresponding set bit position in 'mask', producing a value
|
||||
* that occupies only the bit positions defined by 'mask'.
|
||||
*/
|
||||
|
||||
static uint32_t id2mask(uint32_t id, uint32_t mask)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
uint32_t bit = 1;
|
||||
|
||||
for (uint32_t m = mask; m; m &= m - 1) {
|
||||
if (id & bit)
|
||||
result |= m & (-m);
|
||||
bit <<= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* flush_filtered - flush conntrack entries matching mark and/or status
|
||||
*
|
||||
* Builds a kernel-side filter from the supplied mark and status
|
||||
* value/mask pairs, then issues a single NFCT_Q_FLUSH_FILTER query.
|
||||
* ENOENT (no matching entries) is treated as success.
|
||||
*/
|
||||
|
||||
static int flush_filtered(struct nfct_handle *h,
|
||||
uint32_t mark_val, uint32_t mark_mask,
|
||||
uint32_t status_val, uint32_t status_mask,
|
||||
int have_mark, int have_status)
|
||||
{
|
||||
struct nfct_filter_dump *filter = NULL;
|
||||
int ret;
|
||||
|
||||
filter = nfct_filter_dump_create();
|
||||
if (!filter) {
|
||||
fprintf(stderr, "mwan3ct: nfct_filter_dump_create: %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (have_mark) {
|
||||
struct nfct_filter_dump_mark mark = {
|
||||
.val = mark_val,
|
||||
.mask = mark_mask,
|
||||
};
|
||||
nfct_filter_dump_set_attr(filter, NFCT_FILTER_DUMP_MARK,
|
||||
&mark);
|
||||
}
|
||||
if (have_status) {
|
||||
struct nfct_filter_dump_mark status = {
|
||||
.val = status_val,
|
||||
.mask = status_mask,
|
||||
};
|
||||
nfct_filter_dump_set_attr(filter, NFCT_FILTER_DUMP_STATUS,
|
||||
&status);
|
||||
}
|
||||
|
||||
ret = nfct_query(h, NFCT_Q_FLUSH_FILTER, filter);
|
||||
nfct_filter_dump_destroy(filter);
|
||||
|
||||
if (ret == -1 && errno != ENOENT)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* flush_any_marked - flush conntrack entries for all mark values in a mask
|
||||
*
|
||||
* Iterates over every non-zero combination of bits within 'mask'
|
||||
* and issues a filtered flush for each. Used when the caller wants
|
||||
* to remove all mwan3-marked entries regardless of which interface
|
||||
* they belong to.
|
||||
*/
|
||||
|
||||
static int flush_any_marked(struct nfct_handle *h, uint32_t mask,
|
||||
uint32_t status_val, uint32_t status_mask,
|
||||
int have_status)
|
||||
{
|
||||
int bitcount = __builtin_popcount(mask);
|
||||
uint32_t max_id;
|
||||
|
||||
if (bitcount > 16) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
max_id = (1U << bitcount) - 1;
|
||||
|
||||
for (uint32_t id = 1; id <= max_id; id++) {
|
||||
uint32_t mark_val = id2mask(id, mask);
|
||||
int ret = flush_filtered(h, mark_val, mask, status_val,
|
||||
status_mask, 1, have_status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse_u32 - parse a string as a uint32_t with full validation
|
||||
*
|
||||
* Rejects negative values, overflow, and empty input. On success
|
||||
* *endp points past the last consumed character, allowing the caller
|
||||
* to check for trailing garbage. Returns 0 on success, -1 on failure.
|
||||
*/
|
||||
|
||||
static int parse_u32(const char *s, char **endp, uint32_t *out)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
if (*s == '-')
|
||||
return -1;
|
||||
|
||||
errno = 0;
|
||||
tmp = strtoul(s, endp, 0);
|
||||
if (*endp == s || errno)
|
||||
return -1;
|
||||
if ((uint32_t)tmp != tmp)
|
||||
return -1;
|
||||
*out = (uint32_t)tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse_val_mask - parse a "value/mask" string into two uint32 values
|
||||
*
|
||||
* Accepts "val/mask" or just "val", in which case the mask defaults
|
||||
* to the value itself. Returns 0 on success, -1 on parse failure.
|
||||
*/
|
||||
|
||||
static int parse_val_mask(const char *arg, uint32_t *val, uint32_t *mask)
|
||||
{
|
||||
char *end = NULL;
|
||||
|
||||
if (parse_u32(arg, &end, val))
|
||||
return -1;
|
||||
|
||||
if (*end == '/') {
|
||||
if (parse_u32(end + 1, &end, mask))
|
||||
return -1;
|
||||
if (*end != '\0')
|
||||
return -1;
|
||||
} else if (*end == '\0') {
|
||||
*mask = *val;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* usage - print command usage to stderr
|
||||
*/
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: mwan3ct flush [--mark <val>/<mask>] "
|
||||
"[--mark-any <mask>] [--status <val>/<mask>]\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* main - parse arguments and dispatch the requested flush operation
|
||||
*
|
||||
* Supports three mutually exclusive filter modes: --mark (exact
|
||||
* value/mask match), --mark-any (iterate all non-zero mark values
|
||||
* within a mask), and --status (conntrack status bit filter).
|
||||
* --mark and --status, or --mark-any and --status, may be combined.
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t mark_val = 0, mark_mask = 0;
|
||||
uint32_t status_val = 0, status_mask = 0;
|
||||
int have_mark = 0, have_mark_any = 0, have_status = 0;
|
||||
struct nfct_handle *h = NULL;
|
||||
int ret;
|
||||
|
||||
if (argc >= 2 && (strcmp(argv[1], "--help") == 0 ||
|
||||
strcmp(argv[1], "-h") == 0)) {
|
||||
usage();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (argc < 2 || strcmp(argv[1], "flush") != 0) {
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (int i = 2; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--mark") == 0 && i + 1 < argc) {
|
||||
if (have_mark) {
|
||||
fprintf(stderr,
|
||||
"mwan3ct: duplicate --mark\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (parse_val_mask(argv[++i], &mark_val, &mark_mask)) {
|
||||
fprintf(stderr, "mwan3ct: bad --mark value\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
have_mark = 1;
|
||||
} else if (strcmp(argv[i], "--mark-any") == 0 && i + 1 < argc) {
|
||||
char *end;
|
||||
|
||||
if (have_mark_any) {
|
||||
fprintf(stderr,
|
||||
"mwan3ct: duplicate --mark-any\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (parse_u32(argv[++i], &end, &mark_mask) ||
|
||||
*end != '\0' || !mark_mask) {
|
||||
fprintf(stderr,
|
||||
"mwan3ct: bad --mark-any mask\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
have_mark_any = 1;
|
||||
} else if (strcmp(argv[i], "--status") == 0 && i + 1 < argc) {
|
||||
if (have_status) {
|
||||
fprintf(stderr,
|
||||
"mwan3ct: duplicate --status\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (parse_val_mask(argv[++i],
|
||||
&status_val, &status_mask)) {
|
||||
fprintf(stderr,
|
||||
"mwan3ct: bad --status value\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
have_status = 1;
|
||||
} else {
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (have_mark && have_mark_any) {
|
||||
fprintf(stderr,
|
||||
"mwan3ct: --mark and --mark-any "
|
||||
"are mutually exclusive\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!have_mark && !have_mark_any && !have_status) {
|
||||
fprintf(stderr, "mwan3ct: at least one filter required\n");
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (have_mark && !mark_mask) {
|
||||
fprintf(stderr, "mwan3ct: --mark mask must be non-zero\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (have_mark && (mark_val & ~mark_mask)) {
|
||||
fprintf(stderr,
|
||||
"mwan3ct: --mark value has bits outside mask\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (have_status && !status_mask) {
|
||||
fprintf(stderr,
|
||||
"mwan3ct: --status mask must be non-zero\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (have_status && (status_val & ~status_mask)) {
|
||||
fprintf(stderr,
|
||||
"mwan3ct: --status value has bits outside mask\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
h = nfct_open(CONNTRACK, 0);
|
||||
if (!h) {
|
||||
fprintf(stderr, "mwan3ct: nfct_open: %s\n", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (have_mark_any)
|
||||
ret = flush_any_marked(h, mark_mask, status_val,
|
||||
status_mask, have_status);
|
||||
else
|
||||
ret = flush_filtered(h, mark_val, mark_mask,
|
||||
status_val, status_mask,
|
||||
have_mark, have_status);
|
||||
|
||||
nfct_close(h);
|
||||
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "mwan3ct: flush failed: %s\n", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* mwan3ipcheck - validate and classify IP addresses and CIDR notation
|
||||
*
|
||||
* Uses inet_pton() to determine whether a string is a valid IPv4 or
|
||||
* IPv6 address, optionally with a CIDR prefix length.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
static int classify(const char *arg)
|
||||
{
|
||||
char buf[64];
|
||||
unsigned char addr[sizeof(struct in6_addr)];
|
||||
const char *pfxstr = NULL;
|
||||
int family;
|
||||
size_t len;
|
||||
|
||||
len = strlen(arg);
|
||||
if (len == 0 || len >= sizeof(buf))
|
||||
return 0;
|
||||
|
||||
memcpy(buf, arg, len + 1);
|
||||
|
||||
char *slash = strchr(buf, '/');
|
||||
if (slash) {
|
||||
*slash = '\0';
|
||||
pfxstr = slash + 1;
|
||||
if (*pfxstr == '\0')
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, buf, addr) == 1)
|
||||
family = AF_INET;
|
||||
else if (inet_pton(AF_INET6, buf, addr) == 1)
|
||||
family = AF_INET6;
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (pfxstr) {
|
||||
char *end;
|
||||
long pfx;
|
||||
int max_pfx = (family == AF_INET) ? 32 : 128;
|
||||
|
||||
if (pfxstr[0] == '0' && pfxstr[1] != '\0')
|
||||
return 0;
|
||||
|
||||
pfx = strtol(pfxstr, &end, 10);
|
||||
if (*end != '\0' || end == pfxstr)
|
||||
return 0;
|
||||
if (pfx < 0 || pfx > max_pfx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return family;
|
||||
}
|
||||
|
||||
static int classify_list(const char *arg)
|
||||
{
|
||||
char buf[512];
|
||||
char *token = NULL, *saveptr = NULL;
|
||||
int common_family = 0;
|
||||
|
||||
size_t len = strlen(arg);
|
||||
if (len == 0 || len >= sizeof(buf))
|
||||
return 0;
|
||||
|
||||
memcpy(buf, arg, len + 1);
|
||||
|
||||
for (token = strtok_r(buf, ",", &saveptr);
|
||||
token;
|
||||
token = strtok_r(NULL, ",", &saveptr)) {
|
||||
while (*token && isspace((unsigned char)*token))
|
||||
token++;
|
||||
size_t tlen = strlen(token);
|
||||
while (tlen > 0 && isspace((unsigned char)token[tlen - 1]))
|
||||
token[--tlen] = '\0';
|
||||
if (tlen == 0)
|
||||
continue;
|
||||
|
||||
int family = classify(token);
|
||||
if (family == 0)
|
||||
return 0;
|
||||
|
||||
if (common_family == 0)
|
||||
common_family = family;
|
||||
else if (family != common_family)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (common_family == 0)
|
||||
return 0;
|
||||
|
||||
return common_family;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int result;
|
||||
|
||||
if (argc != 2)
|
||||
result = 0;
|
||||
else
|
||||
result = classify_list(argv[1]);
|
||||
|
||||
if (result == AF_INET)
|
||||
puts("ipv4");
|
||||
else if (result == AF_INET6)
|
||||
puts("ipv6");
|
||||
else if (result == -1) {
|
||||
puts("mixed");
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
puts("invalid");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2020 Aaron Goodman <aaronjg@alumni.stanford.edu>. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* sockopt_wrap.c provides a shared library that intercepts syscalls to various
|
||||
* networking functions to bind the sockets a source IP address and network device
|
||||
* and to set the firewall mark on otugoing packets. Parameters are set using the
|
||||
* DEVICE, SRCIP, FWMARK environment variables.
|
||||
*
|
||||
* Additionally the FAMILY environment variable can be set to either 'ipv4' or
|
||||
* 'ipv6' to cause sockets opened with ipv6 or ipv4 to fail, respectively.
|
||||
*
|
||||
* Each environment variable is optional, and if not set, the library will not
|
||||
* enforce the particular parameter.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <net/if.h>
|
||||
|
||||
static int (*next_socket)(int domain, int type, int protocol);
|
||||
static int (*next_setsockopt)(int sockfd, int level, int optname,
|
||||
const void *optval, socklen_t optlen);
|
||||
static int (*next_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
static int (*next_close)(int fd);
|
||||
static ssize_t (*next_send)(int sockfd, const void *buf, size_t len, int flags);
|
||||
static ssize_t (*next_sendto)(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
static ssize_t (*next_sendmsg)(int sockfd, const struct msghdr *msg, int flags);
|
||||
static int (*next_connect)(int sockfd, const struct sockaddr *addr,
|
||||
socklen_t addrlen);
|
||||
static int device=0;
|
||||
static struct sockaddr_in source4 = {0};
|
||||
#ifdef CONFIG_IPV6
|
||||
static struct sockaddr_in6 source6 = {0};
|
||||
#endif
|
||||
static struct sockaddr * source = 0;
|
||||
static int sockaddr_size = 0;
|
||||
static int is_bound [1024] = {0};
|
||||
|
||||
#define next_func(x)\
|
||||
void set_next_##x(){\
|
||||
if (next_##x) return;\
|
||||
next_##x = dlsym(RTLD_NEXT, #x);\
|
||||
dlerror_handle();\
|
||||
return;\
|
||||
}
|
||||
|
||||
void dlerror_handle()
|
||||
{
|
||||
char *msg;
|
||||
if ((msg = dlerror()) != NULL) {
|
||||
fprintf(stderr, "socket: dlopen failed : %s\n", msg);
|
||||
fflush(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
next_func(bind);
|
||||
next_func(close);
|
||||
next_func(setsockopt);
|
||||
next_func(socket);
|
||||
next_func(send);
|
||||
next_func(sendto);
|
||||
next_func(sendmsg);
|
||||
next_func(connect);
|
||||
|
||||
void dobind(int sockfd)
|
||||
{
|
||||
if (source && sockfd < 1024 && !is_bound[sockfd]) {
|
||||
set_next_bind();
|
||||
if (next_bind(sockfd, source, sockaddr_size)) {
|
||||
perror("mwan3 sockopt_wrap: failed to bind to source address");
|
||||
next_close(sockfd);
|
||||
/* Do not exit — let the caller's syscall fail with EBADF so
|
||||
* the tracked process exits with a normal error code. This
|
||||
* can happen when SRC_IP becomes stale (e.g. after a DHCP
|
||||
* address change) and must not terminate the ping abruptly
|
||||
* with no log from mwan3track. */
|
||||
return;
|
||||
}
|
||||
is_bound[sockfd] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
set_next_connect();
|
||||
dobind(sockfd);
|
||||
return next_connect(sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
|
||||
{
|
||||
set_next_send();
|
||||
dobind(sockfd);
|
||||
return next_send(sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen)
|
||||
{
|
||||
set_next_sendto();
|
||||
dobind(sockfd);
|
||||
return next_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
|
||||
}
|
||||
|
||||
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
|
||||
{
|
||||
set_next_sendmsg();
|
||||
dobind(sockfd);
|
||||
return next_sendmsg(sockfd, msg, flags);
|
||||
}
|
||||
|
||||
int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
set_next_bind();
|
||||
if (device && addr->sa_family == AF_PACKET) {
|
||||
((struct sockaddr_ll*)addr)->sll_ifindex=device;
|
||||
}
|
||||
else if (source && addr->sa_family == AF_INET) {
|
||||
((struct sockaddr_in*)addr)->sin_addr = source4.sin_addr;
|
||||
}
|
||||
#ifdef CONFIG_IPV6
|
||||
else if (source && addr->sa_family == AF_INET6) {
|
||||
((struct sockaddr_in6*)addr)->sin6_addr = source6.sin6_addr;
|
||||
}
|
||||
#endif
|
||||
if (sockfd < 1024)
|
||||
is_bound[sockfd] = 1;
|
||||
return next_bind(sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
int close (int sockfd)
|
||||
{
|
||||
set_next_close();
|
||||
if (sockfd < 1024)
|
||||
is_bound[sockfd]=0;
|
||||
return next_close(sockfd);
|
||||
}
|
||||
|
||||
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen)
|
||||
{
|
||||
set_next_setsockopt();
|
||||
if (level == SOL_SOCKET && (optname == SO_MARK || optname == SO_BINDTODEVICE))
|
||||
return 0;
|
||||
return next_setsockopt(sockfd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int socket(int domain, int type, int protocol)
|
||||
{
|
||||
int handle;
|
||||
|
||||
const char *socket_str = getenv("DEVICE");
|
||||
const char *srcip_str = getenv("SRCIP");
|
||||
const char *fwmark_str = getenv("FWMARK");
|
||||
const char *family_str = getenv("FAMILY");
|
||||
const int iface_len = socket_str ? strnlen(socket_str, IFNAMSIZ) : 0;
|
||||
int has_family = family_str && *family_str != 0;
|
||||
int has_srcip = srcip_str && *srcip_str != 0;
|
||||
const int fwmark = fwmark_str ? (int)strtol(fwmark_str, NULL, 0) : 0;
|
||||
|
||||
set_next_close();
|
||||
set_next_socket();
|
||||
set_next_send();
|
||||
set_next_setsockopt();
|
||||
set_next_sendmsg();
|
||||
set_next_sendto();
|
||||
set_next_connect();
|
||||
if(has_family) {
|
||||
#ifdef CONFIG_IPV6
|
||||
if(domain == AF_INET && strncmp(family_str,"ipv6",4) == 0)
|
||||
return -1;
|
||||
#endif
|
||||
if(domain == AF_INET6 && strncmp(family_str,"ipv4",4) == 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (domain != AF_INET
|
||||
#ifdef CONFIG_IPV6
|
||||
&& domain != AF_INET6
|
||||
#endif
|
||||
) {
|
||||
return next_socket(domain, type, protocol);
|
||||
}
|
||||
|
||||
|
||||
if (iface_len > 0) {
|
||||
if (iface_len == IFNAMSIZ) {
|
||||
fprintf(stderr, "mwan3 sockopt_wrap: interface name too long\n");
|
||||
fflush(stderr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_srcip) {
|
||||
int s;
|
||||
void * addr_buf;
|
||||
if (domain == AF_INET) {
|
||||
addr_buf = &source4.sin_addr;
|
||||
sockaddr_size=sizeof source4;
|
||||
memset(&source4, 0, sockaddr_size);
|
||||
source4.sin_family = domain;
|
||||
source = (struct sockaddr*)&source4;
|
||||
}
|
||||
#ifdef CONFIG_IPV6
|
||||
else {
|
||||
addr_buf = &source6.sin6_addr;
|
||||
sockaddr_size=sizeof source6;
|
||||
memset(&source6, 0, sockaddr_size);
|
||||
source6.sin6_family=domain;
|
||||
source = (struct sockaddr*)&source6;
|
||||
}
|
||||
#endif
|
||||
s = inet_pton(domain, srcip_str, addr_buf);
|
||||
if (s == 0) {
|
||||
fprintf(stderr, "socket: ip address invalid format for family %s\n",
|
||||
domain == AF_INET ? "AF_INET" : domain == AF_INET6 ?
|
||||
"AF_INET6" : "unknown");
|
||||
return -1;
|
||||
}
|
||||
if (s < 0) {
|
||||
perror("inet_pton");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
handle = next_socket(domain, type, protocol);
|
||||
if (handle == -1 ) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
if (iface_len > 0) {
|
||||
device=if_nametoindex(socket_str);
|
||||
if (next_setsockopt(handle, SOL_SOCKET, SO_BINDTODEVICE,
|
||||
socket_str, iface_len + 1)) {
|
||||
perror("mwan3 sockopt_wrap: failed to bind to interface");
|
||||
next_close(handle);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fwmark > 0) {
|
||||
if (next_setsockopt(handle, SOL_SOCKET, SO_MARK,
|
||||
&fwmark, sizeof fwmark)) {
|
||||
perror("mwan3 sockopt_wrap: failed to set firewall mark");
|
||||
next_close(handle);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
Reference in new issue
Block a user