libutil++  1.9.3
 All Classes Functions Variables
EtherSocket.cpp
1 /*
2 ** libutil++
3 ** $Id: EtherSocket.cpp 1653 2016-02-28 19:54:59Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: EtherSocket.cpp 1653 2016-02-28 19:54:59Z sella $";
10 
11 #include "EtherSocket.h"
12 #include "../util/Interface.h"
13 
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <string.h>
17 #include <net/if.h>
18 #include <net/ethernet.h>
19 
20 using namespace sella::net;
21 using namespace sella::util;
22 
23 const unsigned char EtherSocket::BroadcastMAC[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
24 
25 EtherSocket::EtherSocket(int etherType, const std::string &interface, bool raw) throw (SocketException) :
26  Socket(AF_PACKET, (raw) ? SOCK_RAW : SOCK_DGRAM, htons(etherType)),
27  etherType(etherType),
28  raw(raw)
29 {
30  try {
31  ifIndex = Interface::getIndex(interface);
32 
33  } catch (InterfaceException &e) {
34  RETHROW(SocketException, e);
35  }
36 }
37 
38 EtherSocket::EtherSocket(int etherType, int ifIndex, bool raw) throw (SocketException) :
39  Socket(AF_PACKET, (raw) ? SOCK_RAW : SOCK_DGRAM, htons(etherType)),
40  etherType(etherType),
41  ifIndex(ifIndex),
42  raw(raw)
43 { }
44 
45 EtherSocket::EtherSocket(int etherType, bool raw) throw (SocketException) :
46  Socket(AF_PACKET, (raw) ? SOCK_RAW : SOCK_DGRAM, htons(etherType)),
47  etherType(etherType),
48  ifIndex(-1),
49  raw(raw)
50 { }
51 
52 EtherSocket::~EtherSocket() {
53 }
54 
55 const EtherSocket::shared EtherSocket::shared_ptr(int etherType) throw (SocketException) {
56  return std::make_shared<EtherSocket>(etherType);
57 }
58 
59 EtherSocket& EtherSocket::setInterface(const std::string &interface) throw (SocketException) {
60  if ((ifIndex = if_nametoindex(interface.c_str())) == 0) {
61  THROW2(SocketException, "if_nametoindex()");
62  }
63 
64  return *this;
65 }
66 
67 EtherSocket& EtherSocket::setIfIndex(int ifIndex) throw () {
68  this->ifIndex = ifIndex;
69 
70  return *this;
71 }
72 
73 int EtherSocket::getEtherType(void) const throw () {
74  return etherType;
75 }
76 
77 std::string EtherSocket::getInterface(void) const throw (SocketException) {
78  char buf[IF_NAMESIZE];
79 
80  if (ifIndex == -1) {
81  THROW(SocketException, "Interface or index must be set prior to getInterface()");
82  }
83 
84  if (if_indextoname(ifIndex, buf) == NULL) {
85  THROW2(SocketException, "if_indextoname()");
86  }
87 
88  return buf;
89 }
90 
91 int EtherSocket::getIfIndex(void) const throw () {
92  return ifIndex;
93 }
94 
95 bool EtherSocket::isRaw(void) const throw () {
96  return raw;
97 }
98 
99 void EtherSocket::bindInterface(void) throw (SocketException) {
100  sockaddr_ll sll;
101  socklen_t addrlen = sizeof(sockaddr_ll);
102 
103  if (ifIndex == -1) {
104  THROW(SocketException, "Interface or index must be set prior to bindInterface()");
105  }
106 
107  sll.sll_family = AF_PACKET;
108  sll.sll_ifindex = ifIndex;
109  sll.sll_protocol = htons(etherType);
110 
111  if (::bind(s, (sockaddr*) &sll, addrlen) < 0) {
112  THROW2(SocketException, "bind()");
113  }
114 }
115 
116 void EtherSocket::setSoBindToDevice(const std::string &interface) throw (SocketException) {
117  Socket::setSoBindToDevice(interface);
118 }
119 
120 void EtherSocket::setSoBindToDevice(void) throw (SocketException) {
121  Socket::setSoBindToDevice(getInterface());
122 }
123 
124 void EtherSocket::setPromiscous(bool on) throw (SocketException) {
125  struct ifreq ifr;
126 
127  if (ifIndex == -1) {
128  THROW(SocketException, "Interface or index must be set prior to setPromiscous()");
129  }
130 
131  const std::string &name = getInterface();
132  memset(&ifr, 0, sizeof(ifr));
133 
134  strncpy(ifr.ifr_name, name.c_str(), name.size());
135 
136  if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
137  THROW2(SocketException, "ioctl()");
138  }
139 
140  if (on) {
141  ifr.ifr_flags |= IFF_PROMISC;
142  } else {
143  ifr.ifr_flags &= ~IFF_PROMISC;
144  }
145 
146  if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
147  THROW2(SocketException, "ioctl()");
148  }
149 }
150 
151 ssize_t EtherSocket::sendto(const void *data, size_t len, const std::string &dst_mac, int flags) throw (SocketException) {
152  unsigned char addr[6] = { 0, 0, 0, 0, 0, 0 };
153 
154  try {
155  Interface::convertMAC(addr, dst_mac);
156  } catch (InterfaceException &e) {
157  RETHROW(SocketException, e);
158  }
159 
160  return sendto(data, len, addr, flags);
161 }
162 
163 ssize_t EtherSocket::sendto(const void *data, size_t len, const unsigned char *dst_mac, int flags) throw (SocketException) {
164  sockaddr_ll dest_addr = { 0 };
165  socklen_t addrlen = sizeof(sockaddr_ll);
166 
167  if (ifIndex == -1) {
168  THROW(SocketException, "Interface must be set prior to sendto()");
169  }
170 
171  dest_addr.sll_family = AF_PACKET;
172  dest_addr.sll_ifindex = ifIndex;
173  dest_addr.sll_halen = ETHER_ADDR_LEN;
174  dest_addr.sll_protocol = htons(etherType);
175  memcpy(dest_addr.sll_addr, dst_mac, ETHER_ADDR_LEN);
176 
177  return sendto(data, len, flags, (const struct sockaddr_ll*) &dest_addr, addrlen);
178 }
179 
180 ssize_t EtherSocket::sendto(const void *data, size_t len, int flags, const sockaddr_ll *dest_addr, socklen_t addrlen) throw (SocketException) {
181  ssize_t c, r = len;
182 
183  do {
184  if ((c = ::sendto(s, data, len, flags, (const struct sockaddr*) dest_addr, addrlen)) < 0) {
185  switch (errno) {
186  case EINTR:
187  case EAGAIN:
188  case EMSGSIZE:
189  case ENOBUFS:
190  break;
191 
192  default:
193  usable = false;
194  }
195 
196  THROW2(SocketException, "sendto()");
197  } else if (c == 0) {
198  usable = false;
199  }
200  } while ((r -= c) > 0);
201 
202  write = false;
203 
204  return len;
205 }
206 
207 ssize_t EtherSocket::recvfrom(void *data, size_t len, int flags, sockaddr_ll *src_addr, socklen_t *addrlen) throw (SocketException) {
208  ssize_t c;
209 
210  if ((c = ::recvfrom(s, data, len, flags, (sockaddr*) src_addr, addrlen)) < 0) {
211  switch (errno) {
212  case EINTR:
213  case EAGAIN:
214  break;
215 
216  default:
217  usable = false;
218  }
219 
220  THROW2(SocketException, "recv()");
221  } else if (c == 0) {
222  usable = false;
223  }
224 
225  read = except = false;
226 
227  return c;
228 }
229 
230 ssize_t EtherSocket::recvfrom(void *data, size_t len, std::string &src_mac, int flags) throw (SocketException) {
231  sockaddr_ll src_addr;
232  socklen_t addrlen = sizeof(sockaddr_ll);
233  ssize_t c;
234 
235  if ((c = recvfrom(data, len, flags, (sockaddr_ll*) &src_addr, &addrlen)) > 0) {
236  Interface::convertMAC(src_mac, (const unsigned char*) src_addr.sll_addr);
237  } else {
238  src_mac.clear();
239  }
240 
241  return c;
242 }
243 
244 /*
245 ** vim: noet ts=3 sw=3
246 */