提交 e281cbf2 编写于 作者: K Kozlov Dmitry

ppp: Neighbor Discovery for IP version 6 (prefix only)

上级 a1e212b0
......@@ -144,11 +144,11 @@ snmptable -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::sessionsTabl
3. Terminate session by session identifier (Acct-Session-ID):
snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termBySID.0 = 0000000000000001
4. Terminate session by interface name:
snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByIfName = ppp2
snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByIfName.0 = ppp2
5. Terminaten session by IP address (Framed-IP-Address):
snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByIP = 192.168.10.10
snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByIP.0 = 192.168.10.10
6. Terminate session by username:
snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByUsername = user1
snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByUsername.0 = user1
Warning !!!
......
......@@ -69,6 +69,7 @@ ADD_EXECUTABLE(accel-pppd
ppp/ppp_ipv6cp.c
ppp/ppp_ccp.c
ppp/ccp_mppe.c
ppp/ipv6_nd.c
cli/std_cmd.c
cli/show_sessions.c
......
......@@ -47,6 +47,7 @@ static void generate_pool(struct in6_addr *addr, int mask, int prefix_len)
for (; ip <= endip; ip += step) {
it = malloc(sizeof(*it));
*(uint64_t *)it->it.addr.s6_addr = htobe64(ip);
it->it.prefix_len = prefix_len;
list_add_tail(&it->entry, &ippool);
}
}
......
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include "log.h"
#include "ppp.h"
#include "events.h"
#include "memdebug.h"
static int conf_init_ra = 3;
static int conf_init_ra_interval = 1;
static int conf_ra_interval = 60;
struct ipv6_nd_handler_t
{
struct ppp_t *ppp;
struct ppp_pd_t pd;
struct triton_md_handler_t hnd;
struct triton_timer_t timer;
int ra_sent;
};
static void *pd_key;
#define BUF_SIZE 1024
static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h)
{
void *buf = _malloc(BUF_SIZE);
struct nd_router_advert *adv = buf;
struct nd_opt_prefix_info *pinfo;
//struct nd_opt_route_info *rinfo;
//struct nd_opt_rdnss_info_local *rdnssinfo;
//struct nd_opt_mtu *mtu;
struct sockaddr_in6 addr;
memset(adv, 0, sizeof(*adv));
adv->nd_ra_type = ND_ROUTER_ADVERT;
adv->nd_ra_curhoplimit = 64;
adv->nd_ra_router_lifetime = htons(1);
//adv->nd_ra_reachable = 0;
//adv->nd_ra_retransmit = 0;
pinfo = (struct nd_opt_prefix_info *)(adv + 1);
memset(pinfo, 0, sizeof(*pinfo));
pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
pinfo->nd_opt_pi_len = 4;
pinfo->nd_opt_pi_prefix_len = h->ppp->ipv6_prefix_len;
pinfo->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO;
pinfo->nd_opt_pi_valid_time = 0xffffffff;
pinfo->nd_opt_pi_preferred_time = 0xffffffff;
memcpy(&pinfo->nd_opt_pi_prefix, &h->ppp->ipv6_addr, 8);
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr.s6_addr32[0] = htonl(0xff020000);
addr.sin6_addr.s6_addr32[3] = htonl(0x1);
addr.sin6_scope_id = h->ppp->ifindex;
sendto(h->hnd.fd, buf, (void *)(pinfo + 1) - buf, 0, (struct sockaddr *)&addr, sizeof(addr));
_free(buf);
}
static void send_ra_timer(struct triton_timer_t *t)
{
struct ipv6_nd_handler_t *h = container_of(t, typeof(*h), timer);
if (h->ra_sent++ == conf_init_ra) {
h->timer.period = conf_ra_interval * 1000;
triton_timer_mod(t, 0);
}
ipv6_nd_send_ra(h);
}
static int ipv6_nd_read(struct triton_md_handler_t *_h)
{
struct ipv6_nd_handler_t *h = container_of(_h, typeof(*h), hnd);
struct msghdr mhdr;
int chdr_len;
struct iovec iov;
struct cmsghdr *chdr, *cmsg;
struct in6_pktinfo *pkt_info;
struct icmp6_hdr *icmph;
void *buf;
int n;
chdr_len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
chdr = _malloc(chdr_len);
buf = _malloc(BUF_SIZE);
iov.iov_len = BUF_SIZE;
iov.iov_base = buf;
memset(&mhdr, 0, sizeof(mhdr));
mhdr.msg_iov = &iov;
mhdr.msg_iovlen = 1;
mhdr.msg_control = chdr;
mhdr.msg_controllen = chdr_len;
while (1) {
n = recvmsg(h->hnd.fd, &mhdr, 0);
if (n == -1) {
if (errno == EAGAIN)
break;
log_ppp_error("ipv6_nd: recvmsg: %s\n", strerror(errno));
continue;
}
pkt_info = NULL;
for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
if (cmsg->cmsg_level == IPPROTO_IPV6 &&
cmsg->cmsg_type == IPV6_PKTINFO) {
if (cmsg->cmsg_len != CMSG_LEN(sizeof(*pkt_info)))
log_ppp_warn("ipv6_nd: received invalid IPV6_PKTINFO\n");
else
pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
break;
}
}
if (!pkt_info) {
log_ppp_warn("ipv6_nd: no IPV6_PKTINFO\n");
continue;
}
if (n < sizeof(*icmph)) {
log_ppp_warn("ipv6_nd: received short icmp packet (%i)\n", n);
continue;
}
icmph = buf;
if (icmph->icmp6_type != ND_ROUTER_SOLICIT) {
log_ppp_warn("ipv6_nd: received unexcpected icmp packet (%i)\n", icmph->icmp6_type);
continue;
}
/*if (!IN6_IS_ADDR_LINKLOCAL(&pkt_info->ipi6_addr)) {
log_ppp_warn("ipv6_nd: received icmp packet from non link-local address\n");
continue;
}*/
/*if (*(uint64_t *)(pkt_info->ipi6_addr.s6_addr + 8) != *(uint64_t *)(h->ppp->ipv6_addr.s6_addr + 8)) {
log_ppp_warn("ipv6_nd: received icmp packet from unknown address\n");
continue;
}*/
ipv6_nd_send_ra(h);
}
_free(chdr);
_free(buf);
return 0;
}
int ppp_ipv6_nd_start(struct ppp_t *ppp, uint64_t intf_id)
{
int sock;
struct icmp6_filter filter;
struct sockaddr_in6 addr;
struct ipv6_mreq mreq;
int val;
struct ipv6_nd_handler_t *h;
sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (sock < 0) {
log_ppp_error("socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6): %s\n", strerror(errno));
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr.s6_addr32[0] = htons(0xfe80);
*(uint64_t *)(addr.sin6_addr.s6_addr + 8) = intf_id;
addr.sin6_scope_id = ppp->ifindex;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
log_ppp_error("ipv6_nd: bind: %s %i\n", strerror(errno), errno);
goto out_err;
}
val = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_PKTINFO): %s\n", strerror(errno));
goto out_err;
}
val = 2;
if (setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_CHECKSUM): %s\n", strerror(errno));
goto out_err;
}
val = 255;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_UNICAST_HOPS): %s\n", strerror(errno));
goto out_err;
}
if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
goto out_err;
}
/*val = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_HOPLIMIT): %s\n", strerror(errno));
goto out_err;
}*/
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter))) {
log_ppp_error("ipv6_nd: setsockopt(ICMP6_FILTER): %s\n", strerror(errno));
goto out_err;
}
memset(&mreq, 0, sizeof(mreq));
mreq.ipv6mr_interface = ppp->ifindex;
mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xff020000);
mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x2);
if (setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
log_ppp_error("ipv6_nd: failed to join ipv6 allrouters\n");
goto out_err;
}
fcntl(sock, F_SETFL, O_NONBLOCK);
h = _malloc(sizeof(*h));
memset(h, 0, sizeof(*h));
h->ppp = ppp;
h->pd.key = &pd_key;
h->hnd.fd = sock;
h->hnd.read = ipv6_nd_read;
h->timer.expire = send_ra_timer;
h->timer.period = conf_init_ra_interval * 1000;
list_add_tail(&h->pd.entry, &ppp->pd_list);
triton_md_register_handler(ppp->ctrl->ctx, &h->hnd);
triton_md_enable_handler(&h->hnd, MD_MODE_READ);
return 0;
out_err:
close(sock);
return -1;
}
static struct ipv6_nd_handler_t *find_pd(struct ppp_t *ppp)
{
struct ppp_pd_t *pd;
list_for_each_entry(pd, &ppp->pd_list, entry) {
if (pd->key == &pd_key)
return container_of(pd, typeof(struct ipv6_nd_handler_t), pd);
}
return NULL;
}
static void ev_ppp_started(struct ppp_t *ppp)
{
struct ipv6_nd_handler_t *h = find_pd(ppp);
if (!h)
return;
triton_timer_add(ppp->ctrl->ctx, &h->timer, 0);
}
static void ev_ppp_finishing(struct ppp_t *ppp)
{
struct ipv6_nd_handler_t *h = find_pd(ppp);
if (!h)
return;
triton_timer_del(&h->timer);
triton_md_unregister_handler(&h->hnd);
close(h->hnd.fd);
list_del(&h->pd.entry);
_free(h);
}
static void init(void)
{
triton_event_register_handler(EV_PPP_STARTED, (triton_event_func)ev_ppp_started);
triton_event_register_handler(EV_PPP_FINISHING, (triton_event_func)ev_ppp_finishing);
}
DEFINE_INIT(0, init);
......@@ -4,13 +4,10 @@
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <endian.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include "linux_ppp.h"
#include <netlink/netlink.h>
#include "log.h"
#include "events.h"
#include "ppp.h"
......@@ -130,6 +127,9 @@ static int ipaddr_send_conf_req(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_optio
if (conf_check_exists && check_exists(ipv6cp->ppp, &ipaddr_opt->ip->addr))
return -1;
ipv6cp->ppp->ipv6_addr = ipaddr_opt->ip->addr;
ipv6cp->ppp->ipv6_prefix_len = ipaddr_opt->ip->prefix_len;
opt64->hdr.id = CI_INTFID;
opt64->hdr.len = 10;
opt64->val = ipaddr_opt->intf_id;
......@@ -150,7 +150,6 @@ static int ipaddr_recv_conf_req(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_optio
{
struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt);
struct ipv6cp_opt64_t *opt64 = (struct ipv6cp_opt64_t* )ptr;
struct ifreq ifr;
struct in6_ifreq ifr6;
if (opt64->hdr.len != 10)
......@@ -178,25 +177,27 @@ ack:
//if (ipv6cp->ppp->stop_time)
// return IPV6CP_OPT_ACK;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ipv6cp->ppp->ifname);
memset(&ifr6, 0, sizeof(ifr6));
ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80);
*(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ipaddr_opt->intf_id;
ifr6.ifr6_prefixlen = 64;
ifr6.ifr6_ifindex = ipv6cp->ppp->ifindex;
if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) {
log_ppp_error("ppp:ipv6cp: ioctl(SIOCGIFINDEX): %s\n", strerror(errno));
if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) {
log_ppp_error("ppp:ipv6cp: ioctl(SIOCSIFADDR): %s\n", strerror(errno));
return IPV6CP_OPT_REJ;
}
memset(&ifr6, 0, sizeof(ifr6));
ifr6.ifr6_addr.s6_addr16[0] = htons(0xfe80);
*(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ipaddr_opt->intf_id;
ifr6.ifr6_prefixlen = 64;
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
memcpy(ifr6.ifr6_addr.s6_addr, ipaddr_opt->ip->addr.s6_addr, 8);
if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) {
log_ppp_error("ppp:ipv6cp: ioctl(SIOCSIFADDR): %s\n", strerror(errno));
return IPV6CP_OPT_REJ;
}
if (ppp_ipv6_nd_start(ipv6cp->ppp, ipaddr_opt->intf_id))
return IPV6CP_OPT_REJ;
return IPV6CP_OPT_ACK;
}
......
......@@ -88,6 +88,8 @@ static void generate_sessionid(struct ppp_t *ppp)
int __export establish_ppp(struct ppp_t *ppp)
{
struct ifreq ifr;
/* Open an instance of /dev/ppp and connect the channel to it */
if (ioctl(ppp->fd, PPPIOCGCHAN, &ppp->chan_idx) == -1) {
log_ppp_error("ioctl(PPPIOCGCHAN): %s\n", strerror(errno));
......@@ -136,8 +138,17 @@ int __export establish_ppp(struct ppp_t *ppp)
generate_sessionid(ppp);
sprintf(ppp->ifname, "ppp%i", ppp->unit_idx);
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ppp->ifname);
if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) {
log_ppp_error("ppp: ioctl(SIOCGIFINDEX): %s\n", strerror(errno));
goto exit_close_unit;
}
ppp->ifindex = ifr.ifr_ifindex;
log_ppp_info1("connect: %s <--> %s(%s)\n", ppp->ifname, ppp->ctrl->name, ppp->chan_name);
init_layers(ppp);
if (list_empty(&ppp->layers)) {
......
......@@ -95,6 +95,7 @@ struct ppp_t
int state;
char *chan_name;
char ifname[PPP_IFNAME_LEN];
int ifindex;
char sessionid[PPP_SESSIONID_LEN+1];
time_t start_time;
time_t stop_time;
......@@ -183,6 +184,8 @@ struct ppp_layer_data_t *ppp_find_layer_data(struct ppp_t *, struct ppp_layer_t
extern int ppp_shutdown;
void ppp_shutdown_soft(void);
int ppp_ipv6_nd_start(struct ppp_t *ppp, uint64_t intf_id);
extern int conf_ppp_verbose;
extern int conf_single_session;
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册