반응형

 

작성일: 2024년 7월 16일

 

 

아래 글은 나의 주관적 생각이 포함된 것이므로 정확한 기술 Spec을 원하는 분은 이 글을 참고용으로만 읽고,
이 블로그의 중간에 링크를 달아둔 Official document를 열람하는 것을 권장함.

 

 

XDP 개요  (들어가는 글)

XDP(eXpress Data Path)는 OS network stack을 우회하여 별도의 user application으로 보내고 받도록 하는데 사용되는 eBPF 기반의 data path이다.

Linux kernel version 4.8부터 XDP를 포함하므로 XDP 프로그래밍을 위해서 별도로 library를 설치할 필요는 없다.

 

아래 그림만 잘 들여다보면, XDP_* 처리(Action)에 대한 감이 온다.

 

XDP를 이용한 Network Packet Flow를 제거하기

 

위 그림에서 (start), interface output을 물리 네트워크 포트 또는 NIC port 라고 가정하고 보면 Packet 흐름이 자연스러워진다.

그리고, 이 블로그에서는 (start), interface output 가 동일 NIC port라고 가정하고 나머지 내용을 설명할 것이다.   

 

XDP_*  Action Code Description
XDP_PASS 원래의 network packet이 처리되는 것처럼 Network stack으로 보낸다.
(즉, XDP가 없더라도 원래 동작하던 network packet 처리)
XDP_DROP 패킷을 drop (폐기)
XDP_ABORTED Trace point exception과 함께 해당 packet을 drop (폐기)
XDP_TX 위 그림에 묘사된 것처럼 아무 처리하지 않고, 바로 NIC port로 되돌려 보낸다. (반송 처리)
XDP_REDIRECT AF_XDP Address Family를 통해 packet을 다른 NIC port로 보내거나 
User Space Socket으로 redirect한다.
---
  참고로 AF_XDP address family는 Linux kernel 4.18부터 추가되었다.

 

 

예제 / 실습 자료

위 내용을 바탕으로 실습하고자 한다면, 아래 tutorial을 참고할 것!

 

  XDP tutorial : 문서 링크 열기

        아래 git repo에 여러 실습 예제가 있는데, 그 중에서 "basic01-xdp-pass"와 같은 쉬운 예제부터 실습하면서

        전체 처리 절차를 이해하는 추천함!

 

  Tutorial one liners (bpftrace) : 문서 링크 열기

 

  Go Packet Generator (go-pktgen) : 문서 링크 열기

    -> 위 go-pktgen 프로그램은 아래 go package를 사용하므로, 아래 golang pkg source code 분석하는 것을 추천.

          XDP Go Package : 소스 코드 링크 열기   

 

 

Linux kernel source code에서 XDP 관련 코드를 찾아보기 (예시)

Linux kernel source code에서 network driver와 관련한 code를 찾아 보면, 

XDP_*와 관련있는 부분을 쉽게 만날 수 있다.

그 중에서 몇 개를 여기에 적어보겠다.

 

##
## File: linux/latest/source/drivers/net/ethernet/intel/i40e/i40e_txrx.c
##

... 중간 생략 ...
/**
 * i40e_run_xdp - run an XDP program
 * @rx_ring: Rx ring being processed
 * @xdp: XDP buffer containing the frame
 * @xdp_prog: XDP program to run
 **/
static int i40e_run_xdp(struct i40e_ring *rx_ring, struct xdp_buff *xdp, struct bpf_prog *xdp_prog)
{
	int err, result = I40E_XDP_PASS;
	struct i40e_ring *xdp_ring;
	u32 act;

	if (!xdp_prog)
		goto xdp_out;

	prefetchw(xdp->data_hard_start); /* xdp_frame write */

	act = bpf_prog_run_xdp(xdp_prog, xdp);
    
	switch (act) {
    
	case XDP_PASS:   ## NOTE: 따로 처리할 것이 없다.
		break;       ##       그냥, 원래 하던대로 network stack으로 보내면 된다.
        
	case XDP_TX:     ## NOTE: RX 패킷이 들어온 NIC을 찾아서 TX 패킷을 그 NIC으로 보내도록 한다.
		xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index];
		result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring);
		if (result == I40E_XDP_CONSUMED)
			goto out_failure;
		break;
        
	case XDP_REDIRECT:
		err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
		if (err)
			goto out_failure;
		result = I40E_XDP_REDIR;
		break;
        
	default:
		bpf_warn_invalid_xdp_action(rx_ring->netdev, xdp_prog, act);
		fallthrough;
        
	case XDP_ABORTED:  ## NOTE: 패킷을 폐기
out_failure:
		trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
		fallthrough; /* handle aborts by dropping packet */
        
	case XDP_DROP:     ## NOTE: 패킷을 폐기
		result = I40E_XDP_CONSUMED;
		break;
	}
    
