-
Notifications
You must be signed in to change notification settings - Fork 0
/
RouteUtils.cpp
229 lines (159 loc) · 7.22 KB
/
RouteUtils.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/***************************************************************************
* Copyright (C) 2005-2016 Vidyasagara Guntaka *
* All rights reserved. *
* Author : Vidyasagara Reddy Guntaka *
***************************************************************************/
#include "RouteUtils.h"
#include <errno.h>
#include <iostream>
using namespace std;
namespace WaveNs
{
RouteUtils::RouteUtils ()
{
m_sequence = 1;
m_pid = getpid ();
}
RouteUtils::~RouteUtils ()
{
}
void RouteUtils::getSourceIpAddressToReachDestination (const string &destinationIpAddress, string &outputSourceIpAddress, string &outputGateway, unsigned int &outputInterfaceIndex)
{
outputSourceIpAddress = "";
outputGateway = "";
outputInterfaceIndex = 0;
NetLinkRouteMessage *pNetLinkRouteMessage = new NetLinkRouteMessage ();
struct nlmsghdr *pNetLinkMessageHeader = &(pNetLinkRouteMessage->m_netLinkMessageHeader);
memset (pNetLinkRouteMessage, 0, sizeof (NetLinkRouteMessage));
m_sequence++;
pNetLinkMessageHeader->nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
pNetLinkMessageHeader->nlmsg_flags = NLM_F_REQUEST;
pNetLinkMessageHeader->nlmsg_type = RTM_GETROUTE;
pNetLinkMessageHeader->nlmsg_seq = m_sequence;
pNetLinkMessageHeader->nlmsg_pid = m_pid;
// Deliberately restricting it to IPV4 for the demo
pNetLinkRouteMessage->m_routeMessage.rtm_family = AF_INET;
pNetLinkRouteMessage->m_routeMessage.rtm_flags = RTM_F_LOOKUP_TABLE;
int netLinkSocket = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (0 > netLinkSocket)
{
perror ("Could not create a netlink socket : ");
exit (-1);
}
struct in_addr destinationInetAddress;
int status = inet_aton (destinationIpAddress.c_str (), &destinationInetAddress);
if (1 != status)
{
// Not using perror since errno is not set on error.
cerr << destinationIpAddress << " is not a valid destination IPV4 address." << endl;
exit (-2);
}
int routeAttributeLength = RTA_LENGTH (sizeof (destinationInetAddress)); // Since restricting it to IPV4 Address.
struct rtattr *pRouteAttribute;
if ((NLMSG_ALIGN (pNetLinkMessageHeader->nlmsg_len) + RTA_ALIGN (routeAttributeLength)) > sizeof (NetLinkRouteMessage))
{
cerr << "Out of space. Size : " << sizeof (NetLinkRouteMessage) << "exceeded." << endl;
exit (-3);
}
pRouteAttribute = (struct rtattr *) (((void *) pNetLinkMessageHeader) + NLMSG_ALIGN (pNetLinkMessageHeader->nlmsg_len));
pRouteAttribute->rta_type = RTA_DST;
pRouteAttribute->rta_len = routeAttributeLength;
memcpy(RTA_DATA (pRouteAttribute), &destinationInetAddress, sizeof (destinationInetAddress));
pNetLinkMessageHeader->nlmsg_len = NLMSG_ALIGN (pNetLinkMessageHeader->nlmsg_len) + RTA_ALIGN (routeAttributeLength);
pNetLinkRouteMessage->m_routeMessage.rtm_dst_len = -1;
// TODO : Iterate through all of the data is sent instead of posting it just once below
status = send (netLinkSocket, pNetLinkMessageHeader, pNetLinkMessageHeader->nlmsg_len, 0);
if (0 > status)
{
perror ("Could not create a netlink socket : ");
exit (-4);
}
char *pBufferToRead = (char *) pNetLinkMessageHeader;
int bufferLengthReceived = 0;
// TODO : We may need to run a loop here to all data is read.
bufferLengthReceived = recv (netLinkSocket, pBufferToRead + bufferLengthReceived, sizeof (NetLinkRouteMessage), 0);
//cout << "Read Status : " << status << endl;
if (0 > status)
{
perror ("Could not read from netlink socket : ");
exit (-5);
}
if (NLMSG_OK (pNetLinkMessageHeader, bufferLengthReceived) == 0)
{
cerr << "Invalid NetLink Message header received." << endl;
exit (-6);
}
if (NLMSG_ERROR == pNetLinkMessageHeader->nlmsg_type)
{
cerr << "NetLink Message header received indicates an error." << endl;
return;
}
if ((m_sequence != pNetLinkMessageHeader->nlmsg_seq) || (m_pid != pNetLinkMessageHeader->nlmsg_pid))
{
cerr << "Received an unexpected packet." << endl;
cerr << "m_sequence : " << m_sequence << endl;
cerr << "pNetLinkMessageHeader->nlmsg_seq : " << pNetLinkMessageHeader->nlmsg_seq << endl;
cerr << "m_pid : " << m_pid << endl;
cerr << "pNetLinkMessageHeader->nlmsg_pid : " << pNetLinkMessageHeader->nlmsg_pid << endl;
exit (-8);
}
close (netLinkSocket);
string sourceIpAddress;
string gatewayIpAddress;
while (NLMSG_OK (pNetLinkMessageHeader, bufferLengthReceived))
{
struct rtmsg *pRouteMessage = (struct rtmsg *) NLMSG_DATA (pNetLinkMessageHeader);
struct rtattr *pRouteAttribute = (struct rtattr *) RTM_RTA (pRouteMessage);
int routePayloadLength = RTM_PAYLOAD (pNetLinkMessageHeader);
unsigned int destination = 0;
unsigned int source = 0;
unsigned int gateway = 0;
while (RTA_OK (pRouteAttribute, routePayloadLength))
{
// cout << "RTA TYPE : " << pRouteAttribute->rta_type << endl;
switch (pRouteAttribute->rta_type)
{
case RTA_DST :
destination = *((unsigned int *) (RTA_DATA (pRouteAttribute)));
break;
case RTA_PREFSRC :
source = *((unsigned int *) (RTA_DATA (pRouteAttribute)));
break;
case RTA_GATEWAY :
gateway = *((unsigned int *) (RTA_DATA (pRouteAttribute)));
break;
case RTA_OIF :
outputInterfaceIndex = *((int *) (RTA_DATA (pRouteAttribute)));
break;
default :
break;
}
pRouteAttribute = RTA_NEXT (pRouteAttribute, routePayloadLength);
}
if ((0 != source) && (destination == destinationInetAddress.s_addr))
{
in_addr sourceInetAddress;
in_addr gatewayInetAddress;
sourceInetAddress.s_addr = source;
gatewayInetAddress.s_addr = gateway;
char *pSourceIpAddress = inet_ntoa (sourceInetAddress);
if (NULL != pSourceIpAddress)
{
sourceIpAddress = pSourceIpAddress;
}
char *pGatewayIpAddress = inet_ntoa (gatewayInetAddress);
if (NULL != pGatewayIpAddress)
{
gatewayIpAddress = pGatewayIpAddress;
}
break;
}
pNetLinkMessageHeader = NLMSG_NEXT (pNetLinkMessageHeader, bufferLengthReceived);
}
// cout << "Destination : " << destinationIpAddress << ", Source : " << sourceIpAddress << ", Gateway : " << gatewayIpAddress << endl;
outputSourceIpAddress = sourceIpAddress;
outputGateway = gatewayIpAddress;
delete pNetLinkRouteMessage;
return;
}
}