]> git.sur5r.net Git - ngadmin/blob - lib/src/network.c
Lib: fixed memory leaks.
[ngadmin] / lib / src / network.c
1
2 #include "network.h"
3
4
5
6
7 // -----------------------------------
8 int startNetwork (struct ngadmin *nga) {
9  
10  struct ifreq ifr;
11  int ret;
12  
13  
14  // create socket
15  if ( (nga->sock=socket(AF_INET, SOCK_DGRAM, 0))<0 ) {
16   perror("socket");
17   return nga->sock;
18  }
19  
20  memset(&ifr, 0, sizeof(struct ifreq));
21  strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ-1);
22  
23  // get the interface broadcast address
24  if ( (ret=ioctl(nga->sock, SIOCGIFBRDADDR, &ifr))<0 ) {
25   perror("ioctl(SIOCGIFBRDADDR)");
26   close(nga->sock);
27   return ret;
28  }
29  nga->brd=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
30  
31  // get the interface MAC address
32  if ( (ret=ioctl(nga->sock, SIOCGIFHWADDR, &ifr))<0 ) {
33   perror("ioctl(SIOCGIFHWADDR)");
34   close(nga->sock);
35   return ret;
36  }
37  memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
38  
39  // bind
40  memset(&nga->local, 0, sizeof(struct sockaddr_in));
41  nga->local.sin_family=AF_INET;
42  nga->local.sin_port=htons(CLIENT_PORT);
43  
44  if ( (ret=bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in)))<0 ) {
45   perror("bind");
46   close(nga->sock);
47   return ret;
48  }
49  
50  // allow broadcasting
51  ret=1;
52  if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)))<0 ) {
53   perror("setsockopt(SO_BROADCAST)");
54   return ret;
55  }
56  
57  // prevent unicast packets from being routed by setting the TTL to 1
58  ret=1;
59  if ( (ret=setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret)))<0 ) {
60   perror("setsockopt(IP_TTL)");
61   return ret;
62  }
63  
64  
65  return 0;
66  
67 }
68
69
70
71 // ----------------------------------
72 int stopNetwork (struct ngadmin *nga) {
73  
74  return close(nga->sock);
75  
76 }
77
78
79
80 // -------------------------------------
81 int forceInterface (struct ngadmin *nga) {
82  
83  int ret;
84  
85  
86  /*
87  As described bellow, when you have multiple interfaces, this forces the packet 
88  to go to a particular interface. 
89  */
90  if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface)+1))<0 ) {
91   perror("setsockopt(SO_BINDTODEVICE)");
92   return ret;
93  }
94  
95  /*
96  If the switch's IP is not in your network range, for instance because you do 
97  not have DHCP  enabled or you started the switch after it, this allows to 
98  bypass the routing tables and consider every address is directly reachable on 
99  the interface. 
100  */
101  ret=1;
102  if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret)))<0 ) {
103   perror("setsockopt(SO_DONTROUTE)");
104   return ret;
105  }
106  
107  
108  return 0;
109  
110 }
111
112
113
114 // ------------------------------------
115 int updateTimeout (struct ngadmin *nga) {
116  
117  int ret;
118  
119  
120  // specify receive timeout
121  if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval)))<0 ) {
122   perror("setsockopt(SO_RCVTIMEO)");
123   return ret;
124  }
125  
126  
127  return 0;
128  
129 }
130
131
132
133 // ----------------------------------------------------------------
134 int sendNgPacket (struct ngadmin *nga, char code, const List *attr) {
135  
136  char buffer[1500];
137  struct ng_packet np;
138  ListNode *ln;
139  struct attr *at;
140  struct sockaddr_in remote;
141  const struct swi_attr *sa=nga->current;
142  int ret;
143  
144  
145  np.buffer=buffer;
146  np.maxlen=sizeof(buffer);
147  initNgPacket(&np);
148  initNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , ++nga->seq);
149  
150  if ( attr!=NULL ) {
151   for (ln=attr->first; ln!=NULL; ln=ln->next) {
152    at=ln->data;
153    addPacketAttr(&np, at->attr, at->size, at->data);
154   }
155  }
156  
157  memset(&remote, 0, sizeof(struct sockaddr_in));
158  remote.sin_family=AF_INET;
159  remote.sin_port=htons(SWITCH_PORT);
160  
161  if ( sa!=NULL && !nga->keepbroad ) remote.sin_addr=sa->nc.ip;
162  else if ( nga->globalbroad ) remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
163  else remote.sin_addr=nga->brd;
164  
165  
166  if ( (ret=sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)))<0 ) {
167   perror("sendto");
168  }
169  
170  
171  return ret;
172  
173 }
174
175
176
177 // ------------------------------------------------------------------------------------------------------------
178 int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr) {
179  
180  char buffer[1500];
181  struct ng_packet np;
182  struct sockaddr_in remote;
183  socklen_t slen=sizeof(struct sockaddr_in);
184  const struct swi_attr *sa=nga->current;
185  struct timeval rem;
186  fd_set fs;
187  int len=-1;
188  
189  
190  np.buffer=buffer;
191  
192  memset(&remote, 0, sizeof(struct sockaddr_in));
193  remote.sin_family=AF_INET;
194  
195  rem=nga->timeout;
196  
197  while ( 1 ) {
198   
199   FD_ZERO(&fs);
200   FD_SET(nga->sock, &fs);
201   select(nga->sock+1, &fs, NULL, NULL, &rem); // FIXME: non portable
202   
203   len=recvfrom(nga->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&remote, &slen);
204   
205   if ( len<0 ) break;
206   
207   np.maxlen=len;
208   initNgPacket(&np);
209   
210   if ( 
211       ntohs(remote.sin_port)!=SWITCH_PORT || 
212       len<(int)sizeof(struct ng_header) || 
213       !validateNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , nga->seq) || 
214       extractPacketAttributes(&np, error, attr_error, attr)<0
215      ) continue;
216   
217   len=0;
218   break;
219   
220  }
221  
222  
223  return len;
224  
225 }
226
227
228
229 static int checkErrorCode (unsigned char err, unsigned short attr_error) {
230  
231  
232  switch ( err ) {
233   
234   case ERROR_DENIED: return attr_error==ATTR_PASSWORD ? ERR_BADPASS : ERR_DENIED ;
235   case ERROR_INVALID_VALUE: return ERR_INVARG;
236   default: return ERR_OK;
237   
238  }
239  
240  
241 }
242
243
244
245 // ----------------------------------------------
246 int readRequest (struct ngadmin *nga, List *attr) {
247  
248  int i, ret=ERR_OK;
249  unsigned char err;
250  unsigned short attr_error;
251  
252  
253  if ( nga==NULL ) {
254   ret=ERR_INVARG;
255   goto end;
256  }
257  
258  // add end attribute to end
259  pushBackList(attr, newEmptyAttr(ATTR_END));
260  
261  i=sendNgPacket(nga, CODE_READ_REQ, attr);
262  
263  // the list will be filled again by recvNgPacket
264  clearList(attr, (void(*)(void*))freeAttr);
265  
266  if ( i<0 || (i=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr))<0 ) {
267   ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
268   goto end;
269  }
270  
271  
272  // check error code
273  ret=checkErrorCode(err, attr_error);
274  
275  
276  end:
277  
278  return ret;
279  
280 }
281
282
283
284 // -----------------------------------------------
285 int writeRequest (struct ngadmin *nga, List *attr) {
286  
287  int i, ret=ERR_OK;
288  unsigned char err;
289  unsigned short attr_error;
290  
291  
292  if ( nga==NULL ) {
293   ret=ERR_INVARG;
294   goto end;
295  } else if ( nga->current==NULL ) {
296   ret=ERR_NOTLOG;
297   goto end;
298  }
299  
300  
301  if ( attr==NULL ) {
302   attr=createEmptyList();
303  }
304  
305  // add password attribute to start
306  pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
307  
308  // add end attribute to end
309  pushBackList(attr, newEmptyAttr(ATTR_END));
310  
311  i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
312  
313  // the list will be filled again by recvNgPacket
314  // but normally it will be still empty
315  clearList(attr, (void(*)(void*))freeAttr);
316  
317  if ( i<0 || (i=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr))<0 ) {
318   ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
319   goto end;
320  }
321  
322  // check error code
323  ret=checkErrorCode(err, attr_error);
324  
325  
326  end:
327  // the switch replies to write request by just a header (no attributes), so the list can be destroyed
328  destroyList(attr, (void(*)(void*))freeAttr);
329  
330  
331  return ret;
332  
333 }
334
335