1 /*********************************************************************** 2 * 3 * if.c 4 * 5 * Implementation of user-space PPPoE redirector for Linux. 6 * 7 * Functions for opening a raw socket and reading/writing raw Ethernet frames. 8 * 9 * Copyright (C) 2000 by Roaring Penguin Software Inc. 10 * 11 * This program may be distributed according to the terms of the GNU 12 * General Public License, version 2 or (at your option) any later version. 13 * 14 ***********************************************************************/ 15 16 #ifdef HAVE_CONFIG_H 17 #include "config.h" 18 #endif 19 20 #define _GNU_SOURCE 1 21 #include "pppoe.h" 22 #include <pppd/pppd.h> 23 24 #ifdef HAVE_UNISTD_H 25 #include <unistd.h> 26 #endif 27 28 #ifdef HAVE_NETPACKET_PACKET_H 29 #include <netpacket/packet.h> 30 #elif defined(HAVE_LINUX_IF_PACKET_H) 31 #include <linux/if_packet.h> 32 #endif 33 34 #ifdef HAVE_ASM_TYPES_H 35 #include <asm/types.h> 36 #endif 37 38 #ifdef HAVE_SYS_IOCTL_H 39 #include <sys/ioctl.h> 40 #endif 41 42 #include <errno.h> 43 #include <stdlib.h> 44 #include <string.h> 45 46 #ifdef HAVE_NET_IF_ARP_H 47 #include <net/if_arp.h> 48 #endif 49 50 /* Initialize frame types to RFC 2516 values. Some broken peers apparently 51 use different frame types... sigh... */ 52 53 UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY; 54 UINT16_t Eth_PPPOE_Session = ETH_PPPOE_SESSION; 55 56 /********************************************************************** 57 *%FUNCTION: etherType 58 *%ARGUMENTS: 59 * packet -- a received PPPoE packet 60 *%RETURNS: 61 * ethernet packet type (see /usr/include/net/ethertypes.h) 62 *%DESCRIPTION: 63 * Checks the ethernet packet header to determine its type. 64 * We should only be receveing DISCOVERY and SESSION types if the BPF 65 * is set up correctly. Logs an error if an unexpected type is received. 66 * Note that the ethernet type names come from "pppoe.h" and the packet 67 * packet structure names use the LINUX dialect to maintain consistency 68 * with the rest of this file. See the BSD section of "pppoe.h" for 69 * translations of the data structure names. 70 ***********************************************************************/ 71 UINT16_t 72 etherType(PPPoEPacket *packet) 73 { 74 UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto); 75 if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) { 76 error("Invalid ether type 0x%x", type); 77 } 78 return type; 79 } 80 81 /********************************************************************** 82 *%FUNCTION: openInterface 83 *%ARGUMENTS: 84 * ifname -- name of interface 85 * type -- Ethernet frame type 86 * hwaddr -- if non-NULL, set to the hardware address 87 *%RETURNS: 88 * A raw socket for talking to the Ethernet card. Exits on error. 89 *%DESCRIPTION: 90 * Opens a raw Ethernet socket 91 ***********************************************************************/ 92 int 93 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) 94 { 95 int optval=1; 96 int fd; 97 struct ifreq ifr; 98 int domain, stype; 99 size_t maxlen; 100 101 #ifdef HAVE_STRUCT_SOCKADDR_LL 102 struct sockaddr_ll sa; 103 #else 104 struct sockaddr sa; 105 #endif 106 107 memset(&sa, 0, sizeof(sa)); 108 109 #ifdef HAVE_STRUCT_SOCKADDR_LL 110 domain = PF_PACKET; 111 stype = SOCK_RAW; 112 maxlen = IFNAMSIZ; 113 #else 114 domain = PF_INET; 115 stype = SOCK_PACKET; 116 maxlen = sizeof(sa.sa_data); 117 #endif 118 119 if (strlen(ifname) >= maxlen) { 120 error("Can't use interface %.16s: name is too long", ifname); 121 return -1; 122 } 123 124 if ((fd = socket(domain, stype, htons(type))) < 0) { 125 /* Give a more helpful message for the common error case */ 126 if (errno == EPERM) { 127 fatal("Cannot create raw socket -- pppoe must be run as root."); 128 } 129 error("Can't open socket for pppoe: %m"); 130 return -1; 131 } 132 133 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) { 134 error("Can't set socket options for pppoe: %m"); 135 close(fd); 136 return -1; 137 } 138 139 /* Fill in hardware address */ 140 if (hwaddr) { 141 strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 142 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { 143 error("Can't get hardware address for %s: %m", ifname); 144 close(fd); 145 return -1; 146 } 147 memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); 148 #ifdef ARPHRD_ETHER 149 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { 150 warn("Interface %.16s is not Ethernet", ifname); 151 } 152 #endif 153 if (NOT_UNICAST(hwaddr)) { 154 fatal("Can't use interface %.16s: it has broadcast/multicast MAC address", 155 ifname); 156 } 157 } 158 159 /* Sanity check on MTU */ 160 strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 161 if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) { 162 error("Can't get MTU for %s: %m", ifname); 163 } else if (ifr.ifr_mtu < ETH_DATA_LEN) { 164 error("Interface %.16s has MTU of %d -- should be at least %d.", 165 ifname, ifr.ifr_mtu, ETH_DATA_LEN); 166 error("This may cause serious connection problems."); 167 } 168 169 #ifdef HAVE_STRUCT_SOCKADDR_LL 170 /* Get interface index */ 171 sa.sll_family = AF_PACKET; 172 sa.sll_protocol = htons(type); 173 174 strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 175 if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) { 176 error("Could not get interface index for %s: %m", ifname); 177 close(fd); 178 return -1; 179 } 180 sa.sll_ifindex = ifr.ifr_ifindex; 181 182 #else 183 strlcpy(sa.sa_data, ifname, sizeof(sa.sa_data)); 184 #endif 185 186 /* We're only interested in packets on specified interface */ 187 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { 188 error("Failed to bind to interface %s: %m", ifname); 189 close(fd); 190 return -1; 191 } 192 193 return fd; 194 } 195 196 197 /*********************************************************************** 198 *%FUNCTION: sendPacket 199 *%ARGUMENTS: 200 * sock -- socket to send to 201 * pkt -- the packet to transmit 202 * size -- size of packet (in bytes) 203 *%RETURNS: 204 * 0 on success; -1 on failure 205 *%DESCRIPTION: 206 * Transmits a packet 207 ***********************************************************************/ 208 int 209 sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size) 210 { 211 int err; 212 213 if (debug_on()) 214 pppoe_log_packet("Send ", pkt); 215 #if defined(HAVE_STRUCT_SOCKADDR_LL) 216 err = send(sock, pkt, size, 0); 217 #else 218 struct sockaddr sa; 219 220 strlcpy(sa.sa_data, conn->ifName, sizeof(sa.sa_data)); 221 err = sendto(sock, pkt, size, 0, &sa, sizeof(sa)); 222 #endif 223 if (err < 0) { 224 error("error sending pppoe packet: %m"); 225 return -1; 226 } 227 return 0; 228 } 229 230 /*********************************************************************** 231 *%FUNCTION: receivePacket 232 *%ARGUMENTS: 233 * sock -- socket to read from 234 * pkt -- place to store the received packet 235 * size -- set to size of packet in bytes 236 *%RETURNS: 237 * >= 0 if all OK; < 0 if error 238 *%DESCRIPTION: 239 * Receives a packet 240 ***********************************************************************/ 241 int 242 receivePacket(int sock, PPPoEPacket *pkt, int *size) 243 { 244 if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) { 245 error("error receiving pppoe packet: %m"); 246 return -1; 247 } 248 if (debug_on()) 249 pppoe_log_packet("Recv ", pkt); 250 return 0; 251 } 252