Introduction

Let me introduce my self, Who is Fadhil? Fadhil Riyanto (real-name), is a self-taught system programmer (also backend programmer) which live in Indonesian, This is some short & dirty tutorial about computer science and litte about math.

mirrors: blog.fadhils.eu.org

Contributing

Found a mistake? You can freely DM me on telegram or just email me on

Language

Because I'm indonesian, some part of this website may written in indonesian. But I will try to translating it into english language.

Note

[EN] If you found a mistake, let me know. BIG thanks!
[ID] Jika kamu menemukan sesuatu yang sepertinya itu salah, bisa langsung kasih kabar ke saya. Terimakasih.

todo

  • MAKE: ./server/php-fpm-config.md book
  • COMPLETION: ./database/postgresql_system_table
  • COMPLETION: ./database/postgresql_functions
  • MAKE: ./crypto/ca-certificates
  • MAKE: "freeRADIUS deploy"

System programming

How data movement changes a destination register

This snippets is from "Computer Systems A Programmer’s Perspective, by Randal E. Bryant and David R. O’Hallaron"

As described, there are two different conventions regarding whether and how data movement instruc- tions modify the upper bytes of a destination register. This distinction is illustrated by the following code sequence:

1 movabsq $0x0011223344556677, %rax %rax = 0011223344556677
2 movb $-1, %al %rax = 00112233445566FF
3 movw $-1, %ax %rax = 001122334455FFFF
4 movl $-1, %eax %rax = 00000000FFFFFFFF
5 movq $-1, %rax %rax = FFFFFFFFFFFFFFFF

In the following discussion, we use hexadecimal notation. In the example, the instruction on line 1 initializes register %rax to the pattern 0011223344556677. The remaining instructions have immediate value −1 as their source values. Recall that the hexadecimal representation of −1 is of the form FF. . .F, where the number of F’s is twice the number of bytes in the representation. The movb instruction (line 2) therefore sets the low-order byte of %rax to FF, while the movw instruction (line 3) sets the low-order 2 bytes to FFFF, with the remaining bytes unchanged. The movl instruction (line 4) sets the low-order 4 bytes to FFFFFFFF, but it also sets the high-order 4 bytes to 00000000. Finally, the movq instruction (line 5) sets the complete register to FFFFFFFFFFFFFFFF.

some useful links

General embedded ASM linked in C

this is program is succesfully compiled with as, but failed to run due to SIGSEGV.

this is will fail

.data
val:
    .byte 0xF6
    .byte 0xF6
    .byte 0xF6
    .byte 0xF6
    

.globl do_asm

do_asm:
    # movl 0x12345678, %eax
    # movl 0xAABBCCDD, %edx 

    # # move edx 8 bit high into al (eax)
    # movb %dh, %al

    
    movq $9, %rax
    ret

this is will compile

.data
val:
    .byte 0xF6
    .byte 0xF6
    .byte 0xF6
    .byte 0xF6
    

.globl do_asm

.text
do_asm:
    # movl 0x12345678, %eax
    # movl 0xAABBCCDD, %edx 

    # # move edx 8 bit high into al (eax)
    # movb %dh, %al

    
    movq $9, %rax
    ret

the difference only in .text section

Move sign & zero-extends a single byte

Disini saya akan membahas apa itu instruksi MOVSBL dan MOVZBL. pertama tama silahkan baca dulu disini

MOVSBL and MOVZBL
* MOVSBL sign-extends a single byte, and copies it into a
  double-word destination
* MOVZBL expands a single byte to 32 bits with 24 leading
  zeros, and copies it into a double-word destination

pertama tama, lihat kode asm ini.


.section .data
val:
    .byte 0xF6
    .byte 0xF6
    .byte 0xF6
    .byte 0xF6
    

.globl do_asm

.text
do_asm:
    movl $0x12345678, %eax
    movl $0xAABBCCDD, %edx 

    # move edx 8 bit high into al (eax)
    movb %dh, %al

    # reset
    movl $0x12345678, %eax
    movl $0xAABBCCDD, %edx 

    MOVSBL %dh, %eax

    # reset
    movl $0x12345678, %eax
    movl $0xAABBCCDD, %edx 

    MOVZBL %dh, %eax

    
    movq $9, %rax
    ret

dan ini hasilnya, movb biasa (tanpa hapus bagian atas data, bagian atas tetep utuh) gambar

ini hasil signed bagian atas gambar

ini hasil ketika bagian atas kita zerokan gambar

catatan movb %dh, %al memindahkan rdx bagian high ke rax bagian bawah.

movabsq

simplenya, ini kepanjangan dari move absolute quad word (64 bit) contoh kecil

image

itu contoh initial moveabsq int 64 bit, lalu

image contoh move 1 bytes

image move 16 bit, 2 bytes word

image move 32 bit, 4 bytes, tapi disini keformat sebagai int32 wkwk

image full 64 bit move

x86_64 register (fiks technical grade)

gambar

analisis kenapa pakai movabsq, daripada movq

movq hanya bisa accept integer

analisis patch movq pakai 0xffffffff

ada asm

image

kita akan memaksa dari 0x7fffffff menjadi 0xffffffff untuk membuktikan bahwa harusnya movq error, dan digantikan oleh movabsq

initial dulu image

lalu, next replace address 0x555555555119 dengan

set {unsigned char[8]}0x555555555119 = {0x48, 0xc7, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x90}

confirmed berubah jadi 0xffffffff disini image

saatnya kita lanjutkan, apakah error image

ext4 unknown RO compact features

this error come from linux kernel

	/* Check that feature set is OK for a read-write mount */
	if (ext4_has_unknown_ext4_ro_compat_features(sb)) {
		ext4_msg(sb, KERN_ERR, "couldn't mount RDWR because of "
			 "unsupported optional features (%x)",
			 (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) &
				~EXT4_FEATURE_RO_COMPAT_SUPP));
		return 0;
	}

which EXT4_FEATURE_RO_COMPAT_SUPP

#define EXT4_FEATURE_RO_COMPAT_SUPP	(EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
					 EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
					 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
					 EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\
					 EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
					 EXT4_FEATURE_RO_COMPAT_BIGALLOC |\
					 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\
					 EXT4_FEATURE_RO_COMPAT_QUOTA |\
					 EXT4_FEATURE_RO_COMPAT_PROJECT |\
					 EXT4_FEATURE_RO_COMPAT_VERITY |\
					 EXT4_FEATURE_RO_COMPAT_ORPHAN_PRESENT)
#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM		0x0010

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/ext4/ext4.h#n2188

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/ext4/ext4.h#n2024

qemu custom cpio HDA

skrip init custom linux

qemu-system-x86_64 \-kernel ./vmlinux \
                                                 -nographic \
                                                 --append "console=tty0 console=ttyS0 panic=1 root=/dev/sda rootfstype=ext2" \
                                                 -hda root.img \
                                                 -m 1024 \
                                                 -vga none \
                                                 -display none \
                                                 -serial mon:stdio \
                                                 -no-reboot \
                                                 -initrd vfs/root.cpio.gz

generate cpio

find . | cpio -o -H newc | gzip > root.cpio.gz
``

step TCP

TCP steps

  • isi dulu sockaddr_storage, isi pakai inet_pton(); .so_family = AF_INET; sin_port = htons(port)
  • syscall socket(AF_INET, SOCK_STREAM, 0);
  • setsocksopt(fd, SO_REUSEADDR = 1)
  • bind(fd, ss_addr (cast dulu ke sockaddr_in), len nya)
  • listen()

penjelasan ttg kenapa pakai sockaddr_storage dipakai https://stackoverflow.com/questions/19528820/difference-between-sockaddr-and-sockaddr-storage

kenapa harus setsocksopt SO_REUSEADDR? karna jika tidak, TCP Masuk ke timewait state.

sekiranya itu aja sih step TCP ini. untuk UDP pakai aja dgram.

GDB attach

jadi ceritanya, ada bug yg kala di run di terminal, ia buggy, pas di run di gdb, dia gak error sama sekali

gw bingung dah, nah disini. ternyata ada trick nya

  • jalanin dulu programnya kek biasa di terminal, dah running kan

  • ambil pid nya pakai ps aux | grep xyz

  • setelah dapet pid nya, jalankan gdb dengan mode attach pid

pakai sudo gdb -p 12345

  • program akan freeze sejenak, pencet c, enter

nah, lakukan cara yg dipake buat reproduce bug nya, misal pakai nc buat nyepam tcp ke program. ok dapet bug nya

ni kalau kata orang internet, beberapa bug kek app multi thread agak susah di caught. pakai valgrind pun perlu flags2 khusus buat inspect sampai thread nya

hasil oprek socket programming, case socks5 server

bagian IETF SOCKS5 section 6

https://datatracker.ietf.org/doc/html/rfc1928#section-6

BND.ADDR haruslah berupa IPV4/IPV6 address, bukan domain :)

secara general, bentuk packet yg akan dikirim untuk versi IPV4 seperti ini

[0] [VER] => 0x5
[1] [REP] => 0x0
[2] [RSV] => 0x0
[3] [ATYP] => 0x1 atau 0x4
[4] [BND.ADDR] 0xac
[5] [BND.ADDR] 0x43
[6] [BND.ADDR] 0x93
[7] [BND.ADDR] 0x39
[8] [BND.PORT] 0x50 
[9] [BND.PORT] 0x50

maka perhitungannya memory awal + 4 (karna 4 field dah dipakai), start dari sini, insert 4 oktet lagi ipv4 address, lalu insert 2 oktet uint8 sebagai port.

bagian BND.PORT itu unsigned int 16 bit. jadi harus digabung bitnya + diubah dari network order ke host order

fix ncurses kernel build

suppose

*** Unable to find the ncurses libraries or the
 *** required header files.
 *** 'make menuconfig' requires the ncurses libraries.
 *** 
 *** Install ncurses (ncurses-devel) and try again.
 *** 
make[2]: *** [/home/fadhil_riyanto/linux-kernel/busybox-1.37.0/scripts/kconfig/lxdialog/Makefile:15: scripts/kconfig/lxdialog/dochecklxdialog] Error 1
make[1]: *** [/home/fadhil_riyanto/linux-kernel/busybox-1.37.0/scripts/kconfig/Makefile:14: menuconfig] Error 2
make: *** [Makefile:444: menuconfig] Error 2

maka solusi nano scripts/kconfig/lxdialog/Makefile

ubah

always         := $(hostprogs-y) dochecklxdialog

PHP-SRC variadic params

the source code: https://github.com/php/php-src/blob/ba6c00505d4218ff9fe4feb060f636524acfb125/ext/standard/array.c#L1204

mayan ngebantu jg gw ngepahami variadic params di php. ref: https://www.zend.com/resources/php-extensions/basic-php-structures

selfnote :

ZEND_PARSE_PARAMETERS_START(num_required_args, num_max_args) Z_PARAM_VARIADIC('*' or '+', destptr, argc);

catatan:

  • * nol atau lebih parameter
  • + satu atau lebih parameter

nb: akan diupdate berkala

ref: https://wiki.php.net/rfc/fast_zpp

PHP-SRC minit()

https://github.com/php/php-src/blob/3704947696fe0ee93e025fa85621d297ac7a1e4d/main/main.c#L2009

Ketika module PHP diload ke zend engine, yang dipanggil adalah MINIT(), di step ini yg terjadi cuman memory alokasi di ZendMM, dan disini engga ada process atau thread yg dijalan, pure cuman initialisasi data

nah, yang mentrigger MINIT() adalah zend_startup_modules(), trus secara beurutan, ia jg manggil RINIT() via PHP_RINIT_FUNCTION()

struct nya image zend_result (*request_startup_func)(INIT_FUNC_ARGS);

gcc compiler visibility

intresting buat diulik

class rectangle {
        int width, height;

        public:
                void set_value(int, int);
                int area();
};

void rectangle::set_value(int x, int y) 
{
        width = x;
        height = y;
}


int rectangle::area()
{
        return width * height;
}

compile pakai

  • g++ -Wall -c -fPIC abc.cc
  • g++ -o librec.so --shared abc.o
  • nm -C librec.so

akan ada

000000000000110e T rectangle::area()
00000000000010ea T rectangle::set_value(int, int)

nah, disitu kalau di compile pakai -fvisibility=hidden ntar pas di cek pakai nm -CD librec.so

bakalan gak ada. nah ini ada kaitannya sama __attribute__ ((visibility ("hidden")))

tambahan: https://groups.google.com/g/ode-users/c/T3qiy-4dviQ

load effective address

computes a memory address using the same arithmetic that a MOV instruction uses. But unlike the MOV instruction, the LEA instruction just stores the computed address in its target register, instead of loading the contents of that address and storing it.

Consider your first LEA instruction:

tldr nya: mov bisa mengkalkulasi operasi aritmetika dari alamat memori, trus ngambil isinya kalau lea, ia cuman mengkalkulasi alamatnya, hasil itung2an nya disimpan ke operand2

lea -0x18(%ebp), %ebx

tambahan catatan

mov (op1, op2, op3), dest

equal (pseudo): mov op1 + op2 * op3, dest

and lea op1(op2), dest

equal lea op2 + op1, dest (address of op2 + op1, store result into dest)

bahasan tentang rip https://stackoverflow.com/questions/54745872/how-do-rip-relative-variable-references-like-rip-a-in-x86-64-gas-intel-sy

AT&T asm prelude

push eax equal with: mov [esp], eax sub esp, 4

pop eax get values out of stack equal with

add rsp, 4 mov eax, [esp]

Rust stuff

Welcome in this rust stuff section.

Rust cursor, How it works

Cursor in rust basically just a in-memory implementation of Seek. see fseek() here

Imagine, we have a file. and this is representation of contents

abcde

seek start from 1, is bcde, start from 2 is cde and so-on, this is also happen when we use seek from end, for example, seek end -1 is mean e, -2 is de, etc.

From code perspective

this is signature of cursor

pub struct Cursor<T> {
    inner: T,
    pos: u64,
}

and also, this struct implement Write and Seek

so, in order to understanding this concept, let code first in C


#include <string.h>
#include <stdlib.h>
#include <stdio.h>

struct seekfd {
    FILE                *file;
};

int start_open(struct seekfd *seekfd) {
    seekfd->file = fopen("a.txt", "r");

    if (seekfd->file == NULL) {
        fprintf(stderr, "%s", "error");
        return -1;
    }
}

int do_op(struct seekfd *seekfd) {
    char allocated_buf[2048];
    memset(allocated_buf, 0, 2048);

    fseek(seekfd->file, 1, SEEK_SET);
    int ret = fread(allocated_buf, 1, 3, seekfd->file);

    printf("%s", allocated_buf);
}

int main() {
    struct seekfd seekfd;

    int ret = start_open(&seekfd);
    if (ret < 0) {
        return -9;
    }

    ret = do_op(&seekfd);
    if (ret < 0) {
        return ret;
    }
}

compile with

clang fseek.c -o p -g

next step, create dummy files named a.txt with content abcdefghijklmnopqr

first run with fseek(seekfd->file, 0, SEEK_SET); = abc second run with fseek(seekfd->file, 1, SEEK_SET); = bcd etc...

this concept is basically same in Rust

Rust context

this is small example show Seek works (in-memory) instead utilize real file

use std::io::prelude::*;
use std::io::{self, SeekFrom};
use std::io::Cursor;

fn write_bytes<W: Write + Seek>(mut w: W) -> io::Result<()> {
    w.seek(SeekFrom::Start(5))?;
    
    for i in 1..6 {
        w.write(&[i])?;
    }

    Ok(())
}


fn main() {
    let mut buf = Cursor::new(vec![0; 20]);
    write_bytes(&mut buf).unwrap();
    println!("{:?}", &buf.get_ref()); // print vector
}

this is the output

[0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

instead, we change SeekFrom::Start(5) with SeekFrom::Start(10), the write will started at offset 10. this is the output

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0]

Rust bytes has_remaining() method

this function return whatever any best left on buffer. example, let make simple tcp/ip

impl Connection {
    pub fn new(stream: TcpStream) -> Connection {
        Connection {
            stream: BufWriter::new(stream),
            buffer: BytesMut::with_capacity(4096)
        }

    }

    pub async fn read(&mut self) 
        -> std::result::Result<Option<Frame>, Box<dyn std::error::Error + Send + Sync>> {
        
        let _ = self.stream.read_buf(&mut self.buffer).await;
        println!("hasremaining: {}", self.buffer.has_remaining());
        
        while self.buffer.has_remaining() {
            let bytes = self.buffer.get_u8();
            println!("{} -> {}", bytes as char, self.buffer.has_remaining());
        }

        println!("{}", self.buffer.has_remaining());
        // Frame::check(&mut self.buffer);

        Ok(Some(Frame::Null))
    }
}

let's see the server result using ncat

ncat-result

which the input is something look like this

[22:55:41] fadhil_riyanto@integral2 /home/fadhil_riyanto [SIGINT]
> ncat 127.0.0.1 6380
abc

from this output, we know

hasremaining: true <--- this is initial, didn't mean anything
a -> true <--- a already read, but next char is b, why this is true
b -> true <--- next is c, also true
c -> true <--- next is \n char, also true

 -> false <--- this is false because no next chars
false <--- confirm

Also, get_u8 returns the first byte in the buffer. Each time it's called, it advances the position, so subsequent calls return the next bytes.

How Rust into() Box + Error analysis

suppose, we have function return signature like this

std::result::Result<Option<Frame>, Box<dyn std::error::Error + Send + Sync>>

and then, we return something like this from our function

return Err("connection reset".into())

how the into() works?

analysis

look at this snippet

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
    /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
    ///
    /// [`str`]: prim@str
    ///
    /// # Examples
    ///
    /// ```
    /// use std::error::Error;
    /// use std::mem;
    ///
    /// let a_str_error = "a str error";
    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error);
    /// assert!(
    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
    /// ```
    #[inline]
    fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
        From::from(String::from(err))
    }
}

if we go deeper into From::from, we found this

#[inline]
    fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> {
        struct StringError(String);

        impl Error for StringError {
            #[allow(deprecated)]
            fn description(&self) -> &str {
                &self.0
            }
        }

        impl fmt::Display for StringError {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                fmt::Display::fmt(&self.0, f)
            }
        }

        // Purposefully skip printing "StringError(..)"
        impl fmt::Debug for StringError {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                fmt::Debug::fmt(&self.0, f)
            }
        }

        Box::new(StringError(err))
    }

nb: actually StringError is string aliases. then, we see in this section. we created a heap-allocated using Box::new(StringError(err)).

Rust buffer advance

this simple article show how buffer advance works

use bytes::Buf;

fn main() {
    let mut buf = &b"hello world"[..];

    println!("{}", String::from_utf8_lossy(buf.chunk()));

    buf.advance(6);
    println!("{}", String::from_utf8_lossy(buf.chunk()));
}

and the result

hello world
world

