Module: Dcmgr::NodeModules::Nat

Includes:
Helpers::NicHelper, Logger
Included in:
ServiceNetfilter
Defined in:
lib/dcmgr/node_modules/service_netfilter.rb

Instance Method Summary collapse

Methods included from Logger

create, default_logdev, included

Methods included from Helpers::NicHelper

#find_nic, #nic_state, #valid_nic?

Instance Method Details

#arp_respond(ip) ⇒ Object

Returns ebtables command to respond to ARP requests for the address ip.



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/dcmgr/node_modules/service_netfilter.rb', line 125

def arp_respond(ip)
  ip = IPAddress(ip) if ip.is_a?(String)    
  raise "Invalid IP address: #{ip}" unless ip.is_a?(IPAddress)
  
  #Get the mac address for our physical nic
  nic = find_nic(@node.manifest.config.hv_ifindex)
  #TODO: Find a prettier way to get the mac address
  mac_addr = %x{ifconfig | grep '#{nic}' | tr -s ' ' | cut -d ' ' -f5}.chomp
  
  logger.debug "Replying ARP requests for address: #{ip.address}"
  
  "ebtables -t nat -A PREROUTING -p arp --arp-ip-dst #{ip.address} --arp-opcode REQUEST -j arpreply --arpreply-mac #{mac_addr}"
end

#is_natted_ip?(ip) ⇒ Boolean

Returns:

  • (Boolean)


139
140
141
142
143
144
145
# File 'lib/dcmgr/node_modules/service_netfilter.rb', line 139

def is_natted_ip?(ip)
  ip = IPAddress(ip) if ip.is_a?(String)
  #TODO: put in a proper argumenterror here
  raise "Invalid IP address: #{ip}" unless ip.is_a?(IPAddress)
  
  rpc.request('hva-collector', 'is_natted_ip?', ip.address) 
end

#nat_exceptions(inst_map) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/dcmgr/node_modules/service_netfilter.rb', line 106

def nat_exceptions(inst_map)
  inside_exception_ips = rpc.request('hva-collector','get_group_instance_ipv4s',inst_map[:uuid]).map {|ip| IPAddress(ip)}
  outside_exception_ips = rpc.request('hva-collector','get_group_instance_ipv4s',inst_map[:uuid],:outside).map {|ip| IPAddress(ip)}
  
  cmds = []
  inst_map[:instance_nics].each { |nic|
    internal_ip = IPAddress(rpc.request('hva-collector', 'get_iplease_for_nic', nic[:uuid]))
    inside_exception_ips.each { |ex_ip|
      cmds << "iptables -t nat -A POSTROUTING -s #{internal_ip.address} -d #{ex_ip.address}/#{ex_ip.prefix} -j ACCEPT"
    }
    outside_exception_ips.each { |ex_ip|
      cmds << "iptables -t nat -A PREROUTING -s #{internal_ip.address} -d #{ex_ip.address}/#{ex_ip.prefix} -j ACCEPT"
    }
  }
  
  cmds
end

#nat_instance(inst_map) ⇒ Object

Takes an instance and nats it. If the instance is in a network that has a nat_network mapped to it, it will receive a second ip lease for that network. This lease will then be natted to the ip the instance already had in its own network. For example if 192.168.0.0/24 is natted to 172.16.0.0/16, then an instance with ip 192.168.0.10 might be natted to ip 172.16.46.23.

Raises:

  • (ArgumentError)


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
# File 'lib/dcmgr/node_modules/service_netfilter.rb', line 57

def nat_instance(inst_map)
  nat_cmd = []
  raise ArgumentError unless inst_map.is_a?(Hash)
  
  inst_map[:instance_nics].each {
    |nic|       
    nat_ips = rpc.request('hva-collector', 'get_nat_leases', nic[:uuid]).map {|ip| IPAddress(ip)}
    
    #Get the internal ip for this nic
    internal_ip = IPAddress rpc.request('hva-collector', 'get_iplease_for_nic', nic[:uuid])
    inside_exception_ips = rpc.request('hva-collector','get_group_instance_ipv4s',inst_map[:uuid]).map {|ip| IPAddress(ip)}
    outside_exception_ips = rpc.request('hva-collector','get_group_instance_ipv4s',inst_map[:uuid],:outside).map {|ip| IPAddress(ip)}
    
    #output the commands to nat this nic and answer arp requests for its outside ip
    friend_ipset  = inst_map[:uuid] + "_friend_ips"
    nat_ips.each { |external_ip|
      if @node.manifest.config.use_ipset
        
        nat_cmd << "ipset -N #{friend_ipset} iphash"
        
        inside_exception_ips.each { |ex_ip|
          nat_cmd << "ipset -A #{friend_ipset} #{ex_ip.address}"
        }
        
        # The good rules that use ipset
        postrouting_command = "iptables -t nat -A POSTROUTING -s #{internal_ip.address} -m set ! --match-set #{friend_ipset} dst"
        prerouting_command = "iptables -t nat -A PREROUTING -d #{external_ip.address} -m set ! --match-set #{friend_ipset} src"
      else
        # The ugly rules to use in case ipset is not installed
        postrouting_command = "iptables -t nat -A POSTROUTING -s #{internal_ip.address}"
        prerouting_command = "iptables -t nat -A PREROUTING -d #{external_ip.address}"
      end
      
      # Build the final nat rules and log any packets that traverse them
      nat_cmd << postrouting_command  + " -j LOG --log-prefix 'Snat '"
      nat_cmd << postrouting_command  + " -j SNAT --to #{external_ip.address}"
      
      nat_cmd << prerouting_command + " -j LOG --log-prefix 'Dnat '"
      nat_cmd << prerouting_command + " -j DNAT --to #{internal_ip.address}"
      
      logger.debug "Natting #{internal_ip.address} to #{external_ip.address}"
      
      nat_cmd << arp_respond(external_ip)
    }
  }
  
  nat_cmd
end