GNU/Linux >> Linux Esercitazione >  >> Linux

Ottenere gli indirizzi dell'interfaccia di rete locale utilizzando solo proc?

La mia soluzione per recuperare la configurazione di rete IPv4, utilizzando /proc solo:

Sfortunatamente, questo è bash (solo bash e senza qualsiasi fork), non python. Ma spero che questo sarà leggibile:

#!/bin/bash

# ip functions that set variables instead of returning to STDOUT

hexToInt() {
    printf -v $1 "%d\n" 0x${2:6:2}${2:4:2}${2:2:2}${2:0:2}
}
intToIp() {
    local var=$1 iIp
    shift
    for iIp ;do 
        printf -v $var "%s %s.%s.%s.%s" "${!var}" $(($iIp>>24)) \
            $(($iIp>>16&255)) $(($iIp>>8&255)) $(($iIp&255))
    done
}
maskLen() {
    local i
    for ((i=0; i<32 && ( 1 & $2 >> (31-i) ) ;i++));do :;done
    printf -v $1 "%d" $i
}

# The main loop.

while read -a rtLine ;do
    if [ ${rtLine[2]} == "00000000" ] && [ ${rtLine[7]} != "00000000" ] ;then
        hexToInt netInt  ${rtLine[1]}
        hexToInt maskInt ${rtLine[7]}
        if [ $((netInt&maskInt)) == $netInt ] ;then
            for procConnList in /proc/net/{tcp,udp} ;do
                while IFS=': \t\n' read -a conLine ;do
                    if [[ ${conLine[1]} =~ ^[0-9a-fA-F]*$ ]] ;then
                        hexToInt ipInt ${conLine[1]}
                        [ $((ipInt&maskInt)) == $netInt ] && break 3
                    fi
                done < $procConnList
            done
        fi
    fi
done < /proc/net/route 

# And finaly the printout of what's found

maskLen maskBits $maskInt
intToIp addrLine $ipInt $netInt $maskInt
printf -v outForm '%-12s: %%s\\n' Interface Address Network Netmask Masklen
printf "$outForm" $rtLine $addrLine $maskBits\ bits

C'è un esempio di output:

Interface   : eth0
Address     : 192.168.1.32
Network     : 192.168.1.0
Netmask     : 255.255.255.0
Masklen     : 24 bits

Spiegazione:

Uso il valore intero di IPV4 per controllare IP & MASK == NETWORK .

Ho letto prima /proc/net/route per trovare le configurazioni di instradamento, cercando percorsi raggiungibili senza alcun gateway (gw==000000 ).

Per tale percorso, cerco in tutte le connessioni (TCP, poi UDP se non trovato in TCP) per la connessione utilizzando questo route, il primo punto finale è il mio indirizzo host.

Nota:questo non funzionerà con le connessioni PPP

Nota2:questo non funzionerà su un host totalmente silenzioso senza alcuna connessione di rete aperta. Potresti fare qualcosa come echo -ne '' | nc -q 0 -w 1 8.8.8.8 80 & sleep .2 && ./retrieveIp.sh per aver assicurato che qualcosa fosse trovato in /proc/net/tcp .

Nota3, 23.09.2016:la nuova versione di bash usa >(command) sintassi per multiple inline pipe caratteristica . Questo implica un bug alla riga 18:uno spazio must essere presente tra > e ( !!

Nuova versione con gateway

C'è una piccola patch:una volta creato un file chiamato getIPv4.sh copiando lo script precedente, puoi incollare quanto segue nel comando:patch -p0

--- getIPv4.sh
+++ getIPv4.sh
@@ -35,13 +35,16 @@
                 done < $procConnList
             done
         fi
+    elif [ ${rtLine[1]} == "00000000" ] && [ ${rtLine[7]} == "00000000" ] ;then
+       hexToInt netGw ${rtLine[2]}
     fi
 done < /proc/net/route 

 # And finaly the printout of what's found

 maskLen maskBits $maskInt
-intToIp addrLine $ipInt $netInt $maskInt
-printf -v outForm '%-12s: %%s\\n' Interface Address Network Netmask Masklen
+intToIp addrLine $ipInt $netInt $netGw $maskInt
+printf -v outForm '%-12s: %%s\\n' \
+       Interface Address Network Gateway Netmask Masklen
 printf "$outForm" $rtLine $addrLine $maskBits\ bits

Termina con Ctrl d , questo potrebbe restituire:

patching file getIPv4.sh

E forse

Hunk #1 succeeded at 35 with fuzz 2.

Quindi riesegui il tuo script:

getIPv4.sh
Interface   : eth0
Address     : 192.168.1.32
Network     : 192.168.1.0
Gateway     : 192.168.1.1
Netmask     : 255.255.255.0
Masklen     : 24 bits

Potresti trovare l'output di ip addr show più facile da analizzare rispetto all'output di altri strumenti:

$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:24:1d:ce:47:05 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.121/24 brd 192.168.0.255 scope global eth0
    inet6 fe80::224:1dff:fece:4705/64 scope link
       valid_lft forever preferred_lft forever
3: eth1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
    link/ether 00:24:1d:ce:35:d5 brd ff:ff:ff:ff:ff:ff
4: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN
    link/ether 92:e3:6c:08:1f:af brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
    inet6 fe80::90e3:6cff:fe08:1faf/64 scope link
       valid_lft forever preferred_lft forever

Un'altra opzione è il file /proc/net/tcp . Mostra tutte le sessioni TCP attualmente aperte, che è diverso da quello che hai chiesto, ma potrebbe essere abbastanza buono.

$ cat tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
   0: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 13536 1 ffff88019f0a1380 300 0 0 2 -1
   1: 00000000:1355 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 19877854 1 ffff880016e69380 300 0 0 2 -1
   2: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 13633 1 ffff88019f0a1a00 300 0 0 2 -1
   3: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 8971 1 ffff88019f0a0000 300 0 0 2 -1
   4: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 12952880 1 ffff880030e30680 300 0 0 2 -1
   5: 00000000:0539 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 14332 1 ffff88019f0a2080 300 0 0 2 -1
   6: 00000000:C000 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 14334 1 ffff88019f0a2700 300 0 0 2 -1
   7: 0100007F:0A44 00000000:0000 0A 00000000:00000000 00:00000000 00000000   119        0 51794804 1 ffff880016e6a700 300 0 0 2 -1
   8: 7900A8C0:B094 53D50E48:01BB 01 00000000:00000000 00:00000000 00000000  1000        0 64877487 1 ffff880100502080 23 4 16 4 -1
   9: 7900A8C0:9576 537F7D4A:01BB 06 00000000:00000000 03:00000E5D 00000000     0        0 0 3 ffff880100c84600
  10: 7900A8C0:CC84 0CC181AE:01BB 01 00000000:00000000 00:00000000 00000000  1000        0 61775908 1 ffff880198715480 35 4 11 4 -1
$ irb
irb(main):001:0> [0x79, 0x00, 0xa8, 0xc0]
=> [121, 0, 168, 192]

Il mio IP è 192.168.0.121; nota la buffa aritmetica per farlo uscire bene. :)


