Exemplo n.º 1
0
Arquivo: rarpd.c Projeto: afett/rarpd
int find_interfaces(struct rarpd *rarpd)
{
	if (nl_open(&rarpd->nl_ctx) != 0) {
		return -1;
	}

	if (get_links(rarpd) != 0) {
		return -1;
	}

	if (get_addresses(rarpd) != 0) {
		return -1;
	}

	nl_close(&rarpd->nl_ctx);
	return 0;
}
int
netlink_dad_start( int *fd )
{
    int status;
    //int fd;
    struct msghdr msg;
    struct sockaddr_nl dest_addr;
    struct nlmsghdr *nlh;
    struct iovec iov;
    struct dad_failed_msg_t *dad_msg;

    *fd = nl_open();
    if ( *fd < 0) {
        dprintf(LOG_INFO, FNAME, "nl_open failed\n");
        perror("Error\n");
        return 1;
    }

    return 0;
}
Exemplo n.º 3
0
int nl_send(struct nl_handle *hnd, struct iovec *iov, int iovlen)
{
	struct sockaddr_nl sa = {
		.nl_family = AF_NETLINK,
	};
	struct msghdr msg = {
		.msg_name = &sa,
		.msg_namelen = sizeof(sa),
		.msg_iov = iov,
		.msg_iovlen = iovlen,
	};
	struct nlmsghdr *src = iov->iov_base;

	src->nlmsg_seq = ++hnd->seq;
	if (sendmsg(hnd->fd, &msg, 0) < 0)
		return errno;
	return 0;
}

int nl_recv(struct nl_handle *hnd, struct nlmsg_entry **dest, int is_dump)
{
	struct sockaddr_nl sa = {
		.nl_family = AF_NETLINK,
	};
	struct iovec iov;
	struct msghdr msg = {
		.msg_name = &sa,
		.msg_namelen = sizeof(sa),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	char buf[16384];
	int len, err;
	struct nlmsghdr *n;
	struct nlmsg_entry *ptr = NULL; /* GCC false positive */
	struct nlmsg_entry *entry;

	*dest = NULL;
	while (1) {
		iov.iov_base = buf;
		iov.iov_len = sizeof(buf);
		len = recvmsg(hnd->fd, &msg, 0);
		if (len < 0)
			return errno;
		if (!len)
			return EPIPE;
		if (sa.nl_pid) {
			/* not from the kernel */
			continue;
		}
		for (n = (struct nlmsghdr *)buf; NLMSG_OK(n, len); n = NLMSG_NEXT(n, len)) {
			if (n->nlmsg_pid != hnd->pid || n->nlmsg_seq != hnd->seq)
				continue;
			if (is_dump && n->nlmsg_type == NLMSG_DONE)
				return 0;
			if (n->nlmsg_type == NLMSG_ERROR) {
				struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(n);

				err = -nlerr->error;
				goto err_out;
			}
			entry = malloc(n->nlmsg_len + sizeof(void *));
			if (!entry) {
				err = ENOMEM;
				goto err_out;
			}
			entry->next = NULL;
			memcpy(&entry->h, n, n->nlmsg_len);
			if (!*dest)
				*dest = entry;
			else
				ptr->next = entry;
			ptr = entry;
			if (!is_dump)
				return 0;
		}
	}
err_out:
	nlmsg_free(*dest);
	*dest = NULL;
	return err;
}

int nl_exchange(struct nl_handle *hnd,
		struct nlmsghdr *src, struct nlmsg_entry **dest)
{
	struct iovec iov = {
		.iov_base = src,
		.iov_len = src->nlmsg_len,
	};
	int is_dump;
	int err;

	is_dump = !!(src->nlmsg_flags & NLM_F_DUMP);
	err = nl_send(hnd, &iov, 1);
	if (err)
		return err;
	return nl_recv(hnd, dest, is_dump);
}

/* The original payload is not freed. Returns 0 in case of error, length
 * of *dest otherwise. *dest is newly allocated. */
int nla_add_str(void *orig, int orig_len, int nla_type, const char *str,
		void **dest)
{
	struct nlattr *nla;
	int len = strlen(str) + 1;
	int size;

	size = NLA_ALIGN(orig_len) + NLA_HDRLEN + NLA_ALIGN(len);
	*dest = calloc(size, 1);
	if (!*dest)
		return 0;
	if (orig_len)
		memcpy(*dest, orig, orig_len);
	nla = *dest + NLA_ALIGN(orig_len);
	nla->nla_len = NLA_HDRLEN + len;
	nla->nla_type = nla_type;
	memcpy(nla + 1, str, len);
	return size;
}

int rtnl_open(struct nl_handle *hnd)
{
	return nl_open(hnd, NETLINK_ROUTE);
}

int rtnl_dump(struct nl_handle *hnd, int family, int type, struct nlmsg_entry **dest)
{
	struct {
		struct nlmsghdr n;
		struct ifinfomsg i;
	} req;

	memset(&req, 0, sizeof(req));
	req.n.nlmsg_len = sizeof(req);
	req.n.nlmsg_type = type;
	req.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
	req.i.ifi_family = family;
	return nl_exchange(hnd, &req.n, dest);
}

void rtnl_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len)
{
	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
	while (RTA_OK(rta, len)) {
		if (rta->rta_type <= max)
			tb[rta->rta_type] = rta;
		rta = RTA_NEXT(rta, len);
	}
}

