X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=lib%2Fsrc%2Fnetwork.c;h=0ad90561c9eb70443ff5357cf928793d03b9e674;hb=c662193fa4e44d5ceaa60a7c00d5c0f45b43ab69;hp=a7b01d1c2fbe5a4b8bc5a7667628ad4db19c6bf7;hpb=ac848de54334e0135cc4f8fb4048689ce652f289;p=ngadmin diff --git a/lib/src/network.c b/lib/src/network.c index a7b01d1..0ad9056 100644 --- a/lib/src/network.c +++ b/lib/src/network.c @@ -1,398 +1,381 @@ -#include "network.h" - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -// ----------------------------------- -int startNetwork (struct ngadmin *nga) { - - struct ifreq ifr; - int ret; - - - // create socket - if ( (nga->sock=socket(AF_INET, SOCK_DGRAM, 0))<0 ) { - perror("socket"); - return nga->sock; - } - - memset(&ifr, 0, sizeof(struct ifreq)); - strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ-1); - - // get the interface broadcast address - if ( (ret=ioctl(nga->sock, SIOCGIFBRDADDR, &ifr))<0 ) { - perror("ioctl(SIOCGIFBRDADDR)"); - close(nga->sock); - return ret; - } - nga->brd=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr; - - // get the interface MAC address - if ( (ret=ioctl(nga->sock, SIOCGIFHWADDR, &ifr))<0 ) { - perror("ioctl(SIOCGIFHWADDR)"); - close(nga->sock); - return ret; - } - memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - // bind - memset(&nga->local, 0, sizeof(struct sockaddr_in)); - nga->local.sin_family=AF_INET; - nga->local.sin_port=htons(CLIENT_PORT); - - if ( (ret=bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in)))<0 ) { - perror("bind"); - close(nga->sock); - return ret; - } - - // allow broadcasting - ret=1; - if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)))<0 ) { - perror("setsockopt(SO_BROADCAST)"); - return ret; - } - - // prevent unicast packets from being routed by setting the TTL to 1 - ret=1; - if ( (ret=setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret)))<0 ) { - perror("setsockopt(IP_TTL)"); - return ret; - } - - - return 0; - -} - +#include "network.h" -// ---------------------------------- -int stopNetwork (struct ngadmin *nga) { - - return close(nga->sock); - +int startNetwork (struct ngadmin *nga) +{ + struct ifreq ifr; + int ret; + + + /* create socket */ + nga->sock = socket(AF_INET, SOCK_DGRAM, 0); + if (nga->sock < 0) { + perror("socket"); + return nga->sock; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1); + + /* get the interface MAC address */ + ret = ioctl(nga->sock, SIOCGIFHWADDR, &ifr); + if (ret < 0) { + perror("ioctl(SIOCGIFHWADDR)"); + close(nga->sock); + return ret; + } + memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + + /* bind */ + memset(&nga->local, 0, sizeof(struct sockaddr_in)); + nga->local.sin_family = AF_INET; + nga->local.sin_port = htons(CLIENT_PORT); + + ret = bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in)); + if (ret < 0) { + perror("bind"); + close(nga->sock); + return ret; + } + + /* allow broadcasting */ + ret = 1; + ret = setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)); + if (ret < 0) { + perror("setsockopt(SO_BROADCAST)"); + return ret; + } + + /* prevent unicast packets from being routed by setting the TTL to 1 */ + ret = 1; + ret = setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret)); + if (ret < 0) { + perror("setsockopt(IP_TTL)"); + return ret; + } + + + return 0; } - -// ------------------------------------- -int forceInterface (struct ngadmin *nga) { - - int ret; - - - /* - As described bellow, when you have multiple interfaces, this forces the packet - to go to a particular interface. - */ - if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface)+1))<0 ) { - perror("setsockopt(SO_BINDTODEVICE)"); - return ret; - } - - /* - If the switch's IP is not in your network range, for instance because you do - not have DHCP enabled or you started the switch after it, this allows to - bypass the routing tables and consider every address is directly reachable on - the interface. - */ - ret=1; - if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret)))<0 ) { - perror("setsockopt(SO_DONTROUTE)"); - return ret; - } - - - return 0; - +int setBroadcastType (struct ngadmin *nga, bool value) +{ + int ret; + struct ifreq ifr; + + + nga->globalbroad = value; + if (value) { + nga->brd.s_addr = (in_addr_t)0; + return 0; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1); + + /* get the interface broadcast address */ + ret = ioctl(nga->sock, SIOCGIFBRDADDR, &ifr); + if (ret < 0) { + perror("ioctl(SIOCGIFBRDADDR)"); + nga->brd.s_addr = (in_addr_t)0; + nga->globalbroad = true; + return ret; + } + + nga->brd = (*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr; + + return 0; } - -// ------------------------------------ -int updateTimeout (struct ngadmin *nga) { - - int ret; - - - // specify receive timeout - if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval)))<0 ) { - perror("setsockopt(SO_RCVTIMEO)"); - return ret; - } - - - return 0; - +int stopNetwork (struct ngadmin *nga) +{ + return close(nga->sock); } -/* -// --------------------------------------------------------- -int connectSwitch (struct ngadmin *nga, struct swi_attr *sa) { - - struct sockaddr_in remote; - - - memset(&remote, 0, sizeof(struct sockaddr_in)); - remote.sin_family=AF_UNSPEC; - remote.sin_port=htons(SWITCH_PORT); - - nga->current=sa; - - if ( sa!=NULL && !nga->keepbroad ) { - remote.sin_family=AF_INET; - remote.sin_addr=sa->nc.ip; - } - - - return connect(nga->sock, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)); - +int forceInterface (struct ngadmin *nga) +{ + int ret; + + + /* + As described bellow, when you have multiple interfaces, this forces the packet + to go to a particular interface. + */ + ret = setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface) + 1); + if (ret < 0) { + perror("setsockopt(SO_BINDTODEVICE)"); + return ret; + } + + /* + If the switch's IP is not in your network range, for instance because you do + not have DHCP enabled or you started the switch after it, this allows to + bypass the routing tables and consider every address is directly reachable on + the interface. + */ + ret = 1; + ret = setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret)); + if (ret <0) { + perror("setsockopt(SO_DONTROUTE)"); + return ret; + } + + + return 0; } -*/ -// ---------------------------------------------------------------- -int sendNgPacket (struct ngadmin *nga, char code, const List *attr) { - - char buffer[1500]; - struct ng_packet np; - ListNode *ln; - struct attr *at; - struct sockaddr_in remote; - const struct swi_attr *sa=nga->current; - int ret; - - - - - np.buffer=buffer; - np.maxlen=sizeof(buffer); - initNgPacket(&np); - initNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , ++nga->seq); - - if ( attr!=NULL ) { - for (ln=attr->first; ln!=NULL; ln=ln->next) { - at=ln->data; - addPacketAttr(&np, at->attr, at->size, at->data); - } - } - - memset(&remote, 0, sizeof(struct sockaddr_in)); - remote.sin_family=AF_INET; - remote.sin_port=htons(SWITCH_PORT); - - if ( sa!=NULL && !nga->keepbroad ) remote.sin_addr=sa->nc.ip; - else if ( nga->globalbroad ) remote.sin_addr.s_addr=htonl(INADDR_BROADCAST); - else remote.sin_addr=nga->brd; - - - if ( (ret=sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)))<0 ) { - perror("sendto"); - } - - - return ret; - +static int checkErrorCode (const struct nsdp_cmd *nc) +{ + switch (nc->error) { + + case ERROR_DENIED: + return (nc->attr_error == ATTR_PASSWORD) ? ERR_BADPASS : ERR_DENIED; + + case ERROR_INVALID_VALUE: + return ERR_INVARG; + + default: + return ERR_OK; + } } -/* -static int my_poll (struct pollfd *fds, nfds_t nfds, struct timeval *timeout) { - - int ret, rem=-1; - struct timeval start, stop; - - - if ( timeout!=NULL ) { - if ( timeout->tv_sec<0 || timeout->tv_usec<0 ) rem=0; - else rem=timeout->tv_sec*1000+timeout->tv_usec/1000; - } - - gettimeofday(&start, NULL); - ret=poll(fds, nfds, rem); - gettimeofday(&stop, NULL); - - if ( timeout!=NULL ) { - rem-=(stop.tv_sec-start.tv_sec)*1000+(stop.tv_usec-start.tv_usec)/1000; - if ( ret<=0 || rem<0 ) rem=0; - printf("tv_sec = %i, tv_usec = %i\n", start.tv_sec, start.tv_usec); - printf("tv_sec = %i, tv_usec = %i\n", stop.tv_sec, stop.tv_usec); - printf("rem = %i\n", rem); - timeout->tv_sec=rem/1000; - timeout->tv_usec=(rem%1000)*1000; - } - - - return ret; - +void prepareSend (struct ngadmin *nga, struct nsdp_cmd *nc, unsigned char code) +{ + struct swi_attr *sa = nga->current; + + + memset(nc, 0, sizeof(struct nsdp_cmd)); + memcpy(&nc->client_mac, &nga->localmac, ETH_ALEN); + nc->remote_addr.sin_family = AF_INET; + nc->remote_addr.sin_port = htons(SWITCH_PORT); + if (sa != NULL) { + memcpy(&nc->switch_mac, &sa->mac, ETH_ALEN); + nc->ports = sa->ports; + } + + /* destination address selection */ + if (sa != NULL && !nga->keepbroad) + nc->remote_addr.sin_addr = sa->nc.ip; + else if (nga->globalbroad) + nc->remote_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); + else + nc->remote_addr.sin_addr = nga->brd; + + nc->seqnum = ++nga->seq; + nc->code = code; } -*/ -// ------------------------------------------------------------------------------------------------------------ -int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr) { - - char buffer[1500]; - struct ng_packet np; - struct sockaddr_in remote; - socklen_t slen=sizeof(struct sockaddr_in); - const struct swi_attr *sa=nga->current; - struct timeval rem; - //struct pollfd fds; - fd_set fs; - int len=-1; - - - np.buffer=buffer; - - memset(&remote, 0, sizeof(struct sockaddr_in)); - remote.sin_family=AF_INET; - - rem=nga->timeout; - - //fds.fd=nga->sock; - //fds.events=POLLIN; - - while ( 1 ) { - - //my_poll(&fds, 1, &rem); - FD_ZERO(&fs); - FD_SET(nga->sock, &fs); - select(nga->sock+1, &fs, NULL, NULL, &rem); // FIXME: non portable - - len=recvfrom(nga->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&remote, &slen); - - if ( len<0 ) break; - - np.maxlen=len; - initNgPacket(&np); - - if ( - ntohs(remote.sin_port)!=SWITCH_PORT || - len<(int)sizeof(struct ng_header) || - !validateNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , nga->seq) || - extractPacketAttributes(&np, error, attr_error, attr)<0 - ) continue; - - len=0; - break; - - } - - - return len; - +void prepareRecv (struct ngadmin *nga, struct nsdp_cmd *nc, unsigned char code) +{ + struct swi_attr *sa = nga->current; + + + memset(nc, 0, sizeof(struct nsdp_cmd)); + memcpy(&nc->client_mac, &nga->localmac, ETH_ALEN); + nc->remote_addr.sin_family = AF_INET; + nc->remote_addr.sin_port = htons(SWITCH_PORT); + if (sa != NULL) { + memcpy(&nc->switch_mac, &sa->mac, ETH_ALEN); + nc->ports = sa->ports; + } + + /* set filter on switch IP */ + if (sa == NULL) + nc->remote_addr.sin_addr.s_addr = htonl(INADDR_ANY); + else + nc->remote_addr.sin_addr = sa->nc.ip; + + nc->seqnum = nga->seq; + nc->code = code; } - -static int checkErrorCode (unsigned char err, unsigned short attr_error) { - - - switch ( err ) { - - case ERROR_DENIED: return attr_error==ATTR_PASSWORD ? ERR_BADPASS : ERR_DENIED ; - case ERROR_INVALID_VALUE: return ERR_INVARG; - default: return ERR_OK; - - } - - +int readRequest (struct ngadmin *nga, List *attr) +{ + int i, ret = ERR_OK; + struct nsdp_cmd nc; + + + if (nga == NULL) { + ret = ERR_INVARG; + goto end; + } + + /* add end attribute to end */ + pushBackList(attr, newEmptyAttr(ATTR_END)); + + prepareSend(nga, &nc, CODE_READ_REQ); + i = sendNsdpPacket(nga->sock, &nc, attr); + + /* do not destroy the list, it will be filled again later by recvNsdpPacket */ + clearList(attr, (void(*)(void*))freeAttr); + + if (i >= 0) { + prepareRecv(nga, &nc, CODE_READ_REP); + i = recvNsdpPacket(nga->sock, &nc, attr, &nga->timeout); + } + + if (i == -EINVAL) { + ret = ERR_INVARG; + goto end; + } else if (i < 0) { + ret = (errno == EAGAIN || errno == EWOULDBLOCK) ? ERR_TIMEOUT : ERR_NET; + goto end; + } + + + /* check the switch error code */ + ret = checkErrorCode(&nc); + + +end: + return ret; } - -// ---------------------------------------------- -int readRequest (struct ngadmin *nga, List *attr) { - - int i, ret=ERR_OK; - unsigned char err; - unsigned short attr_error; - - - if ( nga==NULL ) { - ret=ERR_INVARG; - goto end; - } - - // add end attribute to end - pushBackList(attr, newEmptyAttr(ATTR_END)); - - i=sendNgPacket(nga, CODE_READ_REQ, attr); - - // the list will be filled again by recvNgPacket - clearList(attr, (void(*)(void*))freeAttr); - - if ( i<0 || (i=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr))<0 ) { - ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ; - goto end; - } - - - // check error code - ret=checkErrorCode(err, attr_error); - - - end: - - return ret; - +int writeRequest (struct ngadmin *nga, List *attr) +{ + int i, ret = ERR_OK; + struct attr *at; + struct nsdp_cmd nc; + + + if (nga == NULL) { + ret = ERR_INVARG; + goto end; + } else if (nga->current == NULL) { + ret = ERR_NOTLOG; + goto end; + } + + + if (attr == NULL) + attr = createEmptyList(); + + /* add password attribute to start */ + at = newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)); + if (nga->encrypt_pass) + passwordEndecode(at->data, at->size); + pushFrontList(attr, at); + + /* add end attribute to end */ + pushBackList(attr, newEmptyAttr(ATTR_END)); + + prepareSend(nga, &nc, CODE_WRITE_REQ); + i = sendNsdpPacket(nga->sock, &nc, attr); + + /* the list will be filled again by recvNgPacket + but normally it will be still empty */ + clearList(attr, (void(*)(void*))freeAttr); + + if (i >= 0) { + prepareRecv(nga, &nc, CODE_WRITE_REP); + i = recvNsdpPacket(nga->sock, &nc, attr, &nga->timeout); + } + + if (i == -EINVAL) { + ret = ERR_INVARG; + goto end; + } else if (i < 0) { + ret = (errno == EAGAIN || errno == EWOULDBLOCK) ? ERR_TIMEOUT : ERR_NET; + goto end; + } + + /* check the switch error code */ + ret = checkErrorCode(&nc); + + +end: + /* the switch replies to write request by just a header (no attributes), so the list can be destroyed */ + destroyList(attr, (void(*)(void*))freeAttr); + + + return ret; } - -// ----------------------------------------------- -int writeRequest (struct ngadmin *nga, List *attr) { - - int i, ret=ERR_OK; - unsigned char err; - unsigned short attr_error; - - - if ( nga==NULL ) { - ret=ERR_INVARG; - goto end; - } else if ( nga->current==NULL ) { - ret=ERR_NOTLOG; - goto end; - } - - - if ( attr==NULL ) { - attr=createEmptyList(); - } - - // add password attribute to start - pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password))); - - // add end attribute to end - pushBackList(attr, newEmptyAttr(ATTR_END)); - - i=sendNgPacket(nga, CODE_WRITE_REQ, attr); - - // the list will be filled again by recvNgPacket - // but normally it will be still empty - clearList(attr, (void(*)(void*))freeAttr); - - if ( i<0 || (i=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr))<0 ) { - ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ; - goto end; - } - - // check error code - ret=checkErrorCode(err, attr_error); - - - end: - // the switch replies to write request by just a header (no attributes), so the list can be destroyed - destroyList(attr, (void(*)(void*))freeAttr); - - - return ret; - +void extractSwitchAttributes (struct swi_attr *sa, const List *l) +{ + const ListNode *ln; + const struct attr *at; + int len; + + + memset(sa, 0, sizeof(struct swi_attr)); + + for (ln = l->first; ln != NULL; ln = ln->next) { + at = ln->data; + + switch (at->attr) { + + case ATTR_PRODUCT: + len = min(at->size, PRODUCT_SIZE); + memcpy(sa->product, at->data, len); + trim(sa->product, len); + break; + + case ATTR_NAME: + len = min(at->size, NAME_SIZE); + memcpy(sa->name, at->data, len); + trim(sa->name, len); + break; + + case ATTR_MAC: + memcpy(&sa->mac, at->data, ETH_ALEN); + break; + + case ATTR_IP: + sa->nc.ip = *(struct in_addr*)at->data; + break; + + case ATTR_NETMASK: + sa->nc.netmask = *(struct in_addr*)at->data; + break; + + case ATTR_GATEWAY: + sa->nc.gw = *(struct in_addr*)at->data; + break; + + case ATTR_DHCP: + sa->nc.dhcp = (ntohs(*(unsigned short*)at->data) == 1); + break; + + case ATTR_FIRM_VER: + len = min(at->size, FIRMWARE_SIZE - 1); + memcpy(sa->firmware, at->data, len); + sa->firmware[len] = '\0'; + break; + + case ATTR_PORTS_COUNT: + sa->ports = *(unsigned char*)at->data; + break; + + case ATTR_END: + return; + } + } }