How to use variables in windows commands to execute from ruby - ruby

I have to execute a ping command from ruby script.
If I directly execute ping 8.8.8.8 it works.
How can i use a variable in place of IP?
I tried
dst_ip="8.8.8.8"
ping_string = "ping "+dst_ip
puts ping_string
ping = `ping_string`
but it dint work.

Do as below :
C:\>irb
irb(main):001:0> ip = '66.249.64.0'
=> "66.249.64.0"
irb(main):002:0> `ping #{ip}`
=> "\nPinging 66.249.64.0 with 32 bytes of data:\nRequest timed out.\nRequest ti
med out.\nRequest timed out.\nRequest timed out.\n\nPing statistics for 66.249.6
4.0:\n Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),\n"
irb(main):003:0>
You don't need to do string operation like this - ping_string = "ping "+dst_ip.

Because interpolation works in `` operator, this should work:
ping = `#{ping_string}`

Related

send email via telnet ruby script

I'm new with ruby and need to send an email via telnet using a relay host with no authentication. I can do it with a linux shell but I need to put it in a script so I can "simplify" its use, I know it's not the best way but I can't find other since the server where i'm working on it's severely restricted and limited.
require 'net/telnet.rb'
mail = Net::Telnet::new(
"Host" => "domain.ip", # default: "localhost"
"Port" => 25, # default: 23
"Output_log" => "output_log", # default: nil (no output)
"Dump_log" => "dump_log", # default: nil (no output)
"Prompt" => /[$%#>] \z/n, # default: /[$%#>] \z/n
"Telnetmode" => true, # default: true
"Timeout" => 10, # default: 10
"Waittime" => 0, # default: 0
)
mail.cmd('helo MYDOMAIN'){ |c| print c }
mail.cmd('mail from: test#domain.com')
mail.cmd('rcpt to: test2#domain.com')
mail.cmd('data')
mail.cmd("subject: test cmd \n\n mensaje de prueba\n\n")
mail.cmd(".\n")
mail.close
I found the net/telnet.rb ruby class and this is my try... after mail.cmd('helo MYDOMAIN') I can't keep writing other commands, what I get is:
220 mail.server.com ESMTP
250 mail.server.com
After this I'm suposed to write mail from, etc. to create the mail. But I can't in the ruby script. I have try using:
mail.puts('mail from: test...')
mail.write('mail from: test...')
mail.print('mail from: test...')
mail.cmd('mail from: test...')
As written in documentation
Also I don't get the telnetmode(true|false) command maybe you could explain it to me please.
-- Edit --
Shell code trying to emulate:
telnet domain.ip 25
#=> Trying domain.ip...
#=> Connected to domain.ip.
#=> Escape character is '^]'.
#=> 220 mail.server.com ESMTP
helo MYDOMAIN
#=>250 mail.server.com
mail from:test#mydomain.com
#=> 250 2.1.0 Ok
rcpt to:test2#mydomain.com
#=> 250 2.1.0 Ok
data
#=> 354 End data with <CR><LF>.<CR><LF>
subject: test mail
test mail body
.
#=> 250 2.0.0 =k: queued as B6F08480D12
quit
#=> 221 2.0.0 Bye
#=> Connection closed by foreign host.
The telnet protocol is really, really rudimentary which is why the telnet command is useful for testing TCP/IP based services such as SMTP or HTTP. It does not mean those services actually use the telnet protocol, as they don't. They're conveniently plain-text in nature which means it's practical to use telnet for simple tests.
You should not be using the Telnet module for anything other than connecting to telnet services, though given it's 2017 it's unlikely you'll find any of those around.
You should be using something like Socket to connect. This can create a bare TCP/IP connection with full control over sending. As this is a wrapper around a regular POSIX filehandle you can use all the IO methods on it for reading, writing, and other control functions, like a proper socket shutdown.
Writing an SMTP adapter is not as easy as it seems, there's a lot of tricky things to tackle with regard to IO. You'll need to use IO.select to properly test for new data, plus that the socket is clear to write your email.
Here's a new stub:
require 'socket'
mail = TCPSocket.new("smtp.example.com", 25)
mail.write("HELO example.com\r\n")
Another note is that when you call require you should never specify the file extension. It's always handled for you.
Thanks to the help of the user ddubs how suggest the net\smtp gem (One that I didn't know) I was able to create a simple mail sender and using the mailfactory gem
Is it a strict requirement that you use telnet? Using ruby-doc.org/stdlib-2.0.0/libdoc/net/smtp/rdoc/Net/SMTP.html will turn your "difficult to maintain" script into something that is much easier to maintain. Even for someone who is completely new to Ruby. – ddubs
Here is the code sample
require 'net/smtp'
require 'mailfactory'
mail_body_HTML = '<h1> mail title</h1> your text in <b>HTML</b>'
mail_body_PLAIN = 'this is plain text'
mail_subject = 'test email'
mail_from = 'noreply#mydomain.com'
mail_to = 'user#otherdomain.com'
# mail_filePath = ''
mail = MailFactory.new()
mail.to = mail_to
mail.from = mail_from
mail.subject = mail_subject
mail.html = mail_body_HTML
# mail.text = mail_body_PLAIN
# mail.attach(mail_filePath)
relay_ip = x.x.x.x
Net::SMTP.start(relay_ip,25) do |smtp|
smtp.send_message(mail.to_s, mail_from, mail_to)
end

Sending packets between Amazon EC2 instances using their MAC-addresses

Using this small ruby script + packetfu, I try to retransmit a broadcast packet to several hosts:
#!/usr/bin/ruby
require 'rubygems'
require 'packetfu'
dev = ARGV[0]
mac=`ip link show #{dev} | awk '/ether/ {print $2}'`
ARGV.shift
dests = ARGV
cap = PacketFu::Capture.new(
:timeout => 4000,
:iface => dev, :start => true,
:filter => "ether src #{mac} and ether[0] & 1 = 1")
loop do
cap.stream.each do |pkt|
frame = PacketFu::IPPacket.parse(pkt)
i = 0
dests.each do |dest|
frame.eth_daddr = dest
frame.ip_header.ip_id = frame.ip_header.ip_id + i
frame.ip_header.ip_sum = frame.ip_header.ip_calc_sum()
frame.to_w(dev)
i = i + 1
end
end
end
Using tcpdump, I see that they are retransmitted (sent several
times).
$ echo "foo" | netcat -ub 192.168.15.255 54321
On host1 (source host), tcpdump shows me at the moment:
12:19:30.602374 0a:f4:8d:75:e5:af > ff:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 46: 192.168.15.17.36339 > 192.168.15.255.54321: UDP, length 4
12:19:30.605856 0a:f4:8d:75:e5:af > 0a:a2:5f:f1:de:e4, ethertype IPv4 (0x0800), length 46: 192.168.15.17.36339 > 192.168.15.255.54321: UDP, length 4
12:19:30.608896 0a:f4:8d:75:e5:af > 0a:25:ef:2c:24:e3, ethertype IPv4 (0x0800), length 46: 192.168.15.17.36339 > 192.168.15.255.54321: UDP, length 4
On host2 (destination host, mac address 0a:a2:5f:f1:de:e4), tcpdump shows nothing.
Security policy allows all traffic in the VPC.
Have you any ideas?
I'm sure that I miss some small thing.
(I thank Kenta Yasukawa for the answer):
Have you turned off the source/destination check for your instances? By
default, EC2 instances drop an incoming packet whose destination address does
not match the receiver IP address. You can disable it by right-clicking on an
instance in Management console and select "Change Source / Destination check",
and click disable. 
To disable the ckeck using EC API Tools:
$ ec2-modify-network-interface-attribute --source-dest-check False eni-8c8c9bca

Connect to a Cisco Switch with Ruby

[EDITED]
I'm trying to connect to a Cisco Switch and execute a few commands. My first try was with Net::SSH and I couldn't establish a channel. Second try was with plink and shell commands. Now I'm trying with Net::Telnet. This time at least I can connect to the switch.
The problem now is that it's executing only the first telnet.cmd(). To execute anything else I need to append some command at the end of the first cmd() (separated by \n). Here is my code:
telnet = Net::Telnet::new("Host" => CISCO,
"Timeout" => 10)
telnet.cmd("#{USER}\n#{PASS}") { |c| print c } #works fine
telnet.cmd("help") { |c| print c } #nothing happens
The second cmd() is not working. How do I fix this?

IPv6 with perl on windows not working

cross-post http://perlmonks.org/index.pl?node_id=984750
(Possible duplicate of perl windows IPv6 )
I tried following sample example from : https://metacpan.org/module/IO::Socket::IP
use IO::Socket::IP -register;
my $sock = IO::Socket->new(
Domain => PF_INET6,
LocalHost => "::1",
Listen => 1,
) or die "Cannot create socket - $#\n";
print "Created a socket of type " . ref($sock) . "\n";
It is giving output as :
Cannot create socket - no address associated with nodename
I am using ActiveState perl 5.14.2 and have built IO::Socket::IP module on it.
Following is the ping result:
c:\>ping ::1
Pinging ::1 with 32 bytes of data:
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Ping statistics for ::1:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms
If I use the IPv4 style loopback address 127.0.0.1, the above code works well.
I am wondering what I am missing.
Update:
I just cleaned the perl setup and path, and freshly installed perl 5.14.2 from
http://www.activestate.com/activeperl/downloads
and then I tried following simple code:
use strict;
use warnings;
use Socket qw(getaddrinfo SOCK_STREAM AI_PASSIVE );
my ( $err, #res ) = getaddrinfo( "::", 8086, {
socktype => SOCK_STREAM,
flags => AI_PASSIVE,
} );
die $err if $err;
it ended with following error:
no address associated with nodename at c:\IPv6.pl line 10.
But with 127.0.0.1 it returns proper value.
I am using windows 2008 R2 box, a same run on my another windows box also fails.
I just tried to trace this call in Socket.pm, and found that a "fake_getaddrinfo" is getting called instead of the real getaddrinfo. It seems the XSLoader was either not able to find/load getaddrinfo from Socket.dll or Socket.dll didn't at all have the getaddrinfo.
What could be the reason?
A similar code below using Socket6 works properly on the same setup:
use Socket;
use Socket6;
#res = getaddrinfo('::', 8086, AF_UNSPEC, SOCK_STREAM);
while(scalar(#res)>=5){
($family, $socktype, $proto, $saddr, $canonname, #res) = #res;
($host, $port) = getnameinfo($saddr, NI_NUMERICHOST | NI_NUMERICSERV);
print ("\nhost= $host port = $port");
socket(Socket_Handle, $family, $socktype, $proto) || next;
bind(Socket_Handle,$saddr ) || die "bind: $!";
listen(Socket_Handle, 5) || die "listen: $!";
($host, $port) = getnameinfo($saddr, NI_NUMERICHOST | NI_NUMERICSERV);
print ("\nReady for connections \nhost= $host port = $port");
$paddr = accept(Client, Socket_Handle);
}
So I can't even blame the setup or the system dlls. Is there an issue with perl's built-in IPv6 support for windows' activestate build?
As stated by vinsworldcom on perlmonks.org, to make use of IPv6 sockets you do need to have the Socket6 module installed. As soon as you'd install this via cpan, the code snippet will work fine.

How do i provide password for su command while using net/telnet in ruby

I am using Net/TELNET to connect to remote host trying to run su command in order to get root privilage. This is how I am doing it
require 'net/telnet'
localhost = Net::Telnet::new("Host" => "192.147.217.27",
"Timeout" => 50,
"Prompt" => /[$%#>] \z/n)
localhost.login("dvsdkrp", "dvsdkvrp") { |c| print c }
localhost.cmd("cd /home/dvsdkrp/workdir/smruti") { |c| print c }
localhost.cmd("su") { |c| print c }
localhost.puts("passwd"){ |c| print c }
I am able to login and able to do smruti directory but when I use su command it takes me to the password prompt but then I get this error, even after I changed the Timeout parameter to 150
Password: C:/Ruby/lib/ruby/1.8/net/telnet.rb:552:in `waitfor': timed out
while waiting for more data (Timeout::Error)
from C:/Ruby/lib/ruby/1.8/net/telnet.rb:679:in `cmd'
from tel.rb:7
What should I do?
The prompt you specify when you create the Telnet object is the one its going to look for before it runs its next command. If you are timing out then I think its because its not seeing the prompt it expects. If you use the Match option when you send the 'su' command, you can specify a prompt specifically for this command.
su_prompt = "Password: "
localhost.cmd("String" => "su", "Match" => /#{su_prompt}/) { |c| print c }
localhost.cmd("passwd")
This new prompt is only used for the current command. The originally specified prompt is still in affect for the rest of the session.

Resources