Exemple #1
0
/*
 *  add an address to an interface.
 */
char*
ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
{
    int i, type, mtu, sendnbrdisc = 0;
    uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
    uchar bcast[IPaddrlen], net[IPaddrlen];
    Iplifc *lifc, **l;
    Fs *f;

    if(ifc->m == nil)
        return "ipifc not yet bound to device";

    f = ifc->conv->p->f;

    type = Rifc;
    memset(ip, 0, IPaddrlen);
    memset(mask, 0, IPaddrlen);
    memset(rem, 0, IPaddrlen);
    switch(argc) {
    case 6:
        if(strcmp(argv[5], "proxy") == 0)
            type |= Rproxy;
    /* fall through */
    case 5:
        mtu = strtoul(argv[4], 0, 0);
        if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
            ifc->maxtu = mtu;
    /* fall through */
    case 4:
        if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
            return Ebadip;
        parseipmask(mask, argv[2]);
        maskip(rem, mask, net);
        break;
    case 3:
        if (parseip(ip, argv[1]) == -1)
            return Ebadip;
        parseipmask(mask, argv[2]);
        maskip(ip, mask, rem);
        maskip(rem, mask, net);
        break;
    case 2:
        if (parseip(ip, argv[1]) == -1)
            return Ebadip;
        memmove(mask, defmask(ip), IPaddrlen);
        maskip(ip, mask, rem);
        maskip(rem, mask, net);
        break;
    default:
        return Ebadarg;
    }
    if(isv4(ip))
        tentative = 0;
    wlock(ifc);

    /* ignore if this is already a local address for this ifc */
    for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
        if(ipcmp(lifc->local, ip) == 0) {
            if(lifc->tentative != tentative)
                lifc->tentative = tentative;
            if(lifcp) {
                lifc->onlink = lifcp->onlink;
                lifc->autoflag = lifcp->autoflag;
                lifc->validlt = lifcp->validlt;
                lifc->preflt = lifcp->preflt;
                lifc->origint = lifcp->origint;
            }
            goto out;
        }
    }

    /* add the address to the list of logical ifc's for this ifc */
    lifc = smalloc(sizeof(Iplifc));
    ipmove(lifc->local, ip);
    ipmove(lifc->mask, mask);
    ipmove(lifc->remote, rem);
    ipmove(lifc->net, net);
    lifc->tentative = tentative;
    if(lifcp) {
        lifc->onlink = lifcp->onlink;
        lifc->autoflag = lifcp->autoflag;
        lifc->validlt = lifcp->validlt;
        lifc->preflt = lifcp->preflt;
        lifc->origint = lifcp->origint;
    } else {		/* default values */
        lifc->onlink = lifc->autoflag = 1;
        lifc->validlt = lifc->preflt = ~0L;
        lifc->origint = NOW / 1000;
    }
    lifc->next = nil;

    for(l = &ifc->lifc; *l; l = &(*l)->next)
        ;
    *l = lifc;

    /* check for point-to-point interface */
    if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
        if(ipcmp(mask, IPallbits) == 0)
            type |= Rptpt;

    /* add local routes */
    if(isv4(ip))
        v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
    else
        v6addroute(f, tifc, rem, mask, rem, type);

    addselfcache(f, ifc, lifc, ip, Runi);

    if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)) {
        ipifcregisterproxy(f, ifc, rem);
        goto out;
    }

    if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
        /* add subnet directed broadcast address to the self cache */
        for(i = 0; i < IPaddrlen; i++)
            bcast[i] = (ip[i] & mask[i]) | ~mask[i];
        addselfcache(f, ifc, lifc, bcast, Rbcast);

        /* add subnet directed network address to the self cache */
        for(i = 0; i < IPaddrlen; i++)
            bcast[i] = (ip[i] & mask[i]) & mask[i];
        addselfcache(f, ifc, lifc, bcast, Rbcast);

        /* add network directed broadcast address to the self cache */
        memmove(mask, defmask(ip), IPaddrlen);
        for(i = 0; i < IPaddrlen; i++)
            bcast[i] = (ip[i] & mask[i]) | ~mask[i];
        addselfcache(f, ifc, lifc, bcast, Rbcast);

        /* add network directed network address to the self cache */
        memmove(mask, defmask(ip), IPaddrlen);
        for(i = 0; i < IPaddrlen; i++)
            bcast[i] = (ip[i] & mask[i]) & mask[i];
        addselfcache(f, ifc, lifc, bcast, Rbcast);

        addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
    }
    else {
        if(ipcmp(ip, v6loopback) == 0) {
            /* add node-local mcast address */
            addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);

            /* add route for all node multicast */
            v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
                       v6allnodesN, Rmulti);
        }

        /* add all nodes multicast address */
        addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);

        /* add route for all nodes multicast */
        v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
                   Rmulti);

        /* add solicited-node multicast address */
        ipv62smcast(bcast, ip);
        addselfcache(f, ifc, lifc, bcast, Rmulti);

        sendnbrdisc = 1;
    }

    /* register the address on this network for address resolution */
    if(isv4(ip) && ifc->m->areg != nil)
        (*ifc->m->areg)(ifc, ip);