xdp_out:
	return result;
}
... 중간 생략 ...

 

 

 

 


 

eBPF 공식 문서

What is eBPF?

  문서 링크: https://ebpf.io/what-is-ebpf/

 

The eBPF Library for Go

  문서 링크: https://ebpf-go.dev/

 

 

 


추천 글

eBPF/XDP: 당신만 모르는 안전하고 빠른 Networking

https://pangyoalto.com/ebpf-and-xdp/

 

eBPF/XDP: 당신만 모르는 안전하고 빠른 Networking

[요약] * eBPF: kernel space 내에서 프로그램을 실행할 수 있도록 하여 어플리케이션 개발자가 런타임에 OS의 기능을 사용할 수 있도록 하는 기술 * XDP: eBPF를 기반으로 한 기술로 packet processing을 할 수

pangyoalto.com

 

 

Unlocking Network Performance with XDP and eBPF

https://medium.com/@khushichhillar02/unlocking-network-performance-with-xdp-and-ebpf-67c712128025

 

Unlocking Network Performance with XDP and eBPF

XDP, eXpress Data Path, is a high-performance networking technology in the Linux kernel that allows for fast and efficient packet…

medium.com

 

Kernel-bypass techniques for high-speed network packet processing(XDP, DPDK, eBPF, SmartNIC)

https://youtu.be/MpjlWt7fvrw?si=bnUQJmA0O3qRf3Jg

 

 

 

WireGuard로 VPN 서버 구축하기

아래 문서에서 다루는 내용은;

  • WireGuard
  • KeyCloak SSO 연동
  • Kernel networking stack을 이용하여 특정 Group 접근을 제어 
  • VPN server에서 사용하는 인증(Authentication)
  • eBPF를 이용한 패킷 필터링(Packet filtering)
  • eBPF map (Key/Value store)

https://tech.devsisters.com/posts/wireguard-vpn-2/

 

 


 

반응형

 

작성일: 2024년 6월 4일

 

Network Traffic을 다루는 앱을 개발하다보면, TLS 또는 HTTPS로 암호화한 통신 내용을 봐야 할 때가 있다.

원칙적으로는 TLS 통신에서 제3자가 패킷 내용을 열람하는 것이 불가능하지만,

내 PC에 저장된 Master Secret 값을 이용하면 복호화가 가능하다. (내 PC는 제3자가 아니니까 이런 복호화가 가능한 얘기가 된다)

 

참고: 3가지 복호화 방법

Master Secret 값을 이용하는 경우 외에도 TLS Payload를 복호화(Decryption)하는 방법이 있다.

Wireshark 매뉴얼에 보면, Master Secret을 포함하여 총 3가지 방법을 소개하고 있다.

방법 A : (Pre)-Master Secret 정보가 담겨있는 Key load file을 사용하여 복호화하기

이 방법이 범용적으로 사용되는 복호화 방법.

Diffie-Hellman(DH) Key 교환이 발생하더라도 (Pre)-Master Secret 정보를 이용하면 복호화가 된다.

이 블로그의 대부분 내용이 이 방식으로 복호화하는 방법이 설명되어 있다.

 
방법 B : RSA private key (예:  PEM 포맷의 private key 파일)을 이용하여 복호화하기

TLS 연동할 Peer 노드(예: 서버)의 RSA private key를 한번만 Wireshark에 등록하면 되므로 가장 편하게 설정할 수 있다.

단, 아래와 같이 조건을 모두 만족하는 경우에만 RSA private key를 사용하여 복호화하는 것이 가능하다.

  • 조건1: Cipher suite가 (EC)DHE 계열이 아니어야 한다.
  • 조건2: TLS 1.0 ~ 1.2만 허용됨. TLS 1.3에서는 복호화할 수 없음.
  • 조건3: Wireshark에 등록할 Private key는 반드시 Server certificate이어야 한다. client certificate 또는 CA(Certificate Authority) certificate은 안 된다.
  • 조건4: TLS handshake 절차에서 'ClientKeyExchange' 과정이 포함되어야 함
즉, 위 4가지 조건을 모두 만족해야 햐는데 현실적으로 요즘 TLS 통신 환경에서 RSA private key를 이용하여 복호화하는 것이 거의 어렵다는 뜻 ㅠㅠ

 

방법 C : Pre-Shared-Key(PSK) 정보를 이용하여 복호화하기

수준 높은 보안을 요구하는 곳에서 PSK를 사용하지 않고,
PSK를 사용하는 것이 흔한 경우가 아니니까, 설명을 생략~

 

 

 

그렇다면,  Master Secret이라는게 무엇이길래 패킷 복호화가 가능한 것일까?

