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
31NetPing::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
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);
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
129NetPing::Result NetPing::icmpPing(const char *dev, const char *host)
130{
131 NetworkClient client(dev);
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 volatile ICMP::Header msg;
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((void *)&msg, sizeof(msg));
172
173 // Send the packet
174 if (::write(sock, (void *)&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, (void *)&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}
Result
Result codes.
Definition Application.h:54
const ArgumentContainer & arguments() const
Get program arguments.
ArgumentParser & parser()
Get program arguments parser.
const char * get(const char *name) const
Get argument by name.
void setDescription(const String &desc)
Set program description.
Result registerPositional(const char *name, const char *description, Size count=1)
Register a positional argument.
Result registerFlag(char arg, const char *name, const char *description)
Register a flag Argument.
@ EchoRequest
Definition ICMP.h:58
@ EchoReply
Definition ICMP.h:55
u32 Address
IP-address.
Definition IPV4.h:47
static const u16 checksum(const void *buffer, const Size length)
Calculate IP checksum.
Definition IPV4.cpp:184
static const Address toAddress(const char *address)
Convert string to IPV4 address.
Definition IPV4.cpp:94
Result arpPing(const char *dev, const char *host)
Send ARP ping/pong.
Definition NetPing.cpp:67
Result icmpPing(const char *dev, const char *host)
Send ICMP ping/pong.
Definition NetPing.cpp:129
virtual ~NetPing()
Class destructor.
Definition NetPing.cpp:41
NetPing(int argc, char **argv)
Class constructor.
Definition NetPing.cpp:31
virtual Result exec()
Execute the application event loop.
Definition NetPing.cpp:45
Networking Client implementation.
Result close(const int sock)
Close the socket.
Result initialize()
Perform initialization.
Result
Result codes.
Result connectSocket(const int sock, const IPV4::Address addr, const u16 port=0)
Connect socket to address/port.
Result createSocket(const SocketType type, int *socket)
Create new socket.
POSIX-compatible application.
C char * strerror(int errnum)
The strerror function maps the number in errnum to a message string.
Definition strerror.cpp:20
C int close(int fildes)
Close a file descriptor.
Definition close.cpp:22
C int errno
The lvalue errno is used by many functions to return error values.
C int printf(const char *format,...)
Output a formatted string to standard output.
Definition printf.cpp:22
C ssize_t read(int fildes, void *buf, size_t nbyte)
Read from a file.
Definition read.cpp:22
C ssize_t write(int fildes, const void *buf, size_t nbyte)
Write on a file.
Definition write.cpp:22
#define ERROR(msg)
Output an error message.
Definition Log.h:61
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define DEBUG(msg)
Output a debug message to standard output.
Definition Log.h:89
Ethernet network address.
Definition Ethernet.h:53
Packet header format.
Definition ICMP.h:65
u16 sequence
Definition ICMP.h:70
u16 id
Definition ICMP.h:69
u8 code
Definition ICMP.h:67
u16 checksum
Definition ICMP.h:68
u8 type
Definition ICMP.h:66