summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..89c23fc
--- /dev/null
+++ b/main.c
@@ -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);
+}
contact: Jan Huwald // Impressum