#1 Le 28/08/2012, à 11:26
- Nfjord
Connaître le type d'une interface réseau en C
Bonjour,
Dans un programme en C, je souhaite effectuer différentes actions en fonction du type d'interface réseau auquel j'ai affaire. Par type d'interface réseau, j'entends 802.3 (ethernet) ou 802.11 (wifi) ou 802.15.X (bluetooth, zigbee, etc.), etc. Aussi, je me demande si le kernel linux peut fournir ce type d'information. En effet, en fonction du type d'interface, le kernel octroie un nom différent : ethX pour les interfaces ethernet, wlanX pour les interfaces wifi, etc. Seulement, me baser sur le nom de l'interface donné par le kernel pour déterminer dans mon programme de quel type il s'agit me semble très peut fiable. D'autant plus que depuis Ubuntu 12.04, le kernel octroie des noms pas très cohérents (par exemple sur mon laptop mon interface ethernet est nommée eth3 et mon interface wifi est nomée eth4 ). Jene sais pas trop comment marche le nommage d'interface réseau dans le kernel mais il doit bien être en mesure de déterminer de quel type il s'agit (peut-être via le driver de la carte ?) et certainement qu'il doit stocker cette info quelque part... mais la question est où ? Et à travers quelle structure puis-je la récupérer en C ?
It's always a long day, 86,400 won't fit into a short.
Hors ligne
#2 Le 28/08/2012, à 13:18
- Haleth
Re : Connaître le type d'une interface réseau en C
Niveau userspace, je trouve pas mieux que la libpcap :'(
J'me demande pourquoi y' rien de cool dans le sysfs, ou alors j'ai pas trouvé
Si, par change, tu programmes du coté kernel, y'a la fonction _get_dev_by_name
Ubuntu is an ancien African word which means "I can't configure Debian"
Because accessor & mutator are against encapsulation (one of OOP principles), good OOP-programmers do not use them. Obviously, procedural-devs do not. In fact, only ugly-devs are still using them.
Hors ligne
#3 Le 28/08/2012, à 14:24
- Nfjord
Re : Connaître le type d'une interface réseau en C
Merci de votre réponse
Je suis en train de regarder du côté de __dev_get_by_name() mais j'ai du mal. D'après ce que j'ai trouvé sur le net, il faut inclure le fichier
#include <linux/netdevice.h>
Seulement gcc ne trouve pas la fonction avec ce header :
/tmp/ccZcr3SM.o: In function `main':
test.c:(.text+0x1d): undefined reference to `__dev_get_by_name'
collect2: ld returned 1 exit status
En regardant de plus près dans netdevice.h la fonction est déclarée comme extern. Et impossible de mettre la main sur le header qui définit cette fonction...
Auriez-vous un exemple simple de l'utilisation de cette fonction ?
Dernière modification par Nfjord (Le 28/08/2012, à 14:34)
It's always a long day, 86,400 won't fit into a short.
Hors ligne
#4 Le 28/08/2012, à 15:38
- darunia_goron
Re : Connaître le type d'une interface réseau en C
La fonction __dev_get_by_name est réservée pour l'implémentation (d'où les deux underscores). De ce fait, elle n'est pas déclarée dans /usr/include/linux/netdevice.h mais uniquement dans /usr/src/linux-`uname -r`/include/linux/netdevice.h
Ton message d'erreur vient du fait que tu utilises le mauvais header. Par contre, je ne peux pas t'aider plus. Je n'ai jamais touché à du réseau à un niveau si bas.
Je serai toi, j'éplucherais les sources d'un programme comme par exemple ifconfig. La solution s'y trouve sûrement.
Hors ligne
#5 Le 28/08/2012, à 17:47
- grim7reaper
Re : Connaître le type d'une interface réseau en C
Salut,
Tout d’abord c’est pas une erreur du compilateur (il a bien trouvé la déclaration de la fonction dans les en-têtes), là c’est une erreur de l’éditeur de liens (mais je vais y revenir).
Ensuite, on préfèrera utiliser dev_get_by_name (« This can be called from any context and does its own locking. ») plutôt que __dev_get_by_name (« The reference counters are not incremented so the caller must be careful with locks. »).
Enfin (la raison de ton problème), Haleth l’a déjà évoqué :
Si, par change, tu programmes du coté kernel, y'a la fonction _get_dev_by_name
Là tu es en user space, pour accéder à cette fonction il faut faire un kernel module qui est différent d’un programme traditionnel (pas d’accès à la libc, pas de main mais un init_module, compilation particulière avec le Makefile-qui-va-bien, …).
Mais sinon, à priori cette fonction aurait pu t’aider ouais. Avec le champ type de la structure net_device, tu pouvais chopper et interpréter le type à partir des constantes kivonbien.
Hors ligne
#6 Le 28/08/2012, à 18:02
- eiger
Re : Connaître le type d'une interface réseau en C
Salut,
Une autre solution serait de passer par sysfs et libudev.
Si tu listes le contenu de /sys/class/net, tu devrais obtenir la liste de tous les devices de la classe "network".
À partir de là, tu peux aller un cran en dessous (/sys/class/net/eth3 par exemple) et extraire le type d'interface.
Ceci dit, même dans ce cas, tu devras te référer aux constantes "kivonbien" données par grim7reaper, car de nombreux attributs des devices ne sont retournés que sous forme numérique.
Un peu de lecture :
http://c-qs.blogspot.ch/2012/06/libudev … orial.html
http://www.signal11.us/oss/udev/
Hors ligne
#7 Le 29/08/2012, à 01:08
- grim7reaper
Re : Connaître le type d'une interface réseau en C
Tu parles de regarder quel fichier ?
Parce que sysfs c’est le premier truc que j’ai tenté (et Haleth aussi il me semble), mais j’ai rien de trouvé de probant.
Le fichier type semblait prometteur mais :
cat /sys/class/net/eth0/type
1
cat /sys/class/net/wlan0/type
1
Ne nous avance pas trop…
Hors ligne
#8 Le 29/08/2012, à 08:10
- eiger
Re : Connaître le type d'une interface réseau en C
J'avais en effet lu un peu trop vite la réponse de Haleth et je n'ai pas vu qu'il avait évoqué sysfs. D'autre part j'ai également zappé le fait que Nfjord s'intéressait à 802.15. La prochaine fois, je lirai moins vite ...
Le fichier type n'est en effet pas un critère sûr. De ce que je viens d'en voir, seuls quelques drivers pour 802.11 déclarent le type à ARPHRD_IEEE80211 (et encore, il faudrait également tenir compte des variantes _PRISM, etc.). La plupart se déclarent comme ARPHRD_ETHER, donc pas de différence avec une carte Ethernet filaire classique. En revanche, le subsystem 802.15.4 du noyau semble utiliser le type ARPHRD_IEEE802154 comme critère pour reconnaître une interface 802.15.4 (exemple pour les raw sockets 802.15.4 : http://lxr.free-electrons.com/source/ne … /raw.c#L78). Donc on peut peut-être tout de même s'en servir pour 802.15.4.
Sinon s'il s'agit de distinguer Ethernet et 802.11, un driver "standard" utilisant le subsystem devrait normalement créer un lien symbolique appelé "phy80211" dans /sys/class/net/wlan0 (voir http://lxr.free-electrons.com/source/ne … ore.c#L818).
Mais on n'est pas à l'abri de tomber sur un driver exotique qui fera tout autrement, voire même de tomber sur un noyau compilé sans sysfs (ceci dit sur une machine "de bureau" ça me paraît peu probable).
Donc il est vrai, ce n'est pas aussi simple.
Hors ligne
#9 Le 29/08/2012, à 09:57
- Nfjord
Re : Connaître le type d'une interface réseau en C
Peut-être que je peux récupérer le type d'interface via l'API rtnetlink ? Je me souviens l'avoir utilisée pour injecter des routes dans la table de routage depuis le userspace. D'après ce lien, il semble possible de récupérer des informations sur les interfaces (dont notamment le type de l'interface) via le message RTM_GETLINK. Je vais tester ça...
It's always a long day, 86,400 won't fit into a short.
Hors ligne
#10 Le 29/08/2012, à 10:53
- Nfjord
Re : Connaître le type d'une interface réseau en C
J'ai trouvé ici un programme C qui demande au kernel des infos sur les interfaces réseaux via l'API rtnetlink. Mais malheureusement les interfaces wifi, bluetooth et ethernet reviennent toutes avec le même ifi_type = 1 (de la struct ifinfomsg). Seule l'interface loopback a son type = 772 (ce qui correspond bien aux constantes "kivonbien")...
It's always a long day, 86,400 won't fit into a short.
Hors ligne
#11 Le 29/08/2012, à 11:35
- Haleth
Re : Connaître le type d'une interface réseau en C
Sinon, comme écrit plus haut, y'a le truc qui rocks à tout les coup: la libpcap (snif un paquet et en déduit le support physique)
Regarde dans l'API de la lib, y'a des fonctions pour te donner le type du support
Je pense que c'est la meilleure solution
Quoique la libudev me semble aussi pas mal (utilisation d'un module ?)
Ubuntu is an ancien African word which means "I can't configure Debian"
Because accessor & mutator are against encapsulation (one of OOP principles), good OOP-programmers do not use them. Obviously, procedural-devs do not. In fact, only ugly-devs are still using them.
Hors ligne
#12 Le 30/08/2012, à 14:38
- Nfjord
Re : Connaître le type d'une interface réseau en C
J'ai effectué quelques tests avec libpcap et libudev. N'étant pas un expert linux, j'ai peut-être mal fait/oublié de tester certaines choses. En tout cas, voici les résultats de ce que j'ai testé.
LIBPCAP
Il existe dans la libpcap la fonction pcap_datalink() qui retourne le link layer type du device qui est en train d'être sniffé. Je teste donc avec 3 interfaces : une ethernet, une wifi et une bluetooth. La fonction me retourne les 3x le même type : EN10MB. Cela ne permet donc pas de différencier le type d'interface physique utilisé. Tous les 3 semblent assimilés au type ethernet.
LIBUDEV
D'après ce que j'ai compris, libudev permet de faire des requêtes au kernel pour obtenir des infos sur les différents périphériques présents sur la machine. Lors d'une requête, il faut spécifier le type de périphérique dont on souhaite obtenir les infos (comme expliqué dans le tuto posté par eiger). Dans /sys/class/, il y a la liste des types de périphériques. J'y retrouve le type bluetooth qui me permet effectivement d'obtenir des infos sur mon interface bluetooth mais le type associé à cette interface est usb_device :
root@econhome:~/Desktop/find_if_type# ./udev_ex bluetooth
Device Node Path: (null)
VID/PID: 413c 8187
Dell Computer Corp
DW375 Bluetooth Module
serial: 9CB70DEAC958
type: usb_device
De plus, je n'arrive pas à lister mes périphériques réseaux 802.3 et 802.11 : lorsque j'effectue une requête avec le type net, il ne me retourne aucun résultat :
root@econhome:~/Desktop/find_if_type# ./udev_ex net
Device Node Path: (null)
Unable to find parent usb device.
J'ai l'impression que les infos récupérables via la libudev sont uniquement les infos déjà présentes dans /sys/class/. Or dans ce dossier, le type associé à mes interfaces 802.3 (/sys/class/net/eth3/type) et 802.11 (/sys/class/net/eth4/type) sont tous les deux de '1'. Donc là encore, impossible de les différencier...
It's always a long day, 86,400 won't fit into a short.
Hors ligne
#13 Le 30/08/2012, à 15:17
- Haleth
Re : Connaître le type d'une interface réseau en C
J'ai test également
Ton exemple avec la libudev ne fonctionne pas parcque tu filtres le subsystem usb, alors que les interfaces sont plutot en PCI
Dans tout les cas, j'ai trouvé, j'imagine, la solution (enfin, y'a une concordance sur toute les interfaces de tout mes PC )
Le fichier /sys/class/net/eth0/link_mode contient toujours 0 (de même que lo & mon pont ethernet)
Le fichier /sys/class/net/wlan0/link_mode contient toujours 1
Testez
1 = wireless
0 = ethernet
Ubuntu is an ancien African word which means "I can't configure Debian"
Because accessor & mutator are against encapsulation (one of OOP principles), good OOP-programmers do not use them. Obviously, procedural-devs do not. In fact, only ugly-devs are still using them.
Hors ligne
#14 Le 30/08/2012, à 17:46
- HP
Re : Connaître le type d'une interface réseau en C
# ls /sys/class/net/
eth0 lo teredo wlan0
# cat /sys/class/net/*/link_mode
0
0
0
0
cat /dev/urandom >/dev/null 2>&1 #github
Hors ligne
#15 Le 30/08/2012, à 18:14
- eiger
Re : Connaître le type d'une interface réseau en C
J'ai l'impression que les infos récupérables via la libudev sont uniquement les infos déjà présentes dans /sys/class/.
Oui, en effet, la libudev sert à parcourir le pseudo-système de fichier sysfs et à en extraire des données.
Or dans ce dossier, le type associé à mes interfaces 802.3 (/sys/class/net/eth3/type) et 802.11 (/sys/class/net/eth4/type) sont tous les deux de '1'. Donc là encore, impossible de les différencier...
Oui, c'est ce que je disais hier, il se trouve que la plupart des drivers 802.11 déclarent leur type à ARPHRD_ETHER en fonctionnement normal (en mode monitor ils semblent déclarer le type attendu, mais ce n'est pas l'état normal de l'interface), donc pas de différence avec une carte 802.3. Seule une poignée déclare le type à ARPHRD_IEEE80211.
En revanche, as-tu dans /sys/class/net/eth4/ un lien symbolique appelé phy80211 ? Si ton driver utilise le subsystem wireless standard, ce devrait être le cas.
Hors ligne
#16 Le 31/08/2012, à 09:11
- Nfjord
Re : Connaître le type d'une interface réseau en C
Dans tout les cas, j'ai trouvé, j'imagine, la solution (enfin, y'a une concordance sur toute les interfaces de tout mes PC
)
Le fichier /sys/class/net/eth0/link_mode contient toujours 0 (de même que lo & mon pont ethernet)
Le fichier /sys/class/net/wlan0/link_mode contient toujours 1
Tout comme HP, cela ne fonctionne pas dans mon cas :
# ls /sys/class/net/
bnep0 eth0 lo mlan0 pan0
# cat /sys/class/net/*/link_mode
0
0
0
0
0
En revanche, as-tu dans /sys/class/net/eth4/ un lien symbolique appelé phy80211 ? Si ton driver utilise le subsystem wireless standard, ce devrait être le cas.
Non, je n'ai pas ce lien symbolique :
# ls -la /sys/class/net/mlan0/
total 0
drwxr-xr-x 5 root root 0 Aug 31 07:54 .
drwxr-xr-x 3 root root 0 Aug 31 07:54 ..
-r--r--r-- 1 root root 4096 Aug 31 08:05 addr_len
-r--r--r-- 1 root root 4096 Aug 31 08:05 address
-r--r--r-- 1 root root 4096 Aug 31 08:05 broadcast
-r--r--r-- 1 root root 4096 Aug 31 08:05 carrier
-r--r--r-- 1 root root 4096 Aug 31 08:05 dev_id
lrwxrwxrwx 1 root root 0 Aug 31 08:05 device -> ../../../mmc0:0001:1
-r--r--r-- 1 root root 4096 Aug 31 08:05 dormant
-r--r--r-- 1 root root 4096 Aug 31 08:05 duplex
-r--r--r-- 1 root root 4096 Aug 31 08:05 features
-rw-r--r-- 1 root root 4096 Aug 31 08:05 flags
-rw-r--r-- 1 root root 4096 Aug 31 08:05 ifalias
-r--r--r-- 1 root root 4096 Aug 31 08:05 ifindex
-r--r--r-- 1 root root 4096 Aug 31 08:05 iflink
-r--r--r-- 1 root root 4096 Aug 31 07:58 link_mode
-rw-r--r-- 1 root root 4096 Aug 31 08:05 mtu
-r--r--r-- 1 root root 4096 Aug 31 08:05 operstate
drwxr-xr-x 2 root root 0 Aug 31 08:05 power
-r--r--r-- 1 root root 4096 Aug 31 08:05 speed
drwxr-xr-x 2 root root 0 Aug 31 08:05 statistics
lrwxrwxrwx 1 root root 0 Aug 31 07:54 subsystem -> ../../../../../../../../../class/net
-rw-r--r-- 1 root root 4096 Aug 31 08:05 tx_queue_len
-r--r--r-- 1 root root 4096 Aug 31 08:05 type
-rw-r--r-- 1 root root 4096 Aug 31 07:54 uevent
drwxr-xr-x 2 root root 0 Aug 31 08:05 wireless
It's always a long day, 86,400 won't fit into a short.
Hors ligne
#17 Le 31/08/2012, à 12:04
- grim7reaper
Re : Connaître le type d'une interface réseau en C
Cela dit, il semblerait que tu aies un dossier wireless
J’ai aussi ce dossier, mais il est absent pour eth0 et lo
Dernière modification par grim7reaper (Le 31/08/2012, à 12:05)
Hors ligne
#18 Le 03/09/2012, à 09:17
- Nfjord
Re : Connaître le type d'une interface réseau en C
Cela dit, il semblerait que tu aies un dossier wireless
J’ai aussi ce dossier, mais il est absent pour eth0 et lo
Mouais... Ce dossier ne contient rien de très pertinent pour mon problème. Je pourrais éventuellement faire un check de l'existence de ce dossier pour chaque interface afin de détecter les interfaces wifi mais cela ne marche pas pour le bluetooth (mes dossiers bnep0/ et pan0/ n'ont pas ce répertoire...).
Pour continuer d'avancer dans mon implémentation, j'ai pour l'instant opté pour la solution où c'est l'utilisateur qui spécifie dans un fichier de config quel est le type de chaque interface. Je parse ensuite le fichier .conf pour récupérer l'information. Mais j'aurai préféré une technique "automatique"... Merci en tout cas à tous de votre aide précieuse
It's always a long day, 86,400 won't fit into a short.
Hors ligne
#19 Le 03/09/2012, à 10:56
- grim7reaper
Re : Connaître le type d'une interface réseau en C
Oui, le contenu est pas génial.
C’est bien un test d’existence que je sous-entendais (en l’absence de phy80211).
Mais ouais, si ça n’y est pas dans bluetooth ça t’avance pas des masses.
C’est vrai que là, vu comme ça, on dirait qu’il y a rien de propre (ou alors on l’a manqué, en dernier recours il y a la lecture des sources d’un logiciel qui fait ça pour voir comment il le fait) pour faire ce que tu veux faire
Hors ligne