thảo luận Hướng dẫn dùng Cloudflare Zero Trust

  • Người tạo chủ đề Người tạo chủ đề Fioren
  • Ngày bắt đầu Ngày bắt đầu
Hướng dẫn sử dụng Router Mikrotik tự động cập nhật IP Wan (IP Public không NAT) lên Cloudflare DNS Location thông qua Cloudflare API.
Cách này là cách cập nhật IP nhanh hơn DDNS bởi vì vừa có IP là nó cập nhật lên Cloudflare không đợi update record DNS toàn cầu.
1. Yêu cầu:
  • Account id (lấy ở #1).
  • API KEY (lấy ở #1).
  • Account Email: email cloudflare của bạn.
  • Tên interface WAN trong router Mikrotik (của mình là pppoe-out1).
  • Router Mikrotik

2. Phiên bản RouterOS: Hiện tại mình test chạy ổn định 3.000 lượt run script không lỗi lầm trên Router OS 7.12 beta 7.

3. Bắt đầu:

- Lấy tên của Interface WAN của bạn như sau:
Mở Winbox, chọn PPP, tên interface WAN của bạn là ở Name (của mình là pppoe-out1):
totPKiV.png

(1) Tạo Script fetch tới Cloudflare API
bTDmCXz.png

Nhấn dấu (+) để tạo Script mới
7JAK6k5.png

Thiết lập tên script và code cho script này:
Code mẫu:
Mã:
:local ip
set $ip [/ip address get [find interface=<EDIT PPPOE INTERFACE>] address]
:local ipWithoutMask [:pick $ip 0 [:find $ip "/"]]
/tool fetch url="https://api.cloudflare.com/client/v4/accounts/<EDIT_ACCOUNT_ID>/gateway/locations/<EDIT_DNS_LOCATION>" \
  mode=https http-method=put \
  http-header-field="Authorization: Bearer <EDIT_API_TOKEN>, Content-Type: application/json, X-Auth-Email: <EDIT_ACCOUNT_EMAIL>, X-Auth-Key: <EDIT_API_TOKEN>" \
  http-data="{ \"client_default\": true, \"ecs_support\": true, \"name\": \"RouterMikrotik\", \"networks\": [{ \"network\": \"$ip\" }] }" \
  output=none
Vui lòng sửa các thông tin dưới đây (không để dấu <>, ví dụ: interface=pppoe-out1):
1. <EDIT PPPOE INTERFACE>
2. <EDIT_ACCOUNT_ID>
3. <EDIT_API_TOKEN>
4. <EDIT_ACCOUNT_EMAIL>
ZBu964N.png

Sau đó nhấn OK để lưu lại.
Như thế này là thành công:
1kNJBkQ.png

(2) Tạo Scheduler để chạy Script mỗi 1 phút (có thể tuỳ chỉnh theo ý bạn)
Chọn System → Scheduler
XEl6L2G.png

Tiếp theo:
ec0ELs4.png


Code:
Mã:
/system script run update
=> Lưu lại và xem thành quả thôi, như thế này là OK.
Fz33ceO.png

Nếu các bạn muốn xem kết quả sau khi fetch tới Cloudflare, sửa code tại Script như sau:
pfY4s8t.png

Code:
Mã:
dst-path="result.txt"
Chúc các bác cấu hình thành công.
 
Sửa lần cuối:
Đến thời điểm này các script đã được viết lại hoàn toàn mà theo mình là đã hoàn thiện vì... chưa nghĩ ra chức năng gì thêm. Để dễ dàng cập nhật nhất thì vào Settings và xóa repo đi rồi fork lại, nhớ lưu lại những list các bạn sang sử dụng.

Xem tệp đính kèm 2079568

Các điểm khác biệt so với phiên bản ban đầu:
  • Hỗ trợ chạy trên Windows với Node.js do đã loại bỏ gần như toàn bộ Shell Script
  • Block tất cả subdomain thay vì chỉ domain được nhập vào.
  • Các định dạng hỗ trợ và cách nhận biết:
    • Hosts: có 127.0.0.1 hoặc 0.0.0.0 ở đầu
    • Domain + Subdomains: có bao gồm subdomain của domain
    • Adblock: có các ký tự ||, ^, $ hay các URL(URL sẽ được bỏ qua do DNS không chặn được)
    • Wildcard Asterisk: có dấu *. ở đầu
    • Wildcard Domains (hoạt động tốt nhất): chỉ bao gồm subdomain cần thiết và số lượng ít hơn định dạng Domain + Subdomain
  • Hỗ trợ chế độ siêu tốc với biến môi trường FAST_MODE
  • Hỗ trợ blocklist và allowlist từ biến môi trường ALLOWLIST_URLSBLOCKLIST_URLS
  • Hỗ trợ ngừng workflow cũ đang chạy trước khi chạy workflow mới trong GitHub Actions
  • Tốc dộ xử lý list nhanh hơn nhiều lần
  • Log rõ ràng hơn list nào sẽ được sử dụng, bao nhiêu domain đã được xử lý
Ví dụ các định dạng

HaGeZi
Xem tệp đính kèm 2079570

OISD
Xem tệp đính kèm 2079571

Log
Xem tệp đính kèm 2079576

Xem tệp đính kèm 2079578

Cách sử dụng script mới nhất:
  • Xóa repo cũ
  • Fork lại
  • Tạo thư mục .github/workflows
  • Copy auto_update_github_action.yml vào .github/workflows
  • Cách thêm biến môi trường tương tự như thêm secret
    • FAST_MODE: không thêm hoặc gán 0 sẽ chạy chế độ cũ, thêm và gán 1 sẽ chạy chế độ mới
    • ALLOWLIST_URLSBLOCKLIST_URLS: không thêm sẽ chạy list có sẵn, thêm thì mỗi list 1 dòng
      Xem tệp đính kèm 2079574
  • Chạy workflow
Lưu ý:
  • Cloudflare giới hạn số lượng request là 1200 mỗi 5 phút: https://developers.cloudflare.com/fundamentals/api/reference/limits/
  • Cách tính số lượng request: số lượng list cũ đã xóa + số lượng list mới + 1 request xóa rule cũ + 1 request tạo rule mới
    Xem tệp đính kèm 2079579
    Xem tệp đính kèm 2079580
    => 166 + 41 + 1 + 1 = 209 requests
  • Để chạy trên máy thì cài Node.js, copy file .env.example ra .env rồi điền giá trị và chạy theo thứ tự:
    Mã:
    npm install
    node download_lists.js
    node cf_gateway_rule_delete.js
    node cf_list_delete.js
    node cf_list_create.js
    node cf_gateway_rule_create.js
Như vậy với lần cập nhật này chỉ cần copy 1 file vào .github/workflows, sau đó thêm biến môi trường, có thay đổi gì thì sửa biến rồi chạy lại workflow là xong, không cần sửa file gì nữa :big_smile:
e bị lỗi hình bác ơi
 
Hướng dẫn sử dụng Cloudflare Worker cập nhật Source IPv4 address trong DNS Location của Cloudflare Zero Trust qua DDNS:
Vì sao lại có điều này:
  • Các bạn muốn áp dụng cho tất cả các thiết bị trong nhà dùng DNS Cloudflare, các thiết bị không thể cài DoT, DoH.
  • Tốc độ phản hồi rất nhanh.
  • IP được cập nhật mỗi phút.
CPNnvDs.png

Ảnh mô tả.
1. Yêu cầu:
  • Có DDNS trỏ tới địa chỉ IP của Router cần match với Cloudflare.
  • Có tài khoản Cloudflare (đa số đã có khi sử dụng Cloudflare Zero Trust như #1)
2. Bắt đầu:
- Truy cập Worker: https://dash.cloudflare.com/?to=/:account/workers-and-pages
(1) Create Worker
rMU9SsE.png


(2) Điền mục "Name" là updatelocation hoặc bất kì
hXctXJ2.png

(3) Kéo xuống cuối trang nhấn Deploy
L5fyIRj.png

(4) Nhấn Edit code
7m1SzUe.png

(5) Xoá tất cả các dòng code có sẵn, copy code dưới đây vào khung
w0HCdZk.png

JavaScript:
addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request));
  });
 
  async function handleRequest(request) {
    const accountEmail = '';
    const accountId = '';
    const apiToken = '';
    const domain = '';
    const ip = await resolveDomain(domain);
 
    if (ip) {
      console.log(`The IP address of ${domain} is: ${ip}`);
      const locationId = await getLocationId(accountId, apiToken, accountEmail);
      if (locationId) {
        console.log(`The location ID is: ${locationId}`);
        const updateResult = await updateLocation(accountId, apiToken, locationId, ip, accountEmail);
        if (updateResult) {
          console.log("Update location successful:");
          console.log(`Location ID: ${updateResult.id}`);
          console.log(`Name: ${updateResult.name}`);
          console.log(`IP: ${updateResult.networks[0].network}`);
          console.log(`Subnet: ${updateResult.networks[0].network.split('/')[1]}`);
          console.log(`Created At: ${updateResult.created_at}`);
          console.log(`Updated At: ${updateResult.updated_at}`);
        } else {
          console.log("No location data found.");
        }
      } else {
        console.log("No locations found.");
      }
    } else {
      console.log(`Failed to resolve the IP address of ${domain}`);
    }
 
    return new Response('Worker execution completed', { status: 200 });
  }
 
  async function resolveDomain(domain) {
    const apiURL = 'https://dns.google.com/resolve';
    const queryURL = new URL(apiURL);
    queryURL.searchParams.append('name', domain);
    queryURL.searchParams.append('type', 'A');
 
    const response = await fetch(queryURL);
    const data = await response.json();
 
    if (data.Answer instanceof Array && data.Answer.length > 0) {
      const ipAddresses = data.Answer
        .filter(answer => answer.type === 1)
        .map(answer => answer.data);
      return ipAddresses[0] || null;
    } else {
      return null;
    }
  }
 
  async function getLocationId(accountId, apiToken, accountEmail) {
 
    const url = `https://api.cloudflare.com/client/v4/accounts/${accountId}/gateway/locations`;
 
    const response = await fetch(url, {
      headers: {
        'Authorization': `Bearer ${apiToken}`,
        'Content-Type': 'application/json',
        'X-Auth-Email': accountEmail,
        'X-Auth-Key': apiToken
      }
    });
 
    if (response.ok) {
      const data = await response.json();
      const result = data.result;
      return result.length > 0 ? result[0].id : null;
    } else {
      return null;
    }
  }
 
  async function updateLocation(accountId, apiToken, locationId, ip, accountEmail) {
    const url = `https://api.cloudflare.com/client/v4/accounts/${accountId}/gateway/locations/${locationId}`;
 
    const response = await fetch(url, {
      method: 'PUT',
      headers: {
        'Authorization': `Bearer ${apiToken}`,
        'Content-Type': 'application/json',
        'X-Auth-Email': accountEmail,
        'X-Auth-Key': apiToken
      },
      body: JSON.stringify({
        client_default: true,
        ecs_support: true,
        name: 'RouterZTE',
        networks: [
          { network: `${ip}/32` }
        ]
      })
    });
 
    if (response.ok) {
      const data = await response.json();
      return data.result || null;
    } else {
      return null;
    }
  }
