Professional Documents
Culture Documents
Deuxième partie
v2 Labo-Unix - http://www.labo-unix.net
2001-2002
1
La programmation réseau. Deuxième partie
Introduction 4
7 Fin 19
8 ANNEXE 19
8.1 Les structures utilsées . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Références 28
Droits de ce document
Copyright (c) 2001 labo-unix.org
Permission vous est donnée de copier, distribuer et/ou modifier ce document selon les
termes de la Licence GNU Free Documentation License, Version 1.1 ou ultérieure pu-
bliée par la Free Software Foundation ; avec les sections inaltérables suivantes :
- pas de section inaltèrable
Une copie de cette Licence est incluse dans la section appelée GNU Free Documenta-
tion License de ce document.
Introduction
Dans la première partie nous avons vu la programmation des sockets, leur utilisation
de base. Même si nous sommes maintenant capables de réaliser de véritables applications
utilisant le réseau, nous n’avons vu qu’une petite partie de ce que l’on peut faire avec des
sockets. Dans ce cours, nous allons voir comment faire des applications qui utilisent
différents protocoles IP (v4 et v6) de manière transparente. Nous allons aussi plonger
un peu plus au cœur des sockets afin de modifier leurs comportements. Nous verrons
également comment faire ses propres trames IP (ou TCP) ainsi qu’un petit aperçu de la
libpcap pour capturer des paquets et les analyser.
Les structures de données sont différentes pour IPv4 et IPv6. Ainsi si pour les sockets
IPv4 nous utilisions la structure sockaddr in pour stocker l’adresse et le service (port), il
existe la structure sockaddr in6 qui est l’équivalent pour IPv6. Ce sont deux structures
similaires mais incompatibles.
struct sockaddr_in {
u_char sin_len;
u_char sin_family; /* la famille du protocole */
u_short sin_port; /* le port au format reseau */
struct in_addr sin_addr; /* l’adresse IP au format reseau */
char sin_zero[8];
};
On voit aisément que les deux structures n’ont pas du tout la même taille. Ce qui
pose un réel problème. En effet, si nous voulons manipuler à la fois les sockets IPv4
ET IPv6, nous devons donc manipuler indépendamment des structures sockaddr in et
sockaddr in6. Dans ce cas, soit nous dupliquons le code afin d’avoir une partie traitant
les sockets IPv4 et une autre les sockets IPv6 (ce qui est très lourd) soit nous nous basons
sur quelques règles simples du langage C :
– Les structures doivent subir les mêmes règles d’alignement en mémoire.
– Le premier champ doit toujours être aligné au début de cette structure.
– Des bytes de séparation peuvent par contre être introduits par le compilateur entre
deux champs afin d’obtenir un alignement correcte pour le type concerné.
– L’ordre des éléments dans une structure doit être conservé.
– Deux valeurs du même type ont toujours les mêmes règles d’alignement et la même
taille.
Pour respecter tout cela on utilise la structure sockaddr storage. Si les structures so-
ckaddr in et sockaddr in6 sont incompatibles, il est toutefois envisageable de créer une
structure plus longue dans laquelle il sera possible de copier aussi bien des objets de
type struct sockaddr in que de type struct sockaddr in6. Il serait même judicieux de
prévoir de l’espace supplémentaire pour de futures versions pouvant nécessiter des struc-
tures plus longues (IPv7 ?). Cette longue structure se nomme sockaddr storage.
Elle est censée être capable de stocker n’importe quelle adresse et n’importe quel iden-
tifiant de service, pour n’importe quel protocole supporté par le système d’exploitation
(IPv4, IPv6, X25, . . .).
L’intérêt d’avoir une structure plus (’trop’) grande est que si nous avons réservé as-
sez d’espace pour un objet de type struct sockaddr storage, nous pouvons copier à
ce même endroit une structure sockaddr in ou une structure sockaddr in6. Le tout est
que sizeof(struct sockaddr in) < sizeof(struct sockaddr storage) et que sizeof(struct so-
ckaddr in6) < sizeof(struct sockaddr storage) soient vérifiés.
Si une application utilise la structure générique sockaddr storage au lieu de sockaddr in,
il est garanti qu’elle saura manipuler simultanément des adresses IPv4 et IPv6. Cepen-
dant, lorsque l’on a un objet de type struct sockaddr storage, il peut être très utile de
savoir quelle structure y a réellement été recopiée. Si l’on souhaite connaı̂tre le numéro
de port, par exemple, il faudra lire le champ sin port en IPv4 et le champ sin6 port en
IPv6. On ne peut pas prendre l’un pour l’autre, car ces données peuvent être stockées à
des endroits différents en mémoire, et c’est sans évoquer les adresses IP dont le format est
totalement incompatible. La solution est très simple : ajouter au début de chaque structure
le même champ, dont le rôle sera de contenir une valeur caractéristique du protocole. Ce
champ se nomme ss family (ou ss family sous linux) .
Cette composition des structures répond parfaitement à tous nos besoins. Il est pos-
sible de stocker des objets de type struct sockaddr in ou struct sockaddr in6 dans une
structure sockaddr storage. Et lorsque l’on est en présence d’un objet de ce type, nous
pouvons en connaı̂tre le protocole exact.
Celle-ci va se baser sur des indices pour essayer de remplir une structure sockaddr storage.
Elle se charge des nom de machines et de services, que ce soit IPv4 ou IPv6.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
Si getaddrinfo() renvoie une valeur non nulle, c’est qu’il y a eu une erreur. Celle-ci
peut être obtenue avec la fonction gai strerror().
Enfin, il ne faut pas oublier de libérer la place en mémoire prise par la liste chaı̂née res.
Ceci s’effectue grâce à la fonction freeaddrinfo().
1.3 Exemple
/* $Id: Socket2.tex,v 1.5 2002/02/01 00:11:02 danseurfou Exp $
*
* Il s’agit du meme client que dans la premiere partie
* du cours mais celui-ci utilise getaddrinfo() au lieu de
* gethostbyname()
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
switch(ac) {
case 3:
port = av[2];
case 2:
hostname = av[1];
case 1:
break;
default:
printf("Usage:\n\t%s [hostname [port]]\n\n", av[0]);
return -1;
}
scan = resultat;
perror("connect");
} else {
send(sd, requete, strlen(requete));
while(recv(sd, buffer, 1024, 0) > 0)
printf(buffer);
close(sd);
break;
}
close(sd);
suivant:
scan = scan->ai_next;
}
freeaddrinfo(resultat);
return 0;
}
On peut aussi par exemple vouloir changer la taille du buffer d’émission ou de réception,
pour des applications spécifiques. Mais voyons :
#include <sys/types.h>
#include <sys/socket.h>
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
s est le socket sur lequel opérer.
Les noms de paramètres au niveau du socket (donc avec level == SOL SOCKET) :
– SO DEBUG : afficher des informations de debuggage
2.1 Exemple
Lorsque l’on ferme un socket, si des données ne sont pas envoyées, elles sont per-
dues. Il y a une option très pratique avec setsockopt() qui permet d’attendre l’envoie des
données encore présentes avant de fermer le socket : SO LINGER. Nous allons faire une
fonction qui modifie ce paramètres sur notre socket.
/* sock est notre socket */
int set_option(int sock)
{
int on = 1;
if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&on, sizeof on)) {
perror("setsockopt");
return -1;
} else
return 0;
}
La fonction fcntl() (file control) permet de manipuler les descripteurs de fichier (donc
aussi de socket).
fd est le desripteur de fichier.
cmd est la commande. En fonction de cette commande, fcntl() peut prendre un troisième
paramètre : int arg.
Pour ceci, il faut d’abord créer le socket. Ensuite, grâce à fcntl(), on peut rendre le
socket non-bloquant. A partir de là, si on utilise la fonction connect(), elle ne se bloquera
pas en attendant l’établissement de la connexion. Elle va renvoyer une erreur (si les pa-
ramètres sont corrects) : EINPROGRESS qui signifie que l’opération est en cours mais
pas terminée. Pour savoir si la connexion s’est correctement passée, on pourra utiliser
les fonctions poll() ou select() en testant l’écriture sur le socket. Evidemment, on peut
toujours bloquer poll() et select() avec un timeout mais on peut aussi leur demander de
tester directement sans se bloquer (avec un timeout de 0).
Ensuite, si l’on utilise read() et que la fonction renvoie l’erreur EAGAIN, c’est qu’il
n’y a rien à lire sur le socket. Idem pour send(). On peut ainsi ne pas bloquer l’appli-
cation sur une opération de lecture ou d’écriture. Si des données sont présentes, read()
fonctionne normalement (idem pour send()).
d’envoyer le signal SIGIO à l’application lorsqu’il y aura des données à lire dessus. Dans
notre programme, nous redirigerons le signal SIGIO vers la fonction de lecture du socket.
Voyons un exemple :
int read_sock(int signal)
{
/* c’est notre fonction de lecture que je ne detaillerai pas.
* Sachez seulement que le paramètre n’est pas le socket mais
* le signal (ici SIGIO). Et n’oubliez pas que l’on utilise pas
* n’importe quelle fonction pendant la gestion d’un signal...
*/
}
/* Comme d’hab, sock est notre socket */
int set_sigio(int sock)
{
int flags = fcntl(sock, F_GETFL);
signal(SIGIO, read_sock);
/* il ne faut pas oublier de spécifier quel PID recevra
* le signal: */
fcntl(sock, F_SETOWN, getpid());
/* ensuite on demande de recevoir le SIGIO sur ce descripteur: */
fcntl(sock, F_SETFL, flags | O_ASYNC);
/* je n’ai pas gerer le eventuelles erreurs... */
}
Grâce à ces quelques lignes, le programme recevra SIGIO dès qu’il y aura des données
à lire sur le socket. Si vous répétez l’opération avec plusieurs sockets, ce sera à vous de
les différencier (grâce à poll() ou select()) pour savoir lequel attends des données qui sont
la cause du signal.
On peut remplacer IPPROTO IP par un autre protocole. Si vous voulez créer vous
même les en-têtes IP, alors il faut le spécifier au système grâce à :
#include <netinet/ip.h>
int on = 1;
setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (void *)&on, sizeof on);
A partir de là, vous pouvez envoyer les paquets grâce à la fonction sendto(). Le
deuxième paramètre va être votre paquet TCP/IP (ou UDP/IP ou ICMP). Vous devez
donc allouer une zone mémoire qui comprendra l’en-tête IP puis l’en-tête TCP puis les
données. Mais il vous faut correctement remplir les en-têtes TCP et IP dont voici les
structures (sur un FreeBSD) :
struct ip {
u_int ip_hl:4, /* header length */
ip_v:4; /* version */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
struct tcphdr {
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
u_int th_x2:4, /* (unused) */
th_off:4; /* data offset */
u_char th_flags;
u_short th_win; /* window */
u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */
};
Remarque : avec linux, le nom de la structure pour les en-tête IP est : struct iphdr.
Vous pouvez aussi très bien créer des paquets ICMP ou UDP/IP ou tout autre protocole
existant, voir même d’un protocole n’existant pas. Encore une fois le but de ce cours
n’est pas de vous expliquer le fonctionnement de TCP/IP. Nous ne rentrerons pas dans
les détails. Vous avez toutes les informations nécessaire pour faire vos paquets.
Si on peut les créer, c’est qu’on peut aussi les analyser. Et c’est beaucoup plus interes-
sant. Avec un RAW socket, on peut obtenir les paquets IP, les décortiquer, voir comment
cela fonctionne. . .et faire son propre analyseur de réseau.
Mais si vous voulez regarder passer tous les paquets qui passent sur le réseau (en tout
cas sur votre cable réseau), il va falloir le demander à la carte réseau.
Le premier paramètre de la fonction ioctl() est un descripteur ouvert. Dans notre cas
un socket, mais celà pourrait aussi être un périphérique (/dev/dsp par exemple pour mo-
difier les paramètres de la carte son). Le deuxième paramètre est le nom du paramètre à
modifier. Pour les sockets, ils sont dans le fichier < sys/sockio.h >. Mais si vous vou-
lez toucher au frame buffer, il va falloir regarder dans < sys/f bio.h > par exemple
(et pour un FreeBSD). Ou bien < sys/soundcard.h > pour la carte son. Tous les
périphériques peuvent être accédés grâce à cette fonction. Le troisième paramètre de
ioctl() est spécifique au périphérique. Dans notre cas, il s’agit d’une structure ifreq (do-
cumentée en annexe).
Maintenant vous pouvez analyser tous les paquets passant sur votre brin : vous pouvez
les recevoir avec la fonction recvfrom() et regarder comment sont constituées les trames.
N’oubliez pas de remettre la carte en mode normal à la fin du programme.
Voici les fonctions les plus utiles. N’oubliez pas d’inclure < pcap.h > et de lier avec
la libpcap (-lpcap) lors de la compilation.
Va nous renvoyer le nom d’un périphérique que l’on peut scruter. errbuf est un tampon
de taille minimum PCAP ERRBUF SIZE.
pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms,
char *ebuf);
Permet d’ouvrir un périphérique pour capturer les paquets. device est ce que nous a
renvoyé la fonction précédentes. snaplen est la taille maximum des paquets que l’on veut.
promisc détermine si la carte doit être en mode promiscuous. to ms est le temps d’attente
d’un paquet en millisecondes avant de renvoyer une erreur. ebuf est le même tampon
d’erreur que précédemment. La structure pcap t renvoyée sera passée en paramètre à
toutes les fonctions qui vont suivre. Renvoie NULL en cas d’erreur.
Fait exactement la même chose mais ne s’arrêtera que lorsqu’elle arrivera au nombre
de paquets à traiter (paramètre cnt, si -1 alors elle boucle à l’infini).
u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h);
Permet de compiler la règle str dans le filtre fp. optimize contrôle si une optimisation
sur le résultat doit être effectuée. netmask est le masque de sous-réseau de l’interface.
int pcap_setfilter(pcap_t *p, struct bpf_program *fp);
Permet de spécifier quels filtres seront utilisés pour capturer les paquets.
void pcap_freecode(struct bpf_program *);
6.6 Exemple
/* Un petit exemple de capture de paquet
*/
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
/* trouver un périphérique */
if((dev = pcap_lookupdev(errbuf)) == NULL) {
printf("%s\n",errbuf);
return -1;
}
printf("peripherique: %s\n",dev);
ptr = eptr->ether_dhost;
i = ETHER_ADDR_LEN;
printf(" Destination Adresse: ");
do{
printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
} while(--i > 0);
puts("");
ptr = eptr->ether_shost;
i = ETHER_ADDR_LEN;
printf(" Source Adresse: ");
do{
printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
} while(--i > 0);
puts("");
return 0;
}
7 Fin
J’espère que ces quelques informations vous aurons interéssées. Et que maintenant
vous êtes capables de faire des applications réseau conséquentes. La programmation C
n’est pas évidente mais lorsque l’on connait suffisamment le domaine, c’est un réel plai-
sir car il n’y a que très peu de limites. Seulement votre imagination. . .
8 ANNEXE
8.1 Les structures utilsées
Attention il s’agit des structures extrait d’un FreeBSD. Sur linux, il se peut qu’il y ait
des changements.
struct sockaddr_in6 {
u_int8_t sin6_len; /* length of this struct(sa_family_t)*/
u_int8_t sin6_family; /* AF_INET6 (sa_family_t) */
u_int16_t sin6_port; /* Transport layer port # (in_port_t)*/
u_int32_t sin6_flowinfo; /* IP6 flow information */
struct in6_addr sin6_addr; /* IP6 address */
u_int32_t sin6_scope_id; /* scope zone index */
};
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
size_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for nodename */
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */
};
struct ip {
u_int ip_hl:4, /* header length */
ip_v:4; /* version */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
struct tcphdr {
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
struct udphdr {
u_short uh_sport; /* source port */
u_short uh_dport; /* destination port */
u_short uh_ulen; /* udp length */
u_short uh_sum; /* udp checksum */
};
struct icmp {
u_char icmp_type; /* type of message, see below */
u_char icmp_code; /* type sub code */
u_short icmp_cksum; /* ones complement cksum of struct */
union {
u_char ih_pptr; /* ICMP_PARAMPROB */
struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
struct ih_idseq {
n_short icd_id;
n_short icd_seq;
} ih_idseq;
int ih_void;
struct ih_pmtu {
n_short ipm_void;
n_short ipm_nextmtu;
} ih_pmtu;
struct ih_rtradv {
u_char irt_num_addrs;
u_char irt_wpa;
u_int16_t irt_lifetime;
} ih_rtradv;
} icmp_hun;
#define icmp_pptr icmp_hun.ih_pptr
#define icmp_gwaddr icmp_hun.ih_gwaddr
#define icmp_id icmp_hun.ih_idseq.icd_id
#define icmp_seq icmp_hun.ih_idseq.icd_seq
#define icmp_void icmp_hun.ih_void
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
union {
struct id_ts {
n_time its_otime;
n_time its_rtime;
n_time its_ttime;
} id_ts;
struct id_ip {
struct ip idi_ip;
} id_ip;
struct icmp_ra_addr id_radv;
u_int32_t id_mask;
char id_data[1];
} icmp_dun;
#define icmp_otime icmp_dun.id_ts.its_otime
#define icmp_rtime icmp_dun.id_ts.its_rtime
#define icmp_ttime icmp_dun.id_ts.its_ttime
#define icmp_ip icmp_dun.id_ip.idi_ip
#define icmp_radv icmp_dun.id_radv
#define icmp_mask icmp_dun.id_mask
#define icmp_data icmp_dun.id_data
};
struct ifreq {
char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
short ifru_flags[2];
int ifru_metric;
int ifru_mtu;
int ifru_phys;
int ifru_media;
caddr_t ifru_data;
int ifru_cap[2];
} ifr_ifru;
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
#define ifr_flags ifr_ifru.ifru_flags[0] /* flags */
#define ifr_prevflags ifr_ifru.ifru_flags[1] /* flags */
#define ifr_metric ifr_ifru.ifru_metric /* metric */
#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
#define ifr_phys ifr_ifru.ifru_phys /* physical wire */
#define ifr_media ifr_ifru.ifru_media /* physical media */
#define ifr_data ifr_ifru.ifru_data /* for use by interface */
#define ifr_reqcap ifr_ifru.ifru_cap[0] /* requested capabilities */
#define ifr_curcap ifr_ifru.ifru_cap[1] /* current capabilities */
};
struct pcap_pkthdr {
struct timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
bpf_u_int32 len; /* lebgth this packet (off wire) */
}
Preamble
The purpose of this License is to make a manual, textbook, or other written document
“free” in the sense of freedom : to assure everyone the effective freedom to copy and
redistribute it, with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way to get credit for
their work, while not being considered responsible for modifications made by others.
This License is a kind of “copyleft”, which means that derivative works of the docu-
ment must themselves be free in the same sense. It complements the GNU General Public
License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because
free software needs free documentation : a free program should come with manuals provi-
ding the same freedoms that the software does. But this License is not limited to software
manuals ; it can be used for any textual work, regardless of subject matter or whether it
is published as a printed book. We recommend this License principally for works whose
purpose is instruction or reference.
The “Cover Texts” are certain short passages of text that are listed, as Front-Cover
Texts or Back-Cover Texts, in the notice that says that the Document is released under
this License.
A “Transparent” copy of the Document means a machine-readable copy, represented
in a format whose specification is available to the general public, whose contents can be
viewed and edited directly and straightforwardly with generic text editors or (for images
composed of pixels) generic paint programs or (for drawings) some widely available dra-
wing editor, and that is suitable for input to text formatters or for automatic translation
to a variety of formats suitable for input to text formatters. A copy made in an otherwise
Transparent file format whose markup has been designed to thwart or discourage sub-
sequent modification by readers is not Transparent. A copy that is not “Transparent” is
called “Opaque”.
Examples of suitable formats for Transparent copies include plain ASCII without mar-
kup, Texinfo input format, LATEX input format, SGML or XML using a publicly available
DTD, and standard-conforming simple HTML designed for human modification. Opaque
formats include PostScript, PDF, proprietary formats that can be read and edited only by
proprietary word processors, SGML or XML for which the DTD and/or processing tools
are not generally available, and the machine-generated HTML produced by some word
processors for output purposes only.
The “Title Page” means, for a printed book, the title page itself, plus such following
pages as are needed to hold, legibly, the material this License requires to appear in the title
page. For works in formats which do not have any title page as such, “Title Page” means
the text near the most prominent appearance of the work’s title, preceding the beginning
of the body of the text.
on the covers in addition. Copying with changes limited to the covers, as long as they
preserve the title of the Document and satisfy these conditions, can be treated as verbatim
copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put
the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest
onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100,
you must either include a machine-readable Transparent copy along with each Opaque
copy, or state in or with each Opaque copy a publicly-accessible computer-network lo-
cation containing a complete Transparent copy of the Document, free of added mate-
rial, which the general network-using public has access to download anonymously at no
charge using public-standard network protocols. If you use the latter option, you must
take reasonably prudent steps, when you begin distribution of Opaque copies in quantity,
to ensure that this Transparent copy will remain thus accessible at the stated location until
at least one year after the last time you distribute an Opaque copy (directly or through
your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well
before redistributing any large number of copies, to give them a chance to provide you
with an updated version of the Document.
9.4 Modifications
You may copy and distribute a Modified Version of the Document under the conditions
of sections 2 and 3 above, provided that you release the Modified Version under precisely
this License, with the Modified Version filling the role of the Document, thus licensing
distribution and modification of the Modified Version to whoever possesses a copy of it.
In addition, you must do these things in the Modified Version :
– Use in the Title Page (and on the covers, if any) a title distinct from that of the
Document, and from those of previous versions (which should, if there were any,
be listed in the History section of the Document). You may use the same title as a
previous version if the original publisher of that version gives permission.
– List on the Title Page, as authors, one or more persons or entities responsible for
authorship of the modifications in the Modified Version, together with at least five
of the principal authors of the Document (all of its principal authors, if it has less
than five).
– State on the Title page the name of the publisher of the Modified Version, as the
publisher.
– Preserve all the copyright notices of the Document.
– Add an appropriate copyright notice for your modifications adjacent to the other
copyright notices.
– Include, immediately after the copyright notices, a license notice giving the public
permission to use the Modified Version under the terms of this License, in the form
shown in the Addendum below.
– Preserve in that license notice the full lists of Invariant Sections and required Cover
Texts given in the Document’s license notice.
– Include an unaltered copy of this License.
– Preserve the section entitled “History”, and its title, and add to it an item stating at
least the title, year, new authors, and publisher of the Modified Version as given on
the Title Page. If there is no section entitled “History” in the Document, create one
stating the title, year, authors, and publisher of the Document as given on its Title
Page, then add an item describing the Modified Version as stated in the previous
sentence.
– Preserve the network location, if any, given in the Document for public access to
a Transparent copy of the Document, and likewise the network locations given in
the Document for previous versions it was based on. These may be placed in the
“History” section. You may omit a network location for a work that was published
at least four years before the Document itself, or if the original publisher of the
version it refers to gives permission.
– In any section entitled “Acknowledgements” or “Dedications”, preserve the sec-
tion’s title, and preserve in the section all the substance and tone of each of the
contributor acknowledgements and/or dedications given therein.
– Preserve all the Invariant Sections of the Document, unaltered in their text and in
their titles. Section numbers or the equivalent are not considered part of the section
titles.
– Delete any section entitled “Endorsements”. Such a section may not be included in
the Modified Version.
– Do not retitle any existing section as “Endorsements” or to conflict in title with any
Invariant Section.
If the Modified Version includes new front-matter sections or appendices that qualify
as Secondary Sections and contain no material copied from the Document, you may at
your option designate some or all of these sections as invariant. To do this, add their titles
to the list of Invariant Sections in the Modified Version’s license notice. These titles must
be distinct from any other section titles.
You may add a section entitled “Endorsements”, provided it contains nothing but en-
dorsements of your Modified Version by various parties – for example, statements of peer
review or that the text has been approved by an organization as the authoritative definition
of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up
to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified
Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added
by (or through arrangements made by) any one entity. If the Document already includes
a cover text for the same cover, previously added by you or by arrangement made by the
same entity you are acting on behalf of, you may not add another ; but you may replace
the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission
to use their names for publicity for or to assert or imply endorsement of any Modified
Version.
clude in the combination all of the Invariant Sections of all of the original documents,
unmodified, and list them all as Invariant Sections of your combined work in its license
notice.
The combined work need only contain one copy of this License, and multiple identical
Invariant Sections may be replaced with a single copy. If there are multiple Invariant
Sections with the same name but different contents, make the title of each such section
unique by adding at the end of it, in parentheses, the name of the original author or
publisher of that section if known, or else a unique number. Make the same adjustment
to the section titles in the list of Invariant Sections in the license notice of the combined
work.
In the combination, you must combine any sections entitled “History” in the various
original documents, forming one section entitled “History” ; likewise combine any sec-
tions entitled “Acknowledgements”, and any sections entitled “Dedications”. You must
delete all sections entitled “Endorsements.”
9.8 Translation
Translation is considered a kind of modification, so you may distribute translations of
the Document under the terms of section 4. Replacing Invariant Sections with translations
requires special permission from their copyright holders, but you may include translations
of some or all Invariant Sections in addition to the original versions of these Invariant
Sections. You may include a translation of this License provided that you also include the
original English version of this License. In case of a disagreement between the translation
and the original English version of this License, the original English version will prevail.
9.9 Termination
You may not copy, modify, sublicense, or distribute the Document except as expressly
provided for under this License. Any other attempt to copy, modify, sublicense or distri-
bute the Document is void, and will automatically terminate your rights under this Li-
cense. However, parties who have received copies, or rights, from you under this License
will not have their licenses terminated so long as such parties remain in full compliance.
Références
[1] http ://www.whitefang.com/rin/