void rtnl_parse_nested(struct rtattr *tb[], int max, struct rtattr *rta)
{
	rtnl_parse(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta));
}

int genl_open(struct nl_handle *hnd)
{
	return nl_open(hnd, NETLINK_GENERIC);
}

int genl_request(struct nl_handle *hnd,
		 int type, int cmd, void *payload, int payload_len,
		 struct nlmsg_entry **dest)
{
	struct {
		struct nlmsghdr n;
		struct genlmsghdr g;
	} req;
	struct iovec iov[2];
	int err;

	memset(&req, 0, sizeof(req));
	req.n.nlmsg_len = sizeof(req) + payload_len;
	req.n.nlmsg_type = type;
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.g.cmd = cmd;
	req.g.version = 1;

	iov[0].iov_base = &req;
	iov[0].iov_len = sizeof(req);
	iov[1].iov_base = payload;
	iov[1].iov_len = payload_len;
	err = nl_send(hnd, iov, 2);
	if (err)
		return err;
	return nl_recv(hnd, dest, 0);
}

unsigned int genl_family_id(struct nl_handle *hnd, const char *name)
{
	unsigned int res = 0;
	struct nlattr *nla;
	int len;
	struct nlmsg_entry *dest;
	void *ptr;

	len = nla_add_str(NULL, 0, CTRL_ATTR_FAMILY_NAME, name, &ptr);
	if (!len)
		return 0;
	if (genl_request(hnd, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
			 ptr, len, &dest)) {
		free(ptr);
		return 0;
	}
	free(ptr);

	len = dest->h.nlmsg_len - NLMSG_HDRLEN - GENL_HDRLEN;
	ptr = (void *)&dest->h + NLMSG_HDRLEN + GENL_HDRLEN;

	while (len > NLA_HDRLEN) {
		nla = ptr;
		if (nla->nla_type == CTRL_ATTR_FAMILY_ID &&
		    nla->nla_len >= NLA_HDRLEN + 2) {
			res = *(uint16_t *)(nla + 1);
			break;
		}

		ptr += NLMSG_ALIGN(nla->nla_len);
		len -= NLMSG_ALIGN(nla->nla_len);
	}

	nlmsg_free(dest);
	return res;

}
Exemplo n.º 4
0
/* ====================================================================== */
int getifaddrs(struct ifaddrs **ifap)
{
  int sd;
  struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
  /* - - - - - - - - - - - - - - - */
  int icnt;
  size_t dlen, xlen, nlen;
  uint32_t max_ifindex = 0;

  pid_t pid = getpid();
  int seq;
  int result;
  int build     ; /* 0 or 1 */

/* ---------------------------------- */
  /* initialize */
  icnt = dlen = xlen = nlen = 0;
  nlmsg_list = nlmsg_end = NULL;

  if (ifap)
    *ifap = NULL;

/* ---------------------------------- */
  /* open socket and bind */
  sd = nl_open();
  if (sd < 0)
    return -1;

/* ---------------------------------- */
   /* gather info */
  if ((seq = nl_getlist(sd, 0, RTM_GETLINK,
			&nlmsg_list, &nlmsg_end)) < 0){
    free_nlmsglist(nlmsg_list);
    nl_close(sd);
    return -1;
  }
  if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR,
			&nlmsg_list, &nlmsg_end)) < 0){
    free_nlmsglist(nlmsg_list);
    nl_close(sd);
    return -1;
  }

