From b9d8cda84d8616e47e90029e183084dc8584e746 Mon Sep 17 00:00:00 2001 From: darkcoven Date: Sat, 26 Nov 2011 12:00:00 +0100 Subject: [PATCH] Added a dissector plugin for Wireshark. Added support for reading VLAN PVID values. Lib: setting IP TTL field to 1 to prevent packet routing. Lib: added a check on an incoming header. Lib: fixed value endianness. --- cli/commands.c | 43 +++++++++++ lib/ngadmin.h | 3 + lib/src/lib.h | 5 ++ lib/src/network.c | 12 ++- lib/src/ngadmin.c | 52 ++++++++++++- lib/src/protocol.c | 6 +- nsdp.lua | 187 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 301 insertions(+), 7 deletions(-) create mode 100644 nsdp.lua diff --git a/cli/commands.c b/cli/commands.c index a35b8bf..b26d2fd 100644 --- a/cli/commands.c +++ b/cli/commands.c @@ -1241,6 +1241,47 @@ static char vlan_char (int t) { } +static bool print_vlan_pvid (struct ngadmin *nga) { + + unsigned short *ports=NULL; + const struct swi_attr *sa; + int i; + bool ret=true; + + + sa=ngadmin_getCurrentSwitch(nga); + + ports=malloc(sa->ports*sizeof(unsigned short)); + i=ngadmin_getPVID(nga, ports); + if ( i!=ERR_OK ) { + printErrCode(i); + ret=false; + goto end; + } + + + printf("PVID: \n"); + printf("Port\t"); + for (i=1; i<=sa->ports; ++i) { + printf("%i\t", i); + } + putchar('\n'); + + printf("VLAN\t"); + for (i=0; iports; ++i) { + printf("%u\t", ports[i]); + } + putchar('\n'); + + + end: + free(ports); + + return ret; + +} + + static bool print_vlan_dot_adv (struct ngadmin *nga) { char buffer[512], *b=buffer; @@ -1306,6 +1347,8 @@ static bool do_vlan_show (int nb UNUSED, const char **com UNUSED, struct ngadmin case VLAN_DOT_ADV: printf("802.1Q advanced\n\n"); ret=print_vlan_dot_adv(nga); + putchar('\n'); + ret=print_vlan_pvid(nga); break; default: printf("unknown (%i)\n", t); diff --git a/lib/ngadmin.h b/lib/ngadmin.h index d0d61de..d7d6702 100644 --- a/lib/ngadmin.h +++ b/lib/ngadmin.h @@ -255,6 +255,9 @@ int ngadmin_getVLANType (struct ngadmin *nga, int *t) EXPORT; int ngadmin_getVLANDotConf (struct ngadmin *nga, char *buf, int *len) EXPORT; +// +int ngadmin_getPVID (struct ngadmin *nga, unsigned short *ports) EXPORT; + #endif diff --git a/lib/src/lib.h b/lib/src/lib.h index ecb5b71..3d47a89 100644 --- a/lib/src/lib.h +++ b/lib/src/lib.h @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -21,6 +22,10 @@ #define CODE_WRITE_REQ 3 #define CODE_WRITE_REP 4 +#define ERROR_READONLY 3 +#define ERROR_INVALID_VALUE 5 +#define ERROR_INVALID_PASSWORD 7 + #define ATTR_PRODUCT 0x0001 #define ATTR_UNK_0002 0x0002 #define ATTR_NAME 0x0003 diff --git a/lib/src/network.c b/lib/src/network.c index d976e3e..52837d0 100644 --- a/lib/src/network.c +++ b/lib/src/network.c @@ -60,6 +60,13 @@ int startNetwork (struct ngadmin *nga) { return ret; } + // prevent unicast packets from being routed + ret=1; + if ( (ret=setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret)))<0 ) { + perror("setsockopt(IP_TTL)"); + return ret; + } + return 0; @@ -232,7 +239,8 @@ int readRequest (struct ngadmin *nga, List *attr) { clearList(attr, (void(*)(void*))freeAttr); if ( i<0 || (i=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr))<0 ) { - ret=ERR_NET; + ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ; + goto end; } if ( err==0x0700 && attr_error==ATTR_PASSWORD ) { @@ -283,7 +291,7 @@ int writeRequest (struct ngadmin *nga, List *attr) { clearList(attr, (void(*)(void*))freeAttr); if ( i<0 || (i=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr))<0 ) { - ret=ERR_NET; + ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ; goto end; } diff --git a/lib/src/ngadmin.c b/lib/src/ngadmin.c index 1f32d09..3393080 100644 --- a/lib/src/ngadmin.c +++ b/lib/src/ngadmin.c @@ -1218,7 +1218,7 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, char *buf, int *len) { ListNode *ln; struct attr *at; struct swi_attr *sa; - int ret=ERR_OK, i; + int ret=ERR_OK, total, i; char *b=buf, *p=NULL; @@ -1229,6 +1229,9 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, char *buf, int *len) { } + total=*len; + *len=0; + attr=createEmptyList(); pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF)); if ( (ret=readRequest(nga, attr))!=ERR_OK ) { @@ -1239,7 +1242,7 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, char *buf, int *len) { for (ln=attr->first; ln!=NULL; ln=ln->next) { at=ln->data; p=at->data; - if ( (b-buf)+2+sa->ports>*len ) break; // no more room + if ( *len+2+sa->ports>total ) break; // no more room if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) { *(unsigned short*)b=ntohs(*(unsigned short*)p);b+=2; for (i=1; i<=sa->ports; ++i) { @@ -1247,11 +1250,10 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, char *buf, int *len) { else if ( (p[2]>>(sa->ports-i))&1 ) *b++=VLAN_UNTAGGED; // untagged else *b++=VLAN_NO; } + *len+=2+sa->ports; } } - *len=b-buf; - end: destroyList(attr, (void(*)(void*))freeAttr); @@ -1262,5 +1264,47 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, char *buf, int *len) { +// ------------------------------------------------------------- +int ngadmin_getPVID (struct ngadmin *nga, unsigned short *ports) { + + List *attr; + ListNode *ln; + struct attr *at; + struct swi_attr *sa; + int ret=ERR_OK; + char *p; + + + if ( nga==NULL || ports==NULL ) { + return ERR_INVARG; + } else if ( (sa=nga->current)==NULL ) { + return ERR_NOTLOG; + } + + + attr=createEmptyList(); + pushBackList(attr, newEmptyAttr(ATTR_VLAN_PVID)); + if ( (ret=readRequest(nga, attr))!=ERR_OK ) { + goto end; + } + + + for (ln=attr->first; ln!=NULL; ln=ln->next) { + at=ln->data; + p=at->data; + if ( at->attr==ATTR_VLAN_PVID && at->size>=3 && p[0]>=1 && p[0]<=sa->ports ) { + ports[p[0]-1]=htons(*(unsigned short*)&p[1]); + } + } + + + end: + destroyList(attr, (void(*)(void*))freeAttr); + + return ret; + +} + + diff --git a/lib/src/protocol.c b/lib/src/protocol.c index a342c96..d1be292 100644 --- a/lib/src/protocol.c +++ b/lib/src/protocol.c @@ -66,6 +66,10 @@ bool validateNgHeader (const struct ng_header *nh, char code, const struct ether return false; } + if ( memcmp(nh->proto_id, "NSDP", 4)!=0 ) { + return false; + } + if ( *(unsigned int*)nh->unk3!=0 ) { return false; } @@ -185,7 +189,7 @@ struct attr* newShortAttr (unsigned short attr, short value) { short *v=malloc(sizeof(short)); - *v=value; + *v=htons(value); return newAttr(attr, sizeof(short), v); diff --git a/nsdp.lua b/nsdp.lua new file mode 100644 index 0000000..11475ce --- /dev/null +++ b/nsdp.lua @@ -0,0 +1,187 @@ + +p_nsdp=Proto("nsdp", "Netgear Switch Description Protocol") +local f_version=ProtoField.uint8("nsdp.version", "Version", base.DEC) +local f_code=ProtoField.uint8("nsdp.code", "Operation Code", base.DEC) +local f_error=ProtoField.uint8("nsdp.error", "Error Code", base.DEC) +local f_errattr=ProtoField.uint16("nsdp.errattr", "Erroneous Attribute", base.HEX) +local f_clientmac=ProtoField.ether("nsdp.clientmac", "Client MAC") +local f_switchmac=ProtoField.ether("nsdp.switchmac", "Switch MAC") +local f_seqnum=ProtoField.uint32("nsdp.seqnum", "Sequence Number", base.DEC) + +local f_attr=ProtoField.uint16("", "Attribute", base.HEX) +local f_attr_code=ProtoField.uint16("", "Attribute Code", base.HEX) +local f_attr_length=ProtoField.uint16("", "Attribute Length", base.DEC) +local f_attr_data=ProtoField.bytes("", "Attribute Data") + +local f_attr_product=ProtoField.string("", "Product") +local f_attr_name=ProtoField.string("", "Name") +local f_attr_mac=ProtoField.ether("", "MAC") +local f_attr_ip=ProtoField.ipv4("", "IP") +local f_attr_mask=ProtoField.ipv4("", "Mask") +local f_attr_gateway=ProtoField.ipv4("", "Gateway") +local f_attr_newpassword=ProtoField.string("", "New Password") +local f_attr_password=ProtoField.string("", "Password") +local f_attr_dhcp=ProtoField.bool("", "DHCP") +local f_attr_firmver=ProtoField.string("", "Firmare Version") +local f_attr_portscount=ProtoField.uint8("", "Ports Count", base.DEC) +local f_attr_port=ProtoField.uint8("", "Port", base.DEC) +local f_attr_port_status=ProtoField.uint8("", "Port Status", base.DEC) + +p_nsdp.fields={ + f_version, f_code, f_error, f_errattr, f_clientmac, f_switchmac, f_seqnum, + f_attr, f_attr_code, f_attr_length, f_attr_data, + f_attr_product, f_attr_name, f_attr_mac, f_attr_ip, f_attr_mask, f_attr_gateway, f_attr_newpassword, f_attr_password, f_attr_portscount, + f_attr_dhcp, f_attr_port, f_attr_port_status, f_attr_firmver +} + + + +local op_codes={ + [1]="Read Request", + [2]="Read Reply", + [3]="Write Request", + [4]="Write Reply" +} + + +local error_codes={ + [0]="OK", + [5]="Invalid Value", + [7]="Invalid Password" +} + + +local status_codes={ + [0]="down", + [4]="100M", + [5]="1000M" +} + + + + + +function dissect_port_status (buffer, offset, subtree) + + subtree:add(f_attr_port, buffer(offset+4, 1)) + subtree:add(f_attr_port_status, buffer(offset+5, 1)):append_text(" ("..(status_codes[buffer(offset+5, 1):uint()] or "unk")..")") + +end + + + + + +local attributes={ + [0x0001]={name="Product", dissect=f_attr_product}, + [0x0003]={name="Name", dissect=f_attr_name}, + [0x0004]={name="MAC", dissect=f_attr_mac}, + [0x0006]={name="IP", dissect=f_attr_ip}, + [0x0007]={name="Mask", dissect=f_attr_mask}, + [0x0008]={name="Gateway", dissect=f_attr_gateway}, + [0x0009]={name="New Password", dissect=f_attr_newpassword}, + [0x000A]={name="Password", dissect=f_attr_password}, + [0x000B]={name="DHCP", dissect=f_attr_dhcp}, + [0x000D]={name="Firmware Version", dissect=f_attr_firmver}, + [0x0C00]={name="Port Status", dissect=dissect_port_status}, + [0x6000]={name="Ports Count", dissect=f_attr_portscount} +} + + + + + +function dissect_header (buffer, subtree) + + subtree:add(f_version, buffer(0, 1)) + + subtree:add(f_code, buffer(1, 1)):append_text(" ("..(op_codes[buffer(1, 1):uint()] or "unknown")..")") + + local errcode=buffer(2, 1):uint() + subtree:add(f_error, buffer(2, 1)):append_text(" ("..(error_codes[errcode] or "unknown")..")") + + -- print the erroneous attribute if an error occurred + if ( errcode~=0 ) then + local atf=attributes[buffer(4, 2):uint()] + subtree:add(f_errattr, buffer(4, 2)):append_text(" ("..(atf and atf.name or "unk")..")") + end + + subtree:add(f_clientmac, buffer(8, 6)) + + subtree:add(f_switchmac, buffer(14, 6)) + + subtree:add(f_seqnum, buffer(20, 4)) + + +end + + + +function dissect_attributes (buffer, subtree) + + local offset=32 + + while ( offset