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(&eth->ether_shost, my_mac, ETH_ALEN);
211   memcpy(&eth->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(&eth->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