summaryrefslogtreecommitdiff
path: root/accel-pppd/ppp/ccp_mppe.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/ppp/ccp_mppe.c')
-rw-r--r--accel-pppd/ppp/ccp_mppe.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/accel-pppd/ppp/ccp_mppe.c b/accel-pppd/ppp/ccp_mppe.c
new file mode 100644
index 00000000..0952aa01
--- /dev/null
+++ b/accel-pppd/ppp/ccp_mppe.c
@@ -0,0 +1,259 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include "linux_ppp.h"
+
+#include "ppp.h"
+#include "ppp_ccp.h"
+#include "log.h"
+#include "events.h"
+
+#include "memdebug.h"
+
+#define MPPE_H (1 << 24)
+#define MPPE_M (1 << 7)
+#define MPPE_S (1 << 6)
+#define MPPE_L (1 << 5)
+#define MPPE_D (1 << 4)
+#define MPPE_C (1 << 0)
+
+#define MPPE_PAD 4
+
+static struct ccp_option_t *mppe_init(struct ppp_ccp_t *ccp);
+static void mppe_free(struct ppp_ccp_t *ccp, struct ccp_option_t *opt);
+static int mppe_send_conf_req(struct ppp_ccp_t *ccp, struct ccp_option_t *opt, uint8_t *ptr);
+static int mppe_recv_conf_req(struct ppp_ccp_t *ccp, struct ccp_option_t *opt, uint8_t *ptr);
+static int mppe_recv_conf_nak(struct ppp_ccp_t *ccp, struct ccp_option_t *opt, uint8_t *ptr);
+static int mppe_recv_conf_rej(struct ppp_ccp_t *ccp, struct ccp_option_t *opt, uint8_t *ptr);
+static void mppe_print(void (*print)(const char *fmt,...),struct ccp_option_t*, uint8_t *ptr);
+
+struct mppe_option_t
+{
+ struct ccp_option_t opt;
+ int mppe;
+ uint8_t recv_key[16];
+ uint8_t send_key[16];
+ int policy; // 1 - allowed, 2 - required
+};
+
+static struct ccp_option_handler_t mppe_opt_hnd = {
+ .init = mppe_init,
+ .send_conf_req = mppe_send_conf_req,
+ .send_conf_nak = mppe_send_conf_req,
+ .recv_conf_req = mppe_recv_conf_req,
+ .recv_conf_nak = mppe_recv_conf_nak,
+ .recv_conf_rej = mppe_recv_conf_rej,
+ .free = mppe_free,
+ .print = mppe_print,
+};
+
+static struct ccp_option_t *mppe_init(struct ppp_ccp_t *ccp)
+{
+ struct mppe_option_t *mppe_opt = _malloc(sizeof(*mppe_opt));
+ memset(mppe_opt, 0, sizeof(*mppe_opt));
+ mppe_opt->mppe = -1;
+ mppe_opt->opt.id = CI_MPPE;
+ mppe_opt->opt.len = 6;
+
+ return &mppe_opt->opt;
+}
+
+static void mppe_free(struct ppp_ccp_t *ccp, struct ccp_option_t *opt)
+{
+ struct mppe_option_t *mppe_opt = container_of(opt, typeof(*mppe_opt), opt);
+
+ _free(mppe_opt);
+}
+
+static int setup_mppe_key(int fd, int transmit, uint8_t *key)
+{
+ struct ppp_option_data data;
+ uint8_t buf[6 + 16];
+
+ memset(buf, 0, sizeof(buf));
+ buf[0] = CI_MPPE;
+ buf[1] = 6;
+ *(uint32_t*)(buf + 2) = htonl(MPPE_S | MPPE_H);
+ if (key)
+ memcpy(buf + 6, key, 16);
+
+ memset(&data, 0, sizeof(data));
+ data.ptr = buf;
+ data.length = sizeof(buf);
+ data.transmit = transmit;
+
+ if (ioctl(fd, PPPIOCSCOMPRESS, &data)) {
+ log_ppp_warn("mppe: MPPE requested but not supported by kernel\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int decrease_mtu(struct ppp_t *ppp)
+{
+ struct ifreq ifr;
+
+ strcpy(ifr.ifr_name, ppp->ifname);
+
+ if (ioctl(sock_fd, SIOCGIFMTU, &ifr)) {
+ log_ppp_error("mppe: failed to get MTU: %s\n", strerror(errno));
+ return -1;
+ }
+
+ ifr.ifr_mtu -= MPPE_PAD;
+
+ if (ioctl(sock_fd, SIOCSIFMTU, &ifr)) {
+ log_ppp_error("mppe: failed to set MTU: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mppe_send_conf_req(struct ppp_ccp_t *ccp, struct ccp_option_t *opt, uint8_t *ptr)
+{
+ struct mppe_option_t *mppe_opt = container_of(opt,typeof(*mppe_opt),opt);
+ struct ccp_opt32_t *opt32 = (struct ccp_opt32_t*)ptr;
+
+ if (mppe_opt->mppe != -1) {
+ opt32->hdr.id = CI_MPPE;
+ opt32->hdr.len = 6;
+ opt32->val = mppe_opt->mppe ? htonl(MPPE_S | MPPE_H) : 0;
+
+ if (mppe_opt->mppe && setup_mppe_key(ccp->ppp->unit_fd, 0, mppe_opt->recv_key))
+ return 0;
+
+ return 6;
+ }
+ return 0;
+}
+
+static int mppe_recv_conf_req(struct ppp_ccp_t *ccp, struct ccp_option_t *opt, uint8_t *ptr)
+{
+ struct mppe_option_t *mppe_opt = container_of(opt, typeof(*mppe_opt), opt);
+ struct ccp_opt32_t *opt32 = (struct ccp_opt32_t *)ptr;
+
+ /*if (!ptr) {
+ if (mppe_opt->policy == 2)
+ return CCP_OPT_NAK;
+ return CCP_OPT_ACK;
+ }*/
+
+ if (opt32->hdr.len != 6)
+ return CCP_OPT_REJ;
+
+ if (mppe_opt->policy == 2) {
+ if (ntohl(opt32->val) != (MPPE_S | MPPE_H))
+ return CCP_OPT_NAK;
+ } else if (mppe_opt->policy == 1) {
+ if (ntohl(opt32->val) == (MPPE_S | MPPE_H))
+ mppe_opt->mppe = 1;
+ else if ((ntohl(opt32->val) & (MPPE_S | MPPE_H)) == (MPPE_S | MPPE_H)) {
+ mppe_opt->mppe = 1;
+ return CCP_OPT_NAK;
+ } else if (opt32->val) {
+ mppe_opt->mppe = 0;
+ return CCP_OPT_NAK;
+ } else
+ mppe_opt->mppe = 0;
+ } else
+ return CCP_OPT_REJ;
+
+ if (mppe_opt->mppe) {
+ if (setup_mppe_key(ccp->ppp->unit_fd, 1, mppe_opt->send_key))
+ return CCP_OPT_REJ;
+
+ decrease_mtu(ccp->ppp);
+
+ log_ppp_debug(" (mppe enabled)");
+ }
+
+ return CCP_OPT_ACK;
+}
+
+static int mppe_recv_conf_rej(struct ppp_ccp_t *ccp, struct ccp_option_t *opt, uint8_t *ptr)
+{
+ struct mppe_option_t *mppe_opt = container_of(opt, typeof(*mppe_opt), opt);
+
+ if (mppe_opt->mppe != 2) {
+ mppe_opt->mppe = -1;
+ return 0;
+ }
+
+ return -1;
+}
+
+static int mppe_recv_conf_nak(struct ppp_ccp_t *ccp, struct ccp_option_t *opt, uint8_t *ptr)
+{
+ struct mppe_option_t *mppe_opt = container_of(opt, typeof(*mppe_opt), opt);
+ struct ccp_opt32_t *opt32 = (struct ccp_opt32_t *)ptr;
+
+ if (opt32->hdr.len != 6)
+ return -1;
+
+ if (mppe_opt->policy == 2) {
+ if (ntohl(opt32->val) == (MPPE_S | MPPE_H))
+ return -1;
+ } else if (mppe_opt->policy == 1) {
+ if ((ntohl(opt32->val) & (MPPE_S | MPPE_H)) == (MPPE_S | MPPE_H))
+ mppe_opt->mppe = 0;
+ else
+ mppe_opt->mppe = 1;
+ } else {
+ if (opt32->val == 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static void mppe_print(void (*print)(const char *fmt,...),struct ccp_option_t *opt, uint8_t *ptr)
+{
+ struct mppe_option_t *mppe_opt = container_of(opt, typeof(*mppe_opt), opt);
+ struct ccp_opt32_t *opt32 = (struct ccp_opt32_t *)ptr;
+ uint32_t bits;
+
+ if (ptr)
+ bits = ntohl(opt32->val);
+ else
+ if (mppe_opt->mppe)
+ bits = MPPE_S | MPPE_H;
+ else
+ bits = 0;
+
+ print("<mppe %sH %sM %sS %sL %sD %sC>",
+ bits & MPPE_H ? "+" : "-",
+ bits & MPPE_M ? "+" : "-",
+ bits & MPPE_S ? "+" : "-",
+ bits & MPPE_L ? "+" : "-",
+ bits & MPPE_D ? "+" : "-",
+ bits & MPPE_C ? "+" : "-"
+ );
+}
+
+static void ev_mppe_keys(struct ev_mppe_keys_t *ev)
+{
+ struct mppe_option_t *mppe_opt = container_of(ccp_find_option(ev->ppp, &mppe_opt_hnd), typeof(*mppe_opt), opt);
+
+ if ((ev->type & 0x04) == 0) {
+ log_ppp_warn("mppe: 128-bit session keys not allowed, disabling mppe ...\n");
+ return;
+ }
+
+ memcpy(mppe_opt->recv_key, ev->recv_key, 16);
+ memcpy(mppe_opt->send_key, ev->send_key, 16);
+ mppe_opt->policy = ev->policy;
+
+ if (ev->policy == 2)
+ mppe_opt->mppe = 1;
+}
+
+static void __init mppe_opt_init()
+{
+ ccp_option_register(&mppe_opt_hnd);
+ triton_event_register_handler(EV_MPPE_KEYS, (triton_event_func)ev_mppe_keys);
+}
+