/* ---------------------------------- */
  /* Estimate size of result buffer and fill it */
  for (build=0; build<=1; build++){
    struct ifaddrs *ifl = NULL, *ifa = NULL;
    struct nlmsghdr *nlh, *nlh0;
    void *data = NULL, *xdata = NULL, *ifdata = NULL;
    char *ifname = NULL, **iflist = NULL;
    uint16_t *ifflist = NULL;
    struct rtmaddr_ifamap ifamap;

    if (build){
      ifa = data = calloc(1,
			  NLMSG_ALIGN(sizeof(struct ifaddrs[icnt]))
			  + dlen + xlen + nlen);
      ifdata = calloc(1, 
		      NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))
		      + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1])));
      if (ifap != NULL)
	*ifap = (ifdata != NULL) ? ifa : NULL;
      else{
	free_data(data, ifdata);
	result = 0;
	break;
      }
      if (data == NULL || ifdata == NULL){
	free_data(data, ifdata);
	result = -1;
	break;
      }
      ifl = NULL;
      data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt;
      xdata = data + dlen;
      ifname = xdata + xlen;
      iflist = ifdata;
      ifflist = ((void *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1]));
    }

    for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){
      int nlmlen = nlm->size;
      if (!(nlh0 = nlm->nlh))
	continue;
      for (nlh = nlh0; 
	   NLMSG_OK(nlh, nlmlen); 
	   nlh=NLMSG_NEXT(nlh,nlmlen)){
	struct ifinfomsg *ifim = NULL;
	struct ifaddrmsg *ifam = NULL;
	struct rtattr *rta;

	size_t nlm_struct_size = 0;
	sa_family_t nlm_family = 0;
	uint32_t nlm_scope = 0, nlm_index = 0;
#ifndef IFA_NETMASK
	size_t sockaddr_size = 0;
	uint32_t nlm_prefixlen = 0;
#endif
	size_t rtasize;

	memset(&ifamap, 0, sizeof(ifamap));

	/* check if the message is what we want */
	if (nlh->nlmsg_pid != pid ||
	    nlh->nlmsg_seq != nlm->seq)
	  continue;
	if (nlh->nlmsg_type == NLMSG_DONE){
	  break; /* ok */
	}
	switch (nlh->nlmsg_type){
	case RTM_NEWLINK:
	  ifim = (struct ifinfomsg *)NLMSG_DATA(nlh);
	  nlm_struct_size = sizeof(*ifim);
	  nlm_family = ifim->ifi_family;
	  nlm_scope = 0;
	  nlm_index = ifim->ifi_index;
	  nlm_prefixlen = 0;
	  if (build)
	    ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags;
	  break;
	case RTM_NEWADDR:
	  ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh);
	  nlm_struct_size = sizeof(*ifam);
	  nlm_family = ifam->ifa_family;
	  nlm_scope = ifam->ifa_scope;
	  nlm_index = ifam->ifa_index;
	  nlm_prefixlen = ifam->ifa_prefixlen;
	  if (build)
	    ifa->ifa_flags = ifflist[nlm_index];
	  break;
	default:
	  continue;
	}
	
	if (!build){
	  if (max_ifindex < nlm_index)
	    max_ifindex = nlm_index;
	} else {
	  if (ifl != NULL)
	    ifl->ifa_next = ifa;
	}

	rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size);
	for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size));
	     RTA_OK(rta, rtasize);
	     rta = RTA_NEXT(rta, rtasize)){
	  struct sockaddr **sap = NULL;
	  void *rtadata = RTA_DATA(rta);
	  size_t rtapayload = RTA_PAYLOAD(rta);
	  socklen_t sa_len;

	  switch(nlh->nlmsg_type){
	  case RTM_NEWLINK:
	    switch(rta->rta_type){
	    case IFLA_ADDRESS:
	    case IFLA_BROADCAST:
	      if (build){
		sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr;
		*sap = (struct sockaddr *)data;
	      }
	      sa_len = ifa_sa_len(AF_PACKET, rtapayload);
	      if (rta->rta_type == IFLA_ADDRESS)
		sockaddr_size = NLMSG_ALIGN(sa_len);
	      if (!build){
		dlen += NLMSG_ALIGN(sa_len);
	      } else {
		memset(*sap, 0, sa_len);
		ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0);
		((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index;
		((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type;
		data += NLMSG_ALIGN(sa_len);
	      }
	      break;
	    case IFLA_IFNAME:/* Name of Interface */
	      if (!build)
		nlen += NLMSG_ALIGN(rtapayload + 1);
	      else{
		ifa->ifa_name = ifname;
		if (iflist[nlm_index] == NULL)
		  iflist[nlm_index] = ifa->ifa_name;
		strncpy(ifa->ifa_name, rtadata, rtapayload);
		ifa->ifa_name[rtapayload] = '\0';
		ifname += NLMSG_ALIGN(rtapayload + 1);
	      }
	      break;
	    case IFLA_STATS:/* Statistics of Interface */
	      if (!build)
		xlen += NLMSG_ALIGN(rtapayload);
	      else{
		ifa->ifa_data = xdata;
		memcpy(ifa->ifa_data, rtadata, rtapayload);
		xdata += NLMSG_ALIGN(rtapayload);
	      }
	      break;
	    case IFLA_UNSPEC:
	      break;
	    case IFLA_MTU:
	      break;
	    case IFLA_LINK:
	      break;
	    case IFLA_QDISC:
	      break;
	    }
	    break;
	  case RTM_NEWADDR:
	    if (nlm_family == AF_PACKET) break;
	    switch(rta->rta_type){
	    case IFA_ADDRESS:
		ifamap.address = rtadata;
		ifamap.address_len = rtapayload;
		break;
	    case IFA_LOCAL:
		ifamap.local = rtadata;
		ifamap.local_len = rtapayload;
		break;
	    case IFA_BROADCAST:
		ifamap.broadcast = rtadata;
		ifamap.broadcast_len = rtapayload;
		break;
#ifdef HAVE_IFADDRS_IFA_ANYCAST
	    case IFA_ANYCAST:
		ifamap.anycast = rtadata;
		ifamap.anycast_len = rtapayload;
		break;
#endif
	    case IFA_LABEL:
	      if (!build)
		nlen += NLMSG_ALIGN(rtapayload + 1);
	      else{
		ifa->ifa_name = ifname;
		if (iflist[nlm_index] == NULL)
		  iflist[nlm_index] = ifname;
		strncpy(ifa->ifa_name, rtadata, rtapayload);
		ifa->ifa_name[rtapayload] = '\0';
		ifname += NLMSG_ALIGN(rtapayload + 1);
	      }
	      break;
	    case IFA_UNSPEC:
	      break;
	    case IFA_CACHEINFO:
	      break;
	    }
	  }
	}
	if (nlh->nlmsg_type == RTM_NEWADDR &&
	    nlm_family != AF_PACKET) {
	  if (!ifamap.local) {
	    ifamap.local = ifamap.address;
	    ifamap.local_len = ifamap.address_len;
	  }
	  if (!ifamap.address) {
	    ifamap.address = ifamap.local;
	    ifamap.address_len = ifamap.local_len;
	  }
	  if (ifamap.address_len != ifamap.local_len ||
	      (ifamap.address != NULL &&
	       memcmp(ifamap.address, ifamap.local, ifamap.address_len))) {
	    /* p2p; address is peer and local is ours */
	    ifamap.broadcast = ifamap.address;
	    ifamap.broadcast_len = ifamap.address_len;
	    ifamap.address = ifamap.local;
	    ifamap.address_len = ifamap.local_len;
	  }
	  if (ifamap.address) {
#ifndef IFA_NETMASK
	    sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
#endif
	    if (!build)
	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
	    else {
	      ifa->ifa_addr = (struct sockaddr *)data;
	      ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len,
				nlm_scope, nlm_index);
	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len));
	    }
	  }
#ifdef IFA_NETMASK
	  if (ifamap.netmask) {
	    if (!build)
	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len));
	    else {
	      ifa->ifa_netmask = (struct sockaddr *)data;
	      ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len,
				nlm_scope, nlm_index);
	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len));
	    }
	  }
