http://www.sikurezza.org/devel/msg00122.html


Archivio: devel@sikurezza.org
Soggetto: Re: recvmsg()
Mittente: Mauro Tortonesi
Data: 19 May 2002 20:49:01 -0000
On Fri, 17 May 2002, Kundera wrote:

> Ciao a tutti, vorrei sapere sta cosa, utilizzando un 
> sok=socket(AF_INET6,SOCK_RAW,IPPROTO_ICMPV6) e la n=recvmsg(sok,&msg,0) 
> l'indirizzo ipv6 del pacchetto in arrivo dove viene messo!?


dalla manpage di recvmsg:

The recvmsg call uses a msghdr structure to minimize the number of 
directly supplied parameters.  This structure has the following form, 
as defined in <sys/socket.h>:

              struct msghdr {
                  void         * msg_name;     /* optional address */
                  socklen_t    msg_namelen;    /* size of address */
                  struct iovec * msg_iov;      /* scatter/gather array */
                  size_t       msg_iovlen;     /* # elements in msg_iov */
                  void         * msg_control;  /* ancillary data, see below */
                  socklen_t    msg_controllen; /* ancillary data buffer len */
                  int          msg_flags;      /* flags on received message */
              };

Here msg_name and msg_namelen specify the source  address  if  the socket  
is  unconnected; msg_name  may  be  given  as a null pointer if no names are 
desired or required.  The fields msg_iov and msg_iovlen describe scatter-gather 
locations, as discussed  in  readv(2). The field  msg_control,  which  has length 
msg_controllen, points to a buffer for other protocol control related messages or 
miscellaneous ancillary data. When recvmsg is  called,  msg_controllen should 
contain the length of the available buffer in msg_control; upon return from a
successful call it will contain the length of the control message sequence.


quindi basta fare:


/* occhio ai jumbo datagrams!!! non e' detto che un buffer di 64kb sia 
 * sufficiente */
const size_t BUFFER_LENGHT = 65536;

int ret;
uint8_t *my_buffer;
struct msghdr msg;
struct iovec iov;
struct sockaddr_storage ss;
struct sockaddr_in6 *sin6;

memset(&msg, 0, sizeof(msg));

my_buffer = (uint8_t *)malloc(BUFFER_LENGTH);
if (my_buffer == NULL) exit(EXIT_FAILURE);

/* qui setti correttamente il buffer di destinazione */
iov.iov_base = my_buffer;
iov.iov_len = BUFFER_LENGHT;

msg.msg_name = &ss;
msg.msg_namelen = sizeof(ss);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;

ret = recvmsg(sok, &msg, 0);

/* qui controlli che non ci siano stati errori */
...

sin6 = (struct sockaddr_in6 *)&ss;


e a questo punto ti ritrovi nella struttura sin6 (e piu' precisamente nel 
campo sin6_addr) l'indirizzo ipv6 del mittente. comunque se non vuoi 
allocare un buffer di 128 byte (sizeof(struct sockaddr_storage) ritorna 
128 bytes) solo per ottenere l'indirizzo ipv6 del mittente puoi procedere 
alla estrapolazione dell'indirizzo ipv6 del mittente utilizzando un
altro metodo (molto piu' complesso) previsto dallo rfc2292, che fa uso 
degli "ancillary data objects". vedi piu' sotto.


> ho anche a disposizione l'header ipv6 in arrivo da qualche parte? 

no, la funzione recvmsg _NON_ ti restituisce l'intero pacchetto ipv6
(al contrario di ipv4). dal draft-ietf-ipngwg-rfc2292bis-07.txt (che 
e' destinato a sostituire lo rfc2292) sezione 3, pagina 19:


3.  IPv6 Raw Sockets

   [...]

   Another difference from IPv4 raw sockets is that complete packets
   (that is, IPv6 packets with extension headers) cannot be sent or
   received using the IPv6 raw sockets API.  Instead, ancillary data
   objects are used to transfer the extension headers and hoplimit
   information, as described in Section 6.  Should an application need
   access to the complete IPv6 packet, some other technique, such as the
   datalink interfaces BPF or DLPI, must be used.


pertanto la situazione si complica enormemente. innanzi tutto devi 
dire alla socket di fornirti i dati sul mittente:

int on = 1;
setsockopt(sok, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));


poi devi preparare un buffer per gli ancillary data objects restituiti da 
recvmsg, e quando ricevi un pacchetto devi andare ad analizzare la struttura 
in6_pktinfo che ti viene restituita seguendo la seguente procedura:


/* 1kb e' anche troppo, ma meglio stare sul sicuro */
const size_t ADO_BUF_SIZE = 1024;
const size_t BUFFER_LENGHT = 65536;

int ret;
uint8_t *ado_buffer;
uint8_t *my_buffer;
struct msghdr msg;
struct iovec iov;
int found = 0;
struct in6_pktinfo info;
struct cmsghdr *cm;
struct in6_addr sender_address;

ado_buffer = (uint8_t *)malloc(ADO_BUF_SIZE);
if (ado_buffer == NULL) exit(EXIT_FAILURE);

my_buffer = (uint8_t *)malloc(BUFFER_LENGTH);
if (my_buffer == NULL) exit(EXIT_FAILURE);

/* qui setti correttamente il buffer di destinazione */
iov.iov_base = my_buffer;
iov.iov_len = BUFFER_LENGHT;

memset(&msg, 0, sizeof(msg));

msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = ado_buffer;
msg.msg_controlen = ADO_BUF_SIZE;

ret = recvmsg(sok, &msg, 0);

/* qui controlli che non ci siano stati errori */
...

for (cm = CMSG_FIRSTHDR(&msg); cm != NULL; cm = CMSG_NXTHDR(&msg, cm)) {
	if (cm->cmsg_level == IPPROTO_IPV6 &&
            cm->cmsg_type == IPV6_PKTINFO &&
            cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
		info = *(struct in6_pktinfo*)CMSG_DATA(cm);
		found = 1;
		break;
	}
}

sender_address = info.ipi6_addr;


spero di essere stato chiaro anche se sono almeno due anni che non uso
le raw socket.

comunque la tua domanda mi sembra un po' off-topic per questa lista. ti 
consiglio di dare un'occhiata al mio sito:

http://project6.ferrara.linux.it

che si occupa esclusivamente di ipv6 e di iscriverti a qualcuna delle 
nostre mailing list (ad esempio project6-it e projec6-devel). 



p.s. scusa la mia insana curiosita', ma che tipo di software stai 
     scrivendo? l'ultima volta che ho lavorato sulle raw socket icmpv6 e' 
     stato quando ho fatto il porting del ping di netkit-base ad ipv6 ;-)


-- 
Aequam memento rebus in arduis servare mentem...

Mauro Tortonesi			mauro@ferrara.linux.it
Ferrara Linux User Group	http://www.ferrara.linux.it
Project6 - IPv6 for Linux	http://project6.ferrara.linux.it


________________________________________________________
http://www.sikurezza.org - Italian Security Mailing List


'Linux > C/C++' 카테고리의 다른 글

LFS (Large File Support)  (0) 2012.07.11
C 언어 레퍼런스 - setvbuf 함수  (0) 2012.07.11
Socket Programming (sendmsg(), recvmsg() example)  (0) 2012.07.11
sendmsg(2) - Linux man page  (0) 2012.07.11
recvmsg(2) - Linux man page  (0) 2012.07.11