Example #1
0
int avahi_open_unicast_socket_ipv6(void) {
    struct sockaddr_in6 local;
    int fd = -1, yes;

    if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
        avahi_log_warn("socket() failed: %s", strerror(errno));
        goto fail;
    }

    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_V6ONLY failed: %s", strerror(errno));
        goto fail;
    }

    memset(&local, 0, sizeof(local));
    local.sin6_family = AF_INET6;

    if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
        avahi_log_warn("bind() failed: %s", strerror(errno));
        goto fail;
    }

    if (ipv6_pktinfo(fd) < 0)
        goto fail;

    if (avahi_set_cloexec(fd) < 0) {
        avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
        goto fail;
    }

    if (avahi_set_nonblock(fd) < 0) {
        avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
        goto fail;
    }

    return fd;

fail:
    if (fd >= 0)
        close(fd);

    return -1;
}
Example #2
0
int avahi_open_unicast_socket_ipv4(void) {
    struct sockaddr_in local;
    int fd = -1;

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        avahi_log_warn("socket() failed: %s", strerror(errno));
        goto fail;
    }

    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;

    if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
        avahi_log_warn("bind() failed: %s", strerror(errno));
        goto fail;
    }

    if (ipv4_pktinfo(fd) < 0) {
         goto fail;
    }

    if (avahi_set_cloexec(fd) < 0) {
        avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
        goto fail;
    }

    if (avahi_set_nonblock(fd) < 0) {
        avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
        goto fail;
    }

    return fd;

fail:
    if (fd >= 0)
        close(fd);

    return -1;
}
Example #3
0
/**
 * Return value is the process return value - zero on success or 1 on failure.
 * 
 * FIXME: This function is too long and unclear whether some code paths return
 * an IPC packet (or whether they shouldn't). There are probably lots of latent
 * bugs.
 */