#endif
	  if (ifamap.broadcast) {
	    if (!build)
	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len));
	    else {
	      ifa->ifa_broadaddr = (struct sockaddr *)data;
	      ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len,
				nlm_scope, nlm_index);
	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len));
	    }
	  }
#ifdef HAVE_IFADDRS_IFA_ANYCAST
	  if (ifamap.anycast) {
	    if (!build)
	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len));
	    else {
	      ifa->ifa_anycast = (struct sockaddr *)data;
	      ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len,
				nlm_scope, nlm_index);
	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len));
	    }
	  }
#endif
	}
	if (!build){
#ifndef IFA_NETMASK
	  dlen += sockaddr_size;
#endif
	  icnt++;
	} else {
	  if (ifa->ifa_name == NULL)
	    ifa->ifa_name = iflist[nlm_index];
#ifndef IFA_NETMASK
	  if (ifa->ifa_addr && 
	      ifa->ifa_addr->sa_family != AF_UNSPEC && 
	      ifa->ifa_addr->sa_family != AF_PACKET){
	    ifa->ifa_netmask = (struct sockaddr *)data;
	    ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen);
	  }
	  data += sockaddr_size;
#endif
	  ifl = ifa++;
	}
      }
    }
    if (!build){
      if (icnt == 0 && (dlen + nlen + xlen == 0)){
	if (ifap != NULL)
	  *ifap = NULL;
	break; /* cannot found any addresses */
      }
    }
    else
      free_data(NULL, ifdata);
  }

/* ---------------------------------- */
  /* Finalize */
  free_nlmsglist(nlmsg_list);
  nl_close(sd);
  return 0;
}
Exemplo n.º 5
0
nfct_t *nfct_create(ginkgo_ctx *ctx, int grps, nfct_notify cb, void *ud)
{
    nfct_t *ct;
    char name[20];
    ginkgo_src src = {
        .name = name,
        .fd = -1,
        .rd = NULL,
        .wr = NULL,
        .pars = nl_parse,
        .resp = nfct_response,
        .hand = nfct_handler,
        .ud = NULL,
    };
    int fd;

    if(! ctx) return NULL;
    if((fd = nl_open(NETLINK_NETFILTER, grps)) < 0)
        return NULL;
    if(! instantiate(ct))  {
        close(fd);
        return NULL;
    }
    ct->ginkgo = ctx;
    ct->nlfd = fd;
    ct->nlgrps = grps;
    ct->nlseq = 0;
    ct->cb = cb;
    ct->ud = ud;

    src.fd = fd;
    src.ud = ct;
    sprintf(name, "nfct-%d", fd);
    if(ginkgo_src_register(ctx, &src, &ct->id, 0) < 0)  {
        close(fd);
        free(ct);
        return NULL;
    }
    return ct;
}

void nfct_destroy(nfct_t *ct)
{
    if(ct)  {
        ginkgo_src_deregister(ct->ginkgo, ct->id, 1, 1);
        close(ct->nlfd);
        free(ct);
    }
}

int nfct_conn_get_counter(const conn_entry *e, conn_counter *counter)
{
    const struct nlattr *orig = e->nla[CTA_COUNTERS_ORIG];
    const struct nlattr *rep = e->nla[CTA_COUNTERS_REPLY];
    struct nlattr *arr[CTA_COUNTERS_MAX + 1];

    if(orig && rep)  {
        nla_parse_nested(arr, CTA_COUNTERS_MAX, orig);
        if(! arr[CTA_COUNTERS_PACKETS] || ! arr[CTA_COUNTERS_BYTES])
            return -1;
        counter->orig_pkts = be64toh(nla_get_be64(arr[CTA_COUNTERS_PACKETS]));
        counter->orig_bytes = be64toh(nla_get_be64(arr[CTA_COUNTERS_BYTES]));

        nla_parse_nested(arr, CTA_COUNTERS_MAX, rep);
        if(! arr[CTA_COUNTERS_PACKETS] || ! arr[CTA_COUNTERS_BYTES])
            return -1;
        counter->rep_pkts = be64toh(nla_get_be64(arr[CTA_COUNTERS_PACKETS]));
        counter->rep_bytes = be64toh(nla_get_be64(arr[CTA_COUNTERS_BYTES]));
        return 0;
    }
    return -1;
}

