#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include typedef unsigned long long aligned_u64; #include typedef unsigned char u8; typedef unsigned short u16; typedef unsigned u32; typedef unsigned long long u64; #include "sau.c" int mk_udp_sa(union sockaddru *local, union sockaddru *remote) { int udp_fd; udp_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (udp_fd < 0) { perror("socket(udp)\n"); exit(1); } int one = 1; if (setsockopt(udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one)) { perror("setsockopt(SO_REUSEADDR)"); exit(1); } if (bind(udp_fd, &local->sa, sizeof(*local))) { perror("bind(UDP)"); exit(1); } if (connect(udp_fd, &remote->sa, sizeof(*remote))) { perror("connect(UDP)"); exit(1); } return udp_fd; } int mk_udp(char *local_addr, char *remote_addr) { union sockaddru *local, *remote; local = parse_sockaddru(local_addr); remote = parse_sockaddru(remote_addr); return mk_udp_sa(local, remote); } int mk_l2tp_session(int udp_fd, u16 our_tunnel_id, u16 our_session_id, u16 peer_tunnel_id, u16 peer_session_id) { int tunnel_fd, session_fd; tunnel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); if (tunnel_fd < 0) { perror("socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP)"); exit(1); } struct sockaddr_pppol2tp tunnel_sa = { .sa_family = AF_PPPOX, .sa_protocol = PX_PROTO_OL2TP, .pppol2tp.fd = udp_fd, .pppol2tp.s_tunnel = our_tunnel_id, .pppol2tp.s_session = 0, .pppol2tp.d_tunnel = peer_tunnel_id, .pppol2tp.d_session = 0, }; if (connect(tunnel_fd, (struct sockaddr *)&tunnel_sa, sizeof(tunnel_sa))) { perror("connect(tunnel_fd)"); return 1; } session_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); if (session_fd < 0) { perror("socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP)"); return 1; } struct sockaddr_pppol2tp session_sa = { .sa_family = AF_PPPOX, .sa_protocol = PX_PROTO_OL2TP, .pppol2tp.fd = udp_fd, .pppol2tp.s_tunnel = our_tunnel_id, .pppol2tp.s_session = our_session_id, .pppol2tp.d_tunnel = peer_tunnel_id, .pppol2tp.d_session = peer_session_id, }; if (connect(session_fd, (struct sockaddr *)&session_sa, sizeof(tunnel_sa))) { perror("connect(session_fd)"); return 1; } return session_fd; } int mk_ppp_chan_dev(int session_fd) { int chindex; int ppp_fd; if (ioctl(session_fd, PPPIOCGCHAN, &chindex)) { perror("ioctl(PPPIOCGCHAN)"); exit(1); } ppp_fd = open("/dev/ppp", O_RDWR); if (ppp_fd < 0) { perror("open(/dev/ppp)"); exit(1); } if (ioctl(ppp_fd, PPPIOCATTCHAN, &chindex)) { perror("ioctl(PPPIOCATTCHAN)"); exit(1); } return ppp_fd; } int mk_ppp_dev(int chan_fd, int *unit) { int ppp_fd; *unit = -1; #if 0 int chindex; if (ioctl(chan_fd, PPPIOCGCHAN, &chindex)) { perror("ioctl(PPPIOCGCHAN)"); exit(1); } #endif ppp_fd = open("/dev/ppp", O_RDWR); if (ppp_fd < 0) { perror("open(/dev/ppp)"); exit(1); } if (ioctl(ppp_fd, PPPIOCNEWUNIT, unit)) { perror("ioctl(PPPIOCATTCHAN)"); exit(1); } printf("created unit %d, fd %d\n", *unit, ppp_fd); int flags = 0; if (ioctl(ppp_fd, PPPIOCSFLAGS, &flags)) { perror("ioctl(PPPIOCSFLAGS)"); exit(1); } if (ioctl(chan_fd, PPPIOCCONNECT, unit)) { perror("ioctl(PPPIOCCONNECT)"); exit(1); } return ppp_fd; } int getifindex(int fd, int unit) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); sprintf(ifr.ifr_name, "ppp%d", unit); if (ioctl(fd, SIOCGIFINDEX, &ifr)) { perror("ioctl(SIOCGIFINDEX)"); exit(1); } printf("unit %d ifindex %d\n", unit, ifr.ifr_ifindex); return ifr.ifr_ifindex; } #define PPPIOCSMULTIHOP_IF _IOWR('t', 91, int) /* set multihop if */ void setup_multihop(int ppp_fd, int ifindex) { if (ioctl(ppp_fd, PPPIOCSMULTIHOP_IF, &ifindex)) { perror("ioctl(PPPIOCSMULTIHOP_IF)"); exit(1); } } int main(void) { int udp1_fd, udp2_fd; int session1_fd, session2_fd; int chan1_fd, chan2_fd; int ppp1_fd, ppp2_fd; int unit1, unit2; int ifindex1, ifindex2; udp1_fd = mk_udp("192.168.122.20@1701", "192.168.122.1@1701"); udp2_fd = mk_udp("192.168.122.20@1701", "192.168.122.11@1701"); session1_fd = mk_l2tp_session(udp1_fd, 2020, 2, 2000, 2); session2_fd = mk_l2tp_session(udp2_fd, 2021, 2, 2001, 2); chan1_fd = mk_ppp_chan_dev(session1_fd); chan2_fd = mk_ppp_chan_dev(session2_fd); ppp1_fd = mk_ppp_dev(chan1_fd, &unit1); ppp2_fd = mk_ppp_dev(chan2_fd, &unit2); ifindex1 = getifindex(udp1_fd, unit1); ifindex2 = getifindex(udp2_fd, unit2); setup_multihop(ppp1_fd, ifindex2); setup_multihop(ppp2_fd, ifindex1); printf("okay!\n"); fflush(stdout); getchar(); printf("shutting down\n"); setup_multihop(ppp1_fd, -1); setup_multihop(ppp2_fd, -1); return 0; }