Rust RESP get_line analysis

if we look at simple tokio redis example (mini redis), we can see how the data is parsed. look at this

the resp is generally read something like this `+abc\r\n'

this is the code that actually crop down the buffer

fn get_line<'a>(src: &mut Cursor<&'a [u8]>) -> Result<&'a [u8], Error> {
    // Scan the bytes directly
    let start = src.position() as usize;
    // Scan to the second to last byte
    let end = src.get_ref().len() - 1;

    for i in start..end {
        if src.get_ref()[i] == b'\r' && src.get_ref()[i + 1] == b'\n' {
            // We found a line, update the position to be *after* the \n
            src.set_position((i + 2) as u64);

            // Return the line
            return Ok(&src.get_ref()[start..i]);
        }
    }

    Err(Error::Incomplete)
}

and I will show you how they works (algorithm)

variables setup

we have start and end, which consist of

let start = src.position() as usize;
let end = src.get_ref().len() - 1;

the src.position() always return 0, also depending on the context. src.get_ref().len() return the length of the buffer, for example, +rand\n\n has length 7.

because we wan't to read two chars at the end, which is \r and \n

so we substract length with 1, this is avoid buffer overflow

suppose this situation: buf: +rand\n\n

when we add everything with 1, we got this idx: 012345 6 7, it is idx[7]is found? no, so we need to sub with 1, the idx is something like this idx: 012345 6, no overflow

then we check the i and i + 1, make sure there is \r\n

set position

now, we set the cursor to the next incoming buffer. which after \r\n

src.set_position((i + 2) as u64);

suppose:

+rand\r\n+randomsomething\r\n
012345 6 ^ 
^^   ^   this is i + 2, indicates next buffer
ii+1 orig i

postgresql - get() generic function signature

In someday, i found

#[track_caller]
    pub fn get<'a, I, T>(&'a self, idx: I) -> T
    where
        I: RowIndex + fmt::Display,
        T: FromSql<'a>,
    {
        match self.get_inner(&idx) {
            Ok(ok) => ok,
            Err(err) => panic!("error retrieving column {}: {}", idx, err),
        }
    }

some sort of notes:

  • https://doc.rust-lang.org/rust-by-example/generics.html
  • https://serokell.io/blog/rust-generics

how to call it

let data2 = data_actual[0].get::<_, i32>(0);

Rust build logging

rust build usually don't show any output if you try to println!() in build.rs, in order to force this, use

println!("cargo:warning=start build!");

result

warning: ourcrate-rs@0.1.0: Something went wrong!

all docs: https://doc.rust-lang.org/cargo/reference/build-scripts.html

Rust tonic gRPC server build process

topik ini khusus membahas gRPC di rust,

build

contoh template build rs:

use std::{env, path::PathBuf};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let out_dir = PathBuf::from(
        "/home/fadhil_riyanto/BALI64/fadev-service-rs/rpc/src/pb".to_string()
    );

    println!("cargo:warning=start build!");
    
    tonic_build::configure()
        .build_server(true)
        .build_client(false)
        .file_descriptor_set_path(out_dir.join("random_service.bin"))
        .compile_protos(
            &["proto/random_service.proto"], 
            &["proto"]
        )?;


    Ok(())
}

nb:

  • file_descriptor_set_path: dipakai sebagai reflection, bakal ketemu kalau pakai grpcurl.
  • build_server dan build_client: disini ada 2 mode build, untuk server atau untuk client. maka kita set server true, client false
  • compile_protos: masing2 berisi 2 param yg menerima slice, param pertama berisi lokasi protobuf, param kedua berisi root foldernya.

anda bisa lihat-lihat contoh lain disini: https://github.com/hyperium/tonic/tree/master/examples

optional:

  • use .out_dir() ketimbang harus nurut dengan apa yang OUT_DIR katakan

OUT_DIR

what it is, simplenya OUT_DIR ini akan diset jika protobuf sudah di compile, dalam artian, file *.proto diubah jadi kumpulan file *.rs yang bakal di include sama macro, kemudian di compile

urutan compile adalah, macro dievaluasi dulu, baru compile, sampai sini masuk akal. ini macro signature nya

#[macro_export]
macro_rules! include_proto {
    ($package: tt) => {
        include!(concat!(env!("OUT_DIR"), concat!("/", $package, ".rs")));
    };
}

tambahan info bisa baca2 sendiri disini: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts, dan jg biasanya ini akan diinclude ke sebuah file handler. kira kira seperti itu

Rust tokio-postgres connection config example

first, this is example from the documentation

 let (client, conn_ctx) = tokio_postgres::connect("host=localhost user=postgres", NoTls);

then, we want to convert it into config like ctx. see this

use tokio_postgres::{NoTls, Error};

#[tokio::main]
async fn main() {
        let mut config = postgres::config::Config::new();
        config.host("localhost");
        config.user("fadhil_riyanto");
        config.password("1921684338");

        let client_ret = config.connect(NoTls);


}

Math

Welcome in this section.

Set operations formula

Union of Two Sets (cardinality)

\[ |A \cup B| = |A| + |B| - |A \cap B| \]

how to read: whole A and B add together, its make a data duplication on center of venn diagram, we remove that duplication using \( |A \cap B| \)

Intersection (steps)

its flip of Union \[ |A \cup B| = |A| + |B| - |A \cap B| \] \[ |A \cap B| = |A| + |B| - |A \cup B| \]

Intersection of three sets

\[ |A \cup B \cup C| = |A| + |B| + |C| - |A \cap B| - |A \cap C| - |B \cap C| + |A \cap B \cap C| \]

how it works, de remove data duplication two times on \( |A \cap B| \), \( |B \cap C| \), and \( |B \cap C| \), then fill the empty section on the center which \( |A \cap B \cap C| \)

This is proof of concept by nice guy on internet: https://www.youtube.com/watch?v=vVZwe3TCJT8.

Difference

\[ |A - B| = |A| - |A \cup B| \]

Symetric difference

1. General formula

\[ A \space \triangle \space B = (A \cup B) - (A \cap B) \] Cardinals version: \[ | A \space \triangle \space B | = |A - B| + |B - A| \] \[ | A \space \triangle \space B | = |A| + |B| - 2|A \cap B| \]

2. Symetric difference properties

  • \( A \space \triangle \space B = B \space \triangle \space A \)

  • \( (A \space \triangle \space B) \space \triangle C = A \space \triangle \space (B \space \triangle C) \)

  • \( (A \space \triangle \space \emptyset) = A \), why?

    • \(A \space \triangle \space B = (A \cup B) - (B \cap A) \)
    • \(A \space \triangle \space \emptyset = (A \cup \emptyset) - (\emptyset \cap A) \), but
    • \( (A \cup \emptyset) = A \) and \( (\emptyset \cap A) = \emptyset \)
    • \( (A - \emptyset) = A \)
  • \( (A \space \triangle \space A) = \emptyset \)

Set stuff

there is some intresting question about discrete math

why \( \mathcal{P}(\emptyset) = \lbrace \emptyset \rbrace \)

consider \( \mathcal(S) \) where \( S \) is a set, for example

  • if \( S = \lbrace a \rbrace \), then \( \mathcal{P}(S) = \lbrace \emptyset, \lbrace a \rbrace \rbrace \), same as \( \mathcal{P}(a) \)
  • if \( S = \lbrace a, b \rbrace \), then \( \mathcal{P}(S) = \lbrace \emptyset, \lbrace a \rbrace, \lbrace b \rbrace, \lbrace a, b \rbrace \rbrace \), same as \( \mathcal{P}(a, b) \)
  • if \( S = \lbrace \emptyset \rbrace \), then \( \mathcal{P}(S) = \lbrace \emptyset, \lbrace \emptyset \rbrace \rbrace \), same as \( \mathcal{P}(\emptyset) \)

so, because \( \lbrace \rbrace \) usually hidden, \( \mathcal{P}(\emptyset) = \lbrace \emptyset \rbrace \)

let \( A = \emptyset, B = \emptyset \), how to \( A \times B \)

Consider \( A \times B = \lbrace (a,b) | a \in A, b \in B \rbrace \)

because

  • A is empty, no elements can be paired
  • B is also empty

conlusion: no paired element = empty

proof by cardinality \( |A| = 0, |B| = 0, \text{so, when } |A \times B| = |A| \times |B| = 0 \times 0 = 0 \)

does \( P(\emptyset) = \lbrace \lbrace \rbrace \rbrace = \lbrace \emptyset \rbrace \) ?

true, this is due \( \lbrace \emptyset \rbrace \) same as \( \lbrace \lbrace \rbrace \rbrace \), then consider example \( P(a) = \lbrace \lbrace \rbrace, \lbrace a \rbrace\rbrace \)

Suppose X and Z are independent of each other

  • \( | \mathcal{P}(X \cap Z)| \)
  • \( | X - Z | \)
  • \( | X \oplus Z | \)
  • \( | X \cap Z | \)
  • \( | \mathcal{P}(X) \cup \mathcal{P}(Z)| \)
  • \( | \overline{\mathcal{P}(X) \cup \mathcal{P}(Z)}| \)

nb: bagian ini belum jadi

Logika

Ringkasan ini dibuat sebagian sebagian dari Kuliah IF1220 Matematika Diskrit ITB oleh bapak Rinaldi Munir. dan berbagai sumber seperti Wikipedia, ChatGPT dsb

Proposisi

adalah pernyataan bahwa suatu dua perbandingan adalah sama besar, contoh

  • \( \frac{a}{b}=\frac{c}{d} \)
  • \( 4 = 2 * 2 \)
  • 13 adalah bilangan ganjil
  • Untuk sembarang bilangan bulat \( n >= 0 \), maka \( 2n \) adalah genap

contoh yang bukan

  • Isilah gelas tersebut dengan air
  • \( x + 3 = 8 \)
  • \( x > 3 \)

dan, Proposisi dilambangkan dengan huruf kecil seperti \( p, q, r, ... \)

Bentuk bentuk nya

  • Proposisi atomik bentuk proposisi tunggal, contoh
    • 2n selalu genap untuk n=0, 1, 2, …
    • Ibukota Maluku Utara adalah Ternate
  • proposisi majemuk diantaranya:
    • conjunction (and): \( \wedge \)
    • disjunction (or): \( \vee \)
    • negation (!n): \( ~ \)
    • exclusive disjunction (xor): \( \oplus \)

Table

p q r p ∧ q ¬q ¬q ∧ r (p ∧ q) ∨ (¬q ∧ r)
T T T T F F T
T T F T F F T
T F T F T T T
T F F F T F F
F T T F F F F
F T F F F F F
F F T F T T T
F F F F T F F

nb:

  • Tautologi adalah pernyataan logika yang selalu benar, tidak peduli nilai kebenaran dari komponen-komponennya. contoh
p q p ∧ q ¬(p ∧ q) p ∨ ¬(p ∧ q)
TTTFT
TFFTT
FTFTT
FFFTT
  • Kontradiksi adalah pernyataan logika yang selalu salah, tidak peduli nilai kebenaran dari komponen-komponennya. contoh
p q p ∧ q p ∨ q ¬(p ∨ q) (p ∧ q) ∧ ¬(p ∨ q)
TTTTFF
TFFTFF
FTFTFF
FFFFTF
- ekivalen Intinya, jika dioperasikan, dia punya hasil tabel kebenaran yang identik, walau rumusnya beda.

gambar wikipedia hukum de morgan

p q p ∧ q ¬(p ∧ q) ¬p ¬q ¬p ∨ ¬q
TTTFFFF
TFFTFTT
FTFTTFT
FFFTTTT

Hukum hukum nya

Bahasa IndonesiaBahasa InggrisContoh
Hukum IdentitasIdentity Lawp ∧ T ≡ p, p ∨ F ≡ p
Hukum DominasiDomination Lawp ∨ T ≡ T, p ∧ F ≡ F
Hukum IdempotensiIdempotent Lawp ∨ p ≡ p, p ∧ p ≡ p
Hukum NegasiNegation Lawp ∨ ¬p ≡ T, p ∧ ¬p ≡ F
Hukum KomutatifCommutative Lawp ∨ q ≡ q ∨ p, p ∧ q ≡ q ∧ p
Hukum AsosiatifAssociative Law(p ∨ q) ∨ r ≡ p ∨ (q ∨ r)
Hukum DistributifDistributive Lawp ∨ (q ∧ r) ≡ (p ∨ q) ∧ (p ∨ r)
Hukum De MorganDe Morgan’s Laws¬(p ∧ q) ≡ ¬p ∨ ¬q, ¬(p ∨ q) ≡ ¬p ∧ ¬q
Hukum InvolusiDouble Negation / Involution¬(¬p) ≡ p
Hukum ImplikasiImplication Lawp → q ≡ ¬p ∨ q
Hukum BiimplikasiBiconditional Lawp ↔ q ≡ (p → q) ∧ (q → p)

Implikasi

Disebut juga proposisi bersyarat, seperti jika x maka y, notasinya \( p \rightarrow q\). \( p \) nya adalah condition, \( q \) nya adalah conlusion

pqp → q
TTT
TFF
FTT
FFT

versi versinya jika dijadikan teks

  • Jika p, maka q (if p, then q)
  • Jika p, q (if p, q)
  • p mengakibatkan q (p implies q)
  • q jika p (q if p)
  • p hanya jika q (p only if q)
  • p syarat cukup untuk q (p is sufficient condition for q)
  • q syarat perlu bagi p (q is necessary condition for q)
  • q bilamana p (q whenever p)
  • q mengikuti dari p (q follows from p)

penjelasan kenapa \( F \rightarrow F = T \)

“If I win the lottery, I’ll buy you a car.”
I didn't win the lottery → (False)

I didn't buy a car → (False)

dan juga \( P \rightarrow Q \) sebenarnya sama dengan \( \sim{P} \vee Q \)

Penjelasan kenapa \( \sim (p \rightarrow q )\) itu sama dengan \( p \space \wedge \sim{q} \)

Kita tahu bahwa \( p \rightarrow q \) itu sebenarnya sama dengan \( \sim{p} \vee p \) , maka steps yang dibutuhkan hanya

  • \( \sim(p \rightarrow q) \)
  • \( \sim(\sim{p} \vee q) \)
  • \( p \space \wedge \sim{q} \)

tabel varian implikasi (Proporsi bersyarat)

  • Konvers (kebalikan): \( q \rightarrow p \)
  • Invers : \( \sim p \rightarrow \sim q \)
  • Kontraposisi : \( \sim q \rightarrow \sim p \)
pq¬p¬qp → qq → p¬p → ¬q¬q → ¬p
TTFFTTTT
TFFTFTTF
FTTFTFFT
FFTTTTTT

Bi-impication

Intinya, operand kanan kiri harus sama, entah sama sama true, atau sama sama false. notasinya: \( p \leftrightarrow q \)

tabel kebenaran

pqp ↔ q
TTT
TFF
FTF
FFT

contoh

pqp ↔ qp → qq → p(p → q) ∧ (q → p)
TTTTTT
TFFFTF
FTFTFF
FFTTTT

analogi simple:

  • Jika suatu bilangan genap, maka habis dibagi 2: \( \text{true} \leftrightarrow \text{true} = \text{true} \)

  • Jika suatu bilangan bukan genap, maka tidak akan habis dibagi 2: \( \text{false} \leftrightarrow \text{false} = \text{true} \)

kumpulan soal Matematika Diskrit

No. 1

Dalam sebuah survei terhadap 120 orang, diperoleh data sebagai berikut:

  • 65 orang suka kopi
  • 70 orang suka teh
  • 50 orang suka cokelat
  • 30 orang suka kopi dan teh
  • 28 orang suka kopi dan cokelat
  • 26 orang suka teh dan cokelat
  • 15 orang suka semua minuman
  • Semua orang minimal menyukai satu jenis minuman

Tentukan:

  1. Banyak orang yang hanya suka kopi
  2. Banyak orang yang suka teh dan cokelat, tapi tidak suka kopi
  3. Banyak orang yang suka tepat dua jenis minuman
  4. Banyak orang yang hanya suka satu jenis minuman

No. 2

Jika diketahui

  • S = {1,2,3 …, 15},
  • A = { 2,3,5,7},
  • B = { 1,3,5,7,9},
  • C = {2,4,6,8}

Tentukan :

  1. A ∪ B ∪ C
  2. A ∩ C
  3. B - A
  4. (A’ ∩ B) - C
  5. (B - C) ∩ A’

No. 3

Dalam survei terhadap 80 mahasiswa, diperoleh data:

  • 45 mahasiswa suka Matematika
  • 38 mahasiswa suka Fisika
  • 40 mahasiswa suka Kimia
  • 20 mahasiswa suka Matematika dan Fisika
  • 25 mahasiswa suka Fisika dan Kimia
  • 18 mahasiswa suka Matematika dan Kimia
  • 10 mahasiswa suka ketiga mata kuliah
  • 8 mahasiswa tidak suka semua mata kuliah

tentukan

  1. Banyak mahasiswa yang suka hanya Matematika
  2. Banyak mahasiswa yang suka tepat dua mata kuliah
  3. Banyak mahasiswa yang suka Matematika atau Kimia tapi tidak Fisika
  4. Banyak mahasiswa yang suka hanya satu mata kuliah
Catatan
format latex menyusul

asal usul rumus sudut vektor

awal mula dari rumus entah berantah ini. link untuk oprek rumus: https://proofwiki.org/wiki/Cosine_Formula_for_Dot_Product

\[ \vec{A} \cdot \vec{B} = |\vec{A}| |\vec{B}| cos(\theta) \]

lalu \[ \frac{\vec{A} \cdot \vec{B}}{|\vec{A}| |\vec{B}|} = cos(\theta) \]

lalu kita bisa balik, menjadi \[ cos(\theta) = \frac{\vec{A} \cdot \vec{B}}{|\vec{A}| |\vec{B}|} \]

\[ arccos(\frac{\vec{A} \cdot \vec{B}}{|\vec{A}| |\vec{B}|}) = \theta \]

solved!

transformasi elementer

beberapa notasi aneh disini diderive dari PPT kampus.

  • \( H_{ij}A \): Swap baris i dengan baris j
  • \( H_i^{(k)} \): mengalikan baris i dengan konstanta k
  • \( H_{ij}^{(k)} \): hitung dulu konstanta k dikali baris j, lalu hasilnya ditambah baris i, simpan jg hasilnya ke baris i
  • \( H_{i \space \space \space \space \space \space \space j}^{\space \space (k) \space \space \space (z)}(A)_i \): intinya, baris ke i dikalikan dgn k, kalau udah lanjut hitung baris j dikalikan z. setelah itu hasilnya tentusaja simpan ke i hasil itung2 an tadi.

Cryptography

Alur konek ke RPC server telegram

step ini dibuat oleh seseorang dari masa lalu sekitar tahun 2020 yang akunnya telah terhapus, credit kepada Butthx

`originals written in telegram chat, but because I want to preserve it. I write it here