(6) Chỉnh sửa các thông tin cho các biến sau:
  • accountEmail: email cloudflare của bạn.
  • accountId: id account cloudflare của bạn, hướng dẫn lấy ở #1.
  • apiToken: apiToken cloudflare của bạn, hướng dẫn lấy ở #1.
  • domain: điền url của ddns của bạn vào.

bdKMLxh.png

(7) Save and deploy
JoVArNE.png

3. Tạo cron trigger để tự động chạy sau mỗi phút
jHp4A26.png

(1) Chọn vào Triggers
d3mQuSg.png

Tiếp tục ở reply sau
*đã cập nhật ảnh lỗi
Thank bác, bác gãi ngay đúng cái chỗ mình ngứa bấy lâu.
 
có fen nào xài còn f670y của viettel cứ reset phát là nó về mặc định ko lưu cấu hình ko 🙄 làm mấy nay cứ tưởng mình cấu hình lỗi chỗ nào vào modem mới thấy hóa ra nó ko lưu
 
có fen nào xài còn f670y của viettel cứ reset phát là nó về mặc định ko lưu cấu hình ko 🙄 làm mấy nay cứ tưởng mình cấu hình lỗi chỗ nào vào modem mới thấy hóa ra nó ko lưu
Theo Miêu biết thì router nào của Vịt Heo cũng bị đẩy cấu hình từ nhà mạng xuống đè lên. Muốn tự set cấu hình phải gọi kĩ thuật can thiệp từ trên tổng đài
 