out:
    wunlock(ifc);
    if(tentative && sendnbrdisc)
        icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
    return nil;
}
Exemple #2
0
/*
 * encapsulate next IP packet on x's write queue in IP/ESP packet
 * and initiate output of the result.
 */
static void
espkick(void *x)
{
	int nexthdr, payload, pad, align;
	uchar *auth;
	Block *bp;
	Conv *c = x;
	Esp4hdr *eh4;
	Esp6hdr *eh6;
	Espcb *ecb;
	Esptail *et;
	Userhdr *uh;
	Versdep vers;

	getverslens(convipvers(c), &vers);
	bp = qget(c->wq);
	if(bp == nil)
		return;

	qlock(c);
	ecb = c->ptcl;

	if(ecb->header) {
		/* make sure the message has a User header */
		bp = pullupblock(bp, Userhdrlen);
		if(bp == nil) {
			qunlock(c);
			return;
		}
		uh = (Userhdr*)bp->rp;
		nexthdr = uh->nexthdr;
		bp->rp += Userhdrlen;
	} else {
		nexthdr = 0;	/* what should this be? */
	}

	payload = BLEN(bp) + ecb->espivlen;

	/* Make space to fit ip header */
	bp = padblock(bp, vers.hdrlen + ecb->espivlen);
	getpktspiaddrs(bp->rp, &vers);

	align = 4;
	if(ecb->espblklen > align)
		align = ecb->espblklen;
	if(align % ecb->ahblklen != 0)
		panic("espkick: ahblklen is important after all");
	pad = (align-1) - (payload + Esptaillen-1)%align;

	/*
	 * Make space for tail
	 * this is done by calling padblock with a negative size
	 * Padblock does not change bp->wp!
	 */
	bp = padblock(bp, -(pad+Esptaillen+ecb->ahlen));
	bp->wp += pad+Esptaillen+ecb->ahlen;

	et = (Esptail*)(bp->rp + vers.hdrlen + payload + pad);

	/* fill in tail */
	et->pad = pad;
	et->nexthdr = nexthdr;

	/* encrypt the payload */
	ecb->cipher(ecb, bp->rp + vers.hdrlen, payload + pad + Esptaillen);
	auth = bp->rp + vers.hdrlen + payload + pad + Esptaillen;

	/* fill in head; construct a new IP header and an ESP header */
	if (vers.version == V4) {
		eh4 = (Esp4hdr *)bp->rp;
		eh4->vihl = IP_VER4;
		v6tov4(eh4->espsrc, c->laddr);
		v6tov4(eh4->espdst, c->raddr);
		eh4->espproto = IP_ESPPROTO;
		eh4->frag[0] = 0;
		eh4->frag[1] = 0;

		hnputl(eh4->espspi, ecb->spi);
		hnputl(eh4->espseq, ++ecb->seq);
	} else {
		eh6 = (Esp6hdr *)bp->rp;
		eh6->vcf[0] = IP_VER6;
		ipmove(eh6->src, c->laddr);
		ipmove(eh6->dst, c->raddr);
		eh6->proto = IP_ESPPROTO;

		hnputl(eh6->espspi, ecb->spi);
		hnputl(eh6->espseq, ++ecb->seq);
	}

	/* compute secure hash */
	ecb->auth(ecb, bp->rp + vers.iphdrlen, (vers.hdrlen - vers.iphdrlen) +
		payload + pad + Esptaillen, auth);

	qunlock(c);
	/* print("esp: pass down: %uld\n", BLEN(bp)); */
	if (vers.version == V4)
		ipoput4(c->p->f, bp, 0, c->ttl, c->tos, c);
	else
		ipoput6(c->p->f, bp, 0, c->ttl, c->tos, c);
}
Exemple #3
0
/*
 *  find the local address 'closest' to the remote system, copy it to
 *  local and return the ifc for that address
 */
