diff options
-rw-r--r-- | src/addr.c | 49 | ||||
-rw-r--r-- | src/addr.h | 13 | ||||
-rw-r--r-- | src/blob.c | 22 | ||||
-rw-r--r-- | src/blob.h | 3 | ||||
-rw-r--r-- | src/squark-auth-snmp.c | 30 |
5 files changed, 101 insertions, 16 deletions
@@ -13,14 +13,22 @@ int addr_len(const sockaddr_any *addr) } } -sockaddr_any *addr_parse(blob_t b, sockaddr_any *addr) +sockaddr_any *addr_parse_prefix(blob_t b, sockaddr_any *addr, uint8_t *prefix_len) { memset(addr, 0, sizeof(*addr)); - addr->ipv4.sin_family = AF_INET; - addr->ipv4.sin_addr.s_addr = blob_inet_addr(b); - if (addr->ipv4.sin_addr.s_addr == -1) - return NULL; - return addr; + + if (blob_pull_inet_addr(&b, &addr->ipv4.sin_addr)) { + addr->ipv4.sin_family = AF_INET; + if (blob_pull_matching(&b, BLOB_STR("/"))) { + if (prefix_len == NULL) + return NULL; + *prefix_len = blob_pull_uint(&b, 10); + } + if (b.len != 0) + return NULL; + return addr; + } + return NULL; } unsigned long addr_hash(const sockaddr_any *addr) @@ -72,3 +80,32 @@ void addr_push_hostaddr(blob_t *b, const sockaddr_any *addr) } blob_push(b, f); } + +static int bitcmp(const uint8_t *a, const uint8_t *b, int len) +{ + int bytes, bits, mask, r; + + bytes = len / 8; + bits = len % 8; + + if (bytes != 0) { + r = memcmp(a, b, bytes); + if (r != 0) + return r; + } + if (bits != 0) { + mask = (0xff << (8 - bits)) & 0xff; + return ((int) (a[bytes] & mask)) - ((int) (b[bytes] & mask)); + } + return 0; +} + +int addr_prefix_cmp(const sockaddr_any *a, const sockaddr_any *b, int prefix) +{ + if (a->any.sa_family != b->any.sa_family) + return a->any.sa_family - b->any.sa_family; + + return bitcmp((const uint8_t *) &a->ipv4.sin_addr.s_addr, + (const uint8_t *) &b->ipv4.sin_addr.s_addr, + prefix); +} @@ -10,11 +10,22 @@ typedef union { } sockaddr_any; int addr_len(const sockaddr_any *addr); -sockaddr_any *addr_parse(blob_t text, sockaddr_any *addr); +sockaddr_any *addr_parse_prefix(blob_t text, sockaddr_any *addr, uint8_t *prefix); unsigned long addr_hash(const sockaddr_any *addr); const char *addr_print(const sockaddr_any *addr); blob_t addr_get_hostaddr_blob(const sockaddr_any *addr); void addr_push_hostaddr(blob_t *b, const sockaddr_any *addr); +int addr_prefix_cmp(const sockaddr_any *a, const sockaddr_any *b, int prefix); + +static inline void addr_invalidate(sockaddr_any *addr) +{ + addr->any.sa_family = AF_UNSPEC; +} + +static inline sockaddr_any *addr_parse(blob_t b, sockaddr_any *addr) +{ + return addr_parse_prefix(b, addr, NULL); +} static inline void addr_copy(sockaddr_any *dst, const sockaddr_any *src) { @@ -139,23 +139,31 @@ int blob_icmp(blob_t a, blob_t b) return strncasecmp(a.ptr, b.ptr, a.len); } -unsigned long blob_inet_addr(blob_t b) +int blob_pull_inet_addr(blob_t *b, struct in_addr *saddr) { unsigned long ip = 0; int i; for (i = 0; i < 3; i++) { - ip += blob_pull_uint(&b, 10); + ip += blob_pull_uint(b, 10); ip <<= 8; - if (!blob_pull_matching(&b, BLOB_STR("."))) + if (!blob_pull_matching(b, BLOB_STR("."))) return 0; } - ip += blob_pull_uint(&b, 10); - if (b.len != 0) - return 0; - return htonl(ip); + ip += blob_pull_uint(b, 10); + saddr->s_addr = htonl(ip); + return 1; } +unsigned long blob_inet_addr(blob_t b) +{ + struct in_addr saddr; + + if (blob_pull_inet_addr(&b, &saddr) && b.len == 0) + return saddr.s_addr; + + return 0; +} blob_t blob_pushed(blob_t buffer, blob_t left) { @@ -3,6 +3,8 @@ #include <string.h> +struct in_addr; + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #if defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ < 96 @@ -56,6 +58,7 @@ int blob_pull_matching(blob_t *b, blob_t e); unsigned int blob_pull_uint(blob_t *b, int radix); blob_t blob_pull_spn(blob_t *b, const blob_t spn); blob_t blob_pull_cspn(blob_t *b, const blob_t cspn); +int blob_pull_inet_addr(blob_t *b, struct in_addr *saddr); blob_t blob_expand_head(blob_t *b, blob_t limits, unsigned char sep); blob_t blob_expand_tail(blob_t *b, blob_t limits, unsigned char sep); diff --git a/src/squark-auth-snmp.c b/src/squark-auth-snmp.c index 90a908b..2ac1a7f 100644 --- a/src/squark-auth-snmp.c +++ b/src/squark-auth-snmp.c @@ -125,6 +125,9 @@ static int username_format_flags; static const blob_t space = BLOB_STR_INIT(" "); static const blob_t lf = BLOB_STR_INIT("\n"); +static sockaddr_any management_subnet; +static uint8_t management_prefix = 0; + /* ----------------------------------------------------------------- */ #define BLOB_OID(objid) BLOB_BUF(objid) @@ -366,7 +369,7 @@ struct switch_info *get_switch(sockaddr_any *addr) config.community = (unsigned char *) snmp_community; config.community_len = strlen(snmp_community); } - config.peername = (char *) addr_print(addr); + config.peername = strdup((char *) addr_print(addr)); si->session = snmp_open(&config); si->next = all_switches[bucket]; @@ -717,6 +720,7 @@ static int auth_handle_portinfo_reply(int oper, netsnmp_session *s, int reqid, n snprintf(auth->status_msg, sizeof(auth->status_msg)-1, "required info missing: info_available=%08x", auth->info_available); + dbg_printf("%s\n", auth->status_msg); done: if (kick_out && auth_ok(auth)) @@ -764,6 +768,8 @@ static void auth_query_port_info(struct auth_context *auth) snprintf(auth->status_msg, sizeof(auth->status_msg)-1, "%s: query port info (%d)", si->session->peername, auth->local_port); + dbg_printf("%s\n", auth->status_msg); + auth_talk_snmp(auth, si->session, pdu, auth_handle_portinfo_reply); } @@ -793,6 +799,16 @@ static int auth_handle_lldp_reply(int oper, netsnmp_session *s, int reqid, netsn /* We have mathing LLDP neighbor */ blob_pull_oid(&res); blob_pull_iana_afn(&res, &spi->link_partner); + + dbg_printf("%s: lldp neighbour is %s\n", + s->peername, addr_print(&spi->link_partner)); + + if (management_prefix != 0 && + addr_prefix_cmp(&spi->link_partner, &management_subnet, management_prefix) != 0) { + dbg_printf("%s: not matching %s/%d\n", + s->peername, addr_print(&management_subnet), management_prefix); + addr_invalidate(&spi->link_partner); + } cache_update(&spi->cache_control); return 1; } @@ -1013,6 +1029,7 @@ static void auth_query_switch_info(struct auth_context *auth) snprintf(auth->status_msg, sizeof(auth->status_msg)-1, "%s: refresh switch information", si->session->peername); + dbg_printf("%s\n", auth->status_msg); if (!cache_refresh(&si->cache_control, auth, auth_query_fib)) return; @@ -1020,6 +1037,7 @@ static void auth_query_switch_info(struct auth_context *auth) snprintf(auth->status_msg, sizeof(auth->status_msg)-1, "%s: query switch information", si->session->peername); + dbg_printf("%s\n", auth->status_msg); pdu = snmp_pdu_create(SNMP_MSG_GET); snmp_add_null_var(pdu, oid_const(SNMPv2_MIB_sysName)); @@ -1090,6 +1108,8 @@ void start_authentication(blob_t token, blob_t ip) "%s: map IP %s to MAC on VLAN %d", l3_root_dev->session->peername, addr_print(&auth->addr), l3_if_ndx); + dbg_printf("%s\n", auth->status_msg); + auth_talk_snmp(auth, l3_root_dev->session, pdu, auth_handle_arp_reply); } @@ -1172,7 +1192,7 @@ int main(int argc, char **argv) init_snmp("squark-auth-snmp"); openlog("squark-auth-snmp", LOG_PID, LOG_DAEMON); - while ((opt = getopt(argc, argv, "Vc:r:i:R:v:f:T:Ks")) != -1) { + while ((opt = getopt(argc, argv, "Vc:r:i:R:v:f:T:KsM:")) != -1) { switch (opt) { case 'V': fprintf(stderr, "squark-auth-snmp %s\n", squark_version); @@ -1204,6 +1224,12 @@ int main(int argc, char **argv) case 's': do_syslog = TRUE; break; + case 'M': + if (!addr_parse_prefix(BLOB_STRLEN(optarg), &management_subnet, &management_prefix)) { + fprintf(stderr, "'%s' is not a valid network prefix\n", optarg); + return 1; + } + break; } } argc -= optind; |