블로그 이미지
훅크선장

카테고리

분류 전체보기 (362)
사진이야기 (23)
펭귄컴퓨팅 (121)
컴퓨터보안 (84)
절름발이 프로그래머 (59)
하드웨어개조 (23)
멀알려줄까 (35)
홈베이킹&홈쿠킹 (2)
잡다한것들 (15)
Total
Today
Yesterday

달력

« » 2024.11
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

공지사항

태그목록

최근에 올라온 글

FreeDNS 의 서비스에서 생성한, 무료 DDNS 도메인을 OpenWRT 23.05.2 에서 설정하는 방법

 

1.  먼저 서브도메인을 생성한다.

https://freedns.afraid.org/subdomain/

 

개인적으로 선호하는 ignorelist.com 도메인을 이용하여, not4you.ignorelist.com 이라고 서브도메인을 생성한다.

 

2.  Dynamic DNS 탭에서 해당 도메인의 Direct URL을 가져온다.

https://freedns.afraid.org/dynamic/

 

not4you.ignorelist.com.bat 라는 파일이 다운로드 되는데, 해당 내용을 보면,

rem not4you.ignorelist.com
cd %~DP0
wget -q --read-timeout=0.0 --waitretry=5 --tries=400 --background https://freedns.afraid.org/dynamic/update.php?

VEVxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxMg==

 

라고 되어 있는데, 이중에서 ? 문자이후의 VEVxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxMg== 만 필요하다.

 

3. OpenWRT 에 SSH 로그인해서, /etc/config 디렉토리 하단의 ddns 파일을 수정한다.

기본 예제 ddns 파일 내용을 무시하고, 다음과 같이 수정한다.

 

config ddns 'global'
     option ddns_dateformat '%F %R'
     option ddns_loglines '250'
     option ddns_rundir '/var/run/ddns'
     option ddns_logdir '/var/log/ddns'

config service 'Test4You'
     option service_name 'afraid.org-keyauth'
     option use_ipv6 '0'
     option enabled '1'
     option lookup_host 'not4you.ignorelist.com'
     option domain 'not4you.ignorelist.com'
     option username 'freedns 계정 이름'
     option password 'VEVxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxMg==' 
     option ip_source 'network'
     option ip_network 'wan'
     option interface 'wan'
     option use_syslog '2'
     option check_unit 'minutes'
     option force_unit 'hours'
     option retry_unit 'seconds'
     option check_interval '10'
     option force_interval '24'
     option retry_max_count '3'
     option retry_interval '60'

 

Luci 웹에서는 상단 메뉴에서 서비스 -> 동적 DNS 로 이동하여 아래 그림과 같이, “새로운 서비스”를 생성하면 된다. 

 

Posted by 훅크선장
, |

OpenWRT 사이트에 있는 Wireguard의 서버와 클라이언트 설정 내용을 참고로 번역하고, 실제로 구성해 본 내용을 정리한 것입니다.

https://openwrt.org/docs/guide-user/services/vpn/wireguard/server

https://openwrt.org/docs/guide-user/services/vpn/wireguard/client

 

Wireguard 구성 개념에서 원래 Server, Client 라는 단어는 존재하지 않고, 그냥 모두 동등한 Peer 일 뿐입니다만,

인터넷 공인 IP를 가진 라우터를 Server 라 칭하고, NAT 내부에서 사설 IP로 동작하는 라우터를 Client라고 지칭해서,

NAT 내부의 Client 라우터가 인터넷 공인IP의 Server라우터에 연결되어, 클라이언트의 트래픽을 VPN 터널링을 통하여 서버측으로 안전하게 이동시킨 후에 인터넷에 접속되도록 하는 것을 구성한 것입니다. 서버와 클라이언트 설정은 아래에 기술합니다.

 

WireGuard server

0. 소프트웨어 설치
opkg update
opkg install luci-proto-wireguard wireguard-tools luci-app-wireguard


1. config용 파라미터 설정
vpn 포트는 udp 51820 이고, 서버측 vpn 인터페이스 IP 주소는 172.16.9.1/24, fd00:9::1/64
※ 클라이언트측 vpn 인터페이스 IP 주소는 172.16.9.2/24, fd00:9::2/64

VPN_IF="vpn"
VPN_PORT="51820"
VPN_ADDR="172.16.9.1/24"
VPN_ADDR6="fd00:9::1/64"

2. 암호화 키 생성
1) 키 생성
umask go=
wg genkey | tee wgserver.key | wg pubkey > wgserver.pub
wg genkey | tee wgclient.key | wg pubkey > wgclient.pub
wg genpsk > wgclient.psk

2) config용 키값 설정 
VPN_KEY="$(cat wgserver.key)"
VPN_PSK="$(cat wgclient.psk)"
VPN_PUB="$(cat wgclient.pub)"

※클라이언트 설정을 위해서, 생성된 키들의 값들 중에서 다음 키들을  확인하고 별도로 저장해두어야 한다!
root@WG_Server:~# cat wgclient.key 
oPPxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
root@WG_Server:~# cat wgclient.psk
XbUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
root@WG_Server:~# cat wgserver.pub
g6XrNLHkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk=

3. 방화벽
VPN zone을 private 영역으로 만든다.
방화벽 설정을 최소화하기 위해서, VPN zone을 LAN zone에 할당하여 합친다.

config zone 'lan'
option name 'lan'
list network 'lan'
list network 'vpn'
option input 'ACCEPT'
option output 'ACCEPT'
option forward 'ACCEPT'

그리고, WAN zone에서 VPN 서버로 연결을 허용한다.

config rule 'wg'
option name 'Allow-WireGuard'
option src 'wan'
option dest_port '51820'
option proto 'udp'
option target 'ACCEPT'

uci rename firewall.@zone[0]="lan"
uci rename firewall.@zone[1]="wan"
uci del_list firewall.lan.network="${VPN_IF}"
uci add_list firewall.lan.network="${VPN_IF}"
uci -q delete firewall.wg
uci set firewall.wg="rule"
uci set firewall.wg.name="Allow-WireGuard"
uci set firewall.wg.src="wan"
uci set firewall.wg.dest_port="${VPN_PORT}"
uci set firewall.wg.proto="udp"
uci set firewall.wg.target="ACCEPT"
uci commit firewall
service firewall restart

4. VPN 네트워크 인터페이스 설정과 peer 추가
1) Wireguard 인터페이스 설정
uci -q delete network.${VPN_IF}
uci set network.${VPN_IF}="interface"
uci set network.${VPN_IF}.proto="wireguard"
uci set network.${VPN_IF}.private_key="${VPN_KEY}"
uci set network.${VPN_IF}.listen_port="${VPN_PORT}"
uci add_list network.${VPN_IF}.addresses="${VPN_ADDR}"
uci add_list network.${VPN_IF}.addresses="${VPN_ADDR6}"
 
2) VPN peers 추가
uci -q delete network.wgclient
uci set network.wgclient="wireguard_${VPN_IF}"
uci set network.wgclient.public_key="${VPN_PUB}"
uci set network.wgclient.preshared_key="${VPN_PSK}"
uci add_list network.wgclient.allowed_ips="${VPN_ADDR%.*}.2/32"
uci add_list network.wgclient.allowed_ips="${VPN_ADDR6%:*}:2/128"
uci commit network
service network restart

 

WireGuard client

