Nyalain PC Dari HP pake WOL
Gw dirumah punya PC yang biasanya selalu nyala. PC itu gw pake buat workstasion kerja gw. Gw juga punya laptop kalo butuh kemana-mana. Itu laptop memang sengaja beli laptop enteng biar gw bisa SSH ke pc dirumah. Issue nya gw engga punya ip public, jadi kalo beda internet engga bisa akses. Hmmm ini masalah. Untung nya ada app kayak zerotier atau tailscale yang kayak layer 3 router over internet. Jadinya gw bisa akses PC gw kalo di jaringan zerotier atau tailscale yang sama.
Zerotier sama tailscale sebenernya punya product yang sedikit beda. Tailscale punya fitur buat ngatur akses akun orang lain kalo mau join ke network. Dimana zerotier lebih berasa kayak router over the internet. Jadi lebih batangan. Gw secara punya keduanya dan lebih sering pake tailscale. Tailscale udah ngurus dns untuk nama device dan berasa lebih simple buat dipake. Untuk zerotier punya beta software zerotier dns yang bisa kasih hostname resolution buat device nya, tapi perlu setup lagi. Nanti gw bakal kasih tau cara setup tailscale dan zerotier.
Setup Tailscale
Buat install tailscale bisa pake script
curl -fsSL https://tailscale.com/install.sh | shAtau kalo di ubuntu bisa lewat
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/focal.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/nullcurl -fsSL https://pkgs.tailscale.com/stable/ubuntu/focal.tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.listsudo apt-get updatesudo apt-get install tailscalesudo tailscale upsetelah itu login di tailscale nya
sudo tailscale upAkan kebuka web, itu tinggal login
bisa cek status apakah terkonek ke tailscale dengan
tailscale statusSetup ZeroTier
Bisa install zerotier lewat
curl -s https://install.zerotier.com | sudo bashMasuk ke halaman https://my.zerotier.com/ dan create network.
Pada setting, set Access Control jadi private.
Pada pc join ke network dengan
sudo zerotier-cli join [network id]Setelah join, di bagian member pada web di centang bagian auth nya agar bisa akses.
installing wol
Nah sekarang PC gw udah bisa diakses dari network luar. Tapi masalahnya PC nya perlu nyala terus. Gw perlu mikir cara biar bisa nyala matiin PC secara remote. Untung nya masih punya raspberry pi lama yang bisa gw nyalain 24 jam. Jadinya gw bisa install aja tailscale di raspberry pi.
Nah sekarang udah bisa akses raspberry pi, gimana caranya gw bisa nyalain pc nya? Untungnya ada teknologi namanya wake on lan (wol). Wol ini cara kerjanya ada komputer yang ngirim magic packet (beneran nama nya itu) ke komputer yang mati. Nanti komputer yang mati nya kalo terima magic packet itu bakal nyala. Raspberry pi dan pc gw sekarang ada di jaringan yang sama dan bisa ngirim wol dari raspberry pi ke pc.
Buat install wol bisa lewat
sudo apt-get install wakeonlanBuat ngecek mac address bisa pake command ip a dan cek lan dari pc.
Buat gw mac nya “a8:a1:59:e8:b3:16” jadi buat nylain nya bisa pake command wol a8:a1:59:e8:b3:16.
Buat cek apa wol nya ini nyampe apa engga bisa di PC nya pake command nc yang listen ke port udp 40000.
nc -v -u -l 40000Tapi kalo ssh terus ke pc buat run wol perlu step terlalu panjang. Gimana kalo dari hp satu perintah aja bisa nyalain pc? Kebetulan gw ngerti cara ngoding c dan networking, jadi bikin aja app nya. Konsepnya gw bikin aplikasi yang listen ke port tertentu. Kalo ada yang konek, gw bakal ngirim wol nya ke pc. Mustinya engga susah kan? Ya engga susah kok, buktinya ini gw bakal taro kode nya disini.
Kode C
#include <arpa/inet.h>#include <errno.h>#include <netinet/in.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>
int server_socket = 0, client_socket = 0;struct sockaddr_in dest_addr = {0};
void on_sigint(int sig) {
printf("Caught signal %d\n", sig); if (close(server_socket) < 0) { perror("can't close server socket"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS);}
int mac_string_to_binary(const char *mac_str, unsigned char *mac_bin) { if (sscanf(mac_str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac_bin[0], &mac_bin[1], &mac_bin[2], &mac_bin[3], &mac_bin[4], &mac_bin[5]) != 6) { return -1; } return 0;}
int main(int argc, char *argv[]) { char *addr = "a8:a1:59:e8:b3:16"; int port = 54321;
if (argc > 1) { if (strlen(argv[1]) != 17) { perror("Invalid MAC address"); exit(EXIT_FAILURE); } addr = argv[1]; }
if (argc > 2) { port = strtoul(argv[2], NULL, 10); if (errno == ERANGE) { perror("Invalid port number"); exit(EXIT_FAILURE); } if (port > 65535) { perror("Port number out of range"); exit(EXIT_FAILURE); } }
if (signal(SIGINT, on_sigint) == SIG_ERR) { perror("signal"); exit(EXIT_FAILURE); }
if (signal(SIGTERM, on_sigint) == SIG_ERR) { perror("signal"); exit(EXIT_FAILURE); }
unsigned char mac_address[6]; if (mac_string_to_binary(addr, mac_address) == -1) { fprintf(stderr, "Invalid MAC address format\n"); exit(EXIT_FAILURE); }
struct sockaddr_in server_addr, client_addr; socklen_t client_addr_len = sizeof(client_addr); char buffer[144] = {0};
server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket == -1) { perror("Socket creation failed"); exit(EXIT_FAILURE); }
server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); // Port number server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("Binding failed"); close(server_socket); exit(EXIT_FAILURE); }
if (listen(server_socket, 5) < 0) { perror("Listening failed"); close(server_socket); exit(EXIT_FAILURE); }
dest_addr.sin_family = AF_INET; dest_addr.sin_port = htons(40000); dest_addr.sin_addr.s_addr = INADDR_BROADCAST;
for (int i = 0; i < 6; i++) { buffer[i] = 0xFF; } for (int i = 0; i < 16; i++) { memcpy(buffer + (i * 6) + 6, mac_address, 6); }
printf("Server listening on port %d. Will send to %s...\n", port, addr);
while (1) { client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len); if (client_socket == -1) { perror("Accepting connection failed"); continue; }
printf("Client connected from %s:%d\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
client_socket = socket(AF_INET, SOCK_DGRAM, 0); if (client_socket == -1) { perror("can't create client socket"); continue; }
struct linger lin = {.l_onoff = 0, .l_linger = 0}; if (setsockopt(client_socket, SOL_SOCKET, SO_LINGER, &lin, sizeof(lin))) { perror("setsockopt(SO_LINGER) failed"); close(client_socket); continue; }
int yes = 1; if (setsockopt(client_socket, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes))) { perror("setsockopt(SO_BROADCAST) failed"); close(client_socket); continue; }
if (setsockopt(client_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { perror("setsockopt(SO_REUSEADDR) failed"); close(client_socket); continue; }
if (setsockopt(client_socket, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0) { perror("setsockopt(SO_REUSEPORT) failed"); close(client_socket); continue; }
if (setsockopt(client_socket, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes))) { perror("setsockopt(SO_BROADCAST) failed"); close(client_socket); continue; }
printf("Sending magic packet to %s\n", addr); if (sendto(client_socket, buffer, sizeof(buffer), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) == -1) { perror("sendto failed"); close(client_socket); continue; }
close(client_socket); printf("Client disconnected\n"); }
close(server_socket);
return 0;}Buat compile nya bisa pake
gcc wol.c -o main./mainIni program c yang simple yang bakal ngirim package ke macadress di ip broadcast dan port 40000. Alesan kenapa engga ngirim magic packet langsung karena perlu akses sudo kalo mau ngoding layer 2 langsung. Dari standar iana, port 9 dipakai untuk WOL, tetapi port dibawah 1024 perlu sudo. Untung nya port 40000 juga bisa dipakai untuk WOL.
Jadi untuk mengetes nya bisa pakai command
nc -w 1 [ip] 54321Jadi sekarang gw tinggal jalanin command itu di HP lewat termux deh.