step 1:

Bikin koneksi ke server telegram pakai TCP yang tersedia (disini gwa pakai TCPIntermediate)

step 2:

Bikin random nonce dengan value int128

step 3:

Kirim bytes dari ReqPqMulti dengan value bytes dari nonce tadi.

step 4:

pick salah satu dari beberapa publick fingerprints yang diberikan dari results step3.

step 5:

Lakuin faktor bilangan pq yang diberikan dari results step3, dapetin lagi hasil pembagian dari pq tadi dengan hasil faktor, terus urutkan dari yang terkecil. untuk yang kecil di kasih nama p dan yang besar kasih nama g.

step 6:

bikin nonce baru (jangan ubah nonce yang lama) dengan value random int256.

step 7:

bikin hash (sha1) dari bytes PQInnerData ke telegram: bytes[pq,bytes p,bytes q,nonce,nonce baru,server nonce (dapet dari step3)]

step 8:

bikin padding dengan random bytes dengan panjang -(length bytes PQInnerData + length sha1) mod 255

step 9:

encrypt bytes[sha,bytes PQInnerData,padding] dengan RSA (pakai publik fingerprints tadi)

step 10:

kirim bytes ReqDhParams: bytes[nonce,server nonce, bytes p, bytes q, encrypted data (step9) ,fingerprint]

step 11:

bikin temporary aes key: bytes[sha1[bytes nonce baru, bytes server nonce],sha1[bytes server nonce, bytes nonce baru] slice 0 – 12]

step 12:

bikin temporary aes initial vector (IV): bytes[sha1[bytes server nonce, bytes nonce baru] slice 12 – end, sha1[bytes nonce baru,bytes nonce baru], bytes[nonce baru] slice 0 – 4 ]

step 13:

decrypt encryptedAnswer (dapet dari step 10) menggunakan AES-256-IGE pakai key sama iv tadi.

step 14:

parse decrypted answer tadi ke TLSchema/TLObject

step 15:

bikin random int(panjang 256 bytes, bukan int256 ygy) kita beri nama b

step 16:

dapetin g_b dengan (g ** b) mod dh_prime

  • g, dh_prime → dapet dari step 14

step 17:

bikin hash sha1 dari bytes[ClientDhInnerData[nonce, server nonce, 0,unsigned big bytes g_b length 256]]

step 18:

bikin padding dengan length -(length bytes ClientDhInnerData + length sha1) mod 16

step 19:

encrypt bytes[bytes step 17,bytes ClientDhInnerData, padding ] dengan AES-256-IGE, key sama iv masih menggunakan yang step 11.

step 20:

kirim bytes[SetClientDhParams[nonce, server nonce, bytes step 19]]

step 21:

Bikin auth key dengan big-unsigned-bytes[big-u-int(g_a) ** b mod dhPrime] length 256

step 22:

Lakuin security check..

notes: Untuk format pengiriman bytes:

bytes[sessionId,messageId,length content,content]
karena belum ada authkey, jadi sessionId  = Buffer.alloc(8)

untuk dapetin real data dari telegram, slice bytes yang di terima dari 20 – end

pengiriman content selalu bentuk bytes, jadi semua parameter jadiin bytes :)

/**
 * tgsnake - Telegram MTProto framework for nodejs.
 * Copyright (C) 2022 butthx <https://github.com/butthx>
 *
 * THIS FILE IS PART OF TGSNAKE
 *
 * tgsnake is a free software : you can redistribute it and/or modify
 * it under the terms of the MIT License as published.
 */

export const DCTest = {
  1: '149.154.175.10',
  2: '149.154.167.40',
  3: '149.154.175.117',
};
export const DCProd = {
  1: '149.154.175.53',
  2: '149.154.167.51',
  3: '149.154.175.100',
  4: '149.154.167.91',
  5: '91.108.56.130',
};
export const DCProdMedia = {
  2: '149.154.167.151',
  4: '149.154.164.250',
};
export const DCTestIPV6 = {
  1: '2001:b28:f23d:f001::e',
  2: '2001:67c:4e8:f002::e',
  3: '2001:b28:f23d:f003::e',
};
export const DCProdIPV6 = {
  1: '2001:b28:f23d:f001::a',
  2: '2001:67c:4e8:f002::a',
  3: '2001:b28:f23d:f003::a',
  4: '2001:67c:4e8:f004::a',
  5: '2001:b28:f23f:f005::a',
};
export const DCProdMediaIPV6 = {
  2: '2001:067c:04e8:f002:0000:0000:0000:000b',
  4: '2001:067c:04e8:f004:0000:0000:0000:000b',
};
export function DataCenter(
  dcId: number,
  testMode: boolean,
  ipv6: boolean,
  media: boolean
): [ip: string, port: number] {
  if (testMode) {
    return [ipv6 ? DCTestIPV6[dcId] : DCTest[dcId], 80];
  } else {
    if (media) {
      return [ipv6 ? DCProdMediaIPV6[dcId] : DCProdMedia[dcId], 443];
    } else {
      return [ipv6 ? DCProdIPV6[dcId] : DCProd[dcId], 443];
    }
  }
}

ca-certificates

draft: mengoprek kriptografi dibalik HTTPS & konsep public private key pair dan juga peran CA authority, kenapa mereka harus dimasukkan ke package ???

dan juga kenapa MITM (Man in the Middle) bisa melogging jaringan, ketika certificate telah dipasang. kenapa hanya dengan certificate mitm bisa mendecode data yang lewat.

Server

Cgit setup

Ku mau share pengalaman bikin self hosting git server, pakai cgit, biar engga kalah aja sama git.kernel.org dan kernel.dk wkwk

step satu, include dir nya sites-available spt biasa, contoh config nya https://gist.github.com/fadhil-riyanto/328f2cc0607eb58b713cdeaa473d08ee, lalu config untuk sites-available nya https://gist.github.com/fadhil-riyanto/c2e26de30c97600e4ee9342aefbd6ece

nb: install fcgiwrap dulu

lalu edit /etc/cgitrc, contoh config: https://gist.github.com/fadhil-riyanto/4033e6ce59a35568c31dbd5e5a1d29bd

harusnya sampai sini, cgit dah bisa diakses, cuman empty repository aja.

ok, lalu kita ke permission2 nya, pertama2 pakai akun root, tldr

cd /root
mkdir git
cd git
mkdir user1, misal aja mkdir fadhil_riyanto
cd fadhil_riyanto

clone git apapun disini, misal git clone https://github.com/fadhil-riyanto/reponame.git --bare (harus pakai bare)

posisi dir ini di /root/git/fadhil-riyanto/reponame.git

ok, balik ke parent dir, posisi di /root/git lakukan chown -R fadhil_riyanto fadhil-riyanto, jika engga nanti error "git submodule update" failed with 'fatal: detected dubious ownership in repository at...' etc...

ok, saatnya push git remote add cgit fadhil_riyanto@123.123.111.222:/root/git/fadhil-riyanto/reponame.git

config HTTPS nginx

Cara config HTTPS di server pakai certbot (NGINX)

  • apt install certbot python3-certbot-nginx
  • verify config na pakai nginx -t
  • generate cert na pakai certbot --nginx -d namasite.com

ganti namasite.com dengan embel2 di /etc/nginx/sites-enabled/somefile.conf

didalamnya kan ada server_name, nah diganti dgn itu

Setup virtual network interface

cara setup virtual ethernet + assign ip nya

  • sudo ip link add veth0 type dummy

bisa dicek pakai ip addr

[11:11:35] fadhil_riyanto@integral2 /etc/systemd/network  
> ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: enp2s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether 2c:4d:54:c6:f2:0c brd ff:ff:ff:ff:ff:ff
    altname enx2c4d54c6f20c
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether f0:03:8c:66:9c:21 brd ff:ff:ff:ff:ff:ff
    inet 192.168.5.44/24 brd 192.168.5.255 scope global dynamic noprefixroute wlan0
       valid_lft 581sec preferred_lft 581sec
    inet 192.168.5.197/24 metric 1024 brd 192.168.5.255 scope global secondary dynamic wlan0
       valid_lft 582sec preferred_lft 582sec
    inet6 fe80::5574:5771:be47:2f7b/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::f203:8cff:fe66:9c21/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever
4: veth0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ether 76:4d:3f:3d:11:7f brd ff:ff:ff:ff:ff:ff
    inet6 fe80::744d:3fff:fe3d:117f/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

lalu assign ip nya

  • sudo ip addr add 192.168.100.10/24 dev veth0
  • sudo ip link set veth0 up

dan bisa diping juga image

untuk remove interface nya bisa pakai sudo ip link delete vnet0

some sorts of equalivalent command

  • Create bridge: brctl addbr br0 ip link add br0 type bridge
  • Delete bridge: brctl delbr br0 ip link delete br0
  • Add interface to bridge: brctl addif br0 eth0 ip link set eth0 master br0
  • Remove interface from bridge: brctl delif br0 eth0 ip link set eth0 nomaster
  • Show bridge info: brctl show or brctl show br0 bridge link show or ip link show master br0
  • Enable/disable STP: brctl stp br0 on/off bridge link set dev eth0 guard off/on (note: STP enable/disable logic is reversed)

ip aliasing

satu interface bisa punya lebih dari 1 IP dinamai sebagai IP aliasing. contoh

eth0 bisa punya 2 ip dengan cara

  • ip addr add 192.168.1.100/24 dev eth0
  • ip addr add 192.168.1.101/24 dev eth0

atau bisa juga ada 2 interface, katakanlah eth0 dengan eth1, masing2 punya ip nya sendiri2 dengan cara

ip addr add 192.168.1.10/24 dev eth0
ip addr add 10.0.0.5/24 dev eth1

tambahan

untuk ngeremove salah satu ip nya, bisa dengan ip addr del <IP NYA>/<CIDR> dev <IFACE>

Setup bridge enp0s16u1

bisa di test dengan

  • hapus dahulu ip yang tadi diberikan ke br0 pakai sudo dhclient -r br0, pastikan ip nya kosong
  • lalu hapus ip milik enp0s16u1
  • test ping
  • lalu lakukan lagi sudo dhclient br0

image

reverse command

Pakai ini untuk in-case ada kesalahan

hapus ip br0

  • ip addr show br0
  • sudo ip addr del 192.168.1.10/24 dev br0

tambahan, kadang tidak bener2 kehapus karna mungkin NetworkManager, systemd-networkd, dhclient aktif.

image

nb: untuk dhcp kadang NetworkManager sama systemd-networkd bertabrakan, solusinya stop dahulu pakai

  • sudo systemctl stop systemd-networkd.socket
  • sudo systemctl stop systemd-networkd

next, buat bridge ke VM. topologi

   [Internet]
       |
     Router
       |
     eth0 (on host) → br0 (bridge)
                      |
    +--------+--------+--------+
    |        |        |        |
  VM1      VM2      VM3      etc.
  ↳ 192.168.12.101   192.168.12.102   ...

mulai dari sini akan utak atik veth

setup veth manual

  • sudo ip link add veth0 type veth peer name veth0-peer
  • sudo ip link set veth0 master br0
  • sudo ip link set veth0 up
  • sudo ip link set veth0-peer up
  • sudo dhclient veth0-peer

topologinya kira2 seperti ini

                +---------------------------+
                |        Linux Host         |
                |                           |
                |   +-------------------+   |
                |   |       br0         |   |  ← bridge acting as a virtual switch
                |   +--------+----------+   |
                |            |              |
                |         veth0            ... ← more veths for other containers/VMs
                |            |
                +------------+--------------+
                             |
                             | (virtual cable)
                             |
                         veth0-peer
                             |
                    +------------------+
                    |   Container/VM   |  ← gets its own IP
                    +------------------+

lanjut assign veth-peer ke qemu (pakai tap device)

topology:

            Linux Host
       +------------------+
       |      br0         |  ← acts as switch
       +--+-----------+---+
          |           |
        eth0         tap0  ← tap device for QEMU VM
                        |
                   QEMU VM

attach

sudo ip tuntap add dev tap0 mode tap
sudo ip link set tap0 up
sudo ip link set tap0 master br0

qemu

sudo qemu-system-x86_64 \
  -enable-kvm \
  -m 2048 \
  -hda ubuntu.qcow2 \
  -netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
  -device virtio-net-pci,netdev=net0

test qemu mikrotik

qemu-system-x86_64 \
                -enable-kvm \
                -boot order=d \
                -drive file=chr.qcow2,format=qcow2 \
                -m 4G \
                -smp 4 \
                -net user,hostfwd=tcp::10022-:22,hostfwd=tcp::8080-:8080 \
                -netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
                -device virtio-net-pci,netdev=net0

untuk test nya, bisa dengan

  • cek ip mikrotik pakai /ip address print
  • lalu ip netns exec namespace_satu ping <IP NYA>
  • Bisa juga pakai dummy http server php, caranya sudo ip netns exec namespace_satu php -S 192.168.12.82:1234 (cek dahulu ip namespace pakai ip addr)

contoh setup pakai namespace

  • create dulu pakai sudo ip netns add namespace_satu
  • set sudo ip link set veth0-peer netns namespace_satu
  • cek dahulu, pastikan didalamnnya masih kosong ip nya, pakai sudo ip netns exec namespace_satu ip addr image
  • lalu kita nyalakan veth0-peer nya sudo ip netns exec namespace_satu ip link set dev veth0-peer up, tapi tetap saja masih belum dapat ip. maka next kita exec dhclient pakai sudo ip netns exec namespace_satu dhclient veth0-peer image
  • test ping keluar image

Setup shadowsocks proxy server

shadowsocks-libev is available in the official repository for Debian 9("Stretch"), unstable, Ubuntu 16.10 and later derivatives:

sudo apt update
sudo apt install shadowsocks-libev

then, create a file config on /etc/shadowsocks-libev/config.json which has contents something like this

{
    "server":["::1", "10.1.1.4"],
    "mode":"tcp_and_udp",
    "server_port":8388,
    "local_port":1080,
    "password":"1u21wW3E0bwu",
    "timeout":86400,
    "method":"chacha20-ietf-poly1305"
}

in this case, I use 10.1.1.4 as local ip, then forwarded through firewall to the public addr.

then, sudo systemctl start shadowsocks-libev

ref: https://shadowsocks.org/doc/configs.html

connect

Alpine htop install on live QEMU

create disk first

qemu-img create -f qcow2 alpine-1.qcow2 1G

start qemu

download iso here https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/x86_64/alpine-virt-3.21.3-x86_64.iso

qemu-system-x86_64 \
      -enable-kvm \
      -m 256 \
      -smp 4 \
      -cpu host \
      -drive file=pc-1.qcow2,format=qcow2 \
      -cdrom alpine-virt-3.21.3-x86_64.iso \
      -boot d \
      -net nic \
      -net user -nographic

default username is root, password left blank, just enter

set eth0 up & DHCP

  • ip link set dev eth0 up
  • udhcpc -i eth0
  • ping 1.1.1.1 (testing)

for /etc/resolv.conf, change to nameserver 1.1.1.1

patch apk configuration

cp /etc/apk/repositories /etc/apk/repositories-old

--- repositories-old
+++ repositories
@@ -1 +1,2 @@
-/media/cdrom/apks
+http://dl-cdn.alpinelinux.org/alpine/v3.21/main
+http://dl-cdn.alpinelinux.org/alpine/v3.21/community

update

  • apk update
  • apk cache download
  • apk cache -v sync

setup partition

Note

set it with your needs, I use entire disk in this docs

make sure first your ext4 kernel module is installed & loaded by typing

  • lsmod | grep ext4: check
  • modprobe ext4
  • lsmod | grep ext4: recheck again

the output is should be something like this image

then we can move forward to ext4 partition generation

partitioning

install parted first using apk add parted, check your disk first using fdisk -l, for example there is /dev/sda

parted section

run parted /dev/sda, inside of parted is

  • unit s
  • mklabel [gpt/msdos]: I use msdos anyway
  • print: identify disk size by see on section something like Disk /dev/sda: 2097152s, there has 2097152s sector, so I use 2097152 - (2948 * 2), which is 2093056s
  • mkpart
    • primary
    • ext4
    • 2048s
    • 2093056s
      • q

resulted partition: image

setup diskless install

warn: you need to enable ext4 kernel module or you'll get mount: mounting /dev/sda1 on /media/sda1 failed: Invalid argument when mounting

  • modprobe ext4
  • apk add e2fsprogs for mkfs.ext4 command
  • mkfs.ext4 /dev/sda1
  • mount /dev/sda1 /media/sda1: mount location should be located on /media, not /mnt

then, you can do normal setup-alpine, except for this thing

  • Which disk(s) would you like to use? (or '?' for help or 'none') [none] none
  • Enter where to store configs ('floppy', 'sda1', 'usb' or 'none') [sda1] sda1
  • Enter apk cache directory (or '?' or 'none') [/media/sda1/cache] /media/sda1/cache

LBU

run lbu commit

Run router-OS on qemu

on normal interface

qemu-system-x86_64 \
          -enable-kvm \
          -boot order=d \
          -cdrom chr-6.49.18.img \
          -drive file=chr.qcow2,format=qcow2 \
          -m 4G \
          -smp 4 \
          -net user,hostfwd=tcp::10022-:22,hostfwd=tcp::8291-:8291 \
          -net nic

setup linux bridge between RouterOS & Alpine linux hosts

this docs is second part of this

first thing that we need to do is create a copy of qcow2 alpine, so we do not need to re-install again. do not forget to change the hostname & password for easy identification

setup bridge

  • sudo ip link add br0-lan type bridge
  • sudo ip link add br1-lan type bridge

setup TAP

tap0 & tap1 connected to br0-lan tap2 & tap3 connected to br1-lan

  • sudo ip tuntap add dev tap0 mode tap
  • sudo ip tuntap add dev tap1 mode tap
  • sudo ip tuntap add dev tap2 mode tap
  • sudo ip tuntap add dev tap3 mode tap
  • sudo ip link set tap0 master br0-lan
  • sudo ip link set tap1 master br0-lan
  • sudo ip link set tap2 master br1-lan
  • sudo ip link set tap3 master br1-lan
  • sudo ip link set tap0 up
  • sudo ip link set tap1 up
  • sudo ip link set tap2 up
  • sudo ip link set tap3 up

launch mikrotik ISO

qemu-system-x86_64 \
      -enable-kvm \
      -boot order=d \
      -drive file=chr.qcow2,format=qcow2 \
      -m 256M \
      -smp 4 \
      -netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
      -device virtio-net-pci,netdev=net0,mac=02:11:2a:3b:ff:c3  \
      -netdev tap,id=net1,ifname=tap2,script=no,downscript=no \
      -device virtio-net-pci,netdev=net1,mac=02:1a:f2:f1:21:b5  \
      -nographic \
      -net user,hostfwd=tcp::10022-:22,hostfwd=tcp::8291-:8291 \
      -net nic

