#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>

#define PORT    0x1234
#define BUFSIZE 8192

// kernel.randomize_va_space = 1
// Seit Kernel 2.6.12
/* Socket Stuff */
void read_from_socket(int sd, char * output){
    // Read a String from a socket
    if (recv(sd, output, BUFSIZE - 1, 0) == -1) {
        perror("recv");
        exit(1);
    }
}

void shutdown_server(int sd, int sd_current){
    /* close up both sockets */
    close(sd_current); 
    close(sd);
        
    /* give client a chance to properly shutdown */
    sleep(1);
}

void init_server(int * sd, int * sd_current){
    int      cc, fromlen, tolen;
    int      addrlen;
    struct   sockaddr_in sin;
    struct   sockaddr_in pin;

    /* get an internet domain socket */
    if ((*sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    // Set Socket Options to avoid "address already in use errors"
    int foo = 0;
    if(setsockopt(*sd, SOL_SOCKET, SO_REUSEADDR, &foo, sizeof(foo)) < 0) {
        perror("(setsockopt) ");
        return; 
    }

    /* complete the socket structure */
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(PORT);

    /* bind the socket to the port number */
    if (bind(*sd, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
        perror("bind");
        exit(1);
    }

    /* show that we are willing to listen */
    if (listen(*sd, 5) == -1) {
        perror("listen");
        exit(1);
    }
    /* wait for a client to talk to us */
    addrlen = sizeof(pin); 
    if ((*sd_current = accept(*sd, (struct sockaddr *)  &pin, &addrlen)) == -1) {
        perror("accept");
        exit(1);
    }

    printf("Hi there, from  %s#\n",inet_ntoa(pin.sin_addr));
    printf("Coming from port %d\n",ntohs(pin.sin_port));
}
/* Ende Socket Stuff */

/* Exploitbarer Krempel */
int bar (){
    printf("Exploit successfull!\n");
}


void function(int sd_current, int b, int c) {
    unsigned char buffer1[140];
    unsigned char buffer2[180];
    int *ret;

    // read from socket 
    read_from_socket(sd_current, buffer1);

    //printf("INPUT: %s\n", buffer2);

    // Buffer 2 in Buffer 1 kopieren
    //strcpy(buffer1, buffer2);
    
    // Rücksprungadresse ausgeben
    printf("Return addresse is set to: \t0x%x\n", *(int *)(buffer1 + 148)); 

    // Adresse von Funktion bar ausgeben
    printf("Function bar is located at: \t0x0%x\n", &bar); 

    // Adresse von Printf ausgeben
    printf("Function printf is located at: \t0x0%x\n", &printf);

    // Position von buffer1 im Speicher
    printf("Shellcode Entrypoint: \t\t0x%x\n", &buffer1);
}

int main() {
    int      sd, sd_current; /* File descriptors for socket */
    

    // Init Server
    init_server(&sd, &sd_current);

    // Execute Function
    function(sd_current, 2, 3);

    // shutdown connection
    shutdown_server(sd, sd_current);
}

// http://www.phrack.org/archives/49/P49-14
// http://www.cert.org/secure-coding/content/t4-seacord-secure-codingv4pdf.pdf
