gratuitous.c 7.16 KB
Newer Older
Benoit Steiner's avatar
Benoit Steiner committed
1 2 3 4 5 6 7 8 9 10 11
/* VideoLAN VLANbridge : gratuitous.c
 *
 * Benoit Steiner, ECP, <benny@via.ecp.fr>
 *
 * Heavily inspired from dhcpcd - DHCP client daemon -
 *   Copyright (C) 1996-1997 Yoichi Hariguchi <yoichi@fore.com>
 *
 * TO DO: 
 */


Benoit Steiner's avatar
Benoit Steiner committed
12 13 14 15
/* For Solaris */
#include <sys/types.h>
#include <strings.h>

Benoit Steiner's avatar
Benoit Steiner committed
16 17 18 19
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_arp.h>
Benoit Steiner's avatar
Benoit Steiner committed
20
#include <net/ethernet.h>
Benoit Steiner's avatar
Benoit Steiner committed
21 22 23 24 25 26 27 28 29 30
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "log.h"
#include "gratuitous.h"

Benoit Steiner's avatar
Benoit Steiner committed
31 32
#define MAC_BCAST	"\xff\xff\xff\xff\xff\xff"
#define IP_BCAST	"\xff\xff\xff\xff"
Benoit Steiner's avatar
Benoit Steiner committed
33 34 35 36 37 38 39

#define MOD_NAME MOD_PERFORMER


/* ARP message which will be send in the raw socket */
struct s_ARPMsg
{
Benoit Steiner's avatar
Benoit Steiner committed
40
  struct ether_header ethhdr;   /* Ethernet header */
Benoit Steiner's avatar
Benoit Steiner committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
  u_short htype;	       	/* hardware type (must be ARPHRD_ETHER) */
  u_short ptype;	       	/* protocol type (must be ETH_P_IP) */
  u_char  hlen;		       	/* hardware address length (must be 6) */
  u_char  plen;		       	/* protocol address length (must be 4) */
  u_short operation;	       	/* ARP opcode */
  u_char  sHwaddr[6];	       	/* sender's hardware address */
  u_char  sInaddr[4];	       	/* sender's IP address */
  u_char  tHwaddr[6];	       	/* target's hardware address */
  u_char  tInaddr[4];	       	/* target's IP address */
  u_char  pad[18];	       	/* pad for min Ethernet payload (60 bytes) */
};


/***************************************************************************/
/* Builds the gratuitous ARP message					   */
/***************************************************************************/
int MakeMsg (const char* pTInAddr, const char* pTHwAddr,
             const char* pSInAddr, const char* pSHwAddr,
Benoit Steiner's avatar
Benoit Steiner committed
59
             /*const char* pSHwSendAddr,*/ struct s_ARPMsg* pamPacket)
Benoit Steiner's avatar
Benoit Steiner committed
60 61 62
{
  bzero(pamPacket, sizeof(*pamPacket));

Benoit Steiner's avatar
Benoit Steiner committed
63
  bcopy(MAC_BCAST, pamPacket->ethhdr.ether_dhost, 6);	/* MAC destination address */
Benoit Steiner's avatar
Benoit Steiner committed
64
  bcopy(pSHwAddr/*pSHwSendAddr*/, pamPacket->ethhdr.ether_shost, 6);	/* MAC source address */
Benoit Steiner's avatar
Benoit Steiner committed
65
  pamPacket->ethhdr.ether_type = htons(ETHERTYPE_ARP);	/* protocol type (Ethernet) */
Benoit Steiner's avatar
Benoit Steiner committed
66 67

  pamPacket->htype = htons(ARPHRD_ETHER);		/* hardware type */
Benoit Steiner's avatar
Benoit Steiner committed
68
  pamPacket->ptype = htons(ETHERTYPE_IP);		/* protocol type (IP) */
Benoit Steiner's avatar
Benoit Steiner committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
  pamPacket->hlen = 6;					/* hardware address length */
  pamPacket->plen = 4;					/* protocol address length */
  pamPacket->operation = htons(ARPOP_REQUEST);		/* ARP op code */

  bcopy(pSHwAddr, pamPacket->sHwaddr, 6);		/* source hardware address */
  bcopy(pSInAddr, pamPacket->sInaddr, 4);		/* source IP address */
  bcopy(pTHwAddr, pamPacket->tHwaddr, 6);		/* target hardware address */
  bcopy(pTInAddr, pamPacket->tInaddr, 4);		/* target IP address */

  return 0;
};


/***************************************************************************/
/* Open and configure a socket to send the gratuitous packet   		   */
/***************************************************************************/
int OpenSocket(int* piSockFd)
{
  int iRc = 0;
  int iOptVal = 1;

Benoit Steiner's avatar
Benoit Steiner committed
90
  *piSockFd = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_ARP));
Benoit Steiner's avatar
Benoit Steiner committed
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123

  if (*piSockFd < 0)
  {
    Log (LOG_ERROR, MOD_NAME, "Unable to open socket to send gratuitous ARP: %s",
         strerror(errno));
    iRc = errno;
  }
  else
  {
    if (setsockopt(*piSockFd, SOL_SOCKET, SO_BROADCAST, &iOptVal, sizeof(&iOptVal)) < 0)
    {
      Log (LOG_ERROR, MOD_NAME, "Unable to configure socket to send gratuitous ARPs: %s",
           strerror(errno));
      iRc = errno;
    }
  }

  return iRc;
}


