📄 ars.c
字号:
{ "TCP", ars_compiler_tcp, 5 }, { "TCPOPT", ars_compiler_tcpopt, 6 }, { NULL, NULL, 7 }, { NULL, NULL, 8 }, { NULL, NULL, 9 }, { NULL, NULL, 10 }, { NULL, NULL, 11 }, { NULL, NULL, 12 }, { NULL, NULL, 13 }, { NULL, NULL, 14 }, { NULL, NULL, 15 }, { NULL, NULL, 16 }, { NULL, NULL, 17 }, { NULL, NULL, 18 }, { NULL, NULL, 19 }, { NULL, NULL, 20 }, { NULL, NULL, 21 }, { NULL, NULL, 22 }, { NULL, NULL, 23 }, { NULL, NULL, 24 }, { NULL, NULL, 25 }, { NULL, NULL, 26 }, { NULL, NULL, 27 }, { NULL, NULL, 28 }, { NULL, NULL, 29 }, { NULL, NULL, 30 }, { "DATA", NULL, 31 }};/* This function call the right compiler for all the layers of the packet: * A compiler just set the protocol fields like the checksum, len, and so on * accordly to the following layers. * Note that the layers are compiled from the last to the first, to ensure * that the checksum and other dependences are sane. */int ars_compile(struct ars_packet *pkt){ int j, err; for (j = pkt->p_layer_nr - 1; j >= 0; j--) { __D(printf("Compiling layer %d\n", j);) /* Skip NULL compilers */ if (ars_linfo[pkt->p_layer[j].l_type].li_compiler != NULL) { /* Call the compiler */ err = ars_linfo[pkt->p_layer[j].l_type].li_compiler(pkt, j); if (err != -ARS_OK) return err; } } return -ARS_OK;}/* The IP compiler: probably the more complex, but still simple */int ars_compiler_ip(struct ars_packet *pkt, int layer){ struct ars_iphdr *ip = pkt->p_layer[layer].l_data; int j = layer, err; int flags = pkt->p_layer[layer].l_flags; int ipoptlen = 0; struct mc_context mc; /* multi-buffer checksum context */ /* IP version */ if (ARS_DONTTAKE(flags, ARS_TAKE_IP_VERSION)) ip->version = 4; /* IP header len */ if (ARS_DONTTAKE(flags, ARS_TAKE_IP_HDRLEN)) { ip->ihl = (ARS_IPHDR_SIZE >> 2); /* Add IP options len */ for (j = layer+1; j < ARS_MAX_LAYER; j++) { if (pkt->p_layer[j].l_type != ARS_TYPE_IPOPT) break; ipoptlen += pkt->p_layer[j].l_size; } ip->ihl += ipoptlen >> 2; } /* IP tot len */ if (ARS_DONTTAKE(flags, ARS_TAKE_IP_TOTLEN)) ip->tot_len = htons(ars_relative_size(pkt, layer)); /* IP protocol field */ if (ARS_DONTTAKE(flags, ARS_TAKE_IP_PROTOCOL)) { ip->protocol = ARS_IPPROTO_RAW; /* This is the default */ while (j < ARS_MAX_LAYER) { if (pkt->p_layer[j].l_type == ARS_TYPE_IPOPT) { j++; continue; } switch(pkt->p_layer[j].l_type) { case ARS_TYPE_IP: ip->protocol = ARS_IPPROTO_IPIP; break; case ARS_TYPE_ICMP: ip->protocol = ARS_IPPROTO_ICMP; break; case ARS_TYPE_UDP: ip->protocol = ARS_IPPROTO_UDP; break; case ARS_TYPE_TCP: ip->protocol = ARS_IPPROTO_TCP; break; } break; } } /* We always calculate the IP checksum, since the kernel * do it only for the first IP header in the datagram */ if (ARS_DONTTAKE(flags, ARS_TAKE_IP_CKSUM)) { ip->check = 0; ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); err = ars_multi_cksum(&mc, ARS_MC_UPDATE, ip, ARS_IPHDR_SIZE); if (err != -ARS_OK) return err; for (j = layer+1; j < ARS_MAX_LAYER; j++) { if (pkt->p_layer[j].l_type != ARS_TYPE_IPOPT) break; err = ars_multi_cksum(&mc, ARS_MC_UPDATE, pkt->p_layer[j].l_data, pkt->p_layer[j].l_size); if (err != -ARS_OK) return err; } ip->check = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); } return -ARS_OK;}/* The ip options compiler: do just option padding with NOP options */int ars_compiler_ipopt(struct ars_packet *pkt, int layer){ int j, opt_size; /* Padding is needed only in the last IP option */ if (layer != ARS_MAX_LAYER-1 && pkt->p_layer[layer+1].l_type == ARS_TYPE_IPOPT) return ARS_OK; /* Search the layer of the relative first TCP option */ j = layer - 1; /* We know that 'layer' is a tcp option */ while (j < ARS_MAX_LAYER && j >= 0 && pkt->p_layer[j].l_type == ARS_TYPE_IPOPT) j--; j++; __D(printf("First IP OPTION layer is %d\n", j);) opt_size = ars_relative_size(pkt, j) - ars_relative_size(pkt, layer+1); __D(printf("IP OPTION size %d\n", opt_size);) if (opt_size % 4) { int padding = 4 - (opt_size % 4); unsigned char *t; int cur_size = pkt->p_layer[layer].l_size; __D(printf("IP OPTION at layer %d needs %d bytes " "of padding\n", layer, padding);) t = realloc(pkt->p_layer[layer].l_data, cur_size + padding); if (t == NULL) { ars_set_error(pkt, "Out of memory padding IP options"); return -ARS_NOMEM; } memset(t+cur_size, ARS_IPOPT_NOP, padding); pkt->p_layer[layer].l_size += padding; } return -ARS_OK;}/* Compute the UDP and TCP checksum using the pseudoheader. * Note that this functions automatically care about TCP/UDP data */int ars_udptcp_cksum(struct ars_packet *pkt, int layer, u_int16_t *sum){ struct ars_iphdr *ip; struct ars_pseudohdr pseudo; struct mc_context mc; /* multi-buffer checksum context */ int j = layer - 1, err; /* search the first IP layer on the left: * it returns an error if between the IP and * the TCP layer there aren't just IPOPT layers: * even with malformed packets this does not * makes sense. */ while (j > 0 && pkt->p_layer[j].l_type == ARS_TYPE_IPOPT) j--; if (pkt->p_layer[j].l_type != ARS_TYPE_IP) { ars_set_error(pkt, "TCP/UDP checksum requested, but IP header " "not found"); return -ARS_INVALID; } ip = pkt->p_layer[j].l_data; memset(&pseudo, 0, sizeof(pseudo)); /* actually not needed */ /* Copy the src and dst IP address */ memcpy(&pseudo.saddr, &ip->saddr, 4); memcpy(&pseudo.daddr, &ip->daddr, 4); pseudo.protocol = (pkt->p_layer[layer].l_type == ARS_TYPE_TCP) ? ARS_IPPROTO_TCP : ARS_IPPROTO_UDP; pseudo.lenght = htons(ars_relative_size(pkt, layer)); /* Finally do the checksum */ ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); err = ars_multi_cksum(&mc, ARS_MC_UPDATE, &pseudo, sizeof(pseudo)); if (err != -ARS_OK) return err; for (j = layer; j < ARS_MAX_LAYER; j++) { if (pkt->p_layer[j].l_type == ARS_TYPE_NULL) break; err = ars_multi_cksum(&mc, ARS_MC_UPDATE, pkt->p_layer[j].l_data, pkt->p_layer[j].l_size); if (err != -ARS_OK) return err; } *sum = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); return -ARS_OK;}/* The tcp compiler */int ars_compiler_tcp(struct ars_packet *pkt, int layer){ struct ars_tcphdr *tcp = pkt->p_layer[layer].l_data; int j, err, tcpoptlen = 0; int flags = pkt->p_layer[layer].l_flags; if (ARS_DONTTAKE(flags, ARS_TAKE_TCP_HDRLEN)) { tcp->th_off = ARS_TCPHDR_SIZE >> 2; /* Add the len of the options */ for (j = layer+1; j < ARS_MAX_LAYER; j++) { if (pkt->p_layer[j].l_type != ARS_TYPE_TCPOPT) break; tcpoptlen += pkt->p_layer[j].l_size; } tcp->th_off += tcpoptlen >> 2; } if (ARS_DONTTAKE(flags, ARS_TAKE_TCP_CKSUM)) { tcp->th_sum = 0; err = ars_udptcp_cksum(pkt, layer, &tcp->th_sum); if (err != -ARS_OK) return err; } return -ARS_OK;}/* The tcp options compiler: do just option padding with NOP options */int ars_compiler_tcpopt(struct ars_packet *pkt, int layer){ int j, opt_size; /* Padding is needed only in the last TCP option */ if (layer != ARS_MAX_LAYER-1 && pkt->p_layer[layer+1].l_type == ARS_TYPE_TCPOPT) return ARS_OK; /* Search the layer of the relative first TCP option */ j = layer - 1; /* We know that 'layer' is a tcp option */ while (j < ARS_MAX_LAYER && j >= 0 && pkt->p_layer[j].l_type == ARS_TYPE_TCPOPT) j--; j++; __D(printf("First TCP OPTION layer is %d\n", j);) opt_size = ars_relative_size(pkt, j) - ars_relative_size(pkt, layer+1); __D(printf("TCP OPTION size %d\n", opt_size);) if (opt_size % 4) { int padding = 4 - (opt_size % 4); unsigned char *t; int cur_size = pkt->p_layer[layer].l_size; __D(printf("TCP OPTION at layer %d needs %d bytes " "of padding\n", layer, padding);) t = realloc(pkt->p_layer[layer].l_data, cur_size + padding); if (t == NULL) { ars_set_error(pkt, "Out of memory padding TCP options"); return -ARS_NOMEM; } memset(t+cur_size, ARS_TCPOPT_NOP, padding); pkt->p_layer[layer].l_size += padding; } return -ARS_OK;}/* The udp compiler, very simple */int ars_compiler_udp(struct ars_packet *pkt, int layer){ struct ars_udphdr *udp = pkt->p_layer[layer].l_data; int err; int flags = pkt->p_layer[layer].l_flags; if (ARS_DONTTAKE(flags, ARS_TAKE_UDP_LEN)) udp->uh_ulen = htons(ars_relative_size(pkt, layer)); if (ARS_DONTTAKE(flags, ARS_TAKE_UDP_CKSUM)) { udp->uh_sum = 0; err = ars_udptcp_cksum(pkt, layer, &udp->uh_sum); if (err != -ARS_OK) return err; } return -ARS_OK;}/* The icmp compiler, just compute the checksum */int ars_compiler_icmp(struct ars_packet *pkt, int layer){ struct ars_icmphdr *icmp = pkt->p_layer[layer].l_data; struct mc_context mc; /* multi-buffer checksum context */ int err, j; int flags = pkt->p_layer[layer].l_flags; if (ARS_DONTTAKE(flags, ARS_TAKE_ICMP_CKSUM)) { icmp->checksum = 0; ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); for (j = layer; j < ARS_MAX_LAYER; j++) { if (pkt->p_layer[j].l_type == ARS_TYPE_NULL) break; err = ars_multi_cksum(&mc, ARS_MC_UPDATE, pkt->p_layer[j].l_data, pkt->p_layer[j].l_size); if (err != -ARS_OK) return err; } icmp->checksum = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); } return -ARS_OK;}/* Open a raw socket, ready for IP header creation and broadcast addresses */int ars_open_rawsocket(struct ars_packet *pkt){ int s; const int one = 1; if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) { ars_set_error(pkt, "Can't open the raw socket"); return -ARS_ERROR; } if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one)) == -1 || setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char*)&one, sizeof(one)) == -1) { close(s); ars_set_error(pkt, "Can't set socket options"); return -ARS_ERROR; } return s;}/* Create the packets using the layers. This function is often called * after the layers compilation. Note that since the packet created * is sane the strange-rawsocket-behaviour of some *BSD will not * be able to send this packet. Use the function ars_bsd_fix() to fix it. * WARNING: The packets returned is malloc()ated, free it */int ars_build_packet(struct ars_packet *pkt, unsigned char **packet, size_t *size){ size_t tot_size, offset = 0; int j = 0; if ((tot_size = ars_packet_size(pkt)) == 0) { ars_set_error(pkt, "Total size 0 building the packet"); return -ARS_INVALID; } if ((*packet = malloc(tot_size)) == NULL) { ars_set_error(pkt, "Out of memory building the packet"); return -ARS_NOMEM; } while (j < ARS_MAX_LAYER && pkt->p_layer[j].l_type != ARS_TYPE_NULL) { memcpy((*packet)+offset, pkt->p_layer[j].l_data, pkt->p_layer[j].l_size); offset += pkt->p_layer[j].l_size; j++; } *size = tot_size; return -ARS_OK;}/* FreeBSD and NetBSD have a strange raw socket layer :( * Call this function anyway to increase portability * since it does not perform any operation if the * system isn't FreeBSD or NetBSD. */int ars_bsd_fix(struct ars_packet *pkt, unsigned char *packet, size_t size){ struct ars_iphdr *ip; if (pkt->p_layer[0].l_type != ARS_TYPE_IP || size < sizeof(struct ars_iphdr)) { ars_set_error(pkt, "BSD fix requested, but layer 0 not IP"); return -ARS_INVALID; } ip = (struct ars_iphdr*) packet;#if defined OSTYPE_FREEBSD || defined OSTYPE_NETBSD || defined OSTYPE_BSDI ip->tot_len = ntohs(ip->tot_len); ip->frag_off = ntohs(ip->frag_off);#endif return -ARS_OK;}/* Set the flags for some layer: if layer == -1 the last layer will be used */int ars_set_flags(struct ars_packet *pkt, int layer, int flags){ if (layer == ARS_LAST_LAYER) layer = pkt->p_layer_nr - 1; if (layer < 0 || layer >= ARS_MAX_LAYER) { ars_set_error(pkt, "Invalid layer setting layer flags"); return -ARS_INVALID; } pkt->p_layer[layer].l_flags = flags; return -ARS_OK;}/* Build, fix, and send the packet */int ars_send(int s, struct ars_packet *pkt, struct sockaddr *sa, socklen_t slen){ struct sockaddr_in sain; struct sockaddr *_sa = sa; unsigned char *packet; size_t size; int error; /* Perform the socket address completion if sa == NULL */ if (sa == NULL) { struct ars_iphdr *ip; memset(&sain, 0, sizeof(sain)); sain.sin_family = AF_INET; /* The first layer MUST be IP if the user requested * the socket address completion */ if (pkt->p_layer[0].l_type != ARS_TYPE_IP) { ars_set_error(pkt, "socket address completion" "requested, but layer 0 isn't IP"); return -ARS_ERROR; } ip = (struct ars_iphdr*) pkt->p_layer[0].l_data; memcpy(&sain.sin_addr.s_addr, &ip->daddr, 4); _sa = (struct sockaddr*) &sain; slen = sizeof(sain); } if ((error = ars_build_packet(pkt, &packet, &size)) != ARS_OK) return error; if ((error = ars_bsd_fix(pkt, packet, size)) != ARS_OK) return error; error = sendto(s, packet, size, 0, _sa, slen); free(packet); return (error != -1) ? -ARS_OK : -ARS_ERROR;}/* Resolve an hostname and write to 'dest' the IP */int ars_resolve(struct ars_packet *pkt, u_int32_t *dest, char *hostname){ struct sockaddr_in sa;#ifndef WIN32 if (inet_aton(hostname, &sa.sin_addr) == 0) {#else if ((sa.sin_addr.S_un.S_addr = inet_addr(hostname)) == INADDR_NONE) {#endif struct hostent *he; he = gethostbyname(hostname); if (he == NULL) { ars_set_error(pkt, "Can't resolve the hostname"); return -ARS_ERROR; } sa.sin_addr.s_addr = ((struct in_addr*) he->h_addr)->s_addr; } memcpy(dest, &sa.sin_addr.s_addr, sizeof(u_int32_t)); return -ARS_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -