.oO Phrack 49 Oo. Volume Seven, Issue Forty-Nine 15 of 16 Scan de post sans drapeau SYN / Uriel Maimon (lifesux@cox.org) --------------------------------------------------------- Introduction : -------------- Au fil du temps, il y a eu une demande croissance pour savoir quels services un hôte propose. Le champ de recherche du scan de port s'est ouvert pour fournir une solution à ce besoin. Au départ, les implémentations comme SATAN se connectaient à chaque port en établissant une connexion TCP complète (via les trois étapes du "three-way-handshake"). Le bon côté, c'est que celui qui scanne n'a pas besoin de construire ses paquets IP puisqu'il utilise les appels systèmes standards, et n'a pas besoin d'accès root (en général, il faut un uid 0 pour utiliser SOCK_RAW, /dev/bpf, /dev/nit et autres du genre). Le mauvais côté est qu'elle est facilement détectable et empêchée par plusieurs méthodes, la plus connue étant le TCP Wrapper de Wietse Venema. L'étape suivante a donc été le SYN-scan ou "scan par ouverture partielle" qui implique qu'une connexion TCP complète n'est jamais établie. L'établissement d'une connexion TCP se fait en trois phases: le client commence par envoyer un paquet TCP avec le drapeau SYN, le serveur envoie ensuite un paquet avec les drapeaux SYN et ACK si le port est ouvert, le drapeau RST sinon (pour fermer la connexion). La troisième phase clot la négociation lorsque le client envoie un paquet TCP avec le drapeau ACK (tous ces paquets ont bien sûr des valeurs spécifiques de séquence, d'acquitement, etc.). La connexion est alors ouverte. Un "SYN-Scanner" n'envoie que le premier de ces paquets, le paquet SYN, et attend un SYN|ACK ou un RST. Lorsqu'il reçoit l'un ou l'autre, il sait si le port est ouvert ou non. L'avantage majeur de cette méthode est qu'elle n'est pas détectée par les systèmes de base comme "SATAN detectors" ou le TCP Wrapper de Wietse. Les principaux problèmes sont : 1) Cette méthode peut quand même être détectée par les systèmes de surveillance qui enregistrent les tentatives de connexion SYN ("tcplog" par exemple), et peuvent être détectées par netstat(1). 2) Le client, sur la plupart des systèmes d'exploitation, a besoin de construire le paquet IP complètement pour ce genre de scan (je n'en connais aucun qui n'en ai pas besoin, si vous en connaissez, faites-le moi savoir). On a donc besoin d'un accès à SOCK_RAW (getprotbyname("raw"); sur la plupart des systèmes) ou /dev/bpf (Berkeley Packet Filter), /dev/nit ("Network Interface Tap" de Sun), etc. Ce qui nécessite la plupart du temps un accès root ou un groupe privilégié. 3) La plupart des pare-feu qui filtreraient ce scan ne filtreront pas le ScanFurtif(©) (tous droits réservés au vicieux petit poulet fictif (kasher) rouge grillé délicieux SELARL). Note à propos des scans de port UDP: ------------------------------------ Dans cet article, je vais ignorer les scans de port UDP pour la simple raison qu'ils n'ont pas la complexité de TCP ; ce n'est pas un protocole de canal de communication avec connexion mais d'échange de paquet sans connexions. Pour scanner un port UDP pour voir s'il écoute, envoyez simplement un paquet UDP à ce port. Vous recevrez un paquet ICMP "Port Destination Injoignable" s'il n'écoute pas. Au mieux de ce que je sache, c'est la seule manière de scanner des ports UDP. Je serais heureux d'en apprendre une nouvelle -- si quelqu'un connaît une autre méthode, envoyez-moi un courriel. Le ScanFurtif ------------- Cette méthode se base sur du mauvais code réseau dans le code BSD. Et puisque la plupart du code réseau de la plupart des systèmes d'aujourd'hui vient du code réseau de BSD, ou une variante, ça marche pour la plupart des systèmes. (Avec l'exception évidente des routeurs Cisco... (mon Dieu! un BON code réseau ?!?@$! Hérésie ! Alan Cox va avoir une attaque s'il entend ça!) Désavantages de cette technique : 1) Le paquet IP doit être construit à la main. Je n'y vois pas de solution, à moins qu'un appel système non-sûr soit ajouté. Mais ça n'est pas nécessaire puisque les services SLIP/PPP sont si courant qu'avoir un accès root sur une machine n'est plus un problème. 2) Cette méthode se base sur un bogue dans le code réseau. Il peut, et va probablement être corrigé dans un futur proche. (Shhhhh. Ne le dite pas à Aan Cox. Il hait le bon code réseau efficient.) OpenBSD, par exemple, l'a déjà corrigé. 3) Le résultat d'un scan n'est jamais connu, et il n'est pas constant entre différentes architectures et systèmes. Il n'est pas fiable. Principaux avantages de cette méthode sur les autres : 1) Difficile à surveiller. Même une fois cette méthode connue, il est difficile de trouver une méthode de surveillance sans corriger le bug. 2) Peut contourner certains pare-feu. 3) Ne sera pas listé par netstat(1). 4) N'utilise aucun des paquets d'un établissement de session TCP. 5) Plusieurs variantes autour du même principe. L'algorithme : J'utilise des paquets TCP avec les drapeaux ACK et FIN. Je les utilise tout simplement parce qu'ils devraient systématiquement générer une réponse RST sur une connexion qui n'est pas ouverte. A partir d'ici, je ferai référence à ces paquets simplement en tant que paquets "RST", "FIN", ou "ACK". Méthode #1 : Envoyer un paquet FIN. Si la machine destination retourne un RST, c'est que le port est fermé. S'il n'y a aucune réponse RST, c'est que le port est en écoute. Le fait que cette méthode marche sur autant d'hôtes est un triste témoignage sur l'état du code réseau dans la plupart des noyaux des systèmes d'exploitation. Méthode #2 : Envoyer un paquet ACK. Si le paquet en réponse a un ttl plus petit que les autres paquets RST reçus, ou si la taille de la fenêtre est plus grande que zéro, le port est probablement en écoute. (Note sur le ttl : Ce bogue est presque incompréhensible. Toutes les fonctions de la pile IP sont des fonctions de routage. À chaque fois que l'interface réseaux change, le ttl décrémente d'un. Si le port est ouvert, le ttl a été décrémenté lorsque le paquet a été reçu et examiné et lorsque le système a remarqué que ce n'était pas un SYN, il donc répondu avec un RST ayant un ttl inférieur par rapport à un port fermé. Mais ce n'est peut être pas pour ça. Je n'ai pas vérifié cette théorie sur le code réseau de BSD. Dites moi si je me trompe. Uriel [Traduction par tbowan @ arsouyes.org] /* * scantcp.c * * version 1.32 * * Scans à la recherche de ports TCP ouverts en leur envoyant des paquets et * en attendant les réponses. Se base sur les specs de TCP et quelques bogues * d'implémentation vu en regardant des logs de tcpdump. * * Comme toujours, des portions réutilisées (parfois avec quelques stops) de * n00k.c (Wow, ce petit bout de code que j'ai écrit il y a si longtemps * continue à me servir d'interface de base pour des trucs cools plus * récents). * * Technique : * * 1. Scan actif : non supporté - pourquoi s'en soucier. * * 2. Scan par ouverture partielle : * a. Envoyer un SYN, * b. Si on reçoit un SYN|ACK, renvoyer un RST, le port écoute, * c. Si on reçoit un RST, le port n'écoute pas. * * 3. Scan furtif : (fonctionne sur presque tous les systèmes testés) * a. Envoyer un FIN, * b. Si on reçoit un RST, le port n'écoute pas, * c. Sinon, le port écoute probablement. * * (Ce bogue dasn la plupart des implémentation n'est pas limitée à FIN; en * fait, d'autres combinaisons de drapeaux auront des effets similaires. Le * FIN a été sélectionné ici parce qu'il retourne toujours un RST lorsque le * port n'écoute pas, et le code était déjà prêt pour gérer les RST en ne * me prenant que 2 minutes pour l'ajouter) * * 4. Scan furtif : (ne fonctionnera pas sur tous les systèmes) * a. Envoyer un ACK, * b. Attendre un RST, * c. Si le TTL est inférieur ou la fenêtre à 0, le port écoute peut être. * * (Ce scan furtif a été créé après avoir regardé des logs de tcpdump avec ces * symptomes. Le ttl qui décrémente d'un semble apparaître sur Linux * uniquement, la taille de fenêtre différente de 0 sur les ACK semble * exister sur tous les BSD.) * * CHANGEMENTS: [Non traduit] * ------------ * 0. (v1.0) * - First code, worked but was put aside since I didn't have time nor * need to continue developing it. * 1. (v1.1) * - BASE CODE MOSTLY REWRITTEN (the old code wasn't that maintainable) * - Added code to actually enforce the usecond-delay without usleep() * (replies might be lost if usleep()ing) * 2. (v1.2) * - Added another stealth scanning method (FIN). * Tested and passed on: * AIX 3 * AIX 4 * IRIX 5.3 * SunOS 4.1.3 * System V 4.0 * Linux * FreeBSD * Solaris * * Tested and failed on: * Cisco router with services on ( IOS 11.0) * * 3. (v1.21) * - Code commented since I intend on abandoning this for a while. * * 4. (v1.3) * - Resending for ports that weren't replied for. * (took some modifications in the internal structures. this also * makes it possible to use non-linear port ranges * (say 1-1024 and 6000)) * * 5. (v1.31) * - Flood detection - will slow up the sending rate if not replies are * recieved for STCP_THRESHOLD consecutive sends. Saves alot of resends * on easily-flooded networks. * * 6. (v1.32) * - Multiple port ranges support. * The format is: |[,|,...] * * Examples: 20-26,113 * 20-100,113-150,6000,6660-6669 * * PLANNED: (when I have time for this) * ------------------------------------ * (v2.x) - Multiple flag combination selections, smart algorithm to point * out uncommon replies and cross-check them with another flag * */ #define RESOLVE_QUIET #include #include #include #include #include #include #include #include #include #include #include #include #include "resolve.c" #include "tcppkt03.c" #define STCP_VERSION "1.32" #define STCP_PORT 1234 /* Notre port source. */ #define STCP_SENDS 3 #define STCP_THRESHOLD 8 #define STCP_SLOWFACTOR 10 /* FONCTIONS GENERALES ------------------------------------------- */ void banner(void) { printf("\nscantcp\n"); printf("version %s\n",STCP_VERSION); } void usage(const char *progname) { printf("\nusage: \n"); printf("%s [sf]\n\n",progname); printf("\t : 0: ouverture partielle (type 0, SYN)\n"); printf("\t 1: Scan furtif (type 1, FIN)\n"); printf("\t 2: Scan furtif (type 2, ACK)\n"); printf("\t : adresse source (cette machine)\n"); printf("\t : cible à scanner\n"); printf("\t : ports et/ou plages de ports - eg: 21-30,113,6000\n"); printf("\t : microsecondes d'attente entre deux enfois TCP\n"); printf("\t : secondes d'attente des réponses TCP\n"); printf("\t[sf] : facteur-ralentissement au cas où les envois sont détectés comme trop rapides\n\n"); } /* GESTION DES OPTIONS etc ---------------------------------------- */ unsigned char *dest_name; unsigned char *spoof_name; struct sockaddr_in destaddr; unsigned long dest_addr; unsigned long spoof_addr; unsigned long usecdelay; unsigned waitdelay; int slowfactor = STCP_SLOWFACTOR; struct portrec /* structure des ports */ { unsigned n; int state; unsigned char ttl; unsigned short int window; unsigned long int seq; char sends; } *ports; char *portstr; unsigned char scanflags; int done; int rawsock; /* socket descriptors */ int tcpsock; int lastidx = 0; /* index du dernier envoi */ int maxports; /* nombre total de ports */ void timeout(int signum) /* gestionnaire de timeout */ { /* C'est en fait la fonction qui */ int someopen = 0; /* analyse les données. Bof. */ unsigned lastsent; int checklowttl = 0; struct portrec *p; printf("* SCAN TERMINE\n\n"); fflush(stdout); done = 1; for (lastsent = 0;lastsentstate == -1) if (p->ttl > 64) { checklowttl = 1; break; } } /* La boucle précédente détermine s'il y a besoin de vérifier les ttl plus petits */ for (lastsent = 0;lastsentn); tcpip_send(rawsock,&destaddr, spoof_addr,destaddr.sin_addr.s_addr, STCP_PORT,ntohs(destaddr.sin_port), TH_RST, p->seq++, 0, 512, NULL, 0); } /* pour RST -tout- ce qui a été envoyé */ /* y compris les réponses reçues */ /* (dont les RST) */ for (lastsent = 0;lastsentstate) { case -1: break; case 1 : printf("# port %d écoute.\n",p->n); someopen++; break; case 2 : printf("# port %d écoute peut être (réponse inconnue).\n", p->n); someopen++; break; default: printf("# port %d doit être re-scanné.\n",p->n); } break; case TH_ACK: switch (p->state) { case -1: if (((p->ttl < 65) && checklowttl) || (p->window >0)) { printf("# port %d écoute peut être",p->n); if (p->ttl < 65) printf(" (petit ttl)"); if (p->window >0) printf(" (grosse fenêtre)"); printf(".\n"); someopen++; } break; case 1: case 2: printf("# port %d a une réponse inattendue.\n", p->n); break; default: printf("# port %d doit être re-scanné.\n",p->n); } break; case TH_FIN: switch (p->state) { case -1: break; case 0 : printf("# port %d peut-être ouvert.\n",p->n); someopen++; break; default: printf("# port %d a une réponse inattendue.\n",p->n); } } } printf("-----------------------------------------------\n"); printf("# nombre de ports ouverts (dont ceux peut-être): %d\n\n",someopen); free(ports); exit(0); /* heh. */ } int resolve_one(const char *name, unsigned long *addr, const char *desc) { struct sockaddr_in tempaddr; if (resolve(name, &tempaddr,0) == -1) { printf("error: impossible de résoudre %s.\n",desc); return -1; } *addr = tempaddr.sin_addr.s_addr; return 0; } void give_info(void) { printf("# adresse de la réponse : %s (%s)\n",spoof_name,inet_ntoa(spoof_addr)); printf("# adresse de la cible : %s (%s)\n",dest_name,inet_ntoa(dest_addr)); printf("# ports : %s\n",portstr); printf("# (nombre total de ports) : %d\n",maxports); printf("# délai entre envois : %lu microsecondes\n",usecdelay); printf("# délai : %u secondes\n",waitdelay); printf("# seuil de détection de flood : %d envois sans réponse\n",STCP_THRESHOLD); printf("# facteur de ralentissement : %d\n",slowfactor); printf("# envois max par port : %d\n\n",STCP_SENDS); } int parse_args(int argc, char *argv[]) { if (strrchr(argv[0],'/') != NULL) argv[0] = strrchr(argv[0],'/') + 1; if (argc < 7) { printf("%s: pas assez d'arguments\n",argv[0]); return -1; } switch (atoi(argv[1])) { case 0 : scanflags = TH_SYN; break; case 1 : scanflags = TH_FIN; break; case 2 : scanflags = TH_ACK; break; default : printf("%s: méthode de scan inconnue\n",argv[0]); return -1; } spoof_name = argv[2]; dest_name = argv[3]; portstr = argv[4]; usecdelay = atol(argv[5]); waitdelay = atoi(argv[6]); if (argc > 7) slowfactor = atoi(argv[7]); if ((usecdelay == 0) && (slowfactor > 0)) { printf("%s: ajustement du délais en microsecodes à 1usec.\n"); usecdelay++; } return 0; } /* MAIN ------------------------------------------------------ */ int build_ports(char *str) /* Construit la base de ports initiale */ { int i; int n; struct portrec *p; int sport; char *s; s = str; maxports = 0; n = 0; while (*s != '\0') { switch (*s) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n *= 10; n += (*s - '0'); break; case '-': if (n == 0) return -1; sport = n; n = 0; break; case ',': if (n == 0) return -1; if (sport != 0) { if (sport >= n) return -1; maxports += n-sport; sport = 0; } else maxports++; n = 0; break; } s++; } if (n == 0) return -1; if (sport != 0) { if (sport >= n) return -1; maxports += n-sport; sport = 0; } else maxports++; maxports+=2; if ((ports = (struct portrec *)malloc((maxports)*sizeof(struct portrec))) == NULL) { fprintf(stderr,"\nerror: pas assez de mémoire pour la base des ports\n\n"); exit(1); } s = str; maxports = 0; n = 0; while (*s != '\0') { switch (*s) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n *= 10; n += (*s - '0'); break; case '-': if (n == 0) return -1; sport = n; n = 0; break; case ',': if (n == 0) return -1; if (sport != 0) { if (sport >= n) return -1; while (sport <= n) { for (i=0;in == sport) break; if (i < maxports-1 ) printf("notice: port en double - %d\n",sport); else { (ports+maxports)->n = sport; maxports++; } sport++; } sport = 0; } else { for (i=0;in == n) break; if (i < maxports-1 ) printf("notice: port en double - %d\n",n); else { (ports+maxports)->n = n; maxports++; } } n = 0; break; } s++; } if (n == 0) return -1; if (sport != 0) { if (sport >= n) return -1; while (sport <= n) { for (i=0;in == sport) break; if (i < maxports-1 ) printf("notice: port en double - %d\n",sport); else { (ports+maxports)->n = sport; maxports++; } sport++; } sport = 0; } else { for (i=0;in == n) break; if (i < maxports-1 ) printf("notice: port en double - %d\n",n); else { (ports+maxports)->n = n; maxports++; } } printf("\n"); for (i=0;istate = 0; p->sends = 0; } return 0; } struct portrec *portbynum(int num) { int i = 0; while ( ((ports+i)->n != num) && (istate != 0) || (p->sends == STCP_SENDS)) { doneports++; lastidx++; lastidx %= maxports; } else break; } if (save) lastidx = oldlastidx; else lastidx = (lastidx + 1) % maxports; if (doneports == maxports) return NULL; return p; } inline unsigned long usecdiff(struct timeval *a, struct timeval *b) { unsigned long s; s = b->tv_sec - a->tv_sec; s *= 1000000; s += b->tv_usec - a->tv_usec; return s; /* retourne la différence en microsecondes */ } void main(int argc, char *argv[]) { int lastsent = 0; char buf[3000]; struct iphdr *ip = (struct iphdr *)(buf); struct tcphdr *tcp = (struct tcphdr *)(buf+sizeof(struct iphdr)); struct sockaddr_in from; int fromlen; struct portrec *readport; fd_set rset, wset; struct timeval waitsend, now, del; unsigned long udiff; int sendthreshold = 0; banner(); if (parse_args(argc,argv)) { usage(argv[0]); return; } if (resolve_one(dest_name, &dest_addr, "destination host")) exit(1); destaddr.sin_addr.s_addr = dest_addr; destaddr.sin_family = AF_INET; if (resolve_one(spoof_name, &spoof_addr, "source host")) exit(1); if ( build_ports(portstr) == -1) { printf("\n%s: mauvais numéro de port\n",argv[0]); usage(argv[0]); return; } give_info(); if ((tcpsock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1) { printf("\nerror: n'a pas pu ouvrir une socket bas niveau\n\n"); exit(1); } if ((rawsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) { printf("\nerror: n'a pas pu obtenir de socket bas niveau\n\n"); exit(1); } /* well, let's get to it. */ done = 0; printf("* DEBUT DE SCAN\n"); fflush(stdout); gettimeofday(&waitsend,NULL); while (!done) { if (nextport(1) == NULL) { alarm(0); /* plus d'envois. Nous devons */ signal(SIGALRM,timeout); /* juste attendre */ alarm(waitdelay); /* secondes avant de resetter */ } /* et fournir les résultats. */ FD_ZERO(&rset); FD_SET(tcpsock,&rset); gettimeofday(&now,NULL); udiff = usecdiff(&waitsend,&now); /* C'est ici qu'on sélect()ionne les choix possibles: * 1. on a déjà envoyé tous les paquets. * 2. il en reste mais c'est trop tôt * 3. il en reste et on peut y aller. */ if (nextport(1) != NULL) if (udiff > usecdelay) { FD_ZERO(&wset); FD_SET(rawsock,&wset); select(FD_SETSIZE,&rset,&wset,NULL,NULL); } else { del.tv_sec = 0; del.tv_usec = usecdelay; select(FD_SETSIZE,&rset,NULL,NULL,&del); } else select(FD_SETSIZE,&rset,NULL,NULL,NULL); if (FD_ISSET(tcpsock,&rset)) /* process the reply */ { fromlen = sizeof(from); recvfrom(tcpsock,&buf,3000,0, (struct sockaddr *)&from,&fromlen); if (from.sin_addr.s_addr == destaddr.sin_addr.s_addr) if (ntohs(tcp->th_dport) == STCP_PORT) { printf("* reçu une réponse"); readport = portbynum(ntohs(tcp->th_sport)); if (readport == NULL) printf(" -- bad port"); else { sendthreshold = 0; if (!readport->state) { readport->ttl = ip->ttl; readport->window = tcp->th_win; if (tcp->th_flags & TH_RST) { readport->state = -1; printf(" (RST)"); if (readport->ttl < 65) printf(" (short ttl)"); if (readport->window > 0) printf(" (big window)"); } else if (tcp->th_flags & (TH_ACK | TH_SYN)) { readport->state = 1; printf(" (SYN+ACK)"); tcpip_send(rawsock,&destaddr, spoof_addr,destaddr.sin_addr.s_addr, STCP_PORT,readport->n, TH_RST, readport->seq++, 0, 512, NULL, 0); } else { readport->state = 2; printf(" (UNEXPECTED)"); tcpip_send(rawsock,&destaddr, spoof_addr,destaddr.sin_addr.s_addr, STCP_PORT,readport->n, TH_RST, readport->seq++, 0, 512, NULL, 0); } } else printf(" (duplicate)"); } printf("\n"); fflush(stdout); } } if (nextport(1) != NULL) if (FD_ISSET(rawsock,&wset)) /* process the sends */ { readport = nextport(0); destaddr.sin_port = htons(readport->n); printf("* sending to port %d ",ntohs(destaddr.sin_port)); readport->seq = lrand48(); readport->sends++; tcpip_send(rawsock,&destaddr, spoof_addr,destaddr.sin_addr.s_addr, STCP_PORT,ntohs(destaddr.sin_port), scanflags, readport->seq++, lrand48(), 512, NULL, 0); gettimeofday(&waitsend,NULL); FD_ZERO(&wset); printf("\n"); if ((++sendthreshold > STCP_THRESHOLD) && (slowfactor)) { printf("\n\n -- SEUIL DEPASSE - RALENTISSEMENT DES ENVOIS\n\n"); usecdelay *= slowfactor; sendthreshold = 0; } } } } /* * tcp_pkt.c * * routines for creating TCP packets, and sending them into sockets. * * (version 0.3) * * * BUGFIX: - it seems like the TCP pseudo header checksum was * acting up in serveral cases. * ADDED : - HEXDUMP macro. * - packet dump handling */ /* remove inlines for smaller size but lower speed */ #include #include #include #include #include #define IPHDRSIZE sizeof(struct iphdr) #define TCPHDRSIZE sizeof(struct tcphdr) #define PSEUDOHDRSIZE sizeof(struct pseudohdr) /* ********** RIPPED CODE START ******************************** */ /* * in_cksum -- * Checksum routine for Internet Protocol family headers (C Version) */ unsigned short in_cksum(addr, len) u_short *addr; int len; { register int nleft = len; register u_short *w = addr; register int sum = 0; u_short answer = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), we add * sequential 16 bit words to it, and at the end, fold back all the * carry bits from the top 16 bits into the lower 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } /* add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return(answer); } /* ********** RIPPED CODE END ******************************** */ /* * HEXDUMP() * * not too much to explain */ inline void HEXDUMP(unsigned len, unsigned char *data) { unsigned i; for (i=0;isaddr = s_addr; pseudo->daddr = t_addr; pseudo->protocol = IPPROTO_TCP; pseudo->tcplength = htons(TCPHDRSIZE+datasize); /* The TCP pseudo-header was created. */ tcp->th_sport = htons(s_port); tcp->th_dport = htons(t_port); tcp->th_off = 5; /* 20 bytes, (no options) */ tcp->th_flags = tcpflags; tcp->th_seq = htonl(seq); tcp->th_ack = htonl(ack); tcp->th_win = htons(win); /* we don't need any bigger, I guess. */ /* The necessary TCP header fields are set. */ tcp->th_sum = in_cksum(pseudo,PSEUDOHDRSIZE+TCPHDRSIZE+datasize); memset(packet,0,IPHDRSIZE); /* The pseudo-header is wiped to clear the IP header fields */ ip->saddr = s_addr; ip->daddr = t_addr; ip->version = 4; ip->ihl = 5; ip->ttl = 255; ip->id = random()%1996; ip->protocol = IPPROTO_TCP; /* should be 6 */ ip->tot_len = htons(IPHDRSIZE + TCPHDRSIZE + datasize); ip->check = in_cksum((char *)packet,IPHDRSIZE); /* The IP header is intact. The packet is ready. */ #ifdef TCP_PKT_DEBUG printf("Packet ready. Dump: \n"); #ifdef TCP_PKT_DEBUG_DATA HEXDUMP(IPHDRSIZE+TCPHDRSIZE+datasize,packet); #else HEXDUMP(IPHDRSIZE+TCPHDRSIZE,packet); #endif printf("\n"); #endif return sendto(socket, packet, IPHDRSIZE+TCPHDRSIZE+datasize, 0, (struct sockaddr *)address, sizeof(struct sockaddr)); /* And off into the raw socket it goes. */ } /* * resolve.c * * resolves an internet text address into (struct sockaddr_in). * * CHANGES: 1. added the RESOLVE_QUIET preprocessor conditions. Jan 1996 * 2. added resolve_rns() to always provide both name/ip. March 1996 */ #include #include #include #include #include int resolve( const char *name, struct sockaddr_in *addr, int port ) { struct hostent *host; /* clear everything in case I forget something */ bzero(addr,sizeof(struct sockaddr_in)); if (( host = gethostbyname(name) ) == NULL ) { #ifndef RESOLVE_QUIET fprintf(stderr,"unable to resolve host \"%s\" -- ",name); perror(""); #endif return -1; } addr->sin_family = host->h_addrtype; memcpy((caddr_t)&addr->sin_addr,host->h_addr,host->h_length); addr->sin_port = htons(port); return 0; } int resolve_rns( char *name , unsigned long addr ) { struct hostent *host; unsigned long address; address = addr; host = gethostbyaddr((char *)&address,4,AF_INET); if (!host) { #ifndef RESOLVE_QUIET fprintf(stderr,"unable to resolve host \"%s\" -- ",inet_ntoa(addr)); perror(""); #endif return -1; } strcpy(name,host->h_name); return 0; } unsigned long addr_to_ulong(struct sockaddr_in *addr) { return addr->sin_addr.s_addr; }