335 lines
6.8 KiB
C
335 lines
6.8 KiB
C
/*
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
* in the LICENSE file.
|
|
*/
|
|
/* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio <giacomo@tesio.it>
|
|
* See /doc/license/gpl-2.0.txt for details about the licensing.
|
|
*/
|
|
/* Portions of this file are Copyright (C) 9front's team.
|
|
* See /doc/license/9front-mit for details about the licensing.
|
|
* See http://code.9front.org/hg/plan9front/ for a list of authors.
|
|
*/
|
|
/*
|
|
* this currently only works for ethernet bootp's -- presotto
|
|
*/
|
|
#include <u.h>
|
|
#include <lib9.h>
|
|
#include <ip.h>
|
|
#include <bio.h>
|
|
#include <ndb.h>
|
|
#include "dat.h"
|
|
|
|
static Ndb *db;
|
|
char *ndbfile;
|
|
|
|
/*
|
|
* open ndbfile as db if not already open. also check for stale data
|
|
* and reload as needed.
|
|
*/
|
|
static Ndb *
|
|
opendb(void)
|
|
{
|
|
static uint32_t lastcheck;
|
|
|
|
/* check no more often than once every minute */
|
|
if(db == nil) {
|
|
db = ndbopen(ndbfile);
|
|
if(db != nil)
|
|
lastcheck = now;
|
|
} else if(now >= lastcheck + 60) {
|
|
if (ndbchanged(db))
|
|
ndbreopen(db);
|
|
lastcheck = now;
|
|
}
|
|
return db;
|
|
}
|
|
|
|
Iplifc*
|
|
findlifc(uint8_t *ip)
|
|
{
|
|
uint8_t x[IPaddrlen];
|
|
Ipifc *ifc;
|
|
Iplifc *lifc;
|
|
|
|
for(ifc = ipifcs; ifc; ifc = ifc->next){
|
|
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
|
|
if(lifc->net[0] == 0)
|
|
continue;
|
|
maskip(ip, lifc->mask, x);
|
|
if(memcmp(x, lifc->net, IPaddrlen) == 0)
|
|
return lifc;
|
|
}
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
int
|
|
forme(uint8_t *ip)
|
|
{
|
|
Ipifc *ifc;
|
|
Iplifc *lifc;
|
|
|
|
for(ifc = ipifcs; ifc; ifc = ifc->next){
|
|
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
|
|
if(memcmp(ip, lifc->ip, IPaddrlen) == 0)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint8_t noetheraddr[6];
|
|
|
|
static void
|
|
setipaddr(uint8_t *addr, char *ip)
|
|
{
|
|
if(ipcmp(addr, IPnoaddr) == 0)
|
|
parseip(addr, ip);
|
|
}
|
|
|
|
static void
|
|
setipmask(uint8_t *mask, char *ip)
|
|
{
|
|
if(ipcmp(mask, IPnoaddr) == 0)
|
|
parseipmask(mask, ip);
|
|
}
|
|
|
|
/*
|
|
* do an ipinfo with defaults
|
|
*/
|
|
int
|
|
lookupip(uint8_t *ipaddr, Info *iip, int gate)
|
|
{
|
|
char ip[32];
|
|
Ndbtuple *t, *nt;
|
|
char *attrs[32], **p;
|
|
|
|
if(opendb() == nil){
|
|
warning(1, "can't open db");
|
|
return -1;
|
|
}
|
|
|
|
p = attrs;
|
|
*p++ = "ip";
|
|
*p++ = "ipmask";
|
|
*p++ = "@ipgw";
|
|
if(!gate){
|
|
*p++ = "bootf";
|
|
*p++ = "bootf2";
|
|
*p++ = "@tftp";
|
|
*p++ = "@tftp2";
|
|
*p++ = "rootpath";
|
|
*p++ = "dhcp";
|
|
*p++ = "vendorclass";
|
|
*p++ = "ether";
|
|
*p++ = "dom";
|
|
*p++ = "@fs";
|
|
*p++ = "@auth";
|
|
}
|
|
*p = 0;
|
|
|
|
memset(iip, 0, sizeof(*iip));
|
|
snprint(ip, sizeof(ip), "%I", ipaddr);
|
|
t = ndbipinfo(db, "ip", ip, attrs, p - attrs);
|
|
if(t == nil)
|
|
return -1;
|
|
|
|
for(nt = t; nt != nil; nt = nt->entry){
|
|
if(strcmp(nt->attr, "ip") == 0)
|
|
setipaddr(iip->ipaddr, nt->val);
|
|
else
|
|
if(strcmp(nt->attr, "ipmask") == 0)
|
|
setipmask(iip->ipmask, nt->val);
|
|
else
|
|
if(strcmp(nt->attr, "fs") == 0)
|
|
setipaddr(iip->fsip, nt->val);
|
|
else
|
|
if(strcmp(nt->attr, "auth") == 0)
|
|
setipaddr(iip->auip, nt->val);
|
|
else
|
|
if(strcmp(nt->attr, "tftp") == 0)
|
|
setipaddr(iip->tftp, nt->val);
|
|
else
|
|
if(strcmp(nt->attr, "tftp2") == 0)
|
|
setipaddr(iip->tftp2, nt->val);
|
|
else
|
|
if(strcmp(nt->attr, "ipgw") == 0)
|
|
setipaddr(iip->gwip, nt->val);
|
|
else
|
|
if(strcmp(nt->attr, "ether") == 0){
|
|
/*
|
|
* this is probably wrong for machines with multiple
|
|
* ethers. bootp or dhcp requests could come from any
|
|
* of the ethers listed in the ndb entry.
|
|
*/
|
|
if(memcmp(iip->etheraddr, noetheraddr, 6) == 0)
|
|
parseether(iip->etheraddr, nt->val);
|
|
iip->indb = 1;
|
|
}
|
|
else
|
|
if(strcmp(nt->attr, "dhcp") == 0){
|
|
if(iip->dhcpgroup[0] == 0)
|
|
strcpy(iip->dhcpgroup, nt->val);
|
|
}
|
|
else
|
|
if(strcmp(nt->attr, "bootf") == 0){
|
|
if(iip->bootf[0] == 0)
|
|
strcpy(iip->bootf, nt->val);
|
|
}
|
|
else
|
|
if(strcmp(nt->attr, "bootf2") == 0){
|
|
if(iip->bootf2[0] == 0)
|
|
strcpy(iip->bootf2, nt->val);
|
|
}
|
|
else
|
|
if(strcmp(nt->attr, "vendor") == 0){
|
|
if(iip->vendor[0] == 0)
|
|
strcpy(iip->vendor, nt->val);
|
|
}
|
|
else
|
|
if(strcmp(nt->attr, "dom") == 0){
|
|
if(iip->domain[0] == 0)
|
|
strcpy(iip->domain, nt->val);
|
|
}
|
|
else
|
|
if(strcmp(nt->attr, "rootpath") == 0){
|
|
if(iip->rootpath[0] == 0)
|
|
strcpy(iip->rootpath, nt->val);
|
|
}
|
|
}
|
|
ndbfree(t);
|
|
maskip(iip->ipaddr, iip->ipmask, iip->ipnet);
|
|
return 0;
|
|
}
|
|
|
|
static uint8_t zeroes[6];
|
|
|
|
/*
|
|
* lookup info about a client in the database. Find an address on the
|
|
* same net as riip.
|
|
*/
|
|
int
|
|
lookup(Bootp *bp, Info *iip, Info *riip)
|
|
{
|
|
Ndbtuple *t, *nt;
|
|
Ndbs s;
|
|
char *hwattr;
|
|
char *hwval, hwbuf[33];
|
|
uint8_t ciaddr[IPaddrlen];
|
|
|
|
if(opendb() == nil){
|
|
warning(1, "can't open db");
|
|
return -1;
|
|
}
|
|
|
|
memset(iip, 0, sizeof(*iip));
|
|
|
|
/* client knows its address? */
|
|
v4tov6(ciaddr, bp->ciaddr);
|
|
if(validip(ciaddr)){
|
|
if(lookupip(ciaddr, iip, 0) < 0) {
|
|
if (debug)
|
|
warning(0, "don't know %I", ciaddr);
|
|
return -1; /* don't know anything about it */
|
|
}
|
|
if(!samenet(riip->ipaddr, iip)){
|
|
warning(0, "%I not on %I", ciaddr, riip->ipnet);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* see if this is a masquerade, i.e., if the ether
|
|
* address doesn't match what we expected it to be.
|
|
*/
|
|
if(memcmp(iip->etheraddr, zeroes, 6) != 0)
|
|
if(memcmp(bp->chaddr, iip->etheraddr, 6) != 0)
|
|
warning(0, "ciaddr %I rcvd from %E instead of %E",
|
|
ciaddr, bp->chaddr, iip->etheraddr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
if(bp->hlen > Maxhwlen)
|
|
return -1;
|
|
switch(bp->htype){
|
|
case 1:
|
|
hwattr = "ether";
|
|
hwval = hwbuf;
|
|
snprint(hwbuf, sizeof(hwbuf), "%E", bp->chaddr);
|
|
break;
|
|
default:
|
|
syslog(0, blog, "not ethernet %E, htype %d, hlen %d",
|
|
bp->chaddr, bp->htype, bp->hlen);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* use hardware address to find an ip address on
|
|
* same net as riip
|
|
*/
|
|
t = ndbsearch(db, &s, hwattr, hwval);
|
|
while(t){
|
|
for(nt = t; nt; nt = nt->entry){
|
|
if(strcmp(nt->attr, "ip") != 0)
|
|
continue;
|
|
parseip(ciaddr, nt->val);
|
|
if(lookupip(ciaddr, iip, 0) < 0)
|
|
continue;
|
|
if(samenet(riip->ipaddr, iip)){
|
|
ndbfree(t);
|
|
return 0;
|
|
}
|
|
}
|
|
ndbfree(t);
|
|
t = ndbsnext(&s, hwattr, hwval);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* interface to ndbipinfo
|
|
*/
|
|
Ndbtuple*
|
|
lookupinfo(uint8_t *ipaddr, char **attr, int n)
|
|
{
|
|
char ip[32];
|
|
|
|
sprint(ip, "%I", ipaddr);
|
|
return ndbipinfo(db, "ip", ip, attr, n);
|
|
}
|
|
|
|
/*
|
|
* return the ip addresses for a type of server for system ip
|
|
*/
|
|
int
|
|
lookupserver(char *attr, uint8_t **ipaddrs, Ndbtuple *t)
|
|
{
|
|
Ndbtuple *nt;
|
|
int rv = 0;
|
|
|
|
for(nt = t; rv < 2 && nt != nil; nt = nt->entry)
|
|
if(strcmp(nt->attr, attr) == 0){
|
|
parseip(ipaddrs[rv], nt->val);
|
|
rv++;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* just lookup the name
|
|
*/
|
|
void
|
|
lookupname(char *val, Ndbtuple *t)
|
|
{
|
|
Ndbtuple *nt;
|
|
|
|
for(nt = t; nt != nil; nt = nt->entry)
|
|
if(strcmp(nt->attr, "dom") == 0){
|
|
strcpy(val, nt->val);
|
|
break;
|
|
}
|
|
}
|