NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
IP_Routing.c
1/************************************************************************************
2* Copyright (C) 2023 *
3* TETCOS, Bangalore. India *
4* *
5* Tetcos owns the intellectual property rights in the Product and its content. *
6* The copying, redistribution, reselling or publication of any or all of the *
7* Product or its content without express prior written consent of Tetcos is *
8* prohibited. Ownership and / or any other right relating to the software and all *
9* intellectual property rights therein shall remain at all times with Tetcos. *
10* *
11* This source code is licensed per the NetSim license agreement. *
12* *
13* No portion of this source code may be used as the basis for a derivative work, *
14* or used, for any purpose other than its intended use per the NetSim license *
15* agreement. *
16* *
17* This source code and the algorithms contained within it are confidential trade *
18* secrets of TETCOS and may not be used as the basis for any other software, *
19* hardware, product or service. *
20* *
21* Author: Shashi Kant Suman *
22* *
23* ----------------------------------------------------------------------------------*/
24#include "main.h"
25#include "List.h"
26#include "IP.h"
27#include "NetSim_utility.h"
28#include "Protocol.h"
29#include "../Firewall/Firewall.h"
30
31/** This function is used to route the packet */
32typedef struct stru_match
33{
34 ptrIP_ROUTINGTABLE table;
35 UINT bitsCount;
36 UINT metric;
37 _ele* ele;
38}MATCH, *ptrMATCH;
39#define MATCH_ALLOC() (ptrMATCH)list_alloc(sizeof(MATCH),offsetof(MATCH,ele))
40
41static void print_match_table(ptrMATCH match, NETSIM_ID d, NETSIM_IPAddress dest, NETSIM_IPAddress src)
42{
43 static FILE* fp = NULL;
44#ifdef PRINT_MATCH_TABLE
45 if (!fp)
46 {
47 fp = fopen("MatchTable.csv", "w");
48 fprintf(fp, "Dest,Gateway,Ifcount,Iflist,\n");
49 fflush(fp);
50 }
51#endif
52 if (fp)
53 {
54 fprintf(fp, " Device %d, dest = %s, Src = %s\n", d, dest->str_ip, src->str_ip);
55 while (match)
56 {
57 UINT i;
58 fprintf(fp, "%s,%s,%d,",
59 match->table->networkDestination->str_ip,
60 match->table->gateway?match->table->gateway->str_ip:"EMPTY",
61 match->table->interfaceCount);
62 for (i = 0; i < match->table->interfaceCount; i++)
63 fprintf(fp, "%s,", match->table->Interface[i]->str_ip);
64 fprintf(fp, "\n");
65 match = LIST_NEXT(match);
66 }
67 fprintf(fp, "\n\n");
68 fflush(fp);
69 }
70}
71
72static void free_match_table(ptrMATCH l)
73{
74 while (l)
75 LIST_FREE(&l, l);
76}
77
78static int match_check(ptrMATCH m1, ptrMATCH m2)
79{
80 if (m2->bitsCount > m1->bitsCount)
81 return 2;
82 if (m2->bitsCount == m1->bitsCount)
83 {
84 if (m2->metric < m1->metric)
85 return 2;
86 }
87 return 0;
88}
89
90static void add_to_match_list(ptrMATCH* l, ptrMATCH c)
91{
92 LIST_ADD(l, c, match_check);
93}
94
95static UINT get_bit_match_count(NETSIM_IPAddress ip1)
96{
97 char b1[40];
98
99 IP_TO_BINARY(ip1, b1);
100
101 UINT l = (UINT)strlen(b1);
102 UINT i;
103 for (i = 0; i < l; i++)
104 {
105 if (b1[i] == '0')
106 break;
107 }
108 return i;
109}
110
111static ptrMATCH get_match_table(ptrIP_ROUTINGTABLE table, NETSIM_IPAddress dest, bool isStatic)
112{
113 ptrMATCH l = NULL;
114 ptrMATCH c = NULL;
115 NETSIM_IPAddress network1;
116 NETSIM_IPAddress network2;
117
118 while (table)
119 {
120 bool isC = (isStatic && table->type == RoutingType_STATIC) || (!isStatic);
121 if (!isC)
122 {
123 table = LIST_NEXT(table);
124 continue;
125 }
126
127 if (!IP_COMPARE(dest, table->networkDestination) && ICMP_CHECKSTATE(dest))
128 {
129 c = MATCH_ALLOC();
130 c->table = table;
131 c->bitsCount = dest->type == 4 ? 32 : 128;
132 if (table->Metric <= 0)
133 c->metric = 999;
134 else
135 c->metric = table->Metric;
136 add_to_match_list(&l, c);
137 }
138 else if (dest->type == table->networkDestination->type)
139 {
140 network1 = IP_NETWORK_ADDRESS(dest, table->netMask, table->prefix_len);
141 network2 = IP_NETWORK_ADDRESS(table->networkDestination, table->netMask, table->prefix_len);
142 if (!IP_COMPARE(network1, network2))
143 {
144 if (ICMP_CHECKSTATE(table->gateway))
145 {
146 c = MATCH_ALLOC();
147 c->table = table;
148 c->bitsCount = dest->type == 4 ? get_bit_match_count(table->netMask) : table->prefix_len;
149 c->metric = table->Metric;
150 add_to_match_list(&l, c);
151 }
152 }
153 }
154 table = LIST_NEXT(table);
155 }
156
157 return l;
158}
159
160void free_ip_route(ptrIP_FORWARD_ROUTE route)
161{
162 if (route == NULL)return;
163 free(route->interfaceId);
164 free(route->nextHop);
165 free(route->nextHopId);
166 free(route->gateway);
167 free(route);
168}
169
170static void update_route_entry(ptrMATCH match, ptrIP_FORWARD_ROUTE route,NETSIM_IPAddress dest)
171{
172 NETSIM_ID i;
173 NETSIM_ID in;
174 if (match)
175 {
176 ptrIP_ROUTINGTABLE table = match->table;
177
178 route->count = table->interfaceCount;
179
180 route->nextHop = calloc(table->interfaceCount, sizeof* route->nextHop);
181 route->gateway = calloc(table->interfaceCount, sizeof* route->gateway);
182 route->interfaceId = calloc(table->interfaceCount, sizeof* route->interfaceId);
183 route->nextHopId = calloc(table->interfaceCount, sizeof* route->nextHopId);
184
185 for (i = 0; i < table->interfaceCount; i++)
186 {
187 if (table->gateway)
188 route->nextHop[i] = table->gateway;
189 else
190 route->nextHop[i] = dest;
191
192 route->gateway[i] = table->Interface[i];
193
194 route->interfaceId[i] = table->nInterfaceId[i];
195
196 if (!table->nGatewayId && table->gateway)
197 table->nGatewayId = fn_NetSim_Stack_GetDeviceId_asIP(table->gateway, &in);
198
199 if (table->nGatewayId)
200 route->nextHopId[i] = table->nGatewayId;
201 else
202 route->nextHopId[i] = 0; //MAC layer will decide
203 }
204 }
205}
206
207static ptrMATCH choose_match_for_reserved_address(ptrMATCH match,
208 NETSIM_IPAddress dest,
209 NETSIM_IPAddress src)
210{
211 bool isResevedAddr = is_reserved_multicast_address(dest);
212 if (!isResevedAddr)
213 return match;
214
215 while (match)
216 {
217 if (isCorrectRoute(&match->table, dest, src))
218 return match;
219 match = LIST_NEXT(match);
220 }
221 return NULL;
222}
223
224static void multicast_update_route_entry(ptrMATCH match,
225 ptrIP_FORWARD_ROUTE route,
226 NETSIM_IPAddress dest,
227 NETSIM_IPAddress src)
228{
229 NETSIM_ID i;
230 NETSIM_ID c;
231 NETSIM_ID in;
232
233 match = choose_match_for_reserved_address(match, dest, src);
234 if (match)
235 {
236 ptrIP_ROUTINGTABLE table = match->table;
237
238 route->count = table->interfaceCount;
239
240 route->nextHop = calloc(table->interfaceCount, sizeof* route->nextHop);
241 route->gateway = calloc(table->interfaceCount, sizeof* route->gateway);
242 route->interfaceId = calloc(table->interfaceCount, sizeof* route->interfaceId);
243 route->nextHopId = calloc(table->interfaceCount, sizeof* route->nextHopId);
244
245 for (i = 0, c = 0; i < table->interfaceCount; i++, c++)
246 {
247 if (table->nInterfaceId[i] == pstruEventDetails->nInterfaceId)
248 {
249 c--;
250 route->count--;
251 continue;
252 }
253
254 if (table->gateway)
255 route->nextHop[c] = table->gateway;
256 else
257 route->nextHop[c] = dest;
258
259 route->gateway[c] = table->Interface[i];
260
261 route->interfaceId[c] = table->nInterfaceId[i];
262
263 if (!table->nGatewayId && table->gateway)
264 table->nGatewayId = fn_NetSim_Stack_GetDeviceId_asIP(table->gateway, &in);
265
266 if (table->nGatewayId)
267 route->nextHopId[c] = table->nGatewayId;
268 else
269 route->nextHopId[c] = 0; //MAC layer will decide
270 }
271 }
272}
273
274static void route_onlink(NETSIM_ID d,
275 NETSIM_IPAddress src,
276 NETSIM_IPAddress dest,
277 ptrIP_FORWARD_ROUTE route)
278{
279 NETSIM_ID i;
280 UINT c = 0;
281 for (i = 0; i < DEVICE(d)->nNumOfInterface; i++)
282 {
283 if (IP_IS_IN_SAME_NETWORK(src,
284 DEVICE_NWADDRESS(d, i + 1),
285 DEVICE_INTERFACE(d, i + 1)->szSubnetMask,
286 DEVICE_INTERFACE(d, i + 1)->prefix_len))
287 {
288 route->count++;
289 if (route->gateway)
290 {
291 route->gateway = realloc(route->gateway, route->count * sizeof* route->gateway);
292 route->interfaceId = realloc(route->interfaceId, route->count * sizeof* route->interfaceId);
293 route->nextHop = realloc(route->nextHop, route->count * sizeof* route->nextHop);
294 route->nextHopId = realloc(route->nextHopId, route->count * sizeof* route->nextHopId);
295 }
296 else
297 {
298 route->gateway = calloc(1, route->count * sizeof* route->gateway);
299 route->interfaceId = calloc(1, route->count * sizeof* route->interfaceId);
300 route->nextHop = calloc(1, route->count * sizeof* route->nextHop);
301 route->nextHopId = calloc(1, route->count * sizeof* route->nextHopId);
302 }
303 route->gateway[c] = DEVICE_NWADDRESS(d, i + 1);
304 route->interfaceId[c] = i + 1;
305 route->nextHop[c] = dest;
306 route->nextHopId[c] = 0;
307 c++;
308 }
309 }
310}
311
312static bool check_my_ip(NETSIM_ID d, NETSIM_IPAddress ip)
313{
314 NETSIM_ID i;
315 for (i = 0; i < DEVICE(d)->nNumOfInterface; i++)
316 if (!IP_COMPARE(DEVICE_NWADDRESS(d, i + 1), ip))
317 return true;
318 return false;
319}
320
321static ptrIP_FORWARD_ROUTE route_unicast(NetSim_PACKET* packet,
322 NETSIM_ID dev)
323{
324 ptrIP_ROUTINGTABLE routingTable = IP_TABLE_GET(dev);
325 NETSIM_IPAddress dest = packet->pstruNetworkData->szDestIP;
326
327 ptrMATCH match = get_match_table(routingTable, dest, false);
328
329 ptrMATCH store = match;
330
331 ptrIP_FORWARD_ROUTE route = (ptrIP_FORWARD_ROUTE)calloc(1, sizeof* route);
332
333 update_route_entry(match, route, dest);
334
335 free_match_table(store);
336
337 if (!route->count)
338 {
339 free_ip_route(route);
340 route = NULL;
341 }
342
343 return route;
344}
345
346static ptrIP_FORWARD_ROUTE route_multicast(NetSim_PACKET* packet,
347 NETSIM_ID dev)
348{
349 ptrIP_ROUTINGTABLE routingTable = IP_TABLE_GET(dev);
350 NETSIM_IPAddress dest = packet->pstruNetworkData->szDestIP;
351 NETSIM_IPAddress src = packet->pstruNetworkData->szSourceIP;
352
353 ptrMATCH match = get_match_table(routingTable, dest, false);
354#ifdef PRINT_MATCH_TABLE
355 print_match_table(match, dev, dest, src);
356#endif
357 ptrMATCH store = match;
358
359 ptrIP_FORWARD_ROUTE route = (ptrIP_FORWARD_ROUTE)calloc(1, sizeof* route);
360
361 multicast_update_route_entry(match, route, dest, src);
362
363 free_match_table(store);
364
365 if (!route->count)
366 {
367 free(route);
368 route = NULL;
369 }
370
371 return route;
372}
373
374ptrIP_FORWARD_ROUTE fn_NetSim_IP_RoutePacket(NetSim_PACKET* packet,
375 NETSIM_ID dev)
376{
377 NETSIM_IPAddress dest = packet->pstruNetworkData->szDestIP;
378
379 if (isMulticastIP(dest))
380 return route_multicast(packet, dev);
381 else
382 return route_unicast(packet, dev);
383}
384
385static void change_table(NETSIM_ID d, ptrIP_ROUTINGTABLE table,
386 NETSIM_IPAddress gateway, NETSIM_ID in, UINT metric)
387{
388 UINT i;
389 bool isfound = false;
390 for (i = 0; i < table->interfaceCount; i++)
391 {
392 if (in == table->nInterfaceId[i])
393 {
394 isfound = true;
395 break;
396 }
397 }
398 if (isfound)
399 {
400 table->gateway = gateway;
401 table->Metric = metric;
402 }
403 else
404 {
405 table->Interface = realloc(table->Interface, (table->interfaceCount + 1) * sizeof* table->Interface);
406 table->nInterfaceId = realloc(table->nInterfaceId, (table->interfaceCount + 1) * sizeof* table->Interface);
407 table->nInterfaceId[table->interfaceCount] = in;
408 table->Interface[table->interfaceCount] = DEVICE_NWADDRESS(d, in);
409 table->gateway = gateway;
410 table->Metric = metric;
411 table->interfaceCount++;
412 }
413}
414
415static void add_table(NETSIM_ID d, NETSIM_IPAddress dest, NETSIM_IPAddress mask,
416 NETSIM_IPAddress gateway, NETSIM_ID in, UINT metric)
417{
418 iptable_add(IP_WRAPPER_GET(d), dest, mask, 0, gateway, 1, &DEVICE_NWADDRESS(d, in), &in, metric, "STATIC");
419}
420
421#define display_error(error, line, file) fnNetSimError("Invalid line in route file %s at line %d: %s", file, line, error)
422/** This function is to configure static ip table */
423void configure_static_ip_route(NETSIM_ID d, char* file)
424{
425 UINT line = 0;
426 NETSIM_ID nDevId = 0;
427 char* temp;
428 int metric = 0;
429
430 char input[BUFSIZ];
431 sprintf(input, "%s%s%s", pszIOPath, pathSeperator, file);
432 FILE* fp = fopen(input, "r");
433 if (fp == NULL)
434 {
435 perror(input);
436 fnNetSimError("Unable to open routing file %s", input);
437 return;
438 }
439
440 while (fgets(input, BUFSIZ, fp))
441 {
442 line++;
443 temp = input;
444 temp = lskip(temp);
445 if (*temp == '#' || !*temp)
446 continue; //Comment or empty line
447
448 char* f = find_word(&temp);
449 if (_stricmp(f, "route"))
450 {
451 display_error("Not start with route", file, line);
452 continue;
453 }
454
455 f = find_word(&temp);
456 if (_stricmp(f, "add"))
457 {
458 display_error("Second word is not add", file, line);
459 continue;
460 }
461
462 f = find_word(&temp);
463 NETSIM_IPAddress dest = STR_TO_IP4(f);
464
465 f = find_word(&temp);
466 if (_stricmp(f, "mask"))
467 {
468 display_error("Fourth word is not mask", file, line);
469 continue;
470 }
471
472 f = find_word(&temp);
473 NETSIM_IPAddress mask = STR_TO_IP4(f);
474
475 f = find_word(&temp);
476 NETSIM_IPAddress gateway = STR_TO_IP4(f);
477
478 f = find_word(&temp);
479 if (_stricmp(f, "metric"))
480 {
481 display_error("Seventh word is not metric", file, line);
482 continue;
483 }
484
485 f = find_word(&temp);
486 UINT metric = atoi(f);
487
488 f = find_word(&temp);
489 if (_stricmp(f, "IF"))
490 {
491 display_error("Ninth word is not if", file, line);
492 continue;
493 }
494
495 f = find_word(&temp);
496 NETSIM_ID in = atoi(f);
497 in = fn_NetSim_GetInterfaceIdByConfigId(d, in);
498
499 ptrIP_ROUTINGTABLE table = iptable_check(PIP_TABLE_GET(d), dest, mask);
500 if (table)
501 change_table(d, table, gateway, in, metric);
502 else
503 add_table(d, dest, mask, gateway, in, metric);
504
505 }
506}
507
508static ptrIP_FORWARD_ROUTE static_route_unicast(NetSim_PACKET* packet,
509 NETSIM_ID dev)
510{
511 ptrIP_ROUTINGTABLE routingTable = IP_TABLE_GET(dev);
512 NETSIM_IPAddress dest = packet->pstruNetworkData->szDestIP;
513
514 ptrMATCH match = get_match_table(routingTable, dest, true);
515
516 ptrMATCH store = match;
517
518 ptrIP_FORWARD_ROUTE route = (ptrIP_FORWARD_ROUTE)calloc(1, sizeof* route);
519
520 update_route_entry(match, route, dest);
521
522 free_match_table(store);
523
524 if (!route->count)
525 {
526 free(route);
527 route = NULL;
528 }
529
530 return route;
531}
532
533static ptrIP_FORWARD_ROUTE static_route_multicast(NetSim_PACKET* packet,
534 NETSIM_ID dev)
535{
536 ptrIP_ROUTINGTABLE routingTable = IP_TABLE_GET(dev);
537 NETSIM_IPAddress dest = packet->pstruNetworkData->szDestIP;
538 NETSIM_IPAddress src = packet->pstruNetworkData->szSourceIP;
539
540 ptrMATCH match = get_match_table(routingTable, dest, true);
541#ifdef PRINT_MATCH_TABLE
542 print_match_table(match, dev, dest, src);
543#endif
544 ptrMATCH store = match;
545
546 ptrIP_FORWARD_ROUTE route = (ptrIP_FORWARD_ROUTE)calloc(1, sizeof* route);
547
548 multicast_update_route_entry(match, route, dest, src);
549
550 free_match_table(store);
551
552 if (!route->count)
553 {
554 free(route);
555 route = NULL;
556 }
557
558 return route;
559}
560
561ptrIP_FORWARD_ROUTE fn_NetSim_IP_RoutePacketViaStaticEntry(NetSim_PACKET* packet, NETSIM_ID dev)
562{
563 NETSIM_IPAddress dest = packet->pstruNetworkData->szDestIP;
564
565 if (isMulticastIP(dest))
566 return static_route_multicast(packet, dev);
567 else
568 return static_route_unicast(packet, dev);
569}
570
571void pass_to_lower_layer(NetSim_PACKET* packet, ptrIP_FORWARD_ROUTE route, UINT c)
572{
573 NetSim_EVENTDETAILS pevent;
574 memset(&pevent, 0, sizeof pevent);
575
576 NETSIM_ID d, n, i;
577
578 d = pstruEventDetails->nDeviceId;
579 if (route)
580 {
581 packet->pstruNetworkData->szNextHopIp = route->nextHop[c];
582 packet->pstruNetworkData->szGatewayIP = route->gateway[c];
583 n = route->nextHopId[c];
584 i = route->interfaceId[c];
585 }
586 else
587 {
588 if (!packet->pstruNetworkData->szGatewayIP)
589 packet->pstruNetworkData->szGatewayIP = fn_NetSim_Stack_GetFirstIPAddressAsId(d, 4);
590
591 if (!pstruEventDetails->nInterfaceId)
592 i = fn_NetSim_Stack_GetInterfaceIdFromIP(d,
593 packet->pstruNetworkData->szGatewayIP);
594 else
595 i = pstruEventDetails->nInterfaceId;
596
597 NETSIM_ID k; //Not used
598 n = fn_NetSim_Stack_GetDeviceId_asIP(packet->pstruNetworkData->szNextHopIp,
599 &k);
600
601 }
602
603 //check for firewall
604 if (fn_NetSim_NETWORK_Firewall(d, i, packet, ACLTYPE_OUTBOUND) == ACLACTION_DENY)
605 {
606 ipMetrics[d - 1]->nFirewallBlocked++;
607 fn_NetSim_Packet_FreePacket(packet);
608 pstruEventDetails->pPacket = NULL;
609 return;
610 }
611
612 if (!IP_COMPARE(packet->pstruNetworkData->szGatewayIP, packet->pstruNetworkData->szNextHopIp))
613 {
614 fnNetSimError("Gateway IP and next hop IP are same. IP address=%s\n",
615 packet->pstruNetworkData->szGatewayIP->str_ip);
616 }
617
618 packet->pstruNetworkData->dOverhead += IPV4_HEADER_SIZE;
619 packet->pstruNetworkData->dPacketSize = packet->pstruNetworkData->dOverhead +
620 packet->pstruNetworkData->dPayload;
621
622
623 //Set the end time
624 packet->pstruNetworkData->dEndTime = pstruEventDetails->dEventTime;
625 packet->pstruNetworkData->nNetworkProtocol = DEVICE_INTERFACE(d, i)->nProtocolId;
626 packet->nTransmitterId = d;
627 packet->nReceiverId = n;
628
629 if (DEVICE_INTERFACE(d, i)->nLocalNetworkProtocol == PROTOCOL_VPN)
630 fn_NetSim_IP_VPN_Run();
631
632 if (pstruEventDetails->pPacket == NULL)
633 return;
634
635 //Increment the count
636 ipMetrics[d - 1]->nPacketSent++;
637
638 ip_write_to_pcap(packet, d, i, pstruEventDetails->dEventTime);
639
640 if (!DEVICE_INTERFACE(d, i)->nLocalNetworkProtocol)
641 {
642 packet->pstruMacData->szSourceMac = (fn_NetSim_Stack_GetMacAddressFromIP(packet->pstruNetworkData->szGatewayIP));
643 NETSIM_IPAddress szDestIPaddr = packet->pstruNetworkData->szNextHopIp;
644 if (isBroadcastIP(szDestIPaddr))
645 packet->pstruMacData->szDestMac = BROADCAST_MAC;
646 else if (isMulticastIP(szDestIPaddr))
647 packet->pstruMacData->szDestMac = multicastIP_to_Mac(szDestIPaddr);
648 else
649 packet->pstruMacData->szDestMac = fn_NetSim_Stack_GetMacAddressFromIP(szDestIPaddr);
650 }
651
652 IP_DEVVAR* ipVar = GET_IP_DEVVAR(d);
653 memset(&pevent, 0, sizeof pevent);
654 pevent.dEventTime = pstruEventDetails->dEventTime + ipVar->processingDelay;
655 pevent.dPacketSize = packet->pstruNetworkData->dPacketSize;
656 if (packet->pstruAppData)
657 {
658 pevent.nApplicationId = packet->pstruAppData->nApplicationId;
659 pevent.nSegmentId = packet->pstruAppData->nSegmentId;
660 }
661 pevent.nDeviceId = d;
662 pevent.nDeviceType = DEVICE_TYPE(d);
663 pevent.nEventType = TIMER_EVENT;
664 pevent.nInterfaceId = i;
665 pevent.nPacketId = packet->nPacketId;
666 pevent.nProtocolId = DEVICE_INTERFACE(d, i)->nProtocolId;
667 pevent.nSubEventType = EVENT_IP_PROCESSING_DELAY;
668 pevent.pPacket = packet;
669 fnpAddEvent(&pevent);
670
671}