1 /* ======================================================================
2 * Copyright (c) 1998-1999 The Johns Hopkins University.
3 * All rights reserved.
4 * The following code was written for use in the Backhand project at
5 * The Center for Networking and Distributed Systems at The Johns
6 * Hopkins University. See the NOTICE file in the mod_backhand
7 * distribution for more details.
8 * ======================================================================
9 */
10
11 #include "ife.h"
12 #include "ife-icmp-support.h"
13
14 static int _if_sock=-1;
15 static int _if_dev=-1;
16 static char _if_error_none[] = "";
17 static char _if_error_exists[] = "IP alias exists";
18 static char _if_error_nosuchinterface[] = "No such interface";
19 static char _if_error_dlpi_error[] = "DLPI error";
20 static char _if_error_dlpi_unexpected[] = "DLPI unexpected response";
21 static char _if_error_alias_up_failed[] = "alias up failed";
22 static char _if_error_alias_down_failed[] = "alias down failed";
23 static char *_if_error=_if_error_none;
24
if_initialize()25 int if_initialize() {
26 if((_if_sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
27 perror ("socket");
28 exit (EXIT_FAILURE);
29 }
30 _if_dev = -1;
31 return 0;
32 }
if_error()33 char *if_error() {
34 return _if_error;
35 }
36 static int
dlpi_attach(int fd,int instance)37 dlpi_attach(int fd, int instance) {
38 dl_attach_req_t req;
39 struct strbuf buf;
40
41 req.dl_primitive = DL_ATTACH_REQ;
42 req.dl_ppa = instance;
43 buf.len = sizeof(req);
44 buf.buf = (void *) &req;
45 return putmsg(fd, &buf, NULL, RS_HIPRI);
46 }
47 static int
dlpi_bind(int fd,u_long sap,u_long max_conind,u_long service_mode,u_long conn_mgmt,u_long xidtest)48 dlpi_bind(int fd, u_long sap, u_long max_conind, u_long service_mode,
49 u_long conn_mgmt, u_long xidtest) {
50 dl_bind_req_t br;
51 struct strbuf ctl;
52
53 br.dl_primitive = DL_BIND_REQ;
54 br.dl_sap = sap;
55 br.dl_max_conind = max_conind;
56 br.dl_service_mode = service_mode;
57 br.dl_conn_mgmt = conn_mgmt;
58 br.dl_xidtest_flg = xidtest;
59 ctl.maxlen = 0;
60 ctl.len = sizeof(br);
61 ctl.buf = (char *)&br;
62
63 return putmsg(fd, &ctl, NULL, 0);
64 }
65 static int
dlpi_mac_req(int fd)66 dlpi_mac_req(int fd) {
67 dl_phys_addr_req_t req;
68 struct strbuf buf;
69
70 req.dl_primitive = DL_PHYS_ADDR_REQ;
71 req.dl_addr_type = DL_CURR_PHYS_ADDR;
72 buf.len = sizeof(req);
73 buf.buf = (void *) &req;
74 return putmsg(fd, &buf, NULL, RS_HIPRI);
75 }
76 static int
dlpi_get_reply(int fd,union DL_primitives * reply,int expected_prim,int maxlen)77 dlpi_get_reply(int fd, union DL_primitives *reply,
78 int expected_prim, int maxlen) {
79 struct strbuf buf;
80 int flags, n;
81 struct pollfd pfd;
82
83 pfd.fd = fd;
84 pfd.events = POLLIN | POLLPRI;
85 do {
86 n = poll(&pfd, 1, 1000);
87 } while(n == -1 && errno == EINTR);
88 if(n <= 0)
89 return -1;
90 buf.maxlen = maxlen;
91 buf.buf = (void *) reply;
92 flags = 0;
93 if(getmsg(fd, &buf, NULL, &flags) < 0) {
94 return -1;
95 }
96
97 if(buf.len < sizeof(ulong)) {
98 _if_error = _if_error_dlpi_unexpected;
99 return -1;
100 }
101
102 if(reply->dl_primitive == expected_prim)
103 return 0;
104
105 if (reply->dl_primitive == DL_ERROR_ACK)
106 _if_error = _if_error_dlpi_error;
107 else
108 _if_error = _if_error_dlpi_unexpected;
109 return -1;
110 }
111
112 static int
dlpi_open_and_attach(char * dev)113 dlpi_open_and_attach(char *dev) {
114 int fd, instance;
115 char ifdev[24];
116 char *cp;
117 struct {
118 union DL_primitives prim;
119 char space[64];
120 } reply;
121
122 strcpy(ifdev, "/dev/");
123 cp = ifdev + 5;
124 while(*dev != '\0')
125 *cp++ = *dev++;
126 *cp = '\0';
127 cp--;
128 while(*cp != '/' && isdigit((int)*cp)) *cp-- = '\0';
129 instance = atoi(dev);
130 fd = open(ifdev, O_RDWR);
131 if(fd < 0) {
132 _if_error = _if_error_nosuchinterface;
133 return -1;
134 }
135 if(dlpi_attach(fd, instance) < 0) {
136 close(fd);
137 return -1;
138 }
139 if(dlpi_get_reply(fd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0) {
140 close(fd);
141 return -1;
142 }
143 if(dlpi_bind(fd, DL_ETHER, 0, DL_CLDLS, 0, 0) < 0) {
144 close(fd);
145 return -1;
146 }
147 if(dlpi_get_reply(fd, &reply.prim, DL_BIND_ACK, sizeof(reply)) < 0) {
148 close(fd);
149 return -1;
150 }
151 return fd;
152 }
153 static int
if_get_mac_address(char * dev,char * mac)154 if_get_mac_address(char *dev, char *mac) {
155 int fd;
156 struct {
157 union DL_primitives prim;
158 char space[64];
159 } reply;
160
161 if(_if_dev < 0)
162 _if_dev = dlpi_open_and_attach(dev);
163
164 if((fd = _if_dev) < 0) {
165 return 0;
166 }
167 if(dlpi_mac_req(fd) < 0) {
168 close(fd);
169 return 0;
170 }
171 if(dlpi_get_reply(fd, &reply.prim,DL_PHYS_ADDR_ACK,sizeof(reply)) < 0) {
172 close(fd);
173 return 0;
174 }
175 if(reply.prim.physaddr_ack.dl_addr_length != ETH_ALEN) {
176 _if_error = _if_error_dlpi_unexpected;
177 close(fd);
178 }
179 memcpy(mac, (char *)&reply+reply.prim.physaddr_ack.dl_addr_offset, ETH_ALEN);
180 return 1;
181 }
182 int
if_send_spoof_request(char * dev,unsigned int new_ip,unsigned int r_ip,unsigned char * remote_mac,int count,int ping)183 if_send_spoof_request(char *dev,
184 unsigned int new_ip, unsigned int r_ip,
185 unsigned char *remote_mac,
186 int count, int ping) {
187 int i,ic;
188 struct ifreq ifr;
189 struct ether_header *eth;
190 struct arphdr *arp;
191 struct interface ifs[1024];
192 unsigned char *cp, *dest_mac;
193 static unsigned char buffer[60];
194 static unsigned char my_mac[ETH_ALEN];
195 static unsigned char bc_mac[ETH_ALEN] =
196 {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
197 memset(&ifr, sizeof(struct ifreq), 0);
198 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
199 ic = if_list_ips(ifs, 1024);
200 for(i=0; i<ic; i++) {
201 if(!strncmp(ifs[i].ifname, ifr.ifr_name, strlen(ifr.ifr_name)) &&
202 (ifs[i].mac[0] || ifs[i].mac[1] || ifs[i].mac[2] ||
203 ifs[i].mac[3] || ifs[i].mac[4] || ifs[i].mac[5]) ) {
204 memcpy(my_mac, ifs[i].mac, ETH_ALEN);
205 break;
206 }
207 }
208 memset(buffer, 0, 60);
209 eth = (struct ether_header *)buffer;
210 memcpy(ð->ether_shost, my_mac, ETH_ALEN);
211 memcpy(ð->ether_dhost, bc_mac, ETH_ALEN);
212 eth->ether_type = htons(ETH_P_ARP);
213 arp = (struct arphdr *)(eth+1);
214 arp->ar_hrd = htons(ARPHRD_ETHER);
215 arp->ar_pro = htons(ETH_P_IP);
216 arp->ar_hln = ETH_ALEN;
217 arp->ar_pln = 4;
218 arp->ar_op = htons(ARPOP_REPLY);
219 cp = (unsigned char *)(arp+1);
220 memcpy(cp, my_mac, ETH_ALEN); cp+=ETH_ALEN;
221 memcpy(cp, &new_ip, 4); cp+=4;
222 dest_mac = cp;
223 memcpy(cp, bc_mac, ETH_ALEN); cp+=ETH_ALEN;
224 memcpy(cp, &r_ip, 4); cp+=4;
225 if(_if_dev < 0) {
226 struct strioctl sioc;
227 _if_dev = dlpi_open_and_attach(dev);
228 if(_if_dev < 0) {
229 return 0;
230 }
231 sioc.ic_cmd = DLIOCRAW;
232 sioc.ic_timout = -1;
233 sioc.ic_len = 0;
234 sioc.ic_dp = 0;
235 if(ioctl(_if_dev, I_STR, &sioc) < 0) {
236 close(_if_dev);
237 _if_dev = -1;
238 }
239 }
240 for(i=0;i<count;i++)
241 write(_if_dev, buffer, 60);
242 if(remote_mac) {
243 memcpy(dest_mac, remote_mac, ETH_ALEN);
244 memcpy(ð->ether_dhost, remote_mac, ETH_ALEN);
245 for(i=0;i<count;i++)
246 write(_if_dev, buffer, 60);
247 if(ping) {
248 compose_ping(buffer, my_mac, remote_mac, new_ip, r_ip);
249 write(_if_dev, buffer, 42);
250 }
251 }
252 return i;
253 }
254 int
if_list_ips(struct interface * ifs,int size)255 if_list_ips(struct interface *ifs,
256 int size) {
257 int count=0;
258 struct ifconf d;
259 struct ifreq *ifr, *end, *cur, *temp;
260 struct in_addr ipaddr;
261 char buffer[1024];
262
263 /* temporary storage for getting broadcast address */
264 temp= (struct ifreq *)buffer;
265
266 d.ifc_len= 4096*8;
267 d.ifc_buf= malloc (d.ifc_len);
268 if(ioctl (_if_sock, SIOCGIFCONF, &d) == -1) {
269 perror("ioctl (SIOCGIFCONF)");
270 free(d.ifc_buf);
271 return 0;
272 }
273
274 ifr=(struct ifreq *)(d.ifc_req);
275 end=(struct ifreq *)(((char *) ifr) + d.ifc_len);
276 while((ifr<end) && (count<size)) {
277 cur= ifr;
278 ifr = (struct ifreq *)(((char *)ifr)+sizeof(struct ifreq));
279 if(((struct sockaddr_in *)&cur->ifr_addr)->sin_family != AF_INET)
280 continue;
281 memcpy(&ipaddr, &(((struct sockaddr_in *)&cur->ifr_addr)->sin_addr),
282 sizeof(struct in_addr));
283 memcpy(temp, cur, sizeof(struct ifreq));
284 if(ioctl (_if_sock, SIOCGIFFLAGS, (char *) cur) < 0)
285 continue;
286 if((cur->ifr_flags & IFF_UP) && (cur->ifr_flags & IFF_BROADCAST)) {
287 memcpy(&ifs[count].ipaddr, &ipaddr, sizeof(struct in_addr));
288 if(ioctl(_if_sock, SIOCGIFBRDADDR, (char *)temp) != -1)
289 memcpy(&ifs[count].bcast,
290 &(((struct sockaddr_in *)&temp->ifr_addr)->sin_addr),
291 sizeof(struct in_addr));
292 if(ioctl(_if_sock, SIOCGIFNETMASK, (char *)temp) != -1)
293 memcpy(&ifs[count].netmask,
294 &(((struct sockaddr_in *)&temp->ifr_addr)->sin_addr),
295 sizeof(struct in_addr));
296 strncpy(ifs[count].ifname, cur->ifr_name, IFNAMSIZ);
297 if_get_mac_address(ifs[count].ifname, ifs[count].mac);
298 count++;
299 }
300 }
301 free(d.ifc_buf);
302 return count;
303 }
304
305 int
if_down(struct interface * areq)306 if_down(struct interface *areq) {
307 int i, ic, isvirtual = 0;
308 struct interface ifs[1024];
309
310 ic = if_list_ips(ifs, 1024);
311 for(i=0; i<ic; i++) {
312 if(!memcmp(&ifs[i].ipaddr, &(areq->ipaddr), sizeof(struct in_addr))) {
313 areq = NULL;
314 if(strchr(ifs[i].ifname, ':')) isvirtual=1;
315 break;
316 }
317 }
318 if(areq) return -1;
319 areq = ifs + i;
320 #ifdef SIOCLIFREMOVEIF
321 if(isvirtual) {
322 struct lifreq todo;
323
324 memset(&todo, 0, sizeof(todo));
325 strncpy(todo.lifr_name, areq->ifname, IFNAMSIZ);
326 ((struct sockaddr_in *)&todo.lifr_addr)->sin_family = AF_INET;
327 memcpy(&((struct sockaddr_in *)&todo.lifr_addr)->sin_addr, &areq->ipaddr,
328 sizeof(struct in_addr));
329 if(ioctl(_if_sock, SIOCLIFREMOVEIF, &todo) < 0) {
330 return -1;
331 }
332 return 0;
333 } else
334 #endif
335 {
336 /* Normal non-LIF code */
337 struct ifreq todo;
338
339 memset(&todo, 0, sizeof(todo));
340 strncpy(todo.ifr_name, areq->ifname, IFNAMSIZ);
341 ((struct sockaddr_in *)&todo.ifr_addr)->sin_family = AF_INET;
342 memset(&((struct sockaddr_in *)&todo.ifr_addr)->sin_addr, 0,
343 sizeof(struct in_addr));
344 ioctl(_if_sock, SIOCSIFADDR, &todo);
345 memset(&todo, 0, sizeof(todo));
346 strncpy(todo.ifr_name, areq->ifname, IFNAMSIZ);
347 if(ioctl(_if_sock, SIOCGIFFLAGS, &todo) < 0) {
348 _if_error = _if_error_alias_down_failed;
349 return -1;
350 }
351 if(todo.ifr_flags & IFF_UP) {
352 todo.ifr_flags &= ~IFF_UP;
353 if(ioctl(_if_sock, SIOCSIFFLAGS, &todo) < 0) {
354 _if_error = _if_error_alias_down_failed;
355 return -1;
356 }
357 }
358 if(!isvirtual) {
359 /* FIXME: unplumb here */
360 }
361 }
362 return 0;
363 }
364
365 int
if_up(struct interface * areq)366 if_up(struct interface *areq) {
367 int i, ic, intexists=0;
368 struct interface ifs[1024];
369 ic = if_list_ips(ifs, 1024);
370 for(i=0; i<ic; i++) {
371 if(!memcmp(&ifs[i].ipaddr, &(areq->ipaddr), sizeof(struct in_addr))) {
372 _if_error = _if_error_exists;
373 return 1;
374 }
375 if(!strcmp(ifs[i].ifname, areq->ifname))
376 intexists = 1;
377 }
378 #ifdef SIOCLIFADDIF
379 if(intexists) {
380 /* Use LIFREQ */
381 struct lifreq todo;
382 char vdev[LIFNAMSIZ];
383
384 memset(&todo, 0, sizeof(todo));
385 strncpy(todo.lifr_name, areq->ifname, LIFNAMSIZ);
386 ((struct sockaddr_in *)&todo.lifr_addr)->sin_family = AF_INET;
387 memcpy(&((struct sockaddr_in *)&todo.lifr_addr)->sin_addr, &areq->ipaddr,
388 sizeof(struct in_addr));
389 if(ioctl(_if_sock, SIOCLIFADDIF, &todo) < 0) {
390 _if_error = _if_error_alias_up_failed;
391 return -1;
392 }
393 strncpy(vdev, todo.lifr_name, LIFNAMSIZ);
394 memset(&todo, 0, sizeof(todo));
395 strncpy(todo.lifr_name, vdev, LIFNAMSIZ);
396 ((struct sockaddr_in *)&todo.lifr_addr)->sin_family = AF_INET;
397 memcpy(&((struct sockaddr_in *)&todo.lifr_addr)->sin_addr, &areq->netmask,
398 sizeof(struct in_addr));
399 if(ioctl(_if_sock, SIOCSLIFNETMASK, &todo) < 0) {
400 _if_error = _if_error_alias_up_failed;
401 goto baillifremove;
402 }
403 memset(&todo, 0, sizeof(todo));
404 strncpy(todo.lifr_name, vdev, LIFNAMSIZ);
405 ((struct sockaddr_in *)&todo.lifr_addr)->sin_family = AF_INET;
406 memcpy(&((struct sockaddr_in *)&todo.lifr_addr)->sin_addr, &areq->bcast,
407 sizeof(struct in_addr));
408 if(ioctl(_if_sock, SIOCSLIFBRDADDR, &todo) < 0) {
409 _if_error = _if_error_alias_up_failed;
410 goto baillifremove;
411 }
412 memset(&todo, 0, sizeof(todo));
413 strncpy(todo.lifr_name, vdev, LIFNAMSIZ);
414 if(ioctl(_if_sock, SIOCGLIFFLAGS, &todo) < 0) {
415 _if_error = _if_error_alias_up_failed;
416 goto baillifremove;
417 }
418 if(!(todo.lifr_flags & IFF_UP)) {
419 todo.lifr_flags |= IFF_UP;
420 if(ioctl(_if_sock, SIOCSLIFFLAGS, &todo) < 0) {
421 _if_error = _if_error_alias_up_failed;
422 goto baillifremove;
423 }
424 }
425 return 0;
426 baillifremove:
427 memset(&todo, 0, sizeof(todo));
428 strncpy(todo.lifr_name, areq->ifname, IFNAMSIZ);
429 ((struct sockaddr_in *)&todo.lifr_addr)->sin_family = AF_INET;
430 memcpy(&((struct sockaddr_in *)&todo.lifr_addr)->sin_addr, &areq->ipaddr,
431 sizeof(struct in_addr));
432 ioctl(_if_sock, SIOCLIFREMOVEIF, &todo);
433 } else {
434 #endif
435 /* old style */
436 if(intexists) {
437 /* We are not capable of LIFing, so we need to manually up an alias */
438 } else {
439 /* Main interface */
440 struct ifreq todo;
441 /* FIXME: we need to plumb here if necessary */
442
443 memset(&todo, 0, sizeof(todo));
444 strncpy(todo.ifr_name, areq->ifname, IFNAMSIZ);
445 ((struct sockaddr_in *)&todo.ifr_addr)->sin_family = AF_INET;
446 memcpy(&((struct sockaddr_in *)&todo.ifr_addr)->sin_addr, &areq->ipaddr,
447 sizeof(struct in_addr));
448 if(ioctl(_if_sock, SIOCSIFADDR, &todo) < 0) {
449 _if_error = _if_error_alias_up_failed;
450 return -1;
451 }
452 memset(&todo, 0, sizeof(todo));
453 strncpy(todo.ifr_name, areq->ifname, IFNAMSIZ);
454 ((struct sockaddr_in *)&todo.ifr_addr)->sin_family = AF_INET;
455 memcpy(&((struct sockaddr_in *)&todo.ifr_addr)->sin_addr, &areq->netmask,
456 sizeof(struct in_addr));
457 if(ioctl(_if_sock, SIOCSIFNETMASK, &todo) < 0) {
458 _if_error = _if_error_alias_up_failed;
459 goto bailifremove;
460 }
461 memset(&todo, 0, sizeof(todo));
462 strncpy(todo.ifr_name, areq->ifname, IFNAMSIZ);
463 ((struct sockaddr_in *)&todo.ifr_addr)->sin_family = AF_INET;
464 memcpy(&((struct sockaddr_in *)&todo.ifr_addr)->sin_addr, &areq->bcast,
465 sizeof(struct in_addr));
466 if(ioctl(_if_sock, SIOCSIFBRDADDR, &todo) < 0) {
467 _if_error = _if_error_alias_up_failed;
468 goto bailifremove;
469 }
470 memset(&todo, 0, sizeof(todo));
471 strncpy(todo.ifr_name, areq->ifname, IFNAMSIZ);
472 if(ioctl(_if_sock, SIOCGIFFLAGS, &todo) < 0) {
473 _if_error = _if_error_alias_up_failed;
474 goto bailifremove;
475 }
476 if(!(todo.ifr_flags & IFF_UP)) {
477 todo.ifr_flags |= IFF_UP;
478 if(ioctl(_if_sock, SIOCSIFFLAGS, &todo) < 0) {
479 _if_error = _if_error_alias_up_failed;
480 goto bailifremove;
481 }
482 }
483 return 0;
484 bailifremove:
485 memset(&todo, 0, sizeof(todo));
486 strncpy(todo.ifr_name, areq->ifname, IFNAMSIZ);
487 ((struct sockaddr_in *)&todo.ifr_addr)->sin_family = AF_INET;
488 memset(&((struct sockaddr_in *)&todo.ifr_addr)->sin_addr, 0,
489 sizeof(struct in_addr));
490 ioctl(_if_sock, SIOCSIFADDR, &todo);
491 }
492 #ifdef SIOCLIFADDIF
493 }
494 #endif
495 return -1;
496 }
497
498