예제 #1
0
static
errno_t	ppfilter_data_out_raw (void *cookie, socket_t so, const struct sockaddr *to,
                               __unused mbuf_t *data, __unused mbuf_t *control, __unused sflt_data_flag_t flags)
{
    int32_t action = cookie ? ((struct pp_filter_cookie*)cookie)->action : COOKIE_NO_ACTION;
    if (action > COOKIE_NO_ACTION)
        return (action); // socket has already been filtered -- this will occur with UDP sockets that call connect

    if (!to) {
        struct sockaddr_in6 local;
        if (0 != sock_getpeername(so, (struct sockaddr*)&local, sizeof(local)))
            bzero(&local, sizeof(local));
        to = (const struct sockaddr*)&local;
    }

    return ( ppfilter_connect((pp_filter_cookie_t)cookie, so, to, 0) ? EHOSTUNREACH : 0 );
}
예제 #2
0
int
libcfs_sock_read (cfs_socket_t *sock, void *buffer, int nob, int timeout)
{
        size_t          rcvlen;
        int             rc;
        cfs_duration_t  to = cfs_time_seconds(timeout);
        cfs_time_t      then;
        struct timeval  tv;

        LASSERT(nob > 0);

        for (;;) {
                struct iovec  iov = {
                        .iov_base = buffer,
                        .iov_len  = nob
                };
                struct  msghdr  msg = {
                        .msg_name       = NULL,
                        .msg_namelen    = 0,
                        .msg_iov        = &iov,
                        .msg_iovlen     = 1,
                        .msg_control    = NULL,
                        .msg_controllen = 0,
                        .msg_flags      = 0,
                };
                cfs_duration_usec(to, &tv);
                rc = -sock_setsockopt(C2B_SOCK(sock), SOL_SOCKET, SO_RCVTIMEO,
                                      &tv, sizeof(tv));
                if (rc != 0) {
                        CERROR("Can't set socket recv timeout "
                                        "%ld.%06d: %d\n",
                                        (long)tv.tv_sec, (int)tv.tv_usec, rc);
                        return rc;
                }

                then = cfs_time_current();
                rc = -sock_receive(C2B_SOCK(sock), &msg, 0, &rcvlen);
                to -= cfs_time_current() - then;

                if (rc != 0 && rc != -EWOULDBLOCK)
                        return rc;
                if (rcvlen == nob)
                        return 0;

                if (to <= 0)
                        return -EAGAIN;

                buffer = ((char *)buffer) + rcvlen;
                nob -= rcvlen;
        }
        return 0;
}

int
libcfs_sock_write (cfs_socket_t *sock, void *buffer, int nob, int timeout)
{
        size_t          sndlen;
        int             rc;
        cfs_duration_t  to = cfs_time_seconds(timeout);
        cfs_time_t      then;
        struct timeval  tv;

        LASSERT(nob > 0);

        for (;;) {
                struct iovec  iov = {
                        .iov_base = buffer,
                        .iov_len  = nob
                };
                struct  msghdr  msg = {
                        .msg_name       = NULL,
                        .msg_namelen    = 0,
                        .msg_iov        = &iov,
                        .msg_iovlen     = 1,
                        .msg_control    = NULL,
                        .msg_controllen = 0,
                        .msg_flags      = (timeout == 0) ? MSG_DONTWAIT : 0,
                };

                if (timeout != 0) {
                        cfs_duration_usec(to, &tv);
                        rc = -sock_setsockopt(C2B_SOCK(sock), SOL_SOCKET, SO_SNDTIMEO,
                                              &tv, sizeof(tv));
                        if (rc != 0) {
                                CERROR("Can't set socket send timeout "
                                       "%ld.%06d: %d\n",
                                       (long)tv.tv_sec, (int)tv.tv_usec, rc);
                                return rc;
                        }
                }

                then = cfs_time_current();
                rc = -sock_send(C2B_SOCK(sock), &msg, 
                                ((timeout == 0) ? MSG_DONTWAIT : 0), &sndlen);
                to -= cfs_time_current() - then;

                if (rc != 0 && rc != -EWOULDBLOCK)
                        return rc;
                if (sndlen == nob)
                        return 0;

                if (to <= 0)
                        return -EAGAIN;
                buffer = ((char *)buffer) + sndlen;
                nob -= sndlen;
        }
        return 0;

}