만약 Server / Client 간 통신이 mTLS 방식으로 연결된다면, 아래와 같이 절차를 따를 것이다.

  1. Client는 Server certificate을 받아서 믿을만한 Network peer인지 확인 (즉, Root CA가 서명한 Certificate인지 확인)
  2. Server는 Client certificate을 받아서 믿을만한 Network peer인지 확인
  3. 서로 믿을만하다고 판단되면, 대칭키 교환 (여기서 교환한 대칭키는 Server, Client가 패킷을 암호화 및 복호화 할 때 사용)
  4. Server, Client가 서로 암호화한 패킷을 주고, 받을 쪽에서는 패킷을 받으면 복호화 처리 (이 때 대칭키를 사용함)

위 mTLS 핸드쉐이킹 절차 3번에서 교화한 대칭키만 있으면, Server / Client 간에 주고 받은 암호화된 HTTPS(또는 TLS) 패킷을 복호화할 수 있다.

 

이론적으로는 위와 같고, 실제로 Chrome browser 또는 Firefox browser로 HTTPS 패킷을 보내고 받은 내용을 복호화하려면 아래와 같이 해야 한다.

 

 

##
## Firefox 브라우저로 테스트할 때.
## 
$ export SSLKEYLOGFILE=/tmp/sslkey.log
$ open /Applications/Firefox.app

##
## Chrome 브라우저로 테스트할 때.
##
$ export SSLKEYLOGFILE=/tmp/sslkey.log 
$ open /Applications/Google\ Chrome.app

 

 

Wireshark을 macOS에서 실행한 경우, 아래의 순서로 설정 화면을 열어 본다.

 

[ Wireshark ]  ->  [ Preferences ]  ->  [ Protocols ]  ->  [ TLS ]  ->  [ (Pre)-Master-Secret log filename ]

 

위 순서로 설정 화면을 오픈하고, 아래 예시 화면처럼 Master-Secret log 파일 경로를 입력하면 된다.

 

 

 

[ OK ] 버튼을 클릭하고, Firefox 브라우저에서 웹 브라우징을 해보면

TLS의 Payload가 눈으로 볼 수 있는 HTTP Payload로 복호화된 것을 확인할 수 있다. 

 

 


참고: 위와 동일한 내용이지만 원문을 읽고 싶다면, 아래 문서 링크를 클릭할 것 !

 

https://wiki.wireshark.org/TLS#using-the-pre-master-secret

 

TLS - Wireshark Wiki

Some applications (such as email) use a single port for both unencrypted and encrypted sessions. To change from unencrypted to encrypted, (START)TLS is used. When a single port directly uses the TLS protocol, it is often referred to as SSL.

wiki.wireshark.org

 

 

 


 

반응형

 

2024년 4월 2일

 

 

일단, 메모만 해놓고 나중에 자세히 스터디하기~

 

 

https://www.ntop.org/products/packet-capture/pf_ring/

 

PF_RING

 

 

 

 

PF_RING Modules

 

 

 

 

https://www.ntop.org/products/packet-capture/pf_ring/pf_ring-zc-zero-copy/

 

 

 

Zero Copy Operations to KVM VM instances

 

 

 

 

 

 


 

 

반응형
테스트한 날짜: 2024년 2월 20일

 

 

잠깐 !!
PPTP Server 구축하기 전에 PPTP Client 설정 및 터널 생성하는 법을 알고 싶다면 아래 문서를 참고 !

 

       https://andrewpage.tistory.com/257

 

 

PPTP 패키지 설치

$ sudo  apt install pptpd

 

 

PPTP 서버 설정

##
## Tunnel Interface에 할당할 IP address를 설정한다.
##   예를 들어, PPTP server는 ppp0 tunnel interface에 10.1.0.1 주소를 할당.
##            PPTP client는 ppp0 tunnel interface에 10.1.0.100 주소를 할당.
##

$ cat /etc/pptpd.conf
... 중간 생략 ...

localip 10.1.0.1
remoteip 10.1.0.100-130

... 중간 생략 ...


##
## PPTP client에 접속 요청할 때, PPTP server가 아래의 network 구성 정보를 client에게 전달하도록 함.
## mtu 값은 실제 physical NIC의 mtu 값보다 대략 60~100 bytes 정도 작게 설정해야
## tunnel session을 통해서 IP 패킷이 전송될 때, IP 패킷의 꼬리 부분이 짤리는 현상이 없다.
## 예를 들어서, physical NIC의 MTU 값이 1500 이라고 가정해보면
##   PPTP tunnel interface의 MTU는 1400 정도 되어야 IP packet이 버려지지 않고 전송된다.
## 만약 실수로 tunnel mtu를 1500으로 설정하면, 1500 byte 짜리 IP packet이 전송되려 할 것이고
## 이 때 IP packet의 뒷 부분 60~100 bytes 정도가 짤리는 현상이 발생할 것이다.
##

$ cat /etc/ppp/pptpd-options
... 중간 생략 ...

ms-dns 1.1.1.1
mtu 1400
mru 1400

default-asyncmap

