#include #include #include #include #include "netswitch.h" #include "sys.h" #include "elog.h" #include "thread.h" #include "cfg.h" #include "lock.h" #include "mail.h" #include "sqlite_handle.h" #include "mqtt.h" #if 1 #define LOGD log_d #define LOGE log_e #define LOGW log_w #else #define LOGD printf #define LOGE printf #define LOGW printf #endif #define SW_PORT_START 99329 #define NETSNMP_DS_APP_DONT_FIX_PDUS 0 #ifdef USE_NETSWITCH typedef struct { netswitch_info_t sw; netswitch_info_t sw2; int ipflag; char host_ip[64]; char local_ip[64]; int port_start; pthread_mutex_t mutex; }ns_handle_t; static ns_handle_t nsHandle; static char *get_string(netsnmp_variable_list *var); /////////////////////////////////////////////////////////// static netsnmp_variable_list* snmp_getx(int version, char *community, char *ip, char *oid_str, int msgtype) { int count; oid name[MAX_OID_LEN]; size_t namelen=MAX_OID_LEN; int status; netsnmp_pdu *pdu=NULL,*rsp=NULL; netsnmp_session session,*ss=NULL; netsnmp_variable_list *vars=NULL,*pvar=NULL; snmp_sess_init(&session); //session.timeout = 500000; //us session.version = version; session.peername = ip; session.community = (unsigned char*)community; session.community_len = strlen(community); oid *poid = snmp_parse_oid(oid_str, name, &namelen); if(poid==NULL) { LOGE("___snmp_parse_oid %s failed\n", oid_str); goto out; } ss = snmp_open(&session); if (ss == NULL) { LOGE("___snmp_open failed\n"); goto out; } pdu = snmp_pdu_create(msgtype); if(!pdu) { LOGE("___snmp_pdu_create failed\n"); goto quit; } if(msgtype==SNMP_MSG_GETBULK) { pdu->errstat = 0;//non_repeaters; pdu->errindex = 10;//max_repetitions; } snmp_add_null_var(pdu, name, namelen); retry: status = snmp_synch_response(ss, pdu, &rsp); if (status == STAT_SUCCESS && rsp) { if (rsp->errstat == SNMP_ERR_NOERROR) { pvar = snmp_clone_varbind(rsp->variables); } else { LOGE("___error in packet, reason: %s\n", snmp_errstring(rsp->errstat)); if (rsp->errindex != 0) { fprintf(stderr, "failed object: "); for (count = 1, vars = rsp->variables; vars && count != rsp->errindex; vars = vars->next_variable, count++) { if (vars) { fprint_objid(stderr, vars->name, vars->name_length); } } fprintf(stderr, "\n"); } //retry if the errored variable was successfully removed if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_APP_DONT_FIX_PDUS)) { pdu = snmp_fix_pdu(rsp, SNMP_MSG_GET); snmp_free_pdu(rsp); rsp = NULL; if (pdu != NULL) { goto retry; } } } } else if (status == STAT_TIMEOUT) { LOGE("snmp_getx timeout: no response from %s\n", session.peername); } else { /* status == STAT_ERROR */ snmp_sess_perror("snmp_getx", ss); } if (rsp) { snmp_free_pdu(rsp); } quit: snmp_close(ss); out: return pvar; } /* SNMP_VERSION_1 SNMP_VERSION_2c SNMP_VERSION_3 SNMP_MSG_GET SNMP_MSG_GETNEXT SNMP_MSG_GETBULK SNMP_MSG_INFORM SNMP_MSG_SET 1.get:获取一个指定OID的信息; 2.getnext:指定最终节点的上一层,获取该层及以下子类的信息; 3.getbulk:和getnext类似,但是getnext只能指定最终层的父节点,而getbulk没有限制; 4.set:向对方发起控制指令; 5.getresponse:获取回应; */ static netsnmp_variable_list* snmp_get(int version, char *community, char *ip, char *oid) { return snmp_getx(version, community, ip, oid, SNMP_MSG_GET); } static netsnmp_variable_list* snmp_getnext(int version, char *community, char *ip, char *oid) { return snmp_getx(version, community, ip, oid, SNMP_MSG_GETNEXT); } static netsnmp_variable_list* snmp_getbulk(int version, char *community, char *ip, char *oid) { return snmp_getx(version, community, ip, oid, SNMP_MSG_GETBULK); } typedef struct { char chr[2]; }seg_t; typedef struct { int cnt; seg_t seg[20]; }mac_data_t; static void trim_space(char *ss) { while(*ss) ss++; ss--; while((*ss)==' ') {*ss=0; ss--;}; } static int parse_mac(char *ss, mac_data_t *mac) { char sp=0; int i=0,j=0,idx=0; if(strstr(ss, "-")) { sp = '-'; } else if(strstr(ss, " ")) { sp = ' '; } else if(strstr(ss, ":")) { sp = ':'; } else { LOGE("___ wrong mac addr\n"); return -1; } trim_space(ss); memset(mac, 0, sizeof(mac_data_t)); while(ss[i]) { if(ss[i]==sp) { idx++; j=0; } else { mac->seg[idx].chr[j++] = (char)toupper(ss[i]); } i++; } mac->cnt = idx+1; return 0; } static int get_mac(char *ss, char *mac) { int i,j,r; mac_data_t mdat; r = parse_mac(ss, &mdat); if(r) { return -1; } j = 0; for(i=0; iport[i]; if(strcmp(mac, pt->mac)==0) { break; } } return pt; } static char *get_string(netsnmp_variable_list *var) { u_char *buf=NULL; size_t buflen=256,outlen=0; buf = calloc(buflen, 1); if(!buf) { LOGE("___ calloc failed\n"); return NULL; } if (sprint_realloc_variable(&buf, &buflen, &outlen, 1, var->name, var->name_length, var)) { return (char*)buf; } else { free(buf); } return NULL; } static int get_ipaddr(int family, char *iface, char *host, char *local) { int r=-1; char temp[100]; struct ifaddrs *ifap, *ifa; if (getifaddrs(&ifap) == -1) { LOGE("___getifaddrs() error\n"); return -1; } for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr != NULL && ifa->ifa_addr->sa_family == family) { if(family==AF_INET) { struct sockaddr_in *sa,*msk; sa = (struct sockaddr_in *) ifa->ifa_addr; msk = (struct sockaddr_in *) ifa->ifa_netmask; char *p = (char*)inet_ntop(family, &sa->sin_addr, temp, INET6_ADDRSTRLEN); if(p) { //printf("___ipv4: %s\n", p); if(strcmp(p, "127.0.0.1") && strcmp(p, "172.17.0.1")) { strcpy(host, p); strcpy(local, p); p = strrchr(host, '.'); p[1] = '1'; p[2] = 0; r = 0; break; } } } else { struct sockaddr_in6 *sa,*msk; sa = (struct sockaddr_in6 *)ifa->ifa_addr; msk = (struct sockaddr_in6 *)ifa->ifa_netmask; char *p = (char*)inet_ntop(family, &sa->sin6_addr, temp, INET6_ADDRSTRLEN); if(p) { //printf("___ipv6: %s\n", p); if(strcmp(p, "::1")) { strcpy(host, p); strcpy(local, p); p = strrchr(host, ':'); p[1] = '1'; p[2] = 0; r = 0; break; } } } } } freeifaddrs(ifap); return r; } static void sw_init(netswitch_info_t *sw) { int i; memset(sw, 0, sizeof(netswitch_info_t)); for(i=0; iport[i].id = -1; } } static void sw_init2(netswitch_info_t *sw) { int i; memset(sw, 0, sizeof(netswitch_info_t)); for(i=0; iport[i].id = i; } } static void sw_sync_mac_by_id(netswitch_info_t *dst, netswitch_info_t *src) { int i,id; for(i=0; iport[i].id; if(src->port[i].id != -1) { strcpy(dst->port[id].mac, src->port[i].mac); } } } static int get_id_by_mac(netswitch_info_t *sw, port_info_t *pt) { int i; if(pt->mac[0]==0) { return -1; } for(i=0; iport[i].mac, pt->mac)==0) { return i; } } return -1; } static void sw_sync_ip_by_mac(netswitch_info_t *dst, netswitch_info_t *src) { int i,id; for(i=0; iport[i]); if(id>=0) { strcpy(dst->port[id].ip, src->port[i].ip); } } } static void sw_print(char *s, netswitch_info_t *sw) { int i,id,flag=0; port_info_t *pt=NULL; for(i=0; iport[i]; if(pt->id>=0 && (pt->ip[0] || pt->mac[0])) { LOGD("__%s__, port[%d].id: %d\n", s, i+1, pt->id); LOGD("__%s__, port[%d].up: %d\n", s, i+1, pt->up); LOGD("__%s__, port[%d].ip: %s\n", s, i+1, pt->ip); LOGD("__%s__, port[%d].mac: %s\n", s, i+1, pt->mac); LOGD("__%s__, port[%d].desc: %s\n", s, i+1, pt->desc); flag = 1; } } if(flag) LOGD("\n"); } /* public BRIDGE-MIB dot1dTpFdbEntry: 1.3.6.1.2.1.17.4.3.1 1: dot1dTpFdbAddress - MacAddress(4 - octets) 2: dot1dTpFdbPort - Integer32(2 - int, int32) 3: dot1dTpFdbStatus - INTEGER(2 - int, int32) private tplink-ipAddr.mib public RFC1213-MIB ipNetToMediaEntry: 1.3.6.1.2.1.4.22.1 1: ipNetToMediaIfIndex - INTEGER(2 - integer (32 bit)) 2: ipNetToMediaPhysAddress - PhysAddress(4 - octets) 3: ipNetToMediaNetAddress - IpAddress(64 - IP address) 4: ipNetToMediaType - INTEGER(2 - integer (32 bit)) ipAddrEntry: 1.3.6.1.2.1.4.20.1 //host ipaddr 1: ipAdEntAddr - IpAddress(64 - IP address) 2: ipAdEntIfIndex - INTEGER(2 - integer (32 bit)) 3: ipAdEntNetMask - IpAddress(64 - IP address) 4: ipAdEntBcastAddr - INTEGER(2 - integer (32 bit)) 5: ipAdEntReasmMaxSize - INTEGER(2 - integer (32 bit)) ifEntry: 1.3.6.1.2.1.2.2.1 1: ifreIndex - INTEGER(2 - integer (32 bit)) 6: ifPhysAddress - PhysAddress(4 - octets) 8: ifOperStatus - INTEGER(2 - integer (32 bit)) No Such Instance currently exists at this OID: 1. MIB文件没有正确添加到MIB树里面,因此agent在收到查询以后真的找不到目标OID. 2. MIB文件添加成功了,但是snmpd.conf里面的关于权限的配置不对。agent在收到client的查询以后也找到了该OID, 但是因为没有权限因此返回“No Such Instance currently exists at this OID”。 关于权限粗看会以为很复杂,尤其是在心浮气燥的时候,其实静下心来仔细看看就会发现也就那么回事 3. 第三种情况比较特殊,对于net-snmp不熟的也可能会范理解上的错误。 使用snmpget而忘记了添加OID结尾的实例标识符,net-snmp则会报出“No Such Instance currently exists at this OID”的错误。 */ static int get_port_start(char *ip) { int port=-1,val; netsnmp_variable_list *var,*pvar; #ifdef SW_STATIC_PORT_START return SW_PORT_START; #endif char *ifEntry="1.3.6.1.2.1.2.2"; var = snmp_getbulk(SNMP_VERSION_2c, "public", ip, ifEntry); if(var) { int id; char *p,*tok="ifIndex."; for (pvar=var; pvar; pvar=pvar->next_variable) { char *pstr = get_string(pvar); if(pstr) { //LOGD("____5___%s\n", pstr); p = strstr(pstr, tok); if(p) { val = atoi(p+strlen(tok)); if(val>2) { port = val; } } free(pstr); if(port>1000) { LOGD("_____start port: %d\n", port); break; } } } snmp_free_varbind(var); } else { LOGE("___get_port_start, snmp_getnext %s failed\n", ifEntry); } return port; } static int get_hostnet(char *hnet, char *hip) { char *p=NULL; strcpy(hnet, hip); p = strrchr(hnet, '.'); if(!p) { p = strrchr(hnet, ':'); if(!p) { return -1; } } p[1] = '0'; p[2] = 0; return 0; } static int set_ip(char *ip) { char temp[200]; sprintf(temp, "ip addr add dev eth0 %s/24", ip); return system(temp); } static int set_gw(char *gw) { char temp[200]; sprintf(temp, "route del default; route add default gw %s", gw); return system(temp); } static int sw_get(netswitch_info_t *sw) { int r=-1; int i,j,find=0; char temp[200]; char *p,*pstr,*tok; netswitch_info_t tmp; netsnmp_variable_list *var,*pvar; ns_handle_t *h=&nsHandle; sw_init2(sw); if(h->ipflag==0) { #ifdef SW_STATIC_IP char hnet[100]; strcpy(h->host_ip, SW_HOST_IP); //get_hostnet(hnet, h->host_ip); //sprintf(temp, "ip addr add dev eth0 %s/24; ip route add %s/24 via %s", SW_PDU_IP, hnet, h->host_ip); //set_ip(SW_PDU_IP); set_gw(h->host_ip); h->ipflag = 1; #else r = get_ipaddr(AF_INET, "eth0", h->host_ip, h->local_ip); if(r) { LOGE("____get ip4 failed\n"); r = get_ipaddr(AF_INET6, "eth0", h->host_ip, h->local_ip); if(r) { LOGE("____get ip6 failed\n"); return -1; } } #if 0 if((p=strrchr(h->local_ip, '.')) || (p=strrchr(h->local_ip, ':'))) { if(strstr(p, "132")==0) { p[1] = 0; strcat(p, "132"); set_ip(h->local_ip); } } #endif set_gw(h->host_ip); h->ipflag = 1; #endif } //LOGD("___netswitch ip: %s\n", h->host_ip); if(h->port_start==-1) { h->port_start = get_port_start(h->host_ip); if(h->port_start==-1) { return -1; } } #if 1 char *dot1dTpFdbEntryOid="1.3.6.1.2.1.17.4.3.1"; var = snmp_getbulk(SNMP_VERSION_2c, "public", h->host_ip, dot1dTpFdbEntryOid); if(var) { sw_init(&tmp); i = j = 0; for (pvar=var; pvar!=NULL; pvar=pvar->next_variable) { char *pstr = get_string(pvar); if(pstr) { //LOGD("__1__%s\n", pstr); if(strstr(pstr, "2.17.4.3.1.1") || strstr(pstr, "3.6.1.2.1.17.4.3.1.1")) { //mac tok = "Hex-STRING: "; p = strstr(pstr, tok); if(p) { p += strlen(tok); get_mac(p, tmp.port[i].mac); //LOGD("____%d___mac: %s\n", i, tmp.port[i].mac); i++; } } if(strstr(pstr, "2.17.4.3.1.2") || strstr(pstr, "3.6.1.2.1.17.4.3.1.2")) { //port tok = "INTEGER: "; p = strstr(pstr, tok); if(p) { p += strlen(tok); tmp.port[j].id = atoi(p) - h->port_start; //LOGD("____%d___id: %s, port_start: %d, id: %d\n", j, p, h->port_start, tmp.port[j].id); j++; } } free(pstr); } } snmp_free_varbind(var); if(j>0) { sw_sync_mac_by_id(sw, &tmp); find = 1; } } else { LOGE("___snmp_getbulk mac failed\n"); } if(find==0) { return -1; } #endif #if 1 char *ipNetToMediaEntryOid="1.3.6.1.2.1.4.22.1"; var = snmp_getbulk(SNMP_VERSION_2c, "public", h->host_ip, ipNetToMediaEntryOid); if(var) { sw_init(&tmp); i = j = 0; for (pvar=var; pvar; pvar=pvar->next_variable) { pstr = get_string(pvar); if(pstr) { //LOGD("__2__%s\n", pstr); if(strstr(pstr, "ipNetToMediaPhysAddress")) { //mac addr tok = "STRING: "; p = strstr(pstr, tok); if(p) { p += strlen(tok); get_mac(p, tmp.port[i].mac); //LOGD("__%d__%s\n", i, tmp.port[i].mac); i++; } } else { tok = "3.6.1.2.1.4.22.1.2."; p = strstr(pstr, tok); if(p) { char *tok1 = " ="; char *tok2 = "Hex-STRING: "; p += strlen(tok); p = strstr(p, ".")+1; char *p1=strstr(p, tok1); char *p2=strstr(p, tok2); if(p1 && p2) { memcpy(tmp.port[i].ip, p, p1-p); tmp.port[i].ip[p1-p] = 0; p2 += strlen(tok2); get_mac(p2, tmp.port[i].mac); LOGD("__%d__ %s, %s\n", i, tmp.port[i].mac, tmp.port[i].ip); i++; } } } if(strstr(pstr, "ipNetToMediaNetAddress")) { //ip addr tok = "IpAddress: "; char *p=strstr(pstr, tok); if(p) { p += strlen(tok); strcpy(tmp.port[j].ip, p); //LOGD("__%d__ %s\n", j, p); j++; } } free(pstr); } } snmp_free_varbind(var); if(i>0) { sw_sync_ip_by_mac(sw, &tmp); //sw_print("11", sw); } } else { LOGE("___snmp_getbulk ip addr failed\n"); } #endif #if 0 char *ifEntry="1.3.6.1.2.1.2.2.1.8"; for(i=0; iport_start); var = snmp_get(SNMP_VERSION_2c, "public", h->host_ip, temp); if(var) { int id; tok = "ifOperStatus."; for (pvar=var; pvar; pvar=pvar->next_variable) { pstr = get_string(pvar); if(pstr) { //LOGD("__3__%s\n", pstr); p = strstr(pstr, tok); if(!p) { //ip addr tok = "INTEGER: "; p = strstr(pstr, tok); if(p) { p += strlen(tok); id = atoi(p)-h->port_start; if(strstr(p, "up")) { sw->port[id].up = 1; } else if(strstr(p, "down")) { sw->port[id].up = 0; } j++; } } free(pstr); } } snmp_free_varbind(var); } else { LOGE("___snmp_get ifup failed\n"); } } //sw_print("111", sw); #endif return 0; } static int sw_chk(netswitch_info_t *sw1, netswitch_info_t *sw2, netswitch_evts_t *evts) { int i,flag=0; memset(evts, 0, sizeof(netswitch_evts_t)); for(i=0; iSW_PORT_INDEX_END) { continue; } #if 0 if(sw1->port[i].up != sw2->port[i].up) { if(sw2->port[i].up) { LOGD("____ port %d plug in\n", i+1); //evts->evt[i].cab = EVT_CAB_IN; } else { LOGD("____ port %d plug out\n", i+1); //evts->evt[i].cab = EVT_CAB_OUT; } //flag = 1; } if(strlen(sw2->port[i].ip) && strcmp(sw1->port[i].ip, sw2->port[i].ip)) { LOGD("____ port %d ip changed from: %s, to: %s\n", i+1, sw1->port[i].ip, sw2->port[i].ip); //evts->evt[i].dev = EVT_IP_CHG; //flag = 1; } #endif if(strlen(sw2->port[i].mac) && strcmp(sw1->port[i].mac, sw2->port[i].mac)) { LOGD("____ port %d mac changed from: %s, to: %s\n", i+1, sw1->port[i].mac, sw2->port[i].mac); evts->evt[i].dev = EVT_MAC_CHG; flag = 1; } } return flag; } static int sw_cpy(netswitch_info_t *dst, netswitch_info_t *src) { int i; for(i=0; iSW_PORT_INDEX_END) { continue; } dst->port[i].up = src->port[i].up; if(src->port[i].ip[0]) { strcpy(dst->port[i].ip, src->port[i].ip); } if(src->port[i].mac[0]) { strcpy(dst->port[i].mac, src->port[i].mac); } } return 0; } static sqlite3* get_db(void) { return __globalDeviceManage.db; } static int get_prod_id(void) { return __globalDeviceManage._globalDevInfo.product.id; } static int sw_save(sqlite3 *db, netswitch_info_t *old, netswitch_info_t *new) { int i; for(i=0; iSW_PORT_INDEX_END) { continue; } if(memcmp(&old->port[i], &new->port[i], sizeof(netswitch_info_t))) { dev_switch_update_port(db, &new->port[i]); //LOGD("____ i: %d, id: %d\n", i, new->port[i].id); } } return 0; } static int sw_alarm(netswitch_evts_t *evts, netswitch_info_t *old, netswitch_info_t *new) { int r=-1; int i,flag=0; time_t now; char temp[400]; char time_str[100]; char alarm_str[4000]; time(&now); strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&now)); alarm_str[0] = 0; for(i=0; ievt[i].dev) { if(evts->evt[i].dev==EVT_MAC_CHG) { //snprintf(temp, sizeof(temp), "port[%d] mac changed from %s to %s\n", i+1, old->port[i].mac, new->port[i].mac); sprintf(temp, "|$%s$|, |$%s$|%d %s -> %s\n", language_alarm_MAC_changed[0], language_alarm_Ch[0], i+1, old->port[i].mac, new->port[i].mac); strcat(alarm_str, temp); flag = 1; } } } if(flag) { r = dev_insert_alarm_info(get_db(), get_prod_id(), 2, time_str, alarm_str); smtp_post_alarm(ALARM_TYPE_NETWORK, 0, NETWORK_MAC_CHANGED, alarm_str); alarm_para_t para; para.id = i+1; para.nalarm = 1; para.action = -1; para.actionId = -1; mqtt_post_alarm(ALARM_TYPE_NETWORK, 0, alarm_str, ¶); } return r; } #endif static void* netswitch_thread(void *arg) { #ifdef USE_NETSWITCH int r; netswitch_evts_t evts; thread_handle_t *h=(thread_handle_t*)arg; ns_handle_t *nh=(ns_handle_t*)h->arg; nh->sw2 = nh->sw; SOCK_STARTUP; while(h->quit==0) { pthread_mutex_lock(&nh->mutex); r = sw_get(&nh->sw2); pthread_mutex_unlock(&nh->mutex); if(r==0 && sw_chk(&nh->sw, &nh->sw2, &evts)) { sw_alarm(&evts, &nh->sw, &nh->sw2); sw_save(get_db(), &nh->sw, &nh->sw2); sw_cpy(&nh->sw, &nh->sw2); } sleep(1); } SOCK_CLEANUP; #endif pthread_exit(NULL); } int netswitch_init(void) { #ifdef USE_NETSWITCH ns_handle_t *h=&nsHandle; memset(h, 0, sizeof(ns_handle_t)); h->port_start = -1; //SW_PORT_START dev_switch_init(get_db(), &h->sw); pthread_mutex_init(&h->mutex, NULL); thread_start(THREAD_ID_SWITCH, netswitch_thread, h); #endif return 0; } int netswitch_deinit(void) { #ifdef USE_NETSWITCH ns_handle_t *h=&nsHandle; thread_stop(THREAD_ID_SWITCH); pthread_mutex_destroy(&h->mutex); #endif return 0; } int netswitch_get(netswitch_info_t *info) { #ifdef USE_NETSWITCH ns_handle_t *h=&nsHandle; if(!info) { return -1; } pthread_mutex_lock(&h->mutex); *info = h->sw2; pthread_mutex_unlock(&h->mutex); #endif return 0; }