int
libcfs_sock_getaddr (cfs_socket_t *sock, int remote, __u32 *ip, int *port)
{
        struct sockaddr_in sin;
        int                rc;

        if (remote != 0) 
                /* Get remote address */
                rc = -sock_getpeername(C2B_SOCK(sock), (struct sockaddr *)&sin, sizeof(sin));
        else 
                /* Get local address */
                rc = -sock_getsockname(C2B_SOCK(sock), (struct sockaddr *)&sin, sizeof(sin));
        if (rc != 0) {
                CERROR ("Error %d getting sock %s IP/port\n",
                         rc, remote ? "peer" : "local");
                return rc;
        }

        if (ip != NULL)
                *ip = ntohl (sin.sin_addr.s_addr);

        if (port != NULL)
                *port = ntohs (sin.sin_port);
        return 0;
}

int
libcfs_sock_setbuf (cfs_socket_t *sock, int txbufsize, int rxbufsize)
{
        int                 option;
        int                 rc;
        
        if (txbufsize != 0) {
                option = txbufsize;
                rc = -sock_setsockopt(C2B_SOCK(sock), SOL_SOCKET, SO_SNDBUF,
                                     (char *)&option, sizeof (option));
                if (rc != 0) {
                        CERROR ("Can't set send buffer %d: %d\n",
                                option, rc);
                        return (rc);
                } 
        } 
        
        if (rxbufsize != 0) {
                option = rxbufsize;
                rc = -sock_setsockopt (C2B_SOCK(sock), SOL_SOCKET, SO_RCVBUF,
                                      (char *)&option, sizeof (option));
                if (rc != 0) {
                        CERROR ("Can't set receive buffer %d: %d\n",
                                option, rc);
                        return (rc);
                }
        }
        return 0;
}
예제 #3
0
//process
// block/allow, or ask user and put thread to sleep
kern_return_t process(void *cookie, socket_t so, const struct sockaddr *to)
{
    //result
    kern_return_t result = kIOReturnError;
    
    //event
    firewallEvent event = {0};
    
    //rule
    int action = RULE_STATE_NOT_FOUND;
    
    //awake reason
    int reason = 0;
    
    //socket type
    int socketType = 0;
    
    //length of socket type
    int socketTypeLength = 0;
    
    //process name
    char processName[PATH_MAX] = {0};

    //what does rule say?
    // loop until we have an answer
    while(true)
    {
        //reset
        bzero(&event, sizeof(event));
        
        //extract action
        action = ((struct cookieStruct*)cookie)->ruleAction;
        
        //get process name
        proc_selfname(processName, PATH_MAX);

        //block?
        if(RULE_STATE_BLOCK == action)
        {
            //dbg msg
            IOLog("LULU: rule says block for %s (pid: %d)\n", processName, proc_selfpid());
            
            //gtfo!
            result = EPERM;
            
            //all done
            goto bail;
        }
        
        //allow?
        else if(RULE_STATE_ALLOW == action)
        {
            //dbg msg
            IOLog("LULU: rule says allow for %s (pid: %d)\n", processName, proc_selfpid());
            
            //ok
            result = kIOReturnSuccess;
            
            //all done
            goto bail;
        }
        
        //not found
        // ->ask daemon and sleep for response
        else if(RULE_STATE_NOT_FOUND == action)
        {
            //dbg msg
            IOLog("LULU: no rule found for %s (pid: %d)\n", processName, proc_selfpid());
            
            //zero out
            bzero(&event, sizeof(firewallEvent));
            
            //set type
            event.networkOutEvent.type = EVENT_NETWORK_OUT;
            
            //add pid
            event.networkOutEvent.pid = proc_selfpid();
            
            //init length
            socketTypeLength = sizeof(socketType);
            
            //get socket type
            sock_getsockopt(so, SOL_SOCKET, SO_TYPE, &socketType, &socketTypeLength);
            
            //save type
            event.networkOutEvent.socketType = socketType;
            
            //UDP sockets destination socket might be null
            // so grab via 'getpeername' and save as 'remote addr'
            if(NULL == to)
            {
                //copy into 'remote addr' for user mode
                if(0 != sock_getpeername(so, (struct sockaddr*)&(event.networkOutEvent.remoteAddress), sizeof(event.networkOutEvent.remoteAddress)))
                {
                    //err msg
                    IOLog("LULU ERROR: sock_getpeername() failed");
                    
                    //bail
                    goto bail;
                }
            }
            
            //copy remote socket for user mode
            else
            {
                //add remote (destination) socket addr
                memcpy(&(event.networkOutEvent.remoteAddress), to, sizeof(event.networkOutEvent.remoteAddress));
            }
            
            //queue it up
            sharedDataQueue->enqueue_tail(&event, sizeof(firewallEvent));
            
            //dbg msg
            IOLog("LULU: queued response to user mode, now going to sleep!\n");
            
            //lock
            IOLockLock(ruleEventLock);
            
            //sleep
            reason = IOLockSleep(ruleEventLock, &ruleEventLock, THREAD_ABORTSAFE);
            
            //TODO: fix panic, think if kext is unloaded (sets ruleEventLock to NULL) this can still wake up?
            // "Preemption level underflow, possible cause unlocking an unlocked mutex or spinlock"
            //  seems to happen when process is killed or kext unloaded while in the IOLockSleep!?
            
            //unlock
            IOLockUnlock(ruleEventLock);
            
            //thread wakeup cuz of signal, etc
            // ->just bail (process likely exited, etc)
            if(THREAD_AWAKENED != reason)
            {
                //dbg msg
                IOLog("LULU: thread awoke, but because of %d!\n", reason);
                
                //gtfo!
                result = EPERM;
                
                //all done
                goto bail;
            }
            
            //dbg msg
            IOLog("LULU: thread awoke, will check/process response\n");
            
            //try get rule action again
            // ->not found, block, allow, etc
            ((struct cookieStruct*)(cookie))->ruleAction = queryRule(proc_selfpid());
            
            //loop to (re)process
        }
        
    }//while
    
bail:
    
    return result;
}
예제 #4
0
//callback for incoming data
// only interested in DNS responses for IP:URL mappings
// code inspired by: https://github.com/williamluke/peerguardian-linux/blob/master/pgosx/kern/ppfilter.c
static errno_t data_in(void *cookie, socket_t so, const struct sockaddr *from, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags)
{
    //dbg msg
    IOLog("LULU: in %s\n", __FUNCTION__);
    
    //port
    in_port_t port = 0;
    
    //peer name
    struct sockaddr_in6 peerName = {0};
    
    //mem buffer
    mbuf_t memBuffer = NULL;
    
    //response size
    size_t responseSize = 0;
    
    //dns header
    dnsHeader* dnsHeader = NULL;
    
    //firewall event
    firewallEvent event = {0};
    
    //destination socket ('from') might be null?
    // if so, grab it via 'getpeername' from the socket
    if(NULL == from)
    {
        //lookup remote socket info
        if(0 != sock_getpeername(so, (struct sockaddr*)&peerName, sizeof(peerName)))
        {
            //err msg
            IOLog("LULU ERROR: sock_getpeername() failed\n");
            
            //bail
            goto bail;
        }
        
        //now, assign
        from = (const struct sockaddr*)&peerName;
    }

    //get port
    switch(from->sa_family)
    {
        //IPv4
        case AF_INET:
            port = ntohs(((const struct sockaddr_in*)from)->sin_port);
            break;
            
        //IPv6
        case AF_INET6:
            port = ntohs(((const struct sockaddr_in6*)from)->sin6_port);
            break;
            
        default:
            break;
    }
    
    //ignore non-DNS
    if(53 != port)
    {
        //bail
        goto bail;
    }
    
    //init memory buffer
    memBuffer = *data;
    if(NULL == memBuffer)
    {
        //bail
        goto bail;
    }
    
    //get memory buffer
    while(MBUF_TYPE_DATA != mbuf_type(memBuffer))
    {
        //get next
        memBuffer = mbuf_next(memBuffer);
        if(NULL == memBuffer)
        {
            //bail
            goto bail;
        }
    }
    
    //sanity check length
    if(mbuf_len(memBuffer) <= sizeof(struct dnsHeader))
    {
        //bail
        goto bail;
    }
    
    //get data
    // should be a DNS header
    dnsHeader = (struct dnsHeader*)mbuf_data(memBuffer);
    
    //ignore everything that isn't a DNS response
    // top bit flag will be 0x1, for "a name service response"
    if(0 == ((ntohs(dnsHeader->flags)) & (1<<(15))))
    {
        //bail
        goto bail;
    }
    
    //ignore any errors
    // bottom (4) bits will be 0x0 for "successful response"
    if(0 != ((ntohs(dnsHeader->flags)) & (1<<(0))))
    {
        //bail
        goto bail;
    }
    
    //ignore any packets that don't have answers
    if(0 == ntohs(dnsHeader->ancount))
    {
        //bail
        goto bail;
    }
    
    //zero out event struct
    bzero(&event, sizeof(firewallEvent));
    
    //set type
    event.dnsResponseEvent.type = EVENT_DNS_RESPONSE;
    
    //set size
    // max, 512
    responseSize = MIN(sizeof(event.dnsResponseEvent.response), mbuf_len(memBuffer));
    
    //copy response
    memcpy(event.dnsResponseEvent.response, mbuf_data(memBuffer), responseSize);
    
    //queue it up
    sharedDataQueue->enqueue_tail(&event, sizeof(firewallEvent));
    
bail:
    
    return kIOReturnSuccess;
}
예제 #5
0
// data in is currently used for PASV FTP support
static
errno_t	ppfilter_data_in (__unused void *cookie, socket_t so, const struct sockaddr *from,
                          mbuf_t *data, __unused mbuf_t *control, __unused sflt_data_flag_t flags)
{
    in_addr_t ip4;
    in_port_t port;

    if (!from) {
        struct sockaddr_in6 local;
        if (0 != sock_getpeername(so, (struct sockaddr*)&local, sizeof(local)))
            bzero(&local, sizeof(local));
        from = (const struct sockaddr*)&local;
    }

    if (AF_INET == from->sa_family) {
        port = ntohs(((const struct sockaddr_in*)from)->sin_port);
    } else if (AF_INET6 == from->sa_family) {
        const struct sockaddr_in6* addr6 = (const struct sockaddr_in6*)from;
        if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) || !IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr))
            return (0); // tables do not contain native ip6 addreses
        port = ntohs(addr6->sin6_port);
    } else
        return (0);

    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    // Short-circuit optimization for ftp filter -- if any other filters are ever added,
    // this will have to be removed.
    if (21 != port)
        return (0);
    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    mbuf_t mdata = *data;
    while (mdata && MBUF_TYPE_DATA != mbuf_type(mdata)) {
        mdata = mbuf_next(mdata);
    }
    if (!mdata)
        return (0);

    char *pkt = mbuf_data(mdata);
    if (!pkt)
        return (0);
    size_t len = mbuf_len(mdata);

    ip4 = INADDR_NONE;
    int block, i;
    pp_data_filter_t filt = pp_data_filters[0];
    for (i = 1; filt; ++i) {
        block = filt(pkt, len, &ip4, &port);
        if (INADDR_NONE != ip4) {
            // add to dynamic list
            pp_dynentries_lock();
            pp_dyn_entry_t e = pp_dyn_entry_get();
            if (e) {
                e->addr = ip4;
                e->port = port;
                e->block = block;
            }
            pp_dynentries_unlock();
            break;
        }
        filt = pp_data_filters[i];
    }

    return (0);
}
예제 #6
0
파일: socket.c 프로젝트: wanggx/Linux1.0
/*
 * System call vectors. Since I (RIB) want to rewrite sockets as streams,
 * we have this level of indirection. Not a lot of overhead, since more of
 * the work is done via read/write/select directly.
 */
