The camel book suggests that V-strings can be used for representing IPv4 addresses:
$ipaddr = 204.148.40.9; # the IPv4 address of oreilly.com
But perldata on the topic of Version Strings states:
Note that using the v-strings for IPv4
addresses is not portable unless you
also use the inet_aton()/inet_ntoa()
routines of the Socket package.
I have two questions:
1) Why is using the v-strings not portable?
2) What's the "standard" way to convert an ip-address from dotted notation to integer? Seems that unpack "N", <v-string> can cause problems sometimes.
The "standard" way to get the encoded form is inet_aton, which handles dotted IP addresses as well as hostnames -- but what do you need it for? More often than not the best idea is just to skip all of the low-level interfaces that deal with such things and use, e.g., IO::Socket.
If you're looking to convert to integer, as you say, and not to the form that socket functions expect (they're similar concepts in C, but less so in Perl), then you can go ahead and use pack just fine as long as you're consistent -- the part that's unportable is the format that socket functions accept. For example, unpack "N", pack "C4", split /\./, "1.2.3.4" will get you a nice unsigned big-endian representation of that address (in the form of the number 16909060 == 0x01020304).
Related
I would like to create an alert software for employees without outsourcing for security reasons. I found a way to send alerts from cmd with msg command, I didn't test this code but I generated it from Microsoft site, if there is any error please let me know
msg #allip.txt "test"
For IP list, I found a solution using arp -a using cmd but I have to clear the extra info in the file like this, the problem is that if I leave the extra info in the text the code doesn't work
Interface: 192.168.1.140 --- 0x3
Internet Address Physical Address Type
192.168.1.1 00-00-00-00-00-00 dynamic
192.168.1.61 00-00-00-00-00-00 dynamic
192.168.1.255 00-00-00-00-00-00 static
...
Is there a way to save only the internet address table
To extract all the cached IP addresses - which is what arp.exe /a reports - use the following:
Note: Judging by the linked docs, these cached addresses, stored along with their "their resolved Ethernet or Token Ring physical addresses", with a separate table maintained for each network adapter, are the IP addresses the computer at hand has actively talked to in the current OS session, which is not the same as the complete set of computers connected to the network.
To scan an entire subnet for reachable IP addresses, consider a third-party function such as Ping-Subnet.
((arp /a) -match '^\s+\d').ForEach({ (-split $_)[0] })
To save to a file, say ips.txt, append > ips.txt or | Set-Content ips.txt.
Note:
In Windows PowerShell, you'll get different character encodings by these file-saving methods (UTF-16 LE ("Unicode") for > / ANSI for Set-Content)
In PowerShell (Core) 7+, you'll get BOM-less UTF-8 files by (consistent) default.
Use Set-Content's -Encoding parameter to control the encoding explicitly.
Explanation:
-match '^\s+\d' filters the array of lines output by arp /a to include only those starting with (^) at least one (+) whitespace char. (\), followed by a decimal digit (\d) - this limits the output lines to the lines showing cache-table entries.
.ForEach() executes a script block ({ ... }) for each matching line.
The unary form of -split, the string splitting operator, splits each matching line into an array of fields by whitespace, and index [0] returns the first such field.
so I know there are libraries that can do this for me but I want to learn pack / unpack.
my goal is I have a user input an ip address / subnet mask and then verify that it's valid.
one way i thought of doing it was "sprintf" and get a binary value of lets say 192.168.1.1 . that's an ok solution, but then i need to prepend the required amount of 0's t make it '8 bit'
that seems like a lot of unnecessary work when pack can put things in binary format. I used the N template i found http://perldoc.perl.org/functions/pack.html my first goal was to get an ip address, convert it to binary, then convert it back.
$ip = "192.168.1.1";
$bi = pack ("N*", $ip);
print unpack("N*",$bi),"\n";
and the output i got was 192 so obviously i don't understand what's going on here.
what exactly is going on here?
pack ("N*", $ip) takes an integer out of $ip and puts it into network byte order.
What you want is packing the 4 decimal octets of the IP address as binary. No need to fiddle with endianness as the IP address string is already in big endian (The highest order byte is already at the start of the string).
I also changed the * to a 4, IP addresses are always 4 octets long:
$ip = "192.168.1.1";
$bi = pack "C4", split('\.', $ip);
print join('.', unpack("C4",$bi)), "\n";
Simple enough, I'd like to split a given IP address into netid (as defined by the netmask) and the hostid in Perl. Example:
$network = NetAddr::IP->new('192.168.255.255/29') || die "invalid space $_";
Now $network->mask returns 255.255.255.248. But there're no methods in NetAddr::IP to apply the mask to split the address into its netid and hostid portions in the /29 space.
NetAddr::IP::Util mentions the operators to do so, but it's documentation is a mess.
At least the netid can be extracted using Net::NetMask:
$netid = Net::Netmask->new('192.168.255.255/29')->base;
This yields 192.168.255.248. Again, no method to get the host portion 0.0.0.7. Maybe the best would be to pack/unpack the IPs into 32 bit int and then simply & them out. Then it would be easier to print the binary representations of IP addresses too, which I found can be really helpful for debugging and documentation purposes.
Use the hostmask() method
$host_wildcard = Net::Netmask->new('192.168.255.255/29')->hostmask;
I have a few numbers in a file in a variety of formats: 8.3, 0.001, 9e-18. I'm looking for an easy way to read them in and store them without any loss of precision. This would be easy in AWK, but how's it done in Perl? I'm only open to using Perl. Thanks!
Also, I was wondering if there's an easy way to print them in an appropriate format. For example, 8.3 should be printed as "8.3" not "8.3e0"
If they're text strings, then reading them into Perl as strings and writing them back out as strings shouldn't result in any loss of precision. If you have to do arithmetic on them, then I suggest installing the CPAN module Math::BigFloat to ensure that you don't lose any precision to rounding.
As to your second question, Perl doesn't do any reformatting unless you ask it to:
$ perl -le 'print 8.3'
8.3
Am I missing something?
From http://perldoc.perl.org/perlnumber.html:
Perl can internally represent numbers in 3 different ways: as native
integers, as native floating point numbers, and as decimal strings.
Decimal strings may have an exponential notation part, as in
"12.34e-56" . Native here means "a format supported by the C compiler
which was used to build perl".
This means that printing the number out depends on how the number is stored internal to perl, which means, in turn, that you have to know how the number is represented on input.
By and large, Perl will just do the right thing, but you should know how what compiler was used, how it represents numbers internally, and how to print those numbers. For example:
$ perldoc -f int
int EXPR
int Returns the integer portion of EXPR. If EXPR is omitted, uses $_. You should
not use this function for rounding: one because it truncates towards 0, and two
because machine representations of floating-point numbers can sometimes produce
counterintuitive results. For example, "int(-6.725/0.025)" produces -268 rather than
the correct -269; that's because it's really more like -268.99999999999994315658
instead. Usually, the "sprintf", "printf", or the "POSIX::floor" and
"POSIX::ceil" functions will serve you better than will int().
I think that if you want to read a number in explicitly as a string, your best bet would be to use unpack() with the 'A*' format.
I'm running an experiment on Berkeley DBs. I'm simply removing the contents from DB a and reinserting the key-value pairs into DB b. However, I am getting Wide character errors when inserting key-value pairs into this DB b. Help?
BerkeleyDB stores bytes ("octets"). Perl strings are made of Perl characters. In order to store Perl characters in the octet-based store, you have to convert the characters to bytes. This is called encoding, as in character-encoding.
The warning you get indicates that Perl is doing the conversion for you, and is guessing about what character encoding you want to use. Since it will probably guess wrong, it's best to explicitly say. The Encode module allows you to do that.
Instead of writing:
$db->store( key => $value );
You should instead write:
use Encode qw(encode);
$db->store( key => encode('utf-8', $value) );
And on the way out:
use Encode qw(decode);
$db->get($key, $octets); # BDB returns the result via the arg list. C programmers...
my $value = decode('utf-8', $octets);
This is true of more than just BDB; whenever you are communicating across the network, via files, via the terminal, or pretty much anything, you must be sure to encode characters to octets on the way out, and decode octets to characters on the way in. Otherwise, your program will not work.