서로 다른 host들은 ethernet 네트워크에 연결을 위해 각자의 network interface 카드(NIC)를 사용한다. 이 NIC는 스위치에 연결되어 같은 네트워크를 이루는 것이다.
---A--- ---B---
| | ---------- | |
| eth0 ---| Switch | --- eth0 |
| | ---------- | |
------- (192.168.1.0) -------
자신의 ethernet을 보기위해서는 ip link
를 쓰면 된다.
ip link
eth0: ...
switch가 192.168.1.0
이라는 IP network를 가지고 있기 때문에, host A와 host B는 다음과 같이 IP를 할당 받을 수 있다.
ip addr add 192.168.1.10/24 dev eth0
ip addr add 192.168.1.11/24 dev eth0
이렇게 ethernet network에 IP가 할당되면 ping을 통해서 IP를 확인할 수 있다. ping이 전달된다는 것은 이들끼리 같은 network에 있다는 것을 의미하는 것이다.
ping 192.168.1.11
Reply from 192.168.1.11: bytes=32 time=4ms TTl=117
...
그런데 host C, host D는 다른 IP 대역을 가진 네트워크에 있다고 하자.
---A--- ---B---
| | ---------- | |
| eth0 ---| Switch | --- eth0 |
| | ---------- | |
------- (192.168.1.0) -------
---C--- ---D---
| | ---------- | |
| eth0 ---| Switch | --- eth0 |
| | ---------- | |
------- (192.168.2.0) -------
어떻게 서로 다른 이들 간의 network를 연결시킬 수 있는가?? 여기서 바로 router의 개념이 등장한다. router를 통해서 이들을 하나로 연결시킬 수 있는데, 다음과 같다.
---A--- ---B---
| | ---------- | |
| eth0 ---| Switch | --- eth0 |
| | ---------- | |
------- (192.168.1.0) -------
|
|
|
---Router---
| |
------------
|
|
---C--- | ---D---
| | ---------- | |
| eth0 ---| Switch | --- eth0 |
| | ---------- | |
------- (192.168.2.0) -------
router는 서로 다른 network를 연결해야하기 때문에, 각 network마다의 IP를 가져야 식별이 가능하다.
---A--- ---B---
| | ---------- | |
| eth0 ---| Switch | --- eth0 |
| | ---------- | |
------- (192.168.1.0) -------
|
|
|
(192.168.1.1)
---Router---
| |
------------
(192.168.2.1)
|
|
---C--- | ---D---
| | ---------- | |
| eth0 ---| Switch | --- eth0 |
| | ---------- | |
------- (192.168.2.0) -------
이제 서로 다른 두 network가 연결된 것을 볼 수 있다. router는 서로 다른 network를 연결해주는 gateway가 된 것이다.
그런데, 어떻게 router가 host B로 부터 온 packet을 host C로 전달할 수 있을까?? 이를 위해서는 몇 가지 설정이 필요하다. 즉, router에게 host C에 대한 IP 정보를 설정해주는 것이 필요하는 것이다. 이를 routing table을 만든다고 한다.
router의 설정을 볼 수 있는 명령어는 다음과 같다.
route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
이제 host B가 host C, D에 속한 network에 packet을 전달할 수 있도록 routing table을 설정해주어야 한다.
ip route add 192.168.2.0/24 via 192.168.1.1
route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.2.0 192.168.1.1 255.255.255.0 UG 0 0 0 eth0
이렇게 설정하면 router입장에서 192.168.1.1
gateway에 들어온 packet을 연결된 19.168.2.0
switch로 전달할 수 있다. 즉, host B가 host C의 192.168.2.10
에 packet을 보내면 packet이 192.168.1.1
을 지나고, router는 192.168.2.10
을 보고 192.168.2.0
switch로 packet을 보내는 것이다. switch는 192.168.2.10
을 보고 host C로 packet을 전달하는 것이다.
반대로 host C에서 host B로 packet을 보내기 위해서도 설정을 해주어야 한다.
ip route add 192.168.1.0/24 via 192.168.2.1
그런데, 수많은 사이트들이 IP를 가지고 있고, 수많은 router들이 있을 것이다. 이들을 routing table로 하나하나 만드는 것은 불가능에 가깝다. 그래서 default gateway를 만드는 것이다.
ip route add default via 192.168.2.1
이제 host C, D가 보내는 packet 중에 routing table에 맞지 않으면 default gateway로 전달되는 것이다.
route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.2.1 0.0.0.0 UG 0 0 0 eth0
default
대신에 0.0.0.0
이라고 써도 된다.
그런데, 만약 host C에서 host D로 packet을 보낸다고 한다면 사실 router를 거칠 필요가 없다. 때문에 router에 gateway로 0.0.0.0
으로 넣을 수 있다.
route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.2.0 0.0.0.0 255.255.255.0 UG 0 0 0 eth0
다음과 같이 192.168.2.0
switch안에서의 network는 gateway를 거치지 않아도 되므로 0.0.0.0으로 설정한다.
만약 다음과 같이 host C, D의 switch가 public internet router와 하나 더 연결될 때는 어떻게 route table을 설정할 수 있을까??
---A--- ---B---
| | ---------- | |
| eth0 ---| Switch | --- eth0 |
| | ---------- | |
------- (192.168.1.0) -------
|
|
|
(192.168.1.1)
---Router--- ---Router---
| | | |---->Internet
------------ ------------
(192.168.2.2) (192.168.2.1)
| |
| |
|----------------
|
---C--- | ---D---
| | ---------- | |
| eth0 ---| Switch | --- eth0 |
| | ---------- | |
------- (192.168.2.0) -------
이 경우 host C, host D의 경우 다음과 같이 routing table을 설정해야한다.
route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.2.1 0.0.0.0 UG 0 0 0 eth0
192.168.1.0 192.168.2.2 255.255.255.0 UG 0 0 0 eth0
192.168.1.0
로 향하는 network packet은 192.168.2.2
router gateway를 지나도록 하는 것이다. 그리고 나머지에 대해서는 192.168.2.1
router gateway를 지나도록 하여, internet에 접속하도록 하는 것이다.
재밌는 것은 host를 통해서도 router를 구현할 수 있는데 다음과 같다.
--A-- ---B--- --C--
| | | | | |
| eth0--(192.168.1.0)--eth0 eth1--(192.168.2.0)--eth0 |
| | | | | |
----- ------- -----
eth0: 192.168.1.5 eth0: 192.168.1.6 eth0: 192.168.2.5
eth1: 192.168.2.6
어떻게 host A가 host C에 packet을 보낼 수 있을까?? host B를 통해서 가능하다.
host A에 다음과 같이 ip route를 추가하도록 한다.
ip route add 192.168.2.0/24 via 192.168.1.6
192.168.2.0/24
는 host C에 대한 network인데, 이 packet이 오는 경우 host B의 192.168.1.6
ethernet에 바로 보내도록 하는 것이다.
반대로 host C 역시도 마찬가지인 것이다.
ip route add 192.168.1.0/24 via 192.168.2.6
이제 host A에서 host C로 전달하기 위해서 ping
을 써보자.
ping 192.168.2.5
그런데 아무것도 출력되지 않는 것을 볼 수 있을 것이다. 이는 host B로 전달되었지만, host C로 가지 않았다는 것이다. 즉, host B가 packet을 drop한 것이다. 왜일까?? 이는 security를 위한 것인데, host B의 eth0와 eth1이 서로 자동으로 연결되지 않는다. 왜냐하면 만약 eth0가 private network에 연결되고, eth1은 public network에 연결되어 있다면 private network에서 전달된 packet이 함부로 public network로 포워딩되기 때문이다.
따라서, 하나의 host안에서 ethernet interface끼리의 packet을 서로 주고 받게하기 위해서는 포워딩 정책을 켜주는 수 밖에 없다.
cat /proc/sys/net/ipv4/ip_forward
0
이 값이 0이라면 forward가 지원되지 않는다는 것이다. 1로 바꿔주면 되는데, reboot 후에도 지속적으로 적용되는 설정을 하고 싶다면, 다음과 같이 /etc/sysctl.conf
를 바꿔주면 된다.
net.ipv4.ip_forward = 1
다음의 host A, host B가 있다고 하자. host B는 DB로서 동작하는 것이다.
db
--A-- ---B---
| | | |
| eth0--(192.168.1.0)--eth0 |
| | | |
----- -------
eth0: 192.168.1.10 eth0: 192.168.1.11
host A, B 둘 다 192.168.1.0
network 대역에 연결되어 있으므로 IP를 통한 통신이 가능하다. host A 입장에서 host B를 db로 사용해야하는데, 고정된 이름으로 호출하고 싶다. 가령 db
로 말이다.
ping db
ping: unknown host db
다음과 같이 ping에 실패하고 말 것이다. 왜냐하면 db에 대한 IP를 모르기 때문이다.
이를 위해서 linux에서는 dns service를 제공하는데, /etc/hosts
를 수정하면 된다.
vi /etc/hosts
192.168.1.11 db
이제 db
에 ping을 보내면 성공할 것이다.
ping db
참고로 이 db
라는 이름은 host name과는 다르다. 따라서 host B의 이름이 host-2
라도 host A에서는 상관없이 db
로 접근이 가능한 것이다.
이제 ssh db
로도 접속이 가능한 것이다.
그런데 문제는 이러한 DNS rule이 너무 많아짐에 따라, 하나하나 host에 DNS rule을 추가해주기 어렵다는 것이다. 따라서, 중앙화된 DNS server를 하나 두는 것이 좋은데, 이것이 바로 DNS server이다.
N개의 host가 있다면 N개 모두 /etc/hosts
를 수정하여 모든 DNS rule을 추가하는 것이 아니라, DNS server를 보도록 하는 것이다.
그럼 어떻게 DNS server를 host에 pointing시킬 수 있는가??
--A-- --DNS--
| | | |
| eth0--(192.168.1.0)--eth0 |
| | | |
----- -------
192.168.1.10 192.168.1.100
DNS
서버의 /etc/hosts
에 dns rule들이 모두 적용되어 있다고 하자. 이제 host A가 DNS server를 어떻게 참조하여 DNS로 IP를 얻어올 수 있는가?? 이는 /etc/resolv.conf
를 수정하면 된다.
cat /etc/resolv.conf
nameserver 192.168.1.100
다음과 같이 /etc/resolv.conf
파일에 nameserver
에 대한 IP를 제공하도록 수정해놓으면 된다.
물론, DNS server를 쓴다해서 직접 DNS rule을 추가하는 것이 불가능한 것은 아니다. /etc/hosts
를 통해서도 단일 dns record를 추가할 수 있다.
그런데 만약 DNS server와 /etc/hosts
가 서로 다른 IP값을 가진다면 어떻게 할까?
TEST(192.168.1.115)
| |
| |
-----
|
--A-- | --DNS--
| | | | |
| eth0--(192.168.1.0)--eth0 |
| | | |
----- -------
192.168.1.10 192.168.1.100
host A의 /etc/hosts
는 다음과 같다고 하자.
192.168.1.115 test
반면 DNS server의 경우는 다음과 같다고 하자.
192.168.1.116 test
사실 local DNS rule이 먼저 적용되고 DNS server의 rule이 적용된다. 따라서, /etc/hosts
에서 test
를 확인했으니 192.168.1.115
가 된다.
만약 이 순서를 바꾸고 싶다면 /etc/nsswitch.conf
를 바꾸면 된다.
...
hosts: files dns
...
files
가 먼저 설정된 것을 볼 수 있다. 즉, local file을 먼저보고 DNS server를 본다는 것이다.
그런데, 여기서 궁금한 것이 수 많은 host 이름들이 있을 것이다. goole, facebook, naver 등등이 있는데, 이들을 어떻게 하나하나 DNS server에서 설정해주냐는 것이다.
이를 위해서 제공되는 것이 바로 well-known public name server이다. 이는 8.8.8.8
로 시작하며, 다음과 같이 설정되어 있을 것이다.
cat /etc/resolv.conf
...
nameserver 8.8.8.8
nameserver 192.168.1.100
8.8.8.8
이 바로 모든 website에 대한 DNS server 역할을 하는 것이다. 따라서, 이 설정을 지우면 public service들에 대한 요청이 전달되지 않는다.
가령, www.goole.com
으로 요청을 보내도 전달되지 않는 것이다.
이렇게 www.google.com
과 같은 것들을 domain names라고 하는데, .
을 기준으로 그룹화되어 있다. 재밌는 것은 domain name들은 뒤부터 그룹화 된다는 것인데,
www.google.com
위의 경우 그룹핑이 된 것이 다음과 같다.
------com------
| |
| --google-- |
| | www ||
| ---------- |
| |
----------------
즉, 최상위는 .com
, 그 다음이 google
그 다음이 www
이다.
만약 goole내의 app, mail, drive, maps와 같은 서비스가 있다면, 다음과 같이 나줄 수 있다.
Root: .
Top level Domain Name: .com
google
subdomain mail, drive, www, maps, app
...
이렇게 계층화되는 것이다.
만약, apps.google.com
으로 요청으로 보내면 먼저, 먼저 회사의 org DNS
를 거친다음 root DNS
로 보내고, .com DNS
로 보낸다. 다음으로 google
인 것을 확인하고 google DNS
로 보낸다. 이제 google DNS내부에서 apps
DNS를 찾아 IP를 전달하는 것이다.
그렇게해서 216.58.221.78
이라는 IP를 알아내면 회사의 org DNS
로 전달되고 lorg DNS
에서는 해당 DNS에 대해서 몇 분간 캐싱을 하게된다.
이는 public network의 domain인 경우이다. 그렇다면 organization의 경우는 어떻게 될까?? 비슷하게 동작한다.
org DNS
에서 요청된 domain을 분석한다.
Root org DNS
doamin mycompany.com
sub domain mail. drive, www, pay, hr
즉, org DNS
에서 다음과 같이 rule을 설정하는 것이다.
192.168.1.10 web.mycompany.com
192.168.1.11 db.mycompany.com
192.168.1.12 nfs.mycompany.com
192.168.1.13 web-1.mycompany.com
192.168.1.14 sql.mycompancy.com
다음으로 해당 org DNS를 사용하는 host들은 org DNS에 대한 nameserver를 등록해야한다.
cat /etc/resolv.conf
nameserver 192.168.1.100
이제 ping을 보내보면 성공한다.
ping web.mycompany.com
그런데 web
으로만 ping을 보내면 실패하고 말 것이다. 만약, subdomain인 web
으로만 보내도 ping이 성공하게끔 하고 싶다면 다음과 같이 /etc/resolv.conf
에 search
를 설정해주면 된다.
cat /etc/resolv.conf
nameserver 192.168.1.100
search mycompany.com prod.mycompany.com
ping web
으로 보내면 mycompany.com
이라는 top level domain에서 해당 sub domain이 있는 지 확인하는 것이다. 즉 web.mycompany.com
을 찾아보는 것이다 . 만약 없다면 web.prod.mycompany.com
에도 요청을 보내보는 것이다.
이렇게 /etc/resolv.conf
르 ㄹ설정하는 것을 DNS record 설정이라고 한다. record에도 종류가 있는데 다음과 같다.
type | key | value |
---|---|---|
A | web-server | 192.168.1.1 |
AAAA | web-server | 2001:0db8:85a3:0000:0000:8a2e:0370:7334 |
CNAME | food.web-server | eat.web-server, hungry.web-server |
dns record type이 3가지가 있는 것인데, A
는 IPv4로 key는 name이고, value가 IP이다. 위에서 우리가 설정한 것이 같은 것이다. AAAA
는 IPv6이다. CNAME
같은 경우는 이름을 맵핑하는 것이다. 가령 food.web-server
로 요청이 오면 eat.web-server
후에 hungry.web-server
에 요청을 보내는 것이다. 즉 하나의 alias를 설정하는 것이다.
DNS ping
을 통해서 DNS record가 잘 설정된 것을 볼 수 있지만, nslookup
을 통해서도 가능하다.
nslookup www.google.com
Server: 8.8.8.8
Address: 8.8.8.8#53
Non-authoritative answer:
Name: www.google.com
Address: 172.217.0.132
이를 dns resultion을 test한다고 한다. 단, nslookup을 사용할 때는 조심해야할 것이 해당 dns record를 DNS server에서 잘 찾을 수 있는 지 확인하기 위해서 사용한다는 것이다. 즉, local etc host file의 entry들은 참조하지 않는다는 것이다.
따라서, nslookup web
이렇게 query하면 실패한다. 오직 DNS server로 query를 보내기 때문이다.
또 다른 DNS name resolution으로 dig가 있다.
dig www.google.com
...
dig
역시도 DNS server에 query를 보내어 확인받는 것이다.