image

based on topology, we know that

  • 02:11:2a:3b:ff:c3 used by tap0 (in routerOS, bridge 0)
  • 02:1a:f2:f1:21:b5 used by tap2 (in routerOS, bridge 1)
  • tap1 & tap3 used by alpine virtual machine

now run alpine iso

alpine (as pc-1)

qemu-system-x86_64 \
            -enable-kvm \
            -m 256 \
            -smp 4 \
            -cpu host \
            -drive file=pc-1.qcow2,format=qcow2 \
            -cdrom alpine-virt-3.21.3-x86_64.iso \
            -boot d \
            -nographic \
            -netdev tap,id=net0,ifname=tap1,script=no,downscript=no \
            -device virtio-net-pci,netdev=net0

alpine (as pc-3)

qemu-system-x86_64 \
            -enable-kvm \
            -m 256 \
            -smp 4 \
            -cpu host \
            -drive file=pc-2.qcow2,format=qcow2 \
            -cdrom alpine-virt-3.21.3-x86_64.iso \
            -boot d \
            -nographic \
            -netdev tap,id=net0,ifname=tap3,script=no,downscript=no \
            -device virtio-net-pci,netdev=net0

WinBox config

first, we need to see the configuration & which etherX by looking to spesific mac-addr, we find out that

[admin@MikroTik] > /interface print
Flags: D - dynamic, X - disabled, R - running, S - slave 
 #     NAME                                TYPE       ACTUAL-MTU L2MTU  MAX-L2MTU MAC-ADDRESS      
 0  R  ;;; wan
       ether1                              ether            1500                  52:54:00:12:34:56
 1  R  ether4                              ether            1500                  02:11:2A:3B:FF:C3
 2  R  ether5                              ether            1500                  02:1A:F2:F1:21:B5
[admin@MikroTik] > 

next thing, lets configure our ip using winbox, this is ip configuration image

DHCP server section image

now, try run udhcpc -i eth0 on each vm

result on pc-1

image

result on pc-2

image

Linux iptables preview (try making a nat)

for example, iptables -t nat the t option from manpage is

          filter:
              This  is  the  default  table  (if  no -t option is passed). It contains the built-in
              chains INPUT (for packets destined to local  sockets),  FORWARD  (for  packets  being
              routed through the box), and OUTPUT (for locally-generated packets).

          nat:
              This  table  is consulted when a packet that creates a new connection is encountered.
              It consists of four built-ins: PREROUTING (for altering packets as soon as they  come
              in),  INPUT  (for  altering packets destined for local sockets), OUTPUT (for altering
              locally-generated packets before routing), and POSTROUTING (for altering  packets  as
              they are about to go out).  IPv6 NAT support is available since kernel 3.7.

          mangle:
              This table is used for specialized packet alteration.  Until kernel 2.4.17 it had two
              built-in chains: PREROUTING (for altering incoming packets before routing) and OUTPUT
              (for  altering locally-generated packets before routing).  Since kernel 2.4.18, three
              other built-in chains are also supported: INPUT (for packets coming into the box  it‐
              self),  FORWARD  (for altering packets being routed through the box), and POSTROUTING
              (for altering packets as they are about to go out).

          raw:
              This table is used mainly for configuring exemptions from connection tracking in com‐
              bination with the NOTRACK target.  It registers at the netfilter  hooks  with  higher
              priority and is thus called before ip_conntrack, or any other IP tables.  It provides
              the  following  built-in chains: PREROUTING (for packets arriving via any network in‐
              terface) and OUTPUT (for packets generated by local processes).

          security:
              This table is used for Mandatory Access Control (MAC) networking rules, such as those
              enabled by the SECMARK and CONNSECMARK targets.  Mandatory Access Control  is  imple‐
              mented by Linux Security Modules such as SELinux.  The security table is called after
              the filter table, allowing any Discretionary Access Control (DAC) rules in the filter
              table  to  take  effect before MAC rules.  This table provides the following built-in
              chains: INPUT (for packets coming into the box itself), OUTPUT (for altering locally-
              generated packets before routing), and FORWARD (for  altering  packets  being  routed
              through the box).

What kind of tables in iptables

according from archlinux wiki

iptables contains five tables:

  • raw is used only for configuring packets so that they are exempt from connection tracking.
  • filter is the default table, and is where all the actions typically associated with a firewall take place.
  • nat is used for network address translation (e.g. port forwarding).
  • mangle is used for specialized packet alterations.
  • security is used for Mandatory Access Control networking rules (e.g. SELinux -- see this article for more details).

In most common use cases, you will only use two of these: filter and nat. The other tables are aimed at complex configurations involving multiple routers and routing decisions and are in any case beyond the scope of these introductory remarks.

Tables & chain details

all iptables chain information can be gathered by this command

sudo iptables -t filter -L
sudo iptables -t nat -L
sudo iptables -t mangle -L
sudo iptables -t raw -L
sudo iptables -t security -L

this is list of all chain by corresponding table

table raw

  • PREROUTING
  • OUTPUT

table nat

  • PREROUTING
  • INPUT
  • OUTPUT
  • POSTROUTING

table mangle

  • PREROUTING
  • INPUT
  • FORWARD
  • OUTPUT
  • POSTROUTING

table filter

  • INPUT
  • FORWARD
  • OUTPUT

table security

  • INPUT
  • FORWARD
  • OUTPUT

we will focus on NAT section.

machine session

In iptables, packet often categorized as 4 different state, such

  • NEW
  • ESTABLISHED
  • RELATED
  • INVALID

this connection tracking is done by a special framework within the kernel called conntrack

command lists

this is some special iptables command collection

  • iptables --list-rules: show all ip rules
  • iptables --table nat --list --line-numbers: will useful if you want to delete spesific rule, i.e, duplicated rule
  • sudo iptables --table nat -D POSTROUTING 2 example: delete rule 2

create your own chain

  • iptables -N chain_name: eq: --new-chain
  • iptables -A chain_name -p icmp -j accept (example)

make changes permanent

sudo iptables-save > /etc/iptables/rules.v4

tables explanation

> sudo iptables --table nat --list
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere             anywhere            
MASQUERADE  all  --  anywhere             anywhere            
MASQUERADE  all  --  anywhere             anywhere            
MASQUERADE  all  --  anywhere             anywhere            

target: what to do with packet. prot: abbr of protocol opt: abbr of options (AI says rarely used) source: its anywhere or explicit ip such 192.168.1.0/24 destination: same as source, can be network

show rules from X table

for example, there has

  • nat table, which contains PREROUTING, INPUT, OUTPUT, POSTROUTING
  • filter table contains main chain that used by iptables for packet filtering, which contains INPUT, FORWARD, OUTPUT

MORE deeper on X table

TablePurposeChains it uses
filterDefault, handles packet filteringINPUT, OUTPUT, FORWARD
natNetwork Address TranslationPREROUTING, POSTROUTING, OUTPUT
manglePacket modification (TTL, TOS, etc.)All chains
rawPre-connection tracking processingPREROUTING, OUTPUT
securitySELinux/LSM-based packet filteringINPUT, OUTPUT, FORWARD

Linux QEMU network address translation

first all, set setup our interface

  • sudo ip tuntap add tap0 mode tap
  • sudo ip tuntap add tap1 mode tap (optional, if there has any more vm)
  • sudo ip link add br0-lan type bridge (our switch)
  • sudo ip addr add 192.168.12.1/24 dev br0-lan
  • sudo ip link set br0-lan up
  • sudo ip link set tap0 up, also with tap1 if needed

Run alpine guest hosts

qemu-system-x86_64 \
            -enable-kvm \
            -m 256 \
            -smp 4 \
            -cpu host \
            -drive file=pc-2.qcow2,format=qcow2 \
            -cdrom alpine-virt-3.21.3-x86_64.iso \
            -boot d \
            -nographic \
            -netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
            -device virtio-net-pci,netdev=net0

Inside of guest VM

Your ip addr output might something like this

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
    link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::5054:ff:fe12:3456/64 scope link 
       valid_lft forever preferred_lft forever

now set eth0 up by typing

  • ip link set eth0 up
  • ip addr add 192.168.12.2/24 dev eth0 (I manually setting up IP)

check ip route

pc-2:~# ip r
192.168.12.0/24 dev eth0 scope link  src 192.168.12.2 

there is no route, run ip route add default via 192.168.12.1, check again with ip route

pc-2:~# ip r
default via 192.168.12.1 dev eth0 
192.168.12.0/24 dev eth0 scope link  src 192.168.12.2 

setting up firewall

we want everyting from br0-lan is forwarded into wlan0, vice versa. in order to do that, we need NAT (network address translation)

here

check your nat table first

sudo iptables --table nat --list -v, make sure there is no

 2151  499K MASQUERADE  all  --  any    wlan0   anywhere             anywhere            

now run

  • sudo iptables --table nat --append POSTROUTING --out-interface wlan0 -j MASQUERADE
  • sudo iptables -t filter -A FORWARD -i wlan0 -o br0-lan -m state --state RELATED,ESTABLISHED -j ACCEPT
  • sudo iptables -t filter -A FORWARD -i br0-lan -o wlan0 -j ACCEPT

QEMU block 8.8.8.8 from host

after this

I want this rule

  • allow other ICMP (i.e 1.1.1.1)
  • deny ICMP 8.8.8.8

iptables rule

suppose, vm ip is 192.168.12.2, so the iptables command is

sudo iptables -t filter -A FORWARD -s 192.168.12.2 -d 8.8.8.8 -p icmp -j DROP

note:

  • t: explicit table
  • a: table FORWARD
  • s: source from 192.168.12.2 (OUR VM)
  • d: destination: 8.8.8.8
  • p: protocol (which is ICMP)
  • j: jump

the problem

you may see ping 8.8.8.8 still success, let check iptables rule

sudo iptables -t filter -L FORWARD -n --line-numbers -v

the output

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination         
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
2    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
3    DROP       icmp --  192.168.12.2         8.8.8.8             

see? when ping to 8.8.8.8, its stop at rule 2, which abort 3st rule, in order to fix it, we need re-order this

remote all rule

sudo iptables -t filter -F FORWARD

re-add

sudo iptables -t filter -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -t filter -A FORWARD -s 192.168.12.2 -d 8.8.8.8 -p icmp -j DROP
sudo iptables -t filter -A FORWARD -s 192.168.12.2/24 -j ACCEPT

Try re-run sudo iptables -t filter -L FORWARD -n --line-numbers

the order should be fixed

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination         
1               all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
2    DROP       icmp --  192.168.12.2         8.8.8.8             
3    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           

image

two alpine guest VM, block custom ports

logic netfilter linux kernel

Logic NAT

misalkan kita ada virtual interface br0, dengan anggotanya tap0, tap1 lalu ingin forward semua traffic ke wlan0 (karna memang wlan0 tidak bisa di jadikan master dari x y z)

maka solusinya iptables

sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE

logic nya

  • fill dulu tabel nat
  • append ke postrouting, jadi setelah packet di routing oleh linux kernel, ada 2 field, source addr (katakanlah ip tap0) lalu destination addr (misal 8.8.8.8)
  • nah, semisal tidak di apa apakan, packet sent ke 8.8.8.8, tapi 8.8.8.8 tidak bisa mengirim back packetnya karna source addr nya invalid (di stage ini, source ip nya adalah IP LAN)
  • maka, setelah linux kernel meng-routingkan packet nya, seketika setelah itu (postrouting), kita ganti source addrnya dengan source ip PUBLIK milik firewall, jadi 8.8.8.8 bisa tahu kemana packet harus dikirim kembali
  • didalam firewall, packet yang tadi diterima, direverse balik oleh nat, dan dikirim balik ke perangkat aslinya.
  • pakai MASQUERADE

logic forward data dari br0 ke wlan

sudo iptables -A FORWARD -i br0 -o wlan0 -j ACCEPT

important notes:

  • chain FORWARD: This chain is only used for packets that are not destined for the local machine, but are routed through it (i.e., from one interface to another).
  • In this case: a device connected to br0 (e.g., a VM or container) wants to access the internet via wlan0.

analoginya

[Device 192.168.100.2] ──> [br0 (Linux bridge)] ──> Linux router ──> [wlan0] ──> Internet

bisa juga -j diganti drop, maka aliran data akan terputus

logic forward dari wlan0 ke br0 (sebaliknya)

sudo iptables -A FORWARD -i wlan0 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT

logic:

  • misal vm tap0 buat koneksi keluar, misal ke 8.8.8.8
  • dari tap0 -> br0 -> wlan0 di allow oleh rule sudo iptables -A FORWARD -i br0 -o wlan0 -j ACCEPT
  • ketika server mengirim respon balik, maka alurnya dari wlan0 ke br0, nah ini fungsi dari sudo iptables -A FORWARD -i wlan0 -o br0 -j ACCEPT

KENAPA harus pakai --state RELATED,ESTABLISHED karna kita butuh packet yg sudah estab duluan yg boleh lewat. ini akan menghindari jaringan luar (wlan0) mengakses br0 -> tap0 & tap1

resep nginx oleh pak hanif

cuplikan config nginx di server, cc @hansputera


server {
        listen 80; # tanpa server_default
        listen [::]:80;

        root /var/www/html/blablabla.fadev.org;
        
        index index.php index.html index.htm index.nginx-debian.html;

        server_name blablabla.fadev.org;

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;

                fastcgi_pass unix:/run/php/php-fpm.sock;
        }
}

ip command

ip addr

ip addr is used to display and manage IP addresses assigned to network interfaces.

example:

  • ip addr
  • ip addr show
  • sudo ip addr add 192.168.1.100/24 dev eth0
  • sudo ip addr del 192.168.1.100/24 dev eth0

anything about ip assigment

ip link is used to display and manage network interfaces (links), focusing on layer 2 (Ethernet, loopback, etc.), not IP addresses.

example:

  • ip link
  • sudo ip link set dev eth0 up
  • sudo ip link set dev eth0 down
  • sudo ip link set dev eth0 mtu 1400

anyting about interface

ip tuntap

ip tuntap manages TUN/TAP virtual network interfaces, which provide a way for user-space programs to interact with network packets as if they were network devices.

  • TUN: Simulates a point-to-point device (layer 3), used for routing IP packets (e.g., VPN tunnels).
  • TAP: Simulates an Ethernet device (layer 2), used for bridging Ethernet frames (e.g., virtual switches, VMs).

example:

  • sudo ip tuntap add mode tap dev tap0
  • sudo ip tuntap add mode tun dev tun0
  • sudo ip tuntap del mode tap dev tap0

ip route

IP routing is the process by which data packets are directed from their source to their destination across interconnected networks using Internet Protocol (IP). This process is fundamental to the operation of the Internet and all IP-based networks.

View routing table:

  • ip route

add route

  • ip route add <destination> via <gateway> dev <interface>

example:

pc-1:~# ip route add default via 192.168.15.1 dev eth0
pc-1:~# ip route
default via 192.168.15.1 dev eth0 
192.168.15.0/24 dev eth0 scope link  src 192.168.15.2 

delete route

  • sudo ip route del <destination> [via <gateway>] [dev <interface>]

example:

pc-1:~# ip route delete default via 192.168.15.1 dev eth0
pc-1:~# ip r
192.168.15.0/24 dev eth0 scope link  src 192.168.15.2 
pc-1:~# 

qemu default network

The default gateway in QEMU when using the default user-mode networking (SLIRP) is typically 10.0.2.2 on the network 10.0.2.0/24. QEMU creates a virtual NAT network where the guest is assigned an IP like 10.0.2.15 by DHCP, and the gateway for the guest to reach outside networks is 10.0.2.2. This gateway is implemented inside QEMU and handles routing and NAT for the guest's traffic.

  • Default network: 10.0.2.0/24
  • Default gateway: 10.0.2.2
  • Default guest IP (DHCP assigned): 10.0.2.15
  • Default DNS server in guest: 10.0.2.3

This setup requires no special host configuration or root privileges and is the default networking mode for QEMU user mode networking.

additional

image

mikrotik firewall

each firewall module (called as table in iptables) has its own predefined chain

  • raw: dipakai sebelum data dilihat oleh conntrack, NAT, masuk routing, dll. intinya di sinilah proses early sebelum benar2 di proses. karna belum sampai ke conntrack, maka akan sangat fast, dipakai untuk mitigasi ddos

    karna statenya ada sebelum conntrack, maka tidak ada status kayak estab, dll, tapi sangat fast + low cpu, only raw matching

    Karna raw table melihat packet sebelum NAT, maka

    • Destination IPs are still the original IPs from the client
    • Source IPs haven't been changed by masquerade or src-nat yet

    chain chain nya

    • prerouting: packet yang datang dari luar just sebelum masuk conntrack
    • output: packet yang digenerate oleh aplikasi, juga statenya sebelum di track oleh conntrack

    contoh

    • /ip firewall raw add chain=prerouting src-address=8.8.8.8 action=drop

    tambahan:

    letak raw di packet flow

    IN → RAW → MANGLE (pre) → CONNECTION TRACKING → NAT (dstnat) → FILTER (input/forward) → MANGLE (post) → NAT (srcnat) → OUT
    
  • filter

    • input
    • forward
    • output
  • mangle

    • prerouting
    • input
    • forward
    • output
    • postrouting
  • nat

    • srcnat
    • dstnat

chains

RouterOS consist of a few default chains. These chains allow you to filter packets at various points:

  • The PREROUTING chain: Rules in this chain apply to packets as they just arrive on the network interface. This chain is present in the nat, mangle and raw tables.
  • The INPUT chain: Rules in this chain apply to packets just before they’re given to a local process. This chain is present in the mangle and filter tables.
  • The OUTPUT chain: The rules here apply to packets just after they’ve been produced by a process. This chain is present in the raw, mangle, nat, and filter tables.
  • The FORWARD chain: The rules here apply to any packets that are routed through the current host. This chain is only present in the mangle and filter tables.
  • The POSTROUTING chain: The rules in this chain apply to packets as they just leave the network interface. This chain is present in the nat and mangle tables.

bring wlan0 connectivity to the network namespace linux & test routerOS

setup network namespace

  • sudo ip netns add firefoxns
  • sudo ip netns exec firefoxns ip link add br0-lan type bridge
  • sudo ip netns exec firefoxns ip tuntap add tap0 mode tap
  • sudo ip netns exec firefoxns ip tuntap add tap1 mode tap
  • sudo ip netns exec firefoxns ip tuntap add tap2 mode tap
  • sudo ip netns exec firefoxns ip link set dev tap0 master br0-lan
  • sudo ip netns exec firefoxns ip link set dev tap1 master br0-lan
  • sudo ip netns exec firefoxns ip link set dev tap2 master br0-lan

enable the network interface (inside netns)

  • sudo ip netns exec firefoxns ip link set br0-lan up
  • sudo ip netns exec firefoxns ip link set tap0 up
  • sudo ip netns exec firefoxns ip link set tap1 up
  • sudo ip netns exec firefoxns ip link set tap2 up

