質問

I am running Linux device with wired network interface. Another end of this interface is plugged into another network-aware device that is configured to use some static IP address and some netmask. Hence we have a very simple network consisting of the two devices and one cable only, not even switches between them, nothing.

The task is to start talking with that another device, and we need

  1. Put the network up with ifconfig or the like.
  2. Get IP address and launch my program that uses this IP address to work with the device.

I know I can do the broadcast ping and obtain the IP address of the device on another end of the cable. This works for me. But to activate the network and do broadcast ping I need to know the network address and netmask. My current bash script looks like

ifconfig 192.168.100.1 netmask 255.255.255.0 up
ping -b 192.168.100.255

And the device responds. Unfortunately, some of these devices might be misconfigured with unpredictable network and netmask. Could anyone propose an idea how to retrieve the network settings (netbase, netmask) automatically? Would be thankful even for a partial solution. A custom C tool could be compiled and installed on my side, if this would help.

役に立ちましたか?

解決

For the first part you can use nmap as long as you can somehow limit the range, as per your comment this already should give you the host you want:

sudo nmap -PR -sn 192.168.0-255.0-255 -e <interface-to-test>

This does discovery based on ARP and if succesful an additional ICMP ping for aliveness afterwards. This one took me about a second on a range with no active local hosts and 5s with 4 active hosts. So you can even expand it to a bit larger range, but not the full IPv4 address space unless you have a day or two. In that case I'd just hook up wireshark or tcpdump and wait for a gratuitous ARP.

edit: For this to work you have to configure your "source machine" with an IP in the subnet you want to test. I assumed it would use the DAD mode of ARP when going out of the subnet or when no ip is configured, but it just doesn't do anything. I added a more generic version to a script I wrote for the algorithm below, but it is a bit slower than simply using nmap to get this result.

Detecting the configured netmask is a bit trickier. But I think this procedure would work, the main idea is that a host will send out an ARP request for hosts in its subnet and nothing or an ARP request for its default-gw for hosts not in its subnet.

  1. Start with the second to smallest subnet N=29.
  2. Pick an IP X from this subnet formed by the host's IP and the subnet mask N. Make sure the picked IP is not the host's IP and not network/broadcast. Also make sure this IP is not a part of the subnet formed by the host's IP and mask N+1.
  3. Ping the other host with source X (you don't care if it answers, just send out a request)
  4. If you see an ARP request for X, decrease N with one. go back to 2
  5. If you don't see an ARP request for X, N+1 is the subnet searched.

One flaw might be that a overambitious network stack implementation might learn the MAC from the incoming ICMP request, but I personally do not know of any end-device stack that works this way.

I don't know if there are tools that do this for you, but it should be easy to do manually with ping, tcpdump and a subnet calculator ;). Or if you feel up to some hacking, it's probably not that much work to implement this with scapy

I went along and wrote a full python scapy script myself that should work, I tested it on my home network on a linksys homegw, another linux machine and an android device:

from __future__ import print_function, absolute_import, unicode_literals
from scapy.base_classes import Net
from scapy.config import conf
from scapy.layers.inet import Ether, ARP, ICMP, IP
from scapy.sendrecv import srp, debug
import scapy.route

iface = b'eth0'
subnet_to_test = b'192.168.1.0/24'
#or:
subnet_to_test = b'192.168.1.*'

#IP/MAC discovery
pkt = Ether(dst=b'ff:ff:ff:ff:ff:ff') / ARP(psrc=b'0.0.0.0', pdst=subnet_to_test, hwdst=b'ff:ff:ff:ff:ff:ff')
responses = srp(pkt, timeout=1, retry=0, verbose=0, iface=iface)
for r in responses[0]:
    found = r[1].getfieldval('psrc')
    foundmac = r[1].getfieldval('hwsrc')

n = 29
conf.debug_match = 1
while n > -1:
    net = Net("{}/{}".format(found, n))
    my_src = net.choice()
    while my_src in Net("{}/{}".format(found, n + 1)):
        my_src = net.choice()
    pkt = Ether(dst=foundmac) / IP(dst=found, src=my_src) / ICMP(type=8)
    resp = srp(pkt, timeout=1, retry=0, verbose=0, iface=iface, filter=b'ether dst FF:FF:FF:FF:FF:FF and arp')
    received = [x for x in debug.recv if x.haslayer(ARP) and x.getfieldval('pdst') == my_src]
    received.extend(x[1] for x in resp[0] if x[1].haslayer(ARP) and x[1].getfieldval('pdst') == my_src)
    if len(received) == 0:
        print("Found host: {}/{} on mac {}".format(found, n + 1, foundmac))
        break
    n -= 1 

他のヒント

What you are asking for is not possible.

Initially, you have an interface with no IP address on it. Because of this, any packets you send out will not know where to send the replies (ICMP, or ARP request will therefore not work).

Since senders' don't know how to reach this interface, you could listen on the interface for any broadcast ARP requests (using tcpdump, wireshark, etc.) This will show you what IP addresses are being resolved in the network, but it does not give you the net mask (and hence the network address). Furthermore, it does not only provide you with the directly connected neighbour's IP address, it will give you all of the ARP requests made within this broadcast domain (so you will possibly see many IP addresses).

Now, as for determining the network mask that the device is using, it is not possible when CIDR is employed (the prefix could be anywhere between /16 and /32, and there is no way to know exactly which one the neighbour device is using.)

That being said, you may want to look into link-local IPv4 addresses. On Linux, there is a program called AVAHI, and on Windows it is called APIPA. Both implement RFC 3927: https://www.rfc-editor.org/rfc/rfc3927

Link-local addresses can only be used to communicate with devices on the same physical or logical link, so if you actually want this device to be on the same subnet, you will have to manually configure the interface.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top