int main(void) { const pid_t pid = getpid(); const long long_pid = (unsigned long) (0xdeadbeef00000000LL | pid); void **p_head = tail_alloc(sizeof(void *)); size_t *p_len = tail_alloc(sizeof(size_t)); if (syscall(__NR_get_robust_list, long_pid, p_head, p_len)) perror_msg_and_skip("get_robust_list"); printf("get_robust_list(%d, [%s], [%lu]) = 0\n", (int) pid, sprintaddr(*p_head), (unsigned long) *p_len); void *head = tail_alloc(*p_len); if (syscall(__NR_set_robust_list, head, *p_len)) perror_msg_and_skip("set_robust_list"); printf("set_robust_list(%p, %lu) = 0\n", head, (unsigned long) *p_len); if (syscall(__NR_get_robust_list, long_pid, p_head, p_len)) perror_msg_and_skip("get_robust_list"); printf("get_robust_list(%d, [%s], [%lu]) = 0\n", (int) pid, sprintaddr(*p_head), (unsigned long) *p_len); puts("+++ exited with 0 +++"); return 0; }
/* check result and die, printing the offending address and error */ void check_res_dumpdie(int res, struct addrinfo *addr, char* syscall) { char buf[NI_MAXHOST]; if (res == -1) { fprintf(stderr, "%s:%s: %s\n", sprintaddr(buf, sizeof(buf), addr), syscall, strerror(errno)); exit(1); } }
/* syslogs who connected to where */ void log_connection(struct connection *cnx) { struct addrinfo addr; struct sockaddr_storage ss; #define MAX_NAMELENGTH (NI_MAXHOST + NI_MAXSERV + 1) char peer[MAX_NAMELENGTH], service[MAX_NAMELENGTH], local[MAX_NAMELENGTH], target[MAX_NAMELENGTH]; int res; addr.ai_addr = (struct sockaddr*)&ss; addr.ai_addrlen = sizeof(ss); res = getpeername(cnx->q[0].fd, addr.ai_addr, &addr.ai_addrlen); if (res == -1) return; /* Can happen if connection drops before we get here. In that case, don't log anything (there is no connection) */ sprintaddr(peer, sizeof(peer), &addr); addr.ai_addrlen = sizeof(ss); res = getsockname(cnx->q[0].fd, addr.ai_addr, &addr.ai_addrlen); if (res == -1) return; sprintaddr(service, sizeof(service), &addr); addr.ai_addrlen = sizeof(ss); res = getpeername(cnx->q[1].fd, addr.ai_addr, &addr.ai_addrlen); if (res == -1) return; sprintaddr(target, sizeof(target), &addr); addr.ai_addrlen = sizeof(ss); res = getsockname(cnx->q[1].fd, addr.ai_addr, &addr.ai_addrlen); if (res == -1) return; sprintaddr(local, sizeof(local), &addr); log_message(LOG_INFO, "connection from %s to %s forwarded from %s to %s\n", peer, service, local, target); }
/* Connect to first address that works and returns a file descriptor, or -1 if * none work. * If transparent proxying is on, use fd_from peer address on external address * of new file descriptor. */ int connect_addr(struct connection *cnx, int fd_from) { struct addrinfo *a, from; struct sockaddr_storage ss; char buf[NI_MAXHOST]; int fd, res; memset(&from, 0, sizeof(from)); from.ai_addr = (struct sockaddr*)&ss; from.ai_addrlen = sizeof(ss); res = getpeername(fd_from, from.ai_addr, &from.ai_addrlen); CHECK_RES_RETURN(res, "getpeername"); for (a = cnx->proto->saddr; a; a = a->ai_next) { /* When transparent, make sure both connections use the same address family */ if (transparent && a->ai_family != from.ai_addr->sa_family) continue; if (verbose) fprintf(stderr, "connecting to %s family %d len %d\n", sprintaddr(buf, sizeof(buf), a), a->ai_addr->sa_family, a->ai_addrlen); /* XXX Needs to match ai_family from fd_from when being transparent! */ fd = socket(a->ai_family, SOCK_STREAM, 0); if (fd == -1) { log_message(LOG_ERR, "forward to %s failed:socket: %s\n", cnx->proto->description, strerror(errno)); } else { if (transparent) { res = bind_peer(fd, fd_from); CHECK_RES_RETURN(res, "bind_peer"); } res = connect(fd, a->ai_addr, a->ai_addrlen); if (res == -1) { log_message(LOG_ERR, "forward to %s failed:connect: %s\n", cnx->proto->description, strerror(errno)); close(fd); } else { return fd; } } } return -1; }