src/internet-stack/ipv4-netfilter.cc
author Qasim Javed <qasimj@gmail.com>
Thu Aug 06 01:55:49 2009 +0600 (2009-08-06)
changeset 4638 19aa5f9b4bdf
parent 4637 0882bb6eac0b
permissions -rw-r--r--
Source NAT working! Run (examples/netfilter-example.cc)
qasimj@4634
     1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
qasimj@4634
     2
/* 
qasimj@4634
     3
 * Copyright (c) 2009 University of Texas at Dallas
qasimj@4634
     4
 * 
qasimj@4634
     5
 * This program is free software; you can redistribute it and/or modify
qasimj@4634
     6
 * it under the terms of the GNU General Public License version 2 as
qasimj@4634
     7
 * published by the Free Software Foundation;
qasimj@4634
     8
 *
qasimj@4634
     9
 * This program is distributed in the hope that it will be useful,
qasimj@4634
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
qasimj@4634
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
qasimj@4634
    12
 * GNU General Public License for more details.
qasimj@4634
    13
 *
qasimj@4634
    14
 * You should have received a copy of the GNU General Public License
qasimj@4634
    15
 * along with this program; if not, write to the Free Software
qasimj@4634
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
qasimj@4634
    17
 * 
qasimj@4634
    18
 * Author: Qasim Javed <qasim@utdallas.edu>
qasimj@4634
    19
 */
qasimj@4634
    20
#include "ns3/log.h"
qasimj@4638
    21
#include "ns3/uinteger.h"
qasimj@4634
    22
#include "ipv4-netfilter.h"
qasimj@4634
    23
#include "ip-conntrack-info.h"
qasimj@4634
    24
#include "ipv4-conntrack-l3-protocol.h"
qasimj@4634
    25
#include "tcp-conntrack-l4-protocol.h"
qasimj@4634
    26
#include "udp-conntrack-l4-protocol.h"
qasimj@4637
    27
#include "icmpv4-conntrack-l4-protocol.h"
qasimj@4638
    28
#include "tcp-header.h"
qasimj@4638
    29
#include "udp-header.h"
qasimj@4634
    30
qasimj@4634
    31
NS_LOG_COMPONENT_DEFINE ("Ipv4Netfilter");
qasimj@4634
    32
qasimj@4634
    33