0. 소프트웨어 설치
opkg update
opkg install luci-proto-wireguard wireguard-tools luci-app-wireguard

1. config용 파라미터 설정
vpn 포트는 udp 51820 이고, 클라이언트측 vpn 인터페이스 IP 주소는 172.16.9.2/24, fd00:9::2/64
VPN_SERV 항목에 반드시 서버측의 공인 IP주소 또는 도메인명을 적어준다. 
※ 서버측 vpn 인터페이스 IP 주소는 172.16.9.1/24, fd00:9::1/64

VPN_IF="vpn"
VPN_SERV="xxx.xxx.xxx.xxx"
VPN_PORT="51820"
VPN_ADDR="172.16.9.2/24"
VPN_ADDR6="fd00:9::2/64"
※ xxx.xxx.xxx.xxx 는 반드시 서버의 인터넷 공인 IP 또는 도메인명으로 교체해야 한다.


2. 암호화 키 생성 

※ 서버측에서 생성한 키를 그대로 사용해야만 한다!
1) 키 생성
umask go=
wg genkey | tee wgserver.key | wg pubkey > wgserver.pub
wg genkey | tee wgclient.key | wg pubkey > wgclient.pub
wg genpsk > wgclient.psk

 

root@WG_Server:~# cat wgclient.key 
oPPxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
root@WG_Server:~# cat wgclient.psk
XbUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
root@WG_Server:~# cat wgserver.pub
g6XrNLHkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk=


2) config용 키값 설정 
VPN_KEY="$(cat wgclient.key)"
VPN_PSK="$(cat wgclient.psk)"
VPN_PUB="$(cat wgserver.pub)"
VPN_KEY="oPPxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx="
VPN_PSK="XbUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
VPN_PUB="g6XrNLHkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk="

3. 방화벽
VPN zone을 public 영역으로 만든다.


config zone 'wan'
option name 'wan'
list network 'wan'
list network 'wan6'
list network 'vpn'
option input 'REJECT'
option output 'ACCEPT'
option forward 'REJECT'
option masq '1'
option mtu_fix '1'


방화벽 설정을 최소화하기 위해서, VPN zone을 WAN zone에 할당하여 합친다.
uci rename firewall.@zone[0]="lan"
uci rename firewall.@zone[1]="wan"
uci del_list firewall.wan.network="${VPN_IF}"
uci add_list firewall.wan.network="${VPN_IF}"
uci commit firewall
service firewall restart

4. VPN 네트워크 인터페이스 설정과 peer 추가
1) Wireguard 인터페이스 설정
uci -q delete network.${VPN_IF}
uci set network.${VPN_IF}="interface"
uci set network.${VPN_IF}.proto="wireguard"
uci set network.${VPN_IF}.private_key="${VPN_KEY}"
uci add_list network.${VPN_IF}.addresses="${VPN_ADDR}"
uci add_list network.${VPN_IF}.addresses="${VPN_ADDR6}"
 
2) VPN peers 추가
uci -q delete network.wgserver
uci set network.wgserver="wireguard_${VPN_IF}"
uci set network.wgserver.public_key="${VPN_PUB}"
uci set network.wgserver.preshared_key="${VPN_PSK}"
uci set network.wgserver.endpoint_host="${VPN_SERV}"
uci set network.wgserver.endpoint_port="${VPN_PORT}"
uci set network.wgserver.persistent_keepalive="25"
uci set network.wgserver.route_allowed_ips="1"
uci add_list network.wgserver.allowed_ips="0.0.0.0/0"
uci add_list network.wgserver.allowed_ips="::/0"
uci commit network
service network restart

Resolve race conditions를 해결하고, 필요하다면 동적연결(dynamic connection)을 구성한다.

 

----------------------------------------------------------------------

5. 테스팅
VPN 연결이 확립되면, traceroute 와  traceroute6 명령어로 확인한다.

traceroute openwrt.org
traceroute6 openwrt.org

현재 접속되고 있는 IP 와 DNS 설정을 확인한다.

클라이언트측에 연결된 PC에서 웹브라우저로 다음  URL에 접근해서, 현재 접속된 IP 주소를 확인해본다.

(서버측의 공인 IP 주소가 출력되어야 한다!)

ipleak.net
dnsleaktest.com

6. 문제 발생시, 확인할 사항들
다음의 정보를 분석하고 수집한다.
1) 서비스 재시작
service log restart; service network restart; sleep 10

2) 로그와 상태
logread -e vpn; netstat -l -n -p | grep -e "^udp\s.*\s-$"
 
3) Runtime 설정
pgrep -f -a wg; wg show; wg showconf vpn
ip address show; ip route show table all
ip rule show; ip -6 rule show; nft list ruleset

4) 지속 설정 
uci show network; uci show firewall; crontab -l

 

Posted by 훅크선장
, |

0. 구성도
1) Site A 홈라우터 (메인 측, 서버 측)

WAN 네트워크 주소(공인 IP) : 86.45.69.6/28
LAN 네트워크 주소 대역 : 192.168.1.1/24
Wireguard IP 주소 : 10.10.10.1/32
라우터에 연결된 PC A : 192.168.1.153


2) Site B 홈라우터 (클라이언트 측)

WAN 네트워크 주소(공인 IP) : 205.79.33.106/25 ※ 공인 IP가 없고, 네트워크 상위에 별도의 홈라우터가 있는 NAT 환경 내에 있어도 상관없다!!
LAN 네트워크 주소 대역 : 192.168.2.1/24
Wireguard IP 주소 : 10.10.10.2/32
라우터에 연결된 PC B : 192.168.2.153

1. Site A 홈라우터 (메인 측, 서버 측) 설정
1) 새로운 interface 추가 :  Wireguard VPN  새로 생성
이름 : site_a
Private Key Gen 키를 눌러서, 키쌍 생성
Listen Port : 51820
IP addresses  : 10.10.10.1/32

고급설정 에서 MTU : 1412 로 설정
Firewall Setting 에서  assign fw zone : vpn 입력후 엔터 치면, 새롭게 생성시켜줌

2) Firewall 방화벽 쪽으로 이동해서,
vpn 존에 대해서, lan to vpn 
              vpn to wan 을 허용

Port Forward 설정
이름   wg, 
프로토콜 UDP,  
source : wan.  
external port 51820. 
Dest: vpn
Internal IP. 10.10.10.1/32 
Internal port 51820

3) Site A 홈라우터의 외부 공인 IP 주소를 복사해둔다. (유투브 비디오에서는 86.45.69.6/28 이었음.)
   클라이언트가 접속해야되는 IP 이기 때문에.
   또한, 클라이언트 접속을 위해서는 1.1)에서 생성한 키쌍에서 Public Key를 복사해두어야 한다.
   ※ 여기 Site A 홈라우터로 접속하려면 반드시, 서버의 공인 IP주소와 포트번호, 그리고 Public Key가 있어야 한다!!

4) Luci 웹 화면에서 Status -> Wireguard 로 가면, 인터페이스가 정상적으로 생성된 것을 볼 수 있다.
   ※ 아직 어떤 Peer 도 생성하지 않았으므로, 접속은 없을 것이다.

2. Site B 홈라우터 (클라이언트 측) 설정
1) 새로운 interface 추가 :  Wireguard VPN  새로 생성
이름 : site_b
Private Key Gen 키를 눌러서, 키쌍 생성
Listen Port : 51820
IP addresses : 10.10.10.2/32