... 중간 생략 ...


##
## 반드시 ip_forward를 enable 시켜야 한다.
## ip_forward 설정이 enable 되어야 한개의 Linux OS내부에서 Physical port 'ens3'와 ppp0 간에 패킷이 forward된다.
##

$  sudo sysctl -w net.ipv4.ip_forward=1

$  cat  /etc/sysctl.conf
... 중간 생략 ...

net.ipv4.ip_forward=1

... 중간 생략 ...

$

 

PPTP 계정 설정

PPTP client가 PPTP server에 접속할 때 사용할 Account 정보를 설정한다.

$ cat /etc/ppp/chap-secrets

# client        server  secret                  IP addresses
mynewid         pptpd   my!pass@word            *
gildong         pptpd   me!hahahoho@            *

 

 

PPTP 서비스 기동

$ systemctl start pptpd

$ systemctl enable pptpd

$ systemctl status pptpd
● pptpd.service - PoPToP Point to Point Tunneling Server
     Loaded: loaded (/lib/systemd/system/pptpd.service; disabled; vendor preset: enabled)
     Active: active (running) since Tue 2024-02-20 22:35:17 KST; 34min ago
     
... 중간 생략 ...

 

 


PPTP Client를 이용하여 PPTP 터널 생성 테스트하기

Ubuntu OS에서 PPTP Client를 설정하는 방법은 아래 문서를 참고 !


     https://andrewpage.tistory.com/257

 

 

 


 

반응형
작성일:  2024년 2월 9일

 

 

MACVLAN 가상 네트워크 포트 만들기

일반적으로 물리 네트워크 포트 1개에는 MAC address 1개, IP address 1개를 설정해서 사용한다.

(본업으로 Network 장비를 개발, 운영하는 사람이 아니라면 이런 단순한 구성이 익숙할 듯)

그런데 물리 네트워크 포트 1개에 '마치 여러 개의 네트워크 포트가 있는 것처럼' 동작하게 만들어야 할 때가 있다.

예를 들어,

  - 물리 포트 eth0에 2개 이상의 MAC address를 설정

  - 물리 포트 eth0에 2개 이상의 IP address를 설정

위 2가지를 모두 지원하는 가상 포트 타입이 'MACVLAN'이다.

[참고: Hypervisor, Virtual Machine Manager 에서 VM이 사용할 NIC 포트를 Bridge 타입으로 설정하면 위와 같은 형상이 된다)

 

Bridge 모드의 MACVLAN 포트 동작 방식 (출처: Red Hat Developer Blog)

 

아래 예시 명령과 같이 따라해보면 바로 이해가 될 듯.

(명령을 실행했던 OS: Ubuntu 22.04)

 

## 물리 NIC 포트 'eth0'에 IP address 설정
ip address add 10.1.4.55/24  dev eth0

## 물리 포트 'eth0'에 가상 포트 'macvlan1'을 만들기
ip link   add   macvlan1 link eth0 type macvlan mode bridge

## network namespace 'net1' 만들기
ip netns  add   net1

## network namespace 'net1'에 가상 포트 'macvlan1'을 추가
ip link   set   macvlan1 netns net1

## 가상 포트 'macvlan1'을 활성화(up)하기
ip netns  exec  net1 ip link set dev macvlan1 up

## 가상 포트에 IP address를 설정
ip netns  exec  net1 ip address  add 10.1.4.51/24 dev macvlan1

## IP 통신이 잘 되는지 'ping test'하기
ip netns  exec  net1 /usr/bin/ping 10.1.4.56


## 테스트 종료, 가상 포트 'macvlan1' 지우기
ip netns  exec  net1 ip link del macvlan1

 

위 예시에서 'mode bridge'로 설정한 부분이 있는데, bridge 모드 외에도 아래와 같은 다양한 모드를 설정할 수 있다.

  - Private

  - VEPA

  - Bridge

  - Passthru

  - Source

위 5 가지 모드에 대한 자세한 설명은 이 문서(Redhat Blod)를 참고할 것!

 

추천 문서

Redhat / Linux interfaces for virtual networking (2018년 10월)

https://developers.redhat.com/blog/2018/10/22/introduction-to-linux-interfaces-for-virtual-networking

 

 

 

 

 

 

 


 

 

반응형

작성일: 2024년 1월 10일

 

잘 만들어진(기성품) VPN 서버 프로그램이 많이 있지만, 나만의 Bespoke VPN 서버를 만들어보면 어떨까?

(일단, 다른 선구자 개발자가 해놓은 결과물을 읽고 차근차근 해봐야지요)

 

 

참고 문서: WireGuard로 멋진 VPN 서버 구축하기

https://tech.devsisters.com/posts/wireguard-vpn-1

 

https://tech.devsisters.com/posts/wireguard-vpn-2

 

 

참고 문서: WireGuard Official Docs