asmlinkage int
sys_socketcall(int call, unsigned long *args)
{
  int er;
  switch(call) {
	case SYS_SOCKET:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_socket(get_fs_long(args+0),
				   get_fs_long(args+1),
				   get_fs_long(args+2)));
	case SYS_BIND:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_bind(get_fs_long(args+0),
				 (struct sockaddr *)get_fs_long(args+1),
				 get_fs_long(args+2)));
	case SYS_CONNECT:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_connect(get_fs_long(args+0),
				    (struct sockaddr *)get_fs_long(args+1),
				    get_fs_long(args+2)));
	case SYS_LISTEN:
		er=verify_area(VERIFY_READ, args, 2 * sizeof(long));
		if(er)
			return er;
		return(sock_listen(get_fs_long(args+0),
				   get_fs_long(args+1)));
	case SYS_ACCEPT:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_accept(get_fs_long(args+0),
				   (struct sockaddr *)get_fs_long(args+1),
				   (int *)get_fs_long(args+2)));
	case SYS_GETSOCKNAME:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_getsockname(get_fs_long(args+0),
					(struct sockaddr *)get_fs_long(args+1),
					(int *)get_fs_long(args+2)));
	case SYS_GETPEERNAME:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_getpeername(get_fs_long(args+0),
					(struct sockaddr *)get_fs_long(args+1),
					(int *)get_fs_long(args+2)));
	case SYS_SOCKETPAIR:
		er=verify_area(VERIFY_READ, args, 4 * sizeof(long));
		if(er)
			return er;
		return(sock_socketpair(get_fs_long(args+0),
				       get_fs_long(args+1),
				       get_fs_long(args+2),
				       (unsigned long *)get_fs_long(args+3)));
	case SYS_SEND:
		er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long));
		if(er)
			return er;
		return(sock_send(get_fs_long(args+0),
				 (void *)get_fs_long(args+1),
				 get_fs_long(args+2),
				 get_fs_long(args+3)));
	case SYS_SENDTO:
		er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long));
		if(er)
			return er;
		return(sock_sendto(get_fs_long(args+0),
				   (void *)get_fs_long(args+1),
				   get_fs_long(args+2),
				   get_fs_long(args+3),
				   (struct sockaddr *)get_fs_long(args+4),
				   get_fs_long(args+5)));
	case SYS_RECV:
		er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long));
		if(er)
			return er;
		return(sock_recv(get_fs_long(args+0),
				 (void *)get_fs_long(args+1),
				 get_fs_long(args+2),
				 get_fs_long(args+3)));
	case SYS_RECVFROM:
		er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long));
		if(er)
			return er;
		return(sock_recvfrom(get_fs_long(args+0),
				     (void *)get_fs_long(args+1),
				     get_fs_long(args+2),
				     get_fs_long(args+3),
				     (struct sockaddr *)get_fs_long(args+4),
				     (int *)get_fs_long(args+5)));
	case SYS_SHUTDOWN:
		er=verify_area(VERIFY_READ, args, 2* sizeof(unsigned long));
		if(er)
			return er;
		return(sock_shutdown(get_fs_long(args+0),
				     get_fs_long(args+1)));
	case SYS_SETSOCKOPT:
		er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long));
		if(er)
			return er;
		return(sock_setsockopt(get_fs_long(args+0),
				       get_fs_long(args+1),
				       get_fs_long(args+2),
				       (char *)get_fs_long(args+3),
				       get_fs_long(args+4)));
	case SYS_GETSOCKOPT:
		er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long));
		if(er)
			return er;
		return(sock_getsockopt(get_fs_long(args+0),
				       get_fs_long(args+1),
				       get_fs_long(args+2),
				       (char *)get_fs_long(args+3),
				       (int *)get_fs_long(args+4)));
	default:
		return(-EINVAL);
  }
}