고급설정 에서 MTU : 1412 로 설정
Firewall Setting 에서  assign fw zone : vpn 입력후 엔터 치면, 새롭게 생성시켜줌
Peers에서 새로운  peer 추가
      Description : site_a
      Public Key : 1.1)에서 생성한 키쌍으로부터 1.3)에서 복사해둔 Public Key를 가져온다.
      Allowed IPs : 10.10.10.0/24.  192.168.1.0/24 ※ site_a 서버측 IP 주소를 모두 등록시켜준다.
      Routed Allowed IPs : checked
      Endpoint Host : 1.3)에서 복사해둔 site_a 서버측의 공인 IP 주소를 써준다.
      Endpoint Port : 51820 ※ site_a에서 정했던 포트번호 그대로 입력

      Persistent Keep Alive : 25 ※ 클라이언트 쪽의 공인 IP가 없는 경우에만 추가적으로 설정 

2) Firewall 방화벽 쪽으로 이동해서,
vpn 존에 대해서, lan to vpn 
              vpn to wan 을 허용

Port Forward 설정
이름    : wg 
프로토콜 : UDP  
source : wan  
external port : 51820. 
Dest   : vpn
Internal IP : 10.10.10.2/32 
Internal port : 51820

Luci 웹 화면에서 Network -> Interfaces 로 가서, wireguard 인터페이스 재시작

3) Site B 홈라우터의 외부 공인 IP 주소를 복사해둔다. (유투브 비디오에서는 205.79.33.106/25 이었음.)
   서버쪽에서 접속해야되는 IP 이기 때문에. ※ 공인 IP가 없고, 네트워크 상위에 별도의 홈라우터가 있는 NAT 환경 내에 있다면, 복사하지 않아도 된다. 무시하면 된다.

   또한, 서버쪽 접속을 위해서는 2.1)에서 생성한 키쌍에서 Public Key를 복사해두어야 한다.
   ※ 여기 Site B 홈라우터로 접속하려면 반드시, 클라이언트의 공인 IP주소와 포트번호, 그리고 Public Key가 있어야 한다!!

4) Luci 웹 화면에서 Status -> Wireguard 로 가면, 인터페이스가 정상적으로 생성된 것을 볼 수 있다.

3. Site A 홈라우터 (메인 측, 서버 측) 설정 수정(클라이언트 쪽 정보 추가)
1) Wireguard VPN 인터페이스 site_a 로 가서,
Peers에서 새로운  peer 추가
      Description : site_b
      Public Key : 2.1)에서 생성한 키쌍으로부터 2.3)에서 복사해둔 Public Key를 가져온다.
      Allowed IPs : 10.10.10.0/24.  192.168.2.0/24 ※ site_b 클라이언트측 IP 주소를 모두 등록시켜준다.
      Routed Allowed IPs : checked
      Endpoint Host : 2.3)에서 복사해둔 site_a 서버측의 공인 IP 주소를 써준다. ※ 공인 IP가 없다면, 무시하고 비워둔다.
      Endpoint Port : 51820 ※ site_b에서 정했던 포트번호 그대로 입력

      Persistent Keep Alive : 25 ※ 클라이언트 쪽의 공인 IP가 없는 경우에만 추가적으로 설정 

※ 이 구성은 둘 다 peer 개념으로 보고 있어야 하고, 양쪽에서 모두 인터넷이 되는 상황이다.

vpn을 통해서, 양측 LAN 영역 까지는 도달이 가능하다.

하지만, LAN 영역까지만 도달하는 것이고, 인터넷 트래픽까지 vpn을 통해서 가능 것은 아니다!!!

client쪽의 모든 트래픽을 VPN tunnel로 모두 보내는 것은 별도의 추가 라우팅 설정 등이 필요하다!(아직 작업중)

 

 

Posted by 훅크선장
, |

CZNIC 라는 체코 회사에서 만든 Turris Omnia, 오픈소스 OpenWRT 기반으로 만들어진 매우 훌륭한 라우터이지만, 이미 몇 년전에 회사가 망했는지? 더이상 업데이트도 안되고 있어서, 결국 OpenWRT 펌웨어로 바꿔서 사용해야 한다.

https://openwrt.org/toh/turris/turris_omnia

 

[OpenWrt Wiki] Turris CZ.NIC Omnia

U-Boot 2015.10-rc2 (Aug 18 2016 - 20:43:35 +0200), Build: jenkins-omnia-master-23 SoC: MV88F6820-A0 Watchdog enabled I2C: ready SPI: ready DRAM: 2 GiB (ECC not enabled) Enabling Armada 385 watchdog. Disabling MCU startup watchdog. Regdomain set to ** MMC:

openwrt.org

 

0. 먼저 해당장비의 U-Boot를 업데이트 해줘야 한다.

Update U-Boot if needed

Log into the factory OS (TurrisOS), and take note of the U-Boot version installed on your device: strings /dev/mtd0 | grep “U-Boot 20”. Alternatively, watch the serial console when booting.

Only if you have a very old Turris Omnia with U-Boot 2015.10-rc2:

  1. Make sure that you are running TurrisOS >= 5.2, and install the turris-nor-update package.
  2. Execute nor-update, to bring U-Boot to a more recent version (which supports OpenWrt's boot script).
  3. After rebooting, check the U-Boot version again. It should be at least U-Boot 2019.07.

https://repo.turris.cz/hbs/medkit/omnia-medkit-latest.tar.gz

 

※ Omnia 복구모드 설명 

https://docs.turris.cz/hw/omnia/rescue-modes/

 

1. USB를 이용한 Stock 펌웨어 복구 모드 

https://www.youtube.com/watch?v=ZrWzpsxqaRU

 

가장 최신?의 Stock 펌웨어 omnia-medkit-latest.tar.gz 파일을 FAT32로 포맷된 USB 장치의 root 영역에 복사한 다음,

장비의 USB 포트에 꽂고나서, 위 복구 동영상과 같이, 장비 후면의 reset 버튼을 길게 누르고, 전면 LED가 4개 켜지는 순간( LED 숫자 2 까지 불이 켜지면,) reset 버튼에서 손을 뗀다. 그럼 USB 장치에 있는 펌웨어로 장비가 자동으로 복구된다.

 

2. Rescue Shell 모드를 이용한 OpenWRT 펌웨어 설치

https://downloads.openwrt.org/releases/23.05.2/targets/mvebu/cortexa9/openwrt-23.05.2-mvebu-cortexa9-cznic_turris-omnia-sysupgrade.img.gz

1) 상위와 같은 최신 버전의 펌웨어 파일을 컴퓨터로 다운로드한다. 그리고, 해당 파일을 gunzip으로 압축을 풀어서, openwrt-23.05.2-mvebu-cortexa9-cznic_turris-omnia-sysupgrade.img 파일로 만듭니다.

2) img 파일을 FAT32로 포맷된 USB 장치의 root 영역에 복사한 다음, 장비의 USB 포트에 꽂고나서, 장비 후면의 reset 버튼을 길게 누르고, 전면 LED가 5개 켜지는 순간( LED 숫자 3 까지 불이 켜지면,) reset 버튼에서 손을 뗀다.

3) 장비가 2) 과정에 의해 rescue shell 모드가 되면, 노트북의 IP를 192.168.1.2/24로 설정하고, 장비에 192.168.1.1 로 접속한다. 이때, 반드시 랜 케이블은 장비의 LAN 포트 4번에 연결하여야 한다. (※ 다른 포트에 연결하면 안된다!!)