https://www.wireguard.com/

 

 

참고 문서: WG-eBPF 오픈 소스 프로젝트 (Security, access control and traffic shaping through L3 VPNs)

https://github.com/pcolladosoto/wg-ebpf

 

 

 

 

 

 

 

 

 

 


 

반응형

 

작성일: 2024년 2월 21일

 

PPTP, L2TP 같은 터널링을 사용할 수 없는 상황에서

방화벽 건너편의 네트워크에 접속할 일이 발생하면, SSH Port Forwarding을 임시방편으로 사용하는 것도 좋다.

물론 전제 조건이 있다.

  - SSH 접속할 수 있도록 방화벽 허용 규칙
     또는
  - DNAT Rule
     또는
  - 공유기의 Port Forward Rule이 미리 설정되어 있어야 한다.

 

즉, 원격 Network에 SSH 접속 만큼은 가능한 환경이라는 가정하에 아래 설명을 봐야 한다.

간단하게 한번 훑어보고 실습 환경으로 가보자.

 

SSH Tunneling에는 3가지가 있다.

  - Local Port Forwarding (Local Tunneling)

  - Remote Port Forwarding

  - Dynamic Port Forwarding

 

각 Tunneling 방식에 대해서는 아래 구체적으로 설명하기로 한다.

 

우선 접속할 대상 Network의 SSH 서버의 설정을 수정해야 한다.

SSH Server Config 설정

$ sudo -s

$ vim /etc/ssh/sshd_config

... 중간 생략 ...
AllowTcpForwarding yes     # <-- yes로 변경
GatewayPorts yes           # <-- yes로 변경
... 중간 생략 ...

$ systemctl restart sshd

 

 

준비 작업 끝 !

예시를 들어서, Local Tunneling에 관해서 설명해보면 이렇다.

 

SSH Local Port Forwarding (Local Tunneling)

아래 그림과 같이 집에 있는 내 맥북 PC에서 회사에 있는 VNC 서버에 접근해보겠다.

 

SSH 터널링 (Local Port Forwarding 방식)

 

위 네트워크 구성도를 참고하여 내 PC(맥북)에서 아래의 명령을 수행한다.

(위 구성도와 아래 명령에 있는 IP Address 값을 매핑해서 보면, 아래 명령의 의미를 이해할 수 있다)

$  ssh  -L 5900:10.1.1.3:5900  root@10.1.1.2

 

그리고 내 PC(맥북)에서 RealVNC Viewer 또는 TigerVNC Viewer에 새 연결 정보를 설정해야 하는데,

주소를 localhost (또는 127.0.0.1)으로 입력해야 한다. (아래 화면을 참고)

 

 

위와 같이 VNC Server의 주소를 설정하고, 접속 버튼을 누르면 

VNC 접속 요청 트래픽은 아래 순서로 흘러간다.

 

  1)  내 맥북 PC VNC Client

  2)  localhost의 ssh client (192.168.1.5:5900)

  3)  사무실의 ssh server (10.1.1.2)

  4)  VNC Server (10.1.1.3:5900)

 

원하는 VNC 접속 성공 !!

 

 


 

 

SSH Remote Port Forwarding

이번에는 완전 반대의 경우를 생각해보자.

사무실 쪽에서 SSH 서버 접속을 허용하지 않아서 Local Tunneling이 안 되는 경우라면, 

사무실에 있는 누군가(나의 친한 동료)가 내 집에 있는 내 맥북에 SSH Tunneling을 요청해주어야 한다.

물론 내 맥북이 Public network에 노출되어야 한다.

이런 방식을 Remote Tunneling이라고 한다. 

 

SSH 터널링 (Remote Port Forwarding 방식)

 

사무실에서 나의 동료가 회사 Linux 서버에서 아래와 명령을 실행해준다.

$  ssh  -R  34343:10.1.1.2:5900  sejong@192.168.1.5 -p 20022

 

그러면 위 명령 때문에 내 맥북 PC에는 TCP Listening port 34343가 생성된다.

## 집에 있는 내 맥북 PC에서 명령을 실행한 결과

$  netstat -anp | grep LISTEN
... 중간 생략 ...
tcp    0    0 0.0.0.0:34343       0.0.0.0:*         LISTEN      -
... 중간 생략 ...

 

이제 내 맥북에서 VNC Viewer를 이용해서 아래 화면과 같이 설정하고 회사 Network로 접속해보자.

VNC Server 주소는 localhost 또는 127.0.0.1 으로 설정하면 된다.

 

위와 같이 VNC Server의 주소를 설정하고, 접속 버튼을 누르면

VNC 접속 요청 트래픽은 아래 순서로 흘러간다.

 

  1)  내 맥북 PC VNC Client

  2)  localhost의 ssh client (192.168.1.5:5900)

  3)  사무실의 ssh server (10.1.1.2)

  4)  VNC Server (10.1.1.3:5900)

 