int worker(const char *mapping_script_file, int sock) {
    ssize_t siz;
    AvahiNatpmdIPCReq req;

    assert(mapping_script_file);
    assert(mapping_script_file[0] == '/');

    mapping_script = mapping_script_file;

    if (avahi_natpm_drop_caps() != 0)
        return 1;

    avahi_set_cloexec(sock);
    /* XXX: Audit to ensure no extra sockets are passed to the child */

    avahi_set_proc_title(argv0, "%s: iptables helper", argv0);

    daemon_log(LOG_DEBUG, "%s: Worker process running with pid %d",
            __FUNCTION__, getpid());

    while ((siz = recv(sock, &req, sizeof(req), 0)) > 0) {
        pid_t pid;
        int status;
        sigset_t newsigs, oldsigs;

        if (siz != sizeof(req)) {
            daemon_log(LOG_NOTICE, "IPC request packet was too short");
            continue;
        }

        /* Prevent a race where the signal gets delivered before we wait on it
         */
        if (-1 == sigemptyset(&newsigs)) {
            daemon_log(LOG_ERR, "sigemptyset() failed: %s", strerror(errno));
            return 1;
        }

        if (-1 == sigaddset(&newsigs, SIGCHLD)) {
            daemon_log(LOG_ERR, "sigaddset(..., SIGCHLD) failed: %s", strerror(errno));
            return 1;
        }

        if (-1 == sigprocmask(SIG_BLOCK, &newsigs, &oldsigs)) {
            daemon_log(LOG_ERR, "sigprocmask(SIG_BLOCK, ...) failed: %s", strerror(errno));
            return 1;
        }

        pid = fork();
        
        if (pid == -1) {
            daemon_log(LOG_ERR, "%s: fork() failed: %s", __FUNCTION__, strerror(errno));
            return 1;
        }

        if (pid == 0) {
            /* child */
            int ret = 1; /* Child process' return value */

            /* Let the child receive SIGCHLD if it wants to */
            if (-1 == sigprocmask(SIG_UNBLOCK, &newsigs, NULL))
                daemon_log(LOG_WARNING, "Child worker process failed to unblock signals: %s",
                        strerror(errno));

            switch(req.op) {
                case IPCREQ_OP_ADD: /*@fallthrough@*/
                case IPCREQ_OP_REMOVE:
                    ret = op_add_remove(&req);
                    break;

                case IPCREQ_OP_PREPARE: /*@fallthrough@*/
                case IPCREQ_OP_CLEANUP:
                    ret = op_prepare_cleanup(&req);
                    break;

                case IPCREQ_OP_CLEAR:
                    ret = op_clear(&req);
                    break;

                default:
                    daemon_log(LOG_WARNING, "Received an IPC packet with bogus operation field");
                    ret = 1;
            }
            
            _exit(ret); /* The child process ends here. */
        }

        { /* parent */
            int signum;
            siginfo_t siginfo;
            const struct timespec waittime = { MAX_RUN_SECONDS, 0 };
            struct sigaction oldhandler, ourhandler;
            pid_t waitedpid;

            memset(&ourhandler, '\0', sizeof(ourhandler));

            ourhandler.sa_handler = sigchld_handler;

            /* Set signal handler for SIGCHLD */
            if (-1 == sigaction(SIGCHLD, &ourhandler, &oldhandler)) {
                daemon_log(LOG_ERR, "Setting signal handler for SIGCHLD failed: %s",
                        strerror(errno));
                return 1;
            }

            /* XXX: Check for SIGHUP and SIGTERM too to stay interactive? */
            while ((signum = sigtimedwait(&newsigs, &siginfo, &waittime)) == -1 && errno == EINTR)
                ;

            assert(signum == SIGCHLD || (signum == -1 && errno == EAGAIN));

            /* Remove signal handler for SIGCHLD */
            if (-1 == sigaction(SIGCHLD, &oldhandler, NULL)) {
                daemon_log(LOG_ERR, "Restoring old SIGCHLD handler failed: %s",
                        strerror(errno));
                return 1;
            }

            /* Restore old signal state */
            if (-1 == sigprocmask(SIG_SETMASK, &oldsigs, NULL)) {
                /* Only fails if SIG_SETMASK is invalid. Never happens ;) */
                daemon_log(LOG_WARNING, "Restoring signal state (sigprocmask(SIG_SETMASK, ...)) failed: %s",
                        strerror(errno));
            }

            if (signum == -1) {
                assert(errno == EAGAIN);
                /* errno could also be EINVAL if waittime is invalid, in which
                 * case we're stuffed anyway */

                daemon_log(LOG_ERR, "Child worker process took more than %ld seconds, gave up waiting",
                        waittime.tv_sec);
                continue;
            }

            /* SIGCHLD arrived. */

            while (((waitedpid = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR) || waitedpid != pid)
                ;

            if (waitedpid == -1) {
                daemon_log(LOG_ERR, "%s: Error waiting for child process to finish: %s",
                        __FUNCTION__, strerror(errno));
                continue;
            }

            assert(waitedpid == pid);

            if (pid > 0 && WIFEXITED(status) && WEXITSTATUS(status) == 0) {
                req.result = NATPMP_RESULT_SUCCESS;
            } else {
                if (pid == -1) {
                    daemon_log(LOG_WARNING, "%s: waitpid failed: %s (probably timed out)",
                            __FUNCTION__, strerror(errno));
                } else {
                    if (WIFEXITED(status))
                        daemon_log(LOG_ERR, "%s: Child exited with status %d",
                                __FUNCTION__, WEXITSTATUS(status));
                    else if (WIFSIGNALED(status))
                        daemon_log(LOG_ERR, "%s: Child exited due to signal %d",
                                __FUNCTION__, WTERMSIG(status));
                    else
                        daemon_log(LOG_ERR, "%s: Child exited, unknown cause",
                                __FUNCTION__);
                }
                req.result = NATPMP_RESULT_NO_RESOURCES;
            }

            if (send(sock, &req, sizeof(req), 0) < (ssize_t)sizeof(req))
                daemon_log(LOG_WARNING, "Failed sending IPC response");
        }
    }

    if (siz == -1) { /* FIXME: EINTR / EAGAIN? */
        daemon_log(LOG_ERR, "%s: Error receiving on IPC socket", __FUNCTION__);
        return 1;
    }
    else {
        assert(siz == 0);
        daemon_log(LOG_INFO, "%s: IPC socket closed, exiting.", __FUNCTION__);
    }

    return 0;
}
Example #4
0
int avahi_open_socket_ipv6(int no_reuse) {
    struct sockaddr_in6 sa, local;
    int fd = -1, yes, r;
    int ttl;

    mdns_mcast_group_ipv6(&sa);

    if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
        avahi_log_warn("socket() failed: %s", strerror(errno));
        goto fail;
    }

    ttl = 255;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
        avahi_log_warn("IPV6_MULTICAST_HOPS failed: %s", strerror(errno));
        goto fail;
    }

    ttl = 255;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
        avahi_log_warn("IPV6_UNICAST_HOPS failed: %s", strerror(errno));
        goto fail;
    }

    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_V6ONLY failed: %s", strerror(errno));
        goto fail;
    }

    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_MULTICAST_LOOP failed: %s", strerror(errno));
        goto fail;
    }

    memset(&local, 0, sizeof(local));
    local.sin6_family = AF_INET6;
    local.sin6_port = htons(AVAHI_MDNS_PORT);

    if (no_reuse)
        r = bind(fd, (struct sockaddr*) &local, sizeof(local));
    else
        r = bind_with_warn(fd, (struct sockaddr*) &local, sizeof(local));

    if (r < 0)
        goto fail;

    if (ipv6_pktinfo(fd) < 0)
        goto fail;

    if (avahi_set_cloexec(fd) < 0) {
        avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
        goto fail;
    }

    if (avahi_set_nonblock(fd) < 0) {
        avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
        goto fail;
    }

    return fd;

