1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2005 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
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, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 
21 #include "ipv4-end-point-demux.h"
22 #include "ipv4-end-point.h"
23 #include "ipv4-interface-address.h"
24 #include "ns3/log.h"
25 
26 
27 namespace ns3 {
28 
29 NS_LOG_COMPONENT_DEFINE ("Ipv4EndPointDemux");
30 
Ipv4EndPointDemux()31 Ipv4EndPointDemux::Ipv4EndPointDemux ()
32   : m_ephemeral (49152), m_portLast (65535), m_portFirst (49152)
33 {
34   NS_LOG_FUNCTION (this);
35 }
36 
~Ipv4EndPointDemux()37 Ipv4EndPointDemux::~Ipv4EndPointDemux ()
38 {
39   NS_LOG_FUNCTION (this);
40   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
41     {
42       Ipv4EndPoint *endPoint = *i;
43       delete endPoint;
44     }
45   m_endPoints.clear ();
46 }
47 
48 bool
LookupPortLocal(uint16_t port)49 Ipv4EndPointDemux::LookupPortLocal (uint16_t port)
50 {
51   NS_LOG_FUNCTION (this << port);
52   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
53     {
54       if ((*i)->GetLocalPort  () == port)
55         {
56           return true;
57         }
58     }
59   return false;
60 }
61 
62 bool
LookupLocal(Ptr<NetDevice> boundNetDevice,Ipv4Address addr,uint16_t port)63 Ipv4EndPointDemux::LookupLocal (Ptr<NetDevice> boundNetDevice, Ipv4Address addr, uint16_t port)
64 {
65   NS_LOG_FUNCTION (this << addr << port);
66   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
67     {
68       if ((*i)->GetLocalPort () == port &&
69           (*i)->GetLocalAddress () == addr &&
70           (*i)->GetBoundNetDevice () == boundNetDevice)
71         {
72           return true;
73         }
74     }
75   return false;
76 }
77 
78 Ipv4EndPoint *
Allocate(void)79 Ipv4EndPointDemux::Allocate (void)
80 {
81   NS_LOG_FUNCTION (this);
82   uint16_t port = AllocateEphemeralPort ();
83   if (port == 0)
84     {
85       NS_LOG_WARN ("Ephemeral port allocation failed.");
86       return 0;
87     }
88   Ipv4EndPoint *endPoint = new Ipv4EndPoint (Ipv4Address::GetAny (), port);
89   m_endPoints.push_back (endPoint);
90   NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
91   return endPoint;
92 }
93 
94 Ipv4EndPoint *
Allocate(Ipv4Address address)95 Ipv4EndPointDemux::Allocate (Ipv4Address address)
96 {
97   NS_LOG_FUNCTION (this << address);
98   uint16_t port = AllocateEphemeralPort ();
99   if (port == 0)
100     {
101       NS_LOG_WARN ("Ephemeral port allocation failed.");
102       return 0;
103     }
104   Ipv4EndPoint *endPoint = new Ipv4EndPoint (address, port);
105   m_endPoints.push_back (endPoint);
106   NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
107   return endPoint;
108 }
109 
110 Ipv4EndPoint *
Allocate(Ptr<NetDevice> boundNetDevice,uint16_t port)111 Ipv4EndPointDemux::Allocate (Ptr<NetDevice> boundNetDevice, uint16_t port)
112 {
113   NS_LOG_FUNCTION (this <<  port << boundNetDevice);
114 
115   return Allocate (boundNetDevice, Ipv4Address::GetAny (), port);
116 }
117 
118 Ipv4EndPoint *
Allocate(Ptr<NetDevice> boundNetDevice,Ipv4Address address,uint16_t port)119 Ipv4EndPointDemux::Allocate (Ptr<NetDevice> boundNetDevice, Ipv4Address address, uint16_t port)
120 {
121   NS_LOG_FUNCTION (this << address << port << boundNetDevice);
122   if (LookupLocal (boundNetDevice, address, port) || LookupLocal (0, address, port))
123     {
124       NS_LOG_WARN ("Duplicated endpoint.");
125       return 0;
126     }
127   Ipv4EndPoint *endPoint = new Ipv4EndPoint (address, port);
128   m_endPoints.push_back (endPoint);
129   NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
130   return endPoint;
131 }
132 
133 Ipv4EndPoint *
Allocate(Ptr<NetDevice> boundNetDevice,Ipv4Address localAddress,uint16_t localPort,Ipv4Address peerAddress,uint16_t peerPort)134 Ipv4EndPointDemux::Allocate (Ptr<NetDevice> boundNetDevice,
135                              Ipv4Address localAddress, uint16_t localPort,
136                              Ipv4Address peerAddress, uint16_t peerPort)
137 {
138   NS_LOG_FUNCTION (this << localAddress << localPort << peerAddress << peerPort << boundNetDevice);
139   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
140     {
141       if ((*i)->GetLocalPort () == localPort &&
142           (*i)->GetLocalAddress () == localAddress &&
143           (*i)->GetPeerPort () == peerPort &&
144           (*i)->GetPeerAddress () == peerAddress &&
145           ((*i)->GetBoundNetDevice () == boundNetDevice || (*i)->GetBoundNetDevice () == 0))
146         {
147           NS_LOG_WARN ("Duplicated endpoint.");
148           return 0;
149         }
150     }
151   Ipv4EndPoint *endPoint = new Ipv4EndPoint (localAddress, localPort);
152   endPoint->SetPeer (peerAddress, peerPort);
153   m_endPoints.push_back (endPoint);
154 
155   NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
156 
157   return endPoint;
158 }
159 
160 void
DeAllocate(Ipv4EndPoint * endPoint)161 Ipv4EndPointDemux::DeAllocate (Ipv4EndPoint *endPoint)
162 {
163   NS_LOG_FUNCTION (this << endPoint);
164   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
165     {
166       if (*i == endPoint)
167         {
168           delete endPoint;
169           m_endPoints.erase (i);
170           break;
171         }
172     }
173 }
174 
175 /*
176  * return list of all available Endpoints
177  */
178 Ipv4EndPointDemux::EndPoints
GetAllEndPoints(void)179 Ipv4EndPointDemux::GetAllEndPoints (void)
180 {
181   NS_LOG_FUNCTION (this);
182   EndPoints ret;
183 
184   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
185     {
186       Ipv4EndPoint* endP = *i;
187       ret.push_back (endP);
188     }
189   return ret;
190 }
191 
192 
193 /*
194  * If we have an exact match, we return it.
195  * Otherwise, if we find a generic match, we return it.
196  * Otherwise, we return 0.
197  */
198 Ipv4EndPointDemux::EndPoints
Lookup(Ipv4Address daddr,uint16_t dport,Ipv4Address saddr,uint16_t sport,Ptr<Ipv4Interface> incomingInterface)199 Ipv4EndPointDemux::Lookup (Ipv4Address daddr, uint16_t dport,
200                            Ipv4Address saddr, uint16_t sport,
201                            Ptr<Ipv4Interface> incomingInterface)
202 {
203   NS_LOG_FUNCTION (this << daddr << dport << saddr << sport << incomingInterface);
204 
205   EndPoints retval1; // Matches exact on local port, wildcards on others
206   EndPoints retval2; // Matches exact on local port/adder, wildcards on others
207   EndPoints retval3; // Matches all but local address
208   EndPoints retval4; // Exact match on all 4
209 
210   NS_LOG_DEBUG ("Looking up endpoint for destination address " << daddr << ":" << dport);
211   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
212     {
213       Ipv4EndPoint* endP = *i;
214 
215       NS_LOG_DEBUG ("Looking at endpoint dport=" << endP->GetLocalPort ()
216                                                  << " daddr=" << endP->GetLocalAddress ()
217                                                  << " sport=" << endP->GetPeerPort ()
218                                                  << " saddr=" << endP->GetPeerAddress ());
219 
220       if (!endP->IsRxEnabled ())
221         {
222           NS_LOG_LOGIC ("Skipping endpoint " << &endP
223                         << " because endpoint can not receive packets");
224           continue;
225         }
226 
227       if (endP->GetLocalPort () != dport)
228         {
229           NS_LOG_LOGIC ("Skipping endpoint " << &endP
230                                              << " because endpoint dport "
231                                              << endP->GetLocalPort ()
232                                              << " does not match packet dport " << dport);
233           continue;
234         }
235       if (endP->GetBoundNetDevice ())
236         {
237           if (endP->GetBoundNetDevice () != incomingInterface->GetDevice ())
238             {
239               NS_LOG_LOGIC ("Skipping endpoint " << &endP
240                                                  << " because endpoint is bound to specific device and"
241                                                  << endP->GetBoundNetDevice ()
242                                                  << " does not match packet device " << incomingInterface->GetDevice ());
243               continue;
244             }
245         }
246 
247       bool localAddressMatchesExact = false;
248       bool localAddressIsAny = false;
249       bool localAddressIsSubnetAny = false;
250 
251       // We have 3 cases:
252       // 1) Exact local / destination address match
253       // 2) Local endpoint bound to Any -> matches anything
254       // 3) Local endpoint bound to x.y.z.0 -> matches Subnet-directed broadcast packet (e.g., x.y.z.255 in a /24 net) and direct destination match.
255 
256       if (endP->GetLocalAddress () == daddr)
257         {
258           // Case 1:
259           localAddressMatchesExact = true;
260         }
261       else if (endP->GetLocalAddress () == Ipv4Address::GetAny ())
262         {
263           // Case 2:
264           localAddressIsAny = true;
265         }
266       else
267         {
268           // Case 3:
269           for (uint32_t i = 0; i < incomingInterface->GetNAddresses (); i++)
270             {
271               Ipv4InterfaceAddress addr = incomingInterface->GetAddress (i);
272 
273               Ipv4Address addrNetpart = addr.GetLocal ().CombineMask (addr.GetMask ());
274               if (endP->GetLocalAddress () == addrNetpart)
275                 {
276                   NS_LOG_LOGIC ("Endpoint is SubnetDirectedAny " << endP->GetLocalAddress () << "/" << addr.GetMask ().GetPrefixLength ());
277 
278                   Ipv4Address daddrNetPart = daddr.CombineMask (addr.GetMask ());
279                   if (addrNetpart == daddrNetPart)
280                     {
281                       localAddressIsSubnetAny = true;
282                     }
283                 }
284             }
285 
286           // if no match here, keep looking
287           if (!localAddressIsSubnetAny)
288             continue;
289         }
290 
291       bool remotePortMatchesExact = endP->GetPeerPort () == sport;
292       bool remotePortMatchesWildCard = endP->GetPeerPort () == 0;
293       bool remoteAddressMatchesExact = endP->GetPeerAddress () == saddr;
294       bool remoteAddressMatchesWildCard = endP->GetPeerAddress () == Ipv4Address::GetAny ();
295 
296       // If remote does not match either with exact or wildcard,
297       // skip this one
298       if (!(remotePortMatchesExact || remotePortMatchesWildCard))
299         continue;
300       if (!(remoteAddressMatchesExact || remoteAddressMatchesWildCard))
301         continue;
302 
303       bool localAddressMatchesWildCard = localAddressIsAny || localAddressIsSubnetAny;
304 
305       if (localAddressMatchesExact && remoteAddressMatchesExact && remotePortMatchesExact)
306         { // All 4 match - this is the case of an open TCP connection, for example.
307           NS_LOG_LOGIC ("Found an endpoint for case 4, adding " << endP->GetLocalAddress () << ":" << endP->GetLocalPort ());
308           retval4.push_back (endP);
309         }
310       if (localAddressMatchesWildCard && remoteAddressMatchesExact && remotePortMatchesExact)
311         { // All but local address - no idea what this case could be.
312           NS_LOG_LOGIC ("Found an endpoint for case 3, adding " << endP->GetLocalAddress () << ":" << endP->GetLocalPort ());
313           retval3.push_back (endP);
314         }
315       if (localAddressMatchesExact && remoteAddressMatchesWildCard && remotePortMatchesWildCard)
316         { // Only local port and local address matches exactly - Not yet opened connection
317           NS_LOG_LOGIC ("Found an endpoint for case 2, adding " << endP->GetLocalAddress () << ":" << endP->GetLocalPort ());
318           retval2.push_back (endP);
319         }
320       if (localAddressMatchesWildCard && remoteAddressMatchesWildCard && remotePortMatchesWildCard)
321         { // Only local port matches exactly - Endpoint open to "any" connection
322           NS_LOG_LOGIC ("Found an endpoint for case 1, adding " << endP->GetLocalAddress () << ":" << endP->GetLocalPort ());
323           retval1.push_back (endP);
324         }
325     }
326 
327   // Here we find the most exact match
328   EndPoints retval;
329   if (!retval4.empty ()) retval = retval4;
330   else if (!retval3.empty ()) retval = retval3;
331   else if (!retval2.empty ()) retval = retval2;
332   else retval = retval1;
333 
334   NS_ABORT_MSG_IF (retval.size () > 1, "Too many endpoints - perhaps you created too many sockets without binding them to different NetDevices.");
335   return retval;  // might be empty if no matches
336 }
337 
338 Ipv4EndPoint *
SimpleLookup(Ipv4Address daddr,uint16_t dport,Ipv4Address saddr,uint16_t sport)339 Ipv4EndPointDemux::SimpleLookup (Ipv4Address daddr,
340                                  uint16_t dport,
341                                  Ipv4Address saddr,
342                                  uint16_t sport)
343 {
344   NS_LOG_FUNCTION (this << daddr << dport << saddr << sport);
345 
346   // this code is a copy/paste version of an old BSD ip stack lookup
347   // function.
348   uint32_t genericity = 3;
349   Ipv4EndPoint *generic = 0;
350   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
351     {
352       if ((*i)->GetLocalPort () != dport)
353         {
354           continue;
355         }
356       if ((*i)->GetLocalAddress () == daddr &&
357           (*i)->GetPeerPort () == sport &&
358           (*i)->GetPeerAddress () == saddr)
359         {
360           /* this is an exact match. */
361           return *i;
362         }
363       uint32_t tmp = 0;
364       if ((*i)->GetLocalAddress () == Ipv4Address::GetAny ())
365         {
366           tmp++;
367         }
368       if ((*i)->GetPeerAddress () == Ipv4Address::GetAny ())
369         {
370           tmp++;
371         }
372       if (tmp < genericity)
373         {
374           generic = (*i);
375           genericity = tmp;
376         }
377     }
378   return generic;
379 }
380 uint16_t
AllocateEphemeralPort(void)381 Ipv4EndPointDemux::AllocateEphemeralPort (void)
382 {
383   // Similar to counting up logic in netinet/in_pcb.c
384   NS_LOG_FUNCTION (this);
385   uint16_t port = m_ephemeral;
386   int count = m_portLast - m_portFirst;
387   do
388     {
389       if (count-- < 0)
390         {
391           return 0;
392         }
393       ++port;
394       if (port < m_portFirst || port > m_portLast)
395         {
396           port = m_portFirst;
397         }
398     } while (LookupPortLocal (port));
399   m_ephemeral = port;
400   return port;
401 }
402 
403 } // namespace ns3
404 
405