namespace ns3 {
qasimj@4638
    34
qasimj@4638
    35
NS_OBJECT_ENSURE_REGISTERED (Ipv4Netfilter);
qasimj@4638
    36
qasimj@4638
    37
TypeId 
qasimj@4638
    38
Ipv4Netfilter::GetTypeId (void)
qasimj@4638
    39
{
qasimj@4638
    40
  static TypeId tId = TypeId ("ns3::Ipv4Netfilter")
qasimj@4638
    41
    .SetParent<Object> ()
qasimj@4638
    42
    .AddAttribute ("EnableNat", "0 disbales NAT and is the default, 1 enabled NAT",
qasimj@4638
    43
                   UintegerValue (0),
qasimj@4638
    44
                   MakeUintegerAccessor (&Ipv4Netfilter::m_enableNat),
qasimj@4638
    45
                   MakeUintegerChecker <uint8_t> ())
qasimj@4638
    46
    ;
qasimj@4638
    47
qasimj@4638
    48
  return tId;
qasimj@4638
    49
}
qasimj@4636
    50
  
qasimj@4636
    51
Ipv4Netfilter::Ipv4Netfilter ()
qasimj@4638
    52
  : m_enableNat (0)
qasimj@4634
    53
{
qasimj@4634
    54
  NS_LOG_FUNCTION_NOARGS();
qasimj@4634
    55
qasimj@4634
    56
  /* Create callback chains for all of the hooks */
qasimj@4634
    57
  for (int i=0; i < NF_INET_NUMHOOKS; i++)
qasimj@4636
    58
    m_netfilterHooks[i] = NetfilterCallbackChain ();
qasimj@4634
    59
qasimj@4634
    60
  /* Create and register Ipv4 connection tracking module */
qasimj@4634
    61
  Ptr<Ipv4ConntrackL3Protocol> ipv4 = Create<Ipv4ConntrackL3Protocol> ();
qasimj@4636
    62
  this->RegisterL3Protocol (ipv4);
qasimj@4634
    63
  
qasimj@4634
    64
  /* Create and register TCP connection tracking module */
qasimj@4634
    65
  Ptr<TcpConntrackL4Protocol> tcp = Create<TcpConntrackL4Protocol> ();
qasimj@4636
    66
  this->RegisterL4Protocol (tcp);
qasimj@4634
    67
  
qasimj@4634
    68
  /* Create and register UDP connection tracking module */
qasimj@4634
    69
  Ptr<UdpConntrackL4Protocol> udp = Create<UdpConntrackL4Protocol> ();
qasimj@4636
    70
  this->RegisterL4Protocol (udp);
qasimj@4637
    71
  
qasimj@4637
    72
  /* Create and register ICMP connection tracking module */
qasimj@4637
    73
  Ptr<Icmpv4ConntrackL4Protocol> icmpv4 = Create<Icmpv4ConntrackL4Protocol> ();
qasimj@4637
    74
  this->RegisterL4Protocol (icmpv4);
qasimj@4638
    75
  
qasimj@4638
    76
  //Ptr <NetworkAddressTranslation> networkAddressTranslation = Create<NetworkAddressTranslation> (this);
qasimj@4634
    77
qasimj@4634
    78
  /* Create and register hook callbacks */
qasimj@4636
    79
  NetfilterHookCallback preRouting = MakeCallback (&Ipv4Netfilter::NetfilterConntrackIn, this);
qasimj@4636
    80
  NetfilterHookCallback localIn = MakeCallback (&Ipv4ConntrackL3Protocol::Ipv4Confirm, PeekPointer (ipv4));
qasimj@4634
    81
qasimj@4638
    82
  Ipv4NetfilterHook nfh = Ipv4NetfilterHook (1, NF_INET_PRE_ROUTING, NF_IP_PRI_CONNTRACK , preRouting); 
qasimj@4638
    83
  Ipv4NetfilterHook nfh1 = Ipv4NetfilterHook (1, NF_INET_LOCAL_OUT, NF_IP_PRI_CONNTRACK, preRouting); 
qasimj@4638
    84
  Ipv4NetfilterHook nfh2 = Ipv4NetfilterHook (1, NF_INET_POST_ROUTING, NF_IP_PRI_CONNTRACK_CONFIRM, localIn); 
qasimj@4638
    85
  Ipv4NetfilterHook nfh3 = Ipv4NetfilterHook (1, NF_INET_LOCAL_IN, NF_IP_PRI_CONNTRACK_CONFIRM, localIn); 
qasimj@4638
    86
  
qasimj@4636
    87
  this->RegisterNetfilterHook (nfh);
qasimj@4636
    88
  this->RegisterNetfilterHook (nfh1);
qasimj@4636
    89
  this->RegisterNetfilterHook (nfh2);
qasimj@4636
    90
  this->RegisterNetfilterHook (nfh3);
qasimj@4638
    91
qasimj@4638
    92
  if (m_enableNat)
qasimj@4638
    93
    EnableNat ();
qasimj@4638
    94
qasimj@4638
    95
  nextAvailablePort = 1024;
qasimj@4634
    96
}
qasimj@4634
    97
qasimj@4634
    98
uint32_t 
qasimj@4638
    99
Ipv4Netfilter::RegisterNetfilterHook (Ipv4NetfilterHook hook)
qasimj@4634
   100
{
qasimj@4634
   101
  //NS_LOG_FUNCTION (this << hook);
qasimj@4636
   102
  m_netfilterHooks[hook.GetHookNumber ()].Insert (hook);
qasimj@4634
   103
  return 0;
qasimj@4634
   104
}
qasimj@4634
   105
qasimj@4634
   106
uint32_t 
qasimj@4636
   107
Ipv4Netfilter::UnRegisterNetfilterHook (Ipv4NetfilterHook& hook)
qasimj@4634
   108
{
qasimj@4636
   109
  m_netfilterHooks[hook.GetHookNumber ()].Remove (hook);
qasimj@4634
   110
  return 0;
qasimj@4634
   111
}
qasimj@4634
   112
qasimj@4634
   113
uint32_t 
qasimj@4634
   114
Ipv4Netfilter::ProcessHook(uint8_t protocolFamily, Hooks_t hookNumber, Ptr<Packet> p, 
qasimj@4636
   115
                           Ptr<NetDevice> in, Ptr<NetDevice> out, 
qasimj@4636
   116
                           ContinueCallback ccb)
qasimj@4634
   117
{
qasimj@4636
   118
  return m_netfilterHooks[(uint32_t)hookNumber].IterateAndCallHook (hookNumber, p, in, out, ccb);
qasimj@4634
   119
}
qasimj@4634
   120
qasimj@4634
   121
uint32_t 
qasimj@4634
   122
Ipv4Netfilter::RegisterL3Protocol(Ptr<NetfilterConntrackL3Protocol> l3Protocol)
qasimj@4634
   123
{
qasimj@4634
   124
  //m_netfilterConntrackL3Protocols.push_back(l3Protocol);
qasimj@4634
   125
  m_netfilterConntrackL3Protocols = l3Protocol;
qasimj@4634
   126
  return 0;
qasimj@4634
   127
}
qasimj@4634
   128
qasimj@4634
   129
uint32_t 
qasimj@4634
   130
Ipv4Netfilter::RegisterL4Protocol(Ptr<NetfilterConntrackL4Protocol> l4Protocol)
qasimj@4634
   131
{
qasimj@4634
   132
  m_netfilterConntrackL4Protocols.push_back(l4Protocol);
qasimj@4634
   133
  return 0;
qasimj@4634
   134
}
qasimj@4634
   135
qasimj@4634
   136
Ptr<NetfilterConntrackL3Protocol> 
qasimj@4636
   137
Ipv4Netfilter::FindL3ProtocolHelper (uint8_t protocolFamily)
qasimj@4634
   138
{
qasimj@4634
   139
  /*Ptr<NetfilterConntrackL3Protocol>::iterator it;
qasimj@4634
   140
qasimj@4634
   141
  for (; it != netfilerConntrackL3Protocols.end(); it++)
qasimj@4634
   142
  {
qasimj@4634
   143
    if (protocolFamily == it->protocol)
qasimj@4634
   144
      return *it;
qasimj@4634
   145
  }*/
qasimj@4634
   146
qasimj@4634
   147
  return m_netfilterConntrackL3Protocols;
qasimj@4634
   148
qasimj@4634
   149
}
qasimj@4634
   150
qasimj@4634
   151
Ptr<NetfilterConntrackL4Protocol> 
qasimj@4636
   152
Ipv4Netfilter::FindL4ProtocolHelper (uint8_t protocol)
qasimj@4634
   153
{
qasimj@4634
   154
  std::vector<Ptr<NetfilterConntrackL4Protocol> >::iterator it;
qasimj@4634
   155
qasimj@4636
   156
  for (it =  m_netfilterConntrackL4Protocols.begin (); it != m_netfilterConntrackL4Protocols.end (); it++)
qasimj@4634
   157
  {
qasimj@4636
   158
    NS_LOG_DEBUG ( "L4 protocol: " << (*it)->GetL4Protocol () << ", This protocol : "<<(int)protocol );
qasimj@4636
   159
    if ((*it)->GetL4Protocol () == protocol) {
qasimj@4634
   160
      NS_LOG_DEBUG ( "Found protocol " <<(int)protocol );
qasimj@4634
   161
      return *it;
qasimj@4634
   162
    }
qasimj@4634
   163
  }
qasimj@4634
   164
qasimj@4634
   165
  return NULL;
qasimj@4634
   166
}
qasimj@4634
   167
qasimj@4634
   168
int 
qasimj@4638
   169
Ipv4Netfilter::UpdateConntrackInfo (uint8_t info)
qasimj@4634
   170
{
qasimj@4638
   171
  m_hash[currentOriginalTuple].SetInfo (info);
qasimj@4638
   172
  m_hash[currentReplyTuple].SetInfo (info);
qasimj@4634
   173
  return 0;
qasimj@4634
   174
}
qasimj@4634
   175
qasimj@4634
   176
bool 
qasimj@4636
   177
Ipv4Netfilter::NetfilterConntrackGetTuple (Ptr<Packet> packet, uint16_t l3Number, uint8_t protocolNumber, 
qasimj@4634
   178
               NetfilterConntrackTuple& tuple, Ptr<NetfilterConntrackL3Protocol> l3Protocol, 
qasimj@4634
   179
               Ptr<NetfilterConntrackL4Protocol> l4Protocol)
qasimj@4634
   180
{
qasimj@4636
   181
  tuple.SetProtocol (l3Number);
qasimj@4634
   182
qasimj@4636
   183
  if (l3Protocol->PacketToTuple (packet, tuple) == false)
qasimj@4634
   184
    return false;
qasimj@4634
   185
qasimj@4634
   186
  //TODO: Do we really need the Protocol Family as well?
qasimj@4634
   187
  //tuple->Set
qasimj@4635
   188
  Ipv4Header ipHeader;
qasimj@4635
   189
  NS_LOG_DEBUG (" :: Remove Ipv4 Header :: ");
qasimj@4636
   190
  packet->RemoveHeader (ipHeader);
qasimj@4634
   191
  
qasimj@4636
   192
  tuple.SetDirection (IP_CT_DIR_ORIGINAL);
qasimj@4635
   193
  
qasimj@4636
   194
  if (l4Protocol->PacketToTuple (packet, tuple) == false)
qasimj@4635
   195
    return false;
qasimj@4635
   196
  
qasimj@4635
   197
  NS_LOG_DEBUG (" :: Add Ipv4 Header :: ");
qasimj@4635
   198
  packet->AddHeader (ipHeader);
qasimj@4634
   199
qasimj@4635
   200
  return true;
qasimj@4634
   201
}
qasimj@4634
   202
qasimj@4635
   203
TupleHashI
qasimj@4636
   204
Ipv4Netfilter::NewConnection (NetfilterConntrackTuple& tuple, Ptr<NetfilterConntrackL3Protocol> l3proto, 
qasimj@4634
   205
                             Ptr<NetfilterConntrackL4Protocol> l4proto, Ptr<Packet> packet)
qasimj@4634
   206
{
qasimj@4634
   207
  NS_LOG_FUNCTION ( this << packet );
qasimj@4634
   208
qasimj@4634
   209
  NetfilterConntrackTuple replyTuple;
qasimj@4634
   210
qasimj@4636
   211
  if (!InvertTuple (replyTuple, tuple, l3proto, l4proto))
qasimj@4636
   212
    return m_hash.end ();
qasimj@4634
   213
qasimj@4635
   214
  // Invoke l4proto->New
qasimj@4634
   215
qasimj@4635
   216
  // Find expectatons here
qasimj@4634
   217
qasimj@4635
   218
  NS_LOG_DEBUG (":: Creating an unconfirmed entry for this tuple ::");
qasimj@4636
   219
  m_unconfirmed[tuple] = IpConntrackInfo ();
qasimj@4635
   220
 
qasimj@4636
   221
  TupleHashI it = m_unconfirmed.find (tuple);
qasimj@4635
   222
  
qasimj@4635
   223
  return it;
qasimj@4634
   224
}
qasimj@4634
   225
qasimj@4634
   226
uint32_t 
qasimj@4634
   227
Ipv4Netfilter::ResolveNormalConntrack (Ptr<Packet> packet, uint32_t protocolFamily, uint8_t protocol, 
qasimj@4634
   228
               Ptr<NetfilterConntrackL3Protocol> l3Protocol, Ptr<NetfilterConntrackL4Protocol> l4Protocol, 
qasimj@4634
   229
               int& setReply, ConntrackInfo_t& ctInfo, Ipv4Header ipHeader)
qasimj@4634
   230
{
qasimj@4634
   231
  NS_LOG_FUNCTION (this << packet);
qasimj@4634
   232
  //NetfilterConntrackTuple tuple (ipHeader.GetSource(), 0, ipHeader.GetDestination(), 0);
qasimj@4634
   233
  NetfilterConntrackTuple tuple;
qasimj@4638
   234
  uint8_t conntrackInfo = 0;
qasimj@4634
   235
  
qasimj@4634
   236
  /* Get a tuple from the information in the packet */
qasimj@4636
   237
  if (!NetfilterConntrackGetTuple (packet, protocolFamily, protocol, tuple, l3Protocol, l4Protocol))
qasimj@4634
   238
  {
qasimj@4634
   239
    NS_LOG_DEBUG ("Cannot create a tuple from the packet");
qasimj@4634
   240
    return -1;
qasimj@4634
   241
  }
qasimj@4634
   242
  
qasimj@4636
   243
  TupleHashI it = m_hash.find (tuple);
qasimj@4634
   244
qasimj@4636
   245
  if (it == m_hash.end ())
qasimj@4634
   246
  {
qasimj@4634
   247
    NS_LOG_DEBUG ("No tuple found");
qasimj@4635
   248
    //TupleHashI newIt = NewConnection(tuple, l3Protocol, l4Protocol, packet);
qasimj@4636
   249
    it = NewConnection (tuple, l3Protocol, l4Protocol, packet);
qasimj@4634
   250
  }
qasimj@4638
   251
  
qasimj@4638
   252
  NetfilterConntrackTuple replyTuple;
qasimj@4638
   253
qasimj@4638
   254
  if (!InvertTuple (replyTuple, tuple, l3Protocol, l4Protocol))
qasimj@4638
   255
    return -1;
qasimj@4638
   256
    
qasimj@4638
   257
  currentOriginalTuple = tuple;
qasimj@4638
   258
  currentReplyTuple = replyTuple;
qasimj@4634
   259
qasimj@4635
   260
  /* TODO: Add a pointer to the hashed tuple in IpConntrackInfo()
qasimj@4635
   261
   * and store these tuples somehwere, when you destruct then you
qasimj@4635
   262
   * you have to take care of the tuples stored in the vector as 
qasimj@4635
   263
   * well 
qasimj@4635
   264
   */
qasimj@4636
   265
  if ((it->first).GetDirection () == (uint8_t)IP_CT_DIR_REPLY)
qasimj@4634
   266
  {
qasimj@4635
   267
    NS_LOG_DEBUG (":: **** This is a REPLY *** ::");
qasimj@4634
   268
    conntrackInfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
qasimj@4634
   269
    setReply = 1;
qasimj@4634
   270
  } else {
qasimj@4634
   271
    NS_LOG_DEBUG (":: Packet is in the original direction ::");
qasimj@4638
   272
    if ( m_hash[tuple].GetStatus () & IPS_SEEN_REPLY) {
qasimj@4638
   273
      NS_LOG_DEBUG (":: Connection ESTABLISHED! ::");
qasimj@4634
   274
      conntrackInfo = IP_CT_ESTABLISHED;
qasimj@4634
   275
    }
qasimj@4634
   276
    else {
qasimj@4634
   277
      NS_LOG_DEBUG (":: New connection :: ");
qasimj@4634
   278
      conntrackInfo = IP_CT_NEW;
qasimj@4634
   279
    }
qasimj@4634
   280
qasimj@4634
   281
  }
qasimj@4638
   282
qasimj@4638
   283
  m_unconfirmed[tuple].SetInfo (conntrackInfo);
qasimj@4638
   284
  //UpdateConntrackInfo (conntrackInfo);
qasimj@4638
   285
  /*NS_LOG_DEBUG ("Adding the conntrack packet tag" );
qasimj@4635
   286
  ConntrackTag ctTag;
qasimj@4635
   287
  bool tagFound = packet->PeekPacketTag (ctTag);
qasimj@4635
   288
qasimj@4635
   289
  if (!tagFound)
qasimj@4635
   290
    packet->AddPacketTag (ConntrackTag (conntrackInfo));
qasimj@4635
   291
  else
qasimj@4635
   292
    NS_LOG_DEBUG ("Tag already present");
qasimj@4638
   293
    */
qasimj@4634
   294
qasimj@4634
   295
  return NF_ACCEPT;
qasimj@4634
   296
qasimj@4634
   297
}
qasimj@4634
   298
qasimj@4634
   299
uint32_t 
qasimj@4636
   300
Ipv4Netfilter::NetfilterConntrackIn (Hooks_t hook, Ptr<Packet> packet, Ptr<NetDevice> in, 
qasimj@4634
   301
                                    Ptr<NetDevice> out, ContinueCallback& ccb)
qasimj@4634
   302
{
qasimj@4634
   303
  NS_LOG_DEBUG ("::: Executing Hook Function :::");
qasimj@4634
   304
  int setReply=0;
qasimj@4634
   305
  ConntrackInfo_t ctInfo;
qasimj@4634
   306
  /* If this packet has been seen previously, Ignore. */
qasimj@4634
   307
qasimj@4634
   308
  /* Find layer 3 helper for this packet */
qasimj@4636
   309
  Ptr<NetfilterConntrackL3Protocol> l3proto = FindL3ProtocolHelper (1);
qasimj@4634
   310
qasimj@4634
   311
  Ipv4Header ipHeader;
qasimj@4634
   312
qasimj@4636
   313
  packet->PeekHeader (ipHeader);
qasimj@4634
   314
qasimj@4636
   315
  NS_LOG_DEBUG ( "IP header protocol: " << (int)ipHeader.GetProtocol ());
qasimj@4634
   316
  
qasimj@4636
   317
  Ptr<NetfilterConntrackL4Protocol> l4proto = FindL4ProtocolHelper (ipHeader.GetProtocol ());
qasimj@4634
   318
qasimj@4634
   319
  /*if (l4proto != NULL) {
qasimj@4634
   320
  }*/
qasimj@4634
   321
qasimj@4636
   322
  ResolveNormalConntrack (packet, 1 /* PF */, ipHeader.GetProtocol (), l3proto, l4proto, setReply, ctInfo, ipHeader);
qasimj@4634
   323
qasimj@4634
   324
  // Call layer 4 Packet callback
qasimj@4634
   325
  //uint32_t ret = l4proto->packet(packet, protocolFamily, hookNumber);
qasimj@4634
   326
qasimj@4638
   327
  if (setReply)
qasimj@4638
   328
  {
qasimj@4638
   329
    NS_LOG_DEBUG ("Setting IPS_SEEN_REPLY");
qasimj@4638
   330
    m_hash[currentOriginalTuple].SetStatus ( IPS_SEEN_REPLY );
qasimj@4638
   331
    m_hash[currentReplyTuple].SetStatus ( IPS_SEEN_REPLY );
qasimj@4638
   332
  }
qasimj@4638
   333
qasimj@4634
   334
  return NF_ACCEPT;
qasimj@4634
   335
qasimj@4634
   336
}
qasimj@4634
   337
qasimj@4635
   338
uint32_t
qasimj@4635
   339
Ipv4Netfilter::NetfilterConntrackConfirm (Ptr<Packet> packet)
qasimj@4635
   340
    //, NetfilterConntrackTuple& orig,
qasimj@4635
   341
     //          NetfilterConntrackTuple& reply)
qasimj@4634
   342
{
qasimj@4635
   343
  NS_LOG_FUNCTION ( this << packet );
qasimj@4635
   344
  /* If this packet has been seen previously, Ignore. */
qasimj@4635
   345
qasimj@4635
   346
  /* Find layer 3 helper for this packet */
qasimj@4638
   347
  /*Ptr<NetfilterConntrackL3Protocol> l3proto = FindL3ProtocolHelper (1);
qasimj@4635
   348
qasimj@4638
   349
    Ipv4Header ipHeader;
qasimj@4635
   350
qasimj@4635
   351
  //packet->RemoveHeader(ipHeader);
qasimj@4636
   352
  packet->PeekHeader (ipHeader);
qasimj@4635
   353
qasimj@4636
   354
  NS_LOG_DEBUG ( "IP header protocol: " << (int)ipHeader.GetProtocol ());
qasimj@4638
   355
qasimj@4636
   356
  Ptr<NetfilterConntrackL4Protocol> l4proto = FindL4ProtocolHelper (ipHeader.GetProtocol ());
qasimj@4638
   357
qasimj@4638
   358
  NetfilterConntrackTuple orig;*/
qasimj@4638
   359
qasimj@4635
   360
  /* Get a tuple from the information in the packet */
qasimj@4638
   361
  /*if (!NetfilterConntrackGetTuple (packet, 1, ipHeader.GetProtocol (), orig, l3proto, l4proto))
qasimj@4638
   362
    {
qasimj@4635
   363
    NS_LOG_DEBUG ("Cannot create a tuple from the packet");
qasimj@4635
   364
    return -1;
qasimj@4638
   365
    }
qasimj@4635
   366
qasimj@4638
   367
    NetfilterConntrackTuple reply;
qasimj@4638
   368
qasimj@4638
   369
qasimj@4638
   370
    InvertTuple (reply, orig, l3proto, l4proto);
qasimj@4638
   371
qasimj@4638
   372
    currentOriginalTuple = orig;
qasimj@4638
   373
    currentReplyTuple = reply;
qasimj@4638
   374
qasimj@4638
   375
    NS_LOG_DEBUG ("Current Original Tuple: " << currentOriginalTuple.GetSource () << ", " << currentOriginalTuple.GetDestination ());
qasimj@4638
   376
    NS_LOG_DEBUG ("Current Reply Tuple: " << currentReplyTuple.GetSource () << ", " << currentReplyTuple.GetDestination ());
qasimj@4638
   377
  //currentTuple[IP_CT_DIR_REPLY] = reply;*/
qasimj@4635
   378
qasimj@4635
   379
  /**************************/
qasimj@4635
   380
qasimj@4638
   381
  /*ConntrackTag ctTag;
qasimj@4634
   382
qasimj@4638
   383
    if (!packet->PeekPacketTag (ctTag))
qasimj@4638
   384
    {
qasimj@4634
   385
    NS_LOG_DEBUG ("ConntrackTag not found");
qasimj@4634
   386
    return 0;
qasimj@4638
   387
    }
qasimj@4638
   388
    else {
qasimj@4636
   389
    if ( CTINFO2DIR (ctTag.GetConntrack ()) != IP_CT_DIR_ORIGINAL)
qasimj@4638
   390
    return 0;
qasimj@4635
   391
qasimj@4636
   392
    if (m_hash.find (orig) != m_hash.end () && m_hash.find (reply) != m_hash.end () )
qasimj@4635
   393
    {
qasimj@4638
   394
    NS_LOG_DEBUG ("Entries already present!");
qasimj@4638
   395
    return NF_DROP;
qasimj@4635
   396
    }
qasimj@4635
   397
qasimj@4635
   398
    NS_LOG_DEBUG ("Creating confirmed hash entries");
qasimj@4638
   399
  //m_hash[orig] = IpConntrackInfo().SetStatus(IPS_CONFIRMED);
qasimj@4638
   400
  m_hash[orig] = IpConntrackInfo ();
qasimj@4638
   401
  m_hash[reply] = IpConntrackInfo ();
qasimj@4635
   402
qasimj@4638
   403
  }*/
qasimj@4638
   404
qasimj@4638
   405
  if ( CTINFO2DIR (m_unconfirmed[currentOriginalTuple].GetInfo ()) != IP_CT_DIR_ORIGINAL) 
qasimj@4638
   406
  {
qasimj@4638
   407
    NS_LOG_DEBUG ("Not a packet in the original direction");
qasimj@4638
   408
    return NF_ACCEPT;
qasimj@4634
   409
  }
qasimj@4634
   410
qasimj@4638
   411
  /*if (m_hash.find (currentOriginalTuple) != m_hash.end () && m_hash.find (currentReplyTuple) != m_hash.end () )
qasimj@4638
   412
  {
qasimj@4638
   413
    NS_LOG_DEBUG ("Entries already present!");
qasimj@4638
   414
    return NF_DROP;
qasimj@4638
   415
  }*/
qasimj@4638
   416
qasimj@4638
   417
  NS_LOG_DEBUG ("Creating confirmed hash entries");
qasimj@4638
   418
  m_hash[currentOriginalTuple] = m_unconfirmed[currentOriginalTuple];
qasimj@4638
   419
  m_hash[currentReplyTuple] = m_unconfirmed[currentOriginalTuple];
qasimj@4635
   420
qasimj@4634
   421
  return 0;
qasimj@4634
   422
}
qasimj@4634
   423
    
qasimj@4638
   424
uint32_t 
qasimj@4638
   425
Ipv4Netfilter::NetfilterDoNat (Hooks_t hookNumber, Ptr<Packet> p, 
qasimj@4638
   426
                               Ptr<NetDevice> in, Ptr<NetDevice> out, ContinueCallback& ccb)
qasimj@4638
   427
{
qasimj@4638
   428
  NS_LOG_FUNCTION ( this << p );
qasimj@4638
   429
  /*ConntrackTag ctTag;
qasimj@4638
   430
qasimj@4638
   431
  bool found = p->PeekPacketTag (ctTag);
qasimj@4638
   432
qasimj@4638
   433
  if (!found)
qasimj@4638
   434
  {
qasimj@4638
   435
    NS_LOG_DEBUG ("Conntrack tag not found");
qasimj@4638
   436
    return NF_ACCEPT;
qasimj@4638
   437
  }*/
qasimj@4638
   438
qasimj@4638
   439
  /* Conntrack has a higher priority so currentOriginalTuple and
qasimj@4638
   440
   * currentReply tuple should always be correct 
qasimj@4638
   441
   */
qasimj@4638
   442
qasimj@4638
   443
  //std::vector<NatRule>::iterator it = FindNatDevice (out);
qasimj@4638
   444
qasimj@4638
   445
  /*if (it == m_natRules.end ())
qasimj@4638
   446
  {
qasimj@4638
   447
    NS_LOG_DEBUG ("No NAT rule for device " << out->GetId ());
qasimj@4638
   448
    return NF_ACCEPT;
qasimj@4638
   449
  }*/
qasimj@4638
   450
        
qasimj@4638
   451
  NS_LOG_DEBUG ("Current Original Tuple: " << currentOriginalTuple.GetSource () << ", " << currentOriginalTuple.GetDestination ());
qasimj@4638
   452
  NS_LOG_DEBUG ("Current Reply Tuple: " << currentReplyTuple.GetSource () << ", " << currentReplyTuple.GetDestination ());
qasimj@4638
   453
qasimj@4638
   454
  NS_LOG_DEBUG ("ConntrackInfo: " << (uint16_t)m_unconfirmed[currentOriginalTuple].GetInfo () );
qasimj@4638
   455
qasimj@4638
   456
  /* TODO: Why are you checking m_hash here when the info is in
qasimj@4638
   457
   * m_unconfirmed. This could be a problem because NAT is sandwiched
qasimj@4638
   458
   * between conntrack hook callbacks 
qasimj@4638
   459
   */
qasimj@4638
   460
  switch (m_unconfirmed[currentOriginalTuple].GetInfo ())
qasimj@4638
   461
  {
qasimj@4638
   462
    case IP_CT_RELATED:
qasimj@4638
   463
    case IP_CT_RELATED + IP_CT_IS_REPLY:
qasimj@4638
   464
      /* This should be updated when "expectations" are added */
qasimj@4638
   465
      break;
qasimj@4638
   466
qasimj@4638
   467
    case IP_CT_NEW:
qasimj@4638
   468
qasimj@4638
   469
      if ( hookNumber == NF_INET_POST_ROUTING )
qasimj@4638
   470
      {
qasimj@4638
   471
        NS_LOG_DEBUG ("SRC_NAT: New Connection encountered");
qasimj@4638
   472
qasimj@4638
   473
        TupleHashI it;
qasimj@4638
   474
qasimj@4638
   475
qasimj@4638
   476
        if ( (it = m_hash.find (currentOriginalTuple)) != m_hash.end ())
qasimj@4638
   477
        {
qasimj@4638
   478
          if ( !((it->second).GetStatus () & IPS_SRC_NAT_DONE) )
qasimj@4638
   479
          {
qasimj@4638
   480
            /* Get a unique tuple and create a mapping */
qasimj@4638
   481
qasimj@4638
   482
            NS_LOG_DEBUG ("Doing rule lookup at device " << out->GetIfIndex ());
qasimj@4638
   483
            std::vector<NatRule>::iterator it = 
qasimj@4638
   484
              FindNatRule ( Ipv4Address (currentOriginalTuple.GetSource ()), out );
qasimj@4638
   485
qasimj@4638
   486
            if ( it == m_natRules.end () )
qasimj@4638
   487
            {
qasimj@4638
   488
              NS_LOG_DEBUG ("No rule matched!");
qasimj@4638
   489
              return NF_ACCEPT;
qasimj@4638
   490
            }
qasimj@4638
   491
                                    
qasimj@4638
   492
            NS_LOG_DEBUG ("Creating a NAT mapping");
qasimj@4638
   493
qasimj@4638
   494
            /* Create a NULL mapping, which does not contain port numbers */
qasimj@4638
   495
            NetfilterConntrackTuple mapping = 
qasimj@4638
   496
              NetfilterConntrackTuple (it->GetMangledSource (), nextAvailablePort,
qasimj@4638
   497
                                         currentOriginalTuple.GetDestination (), 9);
qasimj@4638
   498
            mapping.SetDirection (IP_CT_DIR_ORIGINAL);
qasimj@4638
   499
            nextAvailablePort++;
qasimj@4638
   500
qasimj@4638
   501
            NS_LOG_DEBUG ("Creating a NAT mapping for the tuple " << currentOriginalTuple 
qasimj@4638
   502
                          << ": " << mapping );
qasimj@4638
   503
            m_natMappings[currentOriginalTuple] = mapping;
qasimj@4638
   504
            m_natReplyLookup[mapping] = currentOriginalTuple;
qasimj@4638
   505
          }
qasimj@4638
   506
qasimj@4638
   507
  
qasimj@4638
   508
          NS_LOG_DEBUG (":: Translating addresses and fixing IP checksum ::");
qasimj@4638
   509
          NetfilterNatPacket (hookNumber, p);
qasimj@4638
   510
        }
qasimj@4638
   511
        else
qasimj@4638
   512
          NS_LOG_DEBUG ("BUG: currentTuple non-existent in hash!");
qasimj@4638
   513
      }
qasimj@4638
   514
qasimj@4638
   515
      break;
qasimj@4638
   516
qasimj@4638
   517
    default:
qasimj@4638
   518
      NS_LOG_DEBUG ("SRC_NAT: Connection is established!");
qasimj@4638
   519
      NS_LOG_DEBUG (":: Translating addresses and fixing IP checksum ::");
qasimj@4638
   520
      NetfilterNatPacket (hookNumber, p);
qasimj@4638
   521
  
qasimj@4638
   522
  }
qasimj@4638
   523
qasimj@4638
   524
qasimj@4638
   525
  return NF_ACCEPT;
qasimj@4638
   526
}
qasimj@4638
   527
    
qasimj@4634
   528
bool 
qasimj@4634
   529
Ipv4Netfilter::InvertTuple (NetfilterConntrackTuple& inverse, NetfilterConntrackTuple& orig,
qasimj@4634
   530
                    Ptr<NetfilterConntrackL3Protocol> l3Protocol,
qasimj@4634
   531
                    Ptr<NetfilterConntrackL4Protocol> l4Protocol)
qasimj@4634
   532
{
qasimj@4636
   533
  inverse.SetProtocol (orig.GetProtocol ());
qasimj@4634
   534
qasimj@4636
   535
  if (!l3Protocol->InvertTuple (inverse, orig))
qasimj@4634
   536
    return false;
qasimj@4634
   537
qasimj@4636
   538
  inverse.SetDirection (orig.GetDirection () == IP_CT_DIR_ORIGINAL ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL);
qasimj@4634
   539
  
qasimj@4636
   540
  return l4Protocol->InvertTuple (inverse, orig);
qasimj@4634
   541
qasimj@4634
   542
}
qasimj@4638
   543
    
qasimj@4638
   544
TupleHash&
qasimj@4638
   545
Ipv4Netfilter::GetHash ()
qasimj@4638
   546
{
qasimj@4638
   547
  return m_hash;
qasimj@4638
   548
}
qasimj@4638
   549
    
qasimj@4638
   550
void 
qasimj@4638
   551
Ipv4Netfilter::AddNatRule (NatRule natRule)
qasimj@4638
   552
{
qasimj@4638
   553
  m_natRules.push_back (natRule);
qasimj@4638
   554
}
qasimj@4634
   555
qasimj@4638
   556
std::vector<NatRule>::iterator
qasimj@4638
   557
Ipv4Netfilter::FindNatRule (NatRule natRule)
qasimj@4635
   558
{
qasimj@4638
   559
  std::vector<NatRule>::iterator it = m_natRules.begin ();
qasimj@4635
   560
qasimj@4638
   561
  for ( ; it != m_natRules.end ();  it++)
qasimj@4635
   562
  {
qasimj@4638
   563
    if ( *it == natRule )
qasimj@4638
   564
      return it;
qasimj@4635
   565
  }
qasimj@4635
   566
qasimj@4638
   567
  return m_natRules.end ();
qasimj@4638
   568
}
qasimj@4635
   569
qasimj@4638
   570
std::vector<NatRule>::iterator
qasimj@4638
   571
Ipv4Netfilter::FindNatRule (Ipv4Address orig, Ptr<NetDevice> out)
qasimj@4638
   572
{
qasimj@4638
   573
  std::vector<NatRule>::iterator it = m_natRules.begin ();
qasimj@4635
   574
qasimj@4638
   575
  NS_LOG_DEBUG ("Number of rules: " << m_natRules.size () );
qasimj@4638
   576
  NS_LOG_DEBUG ("Orig: " << orig );
qasimj@4635
   577
qasimj@4638
   578
  for ( ; it != m_natRules.end ();  it++)
qasimj@4638
   579
  {
qasimj@4638
   580
    NS_LOG_DEBUG ("Rule source: " << it->GetOriginalSource () << ", passed in source: " << orig);
qasimj@4638
   581
    NS_LOG_DEBUG ("Rule device: " << it->GetDevice () << ", passed in dev: " << out);
qasimj@4638
   582
    if ( it->GetOriginalSource () == orig && it->GetDevice () == out)
qasimj@4638
   583
    {
qasimj@4638
   584
      NS_LOG_DEBUG ("Rule match found!");
qasimj@4638
   585
      return it;
qasimj@4638
   586
    }
qasimj@4638
   587
  }
qasimj@4635
   588
qasimj@4638
   589
  return m_natRules.end ();
qasimj@4638
   590
}
qasimj@4638
   591
    
qasimj@4638
   592
void 
qasimj@4638
   593
Ipv4Netfilter::EnableNat ()
qasimj@4638
   594
{
qasimj@4638
   595
  m_enableNat = 1;
qasimj@4635
   596
qasimj@4638
   597
  NS_LOG_DEBUG (":: Enabling NAT ::");
qasimj@4638
   598
qasimj@4638
   599
  NetfilterHookCallback doNat = MakeCallback (&Ipv4Netfilter::NetfilterDoNat, this);
qasimj@4638
   600
qasimj@4638
   601
  Ipv4NetfilterHook natCallback1 = Ipv4NetfilterHook (1, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC, doNat); 
qasimj@4638
   602
  Ipv4NetfilterHook natCallback2 = Ipv4NetfilterHook (1, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST, doNat); 
qasimj@4638
   603
  
qasimj@4638
   604
qasimj@4638
   605
  this->RegisterNetfilterHook (natCallback1);
qasimj@4638
   606
  this->RegisterNetfilterHook (natCallback2);
qasimj@4638
   607
}
qasimj@4638
   608
qasimj@4638
   609
uint32_t 
qasimj@4638
   610
Ipv4Netfilter::NetfilterNatPacket (Hooks_t hookNumber, Ptr<Packet> p)
qasimj@4638
   611
{
qasimj@4638
   612
  NS_LOG_FUNCTION ( this << p );
qasimj@4638
   613
  Ipv4Header ipHeader;
qasimj@4638
   614
  uint16_t dstPort; //, srcPort;
qasimj@4638
   615
  Ipv4Address dstAddress, srcAddress;
qasimj@4638
   616
qasimj@4638
   617
  p->RemoveHeader (ipHeader);
qasimj@4638
   618
qasimj@4638
   619
  uint16_t protocol = ipHeader.GetProtocol ();
qasimj@4638
   620
qasimj@4638
   621
  if (hookNumber == NF_INET_POST_ROUTING)
qasimj@4638
   622
  {
qasimj@4638
   623
    NetfilterConntrackTuple mapped = m_natMappings[currentOriginalTuple];
qasimj@4638
   624
qasimj@4638
   625
    ipHeader.SetSource (mapped.GetSource ());
qasimj@4638
   626
qasimj@4638
   627
    if (protocol == IPPROTO_TCP)
qasimj@4638
   628
    {
qasimj@4638
   629
      TcpHeader tcpHeader;
qasimj@4638
   630
qasimj@4638
   631
      p->RemoveHeader (tcpHeader);
qasimj@4638
   632
qasimj@4638
   633
      tcpHeader.SetSourcePort (mapped.GetSourcePort ());
qasimj@4638
   634
qasimj@4638
   635
      p->AddHeader (tcpHeader);
qasimj@4638
   636
qasimj@4638
   637
    }
qasimj@4638
   638
    else
qasimj@4638
   639
    {
qasimj@4638
   640
      UdpHeader udpHeader;
qasimj@4638
   641
qasimj@4638
   642
      p->RemoveHeader (udpHeader);
qasimj@4638
   643
qasimj@4638
   644
      udpHeader.SetSourcePort (mapped.GetSourcePort ());
qasimj@4638
   645
qasimj@4638
   646
      p->AddHeader (udpHeader);
qasimj@4638
   647
    }
qasimj@4638
   648
qasimj@4638
   649
    p->AddHeader (ipHeader);
qasimj@4638
   650
qasimj@4638
   651
    NetfilterConntrackTuple oldOriginalTuple = currentOriginalTuple;
qasimj@4638
   652
qasimj@4638
   653
qasimj@4638
   654
    currentOriginalTuple = NetfilterConntrackTuple (mapped.GetSource(), mapped.GetSourcePort (),
qasimj@4638
   655
                                                    currentOriginalTuple.GetDestination (),
qasimj@4638
   656
                                                    currentOriginalTuple.GetDestinationPort ());
qasimj@4638
   657
qasimj@4638
   658
    currentOriginalTuple.SetDirection (IP_CT_DIR_ORIGINAL);
qasimj@4638
   659
    
qasimj@4638
   660
    currentReplyTuple = NetfilterConntrackTuple (currentOriginalTuple.GetDestination (),
qasimj@4638
   661
                                                  currentOriginalTuple.GetDestinationPort (),
qasimj@4638
   662
                                                  mapped.GetSource (), mapped.GetSourcePort ());
qasimj@4638
   663
    
qasimj@4638
   664
    currentReplyTuple.SetDirection (IP_CT_DIR_REPLY);
qasimj@4638
   665
    
qasimj@4638
   666
    std::cout <<" New Original Tuple: " << currentOriginalTuple << std::endl;
qasimj@4638
   667
    std::cout <<" New Reply Tuple: " << currentReplyTuple << std::endl;
qasimj@4638
   668
qasimj@4638
   669
    m_unconfirmed[currentOriginalTuple] = m_unconfirmed[oldOriginalTuple];
qasimj@4638
   670
qasimj@4638
   671
  }
qasimj@4638
   672
  else if (hookNumber == NF_INET_PRE_ROUTING)
qasimj@4638
   673
  {
qasimj@4638
   674
    NS_LOG_DEBUG ("Mapping back to LAN address");
qasimj@4638
   675
    //NetfilterConntrackTuple mapped = m_natMappings[currentReplyTuple];
qasimj@4638
   676
    NetfilterConntrackTuple temp = currentReplyTuple;
qasimj@4638
   677
    temp.SetDirection (IP_CT_DIR_ORIGINAL);
qasimj@4638
   678
    TranslationMapI transIt = m_natReplyLookup.find (temp);
qasimj@4638
   679
qasimj@4638
   680
    if (transIt == m_natMappings.end ())
qasimj@4638
   681
    {
qasimj@4638
   682
      NS_LOG_DEBUG ("No such mapping found!");
qasimj@4638
   683
      return NF_ACCEPT;
qasimj@4638
   684
    }
qasimj@4638
   685
qasimj@4638
   686
    dstPort = (transIt->second).GetSourcePort ();
qasimj@4638
   687
    dstAddress = (transIt->second).GetSource ();
qasimj@4638
   688
  
qasimj@4638
   689
    currentOriginalTuple = NetfilterConntrackTuple ((transIt->second).GetSource (), (transIt->second).GetSourcePort (), dstAddress, dstPort);
qasimj@4638
   690
    currentReplyTuple = NetfilterConntrackTuple (dstAddress, dstPort, (transIt->second).GetSource (), (transIt->second).GetSourcePort ());
qasimj@4638
   691
qasimj@4638
   692
    NS_LOG_DEBUG ("Setting Destination IP address to : " << dstAddress);
qasimj@4638
   693
    ipHeader.SetDestination (dstAddress);
qasimj@4638
   694
qasimj@4638
   695
    if (protocol == IPPROTO_TCP)
qasimj@4638
   696
    {
qasimj@4638
   697
      TcpHeader tcpHeader;
qasimj@4638
   698
qasimj@4638
   699
      p->RemoveHeader (tcpHeader);
qasimj@4638
   700
qasimj@4638
   701
      tcpHeader.SetDestinationPort (dstPort);
qasimj@4638
   702
qasimj@4638
   703
      p->AddHeader (tcpHeader);
qasimj@4638
   704
qasimj@4638
   705
    }
qasimj@4638
   706
    else
qasimj@4638
   707
    {
qasimj@4638
   708
      UdpHeader udpHeader;
qasimj@4638
   709
qasimj@4638
   710
      p->RemoveHeader (udpHeader);
qasimj@4638
   711
qasimj@4638
   712
      udpHeader.SetDestinationPort (dstPort);
qasimj@4638
   713
      NS_LOG_DEBUG ("Setting destination port to: " << dstPort);
qasimj@4638
   714
qasimj@4638
   715
      p->AddHeader (udpHeader);
qasimj@4638
   716
    }
qasimj@4638
   717
qasimj@4638
   718
    p->AddHeader (ipHeader);
qasimj@4638
   719
  }
qasimj@4638
   720
qasimj@4638
   721
qasimj@4638
   722
qasimj@4638
   723
  return NF_ACCEPT;
qasimj@4638
   724
qasimj@4638
   725
}
qasimj@4635
   726
qasimj@4634
   727
} // Namespace ns3