GNU/Linux >> Belajar Linux >  >> Debian

Ruang Nama Linux

Latar Belakang

Mulai dari kernel 2.6.24, Linux mendukung 6 jenis ruang nama yang berbeda. Namespace berguna dalam menciptakan proses yang lebih terisolasi dari sistem lainnya, tanpa perlu menggunakan teknologi virtualisasi tingkat rendah penuh.

  • CLONE_NEWIPC:IPC Namespaces:SystemV IPC dan POSIX Message Queues dapat diisolasi.
  • CLONE_NEWPID:PID Namespaces:PID diisolasi, artinya PID virtual di dalam namespace dapat berkonflik dengan PID di luar namespace. PID di dalam namespace akan dipetakan ke PID lain di luar namespace. PID pertama di dalam namespace akan menjadi '1' yang di luar namespace ditetapkan ke init
  • CLONE_NEWNET:Ruang Nama Jaringan:Jaringan (/proc/net, IP, antarmuka, dan rute) diisolasi. Layanan dapat dijalankan pada port yang sama dalam ruang nama, dan antarmuka virtual "duplikat" dapat dibuat.
  • CLONE_NEWNS:Pasang Namespaces. Kami memiliki kemampuan untuk mengisolasi titik mount seperti yang terlihat pada proses. Dengan menggunakan ruang nama mount, kita dapat mencapai fungsionalitas yang mirip dengan chroot() namun dengan keamanan yang ditingkatkan.
  • CLONE_NEWUTS:Ruang Nama UTS. Tujuan utama ruang nama ini adalah untuk mengisolasi nama host dan nama NIS.
  • CLONE_NEWUSER:Ruang Nama Pengguna. Di sini, ID pengguna dan grup berbeda di dalam dan di luar ruang nama dan dapat diduplikasi.

Mari kita lihat dulu struktur program C, yang diperlukan untuk mendemonstrasikan ruang nama proses. Berikut ini telah diuji pada Debian 6 dan 7. Pertama, kita perlu mengalokasikan halaman memori pada stack, dan mengatur pointer ke akhir halaman memori tersebut. Kami menggunakan alloca untuk mengalokasikan memori tumpukan daripada malloc yang akan mengalokasikan memori di tumpukan.

void *mem = alloca(sysconf(_SC_PAGESIZE)) + sysconf(_SC_PAGESIZE);

Selanjutnya, kita menggunakan clone untuk membuat proses anak, meneruskan lokasi 'mem' tumpukan anak kita, serta flag yang diperlukan untuk menentukan namespace baru. Kami menetapkan 'callee' sebagai fungsi yang akan dijalankan dalam ruang anak:

mypid = clone(callee, mem, SIGCHLD | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_FILES, NULL);

Setelah memanggil clone, kita kemudian menunggu proses anak selesai, sebelum mengakhiri orang tua. Jika tidak, alur eksekusi induk akan berlanjut dan berhenti segera setelahnya, menyelesaikan turunan dengannya:

while (waitpid(mypid, &r, 0) < 0 && errno == EINTR)
{
	continue;
}

Terakhir, kita akan kembali ke shell dengan kode keluar dari anak:

if (WIFEXITED(r))
{
	return WEXITSTATUS(r);
}
return EXIT_FAILURE;

Sekarang, mari kita lihat fungsi callee:

static int callee()
{
	int ret;
	mount("proc", "/proc", "proc", 0, "");
	setgid(u);
	setgroups(0, NULL);
	setuid(u);
	ret = execl("/bin/bash", "/bin/bash", NULL);
	return ret;
}

Di sini, kita memasang sistem file /proc, dan kemudian mengatur uid (User ID) dan gid (Group ID) ke nilai 'u' sebelum memunculkan /bin/bash shell. LXC adalah alat virtualisasi tingkat OS yang memanfaatkan cgroup dan ruang nama untuk isolasi sumber daya. Mari kita gabungkan semuanya, setel 'u' ke 65534 yang merupakan pengguna "nobody" dan grup "nogroup" di Debian:

#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <grp.h>
#include <alloca.h>
#include <errno.h>
#include <sched.h>
static int callee();
const int u = 65534;
int main(int argc, char *argv[])
{
	int r;
	pid_t mypid;
	void *mem = alloca(sysconf(_SC_PAGESIZE)) + sysconf(_SC_PAGESIZE);
	mypid = clone(callee, mem, SIGCHLD | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_FILES, NULL);
	while (waitpid(mypid, &r, 0) < 0 && errno == EINTR)
	{
		continue;
	}
	if (WIFEXITED(r))
	{
		return WEXITSTATUS(r);
	}
	return EXIT_FAILURE;
}
static int callee()
{
	int ret;
	mount("proc", "/proc", "proc", 0, "");
	setgid(u);
	setgroups(0, NULL);
	setuid(u);
	ret = execl("/bin/bash", "/bin/bash", NULL);
	return ret;
}

Untuk mengeksekusi kode menghasilkan sebagai berikut:

[email protected]:~/pen/tmp# gcc -O -o ns.c -Wall -Werror -ansi -c89 ns.c
[email protected]:~/pen/tmp# ./ns
[email protected]:~/pen/tmp$ id
uid=65534(nobody) gid=65534(nogroup)
[email protected]:~/pen/tmp$ ps auxw
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
nobody       1  0.0  0.0   4620  1816 pts/1    S    21:21   0:00 /bin/bash
nobody       5  0.0  0.0   2784  1064 pts/1    R+   21:21   0:00 ps auxw
[email protected]:~/pen/tmp$ 

Perhatikan bahwa UID dan GID disetel ke none dan nogroup. Secara khusus perhatikan bahwa output ps penuh hanya menunjukkan dua proses yang berjalan dan bahwa PID-nya masing-masing adalah 1 dan 5. Sekarang, mari kita beralih menggunakan ip netns untuk bekerja dengan ruang nama jaringan. Pertama, konfirmasikan bahwa tidak ada ruang nama saat ini:

[email protected]:~# ip netns list
Object "netns" is unknown, try "ip help".

Dalam hal ini, baik ip perlu dimutakhirkan, atau kernel membutuhkannya. Dengan asumsi Anda memiliki kernel yang lebih baru dari 2.6.24, kemungkinan besar itu adalah ip. Setelah memutakhirkan, daftar ip netns seharusnya secara default tidak mengembalikan apa pun. Mari tambahkan namespace baru bernama 'ns1':

[email protected]:~# ip netns add ns1
[email protected]:~# ip netns list
ns1

Pertama, mari buat daftar antarmuka saat ini:

[email protected]:~# ip link list
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0:  mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 1000
    link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff

Sekarang untuk membuat antarmuka virtual baru, dan menambahkannya ke namespace baru kami. Antarmuka virtual dibuat berpasangan, dan dihubungkan satu sama lain - bayangkan kabel crossover virtual:

[email protected]:~# ip link add veth0 type veth peer name veth1
[email protected]:~# ip link list
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0:  mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 1000
    link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff
3: veth1:  mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether d2:e9:52:18:19:ab brd ff:ff:ff:ff:ff:ff
4: veth0:  mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether f2:f7:5e:e2:22:ac brd ff:ff:ff:ff:ff:ff
ifconfig -a sekarang juga akan menampilkan penambahan veth0 dan veth1.

Bagus, sekarang untuk menetapkan antarmuka baru kami ke namespace. Perhatikan bahwa ip netns exec digunakan untuk menjalankan perintah di dalam namespace:

[email protected]:~# ip link set veth1 netns ns1
[email protected]:~# ip netns exec ns1 ip link list
1: lo:  mtu 65536 qdisc noop state DOWN mode DEFAULT 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: veth1:  mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether d2:e9:52:18:19:ab brd ff:ff:ff:ff:ff:ff
ifconfig -a sekarang hanya akan menampilkan veth0, karena veth1 ada di namespace ns1.

Haruskah kita ingin menghapus veth0/veth1:

ip netns exec ns1 ip link del veth1

Kami sekarang dapat menetapkan alamat IP 192.168.5.5/24 ke veth0 di host kami:

ifconfig veth0 192.168.5.5/24

Dan tetapkan veth1 192.168.5.10/24 dalam ns1:

ip netns exec ns1 ifconfig veth1 192.168.5.10/24 up

Untuk menjalankan daftar ip addr di host kami dan di dalam namespace kami:

[email protected]:~# ip addr list
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0:  mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
    link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff
    inet 192.168.3.122/24 brd 192.168.3.255 scope global eth0
    inet6 fe80::20c:29ff:fe65:259e/64 scope link 
       valid_lft forever preferred_lft forever
6: veth0:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 86:b2:c7:bd:c9:11 brd ff:ff:ff:ff:ff:ff
    inet 192.168.5.5/24 brd 192.168.5.255 scope global veth0
    inet6 fe80::84b2:c7ff:febd:c911/64 scope link 
       valid_lft forever preferred_lft forever
[email protected]:~# ip netns exec ns1 ip addr list
1: lo:  mtu 65536 qdisc noop state DOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 12:bd:b6:76:a6:eb brd ff:ff:ff:ff:ff:ff
    inet 192.168.5.10/24 brd 192.168.5.255 scope global veth1
    inet6 fe80::10bd:b6ff:fe76:a6eb/64 scope link 
       valid_lft forever preferred_lft forever

Untuk melihat tabel perutean di dalam dan di luar namespace:

[email protected]:~# ip route list
default via 192.168.3.1 dev eth0  proto static 
192.168.3.0/24 dev eth0  proto kernel  scope link  src 192.168.3.122 
192.168.5.0/24 dev veth0  proto kernel  scope link  src 192.168.5.5 
[email protected]:~# ip netns exec ns1 ip route list
192.168.5.0/24 dev veth1  proto kernel  scope link  src 192.168.5.10 

Terakhir, untuk menghubungkan antarmuka fisik dan virtual, kita memerlukan jembatan. Mari kita bridge eth0 dan veth0 pada host, lalu gunakan DHCP untuk mendapatkan IP dalam namespace ns1:

[email protected]:~# brctl addbr br0
[email protected]:~# brctl addif br0 eth0
[email protected]:~# brctl addif br0 veth0
[email protected]:~# ifconfig eth0 0.0.0.0
[email protected]:~# ifconfig veth0 0.0.0.0
[email protected]:~# dhclient br0
[email protected]:~# ip addr list br0
7: br0:  mtu 1500 qdisc noqueue state UP 
    link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff
    inet 192.168.3.122/24 brd 192.168.3.255 scope global br0
    inet6 fe80::20c:29ff:fe65:259e/64 scope link 
       valid_lft forever preferred_lft forever

br0 telah diberi IP 192.168.3.122/24. Sekarang untuk namespace:

[email protected]:~# ip netns exec ns1 dhclient veth1
[email protected]:~# ip netns exec ns1 ip addr list
1: lo:  mtu 65536 qdisc noop state DOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 12:bd:b6:76:a6:eb brd ff:ff:ff:ff:ff:ff
    inet 192.168.3.248/24 brd 192.168.3.255 scope global veth1
    inet6 fe80::10bd:b6ff:fe76:a6eb/64 scope link 
       valid_lft forever preferred_lft forever

Bagus sekali! veth1 telah ditetapkan 192.168.3.248/24

IO Digital Sec
Konsultan Linux


Debian
  1. Demystifying namespace dan container di Linux

  2. 7 namespace Linux yang paling banyak digunakan

  3. Lihat/manipulasi mount ruang nama di Linux

  1. Bagaimana Melakukan Chroot Dengan Ruang Nama Linux?

  2. Linux – Kernel:Dukungan Namespaces?

  3. Linux – Bagaimana Cara Mendaftar Namespace Di Linux?

  1. Perintah mv Linux

  2. Linux du perintah

  3. Perintah ip Linux