ssh root@192.168.1.1  명령어로 접속할때, 키 교환 에러가 발생하면,

ssh -v -oHostKeyAlgorithms=+ssh-rsa root@192.168.1.1

명령어로 접속하면 된다.

4) rescue shell로 접속하면, 아래 명령어로 먼저 usb 장치를 마운트한다.

mkdir mnt

mount /dev/sda1 /mnt

5) 다음 명령어로 OpenWRT 펌웨어를 설치한다.

dd if=/mnt/openwrt-23.05.2-mvebu-cortexa9-cznic_turris-omnia-sysupgrade.img of=/dev/mmcblk0 bs=4096 conv=fsync

Posted by 훅크선장
, |

WireGuard Installation on OpenWRT 23.05.2

2024년 2월 현재, 인터넷 상에서 다양한 설치 글이 존재하나, 직접 실습해보고 검증해본 결과 아주 조금씩 놓치는 부분들이 있어서,

내 상황에 맞게 수정해서 다음과 같이 정리했습니다.

참고할만한 동영상 및 정보 : https://www.youtube.com/watch?v=6NIJcsJsRaM

 

1. 소프트웨어 설치
opkg update
opkg install luci-proto-wireguard wireguard-tools luci-app-wireguard qrencode
/etc/init.d/network restart

혹은 LuCI → System → Software에 접속하여 반드시 관리도구: 하단 “Update lists...” 버튼을 클릭하여 패키지 목록을 가져온 다음, 
위의 네 개 패키지를 찾아 설치한다. 
그 후 LuCI → System → Startup → Initscripts → network에서 restart를 누른다.

2. Wireguard 인터페이스 생성
LuCI → Network → Interfaces에서 "새로운 인터페이스 추가..."을 클릭한다.

이름: wg0 (인터페이스명을 지정할때, 일반적인 디바이스명 규칙을 따른 것인데, wireguard, vpn 등 원하는 이름을 넣으면 된다.)
protocol: WireGuard VPN
private key: 
public key: 
(키쌍은 "Generate new key pair" 버튼을 누르면 생성된다. 간편하게 생성하면 된다.)
listen port: 49152 (49152 ~ 65535 중에서 골라도 되고, 자기가 지정해도 된다. 방화벽을 열어줘야 하기 때문에, 적당한 포트를 골라서 사용한다. 다른 매뉴얼 등을 보면, 일반적으로 51820 포트번호를 사용하는 것 같다.)
ip addresses: 172.16.8.1/24 (해당 인터페이스에 할당할 IP이다. 사설 IP대역을 하나 지정하면 된다. 10.9.0.1/24, 192.168.253.1/24 등으로 설정하면 된다. 이 IP가 게이트웨이 역할을 하므로, Peer 설정할때, 해당 IP 대역을 기억하고 있어야 한다.)
※ 만약 접속할 Peer 가 여러 곳이라면, 반드시 IP 주소를 여러 개로 나누어 등록해야 한다. 172.16.8.1/24 에 Peer 첫번째, 172.27.10.1/24 에 Peer 두번째 이런 식으로, 다른 Peer들끼리 같은 IP를 사용하면, 두번째 접속하는 Peer는 통신이 안된다!! 네트워크 라우팅 충돌이 발생하므로! 주의!!!

※ Peer 개수가 여러개 라면, 172.16.8.1/24 가 아닌, 172.16.8.1/32 와 같이 Host IP 주소로 딱 지정해주는 것도 좋은 방법이다.
고급설정 탭으로 이동해서, MTU를 1412로 설정해준다.

Peers 탭으로 이동해서, 연결되는 Peer 혹은 클라이언트를 설정한다.
먼저 “피어 추가” 버튼을 눌러준다. 그리고 다음과 같이 입력한다.
설명 : My Peer (접속대상에 대한 이름을 적당하게 지정해준다. Client01 등과 같이 임의로 정해준다.)
공개 키: 
private key: 
(키쌍은 "Generate new key pair" 버튼을 누르면 생성된다. 간편하게 생성하면 된다.)
Preshared Key: 꼭 사용할 필요가 없다.
Allowed IPs: 172.16.8.2/24(현재 설정하는 피어(클라이언트)가 Wireguard VPN 터널 안에서 쓰도록 허용한 IP 대역이다. 앞의 서버 측 설정할 때 사용했던 IP 대역과 특정 IP 하나를 지정해서 써주면 된다.)
※ 만약 접속할 Peer 가 여러 곳이라면, 반드시 IP 주소를 여러 개로 나누어 등록해야 한다. 172.16.8.2/24 에 Peer 첫번째, 172.27.10.2/24 에 Peer 두번째 이런 식으로, 다른 Peer들끼리 같은 IP를 사용하면, 두번째 접속하는 Peer는 통신이 안된다!! 네트워크 라우팅 충돌이 발생하므로! 주의!!!

※ Peer 개수가 여러개 라면, 172.16.8.2/24 가 아닌, 172.16.8.2/32 와 같이 Host IP 주소로 딱 지정해주는 것도 좋은 방법이다.

Route Allowed IPs : 꼭 체크해준다.
Endpoint Host: XXX.XXX.XXX.XXX (반드시 서버측의 wan IP 주소 혹은 도메인명을 적어준다. 현재 설정하고 있는 OpenWRT 공유기의 WAN 인터넷 공인 IP 주소가 입력되어야 한다.)
Endpoint Port: 49152 (앞의 Wireguard 인터페이스에서 지정한 listen port에 지정했던 포트 번호를 넣는다.)

※ 공인IP 주소를 가지지 않는 클라이언트 접속이므로, Endpoint 2개 항목은 입력할 필요가 없다.
Persistent Keep Alive: 25 (일종의 권장값이다. NAT 환경 등에서 접속을 유지하기 위해서 사용하는 값이다.)

입력이 완료되면, Configuration Export 옆의 "Generate configuration..." 버튼을 누르면, 현재 Peer(클라이언트)의 설정을 볼 수 있다.
설정파일의 내용을 가져다가, Peer(클라이언트)의 설정에 사용할 수 있다. 
QR Code를 가지고, 모바일 디바이스에 바로 Peer(클라이언트) 설정을 편하게 입력할 수 있다.

이상의 내용은 SSH 접속을 통하여, 직접 설정 파일을 가지고 만들어 낼 수도 있다. 
/etc/config/network 파일을 편집하여서 할 수도 있다. 아래처럼 추가하면 된다.

config interface 'wg0'
    option proto 'wireguard'
    option private_key '[비밀키 내용 입력]'
    option listen_port '49152'
    list addresses '172.16.8.1/24'
    option mtu '1412'

config wireguard_wg0
    option description 'My Peer'
    option public_key '[공개키 내용 입력]'
    option private_key '[비밀키 내용 입력]'
    list allowed_ips '172.16.8.0/24'
    option route_allowed_ips '1'
    option endpoint_host 'XXX.XXX.XXX.XXX'
    option endpoint_port '49152'
    option persistent_keepalive '25'


생성된 Peer(클라이언트)의 설정파일은 다음과 같다.

[Interface]
PrivateKey = [비밀키 내용 입력]
Address = 172.16.8.2/24
ListenPort = 49152
DNS = 192.168.xxx.1 (서버측 공유기의 LAN IP 주소가 DNS를 담당한다.)