int nfct_conn_get_tcpinfo(const conn_entry *e, conn_tcpinfo *info)
{
    const struct nlattr *proto = e->nla[CTA_PROTOINFO];
    const struct nlattr *tcp;
    struct nlattr *arr[CTA_PROTOINFO_TCP_MAX + 1];

    if(proto)  {
        tcp = (const struct nlattr *)nla_data(proto);
        if(nla_type(tcp) != CTA_PROTOINFO_TCP)
            return -1;
        nla_parse_nested(arr, CTA_PROTOINFO_TCP_MAX, tcp);
        if(arr[CTA_PROTOINFO_TCP_STATE]
           || arr[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]
           || arr[CTA_PROTOINFO_TCP_WSCALE_REPLY]
           || arr[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]
           || arr[CTA_PROTOINFO_TCP_FLAGS_REPLY])  {
            info->state = nla_get_u8(arr[CTA_PROTOINFO_TCP_STATE]);
            info->wscale_orig = nla_get_u8(arr[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]);
            info->wscale_rep = nla_get_u8(arr[CTA_PROTOINFO_TCP_WSCALE_REPLY]);
            nla_get_mem(arr[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL], &info->flags_orig, sizeof(info->flags_orig));
            nla_get_mem(arr[CTA_PROTOINFO_TCP_FLAGS_REPLY], &info->flags_rep, sizeof(info->flags_rep));
            return 0;
        }
    }
    return -1;
}

int nfct_conn_get_sctpinfo(const conn_entry *e, conn_sctpinfo *info)
{
    const struct nlattr *proto = e->nla[CTA_PROTOINFO];
    const struct nlattr *sctp;
    struct nlattr *arr[CTA_PROTOINFO_SCTP_MAX + 1];

    if(proto)  {
        sctp = (const struct nlattr *)nla_data(proto);
        if(nla_type(sctp) != CTA_PROTOINFO_SCTP)
            return -1;
        nla_parse_nested(arr, CTA_PROTOINFO_SCTP_MAX, sctp);
        if(! arr[CTA_PROTOINFO_SCTP_STATE]
           || ! arr[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]
           || ! arr[CTA_PROTOINFO_SCTP_VTAG_REPLY])  {
            info->state = nla_get_u8(arr[CTA_PROTOINFO_SCTP_STATE]);
            info->vtag_orig = ntohl(nla_get_u8(arr[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]));
            info->vtag_rep = ntohl(nla_get_u8(arr[CTA_PROTOINFO_SCTP_VTAG_REPLY]));
            return 0;
        }
    }
    return -1;
}

int __nfct_conn_get_tuple(const conn_entry *e, int type, conn_tuple *tuple)
{
    struct nlattr *arr[CTA_TUPLE_MAX + 1];
    struct nlattr *ip[CTA_IP_MAX + 1];
    struct nlattr *proto[CTA_PROTO_MAX + 1];

    if(! e->nla[type])
        return -1;

    memset(tuple, 0, sizeof(*tuple));
    nla_parse_nested(arr, CTA_TUPLE_MAX, e->nla[type]);
    if(! arr[CTA_TUPLE_IP] || ! arr[CTA_TUPLE_PROTO])  {
        PR_WARN("unexpected NULL tuple IP or proto");
        return-1;
    }

    nla_parse_nested(ip, CTA_IP_MAX, arr[CTA_TUPLE_IP]);
    tuple->src.l3num = e->l3num;
    if(e->l3num == AF_INET)  {
        if(! ip[CTA_IP_V4_SRC] || ! ip[CTA_IP_V4_DST])
            return -1;
        tuple->src.u3.ip = nla_get_be32(ip[CTA_IP_V4_SRC]);
        tuple->dst.u3.ip = nla_get_be32(ip[CTA_IP_V4_DST]);
    }else if(e->l3num == AF_INET6)  {
        if(! ip[CTA_IP_V6_SRC] || ! ip[CTA_IP_V6_DST])
            return -1;
        nla_get_mem(ip[CTA_IP_V6_SRC], &tuple->src.u3.in6, sizeof(tuple->src.u3.in6));
        nla_get_mem(ip[CTA_IP_V6_DST], &tuple->dst.u3.in6, sizeof(tuple->dst.u3.in6));
    }else  {
        PR_WARN("unexpected l3num while parsing tuple:%d", e->l3num);
        return -1;
    }

    nla_parse_nested(proto, CTA_PROTO_MAX, arr[CTA_TUPLE_PROTO]);
    if(! proto[CTA_PROTO_NUM])  {
        PR_WARN("unexpected NULL proto num while parsing tuple");
        return -1;
    }
    tuple->dst.protonum = nla_get_u8(proto[CTA_PROTO_NUM]);
    switch(tuple->dst.protonum)  {
    case IPPROTO_TCP:
    case IPPROTO_UDP:
    case IPPROTO_UDPLITE:
        if(! proto[CTA_PROTO_SRC_PORT] || ! proto[CTA_PROTO_DST_PORT])  {
            PR_WARN("unexpected NULL port while parsing tuple");
            return -1;
        }
        tuple->src.u.tcp.port = nla_get_be16(proto[CTA_PROTO_SRC_PORT]);
        tuple->dst.u.tcp.port = nla_get_be16(proto[CTA_PROTO_DST_PORT]);
        break;
    case IPPROTO_ICMP:
        if(! proto[CTA_PROTO_ICMP_ID] || ! proto[CTA_PROTO_ICMP_TYPE] || ! proto[CTA_PROTO_ICMP_CODE])  {
            PR_WARN("unexpected NULL icmp attr while parsing tuple");
            return -1;
        }
        tuple->src.u.icmp.id = nla_get_be16(proto[CTA_PROTO_ICMP_ID]);
        tuple->dst.u.icmp.type = nla_get_u8(proto[CTA_PROTO_ICMP_TYPE]);
        tuple->dst.u.icmp.code = nla_get_u8(proto[CTA_PROTO_ICMP_CODE]);
        break;
    case IPPROTO_ICMPV6:
        if(! proto[CTA_PROTO_ICMPV6_ID]
           || ! proto[CTA_PROTO_ICMPV6_TYPE]
           || ! proto[CTA_PROTO_ICMPV6_CODE])  {
            PR_WARN("unexpected NULL icmpv6 attr while parsing tuple");
            return -1;
        }
        tuple->src.u.icmp.id = nla_get_be16(proto[CTA_PROTO_ICMPV6_ID]);
        tuple->dst.u.icmp.type = nla_get_u8(proto[CTA_PROTO_ICMPV6_TYPE]);
        tuple->dst.u.icmp.code = nla_get_u8(proto[CTA_PROTO_ICMPV6_CODE]);
        break;
    default:
        PR_INFO("unsupported proto %d while parsing tuple", tuple->dst.protonum);
        return -1;
    }
    return 0;
}

