|
|
|
|
@ -227,6 +227,59 @@ static void socket_monitor_read_cb(int fd, void* arg) {
|
|
|
|
|
/* ===== FreeBSD: AF_ROUTE routing socket ===== */ |
|
|
|
|
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
|
|
|
|
|
|
|
|
|
static int sockaddr_to_plen(const struct sockaddr* sa) { |
|
|
|
|
if (!sa || sa->sa_len == 0) return 0; |
|
|
|
|
switch (sa->sa_family) { |
|
|
|
|
case AF_INET: { |
|
|
|
|
uint32_t m = ntohl(((const struct sockaddr_in*)sa)->sin_addr.s_addr); |
|
|
|
|
int bits = 0; |
|
|
|
|
while (bits < 32 && (m & 0x80000000)) { bits++; m <<= 1; } |
|
|
|
|
return bits; |
|
|
|
|
} |
|
|
|
|
case AF_INET6: { |
|
|
|
|
const uint8_t* a = ((const struct sockaddr_in6*)sa)->sin6_addr.s6_addr; |
|
|
|
|
int bits = 0; |
|
|
|
|
for (int i = 0; i < 16; i++) { |
|
|
|
|
if (a[i] == 0xff) { bits += 8; continue; } |
|
|
|
|
uint8_t b = a[i]; |
|
|
|
|
while (b & 0x80) { bits++; b <<= 1; } |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
return bits; |
|
|
|
|
} |
|
|
|
|
default: return 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void sa_to_str(const struct sockaddr* sa, char* buf, size_t bufsz) { |
|
|
|
|
if (!sa || sa->sa_len == 0) { snprintf(buf, bufsz, "?"); return; } |
|
|
|
|
switch (sa->sa_family) { |
|
|
|
|
case AF_INET: |
|
|
|
|
inet_ntop(AF_INET, &((const struct sockaddr_in*)sa)->sin_addr, buf, (socklen_t)bufsz); break; |
|
|
|
|
case AF_INET6: |
|
|
|
|
inet_ntop(AF_INET6, &((const struct sockaddr_in6*)sa)->sin6_addr, buf, (socklen_t)bufsz); break; |
|
|
|
|
default: snprintf(buf, bufsz, "?%d", sa->sa_family); break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* walk RTA sockaddrs after rtm header, extract addr, gw, plen */ |
|
|
|
|
static void bsd_parse_rtm(struct rt_msghdr* rtm, int mask, char* addr, size_t as, char* gw, size_t gs, int* plen) { |
|
|
|
|
struct sockaddr* sa = (struct sockaddr*)(rtm + 1); |
|
|
|
|
addr[0] = gw[0] = '\0'; *plen = 0; |
|
|
|
|
for (int i = 0, b = 1; i <= RTAX_MAX && mask; i++, b <<= 1) { |
|
|
|
|
if (!(mask & b)) continue; |
|
|
|
|
int sl = sa->sa_len ? (int)RT_ROUNDUP(sa->sa_len) : (int)sizeof(struct sockaddr); |
|
|
|
|
switch (i) { |
|
|
|
|
case RTAX_DST: sa_to_str(sa, addr, as); break; |
|
|
|
|
case RTAX_IFA: sa_to_str(sa, addr, as); break; |
|
|
|
|
case RTAX_GATEWAY: sa_to_str(sa, gw, gs); break; |
|
|
|
|
case RTAX_NETMASK: *plen = sockaddr_to_plen(sa); break; |
|
|
|
|
} |
|
|
|
|
mask &= ~b; |
|
|
|
|
sa = (struct sockaddr*)((char*)sa + sl); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void socket_monitor_bsd_read_cb(int fd, void* arg) { |
|
|
|
|
struct SOCKET_MONITOR* sm = (struct SOCKET_MONITOR*)arg; |
|
|
|
|
char buf[8192]; |
|
|
|
|
@ -267,17 +320,23 @@ static void socket_monitor_bsd_read_cb(int fd, void* arg) {
|
|
|
|
|
case RTM_DELADDR: { |
|
|
|
|
sm->addr_changes++; |
|
|
|
|
struct ifa_msghdr* ifam = (struct ifa_msghdr*)rtm; |
|
|
|
|
char ifname[IFNAMSIZ]; |
|
|
|
|
char ifname[IFNAMSIZ], addr[INET6_ADDRSTRLEN]; int plen; |
|
|
|
|
if (!if_indextoname(ifam->ifam_index, ifname)) snprintf(ifname, sizeof(ifname), "?"); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "addr %s: %s (idx=%u)", |
|
|
|
|
rtm->rtm_type == RTM_NEWADDR ? "NEW" : "DEL", ifname, ifam->ifam_index); |
|
|
|
|
bsd_parse_rtm(rtm, ifam->ifam_addrs, addr, sizeof(addr), NULL, 0, &plen); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "addr %s: %s/%d on %s (idx=%u)", |
|
|
|
|
rtm->rtm_type == RTM_NEWADDR ? "NEW" : "DEL", addr, plen, ifname, ifam->ifam_index); |
|
|
|
|
struct ETCP_SOCKET* es = sm->instance->etcp_sockets; |
|
|
|
|
while (es) { socket_monitor_fire_one(sm, es); es = es->next; } |
|
|
|
|
} break; |
|
|
|
|
case RTM_ADD: |
|
|
|
|
case RTM_DELETE: |
|
|
|
|
case RTM_DELETE: { |
|
|
|
|
sm->route_changes++; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "route %s:", rtm->rtm_type == RTM_ADD ? "ADD" : "DELETE"); |
|
|
|
|
char ifname[IFNAMSIZ], dst[INET6_ADDRSTRLEN], gw[INET6_ADDRSTRLEN]; int plen; |
|
|
|
|
if (!if_indextoname(rtm->rtm_index, ifname)) snprintf(ifname, sizeof(ifname), "?"); |
|
|
|
|
bsd_parse_rtm(rtm, rtm->rtm_addrs, dst, sizeof(dst), gw, sizeof(gw), &plen); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "route %s: %s/%d gw=%s dev=%s (idx=%u)", |
|
|
|
|
rtm->rtm_type == RTM_ADD ? "ADD" : "DELETE", |
|
|
|
|
dst[0] ? dst : "default", plen, gw, ifname, rtm->rtm_index); |
|
|
|
|
{ |
|
|
|
|
struct ETCP_SOCKET* es = sm->instance->etcp_sockets; |
|
|
|
|
while (es) { |
|
|
|
|
|