[Peer]
PublicKey = 공개키 내용 입력]
# PresharedKey not used
AllowedIPs = 0.0.0.0/0, ::/0 (AllowedIPs는 VPN을 거칠 IP를 의미한다. 0.0.0.0/0으로 되어있다면 모든 접속을 VPN을 거쳐서 하게 된다.)
Endpoint = XXX.XXX.XXX.XXX:49152
PersistentKeepAlive = 25

3. 방화벽 Zone 설정
공유기 내부의 방화벽을 VPN이 사용할 수 있도록 열어주어야 한다.
LuCI → Network → Firewall에서 설정 할 수 있다. 
General Settings 탭에서 Zones 하단에 “Add”를 눌러 새로운 Zone을 만든다.

Name: wg0_vpn (원하는 이름으로 선정한다. wireguard, myvpn 등을 사용할 수도 있다.)
Input: Accept
Output: Accept
Forward: Reject
Masquerading: 체크 (VPN 네트워크에서 다른 영역으로 통신을 하려면, 반드시 필요)
MSS clamping: 체크 (VPN 네트워크에서 다른 영역으로 통신을 하려면, 반드시 필요)
Covered Networks: wg0 (이전 인터페이스쪽에서 새로 생성한 인터페이스 명칭을 찾아서 지정한다.)
Allow forward to destination zones: VPN Zone에서 다른 Zone으로 접속을 허용하는 곳으로, LAN 영역과 WAN 영역을 접근하기 위해서는 lan과 wan을 모두 선택해서 지정한다. 네트워크 구성에 따라 lan과 wan을 하나씩만 선택할 수 있으나, 일반적으로는 lan과 wan 모두를 선택하는 것이 좋다.
Allow forward to source zones: 다른 Zone에서 VPN Zone으로 접근을 허용하는 것인데, 정말 특별한 경우가 아니면, lan만 선택한다.

이 작업은 /etc/config/firewall을 수정하여서 할 수도 있다.
config zone
    option name 'wg0_vpn'
    option input 'ACCEPT'
    option output 'ACCEPT'
    option forward 'REJECT'
    option masq '1'
    option mtu_fix '1'
    list network 'wg0'

config forwarding
    option src 'wg0_vpn'
    option dest 'lan'

config forwarding
    option src 'wg0_vpn'
    option dest 'wan'

config forwarding
    option src 'lan'
    option dest 'wg0_vpn'

4. 방화벽 Traffic Rule 설정

이제 서버측의 접속 포트 Listen Port를 열어준다.

Traffic Rules 탭에 들어가 “Add”를 누른다.