create virtual eth pair between host & netns

  • sudo ip link add veth0 type veth peer name veth0-peer
  • sudo ip link set veth0-peer netns firefoxns

assign ip for virtual eth & virtual eth peer

  • sudo ip addr add 10.200.1.1/24 dev veth0
  • sudo ip netns exec firefoxns ip addr add 10.200.1.2/24 dev veth0-peer
  • sudo ip link set veth0 up
  • sudo ip netns exec firefoxns ip link set veth0 up

setup routing table

  • sudo ip netns exec firefoxns ip route add default via 10.200.1.1

setup ip forwarding & network address translation

  • sudo sysctl -w net.ipv4.ip_forward=1
  • sudo iptables -t nat -A POSTROUTING -s 10.200.1.0/24 -o wlan0 -j MASQUERADE

test

  • sudo ip netns exec ping 1.1.1.1

now, run routeros & alpine inside of netns

routeros

sudo ip netns exec firefoxns qemu-system-x86_64 \
            -enable-kvm \
            -m 256 \
            -smp 4 \
            -cpu host \
            -drive file=chr.qcow2,format=qcow2 \
            -boot d \
            -nographic \
            -netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
            -device virtio-net-pci,netdev=net0,mac=02:aa:bb:cc:dd:ee \
            -net user,hostfwd=tcp::8291-:8291 \
            -net nic

alpine

sudo ip netns exec firefoxns qemu-system-x86_64 \
            -enable-kvm \
            -m 256 \
            -smp 4 \
            -cpu host \
            -drive file=pc-2.qcow2,format=qcow2 \
            -cdrom alpine-virt-3.21.3-x86_64.iso \
            -boot d \
            -nographic \
            -netdev tap,id=net0,ifname=tap2,script=no,downscript=no \
            -device virtio-net-pci,netdev=net0,mac=$(randommac)

network namespace + NAT notes

  • ip a
  • sudo ip link add veth0 type veth peer name veth0-peer
  • sudo ip addr add 10.200.1.1/24 dev veth0
  • sudo ip netns add firefoxns
  • sudo ip link set veth0-peer netns firefoxns
  • sudo sysctl -w net.ipv4.ip_forward=1
  • sudo iptables -t nat -A POSTROUTING -s 10.200.1.0/24 -o wlan0 -j MASQUERADE
  • sudo ip netns exec firefoxns ip addr add 10.200.1.2/24 dev veth0-peer
  • sudo ip netns exec firefoxns ip addr add 127.0.0.1/8 dev lo
  • sudo ip netns exec firefoxns ip link set lo up
  • sudo ip netns exec firefoxns ip link set veth0-peer up
  • sudo ip netns exec firefoxns ip route add default via 10.200.1.1
  • sudo ip netns exec firefoxns ip link add br0-lan type bridge
  • sudo ip netns exec firefoxns ip tuntap add tap0 mode tap
  • sudo ip netns exec firefoxns ip tuntap add tap1 mode tap
  • sudo ip netns exec firefoxns ip tuntap add tap2 mode tap
  • sudo ip netns exec firefoxns ip link set dev tap0 master br0-lan
  • sudo ip netns exec firefoxns ip link set dev tap1 master br0-lan
  • sudo ip netns exec firefoxns ip link set dev tap2 master br0-lan
  • sudo ip netns exec firefoxns ip link set dev tap0 up
  • sudo ip netns exec firefoxns ip link set dev tap1 up
  • sudo ip netns exec firefoxns ip link set dev tap2 up
  • sudo ip netns exec firefoxns ip link set dev br0-lan up
  • sudo ip netns exec firefoxns qemu-system-x86_64 -enable-kvm -m 256 -smp 4 -cpu host -drive file=chr.qcow2,format=qcow2 -boot d -nographic -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -device virtio-net-pci,netdev=net0,mac=02:aa:bb:cc:dd:ee -net user,hostfwd=tcp::8291-:8291 -net nic
  • sudo ip netns exec firefoxns qemu-system-x86_64 -enable-kvm -m 256 -smp 4 -cpu host -drive file=pc-1.qcow2,format=qcow2 -cdrom alpine-virt-3.21.3-x86_64.iso -boot d -nographic -netdev tap,id=net0,ifname=tap1,script=no,downscript=no -device virtio-net-pci,netdev=net0,mac=$(randommac)

randommac source code

use rand::Rng;

fn main() {
    let mut rng = rand::thread_rng();
    let mac = format!(
        "52:54:00:{:02x}:{:02x}:{:02x}",
        rng.gen::<u8>(),
        rng.gen::<u8>(),
        rng.gen::<u8>()
    );
    println!("{}", mac);
}

deploy Docmost on server

please read this doc first, https://docmost.com/docs/installation

docker compose config

version: "3"

services:
  docmost:
    image: docmost/docmost:latest
    depends_on:
      - db
      - redis
    environment:
      APP_URL: "http://localhost:3000"
      APP_SECRET: "REPLACE_WITH_LONG_SECRET"
      DATABASE_URL: "postgresql://docmost:STRONG_DB_PASSWORD@db:5432/docmost?schema=public"
      REDIS_URL: "redis://redis:6379"
    ports:
      - "3000:3000"
    restart: unless-stopped
    volumes:
      - docmost:/app/data/storage

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: docmost
      POSTGRES_USER: docmost
      POSTGRES_PASSWORD: STRONG_DB_PASSWORD
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data

  redis:
    image: redis:7.2-alpine
    restart: unless-stopped
    volumes:
      - redis_data:/data

volumes:
  docmost:
  db_data:
  redis_data:

replace your STRONG_DB_PASSWORD with openssl rand -hex 10, and REPLACE_WITH_LONG_SECRET with openssl rand -hex 32, and APP_URL, for example, in my case is https://docmost.fadev.org

run docker compose run

setup reverse proxy (nginx)

go to /etc/nginx/sites-enabled, and create a clone with cp default docmost.fadev.org

fill it like this

server_name docmost.fadev.org;

location / {
	# First attempt to serve request as file, then
	# as directory, then fall back to displaying a 404.
	#try_files $uri $uri/ =404;

	proxy_pass http://127.0.0.1:3000;
}

location /socket.io/ {
	proxy_pass http://127.0.0.1:3000;
	proxy_http_version 1.1;
	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "upgrade";
	proxy_set_header Host $host;
}

location /collab {
	proxy_pass http://127.0.0.1:3000;
	proxy_http_version 1.1;
	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "upgrade";
	proxy_set_header Host $host;
}

HTTPS

run

  • sudo apt install certbot python3-certbot-nginx
  • sudo certbot --nginx -d docmost.fadev.org

Firewall

allow port 443

fix vthxxxxxxxx is not connected to docker0

consider

> ip  a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: enp2s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether 2c:4d:54:c6:f2:0c brd ff:ff:ff:ff:ff:ff
    altname enx2c4d54c6f20c
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether f0:03:8c:66:9c:21 brd ff:ff:ff:ff:ff:ff
    inet 192.168.105.162/24 metric 1024 brd 192.168.105.255 scope global dynamic wlan0
       valid_lft 2920sec preferred_lft 2920sec
    inet 192.168.105.163/24 brd 192.168.105.255 scope global secondary dynamic noprefixroute wlan0
       valid_lft 2921sec preferred_lft 2921sec
    inet6 fe80::ee67:75f9:fa9c:2561/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 86:1e:e0:72:f4:8d brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::841e:e0ff:fe72:f48d/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever
17: veth914db4f@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether d2:02:61:f4:12:d0 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::d002:61ff:fef4:12d0/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

you can see, veth914db4f is not connected to br0. let's try hard

  • run image (explicitly) as bridge network: docker run --network bridge -it --rm -p 127.0.0.1:8000:4000 php-test-server (this is nothing happen)
  • force connect: docker network connect bridge 2cf520235e6a (this is show Error response from daemon: endpoint with name mystifying_yonath already exists in network bridge, but ip a says vethxxxx is not master to anyone). you can try disconnect & connect again

also

docker inspect -f '{{json .NetworkSettings.Networks}}' 2cf520235e6a | jq
{
  "bridge": {
    "IPAMConfig": null,
    "Links": null,
    "Aliases": null,
    "MacAddress": "5a:2d:5d:7c:c1:86",
    "DriverOpts": null,
    "GwPriority": 0,
    "NetworkID": "08f151565c95ba052f682c7560e55199e2d75f3d2348af8f98a9711e9294b3fd",
    "EndpointID": "0522c15ad18fbae05071a7d5e09944b7777deaafd3490082cac237fdfcd14f0c",
    "Gateway": "172.17.0.1",
    "IPAddress": "172.17.0.2",
    "IPPrefixLen": 16,
    "IPv6Gateway": "",
    "GlobalIPv6Address": "",
    "GlobalIPv6PrefixLen": 0,
    "DNSNames": null
  }
}

the medicine: https://forums.docker.com/t/no-connection-to-the-bridge-by-default/134619/8

sudo systemctl stop systemd-networkd.service                                                    
sudo systemctl disable systemd-networkd.service                                                        
sudo systemctl stop systemd-networkd.socket                                                            
sudo systemctl disable systemd-networkd.socket
sudo systemctl start NetworkManager
sudo systemctl enable NetworkManager

php-fpm config

file ini biasanya ada di

  • /usr/local/etc/php-fpm.d/www.conf (di docker php-fpm)
  • /etc/php/8.3/fpm/pool.d/www.conf (di debian bullseye)

intinya, tidak pasti haha.

config structure

general structure nya seperti ini kalau ';' dihilangkan

[www]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

config global (WIP)

config untuk pool (each)

best read https://www.php.net/manual/en/install.fpm.configuration.php

  • [pool_name] intinya ini unique, tidak ada yang sama
  • user / group
    • user: dimana child process akan di run (as user?)
    • group: liat /etc/passwd
  • listen
    • listen: dimana daemon akan listen yg nanti akan di reverse proxy oleh nginx, nilai defaultnya biasanya /run/php/php8.3-fpm.sock atau 127.0.0.1:9000, contoh:

      • ip.add.re.ss:port
      • [ip:6:addr:ess]:port
      • port
      • /path/to/unix/socket
    • listen.backlog: jumlah queue pending connection yang bisa di hold

    • listen.owner: configure ke mana kah /run/php/php8.3-fpm.sock itu ownernya

    • listen.group: same as listen.owner

    • listen.mode: nomor permission si /run/php/php8.3-fpm.sock listen

    • listen.acl_users: WIP

    • listen.acl_groups: WIP

    • listen.allowed_clients: set dari mana FCGI boleh diakses, di kasus nginx, mostly 127.0.0.1, except docker, dia pakai br-xxxxxx yang ip nya pasti bukan 127.0.0.1

    • listen.setfib: WIP

systemd config template

root location: /etc/systemd/system/<YOUR_SERVICE>.service

template

[Unit]
Description=Random service
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=1
User=root
ExecStart=/usr/bin/randomprogram -c /etc/randomprogram/other.toml

[Install]
WantedBy=multi-user.target

Database

psql command

General

  • \bind [PARAM]... set query parameters
  • \copyright show PostgreSQL usage and distribution terms
  • \crosstabview [COLUMNS] execute query and display result in crosstab
  • \errverbose show most recent error message at maximum verbosity
  • \g [(OPTIONS)] [FILE] execute query (and send result to file or |pipe); \g with no arguments is equivalent to a semicolon
  • \gdesc describe result of query, without executing it
  • \gexec execute query, then execute each value in its result
  • \gset [PREFIX] execute query and store result in psql variables
  • \gx [(OPTIONS)] [FILE] as \g, but forces expanded output mode
  • \q quit psql
  • \watch [[i=]SEC] [c=N] [m=MIN] execute query every SEC seconds, up to N times, stop if less than MIN rows are returned

Help

  • \? [commands] show help on backslash commands
  • \? options show help on psql command-line options
  • \? variables show help on special variables
  • \h [NAME] help on syntax of SQL commands, * for all commands

Query Buffer

  • \e [FILE] [LINE] edit the query buffer (or file) with external editor
  • \ef [FUNCNAME [LINE]] edit function definition with external editor
  • \ev [VIEWNAME [LINE]] edit view definition with external editor
  • \p show the contents of the query buffer
  • \r reset (clear) the query buffer
  • \s [FILE] display history or save it to file
  • \w FILE write query buffer to file

Input/Output

  • \copy ... perform SQL COPY with data stream to the client host
  • \echo [-n] [STRING] write string to standard output (-n for no newline)
  • \i FILE execute commands from file
  • \ir FILE as \i, but relative to location of current script
  • \o [FILE] send all query results to file or |pipe
  • \qecho [-n] [STRING] write string to \o output stream (-n for no newline)
  • \warn [-n] [STRING] write string to standard error (-n for no newline)

Conditional

  • \if EXPR begin conditional block
  • \elif EXPR alternative within current conditional block
  • \else final alternative within current conditional block
  • \endif end conditional block

Informational

(options: S = show system objects, + = additional detail)

  • \d[S+] list tables, views, and sequences
  • \d[S+] NAME describe table, view, sequence, or index
  • \da[S] [PATTERN] list aggregates
  • \dA[+] [PATTERN] list access methods
  • \dAc[+] [AMPTRN [TYPEPTRN]] list operator classes
  • \dAf[+] [AMPTRN [TYPEPTRN]] list operator families
  • \dAo[+] [AMPTRN [OPFPTRN]] list operators of operator families
  • \dAp[+] [AMPTRN [OPFPTRN]] list support functions of operator families
  • \db[+] [PATTERN] list tablespaces
  • \dc[S+] [PATTERN] list conversions
  • \dconfig[+] [PATTERN] list configuration parameters
  • \dC[+] [PATTERN] list casts
  • \dd[S] [PATTERN] show object descriptions not displayed elsewhere
  • \dD[S+] [PATTERN] list domains
  • \ddp [PATTERN] list default privileges
  • \dE[S+] [PATTERN] list foreign tables
  • \des[+] [PATTERN] list foreign servers
  • \det[+] [PATTERN] list foreign tables
  • \deu[+] [PATTERN] list user mappings
  • \dew[+] [PATTERN] list foreign-data wrappers
  • \df[anptw][S+] [FUNCPTRN [TYPEPTRN ...]] list [only agg/normal/procedure/trigger/window] functions
  • \dF[+] [PATTERN] list text search configurations
  • \dFd[+] [PATTERN] list text search dictionaries
  • \dFp[+] [PATTERN] list text search parsers
  • \dFt[+] [PATTERN] list text search templates
  • \dg[S+] [PATTERN] list roles
  • \di[S+] [PATTERN] list indexes
  • \dl[+] list large objects, same as \lo_list
  • \dL[S+] [PATTERN] list procedural languages
  • \dm[S+] [PATTERN] list materialized views
  • \dn[S+] [PATTERN] list schemas
  • \do[S+] [OPPTRN [TYPEPTRN [TYPEPTRN]]] list operators
  • \dO[S+] [PATTERN] list collations
  • \dp[S] [PATTERN] list table, view, and sequence access privileges
  • \dP[itn+] [PATTERN] list [only index/table] partitioned relations [n=nested]
  • \drds [ROLEPTRN [DBPTRN]] list per-database role settings
  • \drg[S] [PATTERN] list role grants
  • \dRp[+] [PATTERN] list replication publications
  • \dRs[+] [PATTERN] list replication subscriptions
  • \ds[S+] [PATTERN] list sequences
  • \dt[S+] [PATTERN] list tables
  • \dT[S+] [PATTERN] list data types
  • \du[S+] [PATTERN] list roles
  • \dv[S+] [PATTERN] list views
  • \dx[+] [PATTERN] list extensions
  • \dX [PATTERN] list extended statistics
  • \dy[+] [PATTERN] list event triggers
  • \l[+] [PATTERN] list databases
  • \sf[+] FUNCNAME show a function's definition
  • \sv[+] VIEWNAME show a view's definition
  • \z[S] [PATTERN] same as \dp

Large Objects

  • \lo_export LOBOID FILE write large object to file
  • \lo_import FILE [COMMENT] read large object from file
  • \lo_list[+] list large objects
  • \lo_unlink LOBOID delete a large object

