186 lines
4.0 KiB
C
186 lines
4.0 KiB
C
#include <u.h>
|
|
#define NOPLAN9DEFINES
|
|
#include <libc.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include <sys/un.h>
|
|
#include <netinet/in.h>
|
|
|
|
static char *nets[] = { "tcp", "udp", nil };
|
|
#define CLASS(p) ((*(uchar*)(p))>>6)
|
|
|
|
static struct {
|
|
char *net;
|
|
char *service;
|
|
int port;
|
|
} porttbl[] = {
|
|
"tcp", "9fs", 564,
|
|
"tcp", "whoami", 565,
|
|
"tcp", "guard", 566,
|
|
"tcp", "ticket", 567,
|
|
"tcp", "exportfs", 17007,
|
|
"tcp", "rexexec", 17009,
|
|
"tcp", "ncpu", 17010,
|
|
"tcp", "cpu", 17013,
|
|
"tcp", "venti", 17034,
|
|
"tcp", "wiki", 17035,
|
|
"tcp", "secstore", 5356,
|
|
"udp", "dns", 53,
|
|
"tcp", "dns", 53,
|
|
};
|
|
|
|
static int
|
|
setport(struct sockaddr_storage *ss, int port)
|
|
{
|
|
switch(ss->ss_family){
|
|
case AF_INET:
|
|
((struct sockaddr_in*)ss)->sin_port = htons(port);
|
|
break;
|
|
case AF_INET6:
|
|
((struct sockaddr_in6*)ss)->sin6_port = htons(port);
|
|
break;
|
|
default:
|
|
errstr("unknown protocol family %d", ss->ss_family);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
p9dialparse(char *addr, char **pnet, char **punix, void *phost, int *pport)
|
|
{
|
|
char *net, *host, *port, *e;
|
|
int i;
|
|
struct servent *se;
|
|
struct hostent *he;
|
|
struct sockaddr_storage *ss;
|
|
struct addrinfo *result;
|
|
|
|
ss = phost;
|
|
|
|
memset(ss, 0, sizeof *ss);
|
|
|
|
*punix = nil;
|
|
net = addr;
|
|
if((host = strchr(net, '!')) == nil){
|
|
werrstr("malformed address");
|
|
return -1;
|
|
}
|
|
*host++ = 0;
|
|
if((port = strchr(host, '!')) == nil){
|
|
if(strcmp(net, "unix")==0 || strcmp(net, "net")==0){
|
|
Unix:
|
|
if(strlen(host)+1 > sizeof ((struct sockaddr_un*)ss)->sun_path){
|
|
werrstr("unix socket name too long");
|
|
return -1;
|
|
}
|
|
*punix = host;
|
|
*pnet = "unix";
|
|
ss->ss_family = AF_UNIX;
|
|
strcpy(((struct sockaddr_un*)ss)->sun_path, host);
|
|
*pport = 0;
|
|
return 0;
|
|
}
|
|
werrstr("malformed address");
|
|
return -1;
|
|
}
|
|
*port++ = 0;
|
|
|
|
if(*host == 0){
|
|
werrstr("malformed address (empty host)");
|
|
return -1;
|
|
}
|
|
if(*port == 0){
|
|
werrstr("malformed address (empty port)");
|
|
return -1;
|
|
}
|
|
|
|
if(strcmp(net, "unix") == 0)
|
|
goto Unix;
|
|
|
|
if(strcmp(net, "tcp")!=0 && strcmp(net, "udp")!=0 && strcmp(net, "net") != 0){
|
|
werrstr("bad network %s!%s!%s", net, host, port);
|
|
return -1;
|
|
}
|
|
|
|
/* translate host */
|
|
if(strcmp(host, "*") == 0){
|
|
ss->ss_family = AF_INET6;
|
|
((struct sockaddr_in6*)ss)->sin6_addr = in6addr_any;
|
|
}else if((he = gethostbyname(host)) != nil && he->h_addr_list[0] != nil){
|
|
ss->ss_family = he->h_addrtype;
|
|
switch(ss->ss_family){
|
|
case AF_INET:
|
|
((struct sockaddr_in*)ss)->sin_addr = *(struct in_addr*) *(he->h_addr_list);
|
|
break;
|
|
case AF_INET6:
|
|
((struct sockaddr_in6*)ss)->sin6_addr = *(struct in6_addr*) *(he->h_addr_list);
|
|
break;
|
|
default:
|
|
errstr("unknown protocol family %d", ss->ss_family);
|
|
return -1;
|
|
}
|
|
}else if(getaddrinfo(host, NULL, NULL, &result) == 0) {
|
|
switch (result->ai_family) {
|
|
case AF_INET:
|
|
memmove((struct sockaddr_in*)ss, result->ai_addr, result->ai_addrlen);
|
|
break;
|
|
case AF_INET6:
|
|
memmove((struct sockaddr_in6*)ss, result->ai_addr, result->ai_addrlen);
|
|
break;
|
|
default:
|
|
errstr("unknown protocol family %d", ss->ss_family);
|
|
return -1;
|
|
}
|
|
}else{
|
|
werrstr("unknown host %s", host);
|
|
return -1;
|
|
}
|
|
|
|
/* translate network and port; should return list rather than first */
|
|
if(strcmp(net, "net") == 0){
|
|
for(i=0; nets[i]; i++){
|
|
if((se = getservbyname(port, nets[i])) != nil){
|
|
*pnet = nets[i];
|
|
*pport = ntohs(se->s_port);
|
|
return setport(ss, *pport);
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i=0; i<nelem(porttbl); i++){
|
|
if(strcmp(net, "net") == 0 || strcmp(porttbl[i].net, net) == 0)
|
|
if(strcmp(porttbl[i].service, port) == 0){
|
|
*pnet = porttbl[i].net;
|
|
*pport = porttbl[i].port;
|
|
return setport(ss, *pport);
|
|
}
|
|
}
|
|
|
|
if(strcmp(net, "net") == 0){
|
|
werrstr("unknown service net!*!%s", port);
|
|
return -1;
|
|
}
|
|
|
|
if(strcmp(net, "tcp") != 0 && strcmp(net, "udp") != 0){
|
|
werrstr("unknown network %s", net);
|
|
return -1;
|
|
}
|
|
|
|
*pnet = net;
|
|
i = strtol(port, &e, 0);
|
|
if(*e == 0){
|
|
*pport = i;
|
|
return setport(ss, *pport);
|
|
}
|
|
|
|
if((se = getservbyname(port, net)) != nil){
|
|
*pport = ntohs(se->s_port);
|
|
return setport(ss, *pport);
|
|
}
|
|
werrstr("unknown service %s!*!%s", net, port);
|
|
return -1;
|
|
}
|