void
findlocalip(Fs *f, uchar *local, uchar *remote)
{
    int version, atype = unspecifiedv6, atypel = unknownv6;
    int atyper, deprecated;
    uchar gate[IPaddrlen], gnet[IPaddrlen];
    Ipifc *ifc;
    Iplifc *lifc;
    Route *r;

    USED(atype);
    USED(atypel);
    qlock(f->ipifc);
    r = v6lookup(f, remote, nil);
    version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;

    if(r != nil) {
        ifc = r->ifc;
        if(r->type & Rv4)
            v4tov6(gate, r->v4.gate);
        else {
            ipmove(gate, r->v6.gate);
            ipmove(local, v6Unspecified);
        }

        switch(version) {
        case V4:
            /* find ifc address closest to the gateway to use */
            for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
                maskip(gate, lifc->mask, gnet);
                if(ipcmp(gnet, lifc->net) == 0) {
                    ipmove(local, lifc->local);
                    goto out;
                }
            }
            break;
        case V6:
            /* find ifc address with scope matching the destination */
            atyper = v6addrtype(remote);
            deprecated = 0;
            for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
                atypel = v6addrtype(lifc->local);
                /* prefer appropriate scope */
                if(atypel > atype && atype < atyper ||
                        atypel < atype && atype > atyper) {
                    ipmove(local, lifc->local);
                    deprecated = !v6addrcurr(lifc);
                    atype = atypel;
                } else if(atypel == atype) {
                    /* avoid deprecated addresses */
                    if(deprecated && v6addrcurr(lifc)) {
                        ipmove(local, lifc->local);
                        atype = atypel;
                        deprecated = 0;
                    }
                }
                if(atype == atyper && !deprecated)
                    goto out;
            }
            if(atype >= atyper)
                goto out;
            break;
        default:
            panic("findlocalip: version %d", version);
        }
    }

    switch(version) {
    case V4:
        findprimaryipv4(f, local);
        break;
    case V6:
        findprimaryipv6(f, local);
        break;
    default:
        panic("findlocalip2: version %d", version);
    }

out:
    qunlock(f->ipifc);
}
Exemple #4
0
/*
 *  fill in all the requested attributes for a system.
 *  if the system's entry doesn't have all required,
 *  walk through successively more inclusive networks
 *  for inherited attributes.
 */
