Microsoft MVP성태의 닷넷 이야기
Linux: 73. Linux 측의 socat을 이용한 Hyper-V 호스트와의 vsock 테스트 [링크 복사], [링크+제목 복사],
조회: 8064
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일

(시리즈 글이 6개 있습니다.)
닷넷: 2270. C# - Hyper-V Socket 통신(AF_HYPERV, AF_VSOCK)을 위한 EndPoint 사용자 정의
; https://www.sysnet.pe.kr/2/0/13657

닷넷: 2272. C# - Hyper-V Socket 통신(AF_HYPERV, AF_VSOCK)의 VMID Wildcards 유형
; https://www.sysnet.pe.kr/2/0/13663

Linux: 73. Linux 측의 socat을 이용한 Hyper-V 호스트와의 vsock 테스트
; https://www.sysnet.pe.kr/2/0/13665

Linux: 74. C++ - Vsock 예제 (Hyper-V Socket 연동)
; https://www.sysnet.pe.kr/2/0/13666

닷넷: 2273. C# - 리눅스 환경에서의 Hyper-V Socket 연동 (AF_VSOCK)
; https://www.sysnet.pe.kr/2/0/13667

개발 환경 구성: 721. WSL 2에서의 Hyper-V Socket 연동
; https://www.sysnet.pe.kr/2/0/13713




Linux 측의 socat을 이용한 Hyper-V 호스트와의 vsock 테스트

vsock을 지원하는 socat(SO cket CAT)은 1.7.4 버전부터인데요, (따라서 이것을 테스트하려면 Ubuntu의 경우 22.04 이상이 필요합니다.)

$ sudo apt install socat

자, 그럼 이걸로 Hyper-V 호스트와 리눅스 VM 간의 통신을 테스트해 볼 텐데요, 우선 호스트 측의 윈도우 프로그램은 지난번에 만들어 둔 C# 응용 프로그램으로 대체하겠습니다.

하지만, 그 예제를 그대로 사용할 수는 없고 한 가지 변경을 해야 하는데요, 바로 Service ID를 리눅스 vsock과 호환하도록 맞춰주어야 합니다. 왜냐하면, vsock의 sockaddr 구조체는,

// 버전에 따라 필드의 차이는 있지만 전체적으로 16바이트의 크기는 동일합니다.

struct sockaddr_vm {
	__kernel_sa_family_t svm_family;
	unsigned short svm_reserved1;
	unsigned int svm_port;
	unsigned int svm_cid;
	__u8 svm_flags;
	unsigned char svm_zero[sizeof(struct sockaddr) -
			       sizeof(sa_family_t) -
			       sizeof(unsigned short) -
			       sizeof(unsigned int) -
			       sizeof(unsigned int) -
			       sizeof(__u8)];
};

Guid를 사용하는 윈도우(Hyper-V Socket)와 달리 "unsigned int" 타입의 svm_cid, svm_port를 쓰기 때문입니다. 이러한 차이점을 메우기 위해, 윈도우 측에서는 vsock과 호환하기 위해 특별한 GUID를 소개하고 있습니다.

// Hyper-V Socket Linux guest VSOCK template GUID

struct __declspec(uuid("00000000-facb-11e6-bd58-64006a7986d3")) VSockTemplate{};

 /*
  * GUID example = __uuidof(VSockTemplate);
  * example.Data1 = 2761; // 0x00000AC9
  */

즉, "00000000-facb-11e6-bd58-64006a7986d3" 값을 써야 하고, 앞 부분의 "00000000" 측에 svm_port에 해당하는 값을 16진수로 쓰는 식입니다. 가령, 19000 포트를 쓰고 싶다면 그것의 16진수 값인 0x4a38을 적용해 "00004A38-facb-11e6-bd58-64006a7986d3" 값으로 해야 하는 것입니다.

마지막으로, 저 값을 "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices" 하위에 등록하는 것을 잊지 마시고.




실습을 위해, 이제 지난번 소스코드에서 GcsGuid 값만 바꿔주고,

// 19000번 포트를 사용한다고 가정

public static readonly Guid GcsGuid = new Guid("00004A38-facb-11e6-bd58-64006a7986d3");

(레지스트리 등록 잊지 마시고) 빌드 후 서버 모드로 실행해 둔 후,

ConsoleApp1.exe /server any

Hyper-V에 설치한 Ubuntu 22.04 VM에서 socat을 이용해 다음과 같이 테스트할 수 있습니다.

// socat 실행 후, "test" 입력하고 enter 키를 누르면 ConsoleApp1.exe 측에서 반환하는 "Hello: test"가 출력됩니다.

$ socat - VSOCK-CONNECT:2:19000
test
Hello: test
$

VSOCK-CONNECT 인자와 함께 "2:19000" 값을 주었는데요, 여기서 2는 VMADDR_CID_HOST로 정의된 상수입니다.

/* Use this as the destination CID in an address when referring to the host
 * (any process other than the hypervisor).  VMCI relies on it being 2, but
 * this would be useful for other transports too.
 */

#define VMADDR_CID_HOST 2

즉, VM에서 호스트 측으로 연결 시 svm_cid 필드에 설정해야 하는 값으로, Hyper-V Socket의 "HV_GUID_PARENT(a42e7cda-d03f-480c-9cc2-a4de20abb878)"에 해당한다고 보면 됩니다.




리눅스 측의 vsock 연결을 클라이언트로 했으니 이제 반대로 서버로써도 테스트해야겠죠? ^^

이를 위해 socat을 서버 모드로 실행해 두는데요,

$ socat - VSOCK-LISTEN:19000

역으로 Hyper-V 호스트 측에서는 (전과 다름없이) VM ID를 통해 접속하면 됩니다.

// socat을 실행한 Linux VM의 VM ID가 "f952c5ef-ea6c-4c83-b52c-38f31cf68b61"인 경우,

ConsoleApp1.exe /client f952c5ef-ea6c-4c83-b52c-38f31cf68b61

ConsoleApp1.exe 코드에서는 어차피 Service ID를 "00004A38-facb-11e6-bd58-64006a7986d3"로 사용해 19000 포트로 연결할 것이므로, 결국 필요한 것은 VM ID뿐입니다.

참고로, 윈도우의 경우 Server 측 바인딩이 HV_GUID_WILDCARD와 HV_GUID_LOOPBACK이 가능했는데요, 리눅스도 그와 유사하게 VMADDR_CID_ANY와 (한때 VMADDR_CID_RESERVED였던) VMADDR_CID_LOCAL이 있습니다.

/* The vSocket equivalent of INADDR_ANY.  This works for the svm_cid field of
 * sockaddr_vm and indicates the context ID of the current endpoint.
 */
#define VMADDR_CID_ANY -1U

/* Use this as the destination CID in an address when referring to the
 * local communication (loopback).
 * (This was VMADDR_CID_RESERVED, but even VMCI doesn't use it anymore,
 * it was a legacy value from an older release).
 */
#define VMADDR_CID_LOCAL 1

socat이 어떤 값과 바인딩하는지는 모르겠지만, 위의 설명만 봐서는 VMADDR_CID_ANY인 듯합니다. 이런 경우, 역시나 윈도우에서처럼 같은 VM 내에서는 VMADDR_CID_LOCAL로 연결할 수 있는데요, 따라서 같은 VM 내에서 2개의 터미널을 열어두고 각각 다음과 같이 테스트하면 서로 연결이 됩니다.

// 리눅스 VM의 터미널 A

$ socat - VSOCK-LISTEN:19000

// 리눅스 VM의 터미널 B

$ socat - VSOCK-CONNECT:1:19000

"1:19000"에서 "1"은 VMADDR_CID_LOCAL 값에 해당합니다. 그런 의미에서 본다면 VMADDR_CID_ANY와 VMADDR_CID_LOCAL은 Hyper-V Socket으로 매핑한다면 각각 HV_GUID_WILDCARD와 HV_GUID_LOOPBACK이 됩니다.




참고로, Linux 측에서 vsock 지원 여부를 모듈 열거를 통해 확인할 수 있다고 합니다.

$ lsmod | grep vsock
vsock_loopback                      12288   0
vmw_vsock_virtio_transport_common   61440   1 vsock_loopback
vmw_vsock_vmci_transport            45056   0
vsock                               61440   4 vmw_vsock_virtio_transport_common,vsock_loopback,hv_sock,vmw_vsock_vmci_transport
vmw_vmci                            106496  1 vmw_vsock_vmci_transport

또한, 윈도우의 Hyper-V에서 호스팅하는 것이 아닌, Linux를 호스트로 Linux VM을 돌리는 경우에는 svm_cid 값을 VM 시작 시의 인자로 전달해야 합니다. 가령 qemu의 경우,

// https://github.com/stefano-garzarella/socat-vsock/blob/be46eaf169eea1c63b3d90772610a8733a346e30/EXAMPLES#L236

//////////////////////////////////////////////////////////////////////////////
// VSOCK
# start a linux VM with cid=21
#    qemu-system-x86_64 -m 1G -smp 2 -cpu host -M accel=kvm \
#     -drive if=virtio,file=/path/to/fedora.img,format=qcow2  \
#     -device vhost-vsock-pci,guest-cid=21

# guest listens on port 1234 and host connects to it
guest$ socat - VSOCK-LISTEN:1234
host$ socat - VSOCK-CONNECT:21:1234

# host (well know CID_HOST = 2) listens on port 4321 and guest connects to it
host$ socat - VSOCK-LISTEN:4321
guest$ socat - VSOCK-CONNECT:2:4321

# ssh over vsock (guest-cid = 21)
guest$ socat VSOCK-LISTEN:22,reuseaddr,fork TCP:localhost:22
host$ socat TCP4-LISTEN:22222,reuseaddr,fork VSOCK-CONNECT:21:22
host$ ssh -p 22222 user@localhost

guest-cid 값을 통해 CID를 지정할 수 있습니다.

마지막으로, vsock이 지원되면 /dev/vsock 파일이 열거되는데요,

$ ls /dev/vsock -l
crw-rw-rw- 1 root root 10, 118  7월  2 09:33 /dev/vsock

이 파일에 대해 IOCTL_VM_SOCKETS_GET_LOCAL_CID 명령을 보내면 (qemu의 경우 guest-cid 값으로 전달한) CID 값을 얻는 것이 가능합니다.

#!/usr/bin/env python3
import socket
import struct
import fcntl

with open("/dev/vsock", "rb") as fd:
    r = fcntl.ioctl(fd, socket.IOCTL_VM_SOCKETS_GET_LOCAL_CID, "    ")
    cid = struct.unpack("I", r)[0]

    print("Local CID: {}".format(cid))

# https://gist.github.com/stefano-garzarella/b4971c2bed3c632b48c5e2a823c1cbe1

(qemu 등으로 guest-cid를 설정하지 않은) VM 또는 호스트의 경우에는 CID 값이 4294967295로 나옵니다.




Ubuntu 20.04에서 기본 설치하는 socat은,

$ apt show socat
Package: socat
Version: 1.7.3.3-2
...[생략]...

$ sudo apt install socat

1.7.3 버전인데요, vsock을 지원하지 않습니다.

SOCAT now supports AF_VSOCK
; https://stefano-garzarella.github.io/posts/2021-01-22-socat-vsock/

22.04 우분투 repo의 deb 파일을 직접 다운로드해,

socat_1.7.4.1-3ubuntu4_amd64.deb
; https://ubuntu.pkgs.org/22.04/ubuntu-main-amd64/socat_1.7.4.1-3ubuntu4_amd64.deb.html
; http://archive.ubuntu.com/ubuntu/pool/main/s/socat/socat_1.7.4.1-3ubuntu4_amd64.deb

설치하면,

$ wget http://archive.ubuntu.com/ubuntu/pool/main/s/socat/socat_1.7.4.1-3ubuntu4_amd64.deb
$ sudo apt install ./socat_1.7.4.1-3ubuntu4_amd64.deb

이런 오류가 발생할 것입니다.

$ sudo apt install ./socat_1.7.4.1-3ubuntu4_amd64.deb
...[생략]...

The following packages have unmet dependencies:
 socat : Depends: libc6 (>= 2.34) but 2.31-0ubuntu9.16 is to be installed
         Depends: libssl3 (>= 3.0.0~~alpha1) but it is not installable
E: Unable to correct problems, you have held broken packages.

