+/********************************************************************
+ *
+ * cif6defaultroute - delete a default route through the address given.
+ */
+
+int cif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
+{
+ struct in6_rtmsg rt;
+
+ have_default_route6 = 0;
+
+ memset (&rt, '\0', sizeof (rt));
+
+ rt.rtmsg_ifindex = if_nametoindex(ifname);
+ rt.rtmsg_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
+ rt.rtmsg_dst_len = 0;
+
+ rt.rtmsg_flags = RTF_UP;
+ if (ioctl(sock6_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp()) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+#endif /* INET6 */
+
+/********************************************************************
+ *
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+
+int sifproxyarp (int unit, u_int32_t his_adr)
+{
+ struct arpreq arpreq;
+ char *forw_path;
+
+ if (has_proxy_arp == 0) {
+ memset (&arpreq, '\0', sizeof(arpreq));
+
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ SIN_ADDR(arpreq.arp_pa) = his_adr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+/*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(his_adr, &arpreq.arp_ha, proxy_arp_dev,
+ sizeof(proxy_arp_dev))) {
+ error("Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+ strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
+
+ if (ioctl(sock_fd, SIOCSARP, (caddr_t)&arpreq) < 0) {
+ if ( ! ok_error ( errno ))
+ error("ioctl(SIOCSARP): %m");
+ return 0;
+ }
+ proxy_arp_addr = his_adr;
+ has_proxy_arp = 1;
+
+ if (tune_kernel) {
+ forw_path = path_to_procfs("/sys/net/ipv4/ip_forward");
+ if (forw_path != 0) {
+ int fd = open(forw_path, O_WRONLY);
+ if (fd >= 0) {
+ if (write(fd, "1", 1) != 1)
+ error("Couldn't enable IP forwarding: %m");
+ close(fd);
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+
+int cifproxyarp (int unit, u_int32_t his_adr)
+{
+ struct arpreq arpreq;
+
+ if (has_proxy_arp) {
+ has_proxy_arp = 0;
+ memset (&arpreq, '\0', sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ SIN_ADDR(arpreq.arp_pa) = his_adr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
+
+ if (ioctl(sock_fd, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ if ( ! ok_error ( errno ))
+ warn("ioctl(SIOCDARP): %m");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/********************************************************************
+ *
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+
+static int get_ether_addr (u_int32_t ipaddr,
+ struct sockaddr *hwaddr,
+ char *name, int namelen)
+{
+ struct ifreq *ifr, *ifend;
+ u_int32_t ina, mask;
+ char *aliasp;
+ struct ifreq ifreq, bestifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ u_int32_t bestmask=0;
+ int found_interface = 0;
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sock_fd, SIOCGIFCONF, &ifc) < 0) {
+ if ( ! ok_error ( errno ))
+ error("ioctl(SIOCGIFCONF): %m (line %d)", __LINE__);
+ return 0;
+ }
+
+/*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ ina = SIN_ADDR(ifr->ifr_addr);
+ strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+/*
+ * Check that the interface is up, and not point-to-point
+ * nor loopback.
+ */
+ if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+
+ if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
+ continue;
+/*
+ * Get its netmask and check that it's on the right subnet.
+ */
+ if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+
+ mask = SIN_ADDR(ifreq.ifr_addr);
+
+ if (((ipaddr ^ ina) & mask) != 0)
+ continue; /* no match */
+ /* matched */
+ if (mask >= bestmask) {
+ /* Compare using >= instead of > -- it is possible for
+ an interface to have a netmask of 0.0.0.0 */
+ found_interface = 1;
+ bestifreq = ifreq;
+ bestmask = mask;
+ }
+ }
+ }
+
+ if (!found_interface) return 0;
+
+ strlcpy(name, bestifreq.ifr_name, namelen);
+
+ /* trim off the :1 in eth0:1 */
+ aliasp = strchr(name, ':');
+ if (aliasp != 0)
+ *aliasp = 0;
+
+ info("found interface %s for proxy arp", name);
+/*
+ * Now get the hardware address.
+ */
+ memset (&bestifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
+ if (ioctl (sock_fd, SIOCGIFHWADDR, &bestifreq) < 0) {
+ error("SIOCGIFHWADDR(%s): %m", bestifreq.ifr_name);
+ return 0;
+ }
+
+ memcpy (hwaddr,
+ &bestifreq.ifr_hwaddr,
+ sizeof (struct sockaddr));
+
+ return 1;
+}
+
+/*
+ * get_if_hwaddr - get the hardware address for the specified
+ * network interface device.
+ */
+int
+get_if_hwaddr(u_char *addr, char *name)
+{
+ struct ifreq ifreq;
+ int ret, sock_fd;
+
+ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0)
+ return -1;
+ memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr));
+ strlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
+ ret = ioctl(sock_fd, SIOCGIFHWADDR, &ifreq);
+ close(sock_fd);
+ if (ret >= 0)
+ memcpy(addr, ifreq.ifr_hwaddr.sa_data, 6);
+ return ret;
+}
+
+/*
+ * get_first_ether_hwaddr - get the hardware address for the first
+ * ethernet-style interface on this system.
+ */
+int
+get_first_ether_hwaddr(u_char *addr)
+{
+ struct if_nameindex *if_ni, *i;
+ struct ifreq ifreq;
+ int ret, sock_fd;
+
+ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0)
+ return -1;
+
+ if_ni = if_nameindex();
+ if (!if_ni) {
+ close(sock_fd);
+ return -1;
+ }
+
+ ret = -1;
+
+ for (i = if_ni; !(i->if_index == 0 && i->if_name == NULL); i++) {
+ memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr));
+ strlcpy(ifreq.ifr_name, i->if_name, sizeof(ifreq.ifr_name));
+ ret = ioctl(sock_fd, SIOCGIFHWADDR, &ifreq);
+ if (ret >= 0 && ifreq.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
+ memcpy(addr, ifreq.ifr_hwaddr.sa_data, 6);
+ break;
+ }
+ ret = -1;
+ }
+
+ if_freenameindex(if_ni);
+ close(sock_fd);
+
+ return ret;
+}
+
+/********************************************************************
+ *
+ * Return user specified netmask, modified by any mask we might determine