원하는 VNC 접속 성공 !!

 

 


 

반응형

 


 

작성일: 2023년 12월 12일

 

 

Juniper Switch를 원격에서 제어할 수 있는 API를 찾아보니 아래와 같은 것들이 있었다.

- Python PKG (Juniper가 공식적으로 개발 및 배포하고 Example이 다양하게 많아서 사용하기 좋았다.)

- Ansible Module (Juniper가 공시적으로 배포하지만, 실전에서 사용하기에는 Example이 부족했다)

- SNMP (Juniper가 SNMP 서비스를 제공하지만, 제약이 많다)

- NET-CONF (업계 표준이니까 제공해주지만, 쌩코딩해서 사용하기에는 시간적으로 부담이 된다)

 

구현 시간을 아끼고, 예제도 많은 Python PKG를 선택해서 개발하기로 마음을 굳혔다.

그리고 나중에 시간이 생기면 Ansible playbook을 작성해서 조금 더 추상화해볼 계획이다.


 

 

참고:

아래의 예제는 [ Junos PyEX 개발자 가이드 ] 문서 중에서 업무에 필요한 부분만 추려서 실습하고 작성한 것이다.

시간이 넉넉한 사람은 아래 개발자 가이드를 다 읽어보고 Junos PyEX를 사용하고,

시간이 넉넉하지 않은 사람은 아래 요약된 실습 내용만 따라하면 된다.

https://www.juniper.net/documentation/kr/ko/software/junos-pyez/junos-pyez-developer/index.html

 

 

 

준비 작업 / Juniper Switch 장비 설정 작업

Client 장비의 Junos PyEX가 접근할 수 있도록 Juniper Switch에서는 [ SSH 서비스, NETCONF, Junos XML API ]를 활성화(Enable)해야 한다.

설명은 거창하지만, 아래의 예제 명령을 한줄 입력해주면 끝이다.

 

> configure         // 설정 모드로 진입하기 위한 명령을 입력

Entering configuration mode
Users currently editing the configuration:
... 중간 생략 ...

myuser# set netconf ssh   // NETCONF-over-SSH 서비스를 활성화하는 명령을 입력

myuser# commit            // 위에서 변경한 내용을 시스템에 반영하기 위한 명령을 입력

 

 

Junos PyEX 패키지(jnpr.junos)의 각 모듈에 대한 설명

Module Description
device Junos 디바이스를 표현하는 클래스를 정의하고, Device spec 및 상태를 조회할 수 있는 기능을 지원한다.
command CLI, vty 명령을 지원한다. 
표 형태의 View 출력 Form을 지원한다.
exception Exception handling
factory 사용자가 지정한 형태의 Table, View 출력이 가능하도록 한다.
  예: loadyaml() 함수
facts Device에 대한 정보를 추출하기 위한 Object
op RPC 응답의 XML 출력을 Filtering
resources ... 설명 생략 ...
transport ... 설명 생략 ...
utils Configuration utility, Shell utility, Software installation, Security utility, etc ...

 

준비 작업 / Client 장비에 Python 패키지 설치 작업

내가 사용한 OS: Ubuntu 22.04

 

Juniper Switch를 관리할 Client 장비(Ubuntu 22.04)에서 아래 명령을 수행하여 Junos PyEX 패키지를 설치한다.

$ sudo pip3 install junos-eznc

 

작업 끝. (너무 간단하다 ^^)

 

[ 예제 1 ]  네트워크 포트 Up & Down 예제 프로그램

아래 예제는 Juniper Switch(10.1.1.2) 장치에 접속해서 Giga Ethernet을 Down & Up 상태로 변경하고

Port 상태를 조회하는 기능을 수행한다.

 

아래와 같이 Python 예제 코드를 작성한다.

from jnpr.junos import Device
from jnpr.junos.utils.config import Config
from jnpr.junos.op.ethport import EthPortTable
import time


with Device(host='10.1.1.2', user='myadmin', password='mypasswd') as dev:
    ## 포트 상태를 Up/Down 상태로 변경하기
    with Config(dev, mode='ephemeral') as cu:
        cu.load('set interfaces ge-0/0/8 disable', format='set')      # Port Down 상태로 변경
        #cu.load('delete interfaces ge-0/0/8 disable', format='set')  # Port Up 상태로 변경
        cu.commit()

    time.sleep(5)   ## Config를 commit하고도 2~3초 정도 지나야 Port state 값이 반영되므로 5초 정도 sleep 한다.
    
    ## 전체 포트 상태 정보를 가져오기
    eths = EthPortTable(dev)
    eths.get()
    for item in eths:
        print ("{}: {}".format(item.name, item.oper))

    # 1개 포트 정보만 가져오기
    eths.get("ge-0/0/8")
    # 포트 정보의 모든 컬럼의 내용을 보고 싶다면...
    print(eths.values())
    for item in eths:
        print ("name: {}  operating state: {}  admin state: {}  mac: {}  mtu: {}".format(item.name, item.oper, item.admin, item.macaddr, item.mtu))

 

 

