From e3ec000e93f0eeb365633d36d1a9ce0b139c75b5 Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Fri, 9 Oct 2015 15:41:16 -0400 Subject: [PATCH] Added intercept build file and sources --- make-netcon.mk | 29 +++++ netcon/common.c | 130 +++++++++++++++++++++ netcon/common.h | 34 ++++++ netcon/defs.h | 60 ++++++++++ netcon/intercept | 54 +++++++++ netcon/intercept.c | 8 +- netcon/intercept.h | 233 +++++++++++++++++++++++++++++++++++++ netcon/libintercept.so.1.0 | Bin 0 -> 52880 bytes netcon/sendfd.c | 107 +++++++++++++++++ netcon/sendfd.h | 3 + netcon/utils.c | 93 +++++++++++++++ 11 files changed, 746 insertions(+), 5 deletions(-) create mode 100644 make-netcon.mk create mode 100755 netcon/common.c create mode 100755 netcon/common.h create mode 100644 netcon/defs.h create mode 100755 netcon/intercept create mode 100755 netcon/intercept.h create mode 100755 netcon/libintercept.so.1.0 create mode 100644 netcon/sendfd.c create mode 100644 netcon/sendfd.h create mode 100644 netcon/utils.c diff --git a/make-netcon.mk b/make-netcon.mk new file mode 100644 index 000000000..2aa797ddf --- /dev/null +++ b/make-netcon.mk @@ -0,0 +1,29 @@ +SHCC=gcc + +# intercept-specific +intercept_CFLAGS = -c -fPIC -g -O2 -Wall -std=c99 -D_GNU_SOURCE -DNETCON_INTERCEPT +LIB_NAME = intercept +SHLIB_EXT=dylib +SHLIB_MAJOR = 1 +SHLIB_MINOR = 8 +COMMON = common +OBJS= netcon/intercept.o +SHLIB = ${LIB_NAME}.${SHLIB_EXT}.${SHLIB_MAJOR}.${SHLIB_MINOR} +SHLDFLAGS = -g -O2 -Wall -I. -nostdlib -shared +LIBS = -ldl -lc -lrt -lpthread + +lib: + ${SHCC} $(intercept_CFLAGS) -I. netcon/intercept.c -o netcon/intercept.o + ${SHCC} $(intercept_CFLAGS) -I. netcon/common.c -o netcon/common.o + ${SHCC} $(intercept_CFLAGS) -I. netcon/sendfd.c -o netcon/sendfd.o + ${SHCC} $(SHLDFLAGS) netcon/intercept.o netcon/common.o netcon/sendfd.o -o netcon/libintercept.so.1.0 $(LIBS) + +install: + cp netcon/libintercept.so.1.0 /lib/libintercept.so.1.0 + ln -sf /lib/libintercept.so.1.0 /lib/libintercept + /usr/bin/install -c netcon/intercept /usr/bin + +uninstall: + rm -r /lib/libintercept.so.1.0 + rm -r /lib/libintercept + rm -r /usr/bin/intercept diff --git a/netcon/common.c b/netcon/common.c new file mode 100755 index 000000000..f6487cd53 --- /dev/null +++ b/netcon/common.c @@ -0,0 +1,130 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +void dwr(const char *fmt, ...); + +/* defined in intercept and service */ +extern FILE* logfile; +extern char* logfilename; +//extern flog = -1; + +extern pthread_mutex_t loglock; + + + +#ifdef NETCON_SERVICE + void dwr(int, const char *fmt, ...); + + void dwr(const char *fmt, ...) + { + int saveerr; + va_list ap; + va_start(ap, fmt); + saveerr = errno; + dwr(-1, fmt, ap); + errno = saveerr; + va_end(ap); + } + + void dwr(int pid, const char *fmt, ...) +#endif +#ifdef NETCON_INTERCEPT + void dwr(const char *fmt, ...) +#endif +{ + va_list ap; + int saveerr; + char timestring[20]; + time_t timestamp; + + timestamp = time(NULL); + strftime(timestring, sizeof(timestring), "%H:%M:%S", localtime(×tamp)); + + if(logfile) + fprintf(logfile, "%s ", timestring); + fprintf(stderr, "%s ", timestring); + +#ifdef NETCON_SERVICE + if(ns != NULL) + { + size_t num_intercepts = ns->intercepts.size(); + size_t num_connections = ns->connections.size(); + if(logfile) + fprintf(logfile, "[i/c/tid=%3lu|%3lu|%7d]", num_intercepts, num_connections, pid); + fprintf(stderr, "[i/c/tid=%3lu|%3lu|%7d]", num_intercepts, num_connections, pid); + } + else { + if(logfile) + fprintf(logfile, "[i/c/tid=%3d|%3d|%7d]", 0, 0, -1); + fprintf(stderr, "[i/c/tid=%3d|%3d|%7d]", 0, 0, -1); + } + +#endif + +#ifdef NETCON_INTERCEPT + //pthread_mutex_lock(&loglock); + int pid = getpid(); + if(logfile) + fprintf(logfile, "[tid=%7d]", pid); + fprintf(stderr, "[tid=%7d]", pid); + //pthread_mutex_unlock(&loglock); +#endif + + if(logfile) + fputs(" ", logfile); + fputs(" ", stderr); + + /* logfile */ + va_start(ap, fmt); + saveerr = errno; + if(logfile){ + vfprintf(logfile, fmt, ap); + fflush(logfile); + } + va_end(ap); + + /* console */ + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fflush(stderr); + errno = saveerr; + va_end(ap); +} diff --git a/netcon/common.h b/netcon/common.h new file mode 100755 index 000000000..275db8db8 --- /dev/null +++ b/netcon/common.h @@ -0,0 +1,34 @@ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void set_log_options(int, char *, int); +void show_msg(int level, char *, ...); +unsigned int resolve_ip(char *, int, int); + + +#define MSGERR 0 +#define MSGDEBUG 1 + + +#endif diff --git a/netcon/defs.h b/netcon/defs.h new file mode 100644 index 000000000..455f166f6 --- /dev/null +++ b/netcon/defs.h @@ -0,0 +1,60 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + + +/* Maximum number of socket connections allowed in service */ +#define MAX_SOCKETS 1024 +/* Maximum number of harnesses allowed to be connected to this service */ +#define MAX_INTERCEPTS 256 + +#define SELECT_PERF_WARNING 1000 + +#define CMD_SIZE 32 +#define DATA_IDX CMD_SIZE +#define CMD_IDX 0 +#define BUF_SZ 1024 + +/* number or times an intercept will attempt to connect to the service */ +#define SERVICE_CONNECT_ATTEMPTS 3 + +/* how long we wait when polling various I/O sources in the core I/O loop */ +#define INTERCEPT_POLL_TIMEOUT 0 + +/* how often we want lwIP to poll our callback. + - We use this to resume pending data transfers */ +#define APPLICATION_POLL_FREQ 1 + +/* for passing applications as arguments to the service */ +#define APP_ARGUMENT_LENGTH 128 + + +#define DEFAULT_RPC_PIPE_IDX 0 + +/* display various types of detectable lwip/service/intercept problems */ +#define NETCON_WARNINGS 1 + +typedef int rpc_len_type; diff --git a/netcon/intercept b/netcon/intercept new file mode 100755 index 000000000..3eb27ff7b --- /dev/null +++ b/netcon/intercept @@ -0,0 +1,54 @@ +#!/bin/sh +# usage: +# /usr/bin/intercept program + +if [ $# = 0 ] ; then + echo "$0: insufficient arguments" + exit +fi + +case "$1" in + on) + if [ -z "$LD_PRELOAD" ] + then + export LD_PRELOAD="/lib/libintercept.so.1.0" + else + echo $LD_PRELOAD | grep -q "/lib/libintercept\.so.1.0" || \ + export LD_PRELOAD="/lib/libintercept.so $LD_PRELOAD" + fi + ;; + off) + export LD_PRELOAD=`echo -n $LD_PRELOAD | sed 's/\/lib\/libintercept.so.1.0 \?//'` + if [ -z "$LD_PRELOAD" ] + then + unset LD_PRELOAD + fi + ;; + show|sh) + echo "LD_PRELOAD=\"$LD_PRELOAD\"" + ;; + -h|-?) + echo "" + ;; + *) + if [ -z "$LD_PRELOAD" ] + then + export LD_PRELOAD="/lib/libintercept.so.1.0" + else + echo $LD_PRELOAD | grep -q "/lib/libintercept\.so.1.0" || \ + export LD_PRELOAD="/lib/libintercept.so.1.0 $LD_PRELOAD" + fi + + if [ $# = 0 ] + then + ${SHELL:-/bin/sh} + fi + + if [ $# -gt 0 ] + then + exec "$@" + fi + ;; +esac + +#EOF diff --git a/netcon/intercept.c b/netcon/intercept.c index ba3e9bbf6..074f92d24 100755 --- a/netcon/intercept.c +++ b/netcon/intercept.c @@ -40,7 +40,6 @@ char *progname = ""; #include #include #include -#include #include #include #include @@ -55,7 +54,7 @@ char *progname = ""; #include #include - +#include #include /* For NPs */ @@ -69,13 +68,12 @@ char *progname = ""; #ifdef USE_SOCKS_DNS #include #endif -#include +#include "intercept.h" +#include "common.h" #include "defs.h" #include "utils.c" -#include - /* Global Declarations */ #ifdef USE_SOCKS_DNS static int (*realresinit)(void); diff --git a/netcon/intercept.h b/netcon/intercept.h new file mode 100755 index 000000000..f190e2161 --- /dev/null +++ b/netcon/intercept.h @@ -0,0 +1,233 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + + +#ifndef _HARNESS_H +#define _HARNESS_H 1 + +#include + + +/* Userland RPC codes */ +#define RPC_UNDEFINED 0 +#define RPC_CONNECT 1 +#define RPC_CONNECT_SOCKARG 2 +#define RPC_SELECT 3 +#define RPC_POLL 4 +#define RPC_CLOSE 5 +#define RPC_READ 6 +#define RPC_WRITE 7 +#define RPC_BIND 8 +#define RPC_ACCEPT 9 +#define RPC_LISTEN 10 +#define RPC_SOCKET 11 +#define RPC_SHUTDOWN 12 + +/* Administration RPC codes */ +#define RPC_FD_MAP_COMPLETION 20 // Give the service the value we "see" for the new buffer fd +#define RPC_RETVAL 21 // not RPC per se, but something we should codify +#define RPC_KILL_INTERCEPT 22 // Tells the service we need to shut down all connections + +/* Connection statuses */ +#define UNSTARTED 0 +#define CONNECTING 1 +#define CONNECTED 2 +#define SENDING 3 +#define RECEIVING 4 +#define SENTV4REQ 5 +#define GOTV4REQ 6 +#define SENTV5METHOD 7 +#define GOTV5METHOD 8 +#define SENTV5AUTH 9 +#define GOTV5AUTH 10 +#define SENTV5CONNECT 11 +#define GOTV5CONNECT 12 +#define DONE 13 +#define FAILED 14 + +/* Flags to indicate what events a + socket was select()ed for */ +#define READ (POLLIN|POLLRDNORM) +#define WRITE (POLLOUT|POLLWRNORM|POLLWRBAND) +#define EXCEPT (POLLRDBAND|POLLPRI) +#define READWRITE (READ|WRITE) +#define READWRITEEXCEPT (READ|WRITE|EXCEPT) + + +/* for AF_UNIX sockets */ +#define MAX_PATH_NAME_SIZE 64 + +// bind +#define BIND_SIG int sockfd, const struct sockaddr *addr, socklen_t addrlen +struct bind_st +{ + int sockfd; + struct sockaddr addr; + socklen_t addrlen; + int __tid; +}; + + +// connect +#define CONNECT_SIG int __fd, const struct sockaddr * __addr, socklen_t __len +struct connect_st +{ + int __fd; + struct sockaddr __addr; + socklen_t __len; + int __tid; +}; + + +// close +#define CLOSE_SIG int fd +struct close_st +{ + int fd; +}; + + +// read +#define DEFAULT_READ_BUFFER_SIZE 1024 * 63 +// read buffer sizes (on test machine) min: 4096 default: 87380 max:6147872 +#define READ_SIG int __fd, void *__buf, size_t __nbytes +struct read_st +{ + int fd; + size_t count; + unsigned char buf[DEFAULT_READ_BUFFER_SIZE]; +}; + + + +#define DEFAULT_WRITE_BUFFER_SIZE 1024 * 63 +// write buffer sizes (on test machine) min: 4096 default: 16384 max:4194304 +#define WRITE_SIG int __fd, const void *__buf, size_t __n +struct write_st +{ + int fd; + size_t count; + char buf[DEFAULT_WRITE_BUFFER_SIZE]; +}; + + +#define LISTEN_SIG int sockfd, int backlog +struct listen_st +{ + int sockfd; + int backlog; + int __tid; +}; + + + +#define SOCKET_SIG int socket_family, int socket_type, int protocol +struct socket_st +{ + int socket_family; + int socket_type; + int protocol; + int __tid; +}; + + +#define ACCEPT4_SIG int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags + + +#define ACCEPT_SIG int sockfd, struct sockaddr *addr, socklen_t *addrlen +struct accept_st +{ + int sockfd; + struct sockaddr addr; + socklen_t addrlen; + int __tid; +}; + + +#define SHUTDOWN_SIG int socket, int how +struct shutdown_st +{ + int socket; + int how; +}; + +#define CONNECT_SOCKARG struct sockaddr * +#define SELECT_SIG int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout +#define POLL_SIG struct pollfd *__fds, nfds_t __nfds, int __timeout +#define IOCTL_SIG int __fd, unsigned long int __request, ... +#define FCNTL_SIG int __fd, int __cmd, ... +#define CLONE_SIG int (*fn) (void *arg), void *child_stack, int flags, void *arg +#define DAEMON_SIG int nochdir, int noclose + + +#define SETSOCKOPT_SIG int socket, int level, int option_name, const void *option_value, socklen_t option_len +#define GETSOCKOPT_SIG int sockfd, int level, int optname, void *optval, socklen_t *optlen + + +/* LWIP error beautification */ +const char *lwiperror(int n) +{ + switch(n) + { + case 0: + return "ERR_OK"; + case -1: + return "ERR_MEM (out of memory)"; + case -2: + return "ERR_BUF (buffer error)"; + case -3: + return "ERR_TIMEOUT (timeout)"; + case -4: + return "ERR_RTE (routing problem)"; + case -5: + return "ERR_INPROGRESS (operation in progress)"; + case -6: + return "ERR_VAL (illegal value)"; + case -7: + return "ERR_WOULDBLOCK (operation would block)"; + case -8: + return "ERR_USE (address in use)"; + case -9: + return "ERR_ISCONN (already connected)"; + case -10: + return "Fatal: ERR_ABRT (connection aborted)"; + case -11: + return "Fatal: ERR_RST (connection reset)"; + case -12: + return "Fatal: ERR_CLSD (connection closed)"; + case -13: + return "Fatal: ERR_CONN (not connected)"; + case -14: + return "Fatal: ERR_ARG (illegal argument)"; + case -15: + return "Fatal: ERR_IF (low level netif error)"; + default: + return "UNKNOWN_RET_VAL"; + } +} + +#endif diff --git a/netcon/libintercept.so.1.0 b/netcon/libintercept.so.1.0 new file mode 100755 index 0000000000000000000000000000000000000000..f315f77743a55301f2c69d2949133faedf3f417f GIT binary patch literal 52880 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 MP +#include +#include +#include + +/* Functions used to pass file descriptors between processes */ + +ssize_t sock_fd_write(int sock, int fd); +ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd); + +ssize_t sock_fd_write(int sock, int fd) +{ + ssize_t size; + struct msghdr msg; + struct iovec iov; + char buf = '\0'; + int buflen = 1; + + union + { + struct cmsghdr cmsghdr; + char control[CMSG_SPACE(sizeof (int))]; + } cmsgu; + struct cmsghdr *cmsg; + + iov.iov_base = &buf; + iov.iov_len = buflen; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + if (fd != -1) { + msg.msg_control = cmsgu.control; + msg.msg_controllen = sizeof(cmsgu.control); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof (int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *((int *) CMSG_DATA(cmsg)) = fd; + } else { + msg.msg_control = NULL; + msg.msg_controllen = 0; + } + + size = sendmsg(sock, &msg, 0); + if (size < 0) + perror ("sendmsg"); + return size; +} + + +ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd) +{ + ssize_t size; + + if (fd) { + struct msghdr msg; + struct iovec iov; + union + { + struct cmsghdr cmsghdr; + char control[CMSG_SPACE(sizeof (int))]; + } cmsgu; + struct cmsghdr *cmsg; + + iov.iov_base = buf; + iov.iov_len = bufsize; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgu.control; + msg.msg_controllen = sizeof(cmsgu.control); + size = recvmsg (sock, &msg, 0); + if (size < 0) { + perror ("recvmsg"); + exit(1); + } + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { + if (cmsg->cmsg_level != SOL_SOCKET) { + fprintf (stderr, "invalid cmsg_level %d\n", + cmsg->cmsg_level); + exit(1); + } + if (cmsg->cmsg_type != SCM_RIGHTS) { + fprintf (stderr, "invalid cmsg_type %d\n", + cmsg->cmsg_type); + exit(1); + } + + *fd = *((int *) CMSG_DATA(cmsg)); + } else + *fd = -1; + } else { + size = read (sock, buf, bufsize); + if (size < 0) { + perror("read"); + exit(1); + } + } + return size; +} diff --git a/netcon/sendfd.h b/netcon/sendfd.h new file mode 100644 index 000000000..468f7524e --- /dev/null +++ b/netcon/sendfd.h @@ -0,0 +1,3 @@ + +ssize_t sock_fd_write(int sock, int fd); +ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd); diff --git a/netcon/utils.c b/netcon/utils.c new file mode 100644 index 000000000..8192e10ea --- /dev/null +++ b/netcon/utils.c @@ -0,0 +1,93 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +void get_path_from_pid(char* dest, int pid) +{ + char ppath[50]; + sprintf(ppath, "/proc/%d/exe", pid); + if (readlink (ppath, dest, 50) != -1){ + } +} + +void print_ip(int ip) +{ + unsigned char bytes[4]; + bytes[0] = ip & 0xFF; + bytes[1] = (ip >> 8) & 0xFF; + bytes[2] = (ip >> 16) & 0xFF; + bytes[3] = (ip >> 24) & 0xFF; + printf("%d.%d.%d.%d\n", bytes[0], bytes[1], bytes[2], bytes[3]); + //return buf; +} + + +/* --- */ + + +#ifdef NETCON_SERVICE +ip_addr_t convert_ip(struct sockaddr_in * addr) +{ + ip_addr_t conn_addr; + struct sockaddr_in *ipv4 = addr; + short a = ip4_addr1(&(ipv4->sin_addr)); + short b = ip4_addr2(&(ipv4->sin_addr)); + short c = ip4_addr3(&(ipv4->sin_addr)); + short d = ip4_addr4(&(ipv4->sin_addr)); + IP4_ADDR(&conn_addr, a,b,c,d); + return conn_addr; +} + +ip_addr_t ip_addr_sin(register struct sockaddr_in *sin) { + ip_addr_t ip; + *((struct sockaddr_in*) &ip) = *sin; + return ip; +} +#endif + + +/* --- */ + + +#ifdef NETCON_INTERCEPT + +typedef unsigned char u8_t; + +#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0]) +#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1]) +#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2]) +#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3]) + +int is_local(struct sockaddr_in* addr) +{ + struct sockaddr_in *ipv4 = addr; + short a = ip4_addr1(&(ipv4->sin_addr)); + short b = ip4_addr2(&(ipv4->sin_addr)); + short c = ip4_addr3(&(ipv4->sin_addr)); + short d = ip4_addr4(&(ipv4->sin_addr)); + return (a==127 && b == 0 && c == 0 && d == 1); +} +#endif