fail:
    if (fd >= 0)
        close(fd);

    return -1;
}
Example #5
0
int avahi_open_socket_ipv4(int no_reuse) {
    struct sockaddr_in local;
    int fd = -1, r, ittl;
    uint8_t ttl, cyes;

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        avahi_log_warn("socket() failed: %s", strerror(errno));
        goto fail;
    }

    ttl = 255;
    if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
        avahi_log_warn("IP_MULTICAST_TTL failed: %s", strerror(errno));
        goto fail;
    }

    ittl = 255;
    if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ittl, sizeof(ittl)) < 0) {
        avahi_log_warn("IP_TTL failed: %s", strerror(errno));
        goto fail;
    }

    cyes = 1;
    if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &cyes, sizeof(cyes)) < 0) {
        avahi_log_warn("IP_MULTICAST_LOOP failed: %s", strerror(errno));
        goto fail;
    }

    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(AVAHI_MDNS_PORT);

    if (no_reuse)
        r = bind(fd, (struct sockaddr*) &local, sizeof(local));
    else
        r = bind_with_warn(fd, (struct sockaddr*) &local, sizeof(local));

    if (r < 0)
        goto fail;

    if (ipv4_pktinfo (fd) < 0)
         goto fail;

    if (avahi_set_cloexec(fd) < 0) {
        avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
        goto fail;
    }

    if (avahi_set_nonblock(fd) < 0) {
        avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
        goto fail;
    }

    return fd;

fail:
    if (fd >= 0)
        close(fd);

    return -1;
}
Example #6
0
int avahi_open_socket_ipv4(int no_reuse,AvahiPublishProtocol proto) {
    struct sockaddr_in local;
    int fd = -1, r, ittl;
    uint8_t ttl, cyes;

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        avahi_log_warn("socket() failed: %s", strerror(errno));
        goto fail;
    }

	ttl = 255;
    if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
        avahi_log_warn("IP_MULTICAST_TTL failed: %s", strerror(errno));
        goto fail;
    }

    ittl = 255;
    if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ittl, sizeof(ittl)) < 0) {
        avahi_log_warn("IP_TTL failed: %s", strerror(errno));
        goto fail;
    }

    cyes = 1;
    if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &cyes, sizeof(cyes)) < 0) {
        avahi_log_warn("IP_MULTICAST_LOOP failed: %s", strerror(errno));
        goto fail;
    }

    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
/*
	Here we define only port of local structure because this 
	socket is used by AvahiServer and is used to join multicast 
	group. we pick the address further from local interface
	and joing the group.(ip_mreqn)
	avahi_mcast_join_ipv4()/6
*/
    local.sin_port = htons(proto == AVAHI_LLMNR ? AVAHI_LLMNR_PORT : AVAHI_MDNS_PORT);

    if (no_reuse)
        r = bind(fd, (struct sockaddr*) &local, sizeof(local));
    else
        r = bind_with_warn(fd, (struct sockaddr*) &local, sizeof(local));

    if (r < 0)
        goto fail;
/*
	Just set socket options on 'fd'. No header
	is passed.
*/
    if (ipv4_pktinfo (fd) < 0)
         goto fail;

    if (avahi_set_cloexec(fd) < 0) {
        avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
        goto fail;
    }

    if (avahi_set_nonblock(fd) < 0) {
        avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
        goto fail;
    }

    return fd;

fail:
    if (fd >= 0)
        close(fd);

    return -1;
}