How to multicast using gen_udp in Erlang? - networking

How do you use gen_udp in Erlang to do multicasting? I know its in the code, there is just no documentation behind it. Sending out data is obvious and simple. I was wondering on how to add memberships. Not only adding memberships at start-up, but adding memberships while running would be useful too.

Here is example code on how to listen in on Bonjour / Zeroconf traffic.
-module(zcclient).
-export([open/2,start/0]).
-export([stop/1,receiver/0]).
open(Addr,Port) ->
{ok,S} = gen_udp:open(Port,[{reuseaddr,true}, {ip,Addr}, {multicast_ttl,4}, {multicast_loop,false}, binary]),
inet:setopts(S,[{add_membership,{Addr,{0,0,0,0}}}]),
S.
close(S) -> gen_udp:close(S).
start() ->
S=open({224,0,0,251},5353),
Pid=spawn(?MODULE,receiver,[]),
gen_udp:controlling_process(S,Pid),
{S,Pid}.
stop({S,Pid}) ->
close(S),
Pid ! stop.
receiver() ->
receive
{udp, _Socket, IP, InPortNo, Packet} ->
io:format("~n~nFrom: ~p~nPort: ~p~nData: ~p~n",[IP,InPortNo,inet_dns:decode(Packet)]),
receiver();
stop -> true;
AnythingElse -> io:format("RECEIVED: ~p~n",[AnythingElse]),
receiver()
end.

Multicast sending has been answered, receipt requires subscription to the multicast group.
It (still) seems undocumented, but has been covered on the erlang-questions mailing list before. http://www.erlang.org/pipermail/erlang-questions/2003-March/008071.html
{ok, Socket} = gen_udp:open(Port, [binary, {active, false},
{reuseaddr, true},{ip, Addr},
{add_membership, {Addr, LAddr}}]).
where the Addr is the multicast group, and LAddr is a local interface. (code courtesy of mog)
The same options used above can be passed to inet:setopts including {drop_membership, {Addr, LAddr}} to stop listening to the group.

I try to get this example running on my PC. What could happen, if I get always the message {error,eaddrnotavail} by opening the receive socket?
Example 1: This works:
{ok, Socket} = gen_udp:open(?PORT, [{reuseaddr,true}, {ip,?SERVER_IP},
{multicast_ttl,4}, {multicast_loop,false}, binary]),
Example 2: Getting an runtime Error:
{ok, Socket} = gen_udp:open(?PORT, [{reuseaddr,true}, {ip,?MULTICAST_IP},
{multicast_ttl,4}, {multicast_loop,false}, binary]),
% --> {error,eaddrnotavail}
-define(SERVER_IP, {10,31,123,123}). % The IP of the current computer
-define(PORT, 5353).
-define(MULTICAST_IP, {224,0,0,251}).

Multicast is specified by IP Address
It's the same in erlang as for all languages. The IP addresses 224.0.0.0 through 239.255.255.255 are multicast addresses.
Pick an address in that range, check that you're not overlapping an already assigned address, and you are good to go.
http://www.iana.org/assignments/multicast-addresses

Related

Detect VLAN tagged packets using XDP eBPF