위에서 작성한 Python 예제 코드를 아래와 같이 실행한다.

$  python3 my_example_1.py

ge-0/0/0: down
ge-0/0/1: down
ge-0/0/2: down
ge-0/0/3: down
ge-0/0/4: down
ge-0/0/5: down
ge-0/0/6: down
ge-0/0/7: down
ge-0/0/8: up         <-- 내가 변경한 포트의 상태
ge-0/0/9: down
ge-0/0/10: down
ge-0/0/11: down
ge-0/0/12: down
ge-0/0/13: down
ge-0/0/14: down
ge-0/0/15: down
ge-0/0/16: down
ge-0/0/17: down
ge-0/0/18: down
ge-0/0/19: down
ge-0/0/20: down
ge-0/0/21: down
ge-0/0/22: down
ge-0/0/23: up

[[('oper', 'up'), ('admin', 'up'), ('description', None), ('mtu', 1514), ('link_mode', 'Full-duplex'), ('macaddr', '60:c7:8d:a3:78:74'), ('rx_bytes', '2124'), ('rx_packets', '24'), ('tx_bytes', '586755785'), ('tx_packets', '7013363'), ('running', True), ('present', True)]]

name: ge-0/0/8  operating state: up  admin state: up  mac: 60:c3:8a:a3:78:74  mtu: 1514

$

 

 

 


 

[ 예제 2 ]  Juniper Switch의 VLAN 별, 포트 별 Learning된 MAC Address List를 조회

아래 예제는 Juniper Switch(10.1.1.2) 장치에 접속해서 Juniper Switch가 MAC Learning한 결과물을 조회한다.

Learning된 MAC Address를 각각의 VLAN 별, 포트별로 표현된다.

 

조회 결과물이 XML이기 때문에 XML 데이터 포맷을 처리하기 위한 Python 패키지가 필요한다.

$ pip install xmltodict

 

 

아래와 같이 Python 예제 코드를 작성한다.

import pprint
import xmltodict
from xml.etree import ElementTree
from jnpr.junos import Device
from jnpr.junos.op.ethernetswitchingtable import EthernetSwitchingTable


with Device(host='10.1.1.2', user='myadmin', password='mypasswd') as dev:
    eth_table = dev.rpc.get_ethernet_switching_table_information()
    dict_eth_table = xmltodict.parse(ElementTree.tostring(eth_table, method="xml"))
    pprint.pprint(dict_eth_table, indent=2)

 

 

위에서 작성한 Python 예제 코드를 아래와 같이 실행한다.

$  python3  my_example_2.py

{ 'l2ng-l2ald-rtb-macdb':
    { 'l2ng-l2ald-mac-entry-vlan':
        { '@style': 'brief-rtb',
            'l2ng-l2-mac-routing-instance': 'default-switch',
            'l2ng-l2-vlan-id': '100',
            'l2ng-mac-entry': [
                { 'l2ng-l2-mac-address': '00:03:51:17:07:14',
                  'l2ng-l2-mac-age': '-',
                  'l2ng-l2-mac-flags': 'D',
                  'l2ng-l2-mac-fwd-next-hop': '0',
                  'l2ng-l2-mac-logical-interface': 'ge-0/0/23.0',
                  'l2ng-l2-mac-rtr-id': '0',
                  'l2ng-l2-mac-vlan-name': 'vlan-100'},
                { 'l2ng-l2-mac-address': '00:03:51:20:02:e2',
                  'l2ng-l2-mac-age': '-',
                  'l2ng-l2-mac-flags': 'D',
                  'l2ng-l2-mac-fwd-next-hop': '0',
                  'l2ng-l2-mac-logical-interface': 'ge-0/0/23.0',
                  'l2ng-l2-mac-rtr-id': '0',
                  'l2ng-l2-mac-vlan-name': 'vlan-100'},

                ... 중간 생략 ...

                { 'l2ng-l2-mac-address': 'fc:34:51:b6:35:eb',
                  'l2ng-l2-mac-age': '-',
                  'l2ng-l2-mac-flags': 'D',
                  'l2ng-l2-mac-fwd-next-hop': '0',
                  'l2ng-l2-mac-logical-interface': 'ge-0/0/23.0',
                  'l2ng-l2-mac-rtr-id': '0',
                  'l2ng-l2-mac-vlan-name': 'vlan-100'},
                { 'l2ng-l2-mac-address': 'fc:34:51:e1:35:ea',
                  'l2ng-l2-mac-age': '-',
                  'l2ng-l2-mac-flags': 'D',
                  'l2ng-l2-mac-fwd-next-hop': '0',
                  'l2ng-l2-mac-logical-interface': 'ge-0/0/23.0',
                  'l2ng-l2-mac-rtr-id': '0',
                  'l2ng-l2-mac-vlan-name': 'vlan-100'}
            ],
            'learnt-mac-count': '59',
            'mac-count-global': '59'
        }
    }
}

