Pages

Tuesday, August 9, 2022

Handshake One: SYN, DoS 공격지점, 또는 접속하는 IP들의 목록을 알아보자

코로나19가 한창 여름 내내 감염 신기록을 갈아치우던 뜨거운 여름이었습니다. 저는 한 작은 온라인 커뮤니티의 관리자들이 DoS(Denial of Service, 서비스 거부 공격)에 대항하는걸 지켜보고 있었습니다. 그들은 열정적이었지만, 작업은 그다지 효율적이지 못했습니다. 그들이 쓸 수 있는 도구라고는 웹서버 로그와 그들의 오래된 친구, iptables 뿐이었지요.

사실 보안에 투자할만한 여력이 없는 환경에서는, 이 돌대가리같은(......), 하지만 꽤나 효율적인 공격에 대항해 의존할만한 도구라고는 iptablesnftables같은 것들 밖에는 없습니다. 하지만 일단 공격을 받고 나면, 사람들은 머리가 새하얘지죠. 로그는 너무 길고 복잡하고, 공격자 IP를 사용자 IP로부터 '발라내는' 작업은 꽤나 어렵습니다.

해서, 이런 분들을 도와드리고자 하는 순수한 목적에서 Handshake One이라고 이름붙인 작은 프로그램을 하나 만들었습니다. 이 프로그램을 이용하면 DoS 공격의 원천 IP를 빠르게 확인하거나, 아니면 최소한 현재 서비스에 어떤 IP들이 접속하고 있는지를 파악할 수 있습니다. 이 프로그램은 최근 60초동안 클라이언트 IP에서 발생하는 SYN 패킷을 수집하여 아래와 같은 보고서를 만들어냅니다:

Handshake One TCP SYN counter report
(C)Copyright 2022 Robert Teminian.
This application is provided free of charge, and provided AS IS: though the developer hopes that this would help the user in any way, the software does NOT guarantee anything at all.

Stop by the developer's blog and leave a comment! Visit http://codenested.blogspot.com

====================
At 1660000053
IP Hits
192.168.1.26 14
Total 14

====================
At 1660000054
IP Hits
192.168.1.26 11
Total 11

====================
At 1660000055
IP Hits
192.168.1.26 1
Total 1

현재 세 가지 운영체제에 대한 실행파일이 제공되고 있습니다만, 만일 다른 운영체제를 위한 실행파일이 필요하신 경우 제게 말씀해주세요. 아래 링크를 클릭하면 파일을 다운로드받을 수 있습니다.

위 파일은 모두 압축파일입니다. 원하시는 곳에 압축을 풀어서 사용해주시면 됩니다.

