And from the man page of netintro:
-------------------------------------------------------------------------------
SIOCDIFADDR: [sniped]
and also adopts the convention that specification of the
default address means to delete the first address for the
interface belonging to the address family in which the
original socket was opened.
-------------------------------------------------------------------------------
I can specify an specific IP, say, "192.168.0.2", for SIOCDIFADDR to delete.
But how can i specify this "default address"(said in the netintor(4)) to
"delete the first address of the interface"?
Thanks in advance.
--
Leslie Jackson
To Unsubscribe: send mail to majo...@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message
Try 0.0.0.0. (aka INADDR_ANY).
BMS
> On Mon, Sep 16, 2002 at 11:43:15AM +0800, Leslie Jackson wrote:
> > I can specify an specific IP, say, "192.168.0.2", for SIOCDIFADDR to
> > delete. But how can i specify this "default address"(said in the
> > netintor(4)) to"delete the first address of the interface"?
>
> Try 0.0.0.0. (aka INADDR_ANY).
>
> BMS
Failed using that way. (SIOCDIFADDR: can't assign requested addressed)
The following is the simple code:
/*
* Delete an IP address of lo0
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
int main(void)
{
int s;
struct ifaliasreq ifaliasreq;
struct sockaddr_in *in;
s = socket(PF_INET, SOCK_STREAM, 0);
memset(&ifaliasreq, 0, sizeof(ifaliasreq));
strncpy(ifaliasreq.ifra_name, "lo0", sizeof(ifaliasreq.ifra_name));
in = (struct sockaddr_in *) &ifaliasreq.ifra_addr;
in->sin_family = AF_INET;
in->sin_len = sizeof(ifaliasreq.ifra_addr);
/*
* if i use "0.0.0.0" or INADDR_ANY", i'd get this error:
* SIOCDIFADDR: can't assign requested addressed
*
* in->sin_addr.s_addr = htonl(INADDR_ANY);
* in->sin_addr.s_addr = inet_addr("0.0.0.0");
*/
/* okay if using a specific IP */
in->sin_addr.s_addr = inet_addr("127.0.0.1");
if (ioctl(s, SIOCDIFADDR, &ifaliasreq) == -1)
perror("SIOCDIFADDR");
return (0);
}
Something missed or wrong?
Thanks for any insights.
--
Leslie Jackson
Hello,
You can try to request the first address of the specified interface via
ioctl call.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
/*
* retrieve the FIRST address of the specified interface
* you may want to directly merge it with your code.
*/
in_addr_t get_ifaddr(char *ifname)
{
int s;
struct ifreq ifs;
ifs.ifr_addr.sa_family = AF_INET;
s = socket(ifs.ifr_addr.sa_family, SOCK_DGRAM, 0);
if( s < 0 ) {
perror("get_ifaddr(): socket()");
exit(1);
}
strncpy(ifs.ifr_name, ifname, sizeof(ifs.ifr_name));
if( ioctl(s, OSIOCGIFADDR, &ifs) == -1 ) {
perror("get_ifaddr(): ioctl()");
exit(1);
}
close(s);
return ((struct sockaddr_in *)&(ifs.ifr_addr))->sin_addr.s_addr;
}
/* your code */
int main(int argc, char *argv[])
{
int s;
struct ifaliasreq ifaliasreq;
struct sockaddr_in *in;
if( argc != 2 ) {
fprintf(stderr, "%s ifname\n", argv[0]);
return 1;
}
s = socket(PF_INET, SOCK_STREAM, 0);
if( s == -1 ) {
perror("socket()");
return 1;
}
memset(&ifaliasreq, 0, sizeof(ifaliasreq));
strncpy(ifaliasreq.ifra_name, argv[1], sizeof(ifaliasreq.ifra_name));
in = (struct sockaddr_in *) &ifaliasreq.ifra_addr;
in->sin_family = AF_INET;
in->sin_len = sizeof(ifaliasreq.ifra_addr);
/*
* let get_ifaddr() find the address of the interface
*/
in->sin_addr.s_addr = get_ifaddr(ifaliasreq.ifra_name);
if( ioctl(s, SIOCDIFADDR, &ifaliasreq) == -1 ) {
perror("SIOCDIFADDR");
return 1;
}
return 0;
}
bash-2.05# ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
inet6 fe80::250:fcff:fe22:dc01%rl0 prefixlen 64 scopeid 0x1
inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255
inet 192.168.0.10 netmask 0xffffffff broadcast 192.168.0.10
inet 192.168.0.11 netmask 0xffffffff broadcast 192.168.0.11
ether 00:50:fc:22:dc:01
media: Ethernet 10baseT/UTP
status: no carrier
bash-2.05# ./test rl0
bash-2.05# ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
inet6 fe80::250:fcff:fe22:dc01%rl0 prefixlen 64 scopeid 0x1
inet 192.168.0.10 netmask 0xffffffff broadcast 192.168.0.10
inet 192.168.0.11 netmask 0xffffffff broadcast 192.168.0.11
ether 00:50:fc:22:dc:01
media: Ethernet 10baseT/UTP
status: no carrier
the first rl0 address (192.168.0.1) has been removed.
My bad... a hasty answer to a hastily read question.
Quick answer:- man 4 networking.
Long answer:-
Your best option is probably to issue an SIOCGIFCONF and walk the list. This
should give you the default addresses assigned to each interface. If you need
to look at aliases, use SIOCAIFCONF for the interface you're interested in.
Look at netinet/in.c:in_control(). SIOCSIFADDR is now deprecated, so in a
way you were right to watch what ifconfig was doing. If you need code examples,
have a look in /usr/ports/mbone as some programs which need to determine
multicast capabilities of each configured interface will have to walk the
ifreq/ifconf list.
You'll need to play an elastic buffer game where you specify the size of
the chunk of memory you've allocated for the ifconf array, and if it's
bigger, reallocate it and ask again.
Also if portability is an issue note that Solaris and Linux do it slightly
differently now. We haven't picked up that change yet (...scribbles in TODO
list..) but what it boils down to is this:- instead of playing elastic buffer
games to get the size of the list, you just ask how big the list is.
BMS
> You can try to request the first address of the specified interface via
> ioctl call.
>
> [snip]
> /*
> * let get_ifaddr() find the address of the interface
> */
> in->sin_addr.s_addr = get_ifaddr(ifaliasreq.ifra_name);
> [snip]
Thanks for your sample code.
I've thought of this method. But from 'ktrace'ing ifconfig, i found it never
issued the SIOCGIFADDR request using ioctl().
And actually, there's _really_ somthing i've missed.
I just ktrace'd again, finding that ifconfig just first uses sysctl() with
NET_RT_IFLIST to abtain the whole interface list.
This is what ifconfig does when changing an IP:
1. call sysctl() to obtain the whole interface list.
2. do some needed work.
(ie. get the FIRST IP of the interface from the interface list)
3. issue SIOCDIFADDR request by calling ioctl() to delete the FIRST IP.
4. issue SIOCAIFADDR request by calling ioctl() to assign the new IP.
Now my mind's clear. :-)
Thanks any way, for your help.
--
Leslie Jackson
Cross-platform network manipulation.
-Nate