modem t chặn 2 domain này chưa bao giờ bị đổi dns cả, lên app my viettel nó nhận sai luôn S/N modem, thử xem hết ko
ILkFbXu.png

Mã:
viettelhomewifi.com
viettelacs.vn
1695481694021.png

1695482488691.png
 
Router nhà mạng nhìn “chuyên nghiệp” vậy! Thấy giờ viettel đổi modem có logo với giao diện đơn giản hơn vầy nhiều lắm. Mà 2 tên miền ở trên đề cập check k có IP
router này mới nhận tháng 1 năm nay ấy thím :D , còn vụ ip thì ko rõ, chặn 2 cái đó cái tr069 bị tắt nên ko rõ bọn nhà mạng làm sao
 
Cập nhật code update IP từ DDNS lên Cloudflare để set DNS cho tất cả các thiết bị trong nhà (lên router, thiết bị) không cần DoH, DoT:

JavaScript:
addEventListener('scheduled', (event) => {
  event.waitUntil(handleRequest());
});

addEventListener('fetch', (event) => {
  return event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const accountEmail = '';
  const accountId= '';
  const apiToken = '';
  const domain = '';
  const ip = await resolveDomain(domain);

  if (ip) {
    console.log(`The IP address of ${domain} is: ${ip}`);
    const locationId = await getLocationId(accountId, apiToken, accountEmail);
    if (locationId) {
      console.log(`The location ID is: ${locationId}`);
      const updateResult = await updateLocation(accountId, apiToken, locationId, ip, accountEmail);
      if (updateResult) {
        console.log("Update location successful:");
        console.log(`Location ID: ${updateResult.id}`);
        console.log(`Name: ${updateResult.name}`);
        console.log(`IP: ${updateResult.networks[0].network}`);
        console.log(`Subnet: ${updateResult.networks[0].network.split('/')[1]}`);
        console.log(`Created At: ${updateResult.created_at}`);
        console.log(`Updated At: ${updateResult.updated_at}`);
      } else {
        console.log("No location data found.");
      }
    } else {
      console.log("No locations found.");
    }
  } else {
    console.log(`Failed to resolve the IP address of ${domain}`);
  }

  return new Response('Worker execution completed', { status: 200 });
}

async function resolveDomain(domain) {
  const apiURL = 'https://dns.google.com/resolve';
  const queryURL = new URL(apiURL);
  queryURL.searchParams.append('name', domain);
  queryURL.searchParams.append('type', 'A');

  const response = await fetch(queryURL);
  const data = await response.json();

  if (data.Answer instanceof Array && data.Answer.length > 0) {
    const ipAddresses = data.Answer
      .filter(answer => answer.type === 1)
      .map(answer => answer.data);
    return ipAddresses[0] || null;
  } else {
    return null;
  }
}

async function getLocationId(accountId, apiToken, accountEmail) {

  const url = `https://api.cloudflare.com/client/v4/accounts/${accountId}/gateway/locations`;

  const response = await fetch(url, {
    headers: {
      'Authorization': `Bearer ${apiToken}`,
      'Content-Type': 'application/json',
      'X-Auth-Email': accountEmail,
      'X-Auth-Key': apiToken
    }
  });

  if (response.ok) {
    const data = await response.json();
    const result = data.result;
    return result.length > 0 ? result[0].id : null;
  } else {
    return null;
  }
}

async function updateLocation(accountId, apiToken, locationId, ip, accountEmail) {
  const url = `https://api.cloudflare.com/client/v4/accounts/${accountId}/gateway/locations/${locationId}`;

  const response = await fetch(url, {
    method: 'PUT',
    headers: {
      'Authorization': `Bearer ${apiToken}`,
      'Content-Type': 'application/json',
      'X-Auth-Email': accountEmail,
      'X-Auth-Key': apiToken
    },
    body: JSON.stringify({
      client_default: true,
      ecs_support: true,
      name: 'Home',
      networks: [
        { network: `${ip}/32` }
      ]
    })
  });

  if (response.ok) {
    const data = await response.json();
    return data.result || null;
  } else {
    return null;
  }
}
 

Thống kê chủ đề

Ngày tạo
Fioren,
Người trả lời cuối
tuananhhd88,
Trả lời
4.335
Lượt xem
418.011
Quay lại
Lên đầu trang