/***************************************************************************/
/* Send the gratuitous ARP packet 					   */
/***************************************************************************/
int SendMsg (const char* strDev, const struct s_ARPMsg* pamPacket, int iSockFd)
{
  int iRc = 0;
  struct sockaddr saIfName;

  /* Set the interface to use */
  bzero(&saIfName, sizeof(saIfName));
  strcpy(saIfName.sa_data, strDev);

Benoit Steiner's avatar
Benoit Steiner committed
124
  if (sendto(iSockFd, (char *)pamPacket, sizeof(*pamPacket), 0, &saIfName,
Benoit Steiner's avatar
Benoit Steiner committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
      sizeof(saIfName)) < 0)
  {
    Log(LOG_ERROR, MOD_NAME, "Unable to send gratuitous ARP: %s",
        strerror(errno));
    iRc = errno;
  }
  
  return iRc;
}


/***************************************************************************/
/* Get the IP address of a specified interface				   */
/***************************************************************************/
int GetDevPa (const char* strIfName, struct sockaddr* psaHwAddr, int iSockFd)
{
  int iRc = 0;
  struct ifreq ifrRequest;
  
  /* Get IP address of the device */
  strcpy(ifrRequest.ifr_name, strIfName);

  if (ioctl(iSockFd, SIOCGIFDSTADDR, &ifrRequest) < 0 )
  {
    Log (LOG_ERROR, MOD_NAME, "Unable to retrieve %s IP address: %s",
         strIfName, strerror (errno));
    iRc = errno;
  }
  
  /* Copy it to the sockaddr struct */
  if (!iRc)
    memcpy(psaHwAddr, &(ifrRequest.ifr_hwaddr), sizeof(struct sockaddr));

  return iRc;
};


/***************************************************************************/
/* Get the hardware address of a specified interface			   */
/***************************************************************************/
int GetDevHw (const char* strIfName, struct sockaddr* psaHwAddr, int iSockFd)
{
  int iRc = 0;
  struct ifreq ifrRequest;
  
  /* Get hardware address of the device */
  strcpy(ifrRequest.ifr_name, strIfName);

  if (ioctl(iSockFd, SIOCGIFHWADDR, &ifrRequest) < 0 )
  {
    Log (LOG_ERROR, MOD_NAME, "Unable to retrieve %s MAC address: %s",
         strIfName, strerror (errno));
    iRc = errno;
  }
  
  /* Copy it to the sockaddr struct */
  if (!iRc)
    memcpy(psaHwAddr, &(ifrRequest.ifr_hwaddr), sizeof(struct sockaddr));

  return iRc;
};



/***************************************************************************/
/* Sends a gratuitous ARP                                                  */
/***************************************************************************/
int Gratuitous_Send(const struct sockaddr_in* psaFakeIP,
                    const struct sockaddr* psaFakeHw, const char* strDev)
{
  int iRc = 0;
  struct s_ARPMsg* pamPacket;
Benoit Steiner's avatar
Benoit Steiner committed
197 198
//  struct sockaddr saDevHwAddr;
//  struct sockaddr saDevPaAddr;
Benoit Steiner's avatar
Benoit Steiner committed
199 200 201 202 203 204 205
  int iSockFd;

  /* Open the socket used to send the gratuitous ARP */
  iRc = OpenSocket(&iSockFd);

  /* Get hardware and protocol addresses of the device on which the packet
     will be sent */
Benoit Steiner's avatar
Benoit Steiner committed
206 207 208 209 210
//  if (!iRc)
//  {
//    iRc = GetDevHw(strDev, &saDevHwAddr, iSockFd);
//    iRc |= GetDevPa(strDev, &saDevPaAddr, iSockFd);
//  }
Benoit Steiner's avatar
Benoit Steiner committed
211 212 213 214 215 216 217 218 219 220 221 222
  
  /* Build gratuitous ARP packet */
  if (!iRc)
  {
    pamPacket = (struct s_ARPMsg *)malloc(sizeof(struct s_ARPMsg));
    if (pamPacket == NULL)
    {
      Log (LOG_ERROR, MOD_NAME, "Unable to create gratuitous ARP packet");
      iRc = -1;
    }
    else
      iRc = MakeMsg((char *)&psaFakeIP->sin_addr, psaFakeHw->sa_data,
Benoit Steiner's avatar
Benoit Steiner committed
223
                    (char *)&psaFakeIP->sin_addr, psaFakeHw->sa_data, pamPacket);
Benoit Steiner's avatar
Benoit Steiner committed
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
  }
  
  /* Send the packet */
  if (!iRc)
    iRc = SendMsg (strDev, pamPacket, iSockFd);
  
  if (iRc)
    Log (LOG_WARN, MOD_NAME, "Gratuitous ARP packet for host %s not sent on %s",
         inet_ntoa (psaFakeIP->sin_addr), strDev);

  /* Close the socket */
  if (close (iSockFd) < 0)
    Log (LOG_ERROR, MOD_NAME, "Unable to close socket");
  
  return iRc;
}