Ndbtuple*
ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n)
{
	Ndbtuple *t, *nt, *f;
	Ndbs s;
	char *ipstr;
	uint8_t net[IPaddrlen], ip[IPaddrlen];
	int prefix, smallestprefix, force;
	int64_t r;

	/* just in case */
	fmtinstall('I', eipfmt);
	fmtinstall('M', eipfmt);

	/* get needed attributes */
	f = mkfilter(n, alist);

	/*
	 *  first look for a matching entry with an ip address
	 */
	t = nil;
	ipstr = ndbgetvalue(db, &s, attr, val, "ip", &nt);
	if(ipstr == nil){
		/* none found, make one up */
		if(strcmp(attr, "ip") != 0) {
			ndbfree(f);
			return nil;	
		}
		t = ndbnew("ip", val);
		t->line = t;
		t->entry = nil;
		r = parseip(net, val);
		if(r == -1)
			ndbfree(t);
	} else {
		/* found one */
		while(nt != nil){
			nt = ndbreorder(nt, s.t);
			t = ndbconcatenate(t, nt);
			nt = ndbsnext(&s, attr, val);
		}
		r = parseip(net, ipstr);
		free(ipstr);
	}
	if(r < 0){
		ndbfree(f);
		return nil;
	}
	ipmove(ip, net);
	t = filter(db, t, f);

	/*
	 *  now go through subnets to fill in any missing attributes
	 */
	if(isv4(net)){
		prefix = 127;
		smallestprefix = 100;
		force = 0;
	} else {
		/* in v6, the last 8 bytes have no structure (we hope) */
		prefix = 64;
		smallestprefix = 2;
		memset(net+8, 0, 8);
		force = 1;
	}

	/*
	 *  to find a containing network, keep turning off
	 *  the lower bit and look for a network with
	 *  that address and a shorter mask.  tedius but
	 *  complete, we may need to find a trick to speed this up.
	 */
	for(; prefix >= smallestprefix; prefix--){
		if(filtercomplete(f))
			break;
		if(!force && (net[prefix/8] & (1<<(7-(prefix%8)))) == 0)
			continue;
		force = 0;
		net[prefix/8] &= ~(1<<(7-(prefix%8)));
		t = ndbconcatenate(t, subnet(db, net, f, prefix));
	}

	/*
	 *  if there's an unfulfilled ipmask, make one up
	 */
	nt = ndbfindattr(f, f, "ipmask");
	if(nt && !(nt->ptr & Fignore)){
		char x[64];

		snprint(x, sizeof(x), "%M", defmask(ip));
		t = ndbconcatenate(t, ndbnew("ipmask", x));
	}

	ndbfree(f);
	ndbsetmalloctag(t, getcallerpc());
	return t;
}
Exemple #5
0
/*
 *  called with protocol locked
 */
Conv*
Fsprotoclone(Proto *p, char *user)
{
	Conv *c, **pp, **ep;

retry:
	c = nil;
	ep = &p->conv[p->nc];
	for(pp = p->conv; pp < ep; pp++) {
		c = *pp;
		if(c == nil){
			c = malloc(sizeof(Conv));
			if(c == nil)
				error(Enomem);
			qlock(c);
			c->p = p;
			c->x = pp - p->conv;
			if(p->ptclsize != 0){
				c->ptcl = malloc(p->ptclsize);
				if(c->ptcl == nil) {
					free(c);
					error(Enomem);
				}
			}
			*pp = c;
			p->ac++;
			c->eq = qopen(1024, Qmsg, 0, 0);
			(*p->create)(c);
			break;
		}
		if(canqlock(c)){
			/*
			 *  make sure both processes and protocol
			 *  are done with this Conv
			 */
			if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0))
				break;

			qunlock(c);
		}
	}
	if(pp >= ep) {
		if(p->gc)
			print("Fsprotoclone: garbage collecting Convs\n");
		if(p->gc != nil && (*p->gc)(p))
			goto retry;
		/* debugging: do we ever get here? */
		if (cpuserver)
			panic("Fsprotoclone: all conversations in use");
		return nil;
	}

	c->inuse = 1;
	kstrdup(&c->owner, user);
	c->perm = 0660;
	c->state = Idle;
	ipmove(c->laddr, IPnoaddr);
	ipmove(c->raddr, IPnoaddr);
	c->r = nil;
	c->rgen = 0;
	c->lport = 0;
	c->rport = 0;
	c->restricted = 0;
	c->maxfragsize = 0;
	c->ttl = MAXTTL;
	qreopen(c->rq);
	qreopen(c->wq);
	qreopen(c->eq);

	qunlock(c);
	return c;
}
Exemple #6
0
/*
 *  find the local address 'closest' to the remote system, copy it to
 *  local and return the ifc for that address
 */
