summaryrefslogtreecommitdiff
path: root/forcessl.c
diff options
context:
space:
mode:
authorstww <securethewebwith@priveasy.de>2011-10-31 17:23:41 (GMT)
committerstww <securethewebwith@priveasy.de>2011-10-31 17:23:41 (GMT)
commit635b2bb4009a6f9f66ffbed9b5d94173f6ac029b (patch)
tree61b07578ba272d32a7db298262480fa54ed924a9 /forcessl.c
Initial commitHEADmaster
Diffstat (limited to 'forcessl.c')
-rw-r--r--forcessl.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/forcessl.c b/forcessl.c
new file mode 100644
index 0000000..3360397
--- /dev/null
+++ b/forcessl.c
@@ -0,0 +1,253 @@
+/* TODO: act proper if interface is promisc (only reply to packets
+ send to local host */
+
+#include <arpa/inet.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 <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BLEN 512
+
+const char *payloads[] = {
+ // redirect using javascript with Meta-Refresh as fallback (works
+ // only with browsers, sends dangerous HTTP 200 independent of the
+ // request):
+ "HTTP/1.0 200 OK\r\n"
+ "Refresh: 1; url=https://%s/forcessl_nojs\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<html><body>"
+ "<script language=\"Javascript\">"
+ "location.href = location.href.replace(/^http/i, \"https\");"
+ "</script>"
+ "enabling crypto..."
+ "</body></html>",
+
+ // redirect using 301 (closer to standart, friendly to non-browser
+ // HTTP clients):
+
+ "HTTP/1.0 301 Not enough crypto to process request\r\n"
+ "Location: https://%s/forcessl_nojs\r\n"
+ "Content-type: text/html"
+ "\r\n"
+ "<html><body>"
+ "enabling crypto..."
+ "</body></html>" };
+
+#define AP0(x) if (!(x)) { perror(NULL); exit(EXIT_FAILURE); }
+#define APN(x) if ((x) < 0) { perror(NULL); exit(EXIT_FAILURE); }
+
+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;
+}
+
+void printopts(char **argv) {
+ printf("Usage: %s -i interface [-3|-j] [-p port] [-h target-host]\n"
+ "\t-i interface to listen on\n"
+ "\t-3 use HTTP 301 reponses for redirection\n"
+ "\t-j use Javascript with Meta-Refresh as fallback for redirection (default)\n"
+ "\t-p port to listen (default: 80)\n"
+ "\t-h hostname of the redirection target; if unspecified the request destination IP is used\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv) {
+ // parse cmd line args
+ int opt,
+ port = htons(80);
+ char *target_host = NULL,
+ *output_device = NULL;
+ const char *raw_payload = payloads[0];
+ while ((opt = getopt(argc, argv, "3jp:h:i:")) != -1) {
+ switch (opt) {
+ case 'p':
+ port = htons(atoi(optarg));
+ break;
+ case 'h':
+ AP0(target_host = strdup(optarg));
+ break;
+ case 'i':
+ AP0(output_device = strdup(optarg));
+ break;
+ case '3':
+ raw_payload = payloads[1];
+ break;
+ case 'j':
+ raw_payload = payloads[0];
+ break;
+ default:
+ printopts(argv);
+ }
+ }
+ if (!output_device)
+ printopts(argv);
+
+ // prepare input buffer
+ char *ibuf = malloc(BLEN);
+ AP0(ibuf);
+ 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) - 1 +
+ (target_host ? strlen(target_host) : 15);
+ char *obuf = malloc(os);
+ AP0(obuf);
+ 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);
+
+ if (os - sizeof(struct ethhdr) > 512)
+ fprintf(stderr, "warning: resulting packet size %ld exceeds MTU 512\n",
+ os - sizeof(struct ethhdr));
+
+ // setup sock
+ int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
+ APN(fd);
+
+ // retrieve interface idx (for send())
+ int ifidx;
+ {
+ struct ifreq req;
+ strcpy((char*) &(req.ifr_name), output_device);
+ APN(ioctl(fd, SIOCGIFINDEX, &req));
+ ifidx = req.ifr_ifindex;
+ }
+
+ // bind to interface
+ 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;
+ APN(bind(fd, (struct sockaddr*) &sall, sizeof(sall)));
+
+ // 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 = 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)
+
+ if (target_host)
+ snprintf(o_pld, strlen(raw_payload) + strlen(target_host) - 1,
+ raw_payload, target_host);
+
+
+ // read packets forever
+ while (1) {
+ int is = recv(fd, ibuf, BLEN, 0);
+ APN(is);
+ if ((is >= sizeof(struct ethhdr) + sizeof(struct iphdr)
+ + sizeof(struct tcphdr)) && // packet long enough?
+ (i_eth->h_proto == htons(ETH_P_IP)) && // ip protocol?
+ (i_ip->ihl == 5) && // no IP options
+ (i_ip->protocol == 6) && // tcp protocol?
+ (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?
+ 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;
+ o_tcp->syn = 1;
+ }else if (i_tcp->ack) {
+ 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 (!target_host) {
+ struct in_addr ba;
+ ba.s_addr = i_ip->daddr;
+ char *sa = inet_ntoa(ba);
+ snprintf(o_pld, os - (o_pld - (char*) o_eth),
+ raw_payload, sa);
+ size = size - 15 + strlen(sa);
+ }
+ }
+
+ 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));
+ if (sendto(fd, o_eth, size, 0, (struct sockaddr*) &sall, sizeof(struct sockaddr_ll)) != size) {
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+ }
+}
contact: Jan Huwald // Impressum