사용법은 아래와 같습니다
  • 설치: Windows
    • 원하는 곳에 ZIP 파일의 압축을 풉니다
    • Windows 환경에서, Handshake One은 패킷 캡쳐를 위해 npcap(https://npcap.com/) 을 사용하고 있습니다. 라이브러리를 직접 설치하시거나, Wireshark(https://www.wireshark.org/)를 설치하면 분석프로그램과 npcap을 같이 설치합니다
    • npcap을 설치한 뒤, C:\Windows\Systems32\Npcap에서 Packet.dll과 wpcap.dll을 프로그램 디렉토리에 복사합니다
  • 설치: Linux
    • 원하는 곳에 TGZ 파일의 압축을 풉니다
    • Linux 환경에서, Handshake One은 libpcap을 이용합니다. 일반적으로 libpcap은 tcpdump를 설치하면서 함께 설치되는 경우가 대부분입니다만, 만일 설치되지 않았다면 해당 리눅스 배포본의 패키지 관리자(apt, yum, ......)의 설명을 참고하여 설치해 주세요
  • 환경 설정
    • Handshake One의 환경을 설정할 수 있는 유일한 방법은 HandshakeOne.json 파일을 편집하는 것입니다. 현재 지원되는 설정은 아래와 같습니다
      • resultpath: 보고서 파일을 저장할 디렉토리를 설정합니다. Handshake One은 해당 디렉토리에 "HandshakeOneReport.txt" 파일을 생성하고, 매 30초마다 갱신(덮어쓰기)을 수행합니다
        • 리눅스를 사용하시는 경우, RAM disk 파티션(예: /tmp)으로 설정하여 시스템의 I/O 부하를 줄일 것을 권장합니다
      • sniffer: 패킷을 수집할 디바이스 이름입니다. Linux에서는 일반적으로 ip linkifconfig 같은 명령어에 나오는 이름을 사용하면 됩니다만, Windows에서는 일반적으로 보이는 이름이 아닌 내부 디바이스 이름(예:  \Device\NPF_{12345678-9ABC-DEF0-1234-567890ABCDEF})을 사용하여야 해서 설정이 조금 어려울 수 있습니다. 만일 디바이스 이름과 그에 해당하는 설명(예: Realtek PCIe GbE Family Controller)을 함께 보시려면, Handshake One을 "show" 파라미터와 함께 실행해 주세요(예: HandshakeOne show)
      • reportsizelimit: 보고서 내용을 갱신할 때, 보고서 파일의 크기를 지정된 크기로 제한합니다(바이트 단위). 만일 지정된 크기를 넘어서게 될 경우, 현재 작성되는 timestamp까지의 데이터만을 작성합니다. 이를테면, 10:00:00(09:00:00~09:00:59의 데이터를 포함)에 작성되는 데이터가 1.5MB였다면 갱신시 모든 내용이 저장되고, 10:01:00(10:00:00~10:00:59의 데이터를 포함)에 작성되는 과거 1분간의 데이터가 총 2.5MB이고 10:00:47초 데이터를 쓰던 도중 보고서의 크기가 2MB를 넘었다면 10:00:47까지의 내용만을 작성 완료하고 보고서 쓰기작업을 종료한 후 10:00:02에 보고서를 갱신하게 됩니다.
  • 프로그램 실행
    • Windows: HandshakeOne.exe를 실행해 주시면 됩니다
      • 만일 Handshake One을 Windows Service로 실행하시고 싶으시다면, nssm(http://nssm.cc/)을 이용하실 수 있을 것으로 생각됩니다. 직접 써 본 적은 없지만 평가가 꽤 좋은 프로그램이었습니다
    • Linux: 두 가지 방법이 있습니다
      • HandshakeOne을 직접 실행합니다. 참고: libpcap이 root 권한을 필요로 하므로, HandshakeOne은 sudo나 su 등을 이용하여 root 계정으로 실행되어야 합니다
      • Handshake One을 systemd service로 설정할 수 있습니다. HandshakeOne.service 파일을 필요에 따라 편집하시고(최소한 ExecStart 와 WorkingDirectory가 현재 프로그램의 위치를 반영하게끔 조정되어야 합니다), 아래의 명령을 참조하여 프로그램을 systemd service로 등록해 주세요
        • sudo cp systemd.service /etc/systemd/system
        • sudo systemctl enable HandshakeOne
        • sudo systemctl start HandshakeOne
프로그램에 대한 설명은 여기까집니다! 유용하게 쓰실 수 있으셨으면 좋겠습니다. 제언, 의견, 또는 질문이 있으시면 아래에 코멘트를 남겨주세요. 감사합니다.

Handshake One: Know Your SYN, source of DoS attack, or client IP profiles at least

It was a hot summer in the middle of COVID-19 renewing its infection top day by day. I saw managers of a small online community defend the server against a Dos(Denial of Service) attack. They were enthusiastic, but I found out the work is quite inefficient. The only thing they could rely on was some web server logs and our good old friend iptables.

Well, being too small to invest in some security, we know the only viable option we have is either iptables or nftables against those dull and stupid, yet quite efficient attacks. However, when we encounter the attacks, usually we're puzzled and stuck; log is too long and complicated to read so that we have difficulties on distinguishing attacker IPs against user IPs.

So, I developed a small utility named Handshake One to help server engineers who want to find out sources of DoS attacks as early as possible, or, learn IP profiles for your service at least. This small utility collects SYN packets from clients IPs for past 60 seconds to generate reports as you see below:
Handshake One TCP SYN counter report
(C)Copyright 2022 Robert Teminian.
This application is provided free of charge, and provided AS IS: though the developer hopes that this would help the user in any way, the software does NOT guarantee anything at all.

Stop by the developer's blog and leave a comment! Visit http://codenested.blogspot.com

====================
At 1660000053
IP Hits
192.168.1.26 14
Total 14

====================
At 1660000054
IP Hits
192.168.1.26 11
Total 11

====================
At 1660000055
IP Hits
192.168.1.26 1
Total 1

Currently binaries for three operating systems are supported, but you can contact me to build binaries for other OSes. Click the link below to download the executable binary for each:

They're just compressed files. You can just decompress the file in any directory you want to use.

The usage is as follows:
  • Install: Windows
    • Decompress the ZIP file in any location you want
    • On Windows, Handshake One depends on npcap(https://npcap.com/) for capturing packets. Please install the separate binary, or install Wireshark(https://www.wireshark.org/) which installs both packet analysis tool and npcap.
    • After installing npcap, copy Packet.dll and wpcap.dll from C:\Windows\Systems32\Npcap to the executable directory
  • Install: Linux
    • Decompress the TGZ file in any location you want
    • On Linux, Handshake One depends on libpcap. Usually it is installed alongside with tcpdump but if it's not, consult your Linux distribution's package manager(apt, yum, ......) to install the package
  • Configuration
    • The only way to configure Handshake One is via its configuration file, HandshakeOne.json. Currently there are only two keys
      • resultpath: the directory to save report file. Handshake One will automatically generate and update(overwrite) file named "HandshakeOneReport.txt"on that directory every 30 seconds.
        • In Linux,  I recommend to set the directory to some RAM disk(e.g. /tmp) so that the 
      • sniffer: device name to capture the packets. In Linux its the device name shown on commands like ip link or ifconfig, but in Windows it's a bit tricky since the name npcap refers to is NOT the "human readable name" for the interface, but internal device name like \Device\NPF_{12345678-9ABC-DEF0-1234-567890ABCDEF}. To see the device names and corresponding human readable descriptions(e.g. Realtek PCIe GbE Family Controller), run Handshake One with "show" parameter, e.g. HandshakeOne show
      • reportsizelimit: when updating(actually overwriting) the report file, limit the size of report file in bytes. If the file size is bigger than designated size, the application will write until the last data for the timestamp currently being written and finish. For example, if the report size at 10:00:00(including data for 09:00:00~09:00:59) was 1.5MB the report will contain everything, yet at 10:01:00(including data for 10:00:00~10:00:59)the actual size is 2.5MB and it hits the set limit (i.e. 2MB) around writing data for 10:00:47, it'll complete write data up to 10:00:47, finish writing, and refresh the report at 10:00:02
  • Run the application
    • In Windows, just run HandshakeOne.exe
      • If you're interested in using Handshake One as Windows Service, I think you can use nssm(http://nssm.cc/). Though I have no experience using it, I find very positive reviews in many places.
    • In Linux, you have two choices
      • Run HandshakeOne directly. Caution: since libpcap needs root privilege, HandshakeOne must be run with commands like sudo or su.
      • You can register Handshake One as systemd service. Edit HandshakeOne.service as needed(at least ExecStart and WorkingDirectory must be changed to match exact path for the binary) and refer to following command to register the binary as systemd service
        • sudo cp systemd.service /etc/systemd/system
        • sudo systemctl enable HandshakeOne
        • sudo systemctl start HandshakeOne
So...... That's all, folks! I hope you enjoy the application. If you have any comments, opinions, or questions, please leave a comment.

Sunday, January 16, 2022

Flutter/DART: First Impression

All of sudden, I had a chance to briefly review Flutter. Covering all desktop, mobile, web in single programming language, and for web, compiled to Javascript instead of WebAssembly which takes a forever-log real time compilation time - isn't it lovely and beautiful? (Oh, Qt has WebAssembly port, but it takes forever to compile the code, which may be because of that big fat core library).

Someone said that the biggest weakness of Flutter is DART, but I don't agree. The structure of DART is quite interesting, and considering the accessibility from other programming languages it is both understandable(I'm looking at you, Rust). The only thing I dislike is that darn garbage collector, but I think I should admit if DART doesn't want to manually control pointers in any way. Or, if they force RAII in whatever way everyone will be angry. :P

I think, the biggest drawback of Flutter is state management. For other frameworks you don't have to distinguish stateful against stateless widgets, but in Flutter you must do it verbosely. What's more, if build() is called it automatically finds only changes and applies only found changes. For someone the word "automatic" will say "yeah so it's Google!". But as a C++ developer myself, I throw a question like "why do you compare everything when you can recognize changed area?" For me, it looks like that the Flutter developers designed to change everything, yet distinguishing stateful widgets against stateless ones to minimize overhead to GC(the garbage collector). I think, for me, the property binding of Qt is better than this.

I'm afraid the approach of Google in this way would drop the readability of the code. If you read Introduction to widgets, one of the official documentation for Flutter, you see "the separation of responsibility allows greater complexity to be encapsulated in the individual widgets, while maintaining simplicity in the parent". For me, it sounds like a warning to prepare for the hellish burning(......) hell, when you have to change the stateless widget. What if you have to separate some part of stateless to stateful side? And there's no absolute way to prevent you from doing it. Most of the people select Python or Javascript because they provide very flexible development environment for requirements changed in real time, but I think, for Flutter that kind of flexibility would be a bit hard.

I'm not sure about others' opinions, but for me DART is okay but I'm a bit against Flutter. It's like...... it forces specific development process and design concepts. Do I really have to do it this way? I'm not sure.

Flutter/DART를 훑어보다

어쩌다 보니 요즘 뜨고 있는 개발환경인 Flutter를 살펴보게 되었습니다. 단일 프로그래밍 언어에 단일 환경으로 desktop과 mobile과 web을 모두 커버할 수 있는데다가, 심지어 web의 경우 컴파일하다가 날 샐지도 모르는(......) WebAssembly 대신 Javascript로 직접 컴파일된다 하니, 이 어찌 신박하다 하지 않을 수 있겠습니까(Qt도 WebAssembly 포트가 있습니다만, Qt 자체가 덩치가 크기 때문인지 프로그램을 로딩하다가 날밤을 샐 정도로 답답합니다. -_-).

혹자는 Flutter의 최대 단점은 DART다(......)라는 희대의 명언(?)을 내놓기도 했습니다만, 전 이 부분에 대해서는 그다지 동의하지 않습니다. DART의 구조는 매우 흥미로우며, 타 언어 사용자들로부터의 접근성이나 생산성 향상이라는 측면에서 보면 DART의 구조는 최소한 납득할만하다고 생각합니다(Rust 개발자 여러분, 보고 계십니까). 단, 딱 한 가지 제가 싫어하는 부분이라면 역시 그놈의 쓰레기 수집기(garbage collector)인데, 이 부분은 DART가 메모리 수동 제어를 수행하지 않는다는 것을 고려한다면 어쩔 수 없는 한계라고 봅니다. 그렇다고 RAII라던가 하는걸 문법상으로 강제했다간 다들 들고 일어날거고...... -_-

제가 생각하기에 Flutter의 최대 단점은 상태 관리라고 봅니다. 다른 프레임워크들의 경우 stateful과 stateless widget을 따로 구분할 필요가 없는 반면, Flutter는 이를 명시적으로 구분하도록 되어 있습니다. 그리고 build()를 호출할 경우 현재 상태와 이전 상태를 비교해서 변경된 부분을 자동 인식하여 화면을 빠르게 재구성한다고 되어 있습니다. 변경된 부분을 자동으로 인식한다는 이러한 접근 방법은 한편으로는 '오오 구글'이라는 탄성을 가져오게 할 수도 있지만, 지나가던 C++ 개발자의 눈에는 '그냥 변경된 것만 고치지 왜 쓸데없이 모든 부분을 다 비교하지?'라는 생각이 들게 만들더군요. 무조건 전체를 다 고치도록 해놓고, 그 와중에 GC의 오버헤드를 최대한 줄이기 위해 수동으로 stateful과 stateless widget을 나눈게 전부가 아닌가 싶은 생각이 듭니다. 이 부분은 오히려 Qt의 property binding 구조가 훨씬 더 나은 것 같아요.

특히나 구글의 이러한 접근방식은 프로그램이 복잡해질 경우의 가독성을 크게 떨어뜨릴 것 같습니다. Flutter의 공식 문서 중 하나인 Introduction to widgets를 보면 "the separation of responsibility allows greater complexity to be encapsulated in the individual widgets, while maintaining simplicity in the parent"라는 문장이 나오는데, 제게는 저 문장이 나중에 저 stateless widget을 고쳐야 할 경우가 생긴다면 불지옥이 펼쳐질 수도 있다는 소리처럼 들립니다. 이를테면, stateless widget의 일부는 stateless로 남겨두는 대신 일부는 stateful로 가야 하는 상황이 발생한다면 어떻게 될까요? - 그리고 솔직히 그러지 말라는 법도 없습니다. 사람들이 Python이나 Javascript로 가는 이유 중 하나가 실시간으로 발생하는 요구사항에 대한 유연한 대처가 가능하기 때문인데, Flutter는 구조상 이러한 유연성을 가지기가 어렵지 않을까 하는 생각이 듭니다.

다른 분들은 어떻게 생각하실지 모르겠습니다만, 전 DART는 괜찮은데 Flutter는 조금 거부감이 드는군요. 뭐랄까...... 특정한 개발 프로세스와 디자인 컨셉을 무조건적으로 강제하는 듯한 느낌입니다. 굳이 이렇게까지 해야 할까 하는 생각이 드네요.

Thursday, October 28, 2021

Performance Comparison in multithread environment: robin_hood::unordered_map vs. tbb::concurrent_hash_map

 

robin_hood::unordered_map

robin_hood::unordered_map is said to be among the fastest in replacements for std::unordered_map. Personally I found that both in VS2019 and Ubuntu 20.04 the map reduces about half of the time spent against std::unordered_map. However, considering its birth and origin, in multithreaded environment we need to serialize the access to the hashmap using something like mutex. Or, the angry Lord of Segmentation Fault will fire at you(......).

tbb::concurrent_hash_map

Well, if you're in multithreading environment, you can't avoid this: Intel's proud production, tbb::concurrent_hash_map from oneTBB (Threading Building Block). In multithreaded environment container classes from TBB is quite decent. Certainly, I'm sure Intel devoted the best efforts to TBB, as its performance is about similar to std::unordered_map, if I compare time spent for the operation.

Fastest in Single Thread vs. Optimized for Multithread

One shows the best speed in single thread environment, and the other is optimized for multithreading. Then one thing: what if we apply something like std::shared_mutex to robin_hood::unordered_map? Wouldn't it be faster if there are more read than write?

OK OK. I know it's nerdy, but you know, ....... a lot of programmers are nerds. Right? So I applied that to my current development. The program's read-write ratio is about 3:1, and I applied std::shared_mutex.

The winner? TIE(oops). The time spent for both libraries was about the same or similar.

What's Your Choice?

Anyway it depends(tm), I concluded tbb:concurrent_hash_map is better. I think tbb::concurrent_has_map will show better performance if there are more requests, and you can avoid any mistakes on implementation with with its own syntax for forced data lock.

For some time being, I'd reside on tbb::concurrent_hash_map.

One More Thing: QReadWriteLock vs. std::shared_mutex (C++17)

Oh yeah. Another nerdy test. For this I just had to swap lock/mutex only so I did it too. And unexpectedly, std::shared_mutex won this time. Though the Qt Company and the community did a lot of efforts to optimize QReadWriteLock(e.g. https://codereview.qt-project.org/c/qt/qtbase/+/140322/ and https://woboq.com/blog/qreadwritelock-gets-faster-in-qt57.html), after some years there seems to be better(and standard) alternative.
 
Yet anyway, thanks for your hard work, Qt team!

멀티스레드 환경에서의 성능 비교: robin_hood::unordered_map vs. tbb::concurrent_hash_map

robin_hood::unordered_map

robin_hood::unordered_map은 std::unordered_map을 대체하는 hashmap 중 가장 속력이 빠른 라이브러리로 알려져 있습니다. 제 개인적인 테스트로는 VS2019 및 Ubuntu 20.04 환경 모두에서 std::unordered_map에 대비하여 수행시간이 약 절반 수준으로 줄어들더군요. 하지만 이것도 태생이 태생이라, 멀티스레드에서 사용하기 위해서는 mutex 등을 사용해서 접근을 제어해야 합니다. 안 그랬다간 바로 segmentation fault의 불호령이 떨어집니다(.....).

tbb::concurrent_hash_map

한편, 멀티스레드 환경에 편리하게 사용하기 위한 hashmap이면 역시 인텔의 자랑인 oneTBB (Threading Building Block)의 tbb:concurrent_hash_map을 빼놓을 수가 없습니다. 멀티스레딩 환경에서 접근제어를 신경쓰지 않고 사용하기에는 역시 TBB의 컨테이너 클래스들이 가장 무난하다 하지 않을 수 없겠습니다. 확실히 인텔이 TBB에 신경을 각별히 쓴게 보이는 것이, std::unordered_map과 성능이 거의 비슷합니다. 각 기능별 소요시간이 std::unordered_map과 거의 똑같더군요.

싱글스레드 최속 vs. 멀티스레드 최적

한쪽은 싱글스레드 환경 한정으로 속도면에서는 최강자이고, 다른 한 쪽은 멀티스레딩 환경에서 최적화된 성능을 보여줍니다. 그럼 문득 드는 생각 하나...... robin_hood::unordered_map에다가 std::shared_mutex같은걸 씌우면, 어쩌면 읽기가 쓰기보다 더 많은 환경에서는 oneTBB보다 더 빠를 수도 있지 않을까?

아니 뭐..... 뻘짓인건 알지만, 그래도 길고 짧은건 역시 대봐야 아는 거잖아요? 해서 제가 현재 개발중인 프로그램에 한번 적용해 봤습니다. 해당 프로그램은 읽기와 쓰기 비율이 약 3:1 정도로 추산되고, 접근제어에는 std::shared_mutex를 사용했습니다.

그리고 테스트 결과는...... 승자가 없습니다. robin_hood::unordered_map과 tbb:concurrent_hash_map 모두 소요시간이 비슷하더군요.

당신의 선택은?

프로그램의 구조에 따라 다르겠지만, 전 tbb::concurrent_hash_map이 더 낫겠다는 판단을 내렸습니다. 리소스에 대한 접근 요청이 많아질수록 tbb::concurrent_hash_map이 더 우세할 것 같기도 하고, 고유 문법을 통해 리소스 접근시 data lock을 강제하기 때문에 구현상의 실수가 더 줄어들겠다는 것이 저의 판단입니다.

최소한 당분간 멀티스레드 환경에서는 tbb:concurrent_hash_map을 쓰게 될 것 같네요.

부록: QReadWriteLock vs. std::shared_mutex (C++17)

길고 짧은건 역시 대봐야 합니다. 이왕 하는김에, 저 두 가지 사이에서도 뭔가 속도 차이가 있을까 싶은 생각이 들어서 저 두 가지도 실험해봤습니다. 그리고 여기선 std::shared_mutex가 승리했습니다.
Qt Company와 커뮤니티가 QReadWriteLock을 최적화하기 위해 갖은 노력을 다 하긴 했습니다만(예: https://codereview.qt-project.org/c/qt/qtbase/+/140322/ and https://woboq.com/blog/qreadwritelock-gets-faster-in-qt57.html), 몇년 뒤에 더 좋은-그리고 표준화된- 대안이 나온 것 같네요.
 
뭐 어찌됐건, 전 Qt의 모든 노력과 그 결과물을 존중합니다. 그리고 저 또한 그 위에 얹혀(?) 살고 있기도 하고요(웃음).

Tuesday, July 27, 2021

If clang backend in Qt Creator stops working in Ubuntu 20.04 LTS

Ubutntu 20.04 LTS has Qt Creator  4.11.0 in APT, and if you install this and open a source file you'll encounter continuous error message of  The clangbackend process has finished unexpectedly and was restarted. If you open shell you'll see some additional messages like Error in ClangCodeModelServer::documentsClosed: Document '/path/to/sourcefile.cpp' does not exists!

For more than one year, to avoid the message, I turned off clang code model plugin from the Creator, but today I found a simple solution - downgrade clangd from 10.0(stock default install) to 8.0. What a relief!

Now I can enjoy the powerful help from libclang. :)