I am trying to detect packets with a VLAN tag. I have some PCAP files to containing VLAN tagged packets to test. A Wireshark screenshot of a sample packet:
After reading some tutorials, I wrote the following code:
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
#define bpf_printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), \
##__VA_ARGS__); \
})
SEC("xdpvlan")
int myxdpprogram(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
if ((void*)eth + sizeof(*eth) <= data_end) {
bpf_printk("h_proto is: 0x%x, ETH_P_8021Q is: 0x%x\n", bpf_ntohs(eth->h_proto), ETH_P_8021Q);
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
The output in /sys/kernel/debug/tracing/trace is like this:
bpf_trace_printk: h_proto is: 0x800, ETH_P_8021Q is: 0x8100
I expected:
bpf_trace_printk: h_proto is: 0x8100, ETH_P_8021Q is: 0x8100
I am using Fedora 34 to test, kernel version: 5.11.12-300.fc34.x86_64.
Why the h_proto is not equal to 0x8100?
Update
I have two VMs, and I am using tcpreplay to send packets (PCAP file) from one VM to the other VM that has the eBPF program. VMs are connected through a host-only interface. I load the program using:
ip link set dev ens37 xdpgeneric obj xdp_vlan_kern.o sec xdpvlan
[EDIT] Not sure this answer is correct, have a look at the comments for details.
Generic XDP, or SKB-mode XDP, is an XDP mode that was primarily added for experimenting with XDP (and to provide a model for future driver-based implementations). Given that it requires no support from the NIC driver, it is easier to use, but has lower performance than the other modes (driver/native XDP or XDP hardware offload).
One consequence of not having driver support is that the hook for generic XDP is necessarily higher in the networking stack when compared with native XDP. Generic XDP runs after the socket buffer (SKB) has been allocated. This means that some processing may already have occurred on your packets. In your case, the networking stack has already decapsulated the packets from their VXLAN headers, so you just observe regular IP packets.
Switching to driver-level XDP, providing your hardware (or virtual interface) uses a driver that supports it, should allow you to process your packets before they are sent to the kernel stack and before the VXLAN are removed.
I faced the same problem when running xdp in xdpdrv mode.
In this tutorial I found notes about VLAN offloads on NIC interface:
Since XDP needs to see the VLAN headers as part of the packet headers, it is important to turn off VLAN hardware offload (which most hardware NICs support), since that will remove the VLAN tag from the packet header and instead communicate it out of band to the kernel via the packet hardware descriptor. The testenv script already disables VLAN offload when setting up the environment, but for reference, here is how to turn it off for other devices, using ethtool:
# Check current setting:
ethtool -k DEV | grep vlan-offload
# Disable for both RX and TX
ethtool --offload DEV rxvlan off txvlan off
# Same as:
# ethtool -K DEV rxvlan off txvlan off
I tried to use driver-mode as #Qeole, suggested. I created a pair of virtual interfaces because my NIC's driver didn't support driver specific hook.
ip link add dev veth1 type veth peer name veth2
The I loaded the program:
ip link set dev veth1 xdpdrv obj xdp_vlan_kern.o sec xdpvlan
And the replayed the PCAP file (on the same VM):
tcpreplay -i veth2 vlan.pcap
The output was as I expected:
bpf_trace_printk: h_proto is: 0x8100, ETH_P_8021Q is: 0x8100
Roman Sokolov's answer is correct.
Disabling txvlan on the sending side fixed the error.
ip link add veth0 type veth peer name veth1
ip link add link veth0 name veth0.100 type vlan id 100
ip link set veth0 up
ip link set veth1 up
ip link set veth0.100 up
ip addr add 10.100.0.4/24 dev veth0.100
ethtool -K veth0 txvlan off
Attaching ebpf program on veth1 using SKB mode, injecting packets into veth0.100 (simply run arping would be enough), then I can get packets with vlan tags in my ebpf program.
However it didn't solve the problem when I only disable rxvlan on veth1.
I didn't test this on a physical device yet, I'll try it later and modify this answer.

TCP SYN sent with Scapy never received by server nor noticed by Wireshark on the loopback interface

I have a problem with a very basic usage of Scapy on Windows 7 (Python 3.6, Scapy 2.4.0). I'm also running Npcap 0.99r7 and Wireshark 2.6.2 on this sytem. The system does only have one wireless network interface plus the Npcap loopback interface.
I set up this very classic TCP server... :
import socket
host = '127.0.0.1'
port = 8089
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(1)
connection, address = s.accept()
while 1:
try :
data = connection.recv(1024)
except ConnectionAbortedError:
break
if data:
print('Received: %s' % (data.decode ('utf-8')))
connection.sendall('Data received'.encode())
connection.close()
s.close()
...and I set up this very classic TCP client:
import socket
host = '127.0.0.1'
port = 8089
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send('Hello, world!'.encode())
data = s.recv(1024)
print('Received: %s' % (data.decode('utf-8')))
s.close()
Both works fine. Wireshark does report the whole TCP traffic on the loopback interface.
Now, I'm running the server, and I try to run that piece of code that would just send a SYN to the server with Scapy :
from scapy.layers.inet import IP
from scapy.layers.inet import TCP
from scapy.sendrecv import *
dstHost='127.0.0.1'
dstPort = 8089
packet = IP(src='127.0.0.1', dst=dstHost)/TCP(dport=dstPort, flags='S')
response=sr1(packet, timeout=10)
response.display()
Python reports :
Begin emission:
..Finished sending 1 packets.
......Traceback (most recent call last):
File "R:/Documents/Projets/python/hacking/scan.py", line 46, in <module>
response.display()
AttributeError: 'NoneType' object has no attribute 'display'
Received 8 packets, got 0 answers, remaining 1 packets
Moreover, Wireshark does not see anything on the loopback interface. May somebody give an hint ?
Update 1
As suggested, I tried a more explicit code using sendp() and not send(), since we are talking layer 2 here:
route_add_loopback()
packet = Loopback()/IP(src='127.0.0.1', dst='127.0.0.1')/TCP(dport=8089, flags='S')
sendp(packet,iface='Npcap Loopback Adapter')
Unfortunately, Wireshark does not sniff the packet on either interfaces (the 'Intel(R) Centrino(R) Advanced-N 6235' and the 'Npcap Loopback Adapter').
Note that the call to route_add_loopback() is required, or show_interfaces() won't report the 'Npcap Loopback Adapter', which means that sendp() will fail. It is possible to restore the Scapy routing table by calling conf.route.resync () after route_add_loopback(), but the result is the same : Wireshark does not sniff the packet on either interface.
Should somebody find some Python piece of code running on Windows 7 that succesfully sends a simple TCP packet on the 'Npcap Loopback Adapter', he would be welcome...
The loopback interface is not a "regular" interface; this is particularly true for Windows.
You can check the route used by Scapy to send the packet by running: packet.route().
If the route displayed does not use the loopback interface, you can try to run (that's windows specific) route_add_loopback() and try again.
Another option would be to use srp1() instead of sr1(), and specify the loopback interface as iface= parameter.

'localhost' connection without firewall popup

Consider the following R script:
con <- socketConnection(host = "localhost", port = 8, server = TRUE, blocking = TRUE, open = "a+b")
close(con = con)
Saving these lines as a .R file, and subsequently running it from command line produces (on Windows) a firewall warning. At least, if there is no rule for R under "Windows Firewall with Advanced Security", which appears after the first time. I've been told the same happens on a Mac, but I couldn't verify this myself. How can this be altered to allow for a localhost loopback, but avoid the popup?
Context: I've written some code for people that uses parallel processing (on one single local machine). However, this warning popped up on their screens, and they got suspicious. The silly thing is, that even if people click no or ignore the popup, the parallel processing still seems to works. I take that as a sign that it's possible to modify this code to not give this popup and still function.
I've seen very similar questions in other languages (1, 2, 3), and I was wondering whether it is possible to do the same with R.
Windows 10 Firewall First Time Prompt Example:
My sense is that the easiest way to navigate this problem is to add a firewall rule as part of the application install process.
You can use netsh to add a rule (administrator privileges are required) to enable firewall access programmatically.
I provide an example script below, and I hope this helps point you in the right direction.
Example firewall configuration script
netsh advfirewall firewall add rule name="RScript" action=allow program="C:\Program Files\Microsoft\R Client\R_SERVER\bin\x64\Rscript.exe" enable=yes Localip="127.0.0.1" localport="9999" protocol=tcp interfacetype=any profile=private dir=in
Command Output:
PS <hidden>\dev\stackoverflow\47353848> netsh advfirewall firewall add rule name="RScript" action=allow program="C
:\Program Files\Microsoft\R Client\R_SERVER\bin\x64\Rscript.exe" enable=yes Localip="127.0.0.1" localport="9999" protoco
l=tcp interfacetype=any profile=private dir=in
Ok.
Firewall Rule Added
Assuming you run the R file using RScript, the above netsh script will enable the RScript application to be able to access the loopback address 127.0.0.1 on port 9999 using TCP on a private network. From this point on you should not get a firewall prompt.
Command line with no prompt for firewall
c:\<hidden>\dev\stackoverflow\47353848> Rscript.exe .\server.R
Listening...
Why do this? Well, as far as I have been able to ascertain there is no way to use R's base::socketConnection on Windows without triggering the Windows Defender firewall prompt, even when using the loopback connector. Interesting to note is that if you use Java you don't get prompted. I looked at both implementations, but I couldn't determine why not.
Test Server Code:
server <- function() {
while (TRUE) {
writeLines("Listening...")
con <- socketConnection(host = "loopback",
port = 9999,
server = TRUE,
blocking = TRUE,
timeout = 0,
open = "r+")
data <- readLines(con, 1)
print(data)
response <- toupper(data)
writeLines(response, con)
close(con)
}
}
server()
Test Client Code
client <- function() {
while (TRUE) {
con <- socketConnection(host = "loopback",
port = 9999,
server = FALSE,
blocking = TRUE,
open = "r+")
f <- file("stdin")
open(f)
print("Enter text to be upper-cased, q to quit")
sendme <- readLines(f, n = 1)
if (tolower(sendme) == "q") {
break
}
write_resp <- writeLines(sendme, con)
server_resp <- readLines(con, 1)
print(paste("Your upper cased text: ", server_resp))
close(con)
}
}
client()
(For my take on the firewall rule, see the very end)
The functionality simply does not seem to exist.
In C you create a server socket with socket, bind and listen calls, and get the incoming connection with an accept call.
src\modules\internet\sock.c is the socket handler code, it has two functions for opening a socket, Sock_connect opens and connects a socket, so this is for client side, and int Sock_open(Sock_port_t port, Sock_error_t perr) is the one which opens a server socket (and the actual accept call is in Sock_listen). The problem is that this Sock_open has a port argument only, and the host/interface is hardcoded:
/* open a socket for listening */
int Sock_open(Sock_port_t port, Sock_error_t perr)
{
int sock;
struct sockaddr_in server;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return Sock_error(perr, errno, 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons((short)port);
if ((bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0) ||
(listen(sock, MAXBACKLOG) < 0)) {
close(sock);
return Sock_error(perr, errno, 0);
}
return sock;
}
It binds to and listens on INADDR_ANY, which means all interfaces of your PC (not just the loopback), and it triggers the firewall for sure.
The function is called from the neighboring Rsock.c, still with a single port argument, and where everything else is lost seems to be one step earlier, in sockconn.c:
static Rboolean sock_open(Rconnection con)
{
Rsockconn this = (Rsockconn)con->private;
int sock, sock1, mlen;
int timeout = this->timeout;
char buf[256];
if(timeout == NA_INTEGER || timeout <= 0) timeout = 60;
this->pend = this->pstart = this->inbuf;
if(this->server) {
sock1 = R_SockOpen(this->port);
This last line is where host part of RSockconn is disregarded, though it contains such field:
/* used in internet module */
typedef struct sockconn {
int port;
int server;
int fd;
int timeout;
char *host;
char inbuf[4096], *pstart, *pend;
} *Rsockconn;
(This is defined outside, in src\include\Rconnections.h)
Unfortunately this will not solve your problem, just this is why you have it. You may consider raising an error report for the developers of R. Comments suggest they got the net code from ancient times, when firewalls and internet security were not that much of a concern like they are now:
/* Simple sockets interface derived from the sockets UICI
implementation in Appendix B of Practical UNIX Programming,
K. A. Robbins and S. Robbins, Prentice Hall, 1996. */
Which is nice, just it was 21 years ago.
Originally I did not want to steal the netsh thing from others, but I think you may get wrong suggestions. Actually you should not allow anything, but block everything:
netsh advfirewall firewall add rule name="Rtest" dir=in action=block program="<location and name of your executable>"
And that is it. The thing is that the loopback interface is not firewalled at all (so connections to 127.0.0.1 always work - I tested it too, just to be on the safe side), and you do not want anyone else to reach your program. I saw 'allow'-s in other answers, and you do not want that. Depending on other uses, you may have to restrict the rule with 'localport=8' and/or 'protocol=tcp', but the block part is sure.
You are basically forced to use Windows Firewall, as it comes with Windows. So maybe include a .bat file with your .R file that creates an exception and tells the user to run it? Or maybe make a .exe installer with IExpress? That might do the trick.
I would recommend the .exe installer route though, as a .bat file seems a tad suspicious too, as non-tech-savvy users will cry wolf when it asks for administrator privileges. The netsh command can create firewall exceptions for any program if you would rather the .bat file route.
This one accepts outgoing connections by using the dir=out switch, and enabling the exception via the action=allow switch
netsh advfirewall firewall add rule name="PROGRAM_NAME" dir=out action=allow program="C:\PROGRAMPATH" enable=yes
This one accepts incoming connections by using the dir=in switch, and enabling the exception via the action=allow switch
netsh advfirewall firewall add rule name="PROGRAM_NAME" dir=out action=allow program="C:\PROGRAMPATH" enable=yes
How to add a rule to Windows Firewall - DigitalCitizen
Online Tech Tips - Adjust Windows 10 Firewall Rules & Settings
An alternative to using PSOCK clusters is to use callr for running multiple R sessions in the background. The future.callr package (*) provides parallel backend for the future framework (disclaimer: I'm the author). It'll allow you to parallelize all OSes including Windows without going through sockets (and therefore no firewall). Example:
library("future")
plan(future.callr::callr)
y <- future_lapply(x, FUN = my_fcn_in_parallel)
It also works with doFuture for the foreach framework. Example:
library("doFuture")
plan(future.callr::callr)
registerDoFuture()
y <- foreach(i in seq_along(x)) %dopar% my_fcn_in_parallel(x[[i]])
FYI, for PSOCK clusters, use plan(multisession).
(*) future.callr is on CRAN as of 2018-02-13 will be submitted to CRAN as soon as the developer's version of callr that it depends on is submitted to CRAN.

Information about Switches and Ports from OpenFlow (RYU Controller)

I am attempting to get some information from OpenFlow for my OpenFlow Application on RYU.
The information that I want to get is given below.
For each SWITCH,I want
- DPID
- STATE (ACTIVE/INACTIVE)
For each PORT, I want
- DPID
- PORT_NUMBER
- STATE
- PORT_STATE
Port state - Tracks Port Status message from OF. 1 - ACTIVE. 0 - INACTIVE.OpenFlow 1.0 has 2 types of port status from memory, one concerning whether the port has link and the other concerning whether the port is administratively up. I believe this port status tracks the second type - i.e. port status should be 1 if the port is administratively up even if it doesn't have a link.
Which messages should I listen to to get the above information.Also I tried getting information about ofp_event.EventOFPStateChange.
I tried looking at http://ryu.readthedocs.org/en/latest/genindex.html
I couldn't find the information related to ofp_event.EventOFPStateChange.
Any help to point me in the right direction would be highly appreciated.
You can use the following code. I am using it to identify all switches connected to it. I needed only the DPIDs and out ports. But you can use 'ev.link' for other information.
Hope this helps.
`
class OF13(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
_CONTEXTS = {
'dpset': dpset.DPSet,
}
def __init__(self, *args, **kwargs):
super(OF13, self).__init__(*args, **kwargs)
self.dpset = kwargs['dpset']
def _get_hwaddr(self, dpid, port_no):
return self.dpset.get_port(dpid, port_no).hw_addr
#handler.set_ev_cls(event.EventLinkAdd)
def link_add(self, ev):
print ev.link.src, ev.link.dst
print self._get_hwaddr(ev.link.src.dpid, ev.link.src.port_no)

how to find host name from IP with out login to the host

i need to find the host name of a UNIX host whose IP is known with out login to that UNIX host
Use nslookup
nslookup 208.77.188.166
...
Non-authoritative answer:
166.188.77.208.in-addr.arpa name = www.example.com.
You can do a reverse DNS lookup with host, too. Just give it the IP address as an argument:
$ host 192.168.0.10
server10 has address 192.168.0.10
Another NS lookup utility that can be used for reversed lookup is dig with the -x option:
$ dig -x 72.51.34.34
; <<>> DiG 9.9.2-P1 <<>> -x 72.51.34.34
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12770
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1460
;; QUESTION SECTION:
;34.34.51.72.in-addr.arpa. IN PTR
;; ANSWER SECTION:
34.34.51.72.in-addr.arpa. 42652 IN PTR sb.lwn.net.
;; Query time: 4 msec
;; SERVER: 192.168.178.1#53(192.168.178.1)
;; WHEN: Fri Jan 25 21:23:40 2013
;; MSG SIZE rcvd: 77
or
$ dig -x 127.0.0.1
; <<>> DiG 9.9.2-P1 <<>> -x 127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11689
;; flags: qr aa ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;1.0.0.127.in-addr.arpa. IN PTR
;; ANSWER SECTION:
1.0.0.127.in-addr.arpa. 10 IN PTR localhost.
;; Query time: 2 msec
;; SERVER: 192.168.178.1#53(192.168.178.1)
;; WHEN: Fri Jan 25 21:23:49 2013
;; MSG SIZE rcvd: 63
Quoting from the dig manpage:
Reverse lookups -- mapping addresses to names -- are simplified by the
-x option. addr is an IPv4 address in dotted-decimal notation, or a colon-delimited IPv6 address. When this option is used, there is no
need to provide the name, class and type arguments. dig automatically
performs a lookup for a name like 11.12.13.10.in-addr.arpa and sets
the query type and class to PTR and IN respectively.
For Windows ping -a 10.10.10.10
For Windows, try:
NBTSTAT -A 10.100.3.104
or
ping -a 10.100.3.104
For Linux, try:
nmblookup -A 10.100.3.104
They are almost same.
It depends on the context. I think you're referring to the operating system's hostname (returned by hostname when you're logged in). This command is for internal names only, so to query for a machine's name requires different naming systems. There are multiple systems which use names to identify hosts including DNS, DHCP, LDAP (DN's), hostname, etc. and many systems use zeroconf to synchronize names between multiple naming systems. For this reason, results from hostname will sometimes match results from dig (see below) or other naming systems, but often times they will not match.
DNS is by far the most common and is used both on the internet (like google.com. A 216.58.218.142) and at home (mDNS/LLMNR), so here's how to perform a reverse DNS lookup: dig -x <address> (nslookup and host are simpler, provide less detail, and may even return different results; however, dig is not included in Windows).
Note that hostnames within a CDN will not resolve to the canonical domain name (e.g. "google.com"), but rather the hostname of the host IP you queried (e.g. "dfw25s08-in-f142.1e100.net"; interesting tidbit: 1e100 is 1 googol).
Also note that DNS hosts can have more than one name. This is common for hosts with more than one webserver (virtual hosting), although this is becoming less common thanks to the proliferation of virtualization technologies. These hosts have multiple PTR DNS records.
Finally, note that DNS host records can be overridden by the local machine via /etc/hosts. If you're not getting the hostname you expect, be sure you check this file.
DHCP hostnames are queried differently depending on which DHCP server software is used, because (as far as I know) the protocol does not define a method for querying; however, most servers provide some way of doing this (usually with a privileged account).
Note DHCP names are usually synchronized with DNS server(s), so it's common to see the same hostnames in a DHCP client least table and in the DNS server's A (or AAAA for IPv6) records. Again, this is usually done as part of zeroconf.
Also note that just because a DHCP lease exists for a client, doesn't mean it's still being used.
NetBIOS for TCP/IP (NBT) was used for decades to perform name resolution, but has since been replaced by LLMNR for name resolution (part of zeroconf on Windows). This legacy system can still be queried with the nbtstat (Windows) or nmblookup (Linux).
python -c "import socket;print(socket.gethostbyaddr('127.0.0.1'))"
if you just need the name, no additional info, add [0] at the end:
python -c "import socket;print(socket.gethostbyaddr('8.8.8.8'))[0]"
The other answers here are correct - use reverse DNS lookups.
If you want to do it via a scripting language (Python, Perl) you could use the gethostbyaddr API.
If you are specifically looking for a Windows machine, try below command:
nbtstat -a 10.228.42.57
You can use traceroute command as well.
http://linux.die.net/man/8/traceroute
just use the traceroute it will show you the routing path with host names (IPs resolved)
In most cases, traceroute command works fine. nslookup and host commands may fail.

Resources