]> git.sur5r.net Git - ngadmin/commitdiff
Added a dissector plugin for Wireshark.
authordarkcoven <admin@darkcoven.tk>
Sat, 26 Nov 2011 11:00:00 +0000 (12:00 +0100)
committerdarkcoven <admin@darkcoven.tk>
Sat, 29 Dec 2012 21:41:33 +0000 (22:41 +0100)
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
lib/ngadmin.h
lib/src/lib.h
lib/src/network.c
lib/src/ngadmin.c
lib/src/protocol.c
nsdp.lua [new file with mode: 0644]

index a35b8bf2356d30829b646096523fbdd1bed5921f..b26d2fd44951d3a764ba4fc0b41fe4f287153225 100644 (file)
@@ -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; i<sa->ports; ++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);
index d0d61def8b102dfd45db25815d63be00ab93a04b..d7d670262fd87179672b7f62e93e83f7112f9699 100644 (file)
@@ -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
index ecb5b71e8e9f7d152ef3227d5117547cf81d2dd3..3d47a8942b1ee42456fd16b2881e5e2c026116ce 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <net/if.h>
 
 #include <ngadmin.h>
 #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
index d976e3e19e7c38f7ef5d5d219ab8fb826d02676e..52837d0243260a5687ff06c5c079f2d36505be65 100644 (file)
@@ -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;
  }
  
index 1f32d09d88f3109e54ebe239914967847a0dd874..33930802a7d05df06327a5413aec843426f44c6b 100644 (file)
@@ -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;
+}
+
+
 
 
index a342c96761dd8e75fe202411f6c150d0e97044e0..d1be292b8d8d7f460171001b812522d50235e523 100644 (file)
@@ -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 (file)
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<buffer:len() ) do
+  
+  local code=buffer(offset, 2):uint()
+  local len=buffer(offset+2, 2):uint()
+  local atf=attributes[code]
+  
+  local attr=subtree:add(f_attr, buffer(offset, 4+len), code)
+  attr:append_text(" ("..(atf and atf.name or "unk")..")")
+  
+  attr:add(f_attr_code, buffer(offset, 2))
+  
+  attr:add(f_attr_length, buffer(offset+2, 2))
+  
+  if ( len<=0 ) then
+   -- no data, display nothing
+  elseif ( atf==nil ) then
+   -- unknown attribute, display raw bytes
+   attr:add(f_attr_data, buffer(offset+4, len))
+  elseif ( type(atf.dissect)=="function" ) then
+   -- custom sub-dissector for complex type
+   atf.dissect(buffer, offset, attr)
+  else
+   -- simple type, directly use field
+   attr:add(atf.dissect, buffer(offset+4, len))
+  end
+  
+  offset=offset+4+len
+  
+ end
+end
+
+
+
+function p_nsdp.dissector (buffer, pinfo, tree)
+ pinfo.cols.protocol=p_nsdp.name
+ local subtree=tree:add(p_nsdp, buffer())
+ -- stop if the packet is too small to be valid
+ if ( buffer:len()<32 ) then return end
+ dissect_header(buffer, subtree)
+ -- stop if it is just a header
+ if ( buffer:len()<=32 ) then return end
+ local attr_list=subtree:add(buffer(32), "Attributes list")
+ dissect_attributes(buffer, attr_list)
+end
+
+
+
+function p_nsdp.init ()
+end
+
+
+
+local udp_dissector_table=DissectorTable.get("udp.port")
+dissector=udp_dissector_table:get_dissector(63322)
+udp_dissector_table:add(63322, p_nsdp)
+
+