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