Jump to content

    

Как установить новый ip-адрес интерфейса программно?

Здравствуйте!

 

Есть задача - установить новый ip-адрес интерфейса из работающей программы. Из консоли делается просто: "ifconfig eth0 inet 192.168.1.10".

Попробовал аналогично вызвать ifconfig из пользовательской программы:

 

int main(int argc, char* argv[], char* enpv[])
{
    pid_t num;
    int status;
    num = fork();
    if(num == 0)
    {
        execl("ifconfig", "eth0", "inet", "10.0.2.16");
    }
    else
    {
        wait(&status);
        printf("ending");
    }
    return 0;
}

 

Запускаю, проверяю - адрес не меняется. Что я делают не так? Запускаю эту программу под рутом.

Менять адрес через перезапись в файлах конфигурации - не хочу, т.к. у разных дистрибутивов эти файлы лежат в разных папках.

 

Заранее спасибо.

Share this post


Link to post
Share on other sites

зависит от того, чем управляются интерфейсы в системе в принципе. у разных дистрибутивов разные подходы, поэтому придётся адаптироваться.

Если в системе установлен пакет NetworkManager, то надо работать через него, вернее с ним через D-Bus. Потому как он может в любой момент изменить то что вы там наделали вручную без его ведома.

Если через скрипты, то либо дорабатывать скрипты, либо убирать их совсем и делать все дела самому.

 

в крайнем случае:

https://www.kernel.org/pub/linux/utils/net/...2-3.17.0.tar.gz

смотреть исходник ip/ipaddr.c

Share this post


Link to post
Share on other sites

смотрите как надо вызывать execl, там что то как то не все так просто т.к. при вызове main(int argc, char *argv[])

argv[0] указывает на первую символьную строку, которой всегда является имя программы; argv[1] указывает на первый аргумент и так далее.

а в execl присутвует path.

Share this post


Link to post
Share on other sites

struct sockaddr_in sin;
int s;

s = socket(AF_INET,SOCK_DGRAM,0); //temporary socket 

memset(&ifr, 0, sizeof(struct ifreq));
memset(&sin, 0, sizeof(struct sockaddr));
strncpy(ifr.ifr_name, iface, IF_NAMESIZE-1);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("192.168.0.123"); 

memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));

if(ioctl(s, SIOCSIFADDR, &ifr)< 0){ //set IP-Adress and check for errors
    close(s);
    perror("ioctl()");
    exit(1);
}

как-то так. Но это до первой перезагрузки, если init запускает стартовые скрипты.

Share this post


Link to post
Share on other sites

Добавлю, что установить (изменить) адрес интерфейса также можно через ioctl функцию SIOCSIFADDR.

Share this post


Link to post
Share on other sites

Спасибо за ответы. Несколько дней понадобилось, чтобы разобраться с ioctl.

 

Код - как у psL:

 

s = socket(AF_INET,SOCK_DGRAM,0); //temporary socket

memset(&ifr, 0, sizeof(struct ifreq));
memset(&sin, 0, sizeof(struct sockaddr));
strncpy(ifr.ifr_name, "eth0", IF_NAMESIZE-1);
sin.sin_family = AF_INET;

sin.sin_addr.s_addr = inet_addr("192.168.0.123");

memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));

if(ioctl(s, SIOCSIFADDR, &ifr)< 0) //set IP-Adress and check for errors
{ /*close(s);*/ }
close(s);

 

 

Но проблема в том, что опять ничего не работает. На машине Ubuntu все отлично работает: адрес меняется. Когда запускаю этот код в Angstrom - нифига не пашет. Вот что пишет ifconfig -a.

 

eth0      Link encap:Ethernet  HWaddr BC:6A:29:57:11:80
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

eth1      Link encap:Ethernet  HWaddr BC:6A:29:57:11:81
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

 

Запускаю из-под рута. Может разрешений не хватает ? Но ведь из sh - все задается.

Share this post


Link to post
Share on other sites
Запускаю из-под рута. Может разрешений не хватает ? Но ведь из sh - все задается.

А в программу вставить system (/path_to_script/changeIP.sh)?

Или нужно предварительно вызвать процессор? Я в linux'e не разбираюсь...

Share this post


Link to post
Share on other sites

Команда:

system("ifconfig eth0 10.0.5.20");

действительно позволила установить новый ip. Но во-первых: это странно, а во-вторых: мне кажется - это неправильно - использовать sh для работы прикладного ПО.

 

Если ничего не получится - буду так делать. Но может быть - есть еще какие-нибудь идеи: почему не работает ioctl?

Share this post


Link to post
Share on other sites
Но во-первых: это странно, а во-вторых: мне кажется - это неправильно - использовать sh для работы прикладного ПО.

Не хотите использовать стандартные подпрограммы (ifconfig) - пишите сами. Только, возможно это придется делать каждый раз для новой системы. А зачем тогда шелловский процессор нужен?

А если бы захотелось письмом извещать, - тоже бы стали для этого свою программу писать?

Share this post


Link to post
Share on other sites
действительно позволила установить новый ip. Но во-первых: это странно, а во-вторых: мне кажется - это неправильно - использовать sh для работы прикладного ПО.

Если ничего не получится - буду так делать. Но может быть - есть еще какие-нибудь идеи: почему не работает ioctl?

что мешало еще 30 ноября выудить пакет, содержащий исходники ifconfig (или другой утилиты, умеющей менять адрес) из любимого дистрибутива, и посмотреть как там это сделано?

зачем изобретать то, что давно надежно и качественно написано до вас?

это однокристаллочникам приходится барахтаться, прилаживая ДВС к изобретенному велосипеду..

Share this post


Link to post
Share on other sites
Но проблема в том, что опять ничего не работает.

Запускаю из-под рута. Может разрешений не хватает ?

В Вашем коде два системных вызова. Очевидно, один из них завершается ошибкой. Так обработайте должным образом эту ошибку и выведите ее на экран. Тогда и не придется гадать о том, чего программе не хватает. Хотя бы как-то так:

s = socket(...);
if(s < 0) {
  perror("socket");
  exit(1);
}
...
if(ioctl(...) < 0)
  perror("ioctl");

 

Share this post


Link to post
Share on other sites
Но проблема в том, что опять ничего не работает.

Посмотрите:

strace ifconfig eth0

 

Возможно нужно поднять интерфейс:

        ioctl(s, SIOCGIFFLAGS, &ifr);
        // флаги интерфейса
        ifr.ifr_flags |= IFF_UP | IFF_RUNNING;

        ioctl(s, SIOCSIFFLAGS, &ifr);
        close(s);

Share this post


Link to post
Share on other sites

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