/* fixme: nat seq adj */

nfct_msg *nfct_msg_new(__u8 l3num, int flags)
{
    ginkgo_msg *msg;
    struct nlmsghdr *nlh;
    struct nfgenmsg *nfmsg;
    nfct_msg_ctl *ctl;
    conn_entry *e;

    if((msg = ginkgo_new_msg(0, NFCT_MSG_GOOD_SIZE)))  {
        if(! instantiate(e))  {
            free(msg);
            return NULL;
        }

        nlh = NL_HEADER(msg);
        BZERO(nlh);
        nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        if(flags & NFCT_F_CREATE)
            nlh->nlmsg_flags |= NLM_F_CREATE;
        if(flags & NFCT_F_EXCL)
            nlh->nlmsg_flags |= NLM_F_EXCL;
        if(flags & NFCT_F_DUMP)
            nlh->nlmsg_flags |= NLM_F_DUMP;

        nfmsg = (struct nfgenmsg *)NLMSG_DATA(nlh);
        nfmsg->nfgen_family = l3num;
        nfmsg->version = NFNETLINK_V0;
        nfmsg->res_id = 0;

        BZERO(e);
        e->l3num = l3num;

        ctl = msg_ctl(msg);
        BZERO(ctl);
        ctl->base.entry = e;
        ctl->ctx = (char *)nfmsg + NLMSG_ALIGN(sizeof(struct nfgenmsg));
        ctl->sz = NFCT_MSG_GOOD_SIZE;
        return (nfct_msg *)ctl;
    }
    return NULL;
}
Exemplo n.º 6
0
Arquivo: netif.c Projeto: ghedo/pflask
void setup_netif(struct netif *ifs, pid_t pid) {
    int rc;
    _close_ int sock = nl_open();

    struct netif *i = NULL;

    DL_FOREACH(ifs, i) {
        unsigned int if_index = 0;

        switch (i->type) {
        case MACVLAN: {
            _free_ char *name = NULL;

            rc = asprintf(&name, "pflask-%d", pid);
            fail_if(rc < 0, "OOM");

            if_index = if_nametoindex(i->dev);
            sys_fail_if(!if_index, "Error searching for '%s'", i->dev);

            create_macvlan(sock, if_index, name);

            if_index = if_nametoindex(name);
            break;
        }

        case IPVLAN: {
            _free_ char *name = NULL;

            rc = asprintf(&name, "pflask-%d", pid);
            fail_if(rc < 0, "OOM");

            if_index = if_nametoindex(i->dev);
            sys_fail_if(!if_index, "Error searching for '%s'", i->dev);

            create_ipvlan(sock, if_index, name);

            if_index = if_nametoindex(name);
            break;
        }

        case VETH: {
            _free_ char *name = NULL;

            rc = asprintf(&name, "pflask-%d", pid);
            fail_if(rc < 0, "OOM");

            create_veth_pair(sock, i->dev, name);

            if_index = if_nametoindex(name);
            sys_fail_if(!if_index, "Error searching for '%s'", name);
            break;
        }

        case MOVE:
            if_index = if_nametoindex(i->dev);
            sys_fail_if(!if_index, "Error searching for '%s'", i->dev);
            break;
        }

        move_and_rename_if(sock, pid, if_index, i->name);
    }
Exemplo n.º 7
0
/* ====================================================================== */
int ni_ifaddrs(struct ni_ifaddrs **ifap, sa_family_t family)
{
	int sd;
	struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
	/* - - - - - - - - - - - - - - - */
	int icnt;
	size_t dlen, xlen;
	uint32_t max_ifindex = 0;

	pid_t pid = getpid();
	int seq = 0;
	int result;
	int build;		/* 0 or 1 */

/* ---------------------------------- */
	/* initialize */
	icnt = dlen = xlen = 0;
	nlmsg_list = nlmsg_end = NULL;

	if (ifap)
		*ifap = NULL;

/* ---------------------------------- */
	/* open socket and bind */
	sd = nl_open();
	if (sd < 0)
		return -1;

/* ---------------------------------- */
	/* gather info */
	if ((seq = nl_getlist(sd, seq + 1, RTM_GETADDR, &nlmsg_list, &nlmsg_end)) < 0) {
		free_nlmsglist(nlmsg_list);
		nl_close(sd);
		return -1;
	}

/* ---------------------------------- */
	/* Estimate size of result buffer and fill it */
	for (build = 0; build <= 1; build++) {
		struct ni_ifaddrs *ifl = NULL, *ifa = NULL;
		struct nlmsghdr *nlh, *nlh0;
		void *data = NULL, *xdata = NULL;
		uint16_t *ifflist = NULL;
#ifndef IFA_LOCAL
		struct rtmaddr_ifamap ifamap;
#endif

		if (build) {
			ifa = data = calloc(1, NLMSG_ALIGN(sizeof(struct ni_ifaddrs[icnt]))
					    + dlen + xlen);
			if (ifap != NULL)
				*ifap = ifa;
			else {
				free_data(data);
				result = 0;
				break;
			}
			if (data == NULL) {
				free_data(data);
				result = -1;
				break;
			}
			ifl = NULL;
			data += NLMSG_ALIGN(sizeof(struct ni_ifaddrs)) * icnt;
			xdata = data + dlen;
			ifflist = xdata + xlen;
		}

		for (nlm = nlmsg_list; nlm; nlm = nlm->nlm_next) {
			int nlmlen = nlm->size;
			if (!(nlh0 = nlm->nlh))
				continue;
			for (nlh = nlh0; NLMSG_OK(nlh, nlmlen); nlh = NLMSG_NEXT(nlh, nlmlen)) {
				struct ifaddrmsg *ifam = NULL;
				struct rtattr *rta;

				size_t nlm_struct_size = 0;
				sa_family_t nlm_family = 0;
				uint32_t nlm_scope = 0, nlm_index = 0;
				unsigned int nlm_flags;
				size_t rtasize;

#ifndef IFA_LOCAL
				memset(&ifamap, 0, sizeof(ifamap));
#endif

				/* check if the message is what we want */
				if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq)
					continue;
				if (nlh->nlmsg_type == NLMSG_DONE) {
					break;	/* ok */
				}
				switch (nlh->nlmsg_type) {
				case RTM_NEWADDR:
					ifam = (struct ifaddrmsg *) NLMSG_DATA(nlh);
					nlm_struct_size = sizeof(*ifam);
					nlm_family = ifam->ifa_family;
					nlm_scope = ifam->ifa_scope;
					nlm_index = ifam->ifa_index;
					nlm_flags = ifam->ifa_flags;
					if (family && nlm_family != family)
						continue;
					if (build) {
						ifa->ifa_ifindex = nlm_index;
						ifa->ifa_flags = nlm_flags;
					}
					break;
				default:
					continue;
				}

				if (!build) {
					if (max_ifindex < nlm_index)
						max_ifindex = nlm_index;
				} else {
					if (ifl != NULL)
						ifl->ifa_next = ifa;
				}

				rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size);
				for (rta = (struct rtattr *) (((char *) NLMSG_DATA(nlh)) + 
									NLMSG_ALIGN(nlm_struct_size)); 
				     RTA_OK(rta, rtasize); 
				     rta = RTA_NEXT(rta, rtasize)) {
					void *rtadata = RTA_DATA(rta);
					size_t rtapayload = RTA_PAYLOAD(rta);

					switch (nlh->nlmsg_type) {
					case RTM_NEWADDR:
						if (nlm_family == AF_PACKET)
							break;
						switch (rta->rta_type) {
#ifndef IFA_LOCAL
						case IFA_ADDRESS:
							ifamap.address = rtadata;
							ifamap.address_len = rtapayload;
							break;
						case IFA_LOCAL:
							ifamap.local = rtadata;
							ifamap.local_len = rtapayload;
							break;
						case IFA_BROADCAST:
							ifamap.broadcast = rtadata;
							ifamap.broadcast_len = rtapayload;
							break;
						case IFA_LABEL:
							break;
						case IFA_UNSPEC:
							break;
#else
						case IFA_LOCAL:
							if (!build)
								dlen += NLMSG_ALIGN(rtapayload);
							else {
								memcpy(data, rtadata, rtapayload);
								ifa->ifa_addr = data;
								data += NLMSG_ALIGN(rtapayload);
							}
							break;
#endif
						case IFA_CACHEINFO:
							if (!build)
								xlen += NLMSG_ALIGN(rtapayload);
							else {
								memcpy(xdata, rtadata, rtapayload);
								ifa->ifa_cacheinfo = xdata;
								xdata += NLMSG_ALIGN(rtapayload);
							}
							break;
						}
					}
				}
#ifndef IFA_LOCAL
				if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET) {
					if (!ifamap.local) {
						ifamap.local = ifamap.address;
						ifamap.local_len = ifamap.address_len;
					}
					if (!ifamap.address) {
						ifamap.address = ifamap.local;
						ifamap.address_len = ifamap.local_len;
					}
					if (ifamap.address_len != ifamap.local_len || 
					    (ifamap.address != NULL && 
					     memcmp(ifamap.address, ifamap.local, ifamap.address_len))) {
						/* p2p; address is peer and local is ours */
						ifamap.broadcast = ifamap.address;
						ifamap.broadcast_len = ifamap.address_len;
						ifamap.address = ifamap.local;
						ifamap.address_len = ifamap.local_len;
					}
					if (ifamap.address) {
						if (!build)
							dlen += NLMSG_ALIGN(ifamap.address_len);
						else {
							ifa->ifa_addr = (struct sockaddr *) data;
							memcpy(ifa->ifa_addr, ifamap.address, ifamap.address_len);
							data += NLMSG_ALIGN(ifamap.address_len);
						}
					}
				}
#endif
				if (!build) {
					icnt++;
				} else {
					ifl = ifa++;
				}
			}
		}
		if (!build) {
			if (icnt == 0 && (dlen + xlen == 0)) {
				if (ifap != NULL)
					*ifap = NULL;
				break;	/* cannot found any addresses */
			}
		}
	}