Formatting

  • \a toggle between unaligned and aligned output mode
  • \C [STRING] set table title, or unset if none
  • \f [STRING] show or set field separator for unaligned query output
  • \H toggle HTML output mode (currently off)
  • \pset [NAME [VALUE]] set table output option (border|columns|csv_fieldsep|expanded|fieldsep| fieldsep_zero|footer|format|linestyle|null| numericlocale|pager|pager_min_lines|recordsep| recordsep_zero|tableattr|title|tuples_only| unicode_border_linestyle|unicode_column_linestyle| unicode_header_linestyle|xheader_width)
  • \t [on|off] show only rows (currently off)
  • \T [STRING] set HTML tag attributes, or unset if none
  • \x [on|off|auto] toggle expanded output (currently off)
  • Connection

    • \c[onnect] {[DBNAME|- USER|- HOST|- PORT|-] | conninfo} connect to new database (currently "fadev_infra")
    • \conninfo display information about current connection
    • \encoding [ENCODING] show or set client encoding
    • \password [USERNAME] securely change the password for a user

    Operating System

    • \cd [DIR] change the current working directory
    • \getenv PSQLVAR ENVVAR fetch environment variable
    • \setenv NAME [VALUE] set or unset environment variable
    • \timing [on|off] toggle timing of commands (currently off)
    • ! [COMMAND] execute command in shell or start interactive shell

    Variables

    • \prompt [TEXT] NAME prompt user to set internal variable
    • \set [NAME [VALUE]] set internal variable, or list all if no parameters
    • \unset NAME unset (delete) internal variable

    psql snippet

    psql

    • \df *.* Lists all relations
    • \l Lists all database

    command

    • DROP TABLE table_name CASCADE; used when you want to remove all object depend on them.

    PostgreSQL database creation flow

    in order to create database (for safety, I use postgres account). I use this step.

    first, we need to login as postgres user, use this sudo -u postgres psql, then do

    CREATE DATABASE EXAMPLE_DB;
    

    this is optional

    CREATE USER EXAMPLE_USER WITH ENCRYPTED PASSWORD 'Sup3rS3cret';
    

    grant

    GRANT ALL PRIVILEGES ON DATABASE EXAMPLE_DB TO EXAMPLE_USER;
    

    now, change the state using \c EXAMPLE_DB postgres, execute this command

    GRANT ALL ON SCHEMA public TO EXAMPLE_USER;
    

    then, change ownership

    ALTER DATABASE my_database OWNER TO my_database_user;
    

    notes: https://stackoverflow.com/questions/67276391/why-am-i-getting-a-permission-denied-error-for-schema-public-on-pgadmin-4

    how to use SQLX cli tools for db migration such laravel migrations

    let's meet with this crate, https://crates.io/crates/sqlx-cli, this tools allow you to use db migration such as laravel migration tools;

    first, let's create env variable

    export DATABASE_URL=postgres://fadhil_riyanto:<your_pass>@localhost/<target_db>
    

    then, the things that we do next is only

    sqlx migrate add -r <name>
    

    running

    sqlx migrate run
    

    Postgresql internal (server)

    this thing explain the internal of pgsql system (not the source code I mean)

    difference between catalog vs schema

    key point:

    • schema is folder like, grouping table together, can be created using

      CREATE SCHEMA my_catalog;
      CREATE TABLE my_catalog.metadata_table (...);
      
    • catalog is system schema, can't be created manually, part of internal pgsql system

    • view is a resulted table from XYZ queries, example

      CREATE VIEW active_users AS 
      	SELECT id, name, 
      	FROM
      		users 
      	WHERE
      		active = true;
      

      then query it

      SELECT * FROM active_users;
      

    pg_catalog inside

    this is some stuff inside of pg catalog, you can do that using \dt pg_catalog.*

    • pg_aggregate: Stores information about aggregate functions (like SUM, AVG, etc.).
    • pg_am: Lists access methods for indexes (e.g., btree, hash).
    • pg_amop: Defines operators used in access methods.
    • pg_amproc: Defines support functions used in access methods.
    • pg_attrdef: Stores default values for columns.
    • pg_attribute: Contains column definitions for all tables.
    • pg_auth_members: Shows role memberships (who is a member of what).
    • pg_authid: Stores user/role definitions (superuser access required).
    • pg_cast: Contains rules for casting between data types.
    • pg_class: Contains all table-like objects (tables, views, indexes, sequences, etc.).
    • pg_collation: Defines collations (rules for string comparison).
    • pg_constraint: Stores constraints like PRIMARY KEY, UNIQUE, CHECK, and FOREIGN KEY.
    • pg_conversion: Defines character set conversions.
    • pg_database: Stores information about each database in the cluster.
    • pg_db_role_setting: Stores per-user/per-database configuration settings (GUCs).
    • pg_default_acl: Defines default privileges for newly created objects.
    • pg_depend: Stores dependency relationships between database objects.
    • pg_description: Stores comments/descriptions on database objects.
    • pg_enum: Stores values for ENUM data types.
    • pg_event_trigger: Stores event trigger definitions (triggers on DDL commands).
    • pg_extension: Tracks installed extensions (like uuid-ossp, pgcrypto, etc.).
    • pg_foreign_data_wrapper: Stores definitions of foreign data wrappers (FDW).
    • pg_foreign_server: Stores foreign servers used by FDWs.
    • pg_foreign_table: Stores metadata for foreign tables.
    • pg_index: Contains metadata about indexes (e.g., indexed columns).
    • pg_inherits: Stores table inheritance relationships.
    • pg_init_privs: Records original privileges on built-in objects.
    • pg_language: Stores information about supported procedural languages.
    • pg_largeobject: Stores the actual data of large objects (blobs).
    • pg_largeobject_metadata: Stores metadata about large objects.
    • pg_namespace: Lists all schemas in the database (IMPORTANT)
    • pg_opclass: Stores index operator classes (how a datatype is indexed).
    • pg_operator: Stores SQL operators (like =, <, +, etc.).
    • pg_opfamily: Groups related operator classes.
    • pg_parameter_acl: Stores access control for configuration parameters (PostgreSQL 16+).
    • pg_partitioned_table: Stores metadata for partitioned tables.
    • pg_policy: Stores row-level security policies.
    • pg_proc: Contains all function and procedure definitions.
    • pg_publication: Stores logical replication publications.
    • pg_publication_namespace: Links publications to schemas.
    • pg_publication_rel: Links publications to individual tables.
    • pg_range: Stores definitions of range types (e.g., int4range).
    • pg_replication_origin: Tracks origins for logical replication.
    • pg_rewrite: Stores query rewrite rules (used in views, rules).
    • pg_seclabel: Stores security labels for database objects.
    • pg_sequence: Contains metadata for sequence generators.
    • pg_shdepend: Tracks dependencies involving shared objects (like roles, databases).
    • pg_shdescription: Stores comments on shared objects.
    • pg_shseclabel: Stores security labels on shared objects.
    • pg_statistic: Stores planner statistics for columns.
    • pg_statistic_ext: Stores extended planner statistics (multi-column, NDV, etc.).
    • pg_statistic_ext_data: Contains actual values for extended statistics.
    • pg_subscription: Defines logical replication subscriptions.
    • pg_subscription_rel: Lists tables included in subscriptions.
    • pg_tablespace: Lists all tablespaces (disk locations for data).
    • pg_transform: Stores type transformation functions for procedural languages.
    • pg_trigger: Stores triggers on tables.
    • pg_ts_config: Stores full-text search configurations.
    • pg_ts_config_map: Maps text search config tokens to dictionaries.
    • pg_ts_dict: Stores text search dictionaries.
    • pg_ts_parser: Defines tokenizers for full-text search.
    • pg_ts_template: Defines templates for building text search dictionaries.
    • pg_type: Stores all data types (built-in, custom, enum, composite). (IMPORTANT)
    • pg_user_mapping: Maps users to foreign servers.

    pg_catalog.pg_database details

    this docs can be found in https://www.postgresql.org/docs/16/catalog-pg-database.html

    Column NameTypeDescription
    datnamenameThe name of the database.
    datdbaoidThe OID of the role (user) that owns the database. Use pg_get_userbyid(datdba) to resolve it.
    encodingintThe character encoding of the database (e.g., UTF8 = 6). Use pg_encoding_to_char(encoding) to get the name.
    datlocprovidercharLocale provider used (c = libc, i = ICU).
    datistemplateboolIf true, the database can be used as a template for CREATE DATABASE ... TEMPLATE.
    datallowconnboolIf false, connections to this database are not allowed (except by superusers).
    datconnlimitintThe maximum number of concurrent connections allowed (-1 = no limit).
    datlastsysoidoidThe last system OID used in this database at creation (mainly historical).
    datfrozenxidxidThe transaction ID at which all tuples are known to be frozen (related to VACUUM).
    datminmxidxidThe minimum multixact ID that is still considered potentially unfrozen.
    dattablespaceoidOID of the default tablespace for the database. Use pg_tablespace to resolve.
    datcollatenameLC_COLLATE setting (how strings are sorted).
    datctypenameLC_CTYPE setting (how character classification works).
    daticulocaletextICU locale (used if datlocprovider = 'i').
    datcollversiontextVersion of the collation used (important for collation versioning with ICU).
    dataclaclitem[]Access privileges (GRANTs), stored as an array of ACL items.

management script collection

- show all databases (in current user)

SELECT * FROM pg_catalog.pg_database;`:

- show pg_catalog.pg_tables definition

go back on top in order to see what actually view is

SELECT pg_get_viewdef('pg_catalog.pg_tables', true);`: 

- show all available pgsql datatype

SELECT 
	*
FROM
	pg_catalog.pg_type;

- lists all schema

SELECT
    *
FROM
    pg_catalog.pg_namespace;

- show all dbs with owner

SELECT 
        x.oid as object_id,
        x.datname as db_name,
        CASE 
                WHEN pg_catalog.pg_get_userbyid(x.datdba) LIKE 'unknown (OID=%)' THEN 'UNKNOWN'
                ELSE pg_catalog.pg_get_userbyid(x.datdba)
        END as owner
FROM pg_catalog.pg_database as x;

cond: https://www.postgresql.org/docs/current/functions-conditional.html#FUNCTIONS-CASE

- RENAME db (as postgres user)

ALTER DATABASE xyz RENAME TO abc;

Postgresql II SQL language docs summary

this is incomplete documentation summary of postgresql (SQL section), see complete docs here

5. Data Definition

5.2. Default values

When a new row is created and no values are specified for some of the columns, those columns will be filled with their respective default values. A data manipulation command can also request explicitly that a column be set to its default value, without having to know what that value is

example

CREATE TABLE state (
	uid				integer,
	enable			bool DEFAULT false
)

5.3. Identity column

system table in pgsql (catalog)

pg_tables | docs

catalog pgsql yang isinya data ttg table (di db saat ini), contoh query nya

SELECT
        *
FROM 
        pg_catalog.pg_tables as x
WHERE
        x.schemaname = 'public';

pg_sequences

yg ini isinya sequence2 semua, mirip kayak serial datatype di pgsql image

NOTES: pg_sequence adalah versi low levelnya, sedangkan pg_sequences adalah versi view dari join-an pg_sequence dan pg_class, bukti

SELECT
        *
FROM
        pg_get_viewdef('pg_catalog.pg_sequences', true)

hasil

SELECT 
        n.nspname AS schemaname, 
        c.relname AS sequencename, 
        pg_get_userbyid(c.relowner) AS sequenceowner, 
        s.seqtypid :: regtype AS data_type, 
        s.seqstart AS start_value, 
        s.seqmin AS min_value, 
        s.seqmax AS max_value, 
        s.seqincrement AS increment_by, 
        s.seqcycle AS cycle, 
        s.seqcache AS cache_size, 
        CASE WHEN has_sequence_privilege(c.oid, 'SELECT,USAGE' :: text) THEN pg_sequence_last_value(c.oid :: regclass) ELSE NULL :: bigint END AS last_value 
FROM 
        pg_sequence s 
        JOIN pg_class c ON c.oid = s.seqrelid 
        LEFT JOIN pg_namespace n ON n.oid = c.relnamespace 
WHERE 
        NOT pg_is_other_temp_schema(n.oid) 
        AND c.relkind = 'S' :: "char";

pgsql functions()

pg_get_viewdef

see sql script for particular view, I call this as view reverser

example:

SELECT
        *
FROM
        pg_get_viewdef('pg_catalog.pg_sequences', true)

ref:

akan ada kelanjutan disini.

Dockerfile boilerplate

this folder is a set of dockerfile boilerplate that I used to build something.

php-8.3 debian v11 (bullseye) dev-env

CREATED: Fri Jun 6 06:32:35 PM WIB 2025

FROM debian:bullseye

ENV DEBIAN_FRONTEND=noninteractive
# initial, refresh repo first
RUN apt-get update

# this install base package that need in order to download gpg key (curl, and gnupg)
RUN apt-get install -y ca-certificates
RUN apt-get install -y apt-transport-https
RUN apt-get install -y lsb-release
RUN apt-get install -y gnupg
RUN apt-get install -y curl
RUN apt-get install -y git
RUN apt-get install -y unzip

# add ondrej\PPA
RUN curl -fsSL https://packages.sury.org/php/apt.gpg | gpg --dearmor -o /etc/apt/trusted.gpg.d/php.gpg
RUN echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/php.list

# install actual package, php-xml & php-mbstring is needed by composer. 
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get install -y php8.3
RUN apt-get install -y php8.3-curl
RUN apt-get install -y php8.3-xml
RUN apt-get install -y php8.3-mbstring

# download composer
RUN curl -sS https://getcomposer.org/installer -o composer-setup.php \
        && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
        && rm composer-setup.php

COPY . /app
WORKDIR /app

EXPOSE 4444

# install composer
RUN composer install
CMD [ "php", "-S", "0.0.0.0:4444", "-t", "public" ]

php:8.3.20-fpm-bullseye + nginx

FROM php:8.3.20-fpm-bullseye 

RUN apt-get update && apt-get install -y libpq-dev
RUN docker-php-ext-install pdo pdo_pgsql

COPY . /app
WORKDIR /app

COPY ./docker/fpm/www.conf /usr/local/etc/php-fpm.d/www.conf
# karna php-fpm running pakai user www-data
RUN chown -R www-data:www-data /app/storage


CMD [ "php-fpm" ]

default.conf (nginx)

server {
    listen       80;
    server_name  localhost;

    access_log  off;
    root /app/public;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }


    location ~ \.php$ {

        fastcgi_pass   php:9000; 
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param  DOCUMENT_ROOT $document_root;
        include        fastcgi_params;
    }
}

www.conf


[www]
access.log = /dev/null

user = www-data
group = www-data

listen = 0.0.0.0:9000

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

php:8.3.20-bullseye dev env

this is also works for laravel

FROM php:8.3.20-bullseye

RUN apt-get update && apt-get install -y \
        curl \ 
        libpq-dev \
        git \
        unzip
RUN docker-php-ext-install pdo pdo_pgsql

COPY . /app
WORKDIR /app

RUN curl -sS https://getcomposer.org/installer -o composer-setup.php \
        && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
        && rm composer-setup.php

RUN composer install

CMD [ "php", "-S", "0.0.0.0:10302", "-t", "public" ]

compose.yml

volumes:
  storage:
  db_data:

networks:
  veth_network:
    driver: bridge

services:
  google_sso:
    image: php:8.3.20-bullseye
    build:
      context: .
      dockerfile: dev.backend.Dockerfile
    environment:
      - docker=true
      - DB_HOST=pgsql_db
      - DB_PORT=5432
      - DB_USERNAME=postgres
      - DB_PASSWORD=<PASSWD>
      - DB_DATABASE=google_sso_dev
      - G_SSO_NAME=google-sso-login
      - G_SSO_CLIENT_ID=ABC
      - G_SSO_CLIENT_SECRET=DEF
      - G_SSO_REDIRECT_URI=http://localhost:10302/auth/callback
    ports:
      - "10302:10302"
    networks:
      - veth_network
    volumes:
      - .:/app
      - storage:/app/storage
    depends_on:
      - pgsql_db

  pgsql_db:
    image: postgres:17.5-bullseye
    restart: always
    shm_size: 128mb
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=<PASSWD>
      - POSTGRES_DB=google_sso_dev
    networks:
      - veth_network
    volumes:
      - db_data:/var/lib/postgresql/data
  
  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
    networks:
      - veth_network
    depends_on:
      - pgsql_db

CATATAN unik: ketika ping pgsql_db dari xxx container, ia otomatis resolve dns nya.

PHP (web)

laravel service container

date: Sun Jun 8 11:47:02 PM WIB 2025

links

making

untuk membuat service container, katakanlah isi class ctx yang namanya Google\Client. dia mereturn $client. maka kita harus bikin

php artisan make:provider GoogleApis

nama GoogleApis bebas. lalu cek di folder ./app/Providers/GoogleApis.php harusnya ada, dan di file ./bootstrap/providers.php akan ada

<?php

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\GoogleApis::class,
];

ada App\Providers\GoogleApis::class maksudnya.

registering

dari service provider yang baru saja dibuat, akan ada 2 method, yaitu

  • public function register(): void: boot ini entry dari service, nilai ctx ctx dsb biasanya diload disini
  • public function boot(): void: func ini dipanggil kalau semua service sudah jalan, misal service route di register, tapi method untuk nambahin route routenya. ada di boot

general structure nya (file ./app/Providers/AppServiceProvider.php)

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        //
    }
}

the inside of register function

docs tentang

perbedaanya, bind auto buat fresh ctx tiap kali request datang, sedangkan singleton hanya buat sekali, contoh konkret singleton adalah ctx koneksi mongodb, kita cukup pakai sekali saja, untuk semua container

ini contoh googleclient

// this code is inside of register() func
$this->app->singleton(Client::class, function (Application $app) {
    $client = new Client();
    $client->setApplicationName(env("G_SSO_NAME"));
    $client->setClientId(env("G_SSO_CLIENT_ID"));
    $client->setClientSecret(env("G_SSO_CLIENT_SECRET"));
    $client->setRedirectUri(env("G_SSO_REDIRECT_URI"));
    $client->addScope([
        Service\Oauth2::USERINFO_EMAIL,
        Service\Oauth2::USERINFO_PROFILE
    ]);
    $client->setAccessType('offline');
    $client->setLoginHint('your_email@gmail.com');

    return $client;
});

catatan: use Illuminate\Contracts\Foundation\Application itu ctx bawaan laravel buat ngebind.

how to use

lokasi: controller

kita tinggal panggil saja class (milik aslinya)

contoh

use Google\Client;

class Randomclass extends Controller

{
    /**

     * Create a new controller instance.

     */

    public function __construct(

        protected Client $client,

    ) {}

    public function use_it() {
    	$this->client->some_google_method();
        // $this->client was initialized
    }
}

laravel 12 custom auth guard + tables

Mon Jun 9 05:36:39 AM WIB 2025

di sini saya coba untuk membuat Auth::attempt https://laravel.com/docs/12.x/authentication#authenticating-users, tapi bedanya, ia pakai totally different table. jadi tidak pakai table users

setup model

untuk setup nya, kita buat model dulu seperti biasa pakai php artisan make:model Xyz, disini saya buatnya php artisan make:model GuestUser. lalu cek bagian ./app/Models/GuestUser.php

normalnya class akan extends ke Illuminate\Database\Eloquent\Model, nah ini kita extends kan ke Illuminate\Foundation\Auth\User, dimana class itu kalau dirunut lagi, pasti juga nge-extends ke class Model

bukti

class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}

ok, sudah. saatnya kita pindah ke model yang baru saja dibuat, isi $fillable seperti column database, jangan lupa ganti extends nya dengan extends Authenticatable

hasil akhir seperti ini kira2

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;

class GuestUser extends Authenticatable
{
    protected $table = "guest_user";

    protected $fillable = [
        'name',
        'picture',
        'email',
        'password',
        'token',
        'g_auth_expires_in'
    ];
}

registering guard

agar model kita bisa dibaca oleh Auth facade, maka kita harus registerkan dia dahulu di ./config/auth.php, isi dahulu bagian providers. contoh

