Bonjour à tous !

Je souhaite créer un programme qui doit envoyer des paquets ICMPv6 au niveau d'un lien local (via des Sockets RAW), en remplissant des structures Ethernet, IPv6 et ICMPv6. Avant de remplir ces structures, mon programme doit envoyer une trame ICMPv6 Neighbor Sollicitation pour récupérer l'adresse MAC du destinataire (cela remplace le protocole ARP pour ceux qui l'ignore ). Mais voilà, c'est là que je bloque. Je rencontre un problème lors de l'envoie du paquet ICMPv6 Neigbor Sollicitation.
Ci-dessous vous trouverez le code de mon programme, suivie des explications sur celui-ci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>		// Low-level access network devices
#include <netpacket/packet.h>
#include <net/if.h>		// Struct ifreq
#include <net/ethernet.h>	// Ethernet header
#include <netinet/in.h>		// Structure in6_addr
#include <netinet/ip6.h>	//Header IPv6
#include <netinet/icmp6.h>	// Header ICMPv6 
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
typedef int SOCKET;
 
// Constantes
#define BUFFER_SIZE 1024
#define PAYLOAD_SIZE 10
#define MAC_SIZE 6
 
// Functions
void getLinkLocalAddress(const char *);
void getLocalMacAddress(const char*, unsigned char*);
void sendNeighborSollicitation(struct in6_addr, struct in6_addr, const char*);
int getInterfaceIndex(const char *);
int main(int argc, char *argv[]) {
	char buffer[sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + PAYLOAD_SIZE];
	struct ip6_hdr *i6 = (struct ip6_hdr*)buffer;	
	struct icmp6_hdr *icmp6 = (struct icmp6_hdr*)(buffer + sizeof(struct ip6_hdr));
	char *payload = buffer + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
 
	// Address IPv6
	struct in6_addr ip_src;
	struct in6_addr ip_dst;
	SOCKET s;
	int sockopt=1;
	struct sockaddr_in6 i;
	int n=0; // Number of bytes send
	int index=0; // Index pour remplir le payload
	int size_header = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); // Taille de l'en-tête IPv6 + ICMPv6
	int count=0; // Number of packets to sends
 
	// Pour l'affichage des adresses IPv6
	char src_straddr[INET6_ADDRSTRLEN];
	char dst_straddr[INET6_ADDRSTRLEN];
 
	if(argc < 2 || argc > 3) {
		printf("usage %s : <ip dest> <interface out>\n", argv[0]);
		return;
	}
 
	// On creer notre socket RAW
	s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
 
	if(s == INVALID_SOCKET) {
		printf("Error socket\n");
		return;
	}
 
	// On configure les options socket
	// On indique qu'on utilise nos propres en-tête IP
	/*if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &sockopt, sizeof(sockopt)) == -1) {
		printf("Error socket opt\n");
		return;
	}*/
 
	// On initialise notre buffer d'envoie à 0
	memset(buffer,0,size_header + PAYLOAD_SIZE);
 
	// On remplie nos structure in6_addr pour les adresses IPv6
	/* IPv6 src de lien local : pour l'instant, c'est construit en dur */
	ip_src.s6_addr[0]=0xfe;
	ip_src.s6_addr[1]=0x80;
	ip_src.s6_addr[2]=0x00;
	ip_src.s6_addr[3]=0x00;
	ip_src.s6_addr[4]=0x00;
	ip_src.s6_addr[5]=0x00;
	ip_src.s6_addr[6]=0x00;
	ip_src.s6_addr[7]=0x00;
	ip_src.s6_addr[8]=0x02;
	ip_src.s6_addr[9]=0x25;
	ip_src.s6_addr[10]=0x69;
	ip_src.s6_addr[11]=0xaa;
	ip_src.s6_addr[12]=0xcc;
	ip_src.s6_addr[13]=0x8a;
	ip_src.s6_addr[14]=0xfa;
	ip_src.s6_addr[15]=0xe1;
 
	// Initialize to 0 the variables
	memset(src_straddr, 0, INET6_ADDRSTRLEN);
	memset(dst_straddr, 0, INET6_ADDRSTRLEN);
 
	/* IPv6 de destination */
	inet_pton(AF_INET6, argv[1], &ip_dst); // Convert char* to in6_addr
	inet_ntop(AF_INET6, &ip_dst, dst_straddr, INET6_ADDRSTRLEN); // Convert struct ip_dst to string in dst_straddr
 
	// On configure notre sockaddr
	i.sin6_family=AF_INET6;	
	i.sin6_flowinfo=0;
	i.sin6_addr=ip_dst; 
	i.sin6_port=0;
	i.sin6_scope_id=0;
 
	/****** Ethernet Header ******/
	// On récupère l'adresse MAC de destination en envoyant une trame ICMPv6 Neighbor Sollicitation
	sendNeighborSollicitation(ip_src, ip_dst, argv[2]);
 
	/*
		Ici y'a du code, mais c'est pas à ce niveau que le problème survient.
		L'envoie de la trame ICMPv6 Neighbor Sollicitation se fait dans la fonction sendNeighborSollicitation(...)
	*/
 
	// On ferme notre socket
	close(s);
 
	return;
}
/* Cete fonction récupère l'adresse IPv6 de lien de locale de l'interface */
void getLinkLocalAddress(const char *iface) {
 
}
/* Cette fonction récupère l'adresse MAC de l'interface 'iface' */
void getLocalMacAddress(const char *iface, unsigned char *mac) {
	struct ifreq if_mac;
	SOCKET s;
	int i;
 
	s=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	if(s == INVALID_SOCKET) return;
 
	memset(&if_mac, 0, sizeof(struct ifreq));
	strcpy(if_mac.ifr_name, iface);
	if_mac.ifr_addr.sa_family=AF_INET;
	if(ioctl(s, SIOCGIFHWADDR, &if_mac)<0) return;
 
	memcpy(mac, if_mac.ifr_hwaddr.sa_data, MAC_SIZE);
 
	close(s);
}
/* Cette fonction envoie un paquet ICMPv6 Neighbor Sollicitation à tous les hôtes du lien local
L'adresse IPv6 est type IPv6 Sollicitation (FF02::1:ffxx:xxxx) */
void sendNeighborSollicitation(struct in6_addr ip_src, struct in6_addr ip_dst, const char *iface) {
	// Buffer d'envoie
	//char buffer[sizeof(struct ether_header)+sizeof(struct ip6_hdr)+sizeof(struct icmp6_hdr)+sizeof(nd_neighbor_solicit)];
	char buffer[sizeof(struct ether_header)+sizeof(struct ip6_hdr)+sizeof(struct nd_neighbor_solicit)];
	// Structures for packets
	struct ether_header *eh = (struct ether_header*)buffer;
	struct ip6_hdr *ih = (struct ip6_hdr*)(buffer + sizeof(struct ether_header));
	//struct icmp6_hdr *ich = (struct icmp6_hdr*)(buffer + sizeof(struct ip6_hdr) + sizeof(struct ether_header));
	struct nd_neighbor_solicit *neighbor_solicit = (struct nd_neighbor_solicit*)(buffer+sizeof(struct ether_header)+sizeof(struct ip6_hdr));
	struct in6_addr ip_sollicited; // Structure pour IPv6 address sollicited
	struct sockaddr_ll packet; 
	struct packet_mreq multipacket;
	// Contiendra l'adresse MAC source
	unsigned char mac_src[MAC_SIZE];
	int i,n,ifindex;
	// Variables pour afficher les adresses IPv6
	char str_ipsrc[INET6_ADDRSTRLEN];
	char str_ipdst[INET6_ADDRSTRLEN];
	char str_ipsollicited[INET6_ADDRSTRLEN];
	// On récupère l'adresse MAC de l'interface
	getLocalMacAddress(iface, mac_src);
 
	// On créer socket
	SOCKET s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if(s == INVALID_SOCKET) return;
 
	// On récupère l'index de l'interface
	ifindex=getInterfaceIndex(iface);
 
	// Actve multicast packet
	memset(&multipacket, 0, sizeof(struct packet_mreq));
	multipacket.mr_ifindex=ifindex;
	multipacket.mr_type=PACKET_MR_MULTICAST;
	multipacket.mr_alen=ETH_ALEN;
	multipacket.mr_address[0]=0x33;
	multipacket.mr_address[1]=0x33;
	multipacket.mr_address[2]=ip_dst.s6_addr[12];
	multipacket.mr_address[3]=ip_dst.s6_addr[13];
	multipacket.mr_address[4]=ip_dst.s6_addr[14];
	multipacket.mr_address[5]=ip_dst.s6_addr[15];
 
	if(setsockopt(s, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &multipacket, sizeof(struct packet_mreq)) < 0) {
		perror("setsockopt()");
		return;
	}
 
	// Initialise buffer
	memset(buffer, 0, sizeof(struct ether_header)+sizeof(struct ip6_hdr)+sizeof(struct nd_neighbor_solicit));
 
	/****** On remplie l'en-tête Ethernet ******/
	// MAC Address dst : Multicast IPv6
	eh->ether_dhost[0] = 0x33;
	eh->ether_dhost[1] = 0x33;
	eh->ether_dhost[2] = ip_dst.s6_addr[12];
	eh->ether_dhost[3] = ip_dst.s6_addr[13];
	eh->ether_dhost[4] = ip_dst.s6_addr[14];
	eh->ether_dhost[5] = ip_dst.s6_addr[15];
	// Mac address local (source)
	eh->ether_shost[0] = mac_src[0];
	eh->ether_shost[1] = mac_src[1];
	eh->ether_shost[2] = mac_src[2];
	eh->ether_shost[3] = mac_src[3];
	eh->ether_shost[4] = mac_src[4];
	eh->ether_shost[5] = mac_src[5];
 
	// Affichage MAC Address src/dst
	printf("MAC dst : ");
	for(i=0;i<ETH_ALEN;i++) printf("%x:", eh->ether_dhost[i]);
	printf("\nMAC src : ");
	for(i=0;i<ETH_ALEN;i++) printf("%x:", eh->ether_shost[i]);
	printf("\n");
 
	// Prochaine en-tête (IPv6)
	eh->ether_type = htons(ETHERTYPE_IPV6);
 
	/****** On remplie la structure IPv6 ******/
	ih->ip6_vfc = 6 << 4;
	ih->ip6_plen = sizeof(struct icmp6_hdr);
	ih->ip6_nxt = ND_NEIGHBOR_SOLICIT; 	
	/* IPv6 source address */
	ih->ip6_src = ip_src;
	/* IPv6 dest address : IPv6 sollicited */
	memset(&ip_sollicited, 0, INET6_ADDRSTRLEN);	
	ip_sollicited.s6_addr[0] = 0xff;
	ip_sollicited.s6_addr[1] = 0x02;
	ip_sollicited.s6_addr[2] = 0x00;
	ip_sollicited.s6_addr[3] = 0x00;
	ip_sollicited.s6_addr[4] = 0x00;
	ip_sollicited.s6_addr[5] = 0x00;
	ip_sollicited.s6_addr[6] = 0x00;
	ip_sollicited.s6_addr[7] = 0x00;
	ip_sollicited.s6_addr[8] = 0x00;
	ip_sollicited.s6_addr[9] = 0x00;
	ip_sollicited.s6_addr[10] = 0x00;	
	ip_sollicited.s6_addr[11] = 0x01;	
	ip_sollicited.s6_addr[12] = 0xff;
	ip_sollicited.s6_addr[13] = ip_dst.s6_addr[13];
	ip_sollicited.s6_addr[14] = ip_dst.s6_addr[14];
	ip_sollicited.s6_addr[15] = ip_dst.s6_addr[15];
 
	ih->ip6_dst=ip_sollicited;
 
	// Affichage IP source and dest
	printf("IP Src : %s\n", inet_ntop(AF_INET6, &ip_src, str_ipsrc, INET6_ADDRSTRLEN));
	printf("IP Dst : %s\n", inet_ntop(AF_INET6, &ip_dst, str_ipdst, INET6_ADDRSTRLEN));
	printf("IP Sollicited : %s\n\n", inet_ntop(AF_INET6, &ip_sollicited, str_ipsollicited, INET6_ADDRSTRLEN));	
 
	/****** On construit l'en-tête ICMPv6 ******/
	/*ich->icmp6_type=ICMP6_ECHO_REQUEST;
	ich->icmp6_code=ND_NEIGHBOR_SOLICIT;
	ich->icmp6_cksum=0;*/
 
	/* On remplie l'en-tête Neighbor Sollicitation */
	neighbor_solicit->nd_ns_type=ICMP6_ECHO_REQUEST;
	neighbor_solicit->nd_ns_code=ND_NEIGHBOR_SOLICIT;
	neighbor_solicit->nd_ns_cksum=0;
	neighbor_solicit->nd_ns_target=ip_sollicited;
 
	// Construct sockaddr_ll
	memset(&packet, 0, sizeof(struct sockaddr_ll));	
	packet.sll_family=PF_PACKET;
	//packet.sll_protocol=htons(ETH_P_IPV6);
	//packet.sll_pkttype=PACKET_MULTICAST;
	packet.sll_halen=ETH_ALEN;
	packet.sll_ifindex=ifindex;
	packet.sll_addr[0]=0x33;
	packet.sll_addr[1]=0x33;
	packet.sll_addr[2]=ip_dst.s6_addr[12];
	packet.sll_addr[3]=ip_dst.s6_addr[13];
	packet.sll_addr[4]=ip_dst.s6_addr[14];
	packet.sll_addr[5]=ip_dst.s6_addr[15];
 
	// On affiche l'adresse MAC du sockaddr_ll
	for(i=0;i<ETH_ALEN;i++) printf("%x:", packet.sll_addr[i]);
	printf("\n");
 
	// On envoie 10 fois notre paquet ICMPv6 Neighbor Sollicitation
	for(i=0;i<10;i++) {
		n=sendto(s, buffer, sizeof(buffer), 0, (struct sockaddr*)&packet, sizeof(packet));
		if( n > 0) printf("Sending packet\n");
		else perror("sendto()");
	}
 
	// Close socket
	close(s);
}
/* Cette fonction récupère l'index de l'interface */
int getInterfaceIndex(const char *iface) {
	struct ifreq device;
	SOCKET s;
 
	s=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	if(s == INVALID_SOCKET) return;
 
	strcpy(device.ifr_name, iface);
 
	if(ioctl(s, SIOCGIFINDEX, &device) < 0) return;
	return device.ifr_ifindex;
}
Un peu d'explication sur mon programme :
Tout d'abord, mon programme récupère l'adresse IPv6 et l'interface de sortie via les paramètres de la fonction main(...), puis je fait appel à la fonction sendNeighborSollicitation(...) pour récupérer l'adresse MAC de destination.
Dans la fonction sendNeighborSollicitation(), je remplie la structure Ethernet avec l'adresse MAC source récupérer via la fonction getLocalMacAddress(...), et l'adresse MAC de destination (Adresse de multicast 33:33: xx: xx: xx: xx). Je remplie ensuite la structure pour l'IPv6 avec l'adresse IPv6 source (indiquer en dur dans mon code), et l'adresse IPv6 de destination qui est une adresse IPv6 sollicitée (FF02::1:ffxx: xxxx, où 'x', sont les 24 derniers bits de l'adresse IPv6 de destination). Ensuite, je remplie la structure ICMPv6 Neighbor Sollicitation, puis j'envoie mon paquet.
Mais voilà, c'est là que sa coince. Lors de l'envoie de mon paquet, sendto(...) me renvoie bien le nombre d'octet qu'il à transmit (la taille de mon char buffer[...]), et lorsque je capture mes paquets via Wireshark (effectuer depuis la machine d'où se situe mon programme), j'ai ce type de paquet qui s'affiche 10 fois (du à la boucle for(...)) :
Nom : wirehark.png
Affichages : 293
Taille : 11,1 Ko
Comme vous pouvez le voir, se n'est pas le résultat escompter..., et je fait appel à vous, car j'avoue de pas trouver la solution, et je suis actuellement dans l'impasse.

Si vous avez d'autre questions, car je n'ai pas était assez claire dans mes explications, où des choses que vous comprenez pas dans mon code, n'hésiter pas à me demander, je tâcherais d'y répondre un peu mieux

Pour information je suis sous une Debian jessie.

Je vous remercie d'avance de votre aide qui pourrais m'aider à avancer mon programme.

Cordialement,
vegnagun