/* ---------------------------------- */
	/* Finalize */
	free_nlmsglist(nlmsg_list);
	nl_close(sd);
	return 0;
}
Exemplo n.º 8
0
int main(int argc, char **argv)
{
	int ch, longindex, nr;
	int is_daemon = 1, is_debug = 1;
	pid_t pid;
	struct pollfd *poll_array;

	while ((ch = getopt_long(argc, argv, "fd:vh", long_options, &longindex)) >= 0) {
		switch (ch) {
		case 'f':
			is_daemon = 0;
			break;
		case 'd':
			is_debug = atoi(optarg);
			break;
		case 'v':
			exit(0);
			break;
		case 'h':
			usage(0);
			break;
		default:
			usage(1);
			break;
		}
	}

	init(is_daemon, is_debug);

	if (is_daemon) {
		pid = fork();
		if (pid < 0)
			exit(-1);
		else if (pid)
			exit(0);

		chdir("/");

		close(0);
		open("/dev/null", O_RDWR);
		dup2(0, 1);
		dup2(0, 2);
		setsid();
	}

	nl_fd = nl_open();
	if (nl_fd < 0)
		exit(nl_fd);

	ipc_fd = ipc_open();
	if (ipc_fd < 0)
		exit(ipc_fd);

	dl_init();

	nr = MAX_DL_HANDLES;
	poll_array = poll_init(nr);

	dl_config_load();

	event_loop(nr, poll_array);

	return 0;
}
int
main(int argc,char **argv)
{
    int status;
    int fd;
    struct msghdr msg;
    struct sockaddr_nl dest_addr;
    struct nlmsghdr *nlh;
    struct iovec iov;
    struct dad_failed_msg_t *dad_msg;

    fd = nl_open();
    if (fd < 0) {
        perror("Error\n");
        return -1;
    }

    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(sizeof(struct dad_failed_msg_t)));
    if (!nlh) {
        perror("Malloc Error\n");
        return -1;
    }
    memset(nlh, 0, NLMSG_SPACE(sizeof(struct dad_failed_msg_t)));

    iov.iov_base = (void *)nlh;
    iov.iov_len = NLMSG_SPACE(sizeof(struct dad_failed_msg_t));
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    printf("Starting recv,iov length is %d\n",(int)iov.iov_len);

    while (1) {
        status = recvmsg(fd, &msg, 0);

        if (status < 0) {
            close(fd);
            free(nlh);
            perror("recv");
            return 1;
        }

        if (iov.iov_len == nlh->nlmsg_len) {
            dad_msg = (struct dad_failed_msg_t *)NLMSG_DATA(nlh);

#define ADDR_PREFIX_FMT "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X/%d"
#define ADDR_PREFIX_PARAM(dad_msg) dad_msg->addr.s6_addr16[0],\
            dad_msg->addr.s6_addr16[1],\
            dad_msg->addr.s6_addr16[2],\
            dad_msg->addr.s6_addr16[3],\
            dad_msg->addr.s6_addr16[4],\
            dad_msg->addr.s6_addr16[5],\
            dad_msg->addr.s6_addr16[6],\
            dad_msg->addr.s6_addr16[7],\
            dad_msg->prefix_len

            printf("DAD failed on interface %s,Address:" ADDR_PREFIX_FMT "\n",
                   dad_msg->name,ADDR_PREFIX_PARAM(dad_msg));
        }
    }

    close(fd);
    free(nlh);

    return 0;
}