Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for SOCKS. #19

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions doc/base.pod
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,26 @@ Specify the destination address of the proxied connection. (Arg-Required, From-P

Specify the destination port of the proxied connection. (Arg-Required, From-Prompt)

=back

=head1 SOCKS PROXY OPTIONS

Swaks is able to use a SOCKS proxy to connect SMTP via TCP. It relies on the IO::Socket::Socks module's behavior.

=over 4

=item --socks-host [VALUE]

If this option is used, its argument is used as the host which is the socks proxy.

=item --socks-port [VALUE]

Specify the port the socks proxy is listening for connections to. Defaults to 1080.

=item --socks-version [ 4 | 5 ]

Specify the socks protocol version to speak. Defaults to 5.

=back

=head1 DATA OPTIONS
Expand Down
95 changes: 67 additions & 28 deletions swaks
Original file line number Diff line number Diff line change
Expand Up @@ -116,34 +116,47 @@ sub open_link {
push(@extra_options, "LocalAddr", $G::link{lint}) if ($G::link{lint});
push(@extra_options, "LocalPort", $G::link{lport}) if ($G::link{lport});

# INET6 also supports v4, so use it for everything if it's available. That
# allows the module to handle A vs AAAA records on domain lookups where the
# user hasn't set a specific ip version to be used. If INET6 isn't available
# and it's a domain that only has AAAA records, INET will just handle it like
# a bogus record and we just won't be able to connect
if (avail("ipv6")) {
if ($G::link{force_ipv6}) {
push(@extra_options, "Domain", Socket::AF_INET6() );
} elsif ($G::link{force_ipv4}) {
push(@extra_options, "Domain", Socket::AF_INET() );
}

$G::link{sock} = IO::Socket::INET6->new(
PeerAddr => $G::link{server},
PeerPort => $G::link{port},
Proto => 'tcp',
Timeout => $G::link{timeout},
@extra_options
);
} else {
$G::link{sock} = IO::Socket::INET->new(
PeerAddr => $G::link{server},
PeerPort => $G::link{port},
Proto => 'tcp',
Timeout => $G::link{timeout},
@extra_options
);
}
if (avail('socks') && $G::socks{use}) {
ptrans(11, 'Connecting via SOCKS ' . $G::socks{host} . ':' . $G::socks{port});
$G::link{sock} = IO::Socket::Socks->new(
ProxyAddr => $G::socks{host},
ProxyPort => $G::socks{port},
SocksResolve => $G::socks{version},
ConnectAddr => $G::link{server},
ConnectPort => $G::link{port},
Timeout => $G::link{timeout},
@extra_options
);
} else {
# INET6 also supports v4, so use it for everything if it's available. That
# allows the module to handle A vs AAAA records on domain lookups where the
# user hasn't set a specific ip version to be used. If INET6 isn't available
# and it's a domain that only has AAAA records, INET will just handle it like
# a bogus record and we just won't be able to connect
if (avail("ipv6")) {
if ($G::link{force_ipv6}) {
push(@extra_options, "Domain", Socket::AF_INET6() );
} elsif ($G::link{force_ipv4}) {
push(@extra_options, "Domain", Socket::AF_INET() );
}

$G::link{sock} = IO::Socket::INET6->new(
PeerAddr => $G::link{server},
PeerPort => $G::link{port},
Proto => 'tcp',
Timeout => $G::link{timeout},
@extra_options
);
} else {
$G::link{sock} = IO::Socket::INET->new(
PeerAddr => $G::link{server},
PeerPort => $G::link{port},
Proto => 'tcp',
Timeout => $G::link{timeout},
@extra_options
);
}
}

if ($@) {
ptrans(12, "Error connecting" . ($G::link{lint} ? " $G::link{lint}" : '') .
Expand Down Expand Up @@ -1753,6 +1766,7 @@ sub load_dependencies {
tls => { name => "TLS", req => ['Net::SSLeay'] },
pipe => { name => "Pipe Transport", req => ['IPC::Open2'] },
socket => { name => "Socket Transport", req => ['IO::Socket'] },
socks => { name => "SOCKS Transport", req => ['IO::Socket::Socks'] },
ipv6 => { name => "IPv6", req => ['IO::Socket::INET6'] },
date_manip => { name => "Date Manipulation", req => ['POSIX'] },
hostname => { name => "Local Hostname Detection", req => ['Sys::Hostname'] },
Expand Down Expand Up @@ -2245,6 +2259,23 @@ sub get_option_struct {
prompt => 'PROXY dest_port: ', match => '^.+$',
okey => 'proxy_dest_port', type => 'scalar', },

# SOCKS Proxy
# socks proxy host
{ opts => ['socks-host'], suffix => ':s',
cfgs => OP_ARG_REQ|OP_FROM_PROMPT,
prompt => 'SOCKS host: ', match => '^.+$',
okey => 'socks_host', type => 'scalar', },
# socks proxy port
{ opts => ['socks-port'], suffix => ':s',
cfgs => OP_ARG_REQ|OP_FROM_PROMPT,
prompt => 'SOCKS port: ', match => '^[0-9]+$',
okey => 'socks_port', type => 'scalar', },
# socks proxy version
{ opts => ['socks-version'], suffix => ':s',
cfgs => OP_ARG_REQ|OP_FROM_PROMPT,
prompt => 'SOCKS version: ', match => '^[4|5]$',
okey => 'socks_version', type => 'scalar', },

# this option serve no purpose other than testing the deprecation system
{ opts => ['trigger-deprecation'], suffix => ':s',
cfgs => OP_ARG_REQ|OP_DEPRECATED,
Expand Down Expand Up @@ -3517,6 +3548,14 @@ sub process_args {
}
}

$G::socks{use} = 0;
if (get_arg('socks_host', $o)) {
$G::socks{use} = 1;
$G::socks{host} = get_arg('socks_host', $o);
$G::socks{port} = defined(get_arg('socks_port', $o)) ? get_arg('socks_port', $o) : 1080;
$G::socks{version} = defined(get_arg('socks_version', $o)) ? get_arg('socks_version', $o) : 5;
}

# Handle AUTH options
# auth_optional => 0 - no. Auth must be advertised and must succeed, else error.
# 1 - yes. Success if not advertised, advertised and fails _or_ succeeds.
Expand Down