아마도 저게 동작하려면, socat 빌드를 glibc 2.34 버전을 대상으로, libssl3도 함께 빌드해 링크해야 할 것입니다. 저야 리눅스 초보자라... ^^;




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 7/6/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 121  122  123  124  125  126  127  128  129  130  131  132  133  134  [135]  ...
NoWriterDateCnt.TitleFile(s)
1680정성태6/1/201421420.NET Framework: 439. .NET CLR4 보안 모델 - 1. "Security Level 2"란?파일 다운로드1
1679정성태5/31/201420544.NET Framework: 438. .NET CLR2 보안 모델에서의 APTCA 역할파일 다운로드1
1678정성태5/31/201424271개발 환경 구성: 222. 라이브러리 개발자를 위한 보안 권한 테스트 - "Network Service" 계정 권한으로 실행
1677정성태5/30/201419813VS.NET IDE: 87. IIS Express - 웹 응용 프로그램의 .NET 버전에 맞는 CLR이 로드되지 않는 경우파일 다운로드1
1676정성태5/27/201427940Windows: 95. 윈도우 8에서 Hyper-V 유무에 따른 듀얼 부트 설정하는 방법 [1]
1675정성태5/27/201430073Windows: 94. 윈도우 8.1에서 윈도우 체험 지수(Windows Experience Index, WEI) 확인 방법
1674정성태5/24/201423635VS.NET IDE: 86. 하나의 T4 템플릿으로 여러 개의 소스코드 파일을 자동으로 생성하는 방법 [1]파일 다운로드1
1673정성태5/19/201423160.NET Framework: 437. WACOM 태블릿 환경에서 WinForm 실행시 System.ArgumentException 예외 발생
1672정성태5/15/201423668기타: 46. Microsoft의 응용 프로그램을 클라우드로 제공하는 서비스 - Azure RemoteApp 소개 [2]
1671정성태5/15/201424266.NET Framework: 436. XNA Content 리소스의 해제 후 다시 로드해서 사용하면 ObjectDisposedException 예외 발생 [2]
1670정성태5/15/201424594.NET Framework: 435. .NET GC - 하위 세대의 객체를 포함하는 상위 세대의 참조를 추적하기 위한 card-table
1669정성태5/15/201444635Windows: 93. 윈도우 시스템 디스크 용량 확보를 위한 $PatchCache$ 폴더 삭제 [2]
1668정성태5/10/201423873.NET Framework: 434. Microsoft.SqlServer.Types.SqlGeography 형변환 시 null 반환하는 문제
1667정성태5/5/201424688개발 환경 구성: 221. Azure 데이터베이스를 로컬 DB로 이전하는 방법 [2]
1666정성태5/2/201441328기타: 45. 윈도우 계정의 암호를 알아내는 mimikatz 도구 [5]
1665정성태5/1/201424870.NET Framework: 433. C# - 간단한 HyperLogLog 자료 구조 테스트파일 다운로드1
1664정성태4/28/201422223오류 유형: 227. Process Explorer의 프로세스 뷰가 트리 형식으로 보이지 않는 문제
1663정성태4/28/201418665오류 유형: 226. Visual Studio - We were unable to establish the connection because it is configured for user
1662정성태4/28/201423272개발 환경 구성: 220. supportedRuntime 설정을 위한 app.config Transformation [1]
1661정성태4/26/201420022.NET Framework: 432. WPF - System.Windows.Data Error: 47 : XmlDataProvider has inline XML that does not explicitly set its XmlNamespace (xmlns="").
1660정성태4/25/201427702VC++: 77. C++ 숫자형 값이 범위를 벗어나는 경우의 출력 사례 모음
1659정성태4/17/201427698.NET Framework: 431. .NET EXE 파일을 닷넷 프레임워크 버전에 상관없이 실행할 수 있을까요? [5]
1658정성태4/17/201419809.NET Framework: 430. C#에서 사용자 정의 예약어가 가능할까요? [1]
1657정성태4/10/201439859.NET Framework: 429. C# - 유니코드 한글 문자열을 ks_c_5601-1987로 변환하는 방법 [3]파일 다운로드1
1656정성태3/19/201423034오류 유형: 225. regsvcs 등록 시 0x80040153 오류
1655정성태3/19/201423220Windows: 92. Thumbs.db 파일이 삭제 안 되는 문제
... 121  122  123  124  125  126  127  128  129  130  131  132  133  134  [135]  ...