From 604378a88fc348718b01e5ce8a3a77cf976a7065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Tue, 19 Jul 2011 13:02:51 +0300 Subject: auth-snmp: implement Q-BRIDGE-MIB FIB queries Certain switches seem to export FIB of tagged VLANs only in the Q-BRIDGE-MIB only. Detect if switch support Q-BRIDGE-MIB during information discovery, and prefer it over the older BRIDGE-MIB. Q-BRIDGE-MIB should be used anyway, since it's the only reliable way to trace MAC properly when it appears in multiple VLANs. --- src/squark-auth-snmp.c | 75 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/src/squark-auth-snmp.c b/src/squark-auth-snmp.c index f6e8d5b..d9631a0 100644 --- a/src/squark-auth-snmp.c +++ b/src/squark-auth-snmp.c @@ -2,7 +2,7 @@ * An external acl helper for Squid which collects authentication * information about an IP-address from switches via SNMP. * - * Copyright (C) 2010 Timo Teräs + * Copyright (C) 2010-2011 Timo Teräs * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -11,7 +11,6 @@ */ /* TODO: - * - implement Q-BRIDGE-MIB query * - map vlan names to vlan index * - print some usage information * - poll lldpStatsRemTablesLastChangeTime when doing switch update @@ -33,6 +32,12 @@ #include "authdb.h" #include "filterdb.h" +#if 0 +#define dbg_printf(args...) printf(args) +#else +#define dbg_printf(args...) +#endif + /* Compile time configurables */ #define SWITCH_HASH_SIZE 128 #define PORT_HASH_SIZE 128 @@ -56,8 +61,9 @@ #define FORMAT_PORT_WEBAUTH 0x80 /* %w */ /* Some info about the switch which we need */ -#define SWITCHF_NO_LLDP 0x01 -#define SWITCHF_BRIDGE_MIB_HAS_VLAN 0x02 +#define SWITCHF_NO_LLDP_MIB 0x01 +#define SWITCHF_NO_Q_BRIDGE_MIB 0x02 +#define SWITCHF_BRIDGE_MIB_HAS_VLAN 0x04 /* IANA-AddressFamilyNumbers */ #define IANA_AFN_OTHER 0 @@ -81,6 +87,10 @@ static const oid IP_MIB_ipNetToPhysicalPhysAddress[] = { SNMP_OID_MIB2, 4, 35, 1, 4 }; static const oid BRIDGE_MIB_dot1dTpFdbPort[] = { SNMP_OID_MIB2, 17, 4, 3, 1, 2 }; +static const oid Q_BRIDGE_MIB_dot1qVlanVersionNumber_0[] = + { SNMP_OID_MIB2, 17, 7, 1, 1, 1, 0 }; +static const oid Q_BRIDGE_MIB_dot1qTpFdbPort[] = + { SNMP_OID_MIB2, 17, 7, 1, 2, 2, 1, 2 }; static const oid LLDP_lldpLocSysName[] = { 1, 0, 8802, 1, 1, 2, 1, 3, 3, 0 }; static const oid LLDP_lldpRemManAddrIfSubtype[] = @@ -631,6 +641,9 @@ static blob_t var_parse_type(netsnmp_variable_list **varptr, int asn_tag) if (var->type != asn_tag) return BLOB_NULL; + if (asn_tag == ASN_INTEGER) + return BLOB_PTR_LEN(var->val.integer, sizeof(*var->val.integer)); + return BLOB_PTR_LEN(var->val.string, var->val_len); } @@ -794,9 +807,7 @@ static void auth_query_lldp(struct auth_context *auth, int root_query) blob_t query; int i; - /* printf("Query LLDP info for %s:%d\n", addr_print(&si->addr), spi->port); */ - - if (si->flags & SWITCHF_NO_LLDP) { + if (si->flags & SWITCHF_NO_LLDP_MIB) { memset(&spi->link_partner, 0, sizeof(spi->link_partner)); cache_update(&spi->cache_control); return; @@ -833,8 +844,11 @@ static void auth_query_lldp(struct auth_context *auth, int root_query) } snprintf(auth->status_msg, sizeof(auth->status_msg)-1, - "%s: query LLDP tables (%s)", - si->session->peername, root_query ? "link" : "lacp slaves"); + "%s: query LLDP tables (%s, base port %d)", + si->session->peername, root_query ? "link" : "lacp slaves", + auth->lldp_port[0]); + dbg_printf("%s\n", auth->status_msg); + cache_talk_snmp(&spi->cache_control, si->session, pdu, auth_handle_lldp_reply, auth); } @@ -888,24 +902,30 @@ static void auth_query_fib(struct auth_context *auth) auth->info_available |= si->info_available; - /* printf("Probing switch %s\n", addr_print(&si->addr)); */ - pdu = snmp_pdu_create(SNMP_MSG_GET); - - /* FIXME: Implement Q-BRIDGE-MIB query too. */ - - /* BRIDGE-MIB::dot1dTpFdbPort. = INTEGER: port */ - query = BLOB_OID(query_oids); - blob_push(&query, BLOB_OID(BRIDGE_MIB_dot1dTpFdbPort)); - if (si->flags & SWITCHF_BRIDGE_MIB_HAS_VLAN) + if (si->flags & SWITCHF_NO_Q_BRIDGE_MIB) { + /* BRIDGE-MIB::dot1dTpFdbPort. = INTEGER: port */ + query = BLOB_OID(query_oids); + blob_push(&query, BLOB_OID(BRIDGE_MIB_dot1dTpFdbPort)); + if (si->flags & SWITCHF_BRIDGE_MIB_HAS_VLAN) + blob_push_oid(&query, l2_vlan_ndx); + blob_push_oid_dump(&query, BLOB_BUF(auth->mac)); + query = blob_pushed(BLOB_OID(query_oids), query); + snmp_add_null_var(pdu, oid_blob(query)); + } else { + /* Q-BRIDGE-MIB::dot1qTpFdbPort.. = INTEGER: port */ + query = BLOB_OID(query_oids); + blob_push(&query, BLOB_OID(Q_BRIDGE_MIB_dot1qTpFdbPort)); blob_push_oid(&query, l2_vlan_ndx); - blob_push_oid_dump(&query, BLOB_BUF(auth->mac)); - query = blob_pushed(BLOB_OID(query_oids), query); - snmp_add_null_var(pdu, oid_blob(query)); - + blob_push_oid_dump(&query, BLOB_BUF(auth->mac)); + query = blob_pushed(BLOB_OID(query_oids), query); + snmp_add_null_var(pdu, oid_blob(query)); + } snprintf(auth->status_msg, sizeof(auth->status_msg)-1, - "%s: probe FIB", - si->session->peername); + "%s: probe FIB (%sBRIDGE-MIB)", + si->session->peername, + (si->flags & SWITCHF_NO_Q_BRIDGE_MIB) ? "" : "Q-"); + dbg_printf("%s\n", auth->status_msg); auth_talk_snmp(auth, si->session, pdu, auth_handle_fib_reply); } @@ -925,7 +945,9 @@ static int auth_handle_switch_info_reply(int oper, netsnmp_session *s, int reqid si->system_oid = blob_dup(var_parse_type(&var, ASN_OBJECT_ID)); si->system_version = blob_cstr_dup(var_parse_type(&var, ASN_OCTET_STR)); if (blob_is_null(var_parse_type(&var, ASN_OCTET_STR))) - si->flags |= SWITCHF_NO_LLDP; + si->flags |= SWITCHF_NO_LLDP_MIB; + if (blob_is_null(var_parse_type(&var, ASN_INTEGER))) + si->flags |= SWITCHF_NO_Q_BRIDGE_MIB; if (si->system_name) si->info_available |= FORMAT_SWITCH_NAME; if (si->system_location) @@ -975,6 +997,7 @@ static void auth_query_switch_info(struct auth_context *auth) snmp_add_null_var(pdu, oid_const(SNMPv2_MIB_sysObjectID)); snmp_add_null_var(pdu, oid_const(SEMI_MIB_hpHttpMgVersion)); snmp_add_null_var(pdu, oid_const(LLDP_lldpLocSysName)); + snmp_add_null_var(pdu, oid_const(Q_BRIDGE_MIB_dot1qVlanVersionNumber_0)); cache_talk_snmp(&si->cache_control, si->session, pdu, auth_handle_switch_info_reply, auth); } @@ -1151,7 +1174,7 @@ int main(int argc, char **argv) argv += optind; if (l3_root == NULL || l3_ifname == NULL || l2_vlan == NULL) { - printf("Mandatory information missing\n"); + fprintf(stderr, "Mandatory information missing\n"); return 1; } -- cgit v1.2.3