Name: Allow-Wireguard (기본적으로 사용된는 작명 규칙에 맞게 Allow-Wireguard로 한다.)
Protocol: UDP (Wireguard VPN은 UDP만을 사용하므로, 기본 설정된 TCP는 제거하고,UDP 하나만 지정한다.
Source zone: wan (인터넷쪽 공유기의 외부에서의 접속이므로 wan을 지정한다.)
Destination port: 49152 (앞의 과정에서 지정했던 서버 포트번호 49152을 입력한다.)
Action: accept (포트 접속 허용 규칙이므로, accept를 지정한다.)

이 작업은 /etc/config/firewall을 수정하여서 할 수도 있다.

config rule
    option name 'Allow-Wireguard'
    list proto 'udp'
    option src 'wan'
    option dest_port '49152'
    option target 'ACCEPT'

5. 접속 테스트
클라이언트 쪽에 Wireguard 앱을 설치하고, 앞의 인터페이스 -> wg0 수정 -> Peers 수정 에 가면,
Configuration Export 옆의 "Generate configuration..." 버튼을 누르면, 현재 Peer(클라이언트)의 설정을 볼 수 있다.

Peer(클라이언트)의 설정파일 내용을 복사해서, PC에 설치한 Wireguard 앱의 새로운 Tunnel 설정으로 만들어서 사용할 수 있고,
또는 QR Code를 가지고, 모바일 디바이스에 바로 Peer(클라이언트) 설정을 편하게 입력할 수 있다.
접속을 활성화하면,
Luci에서 Status -> Wireguard 로 가보면, 접속 현황을 볼 수 있다.
※ logread -f 명령에 의한, 프로세스 접속로그는 나타나지 않는다. 커널 VPN이라서... OpenVPN은 이 명령어로 접속로그를 볼 수 있지만, Wireguard는 안된다.

6. 기기 재부팅
커널 VPN 이다보니, 설정 변경이나 Peer 추가 등의 작업 후에는 반드시 기기를 재부팅해야만 한다. 
매우 불편한 점이기는 하다~!

6. 인터페이스 재시작
네트워크 -> 인터페이스  로 가서, wg0 인터페이스를 재시작한다.

※ 재부팅을 해서, 커널을 다시 시작해야 한다고 하는 경우도 있다 한다. 인터페이스 재시작으로 vpn 터널이 활성화되지 않는다면, 기기 재부팅을 해보는 것도 방법이다. 

Posted by 훅크선장
, |

https://www.youtube.com/watch?v=ZS3vXA0s2qU 를 참고하여, 실습을 통해 검증해서 쓴 글입니다.

 

준비물: 2대의 OpenWRT 장치, TAP Client 장비는 VLAN 구성이 가능한 장비여야 편리하다.

1. TAP 서버 설정
패키지 설치 : openvpn-openssl openvpn-easy-rsa luci-app-openvpn
서버의 WAN IP 주소 : 10.0.0.2
서버의 LAN IP 주소 : 192.168.2.1

※ LAN 영역 DHCP Server 일반설정에서 시작 IP주소 끝자리를 100에서 10으로, 150을 20으로 줄여준다.
※ LAN 영역 DHCP Server 고급설정에서 Force 체크해준다!

방화벽 설정에서 OpenVPN 서버가 사용할 포트를 열어준다.
config rule
    option name 'Allow-OpenVPN'
    list proto 'udp'
    option src 'wan'
    option dest_port '1194'
    option target 'ACCEPT'

서버와 클라이언트 인증서 파일들을 생성한다.
openvpn 서버 설정 파일을 입력한다.
필요한 파일은 dh2048.pem ca.crt server.crt server.key
option server_bridge 의 IP 주소 대역은 혼동되지 않는 것을 쓰면 된다.
192.168.50.x 쓰는 것도 좋지만, 구분되기 쉽게 172.16.8.x 대역을 써도 된다.

LAN 인터페이스의 브릿지 인터페이스 설정에 tap0를 추가해준다.(기존에 이미 lan과 wireless가 연결된 브릿지 인터페이스이다.)

2. TAP 클라이언트 설정
패키지 설치 : openvpn-openssl luci-app-openvpn
필요한 파일 : 
클라이언트의 WAN IP 주소 : 10.0.0.3
클라이언트의 LAN IP 주소 : 192.168.3.1
클라이언트의 VPN IP 주소 : 192.168.2.2

※ LAN 영역 DHCP Server 고급설정에서 Force 체크해준다!
※ 공유기를 설정하기 전에, 미리 포트 4번에 연결해야 한다! 왜냐하면, 포트 1번을 VPN에 할당해야 하기 때문에...
먼저 스위치 기능에서 VLAN 3 을 추가하고, 포트 LAN 1을 VLAN 3에만 가입시킨다. 
(tagged, off, untagged 를 아래와 같이 지정한다.)

VLAN ID    CPU(eth0)    LAN 1         LAN 2        LAN 3       LAN 4        WAN
      1             tagged         off              untagged untagged untagged   off
      2             tagged         off              off            off             off               untagged
      3             tagged         untagged  off            off             off               off

새로운 인터페이스 lanvpn을 생성하고, Static address, VLAN eth0.3 을 지정하고,
IP address는 192.168.2.2/24를 지정

방화벽 Zone 에 역시 lanvpn을 생성하고 Forward를 accept로 바꾸고, Covered networks에 lanvpn을 지정한다.
그리고, Allow forward to destination zones: 에 WAN을 추가한다.

openvpn 클라이언트 설정 파일을 입력한다.
필요한 파일은 3개뿐이다. ca.crt client.crt client.key
서버의 IP 또는 도메인 주소 그리고 포트번호만 잘 확인하면 된다.

openvpn 접속을 먼저 완료하고,
lanvpn 인터페이스에 할당된 디바이스를 Bridge Interfaces로 바꾼다. eth0.3 에 부가적으로 tap0 디바이스를 추가한다.
※ 최신버전 OpenWRT에서는 Bridge 디바이스를 아예 별도로 생성해야 한다.

LAN 1 포트에 연결하면, 바로 OpenVPN 서버의 LAN 영역 IP 192.168.2.x 할당받고, 접속가능하다.
대신 다른 클라이언트 영역에는 접근할 수가 없다. 192.168.3.x 접근 불가.

Posted by 훅크선장
, |

import os
import asyncio
from playwright.async_api import async_playwright
from datetime import datetime

# 현재 실행 디렉토리를 가져온다.
current_dir = os.getcwd()
# 디렉토리의 맨 마지막에 / 구분자의 존재 여부를 확인하여, 항상 / 로 끝나도록 만든다.
if current_dir[-1] != '/':
current_dir = current_dir + '/'
# 현재 실행 디렉토리를 출력한다.
#print(current_dir)

# 비동기 실행 메인 함수 
async def main():
    # 현재 날짜와 시간을 얻어오고, 년월일 시분초 형식으로 구성한다.
    current_datetime = datetime.now().strftime("%Y-%m-%d %H-%M-%S")
    #print("Current date & time : ", current_datetime)
    # 년월일 시분초 형식으로 문자열을 생성한다.
    str_current_datetime = str(current_datetime)
    
    # 비동기 playwright 객체를 가지고 실행
    async with async_playwright() as p:
            browser = await p.chromium.launch(headless=True) # 브라우저 생성
            page = await browser.new_page() # 브라우저의 페이지 생성

            await page.goto("https://hook.tistory.com/", timeout=10000) # ※ 접속불가시 timeout 에러 발생!! 에러처리 필요

            # 접속된 페이지의 스크린샷을 뜨고, 지정된 파일이름으로 현재 실행디렉토리 밑에 생성한다.
            await page.screenshot(path=current_dir + 'capture/'+ f'example-chromium-{str_current_datetime}.png')
            print(await page.title())

            #print(await page.locator(
            #       "//div[@class='entry']/div[@class='titleWrap']/div[@class='info']/span[@class='date']"
            #       ).all_text_contents())
            #print(await page.locator(
            #       "//div[@class='entry']/div[@class='titleWrap']/h2/a"
            #       ).all_text_contents())
            #print(await page.locator(
            #       "//div[@class='entry']/div[@class='titleWrap']/h2/a"
            #       ).get_attribute('href').all())
            for a_loc in await page.locator("//div[@class='entry']/div[@class='titleWrap']").all():
                print(await a_loc.locator("//h2/a").text_content())
                print(await a_loc.locator("//div[@class='info']/span[@class='date']").text_content())
                print(await a_loc.locator("//h2/a").get_attribute('href'))
                print("----------------------------------------------------------------------------------------")

            await browser.close() # 브라우저를 종료

# 비동기 실행 
asyncio.run(main())

Posted by 훅크선장
, |

"""
블로그에 있는 글의 제목들을 추출하는 xpath 구문
page.locator("//div[@class='entry']/div[@class='titleWrap']/h2/a").all_text_contents()

블로그에 있는 글의 작성일자를 추출하는 xpath 구문
page.locator("//div[contains(@class,'entry')]/div[@class='titleWrap']/div[@class='info']/span[@class='date']").first.text_content()
page.locator("//div[@class='entry']/div[@class='titleWrap']/div[@class='info']/span[@class='date']").last.text_content()
page.locator("//div[@class='entry']/div[@class='titleWrap']/div[@class='info']/span[@class='date']").all_text_contents()

블로그에 있는 글의 작성일자를 추출하는 css 구문
page.locator('div:nth-child(3) > div.titleWrap > div > span.date').text_content()

블로그에 있는 글의 개별 링크 URL들을 추출하는 xpath 구문
link_locators = page.locator("//div[@class='entry']/div[@class='titleWrap']/h2/a").all()
for l_loc in link_locators:
print(l_loc.get_attribute('href'))
print(l_loc.text_content())

※ locator() 내부에서 명시적으로 css=   xpath= 를 삽입할 수 있지만, 꼭 쓸 필요는 없다.
page.locator("xpath=/html/body/div[1]/div/div[2]/div[2]/div/div[3]/div[1]/div/span[2]").text_content()
"""


from playwright.sync_api import Playwright, sync_playwright, expect
import os
from datetime import datetime

def run(playwright: Playwright) -> None:

  # Get Current Working Directory
  current_dir = os.getcwd()
  if current_dir[-1] != '/':
  current_dir = current_dir + '/'
  #print(current_dir)

  # Get Current Date and Time
  current_datetime = datetime.now().strftime("%Y-%m-%d %H-%M-%S")
  #print("Current Date & Time : ", current_datetime)
  # Convert datetime obj to string
  str_current_datetime = str(current_datetime)

  ## 브라우저가 화면에 나타나지 않도록 headless옵션을 켜고, 크롬브라우저를 사용합니다.
  ## headless=False 이면, 브라우저가 화면에 나타납니다.
  browser = playwright.chromium.launch(headless=True, channel="chromium")
  context = browser.new_context()

  ## 브라우저로 웹페이지를 실행합니다
  page = context.new_page()

  ## 아래 URL 주소로 이동합니다.
  page.goto("https://hook.tistory.com/")

  ## 웹 페이지의 스크린샷을 뜬다. path= 파라미터를 사용하여 저장경로를 별도로 지정한다.
  #page.screenshot(path=current_dir + 'capture/'+ f'screenshot-{str_current_datetime}.png')

  entry_locators = page.locator("//div[@class='entry']/div[@class='titleWrap']").all()
  for a_loc in entry_locators:
    print(a_loc.locator("//h2/a").text_content())
    print(a_loc.locator("//div[@class='info']/span[@class='date']").text_content())
    print(a_loc.locator("//h2/a").get_attribute('href'))
    print("----------------------------------------------------------------------------------------")

  ## 잠시 중지
  #page.pause()

  # 브라우저 종료
  context.close()
  browser.close()

# 주 실행함수 
with sync_playwright() as playwright:
    run(playwright)

Posted by 훅크선장
, |

이전에 리모콘만으로 설정 가능한 LED 벽시계의 리모콘 분실로 인하여, 아두이노를 가지고 IR 리모콘을 만들어보는 별 쓸모없는 작업을 해보았다. 그런데, 가지고 있는 잡동사니 보드 중에 예전 DEFCON 컨퍼런스를 갔을때, Sparkfun 워크숍을 참가해서 받아온 Roshamglo Badge Kit을 발견했다. Roshamglo 배지 키트는 IR 송신부와 수신부, 그리고 5축 스위치를 가졌기에, 간단한 IR 리모콘으로 만들기에 최적인 보드라고 생각한 것이 실수였다!!!

 

일단 Roshamglo 배지 키트는 2017년에 만들어졌고, 일종의 재미로 만든 보드이다보니, 이젠 더이상 아두이노 IDE 상에서 소프트웨어 라이브러리 지원이 안된다. (아두이노 IDE 소프트웨어를  1.6.10~1.8.x 버전대를 사용하더라도, 보드에 대한 기본적인 소프트웨어 지원 패키지가 없기 때문에, 아두이노 IDE에서 도저히 보드를 연결할 수가 없다.)

 

여기서 포기하면, 하드웨어쟁이가 될 수 없다.

그래서, Roshamglo의 기본이 되는 ATtiny84 MCU를 기준으로 아두이노 ISP를 사용하여 프로그래밍을 시도하였다.

 

Roshamglo Badge Kit 에 대한 정보는 아래의 링크들에서...

https://learn.sparkfun.com/tutorials/roshamglo-hookup-guide/all

 

Roshamglo Hookup Guide - SparkFun Learn

Introduction <!--- ###Attributes Before you begin, make sure you have filled out all required fields found under the Attributes tab. The author is responsible for for the following: * **Title** - Pick a title that makes sense for Search Engine Optimization

learn.sparkfun.com

https://learn.sparkfun.com/tutorials/hack-your-roshamglo-badge/all

 

Hack Your Roshamglo Badge - SparkFun Learn

Introduction So you've put together your Roshamglo badge, and now you want more? Well, we can help you with that. In addition to playing infrared (IR) Rock-Paper-Scissors, the Roshamglo board can be reprogrammed with user-created code. This will allow you

learn.sparkfun.com

https://learn.sparkfun.com/tutorials/roshamglo-project-tv-b-gone/introduction

 

Roshamglo Project: TV-B-Gone - SparkFun Learn

Retired KIT-14130 The SparkFun Roshamglo is the new and fun way to play Rock-Paper-Scissors with your friends! The board uses the ATtiny84, and…

learn.sparkfun.com

 

ATtiny84  프로그래밍에 대한 정보는 다음 링크들에서...

https://github.com/SpenceKonde/ATTinyCore

 

GitHub - SpenceKonde/ATTinyCore: Arduino core for ATtiny 1634, 828, x313, x4, x41, x5, x61, x7 and x8

Arduino core for ATtiny 1634, 828, x313, x4, x41, x5, x61, x7 and x8 - GitHub - SpenceKonde/ATTinyCore: Arduino core for ATtiny 1634, 828, x313, x4, x41, x5, x61, x7 and x8

github.com

https://www.instructables.com/Arduino-Uno-to-Program-ATTINY84-Arduino-V-185/

 

Arduino Uno to Program ATTINY84 (Arduino V. 1.8.5)

Arduino Uno to Program ATTINY84 (Arduino V. 1.8.5): Using the Arduino Uno to program ATTINY84-20PU (Digikey item # ATTINY84-20-PU-ND). This Instructable shows how to use the Arduino platform to work with physically smaller processors, such as the ATtiny84

www.instructables.com

https://www.instructables.com/Program-an-ATtiny44458485-with-Arduino/

 

Program an ATtiny44/45/84/85 With Arduino

Program an ATtiny44/45/84/85 With Arduino: This tutorial gives provides the steps to set up, program, and test an ATtiny44/45/84/85 with an Arduino. It is also provides some explanations as to the inner workings of AVR chips in general.

www.instructables.com

https://www.hackster.io/350166/getting-started-with-attiny84-c920ee

 

Getting started with Attiny84

learn how to program Attiny84 with this custom Breakout board with ams1117 for basic level projects like blinking LED and stuff. By Arnov Sharma and JLCPCB.

www.hackster.io

---------------------------------------------------------------------------------------------------------------------

ATtiny84 MCU 프로그래밍 순서

 

0. ATtinyCore 보드 지원 라이브러리 설치 

Preferences... 에서 Additional boards manager URLs : 에  http://drazzy.com/package_drazzy.com_index.json를 추가해주고, Boards Manager에 가서  ATTinyCore by Spence Konde 를 설치해준다.

(이 글을 쓰는 시점에서 Arduino IDE 2.0.4에서 ATTinyCore version 1.5.2 가 설치되어 잘 동작한다.)

1. Arduino Uno를  Arduino ISP로 만든다. (File -> Examples -> 11. ArduinoISP -> ArduinoISP 선택하고, 스케치 업로드)

2. Arduino Uno와 ATtiny84(Roshamglo Badge Kit)와 연결 

    Arduino Uno의 RESET 핀과 GND 핀 사이에 10uF 커패시터를 연결 (커패시터의 짧은 다리가 GND 쪽에)

 

    Arduino Uno 핀 번호                                         Roshamglo 핀 번호 

                3.3V                <----------------->          3.3V

                GND                <----------------->          GND

                  13                  <----------------->           4 (SCK)

                  12                  <----------------->           5 (MISO)

                  11                  <----------------->            6 (MOSI)

                  10                  <----------------->            RESET

 

3. Roshamglo 에 동작시킬, ino 아두이노 프로그램 작성 

Blink 예제는 다음과 같다.

// Blinking Example

int GREEN_LED = 7; // Green LED가 연결된 핀 7번
int RED_LED = 8; // RED LED가 연결된 핀 8번

void setup(){
pinMode(GREEN_LED, OUTPUT); // Green LED를 출력으로 설정합니다.
pinMode(RED_LED, OUTPUT); // RED LED를 출력으로 설정합니다.
}
 
void loop(){
digitalWrite(GREEN_LED, HIGH); // Green LED 켜기
digitalWrite(RED_LED, LOW); // RED LED 끄기
 
delay(1000); // 1초간 유지합니다.
 
digitalWrite(GREEN_LED, LOW); // Green LED 끄기
digitalWrite(RED_LED, HIGH); // RED LED 켜기
delay(1000); // 1초간 유지합니다.
}
 
4.  Tools -> Board 설정에서  ATtinyCore -> ATtiny24/44/84(a) (No Bootloader) 선택 
                     Port는 Arduino Uno 가 연결된 포트를 지정 (/dev/cu.usbmodemXXXXXX 로 표시됨)
                     나머지 칩 설정은 기본을 그대로 둔다. 다만, Clock Source 가 8MHz (Internal) 인것을 반드시 확인한다.
      Programmer 설정에서 “Arduino as ISP”  반드시 지정 
 
5. Tools -> Burn Bootloader 선택 실행 후,
6. Sketch -> Upload using Programmer 로 프로그램을 업로드한다.
 
에러가 없이 다 정상적으로 수행되었다면, Okay~~!!  

  

Posted by 훅크선장
, |

리모콘을 잃어버린 중국제 LED 벽시계의 시간설정을 위해서, 

아두이노 우노와 만능 멤브레인 키패드 3x4, 그리고 IR 송수신 모듈을 가지고  시계용 IR 리모콘을 한번 만들어 보았다.

 

제일 어려운 것이 리모콘의 송신 신호를 알아내는 것이었다. 리모콘이 있다면, 신호를 송신해보고 그 신호를 복제하는 방법으로 하면 쉽게 갈 수 있지만, 리모콘이 없으므로 모든 코드 신호를 다 보내보면서 시계쪽의 변화를 봐야했기에 완전 쌩노가다였다.

 

무아스 퓨어 39cm 슬림형 LED 벽시계
리모콘 키
1) 전원버튼  
0x1C :  LED 전원 On/Off
2) 화면전환, 디스플레이모드 설정(시간, 날짜, 온도)
0x40 :  시간 -> 날짜  -> 온도 
 x1 x1  -> 22 oC