/*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication guards have a user provider, which defines how the
    | users are actually retrieved out of your database or other storage
    | system used by the application. Typically, Eloquent is utilized.
    |
    | If you have multiple user tables or models you may configure multiple
    | providers to represent the model / table. These providers may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => env('AUTH_MODEL', App\Models\User::class),
        ],
        'guest_users' => [
            'driver' => 'eloquent',
            'model' => env('AUTH_MODEL', App\Models\GuestUser::class),
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

make sense kan? guest_users provider, ia memiliki model App\Models\GuestUser::class (note, ::class akan return str),

setelah itu, lihat bagian atasnya, ada guards, disini kita akan naming guardsnya dan juga memberi info provider model mana yang akan dikasih, contoh

/*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | which utilizes session storage plus the Eloquent user provider.
    |
    | All authentication guards have a user provider, which defines how the
    | users are actually retrieved out of your database or other storage
    | system used by the application. Typically, Eloquent is utilized.
    |
    | Supported: "session"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'guest' => [
            'driver' => 'session',
            'provider' => 'guest_users',
        ],
        
    ],

JFYI: Auth::attempt() secara default pakai guards web, nah kita sekarang juga bisa pakai custom, seperti ini Auth::guard("guest")->attempt() secara explicit kita tell laravel untuk pakai guard guest

session

general login flow

if (Auth::guard("guest")->attempt($packed_arr)) {

    $retq = GuestUser::where("email", $packed_arr["email"])->first();
    $retq = Auth::guard("guest")->login($retq);

    return redirect('/dashboard/index');
} else {
    dd("login failed");
}

Auth::guard("guest")->attempt() return boolean, true jika auth benar. Auth::guard("guest")->login($retq); ubah state internalnya bahwa dia sudah login, lalu redirect (penting, jika tidak diredirect, nanti session akan stuck)

laravel Socialite setup

Mon Jun 9 05:49:13 AM WIB 2025

setup

lihat config/services.php, disana hanya ada slack, maka kita tambahin

    'google' => [
        'client_id' => env('G_SSO_CLIENT_ID'),
        'client_secret' => env('G_SSO_CLIENT_SECRET'),
        'redirect' => env('G_SSO_REDIRECT_URI'),
        'name' => env('G_SSO_NAME'),
    ],

usage

dapatkan link permintaan akses, pakai

return Socialite::driver('google')->redirect();

ketika user sudah klik continue & accept share datanya, akan dikirimkan callback, pasang ini ke callback

$user = Socialite::driver('google')->user();
dd($user);

laravel pgsql migration setup

Mon Jun 9 05:56:55 AM WIB 2025

PGSQL datatype to laravel mapping function: https://api.laravel.com/docs/12.x/Illuminate/Database/Schema/Blueprint.html

buat migrationnya dengan

php artisan make:migration create_table_abc

run

php artisan migrate

rollback terbaru

php artisan migrate --rollback 1

Other

bookmarks highly useful link

this section is derived from my original channel @xorriso

https://xenbits.xen.org/docs/4.6-testing/misc/pvh.html

"PVH is to make use of the hardware virtualization extensions present in modern x86 CPUs in order to improve performance."

https://wiki.xenproject.org/wiki/Linux_PVH

Where one will select Processor type and features ---> Linux guest support --->Support for running as a PVH guest

https://github.com/Goldside543/goldspace

https://mongoc.org/libmongoc/current/mongoc_client_new.html

kesimpulan: mongoc_client_new return null on error, but not even the string are correct
no connection checked.

jangan ngeharap mongoc_client_new ngeluarin null

https://faculty.cs.niu.edu/~hutchins/csci480/signals.htm

daftar exit code

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/entry/syscalls/syscall_64.tbl

list syscall

https://www.bitsinthewind.com/about-dac/publications/unix-systems-programming

system programming

https://lwn.net/Articles/205126/

In recent times, Al's work has resulted in a long series of patches merged into the mainline, almost all of which have been marked as "endianness annotations." These patches mostly change the declared types for various functions, variables, and structure members. The new types may be unfamiliar to many, since they are relatively new - though not that new; they were introduced in 2.6.9. These types are __le16, __le32, __le64, __be16, __be32, and __be64.

https://github.com/AugustTan/documents/blob/master/UNIX%20Network%20Programming(Volume1%2C3rd).pdf

https://ics.uci.edu/~aburtsev/143A/2017fall/lectures/

Gas kuliah online tiada kata untuk tidak belajar, di topik ini Pak aburtsev membahas sistem operasi, sistem locknya, memory managemen, kernel, boot step nya, dll

http://osblog.stephenmarz.com/index.html

https://c-ares.org/docs.html#examples

dokumentasi C-ares (async dns resolver)

https://github.com/torvalds/linux/blob/d683b96b072dc4680fc74964eca77e6a23d1fa6e/drivers/char/random.c#L55

"Computers are very predictable devices. Hence it is extremely hard to produce truly random numbers on a computer"

https://stackoverflow.com/questions/17898989/what-is-global-start-in-assembly-language

If you want to use a different entry point name other than _start (which is the default), you can specify -e parameter to ld like

ld -e my_entry_point -o output_filename object_filename

inline ASM GCC

http://www.ucw.cz/~hubicka/papers/amd64/node1.html

movabs is ATT-syntax for mov al/ax/eax/rax, byte/[d|q]word ptr [<64-bit absolute address>] or mov byte/[d|q]word ptr[<64-bit absolute address>], al/ax/eax/rax

tambahan: movabs is used for absolute data moves, to either load an arbitrary 64-bit constant into a register or to load data in a register from a 64-bit address.

https://electronicsreference.com/assembly-language/assembly-language-registers/

bookmark movabs

  • http://www.ucw.cz/~hubicka/papers/amd64/node1.html
  • https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82339
  • https://cs4157.github.io/www/2024-1/lect/13-x86-assembly.html

memory layout linux

this section is pure form, created when I use mdbook

Resume alpro

flowchart

Apa itu flowchart? simplenya, flowchat itu semacam bentuk gambar atau visual dari suatu langkah langkah algoritma. dan tentunya karna ini algoritma, maka ada step step seperti jika x maka y, lalu panah panah dari atas ke bawah, lalu input, dll. contoh flowchart cara memperbiaki lampu

gambar

Class

Apa itu class? class adalah cara kita mengatur kode agar scope nya bisa dipecah, misal func a isinya ada 1000 line, nah agar mudah mendebugnya, kita bisa pecah ke method method yang sangat banyak, dan juga kita tidak perlu lagi pusing dengan banyak variabel, kita cukup memakai satu varlable, lalu gunakan di seluruh class yang dinamai "property"

contoh simple, pakai property untuk nyimpan-tampilkan data,
#include <string>
#include <iostream>

using namespace std;

class abc {
    string nama;
public:
    void set_nama(string nama) {
        this->nama = nama;
    }

    void get_nama() {
        cout << this->nama << endl;
    }
};

int main() {
    abc abc;
    abc.set_nama("fadhil");
    abc.get_nama();
}

Enkapsulasi (encapsulation)

Trik atau cara agar kita bisa memberi aturan ke class/property apakah ia bisa terlihat (public)? atau tidak (private/protected) ke class.

Intinya, bagaimana cara kita agar method atau property, tidak bisa secara sembarang diakses oleh kode lain. misal kita ada class trigonometri, dan method hitung sin, tetapi didalam hitung sin tersebut, ada method kecil kecil lagi yang banyak, tetapi fungsinya seperti hanya untuk ngebantu fungsi sin menjalankan tugasnya, nah fungsi2 yang kecil tadi itu nanti dibuat private, sedangkan fungsi sin yg dipakai dimana mana, dibuat public.

contoh kecil

#include <string>
#include <iostream>

using namespace std;

class abc {
    string nama;
private:
    void print_perkenalan() {
        cout << "perkenalkan nama saya ";
    }

public:
    void set_nama(string nama) {
        this->nama = nama;
    }

    void get_nama() {
        this->print_perkenalan();
        cout << this->nama << endl;
    }
};

int main() {
    abc abc;
    abc.set_nama("fadhil");
    abc.get_nama();
}

terlihat public, private? nah itu adalah contoh encapsulation.

nah, print_perkenalan (hanya contoh) bertindak seolah olah dia hanya internal function dari suatu class yg besar. dan yang dipanggil dimana mana adalah get nama, dimana dibaliknya dia manggil banyak func yang lain.

dan print_perkenalan tidak boleh diakses langsung. termasuk property nama juga tidak boleh diakses langsung

Sorting

Bubble Sort

Konsepnya, dengan cara melempar lempar data array, sampai dia urut, BigO nya O(n^2). cara kerja nya yaitu dengan cara menukar-nukar posisi array sekarang dengan array didepannya, jika array saat ini > dari array didepannya, maka tukar posisinya

misal ada data simple seperti ini

2  3  1  (awal mulanya)
2  1  3  (3 ditukar karna 3 > 1)
1  2  3 (2 ditukar karna 2 > 1)
1  2  3  (selesai)

Selection Sort

TL;DR, menemukan data yg lebih kecil dari nilai minimum saat ini, tunggu loopnya yang didalam selesai baru di swap.

contoh kita akan sorting

2  9  4   1  (belum diapa-apakan)
2  9  4   1  (minimum index ke 0, yaitu 2)
2  9  4   1  (bandingkan 9 dgn index ke 0 yaitu 2, 9 < 2 false)
2  9  4   1  (bandingkan 4 dgn index ke 0, yaitu 2, 4 < 2, false)
2  9  4   1  (bandingkan 1 dgn index ke 0, yaitu 2, 1 < 2, true, maka tukar)
1  9  4   2  (set minimum di index  ke 1 sekarang, yaitu 9)
1  9  4   2  (bandingkan 4 dgn index ke 1, 4 < 9, true, maka kita biarkan karna loop belum selesai, tapi set minimum ke 4)
1  9  4   2  (cek apakah 2 < 4, ya, set minimum ke 2)
1  2  4   9  (tukar)
1  2  4   9  (set minimum ke index ke 3, yaitu 4, apakah 9 < 4, tidak)
--end---

insertion sort

Konsepnya, misal lagi menyusun kartu dari satu per satu. Jadi kamu ambil satu kartu, terus kamu bandingin ke kiri, kalau dia lebih kecil dari yang di kiri-nya, tukar posisinya. Terus begitu sampai semua kartu (data) urut

contoh

5 3 4 1 (unchanged)
3 5 4 1 (3 dimasukkan ke kiri 5 karena 3 < 5)
3 4 5 1 (4 dimasukkan, dia lebih kecil dari 5, jadi tukar)
1 3 4 5 (1 dimasukkan paling kiri, karena dia lebih kecil dari semuanya)

merge sort

misal ada data, terus di bagi-bagi tumpukan data jadi kecil-kecil dulu sampai tinggal satuan, baru nanti disusun lagi sambil dibandingin dan digabungin pelan-pelan sampai jadi urut. Cara kerjanya pakai prinsip divide and conquer Jadi data dibelah-belah jadi dua terus, sampai tinggal 1-an, lalu disatukan lagi sambil diurutin.

contoh gifnya (google)

nah, ini search paling gampang wkwkwk, intinya loop terus array nya, jika ketemu idx nya pakai if else, maka break loopnya & end

binary searching

cara mencarinya data dibagi 2 ditengah tengah, lalu setelah dibagi 2, akan ada low (pojok kiri), mid (tengah tengah), high (pojok kanan). lalu cek saja pastikan data yg dicari == mid

jika tidak, maka cek statusnya dia kurang dari mid atau lebih, jika lebih, cari bagian kanan, jika kurang, cari bagian kiri. proses ini diulang terus dan tiap2 menemukan low dan high baru, maka mid pasti berubah.

single linked list

misal, ini PSEUDOCODE

struct node {
    data_asli,
    pointer_ke_struct_node_lain_sebut_saja_n
}

misal, kita define struct node sebagai a, maka kita ambil addr nya, lalu define lagi b, dimana b berisi data dan juga pointer ke a, lalu misal define lagi c, isinya pointer ke b.

maka secara harfiah, c -> b -> a nah, untuk pengecekan, loop lalu deference terus saja untuk pointernya, jadi yg awalnya di c, setelah deference pointer milik b, posisi sekarang di b, lalu deference pointer next nya, alhasil kita dapat a, dan agar bisa stop. maka bagian palig akhir harus dikasih tanda, contoh disini tandanya bisa pakai nullptr.

intinya jika pas di deference isinya nullptr, maka sudah selesai

sinle linked list circular

sama saja seperti single linked list, hanya aja dibagian akhir daripada diisi nullptr, kita isi pointer balik ke awal. alhasil dia seperti memutar.

Resume alpro double linkedlists

langsung saja ini kodenya, 3 kode bebas, disini saya wrap di func saja karna agar tidak perlu buat banyak file.

penjelasan kode ADA DIBAGIAN BAWAH SNIPPET KODE ini.

#include <cstddef>
#include <iostream>

using namespace std;

struct Node {
  int data;
  Node *prev;
  Node *next;
};

Node *create_node(int data) {
  Node *newly_created_node = new Node;

  newly_created_node->data = data;
  newly_created_node->next = nullptr;
  newly_created_node->prev = nullptr;

  return newly_created_node;
}

void print(Node *head) {
  Node *current = head;
  cout << "Informasi tentang setiap node:" << endl;
  while (current != nullptr) {
    cout << "Alamat: " << current << endl;
    cout << "Nilai: " << current->data << endl;
    cout << "Alamat prev: " << current->prev << endl;
    cout << "Alamat next: " << current->next << endl << endl;
    current = current->next;
  }
  cout << "---------------------------------------" << endl;
}

void insert_last(Node *&head, int data) {
  Node *newly_created_node = create_node(data);
  if (head == nullptr) {
    head = newly_created_node;
  } else {
    Node *current = head;

    while (current->next != nullptr) {
      current = current->next;
    }

    current->next = newly_created_node;
    newly_created_node->prev = current;
  }
}

void insertFirst(Node *&head, int data) {
  Node *newNode = create_node(data);
  if (head == nullptr) {
    head = newNode;
  } else {
    newNode->next = head;
    head->prev = newNode; 
    head = newNode;
  }
}

void delete_first(Node *&head) {

  if (head == nullptr) {
    printf("node kosong\n");
  }

  Node *temp = head;
  head = head->next;

  if (head != nullptr) {
    head->prev = nullptr;
  }

  delete temp;
}

int main() {
  Node *head = nullptr;

  head = create_node(7);
  insert_last(head, 1);
  insert_last(head, 10);
  delete_first(head);
  insertFirst(head, 99);

  print(head);
}

func create_node

Walau bukan bagian dari tugas, saya sekalian jelaskan saja. intinya func ini membuat node baru, yang isinya prev dan next, diisi nullptr (alias nullpointer), dan datanya.

jadi maksud func ini, kita bikin node yang bener2 kosong tanpa terhubung ke siapapun. lalu return value nya.

func insert_last

Cara kerjanya spt ini.

  • kita buat dulu node nya (node yg tidak terhubung dgn siapapun pakai create_node)
  • lalu cek, misalkan head yg dari func main itu masih nullptr (karna emang defaultnya nullptr), maka pertanda linked listsnya masih kosong, maka kita bisa timpa saja.
  • jika tidak? kita simpan dulu node saat ini, anggap saja namanya current
  • sudah kesimpan kan? current kita arahkan ke current->next, alhasil dia ngakses pointer selanjutnya, lalu cek apakah dia nullptr atau bukan (sbg penanda)
  • misal iya, maka saatnya berhenti, lalu sambung, intinya karna dibelakang nullptr, maka untuk nyambungnya, nullptr kita ganti saja pakai address node yang barusan dibuat.
  • agar bisa nyambung kebelaknng, maka prev (previus miliknya new node) kita timpa pakai current, kenapa? node yg terbaru itu prev nya masih nullptr, agar nyambung, maka kita harus isi dengan node sebelumnya yg sudah disimpan.

nb: Node *&head artinya nge-deferensi pointer, sekaligus kalau ada perubahan data, sekalian di update, jadi misal ubah data di func delete_last, maka kalau dibaca oleh insert_first, data yg kita share tetep singkron

func insertFirst

nah, ini func paling easy wkwk, karna head guarantee akan selalu point ke depan, maka untuk nyispin data didepan sangatlah easy.

buat node baru, lalu node baru (next nya) diisi head. untuk prev (milik nya node lama) kita addr node baru.

func delete_first

konsepnya mirip dengan insert first, hanya saja

  • karna head selalu point ke depan, maka kita perlu simpan head (yang sekarang), lalu saatnya pindah state ke node sebelahnya (kekanan)
  • lalu lanjut mark bahwa head->prev itu nullptr, artinya headnya pindah.
  • ok sudah, nah, head yang tadi disimpan, bisa di hapus pakai delete

Rumus sector disk Linux

rumus sector linux

\( x \times 512 = (n \times 1024 \times 1024 \times 1024) \)

dan untuk \( n \) sesuaikan dengan kebutuhan.

disk sector mulai dari 2048. maka misal, x adalah 3145728, command parted nya parted /dev/sda --script mkpart P1 ext4 2048s 3145728s misal ingin menambah sekitar 500 MB, maka offset terakhir ditambah 1, misal

parted /dev/sda --script mkpart P2 ext4 3145729s 4194304s

link referensi

Regex notes

letter & digits

  • \D+: Matching all non digits, then grouping

match any using .

the . match all chars, except \r or \n

example: regexp: r".+"

It will match anything as long as there is at least one character present. no empty string such ""

template workspace json vscode

{
  "folders": [
    {
      "path": "rpc"
    },
    {
      "path": "scraperlib"
    },
    {
      "path": "offlinelook"
    }
  ]
}

Protobuf

protobuf ini intinya format pertukaran data, mirip json, tapi dia pakai schema (mirip graphql), agak kaku, dan ada method2

baca spec: https://protobuf.dev/programming-guides/proto3/

ini termasuk prelude nya

syntax = "proto3";

// this is namefile 
package grpc.fadhil;

lalu ini anggap saja seperti struct, jika di C biasanya sent data over file pakai struct.

message Message1 {}

message Message2 {
  Message1 foo = 1;
}

baru kita define semacam namespace yang didalamnya hold func func yang akan dicall oleh grpc

service SearchService {
  rpc Search(SearchRequest) returns (SearchResponse);
}

Subnetting

pertama tama, range ip dahulu

  • A: 1 - 127

  • B: 128 - 191

  • C: 192 - AKHIR

  • 0b00000000 -> 0 (katakanlah octet ke 4, cidr 24)

  • 0b10000000 -> 0 (cidr 25, 128 hosts) // 2 network

  • 0b11000000 -> 0 (cidr 26, 128 + 64) // 4 network

  • 0b11100000 -> 0 (cidr 27, 128 + 64 + 32) // 8 network

  • 0b11110000 -> 0 (cidr 28, 128 + 64 + 32 + 16) // 16 network

  • 0b11111000 -> 0 (cidr 29, 128 + 64 + 32 + 16 + 8) // 32 network

  • 0b11111100 -> 0 (cidr 30, 128 + 64 + 32 + 16 + 8 + 4) // 64 network

  • 0b11111110 -> 0 (cidr 31, 128 + 64 + 32 + 16 + 8 + 4 + 2) // 128 network

  • 0b11111111 -> 0 (cidr 32, 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1) // 256 network

seperti yg terlihat, bahwa 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255

contoh 192.168.10.0/24:

ada network 192.168.10.0/24, kita ingin bagi jadi 4 jaringan. maka 256 / 4 = 64 hosts, dan ini akan

  • subnet nya: 255.255.255.192
  • 64 hosts: 64 hosts usable, 1 untuk broadcast, 1 untuk network

pembagian nya

  • network 1: 192.168.10.0, broadcast: 192.168.10.63, range ip yang usable: 192.168.10.1 - 192.168.10.62
  • network 2: 192.168.10.64, broadcast: 192.168.10.127, range ip yang usable: 192.168.10.65 - 192.168.10.126
  • network 3: 192.168.10.128, broadcast: 192.168.10.191, range ip yang usable: 192.168.10.129 - 192.168.10.190
  • network 4: 192.168.10.192, broadcast: 192.168.10.255, range ip yang usable: 192.168.10.193 - 192.168.10.254

oprekan hitung2 an:

origin: pakai acuan ip kelas c

jumlah hosts, misal cidr 24, itu max nya 256 kalau 0b11111111, kenapa 0b10000000 itu 128, dan kenapa 0b11000000 itu 192

ok, lalu kenapa jika cidr /26, itu 255.255.255.192, punya 64 hosts, 4 network. semua ini didapat dari (max int case ini 8 bit) / maxint - pad network

ini start dari /24

  • 0b00000000 -> 0 (katakanlah octet ke 4, cidr 24) // 1 network
  • 0b10000000 -> 0 (cidr 25, 128 hosts) // 2 network
  • 0b11000000 -> 0 (cidr 26, 128 + 64) // 4 network
  • 0b11100000 -> 0 (cidr 27, 128 + 64 + 32) // 8 network
  • 0b11110000 -> 0 (cidr 28, 128 + 64 + 32 + 16) // 16 network
  • 0b11111000 -> 0 (cidr 29, 128 + 64 + 32 + 16 + 8) // 32 network
  • 0b11111100 -> 0 (cidr 30, 128 + 64 + 32 + 16 + 8 + 4) // 64 network
  • 0b11111110 -> 0 (cidr 31, 128 + 64 + 32 + 16 + 8 + 4 + 2) // 128 network
  • 0b11111111 -> 0 (cidr 32, 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1) // 256 network

start dari /16

  • 0b0000000000000000 -> 0 (cidr 16, 65535) // 1 net, 65535 hosts
  • 0b1000000000000000 -> 0 (cidr 17, 65535 + ) // 2 net, 32767 hosts
  • 0b1100000000000000 -> 0 (cidr 26, 128 + 64) // 4 net
  • 0b1110000000000000 -> 0 (cidr 27, 128 + 64 + 32) // 8 net
  • 0b1111000000000000 -> 0 (cidr 28, 128 + 64 + 32 + 16) // 16 net
  • 0b1111100000000000 -> 0 (cidr 29, 128 + 64 + 32 + 16 + 8) // 32 net
  • 0b1111110000000000 -> 0 (cidr 30, 128 + 64 + 32 + 16 + 8 + 4) // 64 net
  • 0b1111111000000000 -> 0 (cidr 31, 128 + 64 + 32 + 16 + 8 + 4 + 2) // 128 net
  • 0b1111111100000000 -> 0 (cidr 32, 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1) // 256 net

-- stagging (perhitungan ip cidr 16 keatas) max int 16 bit: 65536

  • /16 : 0b0000000000000000 = 0
  • /17 : 0b1000000000000000 = 32768, maka 65536 / 32768 = 2, alias 2 network, 32768 hosts
  • /18 : 0b1100000000000000 = 49152, maka 65536 / (65536 - 49152) = 4 network, 16384 hosts,
  • /19 : 0b1110000000000000 = 57344, maka 65536 / (65536 - 57344) = 8 network, 8192 hosts,
  • /20 : 0b1111000000000000 = 61440, maka 65536 / (65536 - 61440) = 16 network, 4096 hosts,
  • /21 : 0b1111100000000000 = 61440, maka 65536 / (65536 - 61440) = 32 network, 2048 hosts,
  • /22 : 0b1111110000000000 = 64512, maka 65536 / (65536 - 64512) = 64 network, 1024 hosts,
  • /23 : 0b1111111000000000 = 64512, maka 65536 / (65536 - 64512) = 128 network, 512 hosts,
  • /24 : 0b1111111100000000 = 64512, maka 65536 / (65536 - 64512) = 256 network, 256 hosts,

-- stagging cidr 8 keatas max int int 24 bit: 16777216

  • /9 : 0b100000000000000000000000 = 16777216 / (16777216 - 8388608) = 2 network, 8388608 hosts

  • /10: 0b110000000000000000000000 = 16777216 / (16777216 - 12582912)= 4 network, 4194304 hosts

  • /11: 0b111000000000000000000000 = 16777216 / (16777216 - 14680064)= 8 network, 2097152 hosts

  • /12: 0b111100000000000000000000 = 16777216 / (16777216 - 15728640)= 16 network, 1048576 hosts

  • /13: 0b111110000000000000000000 = 16777216 / (16777216 - 16252928)= 32 network, 524288 hosts

  • /14: 0b111111000000000000000000 = 16777216 / (16777216 - 16515072) = 64 network, 262144 hosts

  • /15: 0b111111100000000000000000 = 16777216 / (16777216 - 16646144) = 128 network, 131072 hosts

  • /16: 0b111111110000000000000000 = 16777216 / (16777216 - 16711680) = 256 network, 65536 hosts

  • /17: 0b111111111000000000000000 = 16777216 / (16777216 - 16744448) = 512 network, 32768 hosts

  • /18: 0b111111111100000000000000 = 16777216 / (16777216 - 16760832) = 1024 network, 16384 hosts

  • /19: 0b111111111110000000000000 = 16777216 / (16777216 - 16769024) = 2048 network, 8192 hosts

  • /20: 0b111111111111000000000000 = 16777216 / (16777216 - 16773120) = 4096 network, 4096 hosts

  • /21: 0b111111111111100000000000 = 16777216 / (16777216 - 16775168) = 8192 network, 2048 hosts

  • /9 : 0b100000000000000000000000:

kumpulan rumus rumus

subnet

rumusnya: \( 2^{jumlah \space angka \space 1 \space di \space setiap \space padding \space subnet}\)

contoh

  • prefix /19, pad terdekatnya /16, maka dari 16 ke 19 ada 3 angka 1 (0b11100000), maka jumlah subnet yang akan terbentuk adalah 2^3 = 8 subnet
  • prefix /26, pad terdekatnya 24, maka dari 24 ke 26 ada 2 angka 1 (0b11000000), maka jumlah subnetnya 2^2 = 4

jumlah hosts

rumusnya: \( 2^{jumlah \space angka \space 0 \space dari \space 32} \)

contoh

  • prefix /19, 32 - 19 = 13 angka 0, maka \( 2^{13} = 8192 \space hosts \)
  • prefix /26, 32 - 26 = 6 angka 0, maka \( 2^{6} = 64 \space hosts \)
  • prefix /8, 32 - 8 = 24 angka 0, maka \( 2^{24} = 16777216 \space hosts \)

Inter-VLAN routing

how to config vlan inter-VLAN routing

topology:

  • VNET1:192.168.10.0/24 (vlan 10)
  • PC1: 192.168.10.2
  • PC2: 192.168.10.3
  • VNET2:192.168.20.0/24 (vlan 20)
  • PC3: 192.168.20.2
  • PC4: 192.168.20.3
  • ROUTER IP (fa0/0.10): 192.168.10.1
  • ROUTER IP (fa0/0.20): 192.168.20.1

SCRIPTS

management

- show vlan brief: show all configured vlan

setup vlan (tanpa setup ip dulu)

Switch>enable
Switch#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
Switch(config)#vlan 10
Switch(config-vlan)#name SALES
Switch(config-vlan)#ex
Switch(config)#vlan 20
Switch(config-vlan)#name IT

lalu setup mode

  • trunk: untuk switch ke router
  • access: untuk switch ke PC

setup untuk vlan 10 dan 10, masing2 dengan network 192.168.10.0/24 dan 192.168.20.0/24

script:

Switch#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
Switch(config)#int fa0/1
Switch(config-if)#switchport mode access
Switch(config-if)#switchport access vlan 10
Switch(config-if)#ex
Switch(config)#int fa0/2
Switch(config-if)#switchport mode access
Switch(config-if)#switchport access vlan 10
Switch(config-if)#ex
Switch(config)#int fa0/3
Switch(config-if)#switchport mode access
Switch(config-if)#switchport access vlan 20
Switch(config-if)#ex
Switch(config)#int fa0/4
Switch(config-if)#switchport mode access
Switch(config-if)#switchport access vlan 20
Switch(config-if)#ex
Switch(config)#

alternative script

Switch(config-if)#int range fa0/1-4
Switch(config-if-range)#switchport mode access

config untuk port fa0/5 ke router (pakai mode trunk)

Switch(config)#int fa0/5
Switch(config-if)#switchport mode trunk
Switch(config-if)#

inter-VLAN routing

enable port Fa0/0 (tanpa assign ip dahulu)

Router(config)#int fa0/0
Router(config-if)#no shut

Router(config-if)#
%LINK-5-CHANGED: Interface FastEthernet0/0, changed state to up

%LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/0, changed state to up

assign ip untuk masing2 vlan

Router(config)#interface FastEthernet0/0
Router(config-if)#int fa0/0.10
Router(config-subif)#
%LINK-5-CHANGED: Interface FastEthernet0/0.10, changed state to up

%LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/0.10, changed state to up

Router(config-subif)#encapsulation dot1q 10 
Router(config-subif)#ip add 192.168.10.1 255.255.255.0
Router(config-subif)#ex
Router(config)#int fa0/0.20
Router(config-subif)#
%LINK-5-CHANGED: Interface FastEthernet0/0.20, changed state to up

%LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/0.20, changed state to up

Router(config-subif)#encapsulation dot1q 20
Router(config-subif)#ip add 192.168.20.1 255.255.255.0
Router(config-subif)#

hasil output show vlan brief

Switch>show vlan brief

VLAN Name                             Status    Ports
---- -------------------------------- --------- -------------------------------
1    default                          active    Fa0/6, Fa0/7, Fa0/8, Fa0/9
                                                Fa0/10, Fa0/11, Fa0/12, Fa0/13
                                                Fa0/14, Fa0/15, Fa0/16, Fa0/17
                                                Fa0/18, Fa0/19, Fa0/20, Fa0/21
                                                Fa0/22, Fa0/23, Fa0/24, Gig0/1
                                                Gig0/2
10   SALES                            active    Fa0/1, Fa0/2
20   IT                               active    Fa0/3, Fa0/4
1002 fddi-default                     active    
1003 token-ring-default               active    
1004 fddinet-default                  active    
1005 trnet-default                    active    
Switch>

tambahan

  • encapsulation dot1q: router on stick routing

Advanced switch cisco command

Tealinux qemu promp & testing

create image

qemu-img create -f qcow2 <NAME>.img 45G

  • Change 45G with your desired size

running system on BIOS mode

this will open SSH connection on port 20022

live

qemu-system-x86_64 \
                -enable-kvm \
                -boot order=d \
                -cdrom tealinux-2025.02.16-x86_64.iso \
                -drive file=tealinux.img,format=qcow2 \
                -m 4G \
                -enable-kvm \
                -smp 4 \
                -net user,hostfwd=tcp::20022-:22 \
                -net nic

non-live

qemu-system-x86_64 \
                -enable-kvm \
                -boot order=d \
                -drive file=tealinux.img,format=qcow2 \
                -m 4G \
                -enable-kvm \
                -smp 4 \
                -net user,hostfwd=tcp::20022-:22 \
                -net nic

running on UEFI mode

in order to running qemu on UEFI mode, we need edk2-ovmf

get your ovmf vars by running cp /usr/share/edk2/x64/OVMF_VARS.4m.fd .

live

qemu-system-x86_64 \
                -enable-kvm \
                -cdrom tealinux-2025.02.16-x86_64.iso \
                -boot order=d \
                -drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd \
                -drive if=pflash,format=raw,file=OVMF_VARS.4m.fd \
                -drive file=tealinux.img,format=qcow2 \
                -m 4G \
                -enable-kvm \
                -smp 4 \
                -net user,hostfwd=tcp::20022-:22 \
                -net nic

non-live

qemu-system-x86_64 \
                -enable-kvm \
                -boot order=d \
                -drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd \
                -drive if=pflash,format=raw,file=OVMF_VARS.4m.fd \
                -drive file=tealinux.img,format=qcow2 \
                -m 4G \
                -enable-kvm \
                -smp 4 \
                -net user,hostfwd=tcp::20022-:22 \
                -net nic

windows

qemu-system-x86_64 \
                -enable-kvm \
                -boot order=d \
                -cdrom Win10_22H2_English_x64v1.iso \
                -drive file=windows-tealinux-mbr.img,format=qcow2 \
                -m 4G \
                -enable-kvm \
                -smp 4 \
                -net user,hostfwd=tcp::20022-:22 \
                -net nic

uefi version

qemu-system-x86_64 \
                 -enable-kvm \
                 -boot order=d \
                 -cdrom Win10_22H2_English_x64v1.iso \
                 -drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd \
                 -drive if=pflash,format=raw,file=OVMF_VARS.4m.fd \
                 -drive file=tealinux.img,format=qcow2 \
                 -m 4G \
                 -enable-kvm \
                 -smp 4 \
                 -net user,hostfwd=tcp::20022-:22

note: bug unwrap error

qemu-system-x86_64 \
                      -enable-kvm \
                      -boot order=d \
                      -cdrom tealinux-2025.02.16-x86_64.iso \
      -drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd \
                      -drive if=pflash,format=raw,file=OVMF_VARS.4m.fd \
                      -drive file=tealinux.img,format=qcow2 \
                      -m 4G \
                      -enable-kvm \
                      -smp 4 \
                      -net user,hostfwd=tcp::20022-:22 \
      -net nic

misc

add more drive

in order add more drive, use this param

  • -drive file=img1.img,format=qcow2
  • -drive file=img1.img,format=qcow2

forward more port

imagine you need to forward another port, not only ssh, the correct command is -net user,hostfwd=tcp::10022-:22,hostfwd=tcp::8080-:8080,hostfwd=tcp::5173-:5173

5173 is our port.

binary operation

catatan subnetting from scratch

origin: pakai acuan ip kelas c

jumlah hosts, misal cidr 24, itu max nya 256 kalau 0b11111111, kenapa 0b10000000 itu 128, dan kenapa 0b11000000 itu 192

ok, lalu kenapa jika cidr /26, itu 255.255.255.192, punya 64 hosts, 4 network. semua ini didapat dari (max int case ini 8 bit) / maxint - pad network

ini start dari /24

  • 0b00000000 -> 0 (katakanlah octet ke 4, cidr 24) // 1 network
  • 0b10000000 -> 0 (cidr 25, 128 hosts) // 2 network
  • 0b11000000 -> 0 (cidr 26, 128 + 64) // 4 network
  • 0b11100000 -> 0 (cidr 27, 128 + 64 + 32) // 8 network
  • 0b11110000 -> 0 (cidr 28, 128 + 64 + 32 + 16) // 16 network
  • 0b11111000 -> 0 (cidr 29, 128 + 64 + 32 + 16 + 8) // 32 network
  • 0b11111100 -> 0 (cidr 30, 128 + 64 + 32 + 16 + 8 + 4) // 64 network
  • 0b11111110 -> 0 (cidr 31, 128 + 64 + 32 + 16 + 8 + 4 + 2) // 128 network
  • 0b11111111 -> 0 (cidr 32, 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1) // 256 network

start dari /16

  • 0b0000000000000000 -> 0 (cidr 16, 65535) // 1 net, 65535 hosts
  • 0b1000000000000000 -> 0 (cidr 17, 65535 + ) // 2 net, 32767 hosts
  • 0b1100000000000000 -> 0 (cidr 26, 128 + 64) // 4 net
  • 0b1110000000000000 -> 0 (cidr 27, 128 + 64 + 32) // 8 net
  • 0b1111000000000000 -> 0 (cidr 28, 128 + 64 + 32 + 16) // 16 net
  • 0b1111100000000000 -> 0 (cidr 29, 128 + 64 + 32 + 16 + 8) // 32 net
  • 0b1111110000000000 -> 0 (cidr 30, 128 + 64 + 32 + 16 + 8 + 4) // 64 net
  • 0b1111111000000000 -> 0 (cidr 31, 128 + 64 + 32 + 16 + 8 + 4 + 2) // 128 net
  • 0b1111111100000000 -> 0 (cidr 32, 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1) // 256 net

-- stagging (perhitungan ip cidr 16 keatas) max int 16 bit: 65536

  • /16 : 0b0000000000000000 = 0
  • /17 : 0b1000000000000000 = 32768, maka 65536 / 32768 = 2, alias 2 network, 32768 hosts
  • /18 : 0b1100000000000000 = 49152, maka 65536 / (65536 - 49152) = 4 network, 16384 hosts,
  • /19 : 0b1110000000000000 = 57344, maka 65536 / (65536 - 57344) = 8 network, 8192 hosts,
  • /20 : 0b1111000000000000 = 61440, maka 65536 / (65536 - 61440) = 16 network, 4096 hosts,
  • /21 : 0b1111100000000000 = 61440, maka 65536 / (65536 - 61440) = 32 network, 2048 hosts,
  • /22 : 0b1111110000000000 = 64512, maka 65536 / (65536 - 64512) = 64 network, 1024 hosts,
  • /23 : 0b1111111000000000 = 64512, maka 65536 / (65536 - 64512) = 128 network, 512 hosts,
  • /24 : 0b1111111100000000 = 64512, maka 65536 / (65536 - 64512) = 256 network, 256 hosts,

-- stagging cidr 8 keatas max int int 24 bit: 16777216

  • /9 : 0b100000000000000000000000 = 16777216 / (16777216 - 8388608) = 2 network, 8388608 hosts

  • /10: 0b110000000000000000000000 = 16777216 / (16777216 - 12582912)= 4 network, 4194304 hosts

  • /11: 0b111000000000000000000000 = 16777216 / (16777216 - 14680064)= 8 network, 2097152 hosts

  • /12: 0b111100000000000000000000 = 16777216 / (16777216 - 15728640)= 16 network, 1048576 hosts

  • /13: 0b111110000000000000000000 = 16777216 / (16777216 - 16252928)= 32 network, 524288 hosts

  • /14: 0b111111000000000000000000 = 16777216 / (16777216 - 16515072) = 64 network, 262144 hosts

  • /15: 0b111111100000000000000000 = 16777216 / (16777216 - 16646144) = 128 network, 131072 hosts

  • /16: 0b111111110000000000000000 = 16777216 / (16777216 - 16711680) = 256 network, 65536 hosts

  • /17: 0b111111111000000000000000 = 16777216 / (16777216 - 16744448) = 512 network, 32768 hosts

  • /18: 0b111111111100000000000000 = 16777216 / (16777216 - 16760832) = 1024 network, 16384 hosts

  • /19: 0b111111111110000000000000 = 16777216 / (16777216 - 16769024) = 2048 network, 8192 hosts

  • /20: 0b111111111111000000000000 = 16777216 / (16777216 - 16773120) = 4096 network, 4096 hosts

  • /21: 0b111111111111100000000000 = 16777216 / (16777216 - 16775168) = 8192 network, 2048 hosts

  • /9 : 0b100000000000000000000000:

set PATH fish shell

first, edit this

  • nvim /home/$(whoami)/.config/fish/config.fish

add this line before if status is-interactive set -gx PATH /new/path $PATH