]> git.sur5r.net Git - ngadmin/blob - lib/src/network.c
52837d0243260a5687ff06c5c079f2d36505be65
[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 // ----------------------------------------------
222 int readRequest (struct ngadmin *nga, List *attr) {
223  
224  int i, ret=ERR_OK;
225  unsigned short err, attr_error;
226  
227  
228  if ( nga==NULL ) {
229   ret=ERR_INVARG;
230   goto end;
231  }
232  
233  // add end attribute to end
234  pushBackList(attr, newEmptyAttr(ATTR_END));
235  
236  i=sendNgPacket(nga, CODE_READ_REQ, attr);
237  
238  // the list will be filled again by recvNgPacket
239  clearList(attr, (void(*)(void*))freeAttr);
240  
241  if ( i<0 || (i=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr))<0 ) {
242   ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
243   goto end;
244  }
245  
246  if ( err==0x0700 && attr_error==ATTR_PASSWORD ) {
247   ret=ERR_BADPASS;
248   goto end;
249  }
250  
251  
252  end:
253  
254  
255  return ret;
256  
257 }
258
259
260
261 // -----------------------------------------------
262 int writeRequest (struct ngadmin *nga, List *attr) {
263  
264  int i, ret=ERR_OK;
265  unsigned short err, attr_error;
266  
267  
268  if ( nga==NULL ) {
269   ret=ERR_INVARG;
270   goto end;
271  } else if ( nga->current==NULL ) {
272   ret=ERR_NOTLOG;
273   goto end;
274  }
275  
276  
277  if ( attr==NULL ) {
278   attr=createEmptyList();
279  }
280  
281  // add password attribute to start
282  pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
283  
284  // add end attribute to end
285  pushBackList(attr, newEmptyAttr(ATTR_END));
286  
287  i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
288  
289  // the list will be filled again by recvNgPacket
290  // but normally it will be still empty
291  clearList(attr, (void(*)(void*))freeAttr);
292  
293  if ( i<0 || (i=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr))<0 ) {
294   ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
295   goto end;
296  }
297  
298  if ( err==0x0700 && attr_error==ATTR_PASSWORD ) {
299   ret=ERR_BADPASS;
300   goto end;
301  }
302  
303  // err==0x0500
304  
305  
306  end:
307  // the switch replies to write request by just a header (no attributes), so the list can be destroyed
308  destroyList(attr, (void(*)(void*))freeAttr);
309  
310  
311  return ret;
312  
313 }
314
315