scclib
Stable Cloud Computing C++ Library
net_if.cc
Go to the documentation of this file.
1 /*
2 BSD 3-Clause License
3 
4 Copyright (c) 2022, Stable Cloud Computing, Inc.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9 1. Redistributions of source code must retain the above copyright notice, this
10  list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright notice,
13  this list of conditions and the following disclaimer in the documentation
14  and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17  contributors may be used to endorse or promote products derived from
18  this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <net/net_if.h>
32 #include <cassert>
33 #include <vector>
34 #include <map>
35 #include <sstream>
36 #include <iostream>
37 #include <iomanip>
38 #include <sys/socket.h>
39 #include <ifaddrs.h>
40 #include <string.h>
41 #include <sys/ioctl.h>
42 #include <linux/if_packet.h>
43 #include <net/if.h>
44 #include <fstream>
45 #include <sys/types.h>
46 #include <netdb.h>
47 #include <util/filedesc.h>
48 #include <net/inet.h>
49 
55 using namespace scc::net;
56 
57 std::vector<InetAddr> NetIf::host_addrs(const std::string& name, NetIf::SocketType type)
58 {
59  std::vector<InetAddr> ret_vect;
60 
61  addrinfo* ai = nullptr;
62  addrinfo hints;
63  memset(&hints, 0, sizeof(addrinfo));
64  hints.ai_family = AF_INET6;
65 
66  if (type == NetIf::SocketType::tcp_stream) hints.ai_socktype |= SOCK_STREAM;
67  if (type == NetIf::SocketType::udp_datagram) hints.ai_socktype |= SOCK_DGRAM;
68 
69  hints.ai_flags = AI_V4MAPPED|AI_ADDRCONFIG;
70 
71  int res = getaddrinfo(name.c_str(), nullptr, &hints, &ai);
72 
73  if (res != 0)
74  {
75  freeaddrinfo(ai);
76  return ret_vect;
77  }
78 
79  addrinfo* cur = ai;
80  while (cur)
81  {
82  ret_vect.emplace_back(cur->ai_addr);
83  cur = cur->ai_next;
84  }
85 
86  freeaddrinfo(ai);
87 
88  return ret_vect;
89 }
90 
93 std::string NetIfAddr::str() const
94 {
95  std::stringstream s;
96  s << InetAddr::str() << " name: " << m_name;
97  return s.str();
98 }
99 
100 std::ostream& operator<<(std::ostream& os, const scc::net::NetIfAddr& nad)
101 {
102  return os.write(nad.str().c_str(), nad.str().size());
103 }
104 
105 std::vector<NetIf> NetIf::all_interfaces()
106 {
107  std::map<int, NetIf> xref;
108 
109  ifaddrs* ifs;
110  int ret;
111  do
112  {
113  ret = getifaddrs(&ifs);
114  }
115  while (ret == -1 && errno == EINTR);
116 
117  if (ret == -1)
118  {
119  throw std::system_error(errno, std::system_category(), "getifaddrs()");
120  }
121 
122  for (ifaddrs* ad = ifs; ad != nullptr; ad = ad->ifa_next)
123  {
124  sockaddr* sa = ad->ifa_addr; // get the address
125  if (sa == nullptr)
126  continue;
127 
128  if (sa->sa_family == AF_PACKET) // this is a packet device, it will always come before the associated addresses
129  {
130 
131  sockaddr_ll* x = (sockaddr_ll*)sa; // this is the mac address (low level address)
132  std::stringstream hwad;
133  for (int i = 0; i < 6; i++)
134  {
135  hwad << std::setw(2) << std::setfill('0') << std::hex;
136  hwad << (int)x->sll_addr[i];
137  hwad << std::setw(0) << std::setfill(' ') << std::dec;
138  if (i != 5)
139  hwad << ":";
140  }
141 
142  NetIf nif(ad->ifa_name, hwad.str(), ad->ifa_flags);
143  xref[nif.index()] = std::move(nif);
144  }
145  else if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) // these are network addresses associated with packet device
146  {
147  int idx;
148  do
149  {
150  idx = if_nametoindex(ad->ifa_name);
151  }
152  while (idx == 0 && errno == EINTR);
153  assert(idx);
154  assert(xref.find(idx) != xref.end());
155 
156  NetIfAddr na(ad->ifa_name, InetAddr(sa));
157 
158  xref[idx].m_addrs.push_back(na);
159  }
160  }
161 
162  freeifaddrs(ifs);
163 
164  std::vector<NetIf> if_ret;
165 
166  // return in index order
167  for (auto& i : xref)
168  {
169  if_ret.push_back(std::move(i.second));
170  }
171 
172  return if_ret;
173 }
174 
175 int NetIf::parse_flags(unsigned flags)
176 {
177  int ret = 0;
178 
179  if ((flags&IFF_UP)==IFF_UP) { ret |= NetIfFlag::if_up; }
180  if ((flags&IFF_LOOPBACK)==IFF_LOOPBACK) { ret |= NetIfFlag::if_loopback; }
181  if ((flags&IFF_POINTOPOINT)==IFF_POINTOPOINT) { ret |= NetIfFlag::if_pointtopoint; }
182  if ((flags&IFF_RUNNING)==IFF_RUNNING) { ret |= NetIfFlag::if_running; }
183  if ((flags&IFF_BROADCAST)==IFF_BROADCAST) { ret |= NetIfFlag::if_broadcast; }
184  if ((flags&IFF_NOARP)==IFF_NOARP) { ret |= NetIfFlag::if_noarp; }
185  if ((flags&IFF_PROMISC)==IFF_PROMISC) { ret |= NetIfFlag::if_promisc; }
186  if ((flags&IFF_ALLMULTI)==IFF_ALLMULTI) { ret |= NetIfFlag::if_allmulti; }
187  if ((flags&IFF_MULTICAST)==IFF_MULTICAST) { ret |= NetIfFlag::if_multicast; }
188  if ((flags&IFF_DYNAMIC)==IFF_DYNAMIC) { ret |= NetIfFlag::if_dynamic; }
189 // IFF_ECHO is not available on all kernel versions
190 #ifdef IFF_ECHO
191  if ((flags&IFF_ECHO)==IFF_ECHO) { ret |= NetIfFlag::if_echo; }
192 #endif
193  return ret;
194 }
195 
196 NetIf::NetIf(const std::string& name, const std::string& hwaddr, int flags)
197  : m_name(name), m_hwaddr(hwaddr), m_index(find_index(name)), m_speed(0), m_mtu(0), m_flags(parse_flags(flags))
198 {
199  try
200  {
201  std::string b("/sys/class/net/");
202  auto f = std::fstream(b+m_name+"/mtu", std::ios_base::in);
203  f >> m_mtu;
204  f.close();
205  if (m_name != "lo")
206  {
207  f = std::fstream(b+m_name+"/speed", std::ios_base::in);
208  f >> m_speed;
209  m_speed /= 8; // bits/char
210  m_speed *= 1e6; // mega
211  f.close();
212  }
213  } catch (...) {} // allow exceptions on optional info
214 }
215 
216 int NetIf::find_index(const std::string& name)
217 {
218  assert(name.size());
219  int sock = ::socket(AF_ROUTE, SOCK_RAW, 0); // get the interface index by most portable method
220  assert(sock != -1);
221  scc::util::FileDesc fdsock(sock); // auto close wrapper
222 
223  ifreq ifr; // from man netdevice
224  strcpy(ifr.ifr_name, name.c_str());
225  int ret;
226  do
227  {
228  ret = ::ioctl(sock, SIOCGIFINDEX, &ifr);
229  }
230  while (ret == -1 && errno == EINTR);
231  assert(ret != -1);
232  return ifr.ifr_ifindex;
233 }
234 
237 std::string NetIf::str() const
238 {
239  std::stringstream s;
240  s << index() << " " << name() << " hwaddr: " << hw_addr() << " speed: " << speed() << " mtu: " << mtu() << std::endl;
241  s << " flags: ";
242  bool sp = false;
243  if ((m_flags&if_up)==if_up) { s << "up"; sp = true; }
244  if ((m_flags&if_broadcast)==if_broadcast) { if (sp) s << " "; s << "broadcast"; sp = true; }
245  if ((m_flags&if_loopback)==if_loopback) { if (sp) s << " "; s << "loopback"; sp = true; }
246  if ((m_flags&if_pointtopoint)==if_pointtopoint) { if (sp) s << " "; s << "point2point"; sp = true; }
247  if ((m_flags&if_multicast)==if_multicast) { if (sp) s << " "; s << "multicast"; sp = true; }
248  if ((m_flags&if_dynamic)==if_dynamic) { if (sp) s << " "; s << "dynamic"; sp = true; }
249  if ((m_flags&if_running)==if_running) { if (sp) s << " "; s << "running"; sp = true; }
250  if ((m_flags&if_noarp)==if_noarp) { if (sp) s << " "; s << "noarp"; sp = true; }
251  if ((m_flags&if_promisc)==if_promisc) { if (sp) s << " "; s << "promisc"; sp = true; }
252  if ((m_flags&if_allmulti)==if_allmulti) { if (sp) s << " "; s << "allmulti"; sp = true; }
253  if ((m_flags&if_echo)==if_echo) { if (sp) s << " "; s << "echo"; }
254 
255  for (auto& ad : m_addrs)
256  {
257  s << "\n " << ad;
258  }
259  return s.str();
260 }
261 
262 std::ostream& operator<<(std::ostream& os, const scc::net::NetIf& nif)
263 {
264  return os.write(nif.str().c_str(), nif.str().size());
265 }
Ipv6 internet address.
Definition: inet.h:120
virtual std::string str() const
Readable address string.
Definition: inet.cc:325
Named address within an interface.
Definition: net_if.h:57
std::string str() const
String representation of a network interface address.
Definition: net_if.cc:93
A network interface.
Definition: net_if.h:90
const std::string & hw_addr() const
Hardware address for the interface.
Definition: net_if.h:138
const int index() const
The interface index.
Definition: net_if.h:135
std::string str() const
String representation of network interface.
Definition: net_if.cc:237
const size_t speed() const
Link speed in bytes / second, 0 means loopback.
Definition: net_if.h:141
const size_t mtu() const
Maximum transmission unit.
Definition: net_if.h:144
static std::vector< NetIf > all_interfaces()
List network interfaces on the local system.
Definition: net_if.cc:105
static std::vector< InetAddr > host_addrs(const std::string &name, SocketType=SocketType::any)
List addresses for the specified host (do a name lookup).
Definition: net_if.cc:57
int flags() const
Flags for this interface.
Definition: net_if.h:149
const std::string & name() const
Name of the interface.
Definition: net_if.h:132
File descriptor.
Definition: filedesc.h:66
File descriptor.
@ name
{2, 5, 4, 41} },
@ if_loopback
Interface is a loopback interface.
Definition: net_if.h:74
@ if_broadcast
Valid broadcast address set.
Definition: net_if.h:73
@ if_multicast
Supports multicast.
Definition: net_if.h:80
@ if_running
Resources allocated.
Definition: net_if.h:76
@ if_noarp
No arp protocol, L2 destination address not set.
Definition: net_if.h:77
@ if_dynamic
The addresses are lost when the interface goes down.
Definition: net_if.h:81
@ if_up
Interface is running.
Definition: net_if.h:72
@ if_pointtopoint
Interface is a point-to-point link.
Definition: net_if.h:75
@ if_allmulti
Receives all multicast packets.
Definition: net_if.h:79
@ if_promisc
Interface is in promiscuous mode.
Definition: net_if.h:78
@ if_echo
Echoes sent packets.
Definition: net_if.h:82
Internet tcp and udp networking.
std::ostream & operator<<(std::ostream &, const scc::net::InetAddr &)
Print the socket address details to an output stream.
Definition: inet.cc:320
Internet network interface utility.