$

 

 


 

[ 예제 3 ]  Juniper Switch의  장치 정보, Spec 등 조회

아래 예제는 Juniper Switch(10.1.1.2) 장치에 접속해서 Juniper Switch의 장치 정보 및 Spec을 조회한다. (아래 항목을 참고)

- Switch model name

- Switch status

- 기동하여 운영되고 있는 시간 (up time)

- Switch 장비 이중화 정보 (Master, Member, FWDD 등)

- FQDN (domain name)

- Switch 장치의 Hostname

- JunOS 정보 (os name, version)

- etc

 

 

아래와 같이 Python 예제 코드를 작성한다.

from pprint import pprint
from jnpr.junos import Device
from jnpr.junos import Device

with Device(host='10.1.1.2', user='myuser', password='mypasswd1234' ) as dev:
    pprint(dev.facts)
    pprint(dev.facts['version'])
    pprint(dev.facts['switch_style'])

 

 

위에서 작성한 Python 예제 코드를 아래와 같이 실행한다.

$  python3  my_example_3.py

{'2RE': False,
 'HOME': '/var/home/admin',
 'RE0': {'last_reboot_reason': '0x1:power cycle/failure',
         'mastership_state': 'master',
         'model': 'RE-EX2300-24T',
         'status': 'OK',
         'up_time': '6 days, 23 hours, 50 minutes, 36 seconds'},
 'RE1': None,
 'RE_hw_mi': False,
 'current_re': ['master',
                'node',
                'fwdd',
                'member',
                'pfem',
                're0',
                'fpc0',
                'localre'],
                
... 중간 생략 ...

 'version': '20.4R3-S2.6',
 'version_info': junos.version_info(major=(20, 4), type=R, minor=3-S2, build=6),
 'virtual': False}
'20.4R3-S2.6'
'VLAN_L2NG'

$

 

 


 

[ 예제 4 ]  Juniper Switch의  Shell 명령, CLI 명령을 원격으로 실행

아래 예제는 Juniper Switch(10.1.1.2) 장치에 접속해서 Juniper Switch의 shell 명령(CLI 명령)을 실행하는 코드이다.

 

아래와 같이 Python 예제 코드를 작성한다.

from jnpr.junos import Device
from jnpr.junos.utils.start_shell import StartShell


dev = Device(host='10.1.1.2', user='myadmin', password='mypasswd1234' )

ss = StartShell(dev)
ss.open()

version = ss.run('cli -c "show version | no-more"')
print(version)

ether_tbl = ss.run('cli -c "show ethernet-switching table interface ge-0/0/23 | no-more"')
print(ether_tbl)

ss.close()

 

 

위에서 작성한 Python 예제 코드를 아래와 같이 실행한다.

$  python3  my_example_4.py

True, 'cli -c "show version | no-more"\r\r\n
 fpc0:\r\n
 --------------------------------------------------------------------------\r\n
 Model: ex2300-24t\r\n
 Junos: 20.4R3-S2.6\r\n
 JUNOS OS Kernel 32-bit  [20211117.c779bdc_builder_stable_11-204ab]\r\n
... 중간 생략 ...
 '
)


(True, 'cli -c "show ethernet-switching table interface ge-0/0/23 | no-more"\r\r\n\r\n
 MAC database for interface ge-0/0/23\r\n\r\n
 MAC database for interface ge-0/0/23.0\r\n\r\n
 MAC flags (S - static MAC, D - dynamic MAC, L - locally learned, P - Persistent static, C - Control MAC\r\n
           SE - statistics enabled, NM - non configured MAC, R - remote PE MAC, O - ovsdb MAC)\r\n\r\n\r\n
 Ethernet switching table : 61 entries, 61 learned\r\n
 Vlan                MAC                 MAC         Age    Logical                NH        RTR \r\n
 name                address             flags              interface              Index     ID\r\n
 default             00:03:5a:17:07:14   D             -   ge-0/0/23.0            0         0       \r\n
 default             00:03:5a:20:02:e2   D             -   ge-0/0/23.0            0         0       \r\n
... 중간 생략 ...
 default             fc:34:5a:e1:35:ea   D             -   ge-0/0/23.0            0         0       \r\n% '
)

$

 

 

 

 

 

 

 

 

참고 문서

Junos PyEX 파이썬 패키지를 사용하여 Juniper Switch 구성 정보를 가져오기

Junos PyEX 파이썬 패키지를 사용하여 출력 내용을 구조화하기 (출력할 컬럼을 선별하여 요약본 만들기)

 

 

 

 

 


 

+ Recent posts