#!/usr/bin/perl # # This code is for use in conjunction with adding NAT's to supernat # # Example usage: # # my $addr = "10.47.3.24"; # # if (Pos::Webtop::Supernat::supernatIsIpInsideCompanyIntranet(db => $db, companyId => 16, actualAddress => $addr)) { # $addr = Pos::Webtop::Supernat::supernatGetInternalAddress( # supernatIp => '127.0.0.1', # supernatPort => 7654, # companyId => 16, # requestType => 'WEB_SESSION', # requestTypeId => '1', # actualAddress => '192.168.0.1'); # } # # This will use the supernat server running on 127.0.0.1:7654. # It will request that a NAT for the actual address of '192.168.0.1' be created using companyId 16 and the NAT # that is created should be correlated with Id 1 of WEB_SESSION. # # On success, a dotted quad ip address is returned that is the address that should be used internally, otherwise undef is returned. # package Pos::Webtop::Supernat; use strict; use Socket; use IO::Socket; use IO::Socket::INET; use IO::Select; sub supernatIsIpInsideCompanyIntranet { my ($db, $companyId, $actualAddress) = @{{@_}}{qw/db companyId actualAddress/}; my $ret = 0; my @subnets = $db->query(sql => " select RAWIP32_TO_DOTTED_QUAD_NO(subnet) as SUBNET, RAWIP32_TO_DOTTED_QUAD_NO(netmask) as NETMASK from customer_subnets where customer_id = '" . $db->escape(dirty => $companyId) . "' union select RAWIP32_TO_DOTTED_QUAD( coalesce(virtual_destination, destination_network)) as SUBNET, RAWIP32_TO_DOTTED_QUAD(destination_netmask) as NETMASK from customer_partner_resources where customer_id = '" . $db->escape(dirty => $companyId) . "' "); my $actualLong = unpack("L", inet_aton($actualAddress)); foreach my $subneta (@subnets) { my ($subnet, $netmask) = @{ $subneta }; my $subnetLong = unpack("L", inet_aton($subnet)); my $netmaskLong = unpack("L", inet_aton($netmask)); if (($actualLong & $netmaskLong) == ($subnetLong & $netmaskLong)) { $ret = 1; last; } } return $ret; } sub supernatGetInternalAddress { my ($supernatIp, $supernatPort, $companyId, $requestType, $requestTypeId, $actualAddress, $requestor) = @{{@_}}{qw/supernatIp supernatPort companyId requestType requestTypeId actualAddress requestor/}; my $connection = IO::Socket::INET->new( PeerAddr => $supernatIp, PeerPort => $supernatPort, Proto => 'tcp') or return undef; $|=1; my $networkByteAddr = unpack("L", inet_aton($actualAddress)); my $cmd = "$companyId;$requestType;$requestTypeId;$networkByteAddr"; # If a requestor is specified, we pass it along. THis allows us to setup supernats on behalf of another. if (defined($requestor)) { my $networkReq = unpack("L", inet_aton($requestor)); $cmd .= ";$networkReq"; } $cmd .= "\n"; syswrite($connection, $cmd); $connection->flush(); my $s = IO::Select->new($connection); my @ready = $s->can_read(15); if (not defined($ready[0])) { return undef; } # we read only first line, other lines have additional information we do not need my $data = <$connection>; chomp $data; my $packed = pack("L", $data); return inet_ntoa($packed); } # db passed here must be same db that supernatd on supernat boxes # is working with. This is typically the webtop db writer. # WARNING using this will cause a commit on the db. sub supernatReleaseDynamicBackendNat { my ($db,$companyId,$actualAddress) = @{{@_}}{qw/db companyId actualAddress/}; my $ret = 0; my @sninfo = $db->query( sql=> " select supernat_nat_id, \"references\" from supernat_ns_nats where customer_id = '" . $db->escape( dirty=> $companyId ) . "' and rawip32_to_dotted_quad_no(customer_internal_addr) = '" . $db->escape( dirty=> $actualAddress ) . "' for update "); if ( not @sninfo ) { warn "Could not release backend dynamic nat because requested actualAddress was not found in nat database!\n"; return undef; } my ($supernatNatId,$backendDynamicReferences) = @{ $sninfo[0] }; if ( (defined $supernatNatId) and ($backendDynamicReferences > 0) ) { $backendDynamicReferences--; $db->do( sql=> " update supernat_ns_nats set \"references\" = $backendDynamicReferences where supernat_nat_id = $supernatNatId "); } $db->commit(); } 1;