void findlocalip(struct Fs *f, uint8_t * local, uint8_t * remote)
{
	struct Ipifc *ifc;
	struct Iplifc *lifc;
	struct route *r;
	uint8_t gate[IPaddrlen];
	uint8_t gnet[IPaddrlen];
	int version;
	int atype = unspecifiedv6, atypel = unknownv6;

	qlock(&f->ipifc->qlock);
	r = v6lookup(f, remote, NULL);
	version = (memcmp(remote, v4prefix, IPv4off) == 0) ? V4 : V6;

	if (r != NULL) {
		ifc = r->rt.ifc;
		if (r->rt.type & Rv4)
			v4tov6(gate, r->v4.gate);
		else {
			ipmove(gate, r->v6.gate);
			ipmove(local, v6Unspecified);
		}

		/* find ifc address closest to the gateway to use */
		switch (version) {
			case V4:
				for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
					maskip(gate, lifc->mask, gnet);
					if (ipcmp(gnet, lifc->net) == 0) {
						ipmove(local, lifc->local);
						goto out;
					}
				}
				break;
			case V6:
				for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
					atypel = v6addrtype(lifc->local);
					maskip(gate, lifc->mask, gnet);
					if (ipcmp(gnet, lifc->net) == 0)
						if (atypel > atype)
							if (v6addrcurr(lifc)) {
								ipmove(local, lifc->local);
								atype = atypel;
								if (atype == globalv6)
									break;
							}
				}
				if (atype > unspecifiedv6)
					goto out;
				break;
			default:
				panic("findlocalip: version %d", version);
		}
	}

	switch (version) {
		case V4:
			findprimaryipv4(f, local);
			break;
		case V6:
			findprimaryipv6(f, local);
			break;
		default:
			panic("findlocalip2: version %d", version);
	}

out:
	qunlock(&f->ipifc->qlock);
}
Exemple #7
0
void
dhcprecv(void)
{
	uint8_t buf[2000];
	Bootp *bp;
	int n, type;
	uint32_t lease;
	uint8_t mask[IPaddrlen];

	qunlock(&dhcp.lk);
	n = read(dhcp.fd, buf, sizeof(buf));
	qlock(&dhcp.lk);

	if(n <= 0)
		myfatal("dhcprecv: bad read: %r");

	bp = parse(buf, n);
	if(bp == 0)
		return;

if(1) {
fprint(2, "recved\n");
bootpdump(buf, n);
}

	type = optgetbyte(bp, ODtype);
	switch(type) {
	default:
		fprint(2, "dhcprecv: unknown type: %d\n", type);
		break;
	case Offer:
		if(dhcp.state != Sselecting)
			break;
		lease = optgetulong(bp, ODlease);
		if(lease == 0)
			myfatal("bad lease");
		if(!optgetaddr(bp, OBmask, mask))
			memset(mask, 0xff, sizeof(mask));
		v4tov6(dhcp.client, bp->yiaddr);
		if(!optgetaddr(bp, ODserverid, dhcp.server)) {
			fprint(2, "dhcprecv: Offer from server with invalid serverid\n");
			break;
		}

		dhcp.lease = lease;
		ipmove(dhcp.mask, mask);
		memmove(dhcp.sname, bp->sname, sizeof(dhcp.sname));
		dhcp.sname[sizeof(dhcp.sname)-1] = 0;

		dhcpsend(Request);
		dhcp.state = Srequesting;
		dhcp.resend = 0;
		dhcp.timeout = 4;
		break;
	case Ack:
		if(dhcp.state != Srequesting)
		if(dhcp.state != Srenewing)
		if(dhcp.state != Srebinding)
			break;
		lease = optgetulong(bp, ODlease);
		if(lease == 0)
			myfatal("bad lease");
		if(!optgetaddr(bp, OBmask, mask))
			memset(mask, 0xff, sizeof(mask));
		v4tov6(dhcp.client, bp->yiaddr);
		dhcp.lease = lease;
		ipmove(dhcp.mask, mask);
		dhcp.state = Sbound;
		break;
	case Nak:
		myfatal("recved nak");
		break;
	}

}