3) 자동밝기 모드 on/off  
0x08 : 자동밝기모드  
L-01 (자동밝기모드 Off)  -> L-AU (자동밝기모드 On)
0x08, sRepeates 20 : 시간구분점 페이드인 아웃 설정정
 Fd --  -> Fd 0n
4) 알람 ON/OFF
0x44 : AL -- (알람 Off)  ->  AL On  (알람 On)
5) 길게 눌러 시간설정  
0x5E, sRepeates 20 : 
6) 알람시간 확인, 길게 눌러 알람시간 설정
0x4A   6:30
7) 수동밝기모드에서 밝기 올림, 설정모드에서 숫자 올림  
0x18 : up
8) 수동밝기모드에서 밝기 내림, 설정모드웨서 숫자 내림
0x52 : down 

 

아두이노 IDE에 keypad 라이브러리와 IRremote 라이브러리를 설치해서 아래 코드를 아두이노 우노에 업로드하면 된다.

물론 키패드와 송수신 모듈을 아두이노와 연결해야 되는데, 연결방법은 인터넷에 다 있다. (검색하면 된다.)

 

참조 사이트:

https://www.makerguides.com/ir-receiver-remote-arduino-tutorial/

 

IR Remote and Receiver with Arduino Tutorial (4 Examples)

