Jump to content
Sign in to follow this  
Dave Nottage

Cannot bind an IPv6 address on macOS

Recommended Posts

I was originally using some Indy code, however I figured I strip back the code to the absolute basics in order to try and find out what is going wrong. This is the result:

uses
  Posix.SysSocket, Posix.NetinetIn, Posix.ArpaInet;

const
  // IPv6 address of en0 on my Mac
  cIPv6 = 'fe80::ca9:418d:c487:cba';
  cPort = 9099;

procedure TForm1.Button1Click(Sender: TObject);
var
  LHandle, LOption, LError: Integer;
  LSockAddrIPv6: sockaddr_in6;
  LNetAddrIPv6: in6_addr;
  LMarshaller: TMarshaller;
  LMsg: string;
begin
  LHandle := socket(AF_INET6, SOCK_DGRAM, 0);
  if LHandle > 0 then
  begin
    LOption := 1;
    if setsockopt(LHandle, SOL_SOCKET, SO_REUSEADDR, LOption, SizeOf(LOption)) = 0 then
    begin
      if inet_pton(AF_INET6, LMarshaller.AsAnsi(cIPv6).ToPointer, @LNetAddrIPv6) = 1 then
      begin
        FillChar(LSockAddrIPv6, SizeOf(LSockAddrIPv6), 0);
        LSockAddrIPv6.sin6_len := SizeOf(LSockAddrIPv6);
        LSockAddrIPv6.sin6_family := AF_INET6;
        LSockAddrIPv6.sin6_addr := LNetAddrIPv6;
        LSockAddrIPv6.sin6_port := htons(cPort);
        if bind(LHandle, PSockAddr(@LSockAddrIPv6)^, SizeOf(LSockAddrIPv6)) = -1 then
        begin
          LError := GetLastError;
          ShowMessage(SysErrorMessage(LError));
        end;
      end;
    end;
  end;
end;

The bind fails, however I'm yet to be able to ascertain why. The error code returned in LError is 49, which apparently equates to: "Can't assign requested address". 

 

Any ideas on what the problem might be? The same code also fails on iOS (using a valid IPv6 address), so is it perhaps an Apple thing?

Edited by Dave Nottage

Share this post


Link to post

I've finally discovered the problem: The sin6_scope_id member of LSockAddrIPv6 needed to be set to the index of the interface that has the address.

Share this post


Link to post
6 hours ago, Dave Nottage said:

I've finally discovered the problem: The sin6_scope_id member of LSockAddrIPv6 needed to be set to the index of the interface that has the address.

And what does that line look like?

  • Like 1

Share this post


Link to post
16 hours ago, Sherlock said:

And what does that line look like?

The simplified version (as per the example) would look like this:

LSockAddrIPv6.sin6_scope_id = 4;

Because the index of the interface in question is 4.

 

I've been working on some "home grown" (i.e. not Indy) code that includes retrieving the local addresses and interface indexes so that they can be used for this kind of thing (amongst others).

 

The purpose is to have a reliable, functional means of advertising that works on all platforms, using IPv4, IPv6 and works on IPv6 only networks. I've diverged from Indy because I was having to jump through too many hoops in order to make it all work, and to simplify everything.

 

I plan on publishing the code when it is complete.

  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×