diff options
author | stww <securethewebwith@priveasy.de> | 2011-10-31 17:23:41 (GMT) |
---|---|---|
committer | stww <securethewebwith@priveasy.de> | 2011-10-31 17:23:41 (GMT) |
commit | 635b2bb4009a6f9f66ffbed9b5d94173f6ac029b (patch) | |
tree | 61b07578ba272d32a7db298262480fa54ed924a9 /main.c |
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 177 |
1 files changed, 177 insertions, 0 deletions
@@ -0,0 +1,177 @@ +/* TODO: act proper if interface is promisc (only reply to packets + send to local host */ + +#include <assert.h> +#include <linux/if_ether.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <malloc.h> +#include <net/ethernet.h> +#include <net/if.h> +#include <netpacket/packet.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/types.h> + +#define BLEN 16384 +#define PORT 80 + +const char * raw_payload = + "HTTP/1.0 301 Not enough crypto to process request\r\n" + "Location: %s\r\n" + "Connection: close\r\n" + "\r\n" + "<html><body>bye bye</body></html>"; + +unsigned chksum(unsigned short *buf, int length) { + unsigned sum = 0; + for (; length > 1; length -= 2) + sum += *buf++; + return sum; +} + +unsigned short ipchksum(struct iphdr *ip) { + unsigned sum = chksum((unsigned short *) ip, sizeof(struct iphdr)); + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + return ~sum; +} + +unsigned short tcpchksum(struct iphdr *ip, struct tcphdr *tcp, int length) { + unsigned sum = + chksum((unsigned short*) &(ip->saddr), sizeof(ip->saddr)) + + chksum((unsigned short*) &(ip->daddr), sizeof(ip->daddr)) + + ((length + ip->protocol) << 8) + + chksum((unsigned short*) tcp, length); + if (length % 2) + sum += *(((char*) tcp) + length - 1); + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + return ~sum; +} + +int main(int argc, char **argv) { + if (argc != 2) { + printf("Usage: %s target-url\n", argv[0]); + return 1; + } + + static unsigned ack_src; + /* prepare input buffer */ + char *ibuf = malloc(BLEN); + assert(ibuf != NULL); + struct ethhdr *i_eth = (struct ethhdr*) ibuf; + struct iphdr *i_ip = (struct iphdr*) (i_eth + 1); + struct tcphdr *i_tcp = (struct tcphdr*) (i_ip + 1); + char *i_pld = (char*) (i_tcp + 1); + + /* prepare output buffer */ + const size_t os = + sizeof(struct ethhdr) + + sizeof(struct iphdr) + + sizeof(struct tcphdr) + + strlen(raw_payload) + strlen(argv[1]) - 1; + char *obuf = malloc(os); + assert(obuf != NULL); + struct ethhdr *o_eth = (struct ethhdr*) obuf; + struct iphdr *o_ip = (struct iphdr*) (o_eth + 1); + struct tcphdr *o_tcp = (struct tcphdr*) (o_ip + 1); + char *o_pld = (char*) (o_tcp + 1); + + /* setup sock */ + int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); + assert(fd >= 0); + + /* retrieve interface idx (for send()) */ + int ifidx; + { + struct ifreq req; + const char *if_name = "eth0"; + strcpy((char*) &(req.ifr_name), if_name); + assert(ioctl(fd, SIOCGIFINDEX, &req) >= 0); + ifidx = req.ifr_ifindex; + printf("device index of %s is %d\n", if_name, ifidx); + } + + /* prefill static output */ + o_eth->h_proto = htons(ETH_P_IP); + + o_ip->ihl = 5; + o_ip->version = 4; + o_ip->tos = 0; + o_ip->id = 0; + o_ip->frag_off = 0; + o_ip->ttl = 255; + o_ip->protocol = 6; + + o_tcp->source = htons(PORT); + o_tcp->res1 = 0; + o_tcp->doff = 5; + o_tcp->ack = 1; + o_tcp->rst = 0; + o_tcp->psh = 1; + o_tcp->urg = 0; + o_tcp->ece = 0; + o_tcp->cwr = 0; + o_tcp->urg_ptr = 0; + o_tcp->window = htons(4); /* first 4 byte are harmless (and we won't + ack them) */ + + snprintf(o_pld, strlen(raw_payload) + strlen(argv[1]) - 1, raw_payload, argv[1]); + + struct sockaddr_ll sall; + sall.sll_family = AF_PACKET; + sall.sll_ifindex = ifidx; + sall.sll_halen = 6; + memcpy(&(sall.sll_addr), &(o_eth->h_dest), sall.sll_halen); + sall.sll_protocol = sall.sll_hatype = sall.sll_pkttype = 0; + + /* read packets forever */ + while (1) { + int is = recv(fd, ibuf, BLEN, 0); + if ((is >= sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr)) && // packet long enough? + (ntohs(i_eth->h_proto) == ETH_P_IP) && // ip protocol? + (i_ip->ihl == 5) && // no IP options + (i_ip->protocol == 6) && // tcp protocol? + (ntohs(i_tcp->dest) == PORT)) { // port 80? + int size = 0; + + /* eth & IP are common for all responses */ + memcpy(&(o_eth->h_dest), &(i_eth->h_source), ETH_ALEN); + memcpy(&(o_eth->h_source), &(i_eth->h_dest), ETH_ALEN); + + o_ip->check = 0; + memcpy(&(o_ip->saddr), &(i_ip->daddr), sizeof(o_ip->saddr)); + memcpy(&(o_ip->daddr), &(i_ip->saddr), sizeof(o_ip->daddr)); + + o_tcp->dest = i_tcp->source; + o_tcp->check = 0; + + if (i_tcp->syn && !i_tcp->ack) { /* first packet of a handshake? */ + printf("syn\n"); + size = os - strlen(o_pld); + o_tcp->seq = i_tcp->seq; + o_tcp->ack_seq = htonl(ntohl(i_tcp->seq) + 1); + o_tcp->fin = 0; //1; + o_tcp->syn = 1; + }else if (i_tcp->ack) { + printf("ack\n"); + size = os; + o_tcp->seq = htonl(ntohl(i_tcp->ack_seq)); + o_tcp->ack_seq = htonl(ntohl(i_tcp->ack_seq)); + o_tcp->fin = 1; + o_tcp->syn = 0; + } + + if (size > 0) { + o_ip->tot_len = htons(size - sizeof(struct ethhdr)); + o_ip->check = ipchksum(o_ip); + o_tcp->check = tcpchksum(o_ip, o_tcp, size - sizeof(struct ethhdr) - sizeof(struct iphdr)); + assert(sendto(fd, o_eth, size, 0, (struct sockaddr*) &sall, sizeof(struct sockaddr_ll)) == size); + } + } + } + close(fd); +} |