Learn how to use an infrared (IR) sensor/receiver and remote with the Arduino. Wiring diagrams and many example codes included!

www.makerguides.com

https://github.com/Arduino-IRremote/Arduino-IRremote#sending-ir-codes

 

GitHub - Arduino-IRremote/Arduino-IRremote: Infrared remote library for Arduino: send and receive infrared signals with multiple

Infrared remote library for Arduino: send and receive infrared signals with multiple protocols - GitHub - Arduino-IRremote/Arduino-IRremote: Infrared remote library for Arduino: send and receive in...

github.com

https://mechatrofice.com/arduino/keypad-interfacing-with-arduino

 

Keypad Interfacing with Arduino 4x4, 4x3 with LCD connection and code

A Matrix Keypad is a very useful module for embedded systems and a variety of projects. This tutorial briefly explains the interface of 4×3 and 4×4 keypads with Arduino and few programs using keypad...

mechatrofice.com

https://lastminuteengineers.com/arduino-keypad-tutorial/

 

In-Depth: Interface 4x3 & 4x4 Membrane Keypad with Arduino

Learn about 4x3 & 4x4 Membrane Keypad along with its Working, Pinout, Wiring, Library, Arduino Code for Reading Key Presses.

lastminuteengineers.com

keypad 라이브러리에는 한번 누름만 존재하고, 길게 누름에 대한 함수가 존재하지 않기 때문에,

그냥 길게 누름의 신호를 별도의 키 하나에 할당해서 간단하게 구현하였다.

LED 벽시계의 키는 8개뿐이지만, 길게 누름이 3개 할당되어 있어서, 키를 11개만 쓰면 되기 때문에.

// Code for IR controller of Mooas LCD Digital Wall Clock
// coded by HooK7346
// 2023. 3. 8.
/*
* Key # : LED On/Off
* Key * : Change Display
* Key 1 : Brightness Auto On/Off
* Key 2 : Time dot Fade In/Out setting
* Key 3 : Alarm On/Off
* Key 4 : Settings Menu
* Key 5 : OK, Next
* Key 7 : Alarm Time Check
* Key 8 : Alarm Setting
* Key 6 : Up
* Key 9 : Down
*/

#include <Arduino.h>
#define DISABLE_CODE_FOR_RECEIVER // Saves 450 bytes program memory and 269 bytes RAM if receiving functions are not used.
//#define SEND_PWM_BY_TIMER // Disable carrier PWM generation in software and use (restricted) hardware PWM.
//#define USE_NO_SEND_PWM // Use no carrier PWM, just simulate an active low receiver signal. Overrides SEND_PWM_BY_TIMER definition
#include "PinDefinitionsAndMore.h" // Define macros for input and output pin etc.
#include <IRremote.hpp>
#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
byte rowPins[ROWS] = {2, 3, 4, 5};
byte colPins[COLS] = {6, 7, 8};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

uint8_t sCmd_LED_On_Off = 0x1C;
uint8_t sCmd_Change_Display = 0x40;
uint8_t sCmd_Bright_Auto_On_Off = 0x08;
uint8_t sCmd_Alarm_On_Off = 0x44;
uint8_t sCmd_Setting = 0x5E;
uint8_t sCmd_Alarm_Setting = 0x4A;
uint8_t sCmd_Up = 0x18;
uint8_t sCmd_Down = 0x52;

uint8_t sRepeats_short = 0;
uint8_t sRepeats_long = 30;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);

Serial.begin(115200);
 
IrSender.begin(DISABLE_LED_FEEDBACK); // Start with IR_SEND_PIN as send pin and disable feedback LED at default feedback LED pin

Serial.print(F("Send IR signals at pin "));
Serial.println(IR_SEND_PIN);
}

void loop() {
char key = keypad.getKey();
switch (key) {
case '#':
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_LED_On_Off, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_short);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_LED_On_Off, sRepeats_short);

break;
case '*': // Change Display button
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_Change_Display, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_short);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_Change_Display, sRepeats_short);

break;
case '1': // Brightness Auto On/Off button
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_Bright_Auto_On_Off, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_short);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_Bright_Auto_On_Off, sRepeats_short);

break;
case '2': // Time dot Fade In/Out setting button
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_Bright_Auto_On_Off, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_long);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_Bright_Auto_On_Off, sRepeats_long);

break;
case '3': // Alarm On/Off button
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_Alarm_On_Off, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_short);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_Alarm_On_Off, sRepeats_short);

break;
case '4': // Settings Menu button
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_Setting, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_long);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_Setting, sRepeats_long);

break;
case '5': // OK, Next button
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_Setting, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_short);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_Setting, sRepeats_short);

break;
case '7': // Alarm Time Check button
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_Alarm_Setting, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_short);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_Alarm_Setting, sRepeats_short);

break;
case '8': // Alarm Settings button
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_Alarm_Setting, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_long);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_Alarm_Setting, sRepeats_long);

break;
case '6': // Up button
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_Up, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_short);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_Up, sRepeats_short);

break;
case '9': // Down button
/*
* Print current send values
*/
//Serial.println();
Serial.print(F("Send now: address=0x00, command=0x"));
Serial.print(sCmd_Down, HEX);
Serial.print(F(", repeats="));
Serial.print(sRepeats_short);
Serial.println();

//Serial.println(F("Send standard NEC with 8 bit address"));
Serial.flush();

IrSender.sendNEC(0x00, sCmd_Down, sRepeats_short);

break;
}
}
Posted by 훅크선장
, |