FreeNOS
NetPing.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Niek Linnenbank
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <MemoryBlock.h>
19 #include <NetworkClient.h>
20 #include <NetworkSocket.h>
21 #include <IPV4.h>
22 #include <ICMP.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <string.h>
29 #include "NetPing.h"
30 
31 NetPing::NetPing(int argc, char **argv)
32  : POSIXApplication(argc, argv)
33 {
34  parser().setDescription("send network pings");
35  parser().registerPositional("DEVICE", "device name of network adapter");
36  parser().registerPositional("HOST", "host address to ping");
37  parser().registerFlag('a', "arp", "send ARP pings");
38  parser().registerFlag('i', "icmp", "send ICMP pings");
39 }
40 
42 {
43 }
44 
46 {
47  DEBUG("");
48 
49  const char *dev = arguments().get("DEVICE");
50  const char *host = arguments().get("HOST");
51  const char *icmp = arguments().get("icmp");
52 
53  DEBUG("sending on device: " << dev);
54 
55  if (icmp)
56  {
57  DEBUG("sending ICMP packets");
58  return icmpPing(dev, host);
59  }
60  else
61  {
62  DEBUG("sending ARP packets");
63  return arpPing(dev, host);
64  }
65 }
66 
68  const char *host)
69 {
70  NetworkClient client(dev);
71  NetworkClient::Result result;
72  Ethernet::Address ethAddr;
73  IPV4::Address ipAddr;
74  int sock;
75 
76  DEBUG("");
77 
78  // Initialize networking client
79  result = client.initialize();
80  if (result != NetworkClient::Success)
81  {
82  ERROR("failed to initialize network client for device: " << dev <<
83  ", result = " << (int) result);
84  return IOError;
85  }
86 
87  // Create an ARP socket
88  result = client.createSocket(NetworkClient::ARP, &sock);
89  if (result != NetworkClient::Success)
90  {
91  ERROR("failed to create ARP socket: result = " << (int) result);
92  return IOError;
93  }
94 
95  // Convert to IPV4 address
96  if (!(ipAddr = IPV4::toAddress(host)))
97  {
98  ERROR("failed to convert to IPV4 address: " << host);
99  return IOError;
100  }
101  printf("Sending ARP request to %s\r\n", host);
102 
103  // Send ARP request
104  if (::write(sock, &ipAddr, sizeof(ipAddr)) < 0)
105  {
106  ERROR("failed to send ARP request: " << strerror(errno));
107  return IOError;
108  }
109 
110  // Receive ARP reply, if any
111  if (::read(sock, &ethAddr, sizeof(ethAddr)) < 0)
112  {
113  ERROR("failed to receive ARP response: " << strerror(errno));
114  return IOError;
115  }
116 
117  // Print the MAC address received
118  printf("Received ARP response for: ");
119 
120  for (Size i = 0; i < sizeof(Ethernet::Address); i++)
121  printf("%x:", ethAddr.addr[i]);
122  printf("\r\n");
123 
124  // Finished
125  client.close(sock);
126  return Success;
127 }
128 
129 NetPing::Result NetPing::icmpPing(const char *dev, const char *host)
130 {
131  NetworkClient client(dev);
132  NetworkClient::Result result;
133  int sock;
134 
135  DEBUG("");
136 
137  // Initialize networking client
138  result = client.initialize();
139  if (result != NetworkClient::Success)
140  {
141  ERROR("failed to initialize network client for device: " << dev <<
142  ", result = " << (int) result);
143  return IOError;
144  }
145 
146  // Create an ICMP socket
147  result = client.createSocket(NetworkClient::ICMP, &sock);
148  if (result != NetworkClient::Success)
149  {
150  ERROR("failed to create ICMP socket: result = " << (int)result);
151  return IOError;
152  }
153 
154  // Connect socket to the given host
155  result = client.connectSocket(sock, IPV4::toAddress(host));
156  if (result != NetworkClient::Success)
157  {
158  ERROR("failed to connect ICMP socket: result = " << (int) result);
159  return IOError;
160  }
161 
162  // Send an echo request
163  ICMP::Header msg;
164  msg.type = ICMP::EchoRequest;
165  msg.code = 0;
166  msg.checksum = 0;
167  msg.id = 1;
168  msg.sequence = 1;
169 
170  // Generate checksum
171  msg.checksum = IPV4::checksum(&msg, sizeof(msg));
172 
173  // Send the packet
174  if (::write(sock, &msg, sizeof(msg)) <= 0)
175  {
176  ERROR("failed to send ICMP request: " << strerror(errno));
177  return IOError;
178  }
179  printf("Sending ICMP request to %s\r\n", host);
180 
181  // Receive echo reply
182  if (::read(sock, &msg, sizeof(msg)) <= 0)
183  {
184  ERROR("failed to receive ICMP response: " << strerror(errno));
185  return IOError;
186  }
187 
188  // Check message type
189  if (msg.type != ICMP::EchoReply)
190  {
191  ERROR("invalid ICMP code in response: " << (int) msg.type);
192  return IOError;
193  }
194 
195  // Print the ICMP address received
196  printf("Received ICMP response with id=%d sequence=%d\r\n",
197  msg.id, msg.sequence);
198 
199  // Finished
200  ::close(sock);
201  return Success;
202 }
NetworkClient::Result
Result
Result codes.
Definition: NetworkClient.h:99
ArgumentContainer::get
const char * get(const char *name) const
Get argument by name.
Definition: ArgumentContainer.cpp:49
NetworkClient::Success
@ Success
Definition: NetworkClient.h:101
NetPing::NetPing
NetPing(int argc, char **argv)
Class constructor.
Definition: NetPing.cpp:31
NetPing::exec
virtual Result exec()
Execute the application event loop.
Definition: NetPing.cpp:45
ICMP::Header::id
u16 id
Definition: ICMP.h:69
fcntl.h
NetworkClient::initialize
Result initialize()
Perform initialization.
Definition: NetworkClient.cpp:35
ICMP::Header
Packet header format.
Definition: ICMP.h:64
write
ssize_t write(int fildes, const void *buf, size_t nbyte)
Write on a file.
Definition: write.cpp:22
NetworkClient::createSocket
Result createSocket(const SocketType type, int *socket)
Create new socket.
Definition: NetworkClient.cpp:80
errno
C int errno
The lvalue errno is used by many functions to return error values.
NetworkClient::close
Result close(const int sock)
Close the socket.
Definition: NetworkClient.cpp:239
string.h
NetPing::~NetPing
virtual ~NetPing()
Class destructor.
Definition: NetPing.cpp:41
NetPing::icmpPing
Result icmpPing(const char *dev, const char *host)
Send ICMP ping/pong.
Definition: NetPing.cpp:129
ICMP::Header::checksum
u16 checksum
Definition: ICMP.h:68
IPV4::checksum
static const u16 checksum(const void *buffer, const Size length)
Calculate IP checksum.
Definition: IPV4.cpp:184
POSIXApplication
POSIX-compatible application.
Definition: POSIXApplication.h:35
Application::Success
@ Success
Definition: Application.h:55
MemoryBlock.h
Application::arguments
const ArgumentContainer & arguments() const
Get program arguments.
Definition: Application.cpp:112
ICMP::Header::code
u8 code
Definition: ICMP.h:67
ICMP::Header::type
u8 type
Definition: ICMP.h:66
ArgumentParser::setDescription
void setDescription(const String &desc)
Set program description.
Definition: ArgumentParser.cpp:95
read
ssize_t read(int fildes, void *buf, size_t nbyte)
Read from a file.
Definition: read.cpp:22
NetworkClient::connectSocket
Result connectSocket(const int sock, const IPV4::Address addr, const u16 port=0)
Connect socket to address/port.
Definition: NetworkClient.cpp:115
Application::IOError
@ IOError
Definition: Application.h:57
DEBUG
#define DEBUG(msg)
Output a debug message to standard output.
Definition: Log.h:89
Ethernet::Address
Ethernet network address.
Definition: Ethernet.h:52
ICMP::EchoReply
@ EchoReply
Definition: ICMP.h:55
printf
int printf(const char *format,...)
Output a formatted string to standard output.
Definition: printf.cpp:22
close
int close(int fildes)
Close a file descriptor.
Definition: close.cpp:22
IPV4::toAddress
static const Address toAddress(const char *address)
Convert string to IPV4 address.
Definition: IPV4.cpp:94
stdio.h
strerror
char * strerror(int errnum)
The strerror function maps the number in errnum to a message string.
Definition: strerror.cpp:20
Ethernet::Address::addr
u8 addr[6]
Definition: Ethernet.h:54
Size
unsigned int Size
Any sane size indicator cannot go negative.
Definition: Types.h:128
Application::Result
Result
Result codes.
Definition: Application.h:53
ArgumentParser::registerFlag
Result registerFlag(char arg, const char *name, const char *description)
Register a flag Argument.
Definition: ArgumentParser.cpp:100
ICMP.h
IPV4::Address
u32 Address
IP-address.
Definition: IPV4.h:47
NetworkClient
Networking Client implementation.
Definition: NetworkClient.h:44
IPV4.h
ArgumentParser::registerPositional
Result registerPositional(const char *name, const char *description, Size count=1)
Register a positional argument.
Definition: ArgumentParser.cpp:119
unistd.h
Application::parser
ArgumentParser & parser()
Get program arguments parser.
Definition: Application.cpp:102
NetworkClient::ARP
@ ARP
Definition: NetworkClient.h:90
ERROR
#define ERROR(msg)
Output an error message.
Definition: Log.h:61
NetPing::arpPing
Result arpPing(const char *dev, const char *host)
Send ARP ping/pong.
Definition: NetPing.cpp:67
NetworkClient::ICMP
@ ICMP
Definition: NetworkClient.h:91
ICMP::EchoRequest
@ EchoRequest
Definition: ICMP.h:58
ICMP::Header::sequence
u16 sequence
Definition: ICMP.h:70
stdlib.h
NetworkClient.h
Ethernet::Address
struct Ethernet::Address Address
Ethernet network address.
NetPing.h
NetworkSocket.h
errno.h