/proc/net/fib_trie contiene la topografia della rete

Per stampare semplicemente gli indirizzi di tutti gli adattatori:

$ awk '/32 host/ { print f } {f=$2}' <<< "$(</proc/net/fib_trie)"
127.0.0.1
192.168.0.5
192.168.1.14

Per determinare l'adattatore di quegli indirizzi (a) consultare le reti di destinazione degli adattatori da /proc/net/route , (b) abbina queste reti con quelle di /proc/net/fib_trie e (c) stampare i corrispondenti indirizzi host /32 elencati sotto quelle reti.

Di nuovo niente python sfortunatamente, ma un bash abbastanza imbarazzante approccio:

#!/bin/bash

ft_local=$(awk '$1=="Local:" {flag=1} flag' <<< "$(</proc/net/fib_trie)")

for IF in $(ls /sys/class/net/); do
    networks=$(awk '$1=="'$IF'" && $3=="00000000" && $8!="FFFFFFFF" {printf $2 $8 "\n"}' <<< "$(</proc/net/route)" )
    for net_hex in $networks; do
            net_dec=$(awk '{gsub(/../, "0x& "); printf "%d.%d.%d.%d\n", $4, $3, $2, $1}' <<< $net_hex)
            mask_dec=$(awk '{gsub(/../, "0x& "); printf "%d.%d.%d.%d\n", $8, $7, $6, $5}' <<< $net_hex)
            awk '/'$net_dec'/{flag=1} /32 host/{flag=0} flag {a=$2} END {print "'$IF':\t" a "\n\t'$mask_dec'\n"}' <<< "$ft_local"
    done
done

exit 0

uscita:

eth0:     192.168.0.5
          255.255.255.0

lo:       127.0.0.1
          255.0.0.0

wlan0:    192.168.1.14
          255.255.255.0

Limitazione nota:

Questo approccio non funziona in modo affidabile per gli indirizzi host che condividono la rete con altri indirizzi host. Questa perdita di unicità della rete rende impossibile determinare l'indirizzo host corretto da fib_trie poiché l'ordine di tali indirizzi non corrisponde necessariamente all'ordine delle reti di instradamento.

Detto questo, non sono sicuro del motivo per cui dovresti volere più indirizzi host appartenenti alla stessa rete in primo luogo. Quindi nella maggior parte dei casi d'uso questo approccio dovrebbe funzionare bene.


Non esiste un analogo IPv4 di /proc/net/if_inet6

ifconfig fa:

fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)
ioctl(fd, SIOCGIFCONF, ...)

Otterrai qualcosa del genere:

ioctl(4, SIOCGIFCONF, {120, {{"lo", {AF_INET, inet_addr("127.0.0.1")}}, {"eth0", {AF_INET, inet_addr("10.6.23.69")}}, {"tun0", {AF_INET, inet_addr("10.253.10.151")}}}})

Linux
  1. Utilizzo dello strumento SS per la risoluzione dei problemi di rete

  2. Come raggiungere un servizio/server che si trova su una rete inaccessibile (usando i tunnel SSH)

  3. Linux:il binding dell'interfaccia di rete sembra funzionare solo come root?

  4. Trova l'unica destinazione del collegamento simbolico?

  5. Ifconfig:7 esempi per configurare l'interfaccia di rete

Come bloccare gli indirizzi falsificati locali utilizzando il firewall Linux

3 modi per configurare un'interfaccia di rete in Linux

Utilizzo di ifstat per le statistiche di rete Linux

Ottieni indirizzi IPv6 in Linux usando ioctl

Ottieni l'indirizzo MAC usando lo script della shell

Consentire l'accesso a un host virtuale Apache solo dalla rete locale