1

Here is a piece of code snippet from tftp

void initsock(int af) {
    struct sockaddr_storage s_in;

    if (f >= 0)
        close(f);

    f = socket(af, SOCK_DGRAM, 0);
    if (f < 0) {
        perror("tftp: socket");
        exit(3);
    }
    printf("protocol family: %d\n", af);

    memset(&s_in, 0, sizeof(s_in));
    s_in.ss_family = af;
    if (bind(f, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) {
        perror("tftp: bind");
        exit(1);
    }
    char ip_str[INET6_ADDRSTRLEN] = {0};

    inet_ntop(s_in.ss_family, get_in_addr((struct sockaddr *)&s_in), ip_str, sizeof ip_str);
    printf("ip address: %s\t port: %d\n", ip_str, get_in_port((struct sockaddr *)&s_in));
}

My question is that why bind() is called here? What's the purpose? The second argument seems empty except for ss_family field, no ip address nor port number.

p.s. Source code from https://packages.ubuntu.com/bionic/tftp

HQW.ang
  • 119
  • 8
  • What implementation of TFTP is this snippet from? Can you post a link to the repository? – Arkadiusz Drabczyk Aug 22 '21 at 11:10
  • Looks like it's used to bind to either IPv4 or IPv6 using the "ANY` address and an ephemeral port. So basically it's to select the IP version to use. – kaylum Aug 22 '21 at 11:39

1 Answers1

0

bind() in this example uses INADDR_ANY as an address what means that it binds to all available interfaces and port 0 that man 2 bind refers to as an ephemeral port what means that it lets operating system choose free port to use. You can add the following snippet at the end of this function and use getsockname() to get the number port number chosen by OS:

    struct sockaddr_in sa;
    socklen_t addrlen = sizeof(sa);

    if (getsockname(f, (struct sockaddr *) &sa, &addrlen) == -1) {
      perror("getsockname()");
    }

    printf("Local IP address is: %s\n", inet_ntoa(sa.sin_addr));
    printf("Local port is: %d\n", (int) ntohs(sa.sin_port));
Arkadiusz Drabczyk
  • 11,227
  • 2
  • 25
  • 38
  • Thanks. The ephemeral port appears in ERRORS section, which is overlooked when I read. Now I know the functionality of bind() here, but still the purpose is unclear. I mean the interface and port number can be chosen when calling sendto(). So why bother here. The port number is not used by the client since I search and find no getsockname result if that is a common way to get the port number. – HQW.ang Aug 22 '21 at 12:35
  • I downloaded http://archive.ubuntu.com/ubuntu/pool/universe/n/netkit-tftp/netkit-tftp_0.17.orig.tar.gz but there is no function called `initsock()`. So let me ask again - where does this snippet in your question come from? – Arkadiusz Drabczyk Aug 22 '21 at 12:45
  • @ArkadiuszDrabczyk: Apparently comes from ubuntu patches applied to the source, http://archive.ubuntu.com/ubuntu/pool/universe/n/netkit-tftp/netkit-tftp_0.17-18ubuntu3.diff.gz – Hasturkun Aug 22 '21 at 15:19
  • @ArkadiuszDrabczyk As Hasturkun remarked, it's from the patche added to orig by ubuntu. Actually, I didn't even notice that, since I downloaded using apt-get source. Forgive me for my carelessness. After applying the patch, it's located in tftp/main.c – HQW.ang Aug 22 '21 at 15:42
  • @ArkadiuszDrabczyk "*You can ... use `getsockname()` to get the number port number chosen by OS*" - which is likely what the calls to `get_in_addr()` and `get_in_port()` are actually doing internally, prior to the `printf()` after `bind()`. – Remy Lebeau Aug 23 '21 at 20:48
  • @RemyLebeau: possibly but I couldn't find a definition of `get_in_port()` anywhere in the linked tarball. – Arkadiusz Drabczyk Aug 23 '21 at 21:10
  • `get_in_addr()` and `get_in_port()` are both added by myself as helper functions to inspect the code. They cannot achieve the same functionality as `getsockname()` does, since they merely extract information from `struct sockaddr`. For example, `return ntohs((struct sockaddr_in*)sa->sin_port);` – HQW.ang Oct 11 '21 at 01:50