linux routing + debug output
This commit is contained in:
1 parent
0b4e5960cf
commit
1aec884c2d
8 files changed
+143
-42
No files matched your search
@@ -532,6 +532,18 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
|
||||
add_route_entry(&cfg->my_subnets, value);
|
||||
}
|
||||
break;
|
||||
case SECTION_DEBUG:
|
||||
// Format: category=level (e.g., etcp=debug, crypto=info)
|
||||
if (cfg->global.debug_levels.count < 16) {
|
||||
strncpy(cfg->global.debug_levels.category[cfg->global.debug_levels.count],
|
||||
key, 15);
|
||||
cfg->global.debug_levels.category[cfg->global.debug_levels.count][15] = '\0';
|
||||
strncpy(cfg->global.debug_levels.level[cfg->global.debug_levels.count],
|
||||
value, 15);
|
||||
cfg->global.debug_levels.level[cfg->global.debug_levels.count][15] = '\0';
|
||||
cfg->global.debug_levels.count++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Key outside section: %s", filename, line_num, key);
|
||||
break;
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ static void routing_pkt_from_tun_cb(struct ll_queue* q, void* arg) {
|
||||
|
||||
struct ROUTE_ARRAY* routes = route_table_lookup(instance->rt, dst_ip);
|
||||
if (!routes || routes->routes == 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "No route to %s, dropping packet", ip_to_str(&addr, AF_INET).str);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "No route to %s, dropping packet", ip_to_str(&addr, AF_INET).str);
|
||||
free(pkt->ll.dgram);
|
||||
memory_pool_free(instance->tun->pool, pkt);
|
||||
} else {
|
||||
|
||||
+82
-37
@@ -46,18 +46,37 @@ struct nl_req {
|
||||
};
|
||||
|
||||
static int netlink_route(int ifindex, uint32_t network, uint8_t prefix_len, int cmd, int flags) {
|
||||
int fd = socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, NETLINK_ROUTE);
|
||||
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (fd < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create netlink socket: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Bind to receive responses
|
||||
struct sockaddr_nl addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pid = getpid();
|
||||
addr.nl_groups = 0;
|
||||
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to bind netlink socket: %s", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Prepare destination address (kernel)
|
||||
struct sockaddr_nl dest;
|
||||
memset(&dest, 0, sizeof(dest));
|
||||
dest.nl_family = AF_NETLINK;
|
||||
dest.nl_pid = 0; // kernel
|
||||
dest.nl_groups = 0;
|
||||
|
||||
struct nl_req req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
|
||||
req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
req.nl.nlmsg_type = cmd; // RTM_NEWROUTE or RTM_DELROUTE
|
||||
req.nl.nlmsg_flags = flags | NLM_F_REQUEST;
|
||||
req.nl.nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK; // Request ACK from kernel
|
||||
req.nl.nlmsg_seq = 1;
|
||||
req.nl.nlmsg_pid = getpid();
|
||||
|
||||
@@ -82,12 +101,15 @@ static int netlink_route(int ifindex, uint32_t network, uint8_t prefix_len, int
|
||||
memcpy(RTA_DATA(rta), &ifindex, 4);
|
||||
req.nl.nlmsg_len = NLMSG_ALIGN(req.nl.nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
if (send(fd, &req, req.nl.nlmsg_len, 0) < 0) {
|
||||
if (sendto(fd, &req, req.nl.nlmsg_len, 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to send netlink message: %s", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Netlink message sent: seq=%u pid=%u len=%d",
|
||||
req.nl.nlmsg_seq, req.nl.nlmsg_pid, req.nl.nlmsg_len);
|
||||
|
||||
// Wait for response with timeout using poll
|
||||
struct pollfd pfd = { .fd = fd, .events = POLLIN };
|
||||
int poll_ret = poll(&pfd, 1, 1000); // 1 second timeout
|
||||
@@ -96,11 +118,13 @@ static int netlink_route(int ifindex, uint32_t network, uint8_t prefix_len, int
|
||||
close(fd);
|
||||
return -1;
|
||||
} else if (poll_ret == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Timeout waiting for netlink response");
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Timeout waiting for netlink response (sent %d bytes)", req.nl.nlmsg_len);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Poll returned: revents=%d", pfd.revents);
|
||||
|
||||
// Receive response
|
||||
char reply[4096];
|
||||
ssize_t len = recv(fd, reply, sizeof(reply), 0);
|
||||
@@ -110,7 +134,12 @@ static int netlink_route(int ifindex, uint32_t network, uint8_t prefix_len, int
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Received netlink response: len=%d", (int)len);
|
||||
|
||||
struct nlmsghdr *nl_hdr = (struct nlmsghdr *)reply;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Netlink msg: type=%d seq=%d pid=%d",
|
||||
nl_hdr->nlmsg_type, nl_hdr->nlmsg_seq, nl_hdr->nlmsg_pid);
|
||||
|
||||
if (nl_hdr->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nl_hdr);
|
||||
if (err->error < 0) {
|
||||
@@ -138,44 +167,42 @@ static int ip_route_cmd(const char *ifname, uint32_t network, uint8_t prefix_len
|
||||
return (ret == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
int tun_route_add(uint32_t ifindex, uint32_t network, uint8_t prefix_len) {
|
||||
if (ifindex == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Interface index is 0");
|
||||
int tun_route_add(uint32_t ifindex, const char *ifname, uint32_t network, uint8_t prefix_len) {
|
||||
if (ifindex == 0 && (!ifname || !ifname[0])) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Interface index and name are both invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
network = htonl(network);
|
||||
|
||||
// Try netlink first
|
||||
if (netlink_route(ifindex, network, prefix_len, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL) == 0) {
|
||||
if (ifindex != 0 && netlink_route(ifindex, network, prefix_len, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fallback to ip route command
|
||||
DEBUG_WARN(DEBUG_CATEGORY_TUN, "Netlink failed, trying ip route command for ifindex %u", ifindex);
|
||||
char ifname[16];
|
||||
snprintf(ifname, sizeof(ifname), "%u", ifindex);
|
||||
return ip_route_cmd(ifname, ntohl(network), prefix_len, "add");
|
||||
const char *dev = ifname ? ifname : "";
|
||||
return ip_route_cmd(dev, ntohl(network), prefix_len, "add");
|
||||
}
|
||||
|
||||
int tun_route_del(uint32_t ifindex, uint32_t network, uint8_t prefix_len) {
|
||||
if (ifindex == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "tun_route_del: ifindex is 0");
|
||||
int tun_route_del(uint32_t ifindex, const char *ifname, uint32_t network, uint8_t prefix_len) {
|
||||
if (ifindex == 0 && (!ifname || !ifname[0])) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "tun_route_del: ifindex and ifname are both invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
network = htonl(network);
|
||||
|
||||
// Try netlink first
|
||||
if (netlink_route(ifindex, network, prefix_len, RTM_DELROUTE, 0) == 0) {
|
||||
if (ifindex != 0 && netlink_route(ifindex, network, prefix_len, RTM_DELROUTE, 0) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fallback to ip route command
|
||||
char ifname[16];
|
||||
snprintf(ifname, sizeof(ifname), "%u", ifindex);
|
||||
DEBUG_WARN(DEBUG_CATEGORY_TUN, "Netlink failed, trying ip route command for ifindex %u", ifindex);
|
||||
return ip_route_cmd(ifname, ntohl(network), prefix_len, "del");
|
||||
const char *dev = ifname ? ifname : "";
|
||||
return ip_route_cmd(dev, ntohl(network), prefix_len, "del");
|
||||
}
|
||||
|
||||
int tun_route_flush(const char *ifname) {
|
||||
@@ -196,11 +223,30 @@ int tun_route_flush(const char *ifname) {
|
||||
return (ret == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
int tun_route_del_all(uint32_t ifindex, const char *ifname, struct CFG_ROUTE_ENTRY *routes) {
|
||||
int count = 0;
|
||||
struct CFG_ROUTE_ENTRY *entry = routes;
|
||||
|
||||
while (entry) {
|
||||
uint32_t network = ntohl(entry->ip.addr.v4.s_addr);
|
||||
if (entry->ip.family == AF_INET) {
|
||||
if (tun_route_del(ifindex, ifname, network, entry->netmask) == 0) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Deleted %d routes via ifindex=%lu", count, (unsigned long)ifindex);
|
||||
return count;
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
// Windows IP Helper API implementation
|
||||
|
||||
int tun_route_add(uint32_t ifindex, uint32_t network, uint8_t prefix_len) {
|
||||
int tun_route_add(uint32_t ifindex, const char *ifname, uint32_t network, uint8_t prefix_len) {
|
||||
(void)ifname; // Not used on Windows
|
||||
if (ifindex == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "tun_route_add: ifindex is 0");
|
||||
return -1;
|
||||
@@ -248,7 +294,8 @@ int tun_route_add(uint32_t ifindex, uint32_t network, uint8_t prefix_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tun_route_del(uint32_t ifindex, uint32_t network, uint8_t prefix_len) {
|
||||
int tun_route_del(uint32_t ifindex, const char *ifname, uint32_t network, uint8_t prefix_len) {
|
||||
(void)ifname; // Not used on Windows
|
||||
if (ifindex == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "tun_route_del: ifindex is 0");
|
||||
return -1;
|
||||
@@ -318,14 +365,14 @@ int tun_route_flush(const char *ifname) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tun_route_del_all(uint32_t ifindex, struct CFG_ROUTE_ENTRY *routes) {
|
||||
int tun_route_del_all(uint32_t ifindex, const char *ifname, struct CFG_ROUTE_ENTRY *routes) {
|
||||
int count = 0;
|
||||
struct CFG_ROUTE_ENTRY *entry = routes;
|
||||
|
||||
while (entry) {
|
||||
uint32_t network = ntohl(entry->ip.addr.v4.s_addr);
|
||||
if (entry->ip.family == AF_INET) {
|
||||
if (tun_route_del(ifindex, network, entry->netmask) == 0) {
|
||||
if (tun_route_del(ifindex, ifname, network, entry->netmask) == 0) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -415,40 +462,38 @@ static int route_cmd(const char *ifname, uint32_t network, uint8_t prefix_len, c
|
||||
return (ret == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
int tun_route_add(uint32_t ifindex, uint32_t network, uint8_t prefix_len) {
|
||||
if (ifindex == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Interface index is 0");
|
||||
int tun_route_add(uint32_t ifindex, const char *ifname, uint32_t network, uint8_t prefix_len) {
|
||||
if (ifindex == 0 && (!ifname || !ifname[0])) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Interface index and name are both invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Try routing socket first
|
||||
if (routing_socket_cmd(ifindex, network, prefix_len, RTM_ADD) == 0) {
|
||||
if (ifindex != 0 && routing_socket_cmd(ifindex, network, prefix_len, RTM_ADD) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fallback to route command
|
||||
DEBUG_WARN(DEBUG_CATEGORY_TUN, "Routing socket failed, trying route command for ifindex %u", ifindex);
|
||||
char ifname[16];
|
||||
snprintf(ifname, sizeof(ifname), "%u", ifindex);
|
||||
return route_cmd(ifname, network, prefix_len, "add");
|
||||
const char *dev = ifname ? ifname : "";
|
||||
return route_cmd(dev, network, prefix_len, "add");
|
||||
}
|
||||
|
||||
int tun_route_del(uint32_t ifindex, uint32_t network, uint8_t prefix_len) {
|
||||
if (ifindex == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "tun_route_del: ifindex is 0");
|
||||
int tun_route_del(uint32_t ifindex, const char *ifname, uint32_t network, uint8_t prefix_len) {
|
||||
if (ifindex == 0 && (!ifname || !ifname[0])) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "tun_route_del: ifindex and ifname are both invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Try routing socket first
|
||||
if (routing_socket_cmd(ifindex, network, prefix_len, RTM_DELETE) == 0) {
|
||||
if (ifindex != 0 && routing_socket_cmd(ifindex, network, prefix_len, RTM_DELETE) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fallback to route command
|
||||
char ifname[16];
|
||||
snprintf(ifname, sizeof(ifname), "%u", ifindex);
|
||||
DEBUG_WARN(DEBUG_CATEGORY_TUN, "Routing socket failed, trying route command for ifindex %u", ifindex);
|
||||
return route_cmd(ifname, network, prefix_len, "delete");
|
||||
const char *dev = ifname ? ifname : "";
|
||||
return route_cmd(dev, network, prefix_len, "delete");
|
||||
}
|
||||
|
||||
int tun_route_flush(const char *ifname) {
|
||||
@@ -474,7 +519,7 @@ int tun_route_add_all(uint32_t ifindex, const char *ifname, struct CFG_ROUTE_ENT
|
||||
while (entry) {
|
||||
uint32_t network = ntohl(entry->ip.addr.v4.s_addr);
|
||||
if (entry->ip.family == AF_INET) {
|
||||
if (tun_route_add(ifindex, network, entry->netmask) == 0) {
|
||||
if (tun_route_add(ifindex, ifname, network, entry->netmask) == 0) {
|
||||
struct in_addr addr;
|
||||
addr.s_addr = entry->ip.addr.v4.s_addr;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Added route %s/%d via %s", ip_to_str(&addr, AF_INET).str, entry->netmask, ifname);
|
||||
|
||||
+6
-3
@@ -14,28 +14,31 @@ struct CFG_ROUTE_ENTRY;
|
||||
/**
|
||||
* @brief Add system route for a subnet via TUN interface
|
||||
* @param ifindex Interface index
|
||||
* @param ifname Interface name (e.g., "tun0")
|
||||
* @param network Network address in host byte order
|
||||
* @param prefix_len Prefix length (1-32)
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int tun_route_add(uint32_t ifindex, uint32_t network, uint8_t prefix_len);
|
||||
int tun_route_add(uint32_t ifindex, const char *ifname, uint32_t network, uint8_t prefix_len);
|
||||
|
||||
/**
|
||||
* @brief Delete system route for a subnet via TUN interface
|
||||
* @param ifindex Interface index
|
||||
* @param ifname Interface name (e.g., "tun0")
|
||||
* @param network Network address in host byte order
|
||||
* @param prefix_len Prefix length (1-32)
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int tun_route_del(uint32_t ifindex, uint32_t network, uint8_t prefix_len);
|
||||
int tun_route_del(uint32_t ifindex, const char *ifname, uint32_t network, uint8_t prefix_len);
|
||||
|
||||
/**
|
||||
* @brief Delete all system routes from config entries
|
||||
* @param ifindex Interface index
|
||||
* @param ifname Interface name (e.g., "tun0")
|
||||
* @param routes Linked list of route entries to delete
|
||||
* @return Number of routes deleted
|
||||
*/
|
||||
int tun_route_del_all(uint32_t ifindex, struct CFG_ROUTE_ENTRY *routes);
|
||||
int tun_route_del_all(uint32_t ifindex, const char *ifname, struct CFG_ROUTE_ENTRY *routes);
|
||||
|
||||
/**
|
||||
* @brief Delete all system routes via specified interface
|
||||
|
||||
+38
-1
@@ -159,6 +159,43 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Applied debug_level from config: %s", config->global.debug_level);
|
||||
}
|
||||
|
||||
// Apply per-category debug levels from [debug] section
|
||||
for (int i = 0; i < config->global.debug_levels.count; i++) {
|
||||
const char* cat_name = config->global.debug_levels.category[i];
|
||||
const char* lvl_str = config->global.debug_levels.level[i];
|
||||
|
||||
debug_category_t cat = 0;
|
||||
// Map category name to bitmask
|
||||
if (strcmp(cat_name, "uasync") == 0) cat = DEBUG_CATEGORY_UASYNC;
|
||||
else if (strcmp(cat_name, "ll_queue") == 0) cat = DEBUG_CATEGORY_LL_QUEUE;
|
||||
else if (strcmp(cat_name, "connection") == 0) cat = DEBUG_CATEGORY_CONNECTION;
|
||||
else if (strcmp(cat_name, "etcp") == 0) cat = DEBUG_CATEGORY_ETCP;
|
||||
else if (strcmp(cat_name, "crypto") == 0) cat = DEBUG_CATEGORY_CRYPTO;
|
||||
else if (strcmp(cat_name, "memory") == 0) cat = DEBUG_CATEGORY_MEMORY;
|
||||
else if (strcmp(cat_name, "timing") == 0) cat = DEBUG_CATEGORY_TIMING;
|
||||
else if (strcmp(cat_name, "config") == 0) cat = DEBUG_CATEGORY_CONFIG;
|
||||
else if (strcmp(cat_name, "tun") == 0) cat = DEBUG_CATEGORY_TUN;
|
||||
else if (strcmp(cat_name, "routing") == 0) cat = DEBUG_CATEGORY_ROUTING;
|
||||
else if (strcmp(cat_name, "timers") == 0) cat = DEBUG_CATEGORY_TIMERS;
|
||||
else if (strcmp(cat_name, "normalizer") == 0) cat = DEBUG_CATEGORY_NORMALIZER;
|
||||
else if (strcmp(cat_name, "bgp") == 0) cat = DEBUG_CATEGORY_BGP;
|
||||
else if (strcmp(cat_name, "socket") == 0) cat = DEBUG_CATEGORY_SOCKET;
|
||||
else if (strcmp(cat_name, "control") == 0) cat = DEBUG_CATEGORY_CONTROL;
|
||||
else if (strcmp(cat_name, "dump") == 0) cat = DEBUG_CATEGORY_DUMP;
|
||||
|
||||
if (cat) {
|
||||
debug_level_t lvl = DEBUG_LEVEL_NONE;
|
||||
if (strcmp(lvl_str, "error") == 0) lvl = DEBUG_LEVEL_ERROR;
|
||||
else if (strcmp(lvl_str, "warn") == 0) lvl = DEBUG_LEVEL_WARN;
|
||||
else if (strcmp(lvl_str, "info") == 0) lvl = DEBUG_LEVEL_INFO;
|
||||
else if (strcmp(lvl_str, "debug") == 0) lvl = DEBUG_LEVEL_DEBUG;
|
||||
else if (strcmp(lvl_str, "trace") == 0) lvl = DEBUG_LEVEL_TRACE;
|
||||
|
||||
debug_set_category_level(cat, lvl);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Applied per-category debug: %s=%s", cat_name, lvl_str);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate instance
|
||||
struct UTUN_INSTANCE *instance = calloc(1, sizeof(struct UTUN_INSTANCE));
|
||||
if (!instance) {
|
||||
@@ -252,7 +289,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
|
||||
// Delete system routes added at startup
|
||||
if (instance->tun->ifindex && instance->route_subnets) {
|
||||
int deleted = tun_route_del_all(instance->tun->ifindex, instance->route_subnets);
|
||||
int deleted = tun_route_del_all(instance->tun->ifindex, instance->tun->ifname, instance->route_subnets);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Deleted %d system routes for TUN interface", deleted);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user