ಚಿಕ್ಕ ಮಕ್ಕಳಿಗೆ BPF, ಭಾಗ ಶೂನ್ಯ: ಕ್ಲಾಸಿಕ್ BPF

ಬರ್ಕ್ಲಿ ಪ್ಯಾಕೆಟ್ ಫಿಲ್ಟರ್‌ಗಳು (BPF) ಎಂಬುದು ಲಿನಕ್ಸ್ ಕರ್ನಲ್ ತಂತ್ರಜ್ಞಾನವಾಗಿದ್ದು, ಇದು ಹಲವಾರು ವರ್ಷಗಳಿಂದ ಇಂಗ್ಲಿಷ್ ಭಾಷೆಯ ಟೆಕ್ ಪ್ರಕಟಣೆಗಳ ಮೊದಲ ಪುಟಗಳಲ್ಲಿದೆ. ಸಮ್ಮೇಳನಗಳು BPF ನ ಬಳಕೆ ಮತ್ತು ಅಭಿವೃದ್ಧಿಯ ವರದಿಗಳಿಂದ ತುಂಬಿವೆ. ಲಿನಕ್ಸ್ ನೆಟ್‌ವರ್ಕ್ ಸಬ್‌ಸಿಸ್ಟಮ್ ನಿರ್ವಾಹಕರಾದ ಡೇವಿಡ್ ಮಿಲ್ಲರ್ ಅವರು ಲಿನಕ್ಸ್ ಪ್ಲಂಬರ್ಸ್ 2018 ನಲ್ಲಿ ತಮ್ಮ ಭಾಷಣವನ್ನು ಕರೆಯುತ್ತಾರೆ "ಈ ಮಾತು XDP ಬಗ್ಗೆ ಅಲ್ಲ" (ಬಿಪಿಎಫ್‌ಗೆ ಎಕ್ಸ್‌ಡಿಪಿ ಒಂದು ಬಳಕೆಯ ಸಂದರ್ಭವಾಗಿದೆ). ಬ್ರೆಂಡನ್ ಗ್ರೆಗ್ ಎಂಬ ಶೀರ್ಷಿಕೆಯ ಭಾಷಣಗಳನ್ನು ನೀಡುತ್ತಾನೆ Linux BPF ಸೂಪರ್ ಪವರ್ಸ್. ಟೋಕೆ ಹೋಯ್ಲ್ಯಾಂಡ್-ಜೋರ್ಗೆನ್ಸೆನ್ ನಗುತ್ತಾನೆಕರ್ನಲ್ ಈಗ ಮೈಕ್ರೋಕರ್ನಲ್ ಆಗಿದೆ. ಎಂಬ ಕಲ್ಪನೆಯನ್ನು ಥಾಮಸ್ ಗ್ರಾಫ್ ಉತ್ತೇಜಿಸುತ್ತಾರೆ BPF ಕರ್ನಲ್‌ಗಾಗಿ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಆಗಿದೆ.

Habré ನಲ್ಲಿ ಇನ್ನೂ BPF ನ ಯಾವುದೇ ವ್ಯವಸ್ಥಿತ ವಿವರಣೆಯಿಲ್ಲ, ಮತ್ತು ಆದ್ದರಿಂದ ಲೇಖನಗಳ ಸರಣಿಯಲ್ಲಿ ನಾನು ತಂತ್ರಜ್ಞಾನದ ಇತಿಹಾಸದ ಬಗ್ಗೆ ಮಾತನಾಡಲು ಪ್ರಯತ್ನಿಸುತ್ತೇನೆ, ವಾಸ್ತುಶಿಲ್ಪ ಮತ್ತು ಅಭಿವೃದ್ಧಿ ಸಾಧನಗಳನ್ನು ವಿವರಿಸುತ್ತೇನೆ ಮತ್ತು BPF ಬಳಸುವ ಅಪ್ಲಿಕೇಶನ್ ಮತ್ತು ಅಭ್ಯಾಸದ ಕ್ಷೇತ್ರಗಳನ್ನು ವಿವರಿಸುತ್ತೇನೆ. ಈ ಲೇಖನ, ಶೂನ್ಯ, ಸರಣಿಯಲ್ಲಿ, ಕ್ಲಾಸಿಕ್ BPF ನ ಇತಿಹಾಸ ಮತ್ತು ವಾಸ್ತುಶಿಲ್ಪವನ್ನು ಹೇಳುತ್ತದೆ ಮತ್ತು ಅದರ ಕಾರ್ಯಾಚರಣೆಯ ತತ್ವಗಳ ರಹಸ್ಯಗಳನ್ನು ಸಹ ಬಹಿರಂಗಪಡಿಸುತ್ತದೆ. tcpdump, seccomp, strace, ಮತ್ತು ಹೆಚ್ಚು.

BPF ನ ಅಭಿವೃದ್ಧಿಯು Linux ನೆಟ್‌ವರ್ಕಿಂಗ್ ಸಮುದಾಯದಿಂದ ನಿಯಂತ್ರಿಸಲ್ಪಡುತ್ತದೆ, BPF ನ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪ್ರಮುಖ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ನೆಟ್‌ವರ್ಕ್‌ಗಳಿಗೆ ಸಂಬಂಧಿಸಿವೆ ಮತ್ತು ಆದ್ದರಿಂದ ಅನುಮತಿಯೊಂದಿಗೆ @ಯೂಕಾರಿಯೊಟ್, ಶ್ರೇಷ್ಠ ಸರಣಿಯ ಗೌರವಾರ್ಥವಾಗಿ ನಾನು ಸರಣಿಯನ್ನು "ಚಿಕ್ಕವರಿಗೆ BPF" ಎಂದು ಕರೆದಿದ್ದೇನೆ "ಸಣ್ಣ ಮಕ್ಕಳಿಗಾಗಿ ನೆಟ್‌ವರ್ಕ್‌ಗಳು".

BPF ಇತಿಹಾಸದಲ್ಲಿ ಒಂದು ಸಣ್ಣ ಕೋರ್ಸ್ (c)

ಆಧುನಿಕ BPF ತಂತ್ರಜ್ಞಾನವು ಅದೇ ಹೆಸರಿನ ಹಳೆಯ ತಂತ್ರಜ್ಞಾನದ ಸುಧಾರಿತ ಮತ್ತು ವಿಸ್ತರಿತ ಆವೃತ್ತಿಯಾಗಿದೆ, ಈಗ ಗೊಂದಲವನ್ನು ತಪ್ಪಿಸಲು ಕ್ಲಾಸಿಕ್ BPF ಎಂದು ಕರೆಯಲಾಗುತ್ತದೆ. ಕ್ಲಾಸಿಕ್ BPF ಆಧಾರದ ಮೇಲೆ ಪ್ರಸಿದ್ಧವಾದ ಉಪಯುಕ್ತತೆಯನ್ನು ರಚಿಸಲಾಗಿದೆ tcpdump, ಯಾಂತ್ರಿಕತೆ seccomp, ಹಾಗೆಯೇ ಕಡಿಮೆ ತಿಳಿದಿರುವ ಮಾಡ್ಯೂಲ್‌ಗಳು xt_bpf ಗೆ iptables ಮತ್ತು ವರ್ಗೀಕರಣ cls_bpf. ಆಧುನಿಕ ಲಿನಕ್ಸ್‌ನಲ್ಲಿ, ಕ್ಲಾಸಿಕ್ ಬಿಪಿಎಫ್ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಹೊಸ ರೂಪಕ್ಕೆ ಅನುವಾದಿಸಲಾಗುತ್ತದೆ, ಆದಾಗ್ಯೂ, ಬಳಕೆದಾರರ ದೃಷ್ಟಿಕೋನದಿಂದ, ಎಪಿಐ ಸ್ಥಳದಲ್ಲಿಯೇ ಉಳಿದಿದೆ ಮತ್ತು ಕ್ಲಾಸಿಕ್ ಬಿಪಿಎಫ್‌ಗಾಗಿ ಹೊಸ ಬಳಕೆಗಳು, ನಾವು ಈ ಲೇಖನದಲ್ಲಿ ನೋಡುವಂತೆ, ಇನ್ನೂ ಕಂಡುಬಂದಿವೆ. ಈ ಕಾರಣಕ್ಕಾಗಿ, ಮತ್ತು ಲಿನಕ್ಸ್‌ನಲ್ಲಿ ಕ್ಲಾಸಿಕಲ್ ಬಿಪಿಎಫ್ ಅಭಿವೃದ್ಧಿಯ ಇತಿಹಾಸವನ್ನು ಅನುಸರಿಸಿ, ಅದು ಹೇಗೆ ಮತ್ತು ಏಕೆ ಅದರ ಆಧುನಿಕ ರೂಪಕ್ಕೆ ವಿಕಸನಗೊಂಡಿತು ಎಂಬುದು ಸ್ಪಷ್ಟವಾಗುತ್ತದೆ, ನಾನು ಕ್ಲಾಸಿಕಲ್ ಬಿಪಿಎಫ್ ಬಗ್ಗೆ ಲೇಖನವನ್ನು ಪ್ರಾರಂಭಿಸಲು ನಿರ್ಧರಿಸಿದೆ.

ಕಳೆದ ಶತಮಾನದ ಎಂಬತ್ತರ ದಶಕದ ಕೊನೆಯಲ್ಲಿ, ಪ್ರಸಿದ್ಧ ಲಾರೆನ್ಸ್ ಬರ್ಕ್ಲಿ ಪ್ರಯೋಗಾಲಯದ ಎಂಜಿನಿಯರ್‌ಗಳು ಕಳೆದ ಶತಮಾನದ ಎಂಭತ್ತರ ದಶಕದ ಉತ್ತರಾರ್ಧದಲ್ಲಿ ಆಧುನಿಕವಾಗಿದ್ದ ಹಾರ್ಡ್‌ವೇರ್‌ನಲ್ಲಿ ನೆಟ್ವರ್ಕ್ ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಸರಿಯಾಗಿ ಫಿಲ್ಟರ್ ಮಾಡುವುದು ಹೇಗೆ ಎಂಬ ಪ್ರಶ್ನೆಗೆ ಆಸಕ್ತಿ ವಹಿಸಿದರು. ಸಿಎಸ್‌ಪಿಎಫ್ (ಸಿಎಂಯು/ಸ್ಟ್ಯಾನ್‌ಫೋರ್ಡ್ ಪ್ಯಾಕೆಟ್ ಫಿಲ್ಟರ್) ತಂತ್ರಜ್ಞಾನದಲ್ಲಿ ಮೂಲತಃ ಅಳವಡಿಸಲಾದ ಫಿಲ್ಟರಿಂಗ್‌ನ ಮೂಲ ಕಲ್ಪನೆಯು ಅನಗತ್ಯ ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಸಾಧ್ಯವಾದಷ್ಟು ಬೇಗ ಫಿಲ್ಟರ್ ಮಾಡುವುದು, ಅಂದರೆ. ಕರ್ನಲ್ ಜಾಗದಲ್ಲಿ, ಇದು ಅನಗತ್ಯ ಡೇಟಾವನ್ನು ಬಳಕೆದಾರರ ಜಾಗಕ್ಕೆ ನಕಲಿಸುವುದನ್ನು ತಪ್ಪಿಸುತ್ತದೆ. ಕರ್ನಲ್ ಜಾಗದಲ್ಲಿ ಬಳಕೆದಾರ ಕೋಡ್ ಅನ್ನು ಚಲಾಯಿಸಲು ರನ್ಟೈಮ್ ಭದ್ರತೆಯನ್ನು ಒದಗಿಸಲು, ಸ್ಯಾಂಡ್ಬಾಕ್ಸ್ಡ್ ವರ್ಚುವಲ್ ಯಂತ್ರವನ್ನು ಬಳಸಲಾಗಿದೆ.

ಆದಾಗ್ಯೂ, ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಫಿಲ್ಟರ್‌ಗಳಿಗಾಗಿ ವರ್ಚುವಲ್ ಯಂತ್ರಗಳನ್ನು ಸ್ಟಾಕ್-ಆಧಾರಿತ ಯಂತ್ರಗಳಲ್ಲಿ ಚಲಾಯಿಸಲು ವಿನ್ಯಾಸಗೊಳಿಸಲಾಗಿದೆ ಮತ್ತು ಹೊಸ RISC ಯಂತ್ರಗಳಲ್ಲಿ ಪರಿಣಾಮಕಾರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವುದಿಲ್ಲ. ಇದರ ಪರಿಣಾಮವಾಗಿ, ಬರ್ಕ್ಲಿ ಲ್ಯಾಬ್ಸ್‌ನ ಇಂಜಿನಿಯರ್‌ಗಳ ಪ್ರಯತ್ನದ ಮೂಲಕ, ಹೊಸ BPF (ಬರ್ಕ್ಲಿ ಪ್ಯಾಕೆಟ್ ಫಿಲ್ಟರ್‌ಗಳು) ತಂತ್ರಜ್ಞಾನವನ್ನು ಅಭಿವೃದ್ಧಿಪಡಿಸಲಾಯಿತು, ಇದರ ವರ್ಚುವಲ್ ಮೆಷಿನ್ ಆರ್ಕಿಟೆಕ್ಚರ್ ಅನ್ನು Motorola 6502 ಪ್ರೊಸೆಸರ್ ಆಧರಿಸಿ ವಿನ್ಯಾಸಗೊಳಿಸಲಾಗಿದೆ - ಅಂತಹ ಪ್ರಸಿದ್ಧ ಉತ್ಪನ್ನಗಳ ವರ್ಕ್‌ಹಾರ್ಸ್ ಆಪಲ್ II ಅಥವಾ ಎನ್ಇಎಸ್. ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪರಿಹಾರಗಳಿಗೆ ಹೋಲಿಸಿದರೆ ಹೊಸ ವರ್ಚುವಲ್ ಯಂತ್ರವು ಫಿಲ್ಟರ್ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಹತ್ತಾರು ಬಾರಿ ಹೆಚ್ಚಿಸಿದೆ.

BPF ಯಂತ್ರ ವಾಸ್ತುಶಿಲ್ಪ

ಉದಾಹರಣೆಗಳನ್ನು ವಿಶ್ಲೇಷಿಸುವ ಮೂಲಕ ನಾವು ವಾಸ್ತುಶಿಲ್ಪದೊಂದಿಗೆ ಕೆಲಸದ ರೀತಿಯಲ್ಲಿ ಪರಿಚಯ ಮಾಡಿಕೊಳ್ಳುತ್ತೇವೆ. ಆದಾಗ್ಯೂ, ಪ್ರಾರಂಭಿಸಲು, ಯಂತ್ರವು ಎರಡು 32-ಬಿಟ್ ರೆಜಿಸ್ಟರ್‌ಗಳನ್ನು ಬಳಕೆದಾರರಿಗೆ ಪ್ರವೇಶಿಸಬಹುದಾದ ಸಂಚಯಕವನ್ನು ಹೊಂದಿದೆ ಎಂದು ಹೇಳೋಣ. A ಮತ್ತು ಸೂಚ್ಯಂಕ ನೋಂದಣಿ X, 64 ಬೈಟ್‌ಗಳ ಮೆಮೊರಿ (16 ಪದಗಳು), ಬರೆಯಲು ಮತ್ತು ನಂತರದ ಓದುವಿಕೆಗೆ ಲಭ್ಯವಿದೆ, ಮತ್ತು ಈ ವಸ್ತುಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು ಆಜ್ಞೆಗಳ ಸಣ್ಣ ವ್ಯವಸ್ಥೆ. ಷರತ್ತುಬದ್ಧ ಅಭಿವ್ಯಕ್ತಿಗಳನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲು ಜಂಪ್ ಸೂಚನೆಗಳು ಕಾರ್ಯಕ್ರಮಗಳಲ್ಲಿ ಸಹ ಲಭ್ಯವಿವೆ, ಆದರೆ ಕಾರ್ಯಕ್ರಮದ ಸಕಾಲಿಕ ಪೂರ್ಣಗೊಳಿಸುವಿಕೆಯನ್ನು ಖಾತರಿಪಡಿಸಲು, ಜಿಗಿತಗಳನ್ನು ಮಾತ್ರ ಮುಂದಕ್ಕೆ ಮಾಡಬಹುದಾಗಿದೆ, ಅಂದರೆ, ನಿರ್ದಿಷ್ಟವಾಗಿ, ಲೂಪ್ಗಳನ್ನು ರಚಿಸಲು ಇದನ್ನು ನಿಷೇಧಿಸಲಾಗಿದೆ.

ಯಂತ್ರವನ್ನು ಪ್ರಾರಂಭಿಸುವ ಸಾಮಾನ್ಯ ಯೋಜನೆ ಈ ಕೆಳಗಿನಂತಿರುತ್ತದೆ. ಬಳಕೆದಾರರು BPF ಆರ್ಕಿಟೆಕ್ಚರ್‌ಗಾಗಿ ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ರಚಿಸುತ್ತಾರೆ ಮತ್ತು ಬಳಸುತ್ತಾರೆ ಕೆಲವು ಕರ್ನಲ್ ಕಾರ್ಯವಿಧಾನ (ಉದಾಹರಣೆಗೆ ಸಿಸ್ಟಮ್ ಕರೆ), ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಲೋಡ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಸಂಪರ್ಕಿಸುತ್ತದೆ ಕೆಲವರಿಗೆ ಕರ್ನಲ್‌ನಲ್ಲಿ ಈವೆಂಟ್ ಜನರೇಟರ್‌ಗೆ (ಉದಾಹರಣೆಗೆ, ಈವೆಂಟ್ ಎಂದರೆ ನೆಟ್‌ವರ್ಕ್ ಕಾರ್ಡ್‌ನಲ್ಲಿ ಮುಂದಿನ ಪ್ಯಾಕೆಟ್ ಆಗಮನವಾಗಿದೆ). ಈವೆಂಟ್ ಸಂಭವಿಸಿದಾಗ, ಕರ್ನಲ್ ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ರನ್ ಮಾಡುತ್ತದೆ (ಉದಾಹರಣೆಗೆ, ಇಂಟರ್ಪ್ರಿಟರ್ನಲ್ಲಿ), ಮತ್ತು ಯಂತ್ರದ ಮೆಮೊರಿಯು ಅನುರೂಪವಾಗಿದೆ ಕೆಲವರಿಗೆ ಕರ್ನಲ್ ಮೆಮೊರಿ ಪ್ರದೇಶ (ಉದಾಹರಣೆಗೆ, ಒಳಬರುವ ಪ್ಯಾಕೆಟ್ನ ಡೇಟಾ).

ಉದಾಹರಣೆಗಳನ್ನು ನೋಡುವುದನ್ನು ಪ್ರಾರಂಭಿಸಲು ಮೇಲಿನವು ನಮಗೆ ಸಾಕಾಗುತ್ತದೆ: ಅಗತ್ಯವಿರುವಂತೆ ನಾವು ಸಿಸ್ಟಮ್ ಮತ್ತು ಕಮಾಂಡ್ ಸ್ವರೂಪದೊಂದಿಗೆ ಪರಿಚಯ ಮಾಡಿಕೊಳ್ಳುತ್ತೇವೆ. ನೀವು ತಕ್ಷಣ ವರ್ಚುವಲ್ ಯಂತ್ರದ ಕಮಾಂಡ್ ಸಿಸ್ಟಮ್ ಅನ್ನು ಅಧ್ಯಯನ ಮಾಡಲು ಮತ್ತು ಅದರ ಎಲ್ಲಾ ಸಾಮರ್ಥ್ಯಗಳ ಬಗ್ಗೆ ತಿಳಿದುಕೊಳ್ಳಲು ಬಯಸಿದರೆ, ನೀವು ಮೂಲ ಲೇಖನವನ್ನು ಓದಬಹುದು BSD ಪ್ಯಾಕೆಟ್ ಫಿಲ್ಟರ್ ಮತ್ತು/ಅಥವಾ ಫೈಲ್‌ನ ಮೊದಲಾರ್ಧ ಡಾಕ್ಯುಮೆಂಟೇಶನ್/ನೆಟ್ವರ್ಕಿಂಗ್/filter.txt ಕರ್ನಲ್ ದಾಖಲಾತಿಯಿಂದ. ಹೆಚ್ಚುವರಿಯಾಗಿ, ನೀವು ಪ್ರಸ್ತುತಿಯನ್ನು ಅಧ್ಯಯನ ಮಾಡಬಹುದು libpcap: ಪ್ಯಾಕೆಟ್ ಕ್ಯಾಪ್ಚರ್ಗಾಗಿ ಆರ್ಕಿಟೆಕ್ಚರ್ ಮತ್ತು ಆಪ್ಟಿಮೈಸೇಶನ್ ಮೆಥಡಾಲಜಿ, ಇದರಲ್ಲಿ BPF ನ ಲೇಖಕರಲ್ಲಿ ಒಬ್ಬರಾದ McCanne, ಸೃಷ್ಟಿಯ ಇತಿಹಾಸದ ಬಗ್ಗೆ ಮಾತನಾಡುತ್ತಾರೆ libpcap.

ಲಿನಕ್ಸ್‌ನಲ್ಲಿ ಕ್ಲಾಸಿಕ್ ಬಿಪಿಎಫ್ ಬಳಸುವ ಎಲ್ಲಾ ಗಮನಾರ್ಹ ಉದಾಹರಣೆಗಳನ್ನು ಪರಿಗಣಿಸಲು ನಾವು ಈಗ ಮುಂದುವರಿಯುತ್ತೇವೆ: tcpdump (libpcap), ಸೆಕೆಂಪ್, xt_bpf, cls_bpf.

tcpdump

BPF ನ ಅಭಿವೃದ್ಧಿಯನ್ನು ಪ್ಯಾಕೆಟ್ ಫಿಲ್ಟರಿಂಗ್‌ಗಾಗಿ ಮುಂಭಾಗದ ಅಭಿವೃದ್ಧಿಯೊಂದಿಗೆ ಸಮಾನಾಂತರವಾಗಿ ನಡೆಸಲಾಯಿತು - ಪ್ರಸಿದ್ಧ ಉಪಯುಕ್ತತೆ tcpdump. ಮತ್ತು, ಇದು ಅನೇಕ ಆಪರೇಟಿಂಗ್ ಸಿಸ್ಟಂಗಳಲ್ಲಿ ಲಭ್ಯವಿರುವ ಕ್ಲಾಸಿಕ್ BPF ಅನ್ನು ಬಳಸುವ ಅತ್ಯಂತ ಹಳೆಯ ಮತ್ತು ಅತ್ಯಂತ ಪ್ರಸಿದ್ಧ ಉದಾಹರಣೆಯಾಗಿರುವುದರಿಂದ, ನಾವು ಅದರೊಂದಿಗೆ ತಂತ್ರಜ್ಞಾನದ ನಮ್ಮ ಅಧ್ಯಯನವನ್ನು ಪ್ರಾರಂಭಿಸುತ್ತೇವೆ.

(ನಾನು Linux ನಲ್ಲಿ ಈ ಲೇಖನದಲ್ಲಿ ಎಲ್ಲಾ ಉದಾಹರಣೆಗಳನ್ನು ನಡೆಸಿದ್ದೇನೆ 5.6.0-rc6. ಉತ್ತಮ ಓದುವಿಕೆಗಾಗಿ ಕೆಲವು ಆಜ್ಞೆಗಳ ಔಟ್‌ಪುಟ್ ಅನ್ನು ಸಂಪಾದಿಸಲಾಗಿದೆ.)

ಉದಾಹರಣೆ: IPv6 ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಗಮನಿಸುವುದು

ಇಂಟರ್ಫೇಸ್‌ನಲ್ಲಿ ನಾವು ಎಲ್ಲಾ IPv6 ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ನೋಡಲು ಬಯಸುತ್ತೇವೆ ಎಂದು ಊಹಿಸೋಣ eth0. ಇದನ್ನು ಮಾಡಲು, ನಾವು ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಚಲಾಯಿಸಬಹುದು tcpdump ಸರಳ ಫಿಲ್ಟರ್ನೊಂದಿಗೆ ip6:

$ sudo tcpdump -i eth0 ip6

ಹೀಗೆ tcpdump ಫಿಲ್ಟರ್ ಅನ್ನು ಕಂಪೈಲ್ ಮಾಡುತ್ತದೆ ip6 BPF ಆರ್ಕಿಟೆಕ್ಚರ್ ಬೈಟ್‌ಕೋಡ್‌ಗೆ ಮತ್ತು ಅದನ್ನು ಕರ್ನಲ್‌ಗೆ ಕಳುಹಿಸಿ (ವಿಭಾಗದಲ್ಲಿರುವ ವಿವರಗಳನ್ನು ನೋಡಿ Tcpdump: ಲೋಡ್ ಆಗುತ್ತಿದೆ) ಇಂಟರ್ಫೇಸ್ ಮೂಲಕ ಹಾದುಹೋಗುವ ಪ್ರತಿಯೊಂದು ಪ್ಯಾಕೆಟ್‌ಗೆ ಲೋಡ್ ಮಾಡಲಾದ ಫಿಲ್ಟರ್ ಅನ್ನು ರನ್ ಮಾಡಲಾಗುತ್ತದೆ eth0. ಫಿಲ್ಟರ್ ಶೂನ್ಯವಲ್ಲದ ಮೌಲ್ಯವನ್ನು ಹಿಂತಿರುಗಿಸಿದರೆ n, ನಂತರ ವರೆಗೆ n ಪ್ಯಾಕೆಟ್‌ನ ಬೈಟ್‌ಗಳನ್ನು ಬಳಕೆದಾರರ ಜಾಗಕ್ಕೆ ನಕಲಿಸಲಾಗುತ್ತದೆ ಮತ್ತು ನಾವು ಅದನ್ನು ಔಟ್‌ಪುಟ್‌ನಲ್ಲಿ ನೋಡುತ್ತೇವೆ tcpdump.

ಚಿಕ್ಕ ಮಕ್ಕಳಿಗೆ BPF, ಭಾಗ ಶೂನ್ಯ: ಕ್ಲಾಸಿಕ್ BPF

ಕರ್ನಲ್‌ಗೆ ಯಾವ ಬೈಟ್‌ಕೋಡ್ ಕಳುಹಿಸಲಾಗಿದೆ ಎಂಬುದನ್ನು ನಾವು ಸುಲಭವಾಗಿ ಕಂಡುಹಿಡಿಯಬಹುದು ಎಂದು ಅದು ತಿರುಗುತ್ತದೆ tcpdump ಸಹಾಯದಿಂದ tcpdump, ನಾವು ಅದನ್ನು ಆಯ್ಕೆಯೊಂದಿಗೆ ಚಲಾಯಿಸಿದರೆ -d:

$ sudo tcpdump -i eth0 -d ip6
(000) ldh      [12]
(001) jeq      #0x86dd          jt 2    jf 3
(002) ret      #262144
(003) ret      #0

ಶೂನ್ಯ ಸಾಲಿನಲ್ಲಿ ನಾವು ಆಜ್ಞೆಯನ್ನು ಚಲಾಯಿಸುತ್ತೇವೆ ldh [12], ಅಂದರೆ “ಲೋಡ್ ಇನ್ ರಿಜಿಸ್ಟರ್ A ವಿಳಾಸ 16 ರಲ್ಲಿ ಅರ್ಧ ಪದ (12 ಬಿಟ್‌ಗಳು) ಇದೆ ಮತ್ತು ಒಂದೇ ಪ್ರಶ್ನೆಯೆಂದರೆ ನಾವು ಯಾವ ರೀತಿಯ ಸ್ಮರಣೆಯನ್ನು ಸಂಬೋಧಿಸುತ್ತಿದ್ದೇವೆ? ಉತ್ತರ ಅದು x ಪ್ರಾರಂಭವಾಗುತ್ತದೆ (x+1)ವಿಶ್ಲೇಷಿಸಿದ ನೆಟ್‌ವರ್ಕ್ ಪ್ಯಾಕೆಟ್‌ನ ಬೈಟ್. ನಾವು ಎತರ್ನೆಟ್ ಇಂಟರ್ಫೇಸ್ನಿಂದ ಪ್ಯಾಕೆಟ್ಗಳನ್ನು ಓದುತ್ತೇವೆ eth0, ಮತ್ತು ಇದು ಅರ್ಥಪ್ಯಾಕೆಟ್ ಈ ರೀತಿ ಕಾಣುತ್ತದೆ (ಸರಳತೆಗಾಗಿ, ಪ್ಯಾಕೆಟ್‌ನಲ್ಲಿ ಯಾವುದೇ VLAN ಟ್ಯಾಗ್‌ಗಳಿಲ್ಲ ಎಂದು ನಾವು ಭಾವಿಸುತ್ತೇವೆ):

       6              6          2
|Destination MAC|Source MAC|Ether Type|...|

ಆದ್ದರಿಂದ ಆಜ್ಞೆಯನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಿದ ನಂತರ ldh [12] ರಿಜಿಸ್ಟರ್‌ನಲ್ಲಿ A ಒಂದು ಜಾಗ ಇರುತ್ತದೆ Ether Type - ಈ ಎತರ್ನೆಟ್ ಚೌಕಟ್ಟಿನಲ್ಲಿ ರವಾನೆಯಾಗುವ ಪ್ಯಾಕೆಟ್ ಪ್ರಕಾರ. 1 ನೇ ಸಾಲಿನಲ್ಲಿ ನಾವು ರಿಜಿಸ್ಟರ್‌ನ ವಿಷಯಗಳನ್ನು ಹೋಲಿಸುತ್ತೇವೆ A (ಪ್ಯಾಕೇಜ್ ಪ್ರಕಾರ) ಸಿ 0x86dd, ಮತ್ತು ಇದು ಮತ್ತು ಹೊಂದಿವೆ ನಾವು ಆಸಕ್ತಿ ಹೊಂದಿರುವ ಪ್ರಕಾರವು IPv6 ಆಗಿದೆ. 1 ನೇ ಸಾಲಿನಲ್ಲಿ, ಹೋಲಿಕೆ ಆಜ್ಞೆಯ ಜೊತೆಗೆ, ಇನ್ನೂ ಎರಡು ಕಾಲಮ್‌ಗಳಿವೆ - jt 2 и jf 3 - ಹೋಲಿಕೆ ಯಶಸ್ವಿಯಾದರೆ ನೀವು ಹೋಗಬೇಕಾದ ಗುರುತುಗಳು (A == 0x86dd) ಮತ್ತು ವಿಫಲವಾಗಿದೆ. ಆದ್ದರಿಂದ, ಯಶಸ್ವಿ ಪ್ರಕರಣದಲ್ಲಿ (IPv6) ನಾವು 2 ನೇ ಸಾಲಿಗೆ ಹೋಗುತ್ತೇವೆ ಮತ್ತು ವಿಫಲವಾದ ಸಂದರ್ಭದಲ್ಲಿ - 3 ನೇ ಸಾಲಿಗೆ. 3 ನೇ ಸಾಲಿನಲ್ಲಿ ಪ್ರೋಗ್ರಾಂ ಕೋಡ್ 0 ನೊಂದಿಗೆ ಕೊನೆಗೊಳ್ಳುತ್ತದೆ (ಪ್ಯಾಕೆಟ್ ಅನ್ನು ನಕಲಿಸಬೇಡಿ), 2 ನೇ ಸಾಲಿನಲ್ಲಿ ಪ್ರೋಗ್ರಾಂ ಕೋಡ್ನೊಂದಿಗೆ ಕೊನೆಗೊಳ್ಳುತ್ತದೆ 262144 (ನನಗೆ ಗರಿಷ್ಠ 256 ಕಿಲೋಬೈಟ್‌ಗಳ ಪ್ಯಾಕೇಜ್ ಅನ್ನು ನಕಲಿಸಿ).

ಹೆಚ್ಚು ಸಂಕೀರ್ಣವಾದ ಉದಾಹರಣೆ: ನಾವು ಗಮ್ಯಸ್ಥಾನ ಪೋರ್ಟ್ ಮೂಲಕ TCP ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ನೋಡುತ್ತೇವೆ

ಗಮ್ಯಸ್ಥಾನ ಪೋರ್ಟ್ 666 ನೊಂದಿಗೆ ಎಲ್ಲಾ TCP ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ನಕಲಿಸುವ ಫಿಲ್ಟರ್ ಹೇಗಿದೆ ಎಂದು ನೋಡೋಣ. IPv4 ಕೇಸ್ ಸರಳವಾಗಿರುವುದರಿಂದ ನಾವು IPv6 ಕೇಸ್ ಅನ್ನು ಪರಿಗಣಿಸುತ್ತೇವೆ. ಈ ಉದಾಹರಣೆಯನ್ನು ಅಧ್ಯಯನ ಮಾಡಿದ ನಂತರ, ನೀವು IPv6 ಫಿಲ್ಟರ್ ಅನ್ನು ವ್ಯಾಯಾಮವಾಗಿ ಅನ್ವೇಷಿಸಬಹುದು (ip6 and tcp dst port 666) ಮತ್ತು ಸಾಮಾನ್ಯ ಪ್ರಕರಣಕ್ಕೆ ಫಿಲ್ಟರ್ (tcp dst port 666) ಆದ್ದರಿಂದ, ನಾವು ಆಸಕ್ತಿ ಹೊಂದಿರುವ ಫಿಲ್ಟರ್ ಈ ರೀತಿ ಕಾಣುತ್ತದೆ:

$ sudo tcpdump -i eth0 -d ip and tcp dst port 666
(000) ldh      [12]
(001) jeq      #0x800           jt 2    jf 10
(002) ldb      [23]
(003) jeq      #0x6             jt 4    jf 10
(004) ldh      [20]
(005) jset     #0x1fff          jt 10   jf 6
(006) ldxb     4*([14]&0xf)
(007) ldh      [x + 16]
(008) jeq      #0x29a           jt 9    jf 10
(009) ret      #262144
(010) ret      #0

0 ಮತ್ತು 1 ಸಾಲುಗಳು ಏನು ಮಾಡುತ್ತವೆ ಎಂದು ನಮಗೆ ಈಗಾಗಲೇ ತಿಳಿದಿದೆ. 2 ನೇ ಸಾಲಿನಲ್ಲಿ ಇದು IPv4 ಪ್ಯಾಕೆಟ್ ಎಂದು ನಾವು ಈಗಾಗಲೇ ಪರಿಶೀಲಿಸಿದ್ದೇವೆ (ಈಥರ್ ಟೈಪ್ = 0x800) ಮತ್ತು ಅದನ್ನು ರಿಜಿಸ್ಟರ್‌ಗೆ ಲೋಡ್ ಮಾಡಿ A ಪ್ಯಾಕೆಟ್ನ 24 ನೇ ಬೈಟ್. ನಮ್ಮ ಪ್ಯಾಕೇಜ್ ತೋರುತ್ತಿದೆ

       14            8      1     1
|ethernet header|ip fields|ttl|protocol|...|

ಅಂದರೆ ನಾವು ರಿಜಿಸ್ಟರ್‌ಗೆ ಲೋಡ್ ಮಾಡುತ್ತೇವೆ A ಐಪಿ ಹೆಡರ್‌ನ ಪ್ರೋಟೋಕಾಲ್ ಕ್ಷೇತ್ರ, ಇದು ತಾರ್ಕಿಕವಾಗಿದೆ, ಏಕೆಂದರೆ ನಾವು TCP ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಮಾತ್ರ ನಕಲಿಸಲು ಬಯಸುತ್ತೇವೆ. ನಾವು ಪ್ರೋಟೋಕಾಲ್ ಅನ್ನು ಹೋಲಿಸುತ್ತೇವೆ 0x6 (IPPROTO_TCP3 ನೇ ಸಾಲಿನಲ್ಲಿ.

4 ಮತ್ತು 5 ನೇ ಸಾಲುಗಳಲ್ಲಿ ನಾವು ವಿಳಾಸ 20 ರಲ್ಲಿ ಇರುವ ಅರ್ಧ ಪದಗಳನ್ನು ಲೋಡ್ ಮಾಡುತ್ತೇವೆ ಮತ್ತು ಆಜ್ಞೆಯನ್ನು ಬಳಸುತ್ತೇವೆ jset ಮೂರರಲ್ಲಿ ಒಂದನ್ನು ಹೊಂದಿಸಲಾಗಿದೆಯೇ ಎಂದು ಪರಿಶೀಲಿಸಿ ಧ್ವಜಗಳು - ನೀಡಿದ ಮಾಸ್ಕ್ ಧರಿಸಿ jset ಮೂರು ಪ್ರಮುಖ ಬಿಟ್‌ಗಳನ್ನು ತೆರವುಗೊಳಿಸಲಾಗಿದೆ. ಮೂರು ಬಿಟ್‌ಗಳಲ್ಲಿ ಎರಡು ಪ್ಯಾಕೆಟ್ ವಿಘಟಿತ ಐಪಿ ಪ್ಯಾಕೆಟ್‌ನ ಭಾಗವಾಗಿದೆಯೇ ಮತ್ತು ಹಾಗಿದ್ದಲ್ಲಿ, ಅದು ಕೊನೆಯ ತುಣುಕಾಗಿದೆಯೇ ಎಂದು ನಮಗೆ ತಿಳಿಸುತ್ತದೆ. ಮೂರನೇ ಬಿಟ್ ಕಾಯ್ದಿರಿಸಲಾಗಿದೆ ಮತ್ತು ಶೂನ್ಯವಾಗಿರಬೇಕು. ನಾವು ಅಪೂರ್ಣ ಅಥವಾ ಮುರಿದ ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಲು ಬಯಸುವುದಿಲ್ಲ, ಆದ್ದರಿಂದ ನಾವು ಎಲ್ಲಾ ಮೂರು ಬಿಟ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸುತ್ತೇವೆ.

ಈ ಪಟ್ಟಿಯಲ್ಲಿ 6 ನೇ ಸಾಲು ಅತ್ಯಂತ ಆಸಕ್ತಿದಾಯಕವಾಗಿದೆ. ಅಭಿವ್ಯಕ್ತಿ ldxb 4*([14]&0xf) ನಾವು ರಿಜಿಸ್ಟರ್‌ಗೆ ಲೋಡ್ ಮಾಡುತ್ತೇವೆ ಎಂದರ್ಥ X ಪ್ಯಾಕೆಟ್‌ನ ಹದಿನೈದನೇ ಬೈಟ್‌ನ ಕನಿಷ್ಠ ಗಮನಾರ್ಹ ನಾಲ್ಕು ಬಿಟ್‌ಗಳು 4 ರಿಂದ ಗುಣಿಸಿದಾಗ. ಹದಿನೈದನೇ ಬೈಟ್‌ನ ಕನಿಷ್ಠ ಗಮನಾರ್ಹ ನಾಲ್ಕು ಬಿಟ್‌ಗಳು ಕ್ಷೇತ್ರವಾಗಿದೆ ಇಂಟರ್ನೆಟ್ ಹೆಡರ್ ಉದ್ದ IPv4 ಹೆಡರ್, ಇದು ಹೆಡರ್‌ನ ಉದ್ದವನ್ನು ಪದಗಳಲ್ಲಿ ಸಂಗ್ರಹಿಸುತ್ತದೆ, ಆದ್ದರಿಂದ ನೀವು ನಂತರ 4 ರಿಂದ ಗುಣಿಸಬೇಕಾಗುತ್ತದೆ. ಕುತೂಹಲಕಾರಿಯಾಗಿ, ಅಭಿವ್ಯಕ್ತಿ 4*([14]&0xf) ಈ ಫಾರ್ಮ್‌ನಲ್ಲಿ ಮಾತ್ರ ಬಳಸಬಹುದಾದ ಮತ್ತು ರಿಜಿಸ್ಟರ್‌ಗಾಗಿ ಮಾತ್ರ ವಿಶೇಷ ವಿಳಾಸ ಯೋಜನೆಗೆ ಪದನಾಮವಾಗಿದೆ X, ಅಂದರೆ ನಾವೂ ಹೇಳಲು ಸಾಧ್ಯವಿಲ್ಲ ldb 4*([14]&0xf) ಅಲ್ಲ ldxb 5*([14]&0xf) (ನಾವು ಬೇರೆ ಆಫ್‌ಸೆಟ್ ಅನ್ನು ಮಾತ್ರ ನಿರ್ದಿಷ್ಟಪಡಿಸಬಹುದು, ಉದಾಹರಣೆಗೆ, ldxb 4*([16]&0xf)) ಸ್ವೀಕರಿಸಲು ನಿಖರವಾಗಿ ಈ ವಿಳಾಸ ಯೋಜನೆಯನ್ನು BPF ಗೆ ಸೇರಿಸಲಾಗಿದೆ ಎಂಬುದು ಸ್ಪಷ್ಟವಾಗಿದೆ X (ಸೂಚ್ಯಂಕ ರಿಜಿಸ್ಟರ್) IPv4 ಹೆಡರ್ ಉದ್ದ.

ಆದ್ದರಿಂದ 7 ನೇ ಸಾಲಿನಲ್ಲಿ ನಾವು ಅರ್ಧ ಪದವನ್ನು ಲೋಡ್ ಮಾಡಲು ಪ್ರಯತ್ನಿಸುತ್ತೇವೆ (X+16). 14 ಬೈಟ್‌ಗಳನ್ನು ಈಥರ್ನೆಟ್ ಹೆಡರ್ ಆಕ್ರಮಿಸಿಕೊಂಡಿದೆ ಎಂದು ನೆನಪಿಸಿಕೊಳ್ಳುವುದು, ಮತ್ತು X IPv4 ಹೆಡರ್‌ನ ಉದ್ದವನ್ನು ಒಳಗೊಂಡಿದೆ, ನಾವು ಅದನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುತ್ತೇವೆ A TCP ಗಮ್ಯಸ್ಥಾನ ಪೋರ್ಟ್ ಅನ್ನು ಲೋಡ್ ಮಾಡಲಾಗಿದೆ:

       14           X           2             2
|ethernet header|ip header|source port|destination port|

ಅಂತಿಮವಾಗಿ, 8 ನೇ ಸಾಲಿನಲ್ಲಿ ನಾವು ಗಮ್ಯಸ್ಥಾನದ ಪೋರ್ಟ್ ಅನ್ನು ಅಪೇಕ್ಷಿತ ಮೌಲ್ಯದೊಂದಿಗೆ ಹೋಲಿಸುತ್ತೇವೆ ಮತ್ತು 9 ಅಥವಾ 10 ಸಾಲುಗಳಲ್ಲಿ ನಾವು ಫಲಿತಾಂಶವನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತೇವೆ - ಪ್ಯಾಕೆಟ್ ಅನ್ನು ನಕಲಿಸಬೇಕೆ ಅಥವಾ ಬೇಡವೇ.

Tcpdump: ಲೋಡ್ ಆಗುತ್ತಿದೆ

ಹಿಂದಿನ ಉದಾಹರಣೆಗಳಲ್ಲಿ, ಪ್ಯಾಕೆಟ್ ಫಿಲ್ಟರಿಂಗ್‌ಗಾಗಿ ನಾವು BPF ಬೈಟ್‌ಕೋಡ್ ಅನ್ನು ಕರ್ನಲ್‌ಗೆ ಹೇಗೆ ಲೋಡ್ ಮಾಡುತ್ತೇವೆ ಎಂಬುದರ ಕುರಿತು ನಾವು ನಿರ್ದಿಷ್ಟವಾಗಿ ವಿವರವಾಗಿ ವಾಸಿಸುವುದಿಲ್ಲ. ಸಾಮಾನ್ಯವಾಗಿ ಹೇಳುವುದಾದರೆ, tcpdump ಅನೇಕ ವ್ಯವಸ್ಥೆಗಳಿಗೆ ಮತ್ತು ಫಿಲ್ಟರ್‌ಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು ಪೋರ್ಟ್ ಮಾಡಲಾಗಿದೆ tcpdump ಗ್ರಂಥಾಲಯವನ್ನು ಬಳಸುತ್ತದೆ libpcap. ಸಂಕ್ಷಿಪ್ತವಾಗಿ, ಬಳಸಿ ಇಂಟರ್ಫೇಸ್ನಲ್ಲಿ ಫಿಲ್ಟರ್ ಅನ್ನು ಇರಿಸಲು libpcap, ನೀವು ಈ ಕೆಳಗಿನವುಗಳನ್ನು ಮಾಡಬೇಕಾಗಿದೆ:

  • ಒಂದು ರೀತಿಯ ವಿವರಣೆಯನ್ನು ರಚಿಸಿ pcap_t ಇಂಟರ್ಫೇಸ್ ಹೆಸರಿನಿಂದ: pcap_create,
  • ಇಂಟರ್ಫೇಸ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ: pcap_activate,
  • ಕಂಪೈಲ್ ಫಿಲ್ಟರ್: pcap_compile,
  • ಸಂಪರ್ಕ ಫಿಲ್ಟರ್: pcap_setfilter.

ಕಾರ್ಯ ಹೇಗಿದೆ ಎಂಬುದನ್ನು ನೋಡಲು pcap_setfilter ಲಿನಕ್ಸ್‌ನಲ್ಲಿ ಅಳವಡಿಸಲಾಗಿದೆ, ನಾವು ಬಳಸುತ್ತೇವೆ strace (ಕೆಲವು ಸಾಲುಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ):

$ sudo strace -f -e trace=%network tcpdump -p -i eth0 ip
socket(AF_PACKET, SOCK_RAW, 768)        = 3
bind(3, {sa_family=AF_PACKET, sll_protocol=htons(ETH_P_ALL), sll_ifindex=if_nametoindex("eth0"), sll_hatype=ARPHRD_NETROM, sll_pkttype=PACKET_HOST, sll_halen=0}, 20) = 0
setsockopt(3, SOL_SOCKET, SO_ATTACH_FILTER, {len=4, filter=0xb00bb00bb00b}, 16) = 0
...

ಔಟ್ಪುಟ್ನ ಮೊದಲ ಎರಡು ಸಾಲುಗಳಲ್ಲಿ ನಾವು ರಚಿಸುತ್ತೇವೆ ಕಚ್ಚಾ ಸಾಕೆಟ್ ಎಲ್ಲಾ ಎತರ್ನೆಟ್ ಚೌಕಟ್ಟುಗಳನ್ನು ಓದಲು ಮತ್ತು ಇಂಟರ್ಫೇಸ್ಗೆ ಬಂಧಿಸಲು eth0. ಆಫ್ ನಮ್ಮ ಮೊದಲ ಉದಾಹರಣೆ ಫಿಲ್ಟರ್ ಎಂದು ನಮಗೆ ತಿಳಿದಿದೆ ip ನಾಲ್ಕು BPF ಸೂಚನೆಗಳನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ ಮತ್ತು ಮೂರನೇ ಸಾಲಿನಲ್ಲಿ ನಾವು ಆಯ್ಕೆಯನ್ನು ಹೇಗೆ ಬಳಸುತ್ತೇವೆ ಎಂಬುದನ್ನು ನೋಡುತ್ತೇವೆ SO_ATTACH_FILTER ಸಿಸ್ಟಮ್ ಕರೆ setsockopt ನಾವು 4 ಉದ್ದದ ಫಿಲ್ಟರ್ ಅನ್ನು ಲೋಡ್ ಮಾಡುತ್ತೇವೆ ಮತ್ತು ಸಂಪರ್ಕಿಸುತ್ತೇವೆ. ಇದು ನಮ್ಮ ಫಿಲ್ಟರ್ ಆಗಿದೆ.

ಕ್ಲಾಸಿಕ್ ಬಿಪಿಎಫ್‌ನಲ್ಲಿ, ಫಿಲ್ಟರ್ ಅನ್ನು ಲೋಡ್ ಮಾಡುವುದು ಮತ್ತು ಸಂಪರ್ಕಿಸುವುದು ಯಾವಾಗಲೂ ಪರಮಾಣು ಕಾರ್ಯಾಚರಣೆಯಾಗಿ ಸಂಭವಿಸುತ್ತದೆ ಮತ್ತು ಬಿಪಿಎಫ್‌ನ ಹೊಸ ಆವೃತ್ತಿಯಲ್ಲಿ, ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಲೋಡ್ ಮಾಡುವುದು ಮತ್ತು ಅದನ್ನು ಈವೆಂಟ್ ಜನರೇಟರ್‌ಗೆ ಬಂಧಿಸುವುದು ಸಮಯಕ್ಕೆ ಪ್ರತ್ಯೇಕಿಸಲ್ಪಟ್ಟಿದೆ ಎಂದು ಗಮನಿಸಬೇಕಾದ ಅಂಶವಾಗಿದೆ.

ಗುಪ್ತ ಸತ್ಯ

ಔಟ್ಪುಟ್ನ ಸ್ವಲ್ಪ ಹೆಚ್ಚು ಸಂಪೂರ್ಣ ಆವೃತ್ತಿಯು ಈ ರೀತಿ ಕಾಣುತ್ತದೆ:

$ sudo strace -f -e trace=%network tcpdump -p -i eth0 ip
socket(AF_PACKET, SOCK_RAW, 768)        = 3
bind(3, {sa_family=AF_PACKET, sll_protocol=htons(ETH_P_ALL), sll_ifindex=if_nametoindex("eth0"), sll_hatype=ARPHRD_NETROM, sll_pkttype=PACKET_HOST, sll_halen=0}, 20) = 0
setsockopt(3, SOL_SOCKET, SO_ATTACH_FILTER, {len=1, filter=0xbeefbeefbeef}, 16) = 0
recvfrom(3, 0x7ffcad394257, 1, MSG_TRUNC, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
setsockopt(3, SOL_SOCKET, SO_ATTACH_FILTER, {len=4, filter=0xb00bb00bb00b}, 16) = 0
...

ಮೇಲೆ ಹೇಳಿದಂತೆ, ನಾವು ನಮ್ಮ ಫಿಲ್ಟರ್ ಅನ್ನು 5 ನೇ ಸಾಲಿನಲ್ಲಿ ಸಾಕೆಟ್‌ಗೆ ಲೋಡ್ ಮಾಡುತ್ತೇವೆ ಮತ್ತು ಸಂಪರ್ಕಿಸುತ್ತೇವೆ, ಆದರೆ 3 ಮತ್ತು 4 ಸಾಲುಗಳಲ್ಲಿ ಏನಾಗುತ್ತದೆ? ಇದು ಎಂದು ತಿರುಗುತ್ತದೆ libpcap ನಮ್ಮನ್ನು ನೋಡಿಕೊಳ್ಳುತ್ತದೆ - ಆದ್ದರಿಂದ ನಮ್ಮ ಫಿಲ್ಟರ್‌ನ ಔಟ್‌ಪುಟ್ ಅದನ್ನು ಪೂರೈಸದ ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಿರುವುದಿಲ್ಲ, ಲೈಬ್ರರಿ ಸಂಪರ್ಕಿಸುತ್ತದೆ ನಕಲಿ ಫಿಲ್ಟರ್ ret #0 (ಎಲ್ಲಾ ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಬಿಡಿ), ಸಾಕೆಟ್ ಅನ್ನು ತಡೆರಹಿತ ಮೋಡ್‌ಗೆ ಬದಲಾಯಿಸುತ್ತದೆ ಮತ್ತು ಹಿಂದಿನ ಫಿಲ್ಟರ್‌ಗಳಿಂದ ಉಳಿಯಬಹುದಾದ ಎಲ್ಲಾ ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಕಳೆಯಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ.

ಒಟ್ಟಾರೆಯಾಗಿ, ಕ್ಲಾಸಿಕ್ BPF ಅನ್ನು ಬಳಸಿಕೊಂಡು Linux ನಲ್ಲಿ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಫಿಲ್ಟರ್ ಮಾಡಲು, ನೀವು ರಚನೆಯ ರೂಪದಲ್ಲಿ ಫಿಲ್ಟರ್ ಅನ್ನು ಹೊಂದಿರಬೇಕು struct sock_fprog ಮತ್ತು ತೆರೆದ ಸಾಕೆಟ್, ಅದರ ನಂತರ ಫಿಲ್ಟರ್ ಅನ್ನು ಸಿಸ್ಟಮ್ ಕರೆಯನ್ನು ಬಳಸಿಕೊಂಡು ಸಾಕೆಟ್ಗೆ ಜೋಡಿಸಬಹುದು setsockopt.

ಕುತೂಹಲಕಾರಿಯಾಗಿ, ಫಿಲ್ಟರ್ ಅನ್ನು ಕಚ್ಚಾ ಮಾತ್ರವಲ್ಲದೆ ಯಾವುದೇ ಸಾಕೆಟ್ಗೆ ಜೋಡಿಸಬಹುದು. ಇಲ್ಲಿ ಉದಾಹರಣೆ ಎಲ್ಲಾ ಒಳಬರುವ UDP ಡೇಟಾಗ್ರಾಮ್‌ಗಳಿಂದ ಮೊದಲ ಎರಡು ಬೈಟ್‌ಗಳನ್ನು ಹೊರತುಪಡಿಸಿ ಎಲ್ಲವನ್ನೂ ಕತ್ತರಿಸುವ ಪ್ರೋಗ್ರಾಂ. (ಲೇಖನವನ್ನು ಅಸ್ತವ್ಯಸ್ತಗೊಳಿಸದಂತೆ ನಾನು ಕೋಡ್‌ನಲ್ಲಿ ಕಾಮೆಂಟ್‌ಗಳನ್ನು ಸೇರಿಸಿದ್ದೇನೆ.)

ಬಳಕೆಯ ಕುರಿತು ಹೆಚ್ಚಿನ ವಿವರಗಳು setsockopt ಫಿಲ್ಟರ್ಗಳನ್ನು ಸಂಪರ್ಕಿಸಲು, ನೋಡಿ ಸಾಕೆಟ್ (7), ಆದರೆ ನಿಮ್ಮ ಸ್ವಂತ ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಬರೆಯುವ ಬಗ್ಗೆ struct sock_fprog ಸಹಾಯವಿಲ್ಲದೆ tcpdump ನಾವು ವಿಭಾಗದಲ್ಲಿ ಮಾತನಾಡುತ್ತೇವೆ ನಮ್ಮ ಸ್ವಂತ ಕೈಗಳಿಂದ BPF ಅನ್ನು ಪ್ರೋಗ್ರಾಮಿಂಗ್ ಮಾಡುವುದು.

ಕ್ಲಾಸಿಕ್ BPF ಮತ್ತು 21 ನೇ ಶತಮಾನ

BPF ಅನ್ನು 1997 ರಲ್ಲಿ ಲಿನಕ್ಸ್‌ನಲ್ಲಿ ಸೇರಿಸಲಾಯಿತು ಮತ್ತು ದೀರ್ಘಕಾಲದವರೆಗೆ ಕೆಲಸಗಾರನಾಗಿ ಉಳಿದಿದೆ libpcap ಯಾವುದೇ ವಿಶೇಷ ಬದಲಾವಣೆಗಳಿಲ್ಲದೆ (ಲಿನಕ್ಸ್-ನಿರ್ದಿಷ್ಟ ಬದಲಾವಣೆಗಳು, ಸಹಜವಾಗಿ, ಇದು, ಆದರೆ ಅವರು ಜಾಗತಿಕ ಚಿತ್ರವನ್ನು ಬದಲಾಯಿಸಲಿಲ್ಲ). ಬಿಪಿಎಫ್ ವಿಕಸನಗೊಳ್ಳುವ ಮೊದಲ ಗಂಭೀರ ಚಿಹ್ನೆಗಳು 2011 ರಲ್ಲಿ ಎರಿಕ್ ಡುಮಾಜೆಟ್ ಪ್ರಸ್ತಾಪಿಸಿದಾಗ ಬಂದವು ಪ್ಯಾಚ್, ಇದು ಜಸ್ಟ್ ಇನ್ ಟೈಮ್ ಕಂಪೈಲರ್ ಅನ್ನು ಕರ್ನಲ್‌ಗೆ ಸೇರಿಸುತ್ತದೆ - BPF ಬೈಟ್‌ಕೋಡ್ ಅನ್ನು ಸ್ಥಳೀಯಕ್ಕೆ ಪರಿವರ್ತಿಸಲು ಅನುವಾದಕ x86_64 ಕೋಡ್.

JIT ಕಂಪೈಲರ್ ಬದಲಾವಣೆಗಳ ಸರಪಳಿಯಲ್ಲಿ ಮೊದಲನೆಯದು: 2012 ರಲ್ಲಿ ಕಂಡ ಫಿಲ್ಟರ್ಗಳನ್ನು ಬರೆಯುವ ಸಾಮರ್ಥ್ಯ ಸೆಕಾಂಪ್, BPF ಬಳಸಿಕೊಂಡು, ಜನವರಿ 2013 ರಲ್ಲಿ ಇತ್ತು ಸೇರಿಸಲಾಗಿದೆ ಮಾಡ್ಯೂಲ್ xt_bpf, ಇದು ನಿಮಗೆ ನಿಯಮಗಳನ್ನು ಬರೆಯಲು ಅನುವು ಮಾಡಿಕೊಡುತ್ತದೆ iptables BPF ಸಹಾಯದಿಂದ, ಮತ್ತು ಅಕ್ಟೋಬರ್ 2013 ರಲ್ಲಿ ಸೇರಿಸಲಾಗಿದೆ ಮಾಡ್ಯೂಲ್ ಕೂಡ cls_bpf, ಇದು BPF ಅನ್ನು ಬಳಸಿಕೊಂಡು ಟ್ರಾಫಿಕ್ ವರ್ಗೀಕರಣಗಳನ್ನು ಬರೆಯಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ.

ಈ ಎಲ್ಲಾ ಉದಾಹರಣೆಗಳನ್ನು ನಾವು ಶೀಘ್ರದಲ್ಲೇ ಹೆಚ್ಚು ವಿವರವಾಗಿ ನೋಡುತ್ತೇವೆ, ಆದರೆ ಲೈಬ್ರರಿಯಿಂದ ಒದಗಿಸಲಾದ ಸಾಮರ್ಥ್ಯಗಳಿಂದ BPF ಗಾಗಿ ಅನಿಯಂತ್ರಿತ ಕಾರ್ಯಕ್ರಮಗಳನ್ನು ಬರೆಯುವುದು ಮತ್ತು ಕಂಪೈಲ್ ಮಾಡುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಲು ನಮಗೆ ಇದು ಉಪಯುಕ್ತವಾಗಿದೆ. libpcap ಸೀಮಿತ (ಸರಳ ಉದಾಹರಣೆ: ಫಿಲ್ಟರ್ ರಚಿಸಲಾಗಿದೆ libpcap ಕೇವಲ ಎರಡು ಮೌಲ್ಯಗಳನ್ನು ಹಿಂತಿರುಗಿಸಬಹುದು - 0 ಅಥವಾ 0x40000) ಅಥವಾ ಸಾಮಾನ್ಯವಾಗಿ, ಸೆಕ್ಕಾಂಪ್ನ ಸಂದರ್ಭದಲ್ಲಿ, ಅನ್ವಯಿಸುವುದಿಲ್ಲ.

ನಮ್ಮ ಸ್ವಂತ ಕೈಗಳಿಂದ BPF ಅನ್ನು ಪ್ರೋಗ್ರಾಮಿಂಗ್ ಮಾಡುವುದು

BPF ಸೂಚನೆಗಳ ಬೈನರಿ ಸ್ವರೂಪದೊಂದಿಗೆ ಪರಿಚಯ ಮಾಡಿಕೊಳ್ಳೋಣ, ಇದು ತುಂಬಾ ಸರಳವಾಗಿದೆ:

   16    8    8     32
| code | jt | jf |  k  |

ಪ್ರತಿಯೊಂದು ಸೂಚನೆಯು 64 ಬಿಟ್‌ಗಳನ್ನು ಆಕ್ರಮಿಸುತ್ತದೆ, ಇದರಲ್ಲಿ ಮೊದಲ 16 ಬಿಟ್‌ಗಳು ಸೂಚನಾ ಕೋಡ್ ಆಗಿರುತ್ತವೆ, ನಂತರ ಎರಡು ಎಂಟು-ಬಿಟ್ ಇಂಡೆಂಟ್‌ಗಳಿವೆ, jt и jf, ಮತ್ತು ವಾದಕ್ಕಾಗಿ 32 ಬಿಟ್‌ಗಳು K, ಇದರ ಉದ್ದೇಶವು ಆಜ್ಞೆಯಿಂದ ಆಜ್ಞೆಗೆ ಬದಲಾಗುತ್ತದೆ. ಉದಾಹರಣೆಗೆ, ಆಜ್ಞೆ ret, ಇದು ಕೋಡ್ ಅನ್ನು ಹೊಂದಿರುವ ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಕೊನೆಗೊಳಿಸುತ್ತದೆ 6, ಮತ್ತು ರಿಟರ್ನ್ ಮೌಲ್ಯವನ್ನು ಸ್ಥಿರದಿಂದ ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತದೆ K. C ನಲ್ಲಿ, ಒಂದೇ BPF ಸೂಚನೆಯನ್ನು ರಚನೆಯಾಗಿ ಪ್ರತಿನಿಧಿಸಲಾಗುತ್ತದೆ

struct sock_filter {
        __u16   code;
        __u8    jt;
        __u8    jf;
        __u32   k;
}

ಮತ್ತು ಇಡೀ ಪ್ರೋಗ್ರಾಂ ರಚನೆಯ ರೂಪದಲ್ಲಿದೆ

struct sock_fprog {
        unsigned short len;
        struct sock_filter *filter;
}

ಹೀಗಾಗಿ, ನಾವು ಈಗಾಗಲೇ ಕಾರ್ಯಕ್ರಮಗಳನ್ನು ಬರೆಯಬಹುದು (ಉದಾಹರಣೆಗೆ, ನಾವು ಸೂಚನಾ ಕೋಡ್‌ಗಳನ್ನು ತಿಳಿದಿದ್ದೇವೆ [1]) ಫಿಲ್ಟರ್ ಈ ರೀತಿ ಕಾಣಿಸುತ್ತದೆ ip6 ನಿಂದ ನಮ್ಮ ಮೊದಲ ಉದಾಹರಣೆ:

struct sock_filter code[] = {
        { 0x28, 0, 0, 0x0000000c },
        { 0x15, 0, 1, 0x000086dd },
        { 0x06, 0, 0, 0x00040000 },
        { 0x06, 0, 0, 0x00000000 },
};
struct sock_fprog prog = {
        .len = ARRAY_SIZE(code),
        .filter = code,
};

ಕಾರ್ಯಕ್ರಮ prog ನಾವು ಕರೆಯಲ್ಲಿ ಕಾನೂನುಬದ್ಧವಾಗಿ ಬಳಸಬಹುದು

setsockopt(sk, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog))

ಯಂತ್ರ ಸಂಕೇತಗಳ ರೂಪದಲ್ಲಿ ಕಾರ್ಯಕ್ರಮಗಳನ್ನು ಬರೆಯುವುದು ತುಂಬಾ ಅನುಕೂಲಕರವಲ್ಲ, ಆದರೆ ಕೆಲವೊಮ್ಮೆ ಇದು ಅಗತ್ಯವಾಗಿರುತ್ತದೆ (ಉದಾಹರಣೆಗೆ, ಡೀಬಗ್ ಮಾಡಲು, ಯುನಿಟ್ ಪರೀಕ್ಷೆಗಳನ್ನು ರಚಿಸುವುದು, ಹ್ಯಾಬ್ರೆಯಲ್ಲಿ ಲೇಖನಗಳನ್ನು ಬರೆಯುವುದು, ಇತ್ಯಾದಿ). ಅನುಕೂಲಕ್ಕಾಗಿ, ಫೈಲ್ನಲ್ಲಿ <linux/filter.h> ಸಹಾಯಕ ಮ್ಯಾಕ್ರೋಗಳನ್ನು ವ್ಯಾಖ್ಯಾನಿಸಲಾಗಿದೆ - ಮೇಲಿನ ಅದೇ ಉದಾಹರಣೆಯನ್ನು ಪುನಃ ಬರೆಯಬಹುದು

struct sock_filter code[] = {
        BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 12),
        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ETH_P_IPV6, 0, 1),
        BPF_STMT(BPF_RET|BPF_K, 0x00040000),
        BPF_STMT(BPF_RET|BPF_K, 0),
}

ಆದಾಗ್ಯೂ, ಈ ಆಯ್ಕೆಯು ತುಂಬಾ ಅನುಕೂಲಕರವಾಗಿಲ್ಲ. ಲಿನಕ್ಸ್ ಕರ್ನಲ್ ಪ್ರೋಗ್ರಾಮರ್‌ಗಳು ಇದನ್ನು ತರ್ಕಿಸಿದ್ದಾರೆ ಮತ್ತು ಆದ್ದರಿಂದ ಡೈರೆಕ್ಟರಿಯಲ್ಲಿ tools/bpf ಕ್ಲಾಸಿಕ್ BPF ನೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು ನೀವು ಅಸೆಂಬ್ಲರ್ ಮತ್ತು ಡೀಬಗರ್ ಅನ್ನು ಕಾಣಬಹುದು ಕರ್ನಲ್ಗಳು.

ಅಸೆಂಬ್ಲಿ ಭಾಷೆಯು ಡೀಬಗ್ ಔಟ್‌ಪುಟ್‌ಗೆ ಹೋಲುತ್ತದೆ tcpdump, ಆದರೆ ಹೆಚ್ಚುವರಿಯಾಗಿ ನಾವು ಸಾಂಕೇತಿಕ ಲೇಬಲ್‌ಗಳನ್ನು ನಿರ್ದಿಷ್ಟಪಡಿಸಬಹುದು. ಉದಾಹರಣೆಗೆ, TCP/IPv4 ಹೊರತುಪಡಿಸಿ ಎಲ್ಲಾ ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಬೀಳಿಸುವ ಪ್ರೋಗ್ರಾಂ ಇಲ್ಲಿದೆ:

$ cat /tmp/tcp-over-ipv4.bpf
ldh [12]
jne #0x800, drop
ldb [23]
jneq #6, drop
ret #-1
drop: ret #0

ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ, ಅಸೆಂಬ್ಲರ್ ಸ್ವರೂಪದಲ್ಲಿ ಕೋಡ್ ಅನ್ನು ಉತ್ಪಾದಿಸುತ್ತದೆ <количество инструкций>,<code1> <jt1> <jf1> <k1>,..., TCP ಯೊಂದಿಗಿನ ನಮ್ಮ ಉದಾಹರಣೆಗಾಗಿ ಅದು ಇರುತ್ತದೆ

$ tools/bpf/bpf_asm /tmp/tcp-over-ipv4.bpf
6,40 0 0 12,21 0 3 2048,48 0 0 23,21 0 1 6,6 0 0 4294967295,6 0 0 0,

ಸಿ ಪ್ರೋಗ್ರಾಮರ್‌ಗಳ ಅನುಕೂಲಕ್ಕಾಗಿ, ವಿಭಿನ್ನ ಔಟ್‌ಪುಟ್ ಸ್ವರೂಪವನ್ನು ಬಳಸಬಹುದು:

$ tools/bpf/bpf_asm -c /tmp/tcp-over-ipv4.bpf
{ 0x28,  0,  0, 0x0000000c },
{ 0x15,  0,  3, 0x00000800 },
{ 0x30,  0,  0, 0x00000017 },
{ 0x15,  0,  1, 0x00000006 },
{ 0x06,  0,  0, 0xffffffff },
{ 0x06,  0,  0, 0000000000 },

ಈ ಪಠ್ಯವನ್ನು ಪ್ರಕಾರದ ರಚನೆಯ ವ್ಯಾಖ್ಯಾನಕ್ಕೆ ನಕಲಿಸಬಹುದು struct sock_filter, ನಾವು ಈ ವಿಭಾಗದ ಆರಂಭದಲ್ಲಿ ಮಾಡಿದಂತೆ.

Linux ಮತ್ತು netsniff-ng ವಿಸ್ತರಣೆಗಳು

ಪ್ರಮಾಣಿತ BPF ಜೊತೆಗೆ, Linux ಮತ್ತು tools/bpf/bpf_asm ಬೆಂಬಲ ಮತ್ತು ಪ್ರಮಾಣಿತವಲ್ಲದ ಸೆಟ್. ಮೂಲಭೂತವಾಗಿ, ರಚನೆಯ ಕ್ಷೇತ್ರಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ಸೂಚನೆಗಳನ್ನು ಬಳಸಲಾಗುತ್ತದೆ struct sk_buff, ಇದು ಕರ್ನಲ್‌ನಲ್ಲಿ ನೆಟ್‌ವರ್ಕ್ ಪ್ಯಾಕೆಟ್ ಅನ್ನು ವಿವರಿಸುತ್ತದೆ. ಆದಾಗ್ಯೂ, ಇತರ ರೀತಿಯ ಸಹಾಯಕ ಸೂಚನೆಗಳೂ ಇವೆ, ಉದಾಹರಣೆಗೆ ldw cpu ರಿಜಿಸ್ಟರ್‌ಗೆ ಲೋಡ್ ಆಗುತ್ತದೆ A ಕರ್ನಲ್ ಕಾರ್ಯವನ್ನು ಚಲಾಯಿಸುವ ಫಲಿತಾಂಶ raw_smp_processor_id(). (BPF ನ ಹೊಸ ಆವೃತ್ತಿಯಲ್ಲಿ, ಈ ಪ್ರಮಾಣಿತವಲ್ಲದ ವಿಸ್ತರಣೆಗಳನ್ನು ಮೆಮೊರಿ, ರಚನೆಗಳು ಮತ್ತು ಈವೆಂಟ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ಕರ್ನಲ್ ಸಹಾಯಕಗಳ ಗುಂಪಿನೊಂದಿಗೆ ಪ್ರೊಗ್ರಾಮ್‌ಗಳನ್ನು ಒದಗಿಸಲು ವಿಸ್ತರಿಸಲಾಗಿದೆ.) ನಾವು ನಕಲಿಸುವ ಫಿಲ್ಟರ್‌ನ ಆಸಕ್ತಿದಾಯಕ ಉದಾಹರಣೆ ಇಲ್ಲಿದೆ. ವಿಸ್ತರಣೆಯನ್ನು ಬಳಸಿಕೊಂಡು ಬಳಕೆದಾರರ ಜಾಗಕ್ಕೆ ಪ್ಯಾಕೆಟ್ ಹೆಡರ್‌ಗಳು poff, ಪೇಲೋಡ್ ಆಫ್‌ಸೆಟ್:

ld poff
ret a

BPF ವಿಸ್ತರಣೆಗಳನ್ನು ಬಳಸಲಾಗುವುದಿಲ್ಲ tcpdump, ಆದರೆ ಯುಟಿಲಿಟಿ ಪ್ಯಾಕೇಜ್‌ನೊಂದಿಗೆ ಪರಿಚಯ ಮಾಡಿಕೊಳ್ಳಲು ಇದು ಉತ್ತಮ ಕಾರಣವಾಗಿದೆ netsniff-ng, ಇದು ಇತರ ವಿಷಯಗಳ ಜೊತೆಗೆ, ಸುಧಾರಿತ ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಒಳಗೊಂಡಿದೆ netsniff-ng, ಇದು, BPF ಬಳಸಿಕೊಂಡು ಫಿಲ್ಟರಿಂಗ್ ಜೊತೆಗೆ, ಪರಿಣಾಮಕಾರಿ ಟ್ರಾಫಿಕ್ ಜನರೇಟರ್ ಅನ್ನು ಸಹ ಹೊಂದಿದೆ ಮತ್ತು ಹೆಚ್ಚು ಮುಂದುವರಿದಿದೆ tools/bpf/bpf_asm, ಎಂಬ ಬಿಪಿಎಫ್ ಅಸೆಂಬ್ಲರ್ bpfc. ಪ್ಯಾಕೇಜ್ ಸಾಕಷ್ಟು ವಿವರವಾದ ದಸ್ತಾವೇಜನ್ನು ಹೊಂದಿದೆ, ಲೇಖನದ ಕೊನೆಯಲ್ಲಿ ಲಿಂಕ್‌ಗಳನ್ನು ಸಹ ನೋಡಿ.

ಸೆಕಾಂಪ್

ಆದ್ದರಿಂದ, ಅನಿಯಂತ್ರಿತ ಸಂಕೀರ್ಣತೆಯ ಬಿಪಿಎಫ್ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಹೇಗೆ ಬರೆಯುವುದು ಎಂದು ನಮಗೆ ಈಗಾಗಲೇ ತಿಳಿದಿದೆ ಮತ್ತು ಹೊಸ ಉದಾಹರಣೆಗಳನ್ನು ನೋಡಲು ಸಿದ್ಧವಾಗಿದೆ, ಅದರಲ್ಲಿ ಮೊದಲನೆಯದು ಸೆಕಾಂಪ್ ತಂತ್ರಜ್ಞಾನವಾಗಿದೆ, ಇದು ಬಿಪಿಎಫ್ ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಬಳಸಿ, ಸಿಸ್ಟಮ್ ಕರೆ ಆರ್ಗ್ಯುಮೆಂಟ್‌ಗಳ ಸೆಟ್ ಮತ್ತು ಸೆಟ್ ಅನ್ನು ನಿರ್ವಹಿಸಲು ಅನುಮತಿಸುತ್ತದೆ. ನಿರ್ದಿಷ್ಟ ಪ್ರಕ್ರಿಯೆ ಮತ್ತು ಅದರ ವಂಶಸ್ಥರು.

seccomp ನ ಮೊದಲ ಆವೃತ್ತಿಯನ್ನು 2005 ರಲ್ಲಿ ಕರ್ನಲ್‌ಗೆ ಸೇರಿಸಲಾಯಿತು ಮತ್ತು ಅದು ಹೆಚ್ಚು ಜನಪ್ರಿಯವಾಗಿರಲಿಲ್ಲ, ಏಕೆಂದರೆ ಇದು ಒಂದೇ ಒಂದು ಆಯ್ಕೆಯನ್ನು ಒದಗಿಸಿದೆ - ಕೆಳಗಿನ ಪ್ರಕ್ರಿಯೆಗೆ ಲಭ್ಯವಿರುವ ಸಿಸ್ಟಮ್ ಕರೆಗಳ ಸೆಟ್ ಅನ್ನು ಮಿತಿಗೊಳಿಸಲು: read, write, exit и sigreturn, ಮತ್ತು ನಿಯಮಗಳನ್ನು ಉಲ್ಲಂಘಿಸಿದ ಪ್ರಕ್ರಿಯೆಯನ್ನು ಬಳಸಿಕೊಂಡು ಕೊಲ್ಲಲಾಯಿತು SIGKILL. ಆದಾಗ್ಯೂ, 2012 ರಲ್ಲಿ, seccomp BPF ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಬಳಸುವ ಸಾಮರ್ಥ್ಯವನ್ನು ಸೇರಿಸಿತು, ಇದು ಅನುಮತಿಸಲಾದ ಸಿಸ್ಟಮ್ ಕರೆಗಳ ಗುಂಪನ್ನು ವ್ಯಾಖ್ಯಾನಿಸಲು ಮತ್ತು ಅವರ ವಾದಗಳ ಮೇಲೆ ಪರಿಶೀಲನೆಗಳನ್ನು ಮಾಡಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ. (ಆಸಕ್ತಿದಾಯಕವಾಗಿ, ಈ ಕಾರ್ಯಚಟುವಟಿಕೆಯ ಮೊದಲ ಬಳಕೆದಾರರಲ್ಲಿ Chrome ಒಂದಾಗಿದೆ, ಮತ್ತು Chrome ಜನರು ಪ್ರಸ್ತುತ BPF ನ ಹೊಸ ಆವೃತ್ತಿಯನ್ನು ಆಧರಿಸಿ KRSI ಕಾರ್ಯವಿಧಾನವನ್ನು ಅಭಿವೃದ್ಧಿಪಡಿಸುತ್ತಿದ್ದಾರೆ ಮತ್ತು Linux ಭದ್ರತಾ ಮಾಡ್ಯೂಲ್‌ಗಳ ಗ್ರಾಹಕೀಕರಣವನ್ನು ಅನುಮತಿಸುತ್ತಿದ್ದಾರೆ.) ಹೆಚ್ಚುವರಿ ದಾಖಲಾತಿಗೆ ಲಿಂಕ್‌ಗಳನ್ನು ಕೊನೆಯಲ್ಲಿ ಕಾಣಬಹುದು. ಲೇಖನದ.

seccomp ಅನ್ನು ಬಳಸುವ ಕುರಿತು ಹಬ್‌ನಲ್ಲಿ ಈಗಾಗಲೇ ಲೇಖನಗಳಿವೆ ಎಂಬುದನ್ನು ಗಮನಿಸಿ, ಈ ಕೆಳಗಿನ ಉಪವಿಭಾಗಗಳನ್ನು ಓದುವ ಮೊದಲು (ಅಥವಾ ಬದಲಿಗೆ) ಯಾರಾದರೂ ಅವುಗಳನ್ನು ಓದಲು ಬಯಸುತ್ತಾರೆ. ಲೇಖನದಲ್ಲಿ ಕಂಟೈನರ್‌ಗಳು ಮತ್ತು ಭದ್ರತೆ: seccomp seccomp ಅನ್ನು ಬಳಸುವ ಉದಾಹರಣೆಗಳನ್ನು ಒದಗಿಸುತ್ತದೆ, 2007 ರ ಆವೃತ್ತಿ ಮತ್ತು BPF ಅನ್ನು ಬಳಸುವ ಆವೃತ್ತಿ (ಫಿಲ್ಟರ್‌ಗಳನ್ನು libseccomp ಬಳಸಿ ರಚಿಸಲಾಗಿದೆ), ಡಾಕರ್‌ನೊಂದಿಗೆ seccomp ನ ಸಂಪರ್ಕದ ಬಗ್ಗೆ ಮಾತನಾಡುತ್ತದೆ ಮತ್ತು ಅನೇಕ ಉಪಯುಕ್ತ ಲಿಂಕ್‌ಗಳನ್ನು ಸಹ ಒದಗಿಸುತ್ತದೆ. ಲೇಖನದಲ್ಲಿ systemd ನೊಂದಿಗೆ ಡೀಮನ್‌ಗಳನ್ನು ಪ್ರತ್ಯೇಕಿಸುವುದು ಅಥವಾ "ಇದಕ್ಕಾಗಿ ನಿಮಗೆ ಡಾಕರ್ ಅಗತ್ಯವಿಲ್ಲ!" ಇದು ನಿರ್ದಿಷ್ಟವಾಗಿ, ಡೀಮನ್‌ಗಳು ಚಾಲನೆಯಲ್ಲಿರುವ systemd ಗಾಗಿ ಸಿಸ್ಟಮ್ ಕರೆಗಳ ಕಪ್ಪುಪಟ್ಟಿಗಳನ್ನು ಅಥವಾ ವೈಟ್‌ಲಿಸ್ಟ್‌ಗಳನ್ನು ಹೇಗೆ ಸೇರಿಸುವುದು ಎಂಬುದನ್ನು ಒಳಗೊಂಡಿದೆ.

ಮುಂದೆ ನಾವು ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಬರೆಯುವುದು ಮತ್ತು ಲೋಡ್ ಮಾಡುವುದು ಹೇಗೆ ಎಂದು ನೋಡೋಣ seccomp ಬೇರ್ ಸಿ ಮತ್ತು ಲೈಬ್ರರಿಯನ್ನು ಬಳಸಿ libseccomp ಮತ್ತು ಪ್ರತಿ ಆಯ್ಕೆಯ ಸಾಧಕ-ಬಾಧಕಗಳು ಯಾವುವು, ಮತ್ತು ಅಂತಿಮವಾಗಿ, ಪ್ರೋಗ್ರಾಂನಿಂದ seccomp ಅನ್ನು ಹೇಗೆ ಬಳಸಲಾಗುತ್ತದೆ ಎಂದು ನೋಡೋಣ strace.

ಸೆಕ್ಕಾಂಪ್ಗಾಗಿ ಫಿಲ್ಟರ್ಗಳನ್ನು ಬರೆಯುವುದು ಮತ್ತು ಲೋಡ್ ಮಾಡುವುದು

BPF ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಹೇಗೆ ಬರೆಯಬೇಕೆಂದು ನಮಗೆ ಈಗಾಗಲೇ ತಿಳಿದಿದೆ, ಆದ್ದರಿಂದ ನಾವು ಮೊದಲು seccomp ಪ್ರೋಗ್ರಾಮಿಂಗ್ ಇಂಟರ್ಫೇಸ್ ಅನ್ನು ನೋಡೋಣ. ನೀವು ಪ್ರಕ್ರಿಯೆಯ ಮಟ್ಟದಲ್ಲಿ ಫಿಲ್ಟರ್ ಅನ್ನು ಹೊಂದಿಸಬಹುದು ಮತ್ತು ಎಲ್ಲಾ ಮಕ್ಕಳ ಪ್ರಕ್ರಿಯೆಗಳು ನಿರ್ಬಂಧಗಳನ್ನು ಪಡೆದುಕೊಳ್ಳುತ್ತವೆ. ಸಿಸ್ಟಮ್ ಕರೆಯನ್ನು ಬಳಸಿಕೊಂಡು ಇದನ್ನು ಮಾಡಲಾಗುತ್ತದೆ seccomp(2):

seccomp(SECCOMP_SET_MODE_FILTER, flags, &filter)

ಅಲ್ಲಿ &filter - ಇದು ನಮಗೆ ಈಗಾಗಲೇ ಪರಿಚಿತವಾಗಿರುವ ರಚನೆಯ ಪಾಯಿಂಟರ್ ಆಗಿದೆ struct sock_fprog, ಅಂದರೆ BPF ಕಾರ್ಯಕ್ರಮ.

seccomp ಗಾಗಿ ಪ್ರೋಗ್ರಾಂಗಳು ಸಾಕೆಟ್‌ಗಳಿಗಾಗಿ ಪ್ರೋಗ್ರಾಂಗಳಿಂದ ಹೇಗೆ ಭಿನ್ನವಾಗಿವೆ? ಪ್ರಸರಣ ಸಂದರ್ಭ. ಸಾಕೆಟ್‌ಗಳ ಸಂದರ್ಭದಲ್ಲಿ, ನಮಗೆ ಪ್ಯಾಕೆಟ್ ಹೊಂದಿರುವ ಮೆಮೊರಿ ಪ್ರದೇಶವನ್ನು ನೀಡಲಾಗಿದೆ ಮತ್ತು ಸೆಕಾಂಪ್‌ನ ಸಂದರ್ಭದಲ್ಲಿ ನಮಗೆ ಈ ರೀತಿಯ ರಚನೆಯನ್ನು ನೀಡಲಾಗಿದೆ

struct seccomp_data {
    int   nr;
    __u32 arch;
    __u64 instruction_pointer;
    __u64 args[6];
};

ಇದು nr ಪ್ರಾರಂಭಿಸಬೇಕಾದ ಸಿಸ್ಟಂ ಕರೆ ಸಂಖ್ಯೆ, arch - ಪ್ರಸ್ತುತ ವಾಸ್ತುಶೈಲಿ (ಇದರ ಬಗ್ಗೆ ಇನ್ನಷ್ಟು ಕೆಳಗೆ), args - ಆರು ಸಿಸ್ಟಮ್ ಕರೆ ಆರ್ಗ್ಯುಮೆಂಟ್‌ಗಳು, ಮತ್ತು instruction_pointer ಸಿಸ್ಟಂ ಕರೆ ಮಾಡಿದ ಬಳಕೆದಾರರ ಸ್ಥಳ ಸೂಚನೆಗೆ ಪಾಯಿಂಟರ್ ಆಗಿದೆ. ಹೀಗಾಗಿ, ಉದಾಹರಣೆಗೆ, ಸಿಸ್ಟಮ್ ಕರೆ ಸಂಖ್ಯೆಯನ್ನು ರಿಜಿಸ್ಟರ್ಗೆ ಲೋಡ್ ಮಾಡಲು A ನಾವು ಹೇಳಬೇಕು

ldw [0]

seccomp ಪ್ರೋಗ್ರಾಂಗಳಿಗಾಗಿ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳಿವೆ, ಉದಾಹರಣೆಗೆ, ಸಂದರ್ಭವನ್ನು 32-ಬಿಟ್ ಜೋಡಣೆಯಿಂದ ಮಾತ್ರ ಪ್ರವೇಶಿಸಬಹುದು ಮತ್ತು ನೀವು ಅರ್ಧ ಪದ ಅಥವಾ ಬೈಟ್ ಅನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ - ಫಿಲ್ಟರ್ ಅನ್ನು ಲೋಡ್ ಮಾಡಲು ಪ್ರಯತ್ನಿಸುವಾಗ ldh [0] ಸಿಸ್ಟಮ್ ಕರೆ seccomp ಹಿಂತಿರುಗುತ್ತಾರೆ EINVAL. ಕಾರ್ಯವು ಲೋಡ್ ಮಾಡಲಾದ ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸುತ್ತದೆ seccomp_check_filter() ಕರ್ನಲ್ಗಳು. (ತಮಾಷೆಯ ವಿಷಯವೆಂದರೆ, seccomp ಕಾರ್ಯವನ್ನು ಸೇರಿಸಿದ ಮೂಲ ಬದ್ಧತೆಯಲ್ಲಿ, ಅವರು ಈ ಕಾರ್ಯಕ್ಕೆ ಸೂಚನೆಯನ್ನು ಬಳಸಲು ಅನುಮತಿಯನ್ನು ಸೇರಿಸಲು ಮರೆತಿದ್ದಾರೆ mod (ವಿಭಾಗದ ಶೇಷ) ಮತ್ತು ಈಗ ಸೆಕಾಂಪ್ BPF ಕಾರ್ಯಕ್ರಮಗಳಿಗೆ ಲಭ್ಯವಿಲ್ಲ, ಅದರ ಸೇರ್ಪಡೆಯಿಂದ ಒಡೆಯುತ್ತದೆ ABI.)

ಮೂಲಭೂತವಾಗಿ, ನಾವು ಈಗಾಗಲೇ seccomp ಕಾರ್ಯಕ್ರಮಗಳನ್ನು ಬರೆಯಲು ಮತ್ತು ಓದಲು ಎಲ್ಲವನ್ನೂ ತಿಳಿದಿದ್ದೇವೆ. ಸಾಮಾನ್ಯವಾಗಿ ಪ್ರೋಗ್ರಾಂ ತರ್ಕವನ್ನು ಸಿಸ್ಟಮ್ ಕರೆಗಳ ಬಿಳಿ ಅಥವಾ ಕಪ್ಪು ಪಟ್ಟಿಯಂತೆ ಜೋಡಿಸಲಾಗುತ್ತದೆ, ಉದಾಹರಣೆಗೆ ಪ್ರೋಗ್ರಾಂ

ld [0]
jeq #304, bad
jeq #176, bad
jeq #239, bad
jeq #279, bad
good: ret #0x7fff0000 /* SECCOMP_RET_ALLOW */
bad: ret #0

304, 176, 239, 279 ಸಂಖ್ಯೆಯ ನಾಲ್ಕು ಸಿಸ್ಟಮ್ ಕರೆಗಳ ಕಪ್ಪುಪಟ್ಟಿಯನ್ನು ಪರಿಶೀಲಿಸುತ್ತದೆ. ಈ ಸಿಸ್ಟಮ್ ಕರೆಗಳು ಯಾವುವು? ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಯಾವ ವಾಸ್ತುಶಿಲ್ಪಕ್ಕಾಗಿ ಬರೆಯಲಾಗಿದೆ ಎಂದು ನಮಗೆ ತಿಳಿದಿಲ್ಲವಾದ್ದರಿಂದ ನಾವು ಖಚಿತವಾಗಿ ಹೇಳಲು ಸಾಧ್ಯವಿಲ್ಲ. ಆದ್ದರಿಂದ, seccomp ನ ಲೇಖಕರು ಆಫರ್ ಆರ್ಕಿಟೆಕ್ಚರ್ ಚೆಕ್‌ನೊಂದಿಗೆ ಎಲ್ಲಾ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಪ್ರಾರಂಭಿಸಿ (ಪ್ರಸ್ತುತ ಆರ್ಕಿಟೆಕ್ಚರ್ ಅನ್ನು ಕ್ಷೇತ್ರವಾಗಿ ಸಂದರ್ಭದಲ್ಲಿ ಸೂಚಿಸಲಾಗುತ್ತದೆ arch ರಚನೆಗಳು struct seccomp_data) ವಾಸ್ತುಶಿಲ್ಪವನ್ನು ಪರಿಶೀಲಿಸಿದಾಗ, ಉದಾಹರಣೆಯ ಪ್ರಾರಂಭವು ಈ ರೀತಿ ಕಾಣುತ್ತದೆ:

ld [4]
jne #0xc000003e, bad_arch ; SCMP_ARCH_X86_64

ತದನಂತರ ನಮ್ಮ ಸಿಸ್ಟಂ ಕರೆ ಸಂಖ್ಯೆಗಳು ಕೆಲವು ಮೌಲ್ಯಗಳನ್ನು ಪಡೆಯುತ್ತವೆ.

ನಾವು seccomp ಬಳಕೆಗಾಗಿ ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಬರೆಯುತ್ತೇವೆ ಮತ್ತು ಲೋಡ್ ಮಾಡುತ್ತೇವೆ libseccomp

ಸ್ಥಳೀಯ ಕೋಡ್‌ನಲ್ಲಿ ಅಥವಾ BPF ಅಸೆಂಬ್ಲಿಯಲ್ಲಿ ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಬರೆಯುವುದು ಫಲಿತಾಂಶದ ಮೇಲೆ ಸಂಪೂರ್ಣ ನಿಯಂತ್ರಣವನ್ನು ಹೊಂದಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ, ಆದರೆ ಅದೇ ಸಮಯದಲ್ಲಿ, ಪೋರ್ಟಬಲ್ ಮತ್ತು/ಅಥವಾ ಓದಬಹುದಾದ ಕೋಡ್ ಅನ್ನು ಹೊಂದಲು ಕೆಲವೊಮ್ಮೆ ಆದ್ಯತೆ ನೀಡಲಾಗುತ್ತದೆ. ಗ್ರಂಥಾಲಯವು ಇದಕ್ಕೆ ನಮಗೆ ಸಹಾಯ ಮಾಡುತ್ತದೆ ಲಿಬ್ಸೆಕಾಂಪ್, ಇದು ಕಪ್ಪು ಅಥವಾ ಬಿಳಿ ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಬರೆಯಲು ಪ್ರಮಾಣಿತ ಇಂಟರ್ಫೇಸ್ ಅನ್ನು ಒದಗಿಸುತ್ತದೆ.

ಉದಾಹರಣೆಗೆ, ಬಳಕೆದಾರರ ಆಯ್ಕೆಯ ಬೈನರಿ ಫೈಲ್ ಅನ್ನು ರನ್ ಮಾಡುವ ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಬರೆಯೋಣ, ಈ ಹಿಂದೆ ಸಿಸ್ಟಮ್ ಕರೆಗಳ ಕಪ್ಪು ಪಟ್ಟಿಯನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ ಮೇಲಿನ ಲೇಖನ (ಹೆಚ್ಚಿನ ಓದುವಿಕೆಗಾಗಿ ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಸರಳೀಕರಿಸಲಾಗಿದೆ, ಪೂರ್ಣ ಆವೃತ್ತಿಯನ್ನು ಕಾಣಬಹುದು ಇಲ್ಲಿ):

#include <seccomp.h>
#include <unistd.h>
#include <err.h>

static int sys_numbers[] = {
        __NR_mount,
        __NR_umount2,
       // ... еще 40 системных вызовов ...
        __NR_vmsplice,
        __NR_perf_event_open,
};

int main(int argc, char **argv)
{
        scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);

        for (size_t i = 0; i < sizeof(sys_numbers)/sizeof(sys_numbers[0]); i++)
                seccomp_rule_add(ctx, SCMP_ACT_TRAP, sys_numbers[i], 0);

        seccomp_load(ctx);

        execvp(argv[1], &argv[1]);
        err(1, "execlp: %s", argv[1]);
}

ಮೊದಲು ನಾವು ಒಂದು ಶ್ರೇಣಿಯನ್ನು ವ್ಯಾಖ್ಯಾನಿಸುತ್ತೇವೆ sys_numbers ನಿರ್ಬಂಧಿಸಲು 40+ ಸಿಸ್ಟಮ್ ಕರೆ ಸಂಖ್ಯೆಗಳು. ನಂತರ, ಸಂದರ್ಭವನ್ನು ಪ್ರಾರಂಭಿಸಿ ctx ಮತ್ತು ನಾವು ಏನು ಅನುಮತಿಸಲು ಬಯಸುತ್ತೇವೆ ಎಂಬುದನ್ನು ಲೈಬ್ರರಿಗೆ ತಿಳಿಸಿ (SCMP_ACT_ALLOW) ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ಎಲ್ಲಾ ಸಿಸ್ಟಮ್ ಕರೆಗಳು (ಕಪ್ಪುಪಟ್ಟಿಗಳನ್ನು ನಿರ್ಮಿಸುವುದು ಸುಲಭ). ನಂತರ, ಒಂದೊಂದಾಗಿ, ನಾವು ಕಪ್ಪುಪಟ್ಟಿಯಿಂದ ಎಲ್ಲಾ ಸಿಸ್ಟಮ್ ಕರೆಗಳನ್ನು ಸೇರಿಸುತ್ತೇವೆ. ಪಟ್ಟಿಯಿಂದ ಸಿಸ್ಟಮ್ ಕರೆಗೆ ಪ್ರತಿಕ್ರಿಯೆಯಾಗಿ, ನಾವು ವಿನಂತಿಸುತ್ತೇವೆ SCMP_ACT_TRAP, ಈ ಸಂದರ್ಭದಲ್ಲಿ seccomp ಪ್ರಕ್ರಿಯೆಗೆ ಸಂಕೇತವನ್ನು ಕಳುಹಿಸುತ್ತದೆ SIGSYS ಯಾವ ಸಿಸ್ಟಮ್ ಕರೆ ನಿಯಮಗಳನ್ನು ಉಲ್ಲಂಘಿಸಿದೆ ಎಂಬುದರ ವಿವರಣೆಯೊಂದಿಗೆ. ಅಂತಿಮವಾಗಿ, ನಾವು ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಬಳಸಿಕೊಂಡು ಕರ್ನಲ್ಗೆ ಲೋಡ್ ಮಾಡುತ್ತೇವೆ seccomp_load, ಇದು ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಕಂಪೈಲ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಸಿಸ್ಟಮ್ ಕರೆಯನ್ನು ಬಳಸಿಕೊಂಡು ಪ್ರಕ್ರಿಯೆಗೆ ಲಗತ್ತಿಸುತ್ತದೆ seccomp(2).

ಯಶಸ್ವಿ ಸಂಕಲನಕ್ಕಾಗಿ, ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಗ್ರಂಥಾಲಯದೊಂದಿಗೆ ಲಿಂಕ್ ಮಾಡಬೇಕು libseccomp, ಉದಾಹರಣೆಗೆ:

cc -std=c17 -Wall -Wextra -c -o seccomp_lib.o seccomp_lib.c
cc -o seccomp_lib seccomp_lib.o -lseccomp

ಯಶಸ್ವಿ ಉಡಾವಣೆಯ ಉದಾಹರಣೆ:

$ ./seccomp_lib echo ok
ok

ನಿರ್ಬಂಧಿಸಲಾದ ಸಿಸ್ಟಮ್ ಕರೆಗೆ ಉದಾಹರಣೆ:

$ sudo ./seccomp_lib mount -t bpf bpf /tmp
Bad system call

ನಾವು ಉಪಯೋಗಿಸುತ್ತೀವಿ straceವಿವರಗಳಿಗಾಗಿ:

$ sudo strace -e seccomp ./seccomp_lib mount -t bpf bpf /tmp
seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=50, filter=0x55d8e78428e0}) = 0
--- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0xboobdeadbeef, si_syscall=__NR_mount, si_arch=AUDIT_ARCH_X86_64} ---
+++ killed by SIGSYS (core dumped) +++
Bad system call

ಕಾನೂನುಬಾಹಿರ ಸಿಸ್ಟಮ್ ಕರೆಯ ಬಳಕೆಯಿಂದಾಗಿ ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಕೊನೆಗೊಳಿಸಲಾಗಿದೆ ಎಂದು ನಾವು ಹೇಗೆ ತಿಳಿಯಬಹುದು mount(2).

ಆದ್ದರಿಂದ, ನಾವು ಲೈಬ್ರರಿಯನ್ನು ಬಳಸಿಕೊಂಡು ಫಿಲ್ಟರ್ ಅನ್ನು ಬರೆದಿದ್ದೇವೆ libseccomp, ಕ್ಷುಲ್ಲಕವಲ್ಲದ ಕೋಡ್ ಅನ್ನು ನಾಲ್ಕು ಸಾಲುಗಳಲ್ಲಿ ಅಳವಡಿಸುವುದು. ಮೇಲಿನ ಉದಾಹರಣೆಯಲ್ಲಿ, ಹೆಚ್ಚಿನ ಸಂಖ್ಯೆಯ ಸಿಸ್ಟಮ್ ಕರೆಗಳು ಇದ್ದಲ್ಲಿ, ಎಕ್ಸಿಕ್ಯೂಶನ್ ಸಮಯವನ್ನು ಗಮನಾರ್ಹವಾಗಿ ಕಡಿಮೆ ಮಾಡಬಹುದು, ಏಕೆಂದರೆ ಚೆಕ್ ಕೇವಲ ಹೋಲಿಕೆಗಳ ಪಟ್ಟಿಯಾಗಿದೆ. ಆಪ್ಟಿಮೈಸೇಶನ್‌ಗಾಗಿ, libseccomp ಇತ್ತೀಚೆಗೆ ಹೊಂದಿತ್ತು ಪ್ಯಾಚ್ ಒಳಗೊಂಡಿದೆ, ಇದು ಫಿಲ್ಟರ್ ಗುಣಲಕ್ಷಣಕ್ಕೆ ಬೆಂಬಲವನ್ನು ಸೇರಿಸುತ್ತದೆ SCMP_FLTATR_CTL_OPTIMIZE. ಈ ಗುಣಲಕ್ಷಣವನ್ನು 2 ಗೆ ಹೊಂದಿಸುವುದರಿಂದ ಫಿಲ್ಟರ್ ಅನ್ನು ಬೈನರಿ ಹುಡುಕಾಟ ಪ್ರೋಗ್ರಾಂ ಆಗಿ ಪರಿವರ್ತಿಸುತ್ತದೆ.

ಬೈನರಿ ಹುಡುಕಾಟ ಫಿಲ್ಟರ್‌ಗಳು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತವೆ ಎಂಬುದನ್ನು ನೀವು ನೋಡಲು ಬಯಸಿದರೆ, ಒಮ್ಮೆ ನೋಡಿ ಸರಳ ಸ್ಕ್ರಿಪ್ಟ್, ಸಿಸ್ಟಮ್ ಕರೆ ಸಂಖ್ಯೆಗಳನ್ನು ಡಯಲ್ ಮಾಡುವ ಮೂಲಕ BPF ಅಸೆಂಬ್ಲರ್‌ನಲ್ಲಿ ಅಂತಹ ಕಾರ್ಯಕ್ರಮಗಳನ್ನು ಉತ್ಪಾದಿಸುತ್ತದೆ, ಉದಾಹರಣೆಗೆ:

$ echo 1 3 6 8 13 | ./generate_bin_search_bpf.py
ld [0]
jeq #6, bad
jgt #6, check8
jeq #1, bad
jeq #3, bad
ret #0x7fff0000
check8:
jeq #8, bad
jeq #13, bad
ret #0x7fff0000
bad: ret #0

BPF ಪ್ರೋಗ್ರಾಂಗಳು ಇಂಡೆಂಟೇಶನ್ ಜಿಗಿತಗಳನ್ನು ನಿರ್ವಹಿಸಲು ಸಾಧ್ಯವಾಗದ ಕಾರಣ, ಗಮನಾರ್ಹವಾಗಿ ವೇಗವಾಗಿ ಏನನ್ನೂ ಬರೆಯುವುದು ಅಸಾಧ್ಯ (ನಾವು ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ, ಉದಾಹರಣೆಗೆ, jmp A ಅಥವಾ jmp [label+X]) ಮತ್ತು ಆದ್ದರಿಂದ ಎಲ್ಲಾ ಪರಿವರ್ತನೆಗಳು ಸ್ಥಿರವಾಗಿರುತ್ತವೆ.

ಸೆಕೆಂಪ್ ಮತ್ತು ಸ್ಟ್ರೇಸ್

ಉಪಯುಕ್ತತೆ ಎಲ್ಲರಿಗೂ ತಿಳಿದಿದೆ strace Linux ನಲ್ಲಿ ಪ್ರಕ್ರಿಯೆಗಳ ನಡವಳಿಕೆಯನ್ನು ಅಧ್ಯಯನ ಮಾಡಲು ಅನಿವಾರ್ಯ ಸಾಧನವಾಗಿದೆ. ಆದಾಗ್ಯೂ, ಅನೇಕರು ಇದರ ಬಗ್ಗೆ ಕೇಳಿದ್ದಾರೆ ಕಾರ್ಯಕ್ಷಮತೆಯ ಸಮಸ್ಯೆಗಳು ಈ ಉಪಯುಕ್ತತೆಯನ್ನು ಬಳಸುವಾಗ. ವಾಸ್ತವವೆಂದರೆ ಅದು strace ಬಳಸಿ ಅಳವಡಿಸಲಾಗಿದೆ ptrace(2), ಮತ್ತು ಈ ಕಾರ್ಯವಿಧಾನದಲ್ಲಿ ನಾವು ಪ್ರಕ್ರಿಯೆಯನ್ನು ನಿಲ್ಲಿಸಲು ಯಾವ ಸಿಸ್ಟಮ್ ಕರೆಗಳ ಸೆಟ್ನಲ್ಲಿ ನಿರ್ದಿಷ್ಟಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ, ಅಂದರೆ, ಉದಾಹರಣೆಗೆ, ಆಜ್ಞೆಗಳು

$ time strace du /usr/share/ >/dev/null 2>&1

real    0m3.081s
user    0m0.531s
sys     0m2.073s

и

$ time strace -e open du /usr/share/ >/dev/null 2>&1

real    0m2.404s
user    0m0.193s
sys     0m1.800s

ಸರಿಸುಮಾರು ಅದೇ ಸಮಯದಲ್ಲಿ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲಾಗುತ್ತದೆ, ಆದಾಗ್ಯೂ ಎರಡನೇ ಸಂದರ್ಭದಲ್ಲಿ ನಾವು ಕೇವಲ ಒಂದು ಸಿಸ್ಟಮ್ ಕರೆಯನ್ನು ಪತ್ತೆಹಚ್ಚಲು ಬಯಸುತ್ತೇವೆ.

ಹೊಸ ಆಯ್ಕೆ --seccomp-bpf, ಸೇರಿಸಲಾಗಿದೆ strace ಆವೃತ್ತಿ 5.3, ಪ್ರಕ್ರಿಯೆಯನ್ನು ಹಲವು ಬಾರಿ ವೇಗಗೊಳಿಸಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ ಮತ್ತು ಒಂದು ಸಿಸ್ಟಮ್ ಕರೆಯ ಜಾಡಿನ ಅಡಿಯಲ್ಲಿ ಆರಂಭಿಕ ಸಮಯವನ್ನು ಈಗಾಗಲೇ ಸಾಮಾನ್ಯ ಪ್ರಾರಂಭದ ಸಮಯಕ್ಕೆ ಹೋಲಿಸಬಹುದು:

$ time strace --seccomp-bpf -e open du /usr/share/ >/dev/null 2>&1

real    0m0.148s
user    0m0.017s
sys     0m0.131s

$ time du /usr/share/ >/dev/null 2>&1

real    0m0.140s
user    0m0.024s
sys     0m0.116s

(ಇಲ್ಲಿ, ಸಹಜವಾಗಿ, ನಾವು ಈ ಆಜ್ಞೆಯ ಮುಖ್ಯ ಸಿಸ್ಟಮ್ ಕರೆಯನ್ನು ಪತ್ತೆಹಚ್ಚದಿರುವಲ್ಲಿ ಸ್ವಲ್ಪ ಮೋಸವಿದೆ. ನಾವು ಪತ್ತೆಹಚ್ಚುತ್ತಿದ್ದರೆ, ಉದಾಹರಣೆಗೆ, newfsstat, ನಂತರ strace ಇಲ್ಲದೆ ಇದ್ದಂತೆಯೇ ಗಟ್ಟಿಯಾಗಿ ಬ್ರೇಕ್ ಹಾಕುತ್ತಿದ್ದರು --seccomp-bpf.)

ಈ ಆಯ್ಕೆಯು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ? ಅವಳಿಲ್ಲದೆ strace ಪ್ರಕ್ರಿಯೆಗೆ ಸಂಪರ್ಕಿಸುತ್ತದೆ ಮತ್ತು ಅದನ್ನು ಬಳಸಲು ಪ್ರಾರಂಭಿಸುತ್ತದೆ PTRACE_SYSCALL. ನಿರ್ವಹಿಸಿದ ಪ್ರಕ್ರಿಯೆಯು (ಯಾವುದೇ) ಸಿಸ್ಟಮ್ ಕರೆಯನ್ನು ನೀಡಿದಾಗ, ನಿಯಂತ್ರಣವನ್ನು ವರ್ಗಾಯಿಸಲಾಗುತ್ತದೆ strace, ಇದು ಸಿಸ್ಟಮ್ ಕರೆಯ ಆರ್ಗ್ಯುಮೆಂಟ್‌ಗಳನ್ನು ನೋಡುತ್ತದೆ ಮತ್ತು ಅದರೊಂದಿಗೆ ರನ್ ಮಾಡುತ್ತದೆ PTRACE_SYSCALL. ಸ್ವಲ್ಪ ಸಮಯದ ನಂತರ, ಪ್ರಕ್ರಿಯೆಯು ಸಿಸ್ಟಮ್ ಕರೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸುತ್ತದೆ ಮತ್ತು ಅದನ್ನು ನಿರ್ಗಮಿಸುವಾಗ, ನಿಯಂತ್ರಣವನ್ನು ಮತ್ತೆ ವರ್ಗಾಯಿಸಲಾಗುತ್ತದೆ strace, ಇದು ರಿಟರ್ನ್ ಮೌಲ್ಯಗಳನ್ನು ನೋಡುತ್ತದೆ ಮತ್ತು ಬಳಸಿಕೊಂಡು ಪ್ರಕ್ರಿಯೆಯನ್ನು ಪ್ರಾರಂಭಿಸುತ್ತದೆ PTRACE_SYSCALL, ಮತ್ತು ಇತ್ಯಾದಿ.

ಚಿಕ್ಕ ಮಕ್ಕಳಿಗೆ BPF, ಭಾಗ ಶೂನ್ಯ: ಕ್ಲಾಸಿಕ್ BPF

ಆದಾಗ್ಯೂ, ಸೆಕಾಂಪ್ನೊಂದಿಗೆ, ಈ ಪ್ರಕ್ರಿಯೆಯನ್ನು ನಾವು ಬಯಸಿದಂತೆ ನಿಖರವಾಗಿ ಹೊಂದುವಂತೆ ಮಾಡಬಹುದು. ಅವುಗಳೆಂದರೆ, ನಾವು ಸಿಸ್ಟಮ್ ಕರೆಯನ್ನು ಮಾತ್ರ ನೋಡಲು ಬಯಸಿದರೆ X, ನಂತರ ನಾವು BPF ಫಿಲ್ಟರ್ ಅನ್ನು ಬರೆಯಬಹುದು X ಮೌಲ್ಯವನ್ನು ಹಿಂದಿರುಗಿಸುತ್ತದೆ SECCOMP_RET_TRACE, ಮತ್ತು ನಮಗೆ ಆಸಕ್ತಿಯಿಲ್ಲದ ಕರೆಗಳಿಗೆ - SECCOMP_RET_ALLOW:

ld [0]
jneq #X, ignore
trace: ret #0x7ff00000
ignore: ret #0x7fff0000

ಈ ಸಂದರ್ಭದಲ್ಲಿ strace ಆರಂಭದಲ್ಲಿ ಪ್ರಕ್ರಿಯೆಯು ಪ್ರಾರಂಭವಾಗುತ್ತದೆ PTRACE_CONT, ಸಿಸ್ಟಮ್ ಕರೆ ಇಲ್ಲದಿದ್ದರೆ ನಮ್ಮ ಫಿಲ್ಟರ್ ಅನ್ನು ಪ್ರತಿ ಸಿಸ್ಟಮ್ ಕರೆಗೆ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲಾಗುತ್ತದೆ X, ನಂತರ ಪ್ರಕ್ರಿಯೆಯು ಚಾಲನೆಯಲ್ಲಿದೆ, ಆದರೆ ಇದು ವೇಳೆ X, ನಂತರ seccomp ನಿಯಂತ್ರಣವನ್ನು ವರ್ಗಾಯಿಸುತ್ತದೆ straceಇದು ವಾದಗಳನ್ನು ನೋಡುತ್ತದೆ ಮತ್ತು ಪ್ರಕ್ರಿಯೆಯನ್ನು ಪ್ರಾರಂಭಿಸುತ್ತದೆ PTRACE_SYSCALL (ಸಿಸ್ಟಮ್ ಕರೆಯಿಂದ ನಿರ್ಗಮಿಸುವಾಗ ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಚಲಾಯಿಸುವ ಸಾಮರ್ಥ್ಯವನ್ನು seccomp ಹೊಂದಿಲ್ಲ). ಸಿಸ್ಟಮ್ ಕರೆ ಹಿಂತಿರುಗಿದಾಗ, strace ಬಳಸಿಕೊಂಡು ಪ್ರಕ್ರಿಯೆಯನ್ನು ಮರುಪ್ರಾರಂಭಿಸುತ್ತದೆ PTRACE_CONT ಮತ್ತು seccomp ನಿಂದ ಹೊಸ ಸಂದೇಶಗಳಿಗಾಗಿ ಕಾಯುತ್ತದೆ.

ಚಿಕ್ಕ ಮಕ್ಕಳಿಗೆ BPF, ಭಾಗ ಶೂನ್ಯ: ಕ್ಲಾಸಿಕ್ BPF

ಆಯ್ಕೆಯನ್ನು ಬಳಸುವಾಗ --seccomp-bpf ಎರಡು ನಿರ್ಬಂಧಗಳಿವೆ. ಮೊದಲನೆಯದಾಗಿ, ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪ್ರಕ್ರಿಯೆಗೆ ಸೇರಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ (ಆಯ್ಕೆ -p ಕಾರ್ಯಕ್ರಮಗಳು strace), ಏಕೆಂದರೆ ಇದನ್ನು seccomp ಬೆಂಬಲಿಸುವುದಿಲ್ಲ. ಎರಡನೆಯದಾಗಿ, ಯಾವುದೇ ಸಾಧ್ಯತೆಗಳಿಲ್ಲ ಕೇವಲ ಮಗುವಿನ ಪ್ರಕ್ರಿಯೆಗಳನ್ನು ನೋಡಿ, ಏಕೆಂದರೆ ಇದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುವ ಸಾಮರ್ಥ್ಯವಿಲ್ಲದೆಯೇ ಎಲ್ಲಾ ಮಕ್ಕಳ ಪ್ರಕ್ರಿಯೆಗಳಿಂದ seccomp ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಆನುವಂಶಿಕವಾಗಿ ಪಡೆಯಲಾಗುತ್ತದೆ.

ಎಷ್ಟು ನಿಖರವಾಗಿ ಎಂಬುದರ ಕುರಿತು ಸ್ವಲ್ಪ ಹೆಚ್ಚು ವಿವರ strace ಕೆಲಸ ಮಾಡುತ್ತದೆ seccomp ನಿಂದ ಕಂಡುಹಿಡಿಯಬಹುದು ಇತ್ತೀಚಿನ ವರದಿ. ನಮಗೆ, ಅತ್ಯಂತ ಆಸಕ್ತಿದಾಯಕ ಸಂಗತಿಯೆಂದರೆ, ಸೆಕಾಂಪ್ ಪ್ರತಿನಿಧಿಸುವ ಕ್ಲಾಸಿಕ್ ಬಿಪಿಎಫ್ ಅನ್ನು ಇಂದಿಗೂ ಬಳಸಲಾಗುತ್ತದೆ.

xt_bpf

ಈಗ ನೆಟ್‌ವರ್ಕ್‌ಗಳ ಜಗತ್ತಿಗೆ ಹಿಂತಿರುಗಿ ನೋಡೋಣ.

ಹಿನ್ನೆಲೆ: ಬಹಳ ಹಿಂದೆಯೇ, 2007 ರಲ್ಲಿ, ಕೋರ್ ಆಗಿತ್ತು ಸೇರಿಸಲಾಗಿದೆ ಮಾಡ್ಯೂಲ್ xt_u32 ನೆಟ್ಫಿಲ್ಟರ್ಗಾಗಿ. ಇದು ಇನ್ನೂ ಹೆಚ್ಚು ಪ್ರಾಚೀನ ಸಂಚಾರ ವರ್ಗೀಕರಣದೊಂದಿಗೆ ಸಾದೃಶ್ಯದಿಂದ ಬರೆಯಲ್ಪಟ್ಟಿದೆ cls_u32 ಮತ್ತು ಕೆಳಗಿನ ಸರಳ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಬಳಸಿಕೊಂಡು iptables ಗಾಗಿ ಅನಿಯಂತ್ರಿತ ಬೈನರಿ ನಿಯಮಗಳನ್ನು ಬರೆಯಲು ನಿಮಗೆ ಅನುಮತಿಸಲಾಗಿದೆ: ಪ್ಯಾಕೇಜ್‌ನಿಂದ 32 ಬಿಟ್‌ಗಳನ್ನು ಲೋಡ್ ಮಾಡಿ ಮತ್ತು ಅವುಗಳ ಮೇಲೆ ಅಂಕಗಣಿತದ ಕಾರ್ಯಾಚರಣೆಗಳ ಗುಂಪನ್ನು ನಿರ್ವಹಿಸಿ. ಉದಾಹರಣೆಗೆ,

sudo iptables -A INPUT -m u32 --u32 "6&0xFF=1" -j LOG --log-prefix "seen-by-xt_u32"

IP ಹೆಡರ್‌ನ 32 ಬಿಟ್‌ಗಳನ್ನು ಲೋಡ್ ಮಾಡುತ್ತದೆ, ಪ್ಯಾಡಿಂಗ್ 6 ರಿಂದ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ ಮತ್ತು ಅವುಗಳಿಗೆ ಮುಖವಾಡವನ್ನು ಅನ್ವಯಿಸುತ್ತದೆ 0xFF (ಕಡಿಮೆ ಬೈಟ್ ತೆಗೆದುಕೊಳ್ಳಿ). ಈ ಕ್ಷೇತ್ರ protocol IP ಹೆಡರ್ ಮತ್ತು ನಾವು ಅದನ್ನು 1 (ICMP) ನೊಂದಿಗೆ ಹೋಲಿಸುತ್ತೇವೆ. ನೀವು ಒಂದು ನಿಯಮದಲ್ಲಿ ಅನೇಕ ಚೆಕ್ಗಳನ್ನು ಸಂಯೋಜಿಸಬಹುದು, ಮತ್ತು ನೀವು ಆಪರೇಟರ್ ಅನ್ನು ಸಹ ಕಾರ್ಯಗತಗೊಳಿಸಬಹುದು @ - X ಬೈಟ್‌ಗಳನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ. ಉದಾಹರಣೆಗೆ, ನಿಯಮ

iptables -m u32 --u32 "6&0xFF=0x6 && 0>>22&0x3C@4=0x29"

TCP ಅನುಕ್ರಮ ಸಂಖ್ಯೆ ಸಮಾನವಾಗಿಲ್ಲದಿದ್ದರೆ ಪರಿಶೀಲಿಸುತ್ತದೆ 0x29. ನಾನು ಹೆಚ್ಚಿನ ವಿವರಗಳಿಗೆ ಹೋಗುವುದಿಲ್ಲ, ಏಕೆಂದರೆ ಅಂತಹ ನಿಯಮಗಳನ್ನು ಕೈಯಿಂದ ಬರೆಯುವುದು ತುಂಬಾ ಅನುಕೂಲಕರವಲ್ಲ ಎಂದು ಈಗಾಗಲೇ ಸ್ಪಷ್ಟವಾಗಿದೆ. ಲೇಖನದಲ್ಲಿ BPF - ಮರೆತುಹೋದ ಬೈಟ್‌ಕೋಡ್, ಬಳಕೆ ಮತ್ತು ನಿಯಮ ರಚನೆಯ ಉದಾಹರಣೆಗಳೊಂದಿಗೆ ಹಲವಾರು ಲಿಂಕ್‌ಗಳಿವೆ xt_u32. ಈ ಲೇಖನದ ಕೊನೆಯಲ್ಲಿ ಲಿಂಕ್‌ಗಳನ್ನು ಸಹ ನೋಡಿ.

ಮಾಡ್ಯೂಲ್ ಬದಲಿಗೆ 2013 ರಿಂದ ಮಾಡ್ಯೂಲ್ xt_u32 ನೀವು BPF ಆಧಾರಿತ ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಬಳಸಬಹುದು xt_bpf. ಇಲ್ಲಿಯವರೆಗೆ ಓದಿದ ಯಾರಾದರೂ ಅದರ ಕಾರ್ಯಾಚರಣೆಯ ತತ್ವದ ಬಗ್ಗೆ ಈಗಾಗಲೇ ಸ್ಪಷ್ಟವಾಗಿರಬೇಕು: BPF ಬೈಟ್‌ಕೋಡ್ ಅನ್ನು iptables ನಿಯಮಗಳಂತೆ ಚಲಾಯಿಸಿ. ನೀವು ಹೊಸ ನಿಯಮವನ್ನು ರಚಿಸಬಹುದು, ಉದಾಹರಣೆಗೆ, ಈ ರೀತಿ:

iptables -A INPUT -m bpf --bytecode <байткод> -j LOG

ಇಲ್ಲಿ <байткод> - ಇದು ಅಸೆಂಬ್ಲರ್ ಔಟ್‌ಪುಟ್ ಫಾರ್ಮ್ಯಾಟ್‌ನಲ್ಲಿರುವ ಕೋಡ್ ಆಗಿದೆ bpf_asm ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ, ಉದಾಹರಣೆಗೆ,

$ cat /tmp/test.bpf
ldb [9]
jneq #17, ignore
ret #1
ignore: ret #0

$ bpf_asm /tmp/test.bpf
4,48 0 0 9,21 0 1 17,6 0 0 1,6 0 0 0,

# iptables -A INPUT -m bpf --bytecode "$(bpf_asm /tmp/test.bpf)" -j LOG

ಈ ಉದಾಹರಣೆಯಲ್ಲಿ ನಾವು ಎಲ್ಲಾ UDP ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಫಿಲ್ಟರ್ ಮಾಡುತ್ತಿದ್ದೇವೆ. ಮಾಡ್ಯೂಲ್‌ನಲ್ಲಿ BPF ಕಾರ್ಯಕ್ರಮದ ಸಂದರ್ಭ xt_bpf, ಸಹಜವಾಗಿ, iptables ಸಂದರ್ಭದಲ್ಲಿ, IPv4 ಹೆಡರ್‌ನ ಪ್ರಾರಂಭಕ್ಕೆ ಪ್ಯಾಕೆಟ್ ಡೇಟಾವನ್ನು ಸೂಚಿಸುತ್ತದೆ. BPF ಪ್ರೋಗ್ರಾಂನಿಂದ ಮೌಲ್ಯವನ್ನು ಹಿಂತಿರುಗಿಸಿ ಬೂಲಿಯನ್ಅಲ್ಲಿ false ಪ್ಯಾಕೆಟ್ ಹೊಂದಿಕೆಯಾಗಲಿಲ್ಲ ಎಂದರ್ಥ.

ಮಾಡ್ಯೂಲ್ ಎಂಬುದು ಸ್ಪಷ್ಟವಾಗಿದೆ xt_bpf ಮೇಲಿನ ಉದಾಹರಣೆಗಿಂತ ಹೆಚ್ಚು ಸಂಕೀರ್ಣ ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ. ಕ್ಲೌಡ್‌ಫೇರ್‌ನಿಂದ ನಿಜವಾದ ಉದಾಹರಣೆಗಳನ್ನು ನೋಡೋಣ. ಇತ್ತೀಚಿನವರೆಗೂ ಅವರು ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಬಳಸುತ್ತಿದ್ದರು xt_bpf DDoS ದಾಳಿಯಿಂದ ರಕ್ಷಿಸಲು. ಲೇಖನದಲ್ಲಿ BPF ಪರಿಕರಗಳನ್ನು ಪರಿಚಯಿಸಲಾಗುತ್ತಿದೆ ಅವರು BPF ಫಿಲ್ಟರ್‌ಗಳನ್ನು ಹೇಗೆ (ಮತ್ತು ಏಕೆ) ಉತ್ಪಾದಿಸುತ್ತಾರೆ ಮತ್ತು ಅಂತಹ ಫಿಲ್ಟರ್‌ಗಳನ್ನು ರಚಿಸಲು ಉಪಯುಕ್ತತೆಗಳ ಗುಂಪಿಗೆ ಲಿಂಕ್‌ಗಳನ್ನು ಪ್ರಕಟಿಸುತ್ತಾರೆ ಎಂಬುದನ್ನು ಅವರು ವಿವರಿಸುತ್ತಾರೆ. ಉದಾಹರಣೆಗೆ, ಉಪಯುಕ್ತತೆಯನ್ನು ಬಳಸುವುದು bpfgen ಹೆಸರಿಗಾಗಿ DNS ಪ್ರಶ್ನೆಗೆ ಹೊಂದಿಕೆಯಾಗುವ BPF ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ನೀವು ರಚಿಸಬಹುದು habr.com:

$ ./bpfgen --assembly dns -- habr.com
ldx 4*([0]&0xf)
ld #20
add x
tax

lb_0:
    ld [x + 0]
    jneq #0x04686162, lb_1
    ld [x + 4]
    jneq #0x7203636f, lb_1
    ldh [x + 8]
    jneq #0x6d00, lb_1
    ret #65535

lb_1:
    ret #0

ಪ್ರೋಗ್ರಾಂನಲ್ಲಿ ನಾವು ಮೊದಲು ರಿಜಿಸ್ಟರ್ಗೆ ಲೋಡ್ ಮಾಡುತ್ತೇವೆ X ಸಾಲಿನ ವಿಳಾಸದ ಪ್ರಾರಂಭ x04habrx03comx00 UDP ಡೇಟಾಗ್ರಾಮ್ ಒಳಗೆ ಮತ್ತು ನಂತರ ವಿನಂತಿಯನ್ನು ಪರಿಶೀಲಿಸಿ: 0x04686162 <-> "x04hab" ಮತ್ತು ಹೀಗೆ.

ಸ್ವಲ್ಪ ಸಮಯದ ನಂತರ, ಕ್ಲೌಡ್‌ಫೇರ್ p0f -> BPF ಕಂಪೈಲರ್ ಕೋಡ್ ಅನ್ನು ಪ್ರಕಟಿಸಿತು. ಲೇಖನದಲ್ಲಿ p0f BPF ಕಂಪೈಲರ್ ಅನ್ನು ಪರಿಚಯಿಸಲಾಗುತ್ತಿದೆ ಅವರು p0f ಎಂದರೇನು ಮತ್ತು p0f ಸಹಿಯನ್ನು BPF ಗೆ ಹೇಗೆ ಪರಿವರ್ತಿಸುವುದು ಎಂಬುದರ ಕುರಿತು ಮಾತನಾಡುತ್ತಾರೆ:

$ ./bpfgen p0f -- 4:64:0:0:*,0::ack+:0
39,0 0 0 0,48 0 0 8,37 35 0 64,37 0 34 29,48 0 0 0,
84 0 0 15,21 0 31 5,48 0 0 9,21 0 29 6,40 0 0 6,
...

ಪ್ರಸ್ತುತ ಕ್ಲೌಡ್‌ಫೇರ್ ಅನ್ನು ಬಳಸುತ್ತಿಲ್ಲ xt_bpf, ಅವರು XDP ಗೆ ಸ್ಥಳಾಂತರಗೊಂಡಾಗಿನಿಂದ - BPF ನ ಹೊಸ ಆವೃತ್ತಿಯನ್ನು ಬಳಸುವ ಆಯ್ಕೆಗಳಲ್ಲಿ ಒಂದಾಗಿದೆ, ನೋಡಿ. L4Drop: XDP DDoS ತಗ್ಗಿಸುವಿಕೆಗಳು.

cls_bpf

ಕರ್ನಲ್‌ನಲ್ಲಿ ಕ್ಲಾಸಿಕ್ BPF ಅನ್ನು ಬಳಸುವ ಕೊನೆಯ ಉದಾಹರಣೆಯೆಂದರೆ ವರ್ಗೀಕರಣ cls_bpf ಲಿನಕ್ಸ್‌ನಲ್ಲಿನ ಟ್ರಾಫಿಕ್ ನಿಯಂತ್ರಣ ಉಪವ್ಯವಸ್ಥೆಗಾಗಿ, 2013 ರ ಕೊನೆಯಲ್ಲಿ ಲಿನಕ್ಸ್‌ಗೆ ಸೇರಿಸಲಾಗಿದೆ ಮತ್ತು ಪ್ರಾಚೀನವನ್ನು ಕಲ್ಪನಾತ್ಮಕವಾಗಿ ಬದಲಾಯಿಸುತ್ತದೆ cls_u32.

ಆದಾಗ್ಯೂ, ನಾವು ಈಗ ಕೆಲಸವನ್ನು ವಿವರಿಸುವುದಿಲ್ಲ cls_bpf, ಕ್ಲಾಸಿಕ್ ಬಿಪಿಎಫ್ ಬಗ್ಗೆ ಜ್ಞಾನದ ದೃಷ್ಟಿಕೋನದಿಂದ ಇದು ನಮಗೆ ಏನನ್ನೂ ನೀಡುವುದಿಲ್ಲ - ನಾವು ಈಗಾಗಲೇ ಎಲ್ಲಾ ಕಾರ್ಯಚಟುವಟಿಕೆಗಳೊಂದಿಗೆ ಪರಿಚಿತರಾಗಿದ್ದೇವೆ. ಹೆಚ್ಚುವರಿಯಾಗಿ, ವಿಸ್ತೃತ BPF ಕುರಿತು ಮಾತನಾಡುವ ನಂತರದ ಲೇಖನಗಳಲ್ಲಿ, ನಾವು ಈ ವರ್ಗೀಕರಣವನ್ನು ಒಂದಕ್ಕಿಂತ ಹೆಚ್ಚು ಬಾರಿ ಭೇಟಿ ಮಾಡುತ್ತೇವೆ.

ಕ್ಲಾಸಿಕ್ ಬಿಪಿಎಫ್ ಸಿ ಬಳಸುವ ಬಗ್ಗೆ ಮಾತನಾಡದಿರಲು ಇನ್ನೊಂದು ಕಾರಣ cls_bpf ಸಮಸ್ಯೆಯೆಂದರೆ, ವಿಸ್ತೃತ BPF ಗೆ ಹೋಲಿಸಿದರೆ, ಈ ಸಂದರ್ಭದಲ್ಲಿ ಅನ್ವಯದ ವ್ಯಾಪ್ತಿಯು ಆಮೂಲಾಗ್ರವಾಗಿ ಸಂಕುಚಿತವಾಗಿದೆ: ಶಾಸ್ತ್ರೀಯ ಕಾರ್ಯಕ್ರಮಗಳು ಪ್ಯಾಕೇಜ್‌ಗಳ ವಿಷಯಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ ಮತ್ತು ಕರೆಗಳ ನಡುವೆ ಸ್ಥಿತಿಯನ್ನು ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ.

ಆದ್ದರಿಂದ ಕ್ಲಾಸಿಕ್ BPF ಗೆ ವಿದಾಯ ಹೇಳುವ ಸಮಯ ಮತ್ತು ಭವಿಷ್ಯದತ್ತ ನೋಡುವ ಸಮಯ.

ಕ್ಲಾಸಿಕ್ BPF ಗೆ ವಿದಾಯ

ತೊಂಬತ್ತರ ದಶಕದ ಆರಂಭದಲ್ಲಿ ಅಭಿವೃದ್ಧಿಪಡಿಸಿದ ಬಿಪಿಎಫ್ ತಂತ್ರಜ್ಞಾನವು ಕಾಲು ಶತಮಾನದವರೆಗೆ ಯಶಸ್ವಿಯಾಗಿ ಹೇಗೆ ಬದುಕಿತು ಮತ್ತು ಕೊನೆಯವರೆಗೂ ಹೊಸ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಕಂಡುಕೊಂಡಿದೆ ಎಂಬುದನ್ನು ನಾವು ನೋಡಿದ್ದೇವೆ. ಆದಾಗ್ಯೂ, ಸ್ಟಾಕ್ ಯಂತ್ರಗಳಿಂದ RISC ಗೆ ಪರಿವರ್ತನೆಯಂತೆಯೇ, ಇದು ಕ್ಲಾಸಿಕ್ BPF ನ ಅಭಿವೃದ್ಧಿಗೆ ಪ್ರಚೋದನೆಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸಿತು, 32 ರ ದಶಕದಲ್ಲಿ 64-ಬಿಟ್‌ನಿಂದ XNUMX-ಬಿಟ್ ಯಂತ್ರಗಳಿಗೆ ಪರಿವರ್ತನೆಯಾಯಿತು ಮತ್ತು ಕ್ಲಾಸಿಕ್ BPF ಬಳಕೆಯಲ್ಲಿಲ್ಲದಂತಾಯಿತು. ಹೆಚ್ಚುವರಿಯಾಗಿ, ಕ್ಲಾಸಿಕ್ ಬಿಪಿಎಫ್‌ನ ಸಾಮರ್ಥ್ಯಗಳು ಬಹಳ ಸೀಮಿತವಾಗಿವೆ ಮತ್ತು ಹಳತಾದ ವಾಸ್ತುಶಿಲ್ಪದ ಜೊತೆಗೆ - ಬಿಪಿಎಫ್ ಕಾರ್ಯಕ್ರಮಗಳಿಗೆ ಕರೆಗಳ ನಡುವೆ ಸ್ಥಿತಿಯನ್ನು ಉಳಿಸುವ ಸಾಮರ್ಥ್ಯವನ್ನು ನಾವು ಹೊಂದಿಲ್ಲ, ನೇರ ಬಳಕೆದಾರರ ಸಂವಹನದ ಸಾಧ್ಯತೆಯಿಲ್ಲ, ಸಂವಹನ ಮಾಡುವ ಸಾಧ್ಯತೆಯಿಲ್ಲ ಕರ್ನಲ್ ಜೊತೆಗೆ, ಸೀಮಿತ ಸಂಖ್ಯೆಯ ರಚನೆ ಕ್ಷೇತ್ರಗಳನ್ನು ಓದುವುದನ್ನು ಹೊರತುಪಡಿಸಿ sk_buff ಮತ್ತು ಸರಳವಾದ ಸಹಾಯಕ ಕಾರ್ಯಗಳನ್ನು ಪ್ರಾರಂಭಿಸುವುದರಿಂದ, ನೀವು ಪ್ಯಾಕೆಟ್‌ಗಳ ವಿಷಯಗಳನ್ನು ಬದಲಾಯಿಸಲು ಮತ್ತು ಅವುಗಳನ್ನು ಮರುನಿರ್ದೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ.

ವಾಸ್ತವವಾಗಿ, ಪ್ರಸ್ತುತ ಲಿನಕ್ಸ್‌ನಲ್ಲಿ ಕ್ಲಾಸಿಕ್ ಬಿಪಿಎಫ್‌ನ ಉಳಿದಿರುವುದು API ಇಂಟರ್ಫೇಸ್ ಆಗಿದೆ, ಮತ್ತು ಕರ್ನಲ್‌ನ ಒಳಗೆ ಎಲ್ಲಾ ಕ್ಲಾಸಿಕ್ ಪ್ರೋಗ್ರಾಂಗಳು, ಅದು ಸಾಕೆಟ್ ಫಿಲ್ಟರ್‌ಗಳು ಅಥವಾ ಸೆಕಾಂಪ್ ಫಿಲ್ಟರ್‌ಗಳು, ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಹೊಸ ಫಾರ್ಮ್ಯಾಟ್‌ಗೆ ಅನುವಾದಿಸಲಾಗುತ್ತದೆ, ವಿಸ್ತೃತ BPF. (ಮುಂದಿನ ಲೇಖನದಲ್ಲಿ ಇದು ಹೇಗೆ ಸಂಭವಿಸುತ್ತದೆ ಎಂಬುದರ ಕುರಿತು ನಾವು ಮಾತನಾಡುತ್ತೇವೆ.)

ಹೊಸ ವಾಸ್ತುಶಿಲ್ಪಕ್ಕೆ ಪರಿವರ್ತನೆಯು 2013 ರಲ್ಲಿ ಪ್ರಾರಂಭವಾಯಿತು, ಅಲೆಕ್ಸಿ ಸ್ಟಾರೊವೊಯ್ಟೊವ್ ಬಿಪಿಎಫ್ ನವೀಕರಣ ಯೋಜನೆಯನ್ನು ಪ್ರಸ್ತಾಪಿಸಿದಾಗ. 2014 ರಲ್ಲಿ ಅನುಗುಣವಾದ ಪ್ಯಾಚ್ಗಳು ಕಾಣಿಸತೊಡಗಿತು ಕೋರ್ನಲ್ಲಿ. ನಾನು ಅರ್ಥಮಾಡಿಕೊಂಡಂತೆ, ಆರಂಭಿಕ ಯೋಜನೆಯು 64-ಬಿಟ್ ಯಂತ್ರಗಳಲ್ಲಿ ಹೆಚ್ಚು ಪರಿಣಾಮಕಾರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಆರ್ಕಿಟೆಕ್ಚರ್ ಮತ್ತು JIT ಕಂಪೈಲರ್ ಅನ್ನು ಆಪ್ಟಿಮೈಸ್ ಮಾಡುವುದು ಮಾತ್ರವಾಗಿತ್ತು, ಆದರೆ ಬದಲಿಗೆ ಈ ಆಪ್ಟಿಮೈಸೇಶನ್‌ಗಳು ಲಿನಕ್ಸ್ ಅಭಿವೃದ್ಧಿಯಲ್ಲಿ ಹೊಸ ಅಧ್ಯಾಯದ ಆರಂಭವನ್ನು ಗುರುತಿಸಿವೆ.

ಈ ಸರಣಿಯಲ್ಲಿನ ಹೆಚ್ಚಿನ ಲೇಖನಗಳು ಹೊಸ ತಂತ್ರಜ್ಞಾನದ ಆರ್ಕಿಟೆಕ್ಚರ್ ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ, ಇದನ್ನು ಆರಂಭದಲ್ಲಿ ಆಂತರಿಕ BPF ಎಂದು ಕರೆಯಲಾಗುತ್ತದೆ, ನಂತರ ವಿಸ್ತೃತ BPF ಮತ್ತು ಈಗ ಸರಳವಾಗಿ BPF ಎಂದು ಕರೆಯಲಾಗುತ್ತದೆ.

ಉಲ್ಲೇಖಗಳು

  1. ಸ್ಟೀವನ್ ಮೆಕ್‌ಕಾನ್ನೆ ಮತ್ತು ವ್ಯಾನ್ ಜಾಕೋಬ್ಸನ್, "ದಿ ಬಿಎಸ್‌ಡಿ ಪ್ಯಾಕೆಟ್ ಫಿಲ್ಟರ್: ಎ ನ್ಯೂ ಆರ್ಕಿಟೆಕ್ಚರ್ ಫಾರ್ ಯೂಸರ್-ಲೆವೆಲ್ ಪ್ಯಾಕೆಟ್ ಕ್ಯಾಪ್ಚರ್", https://www.tcpdump.org/papers/bpf-usenix93.pdf
  2. ಸ್ಟೀವನ್ ಮೆಕ್ಕನ್ನೆ, "libpcap: ಪ್ಯಾಕೆಟ್ ಕ್ಯಾಪ್ಚರ್ಗಾಗಿ ಆರ್ಕಿಟೆಕ್ಚರ್ ಮತ್ತು ಆಪ್ಟಿಮೈಸೇಶನ್ ಮೆಥಡಾಲಜಿ", https://sharkfestus.wireshark.org/sharkfest.11/presentations/McCanne-Sharkfest'11_Keynote_Address.pdf
  3. tcpdump, libpcap: https://www.tcpdump.org/
  4. IPtable U32 ಮ್ಯಾಚ್ ಟ್ಯುಟೋರಿಯಲ್.
  5. BPF - ಮರೆತುಹೋದ ಬೈಟ್‌ಕೋಡ್: https://blog.cloudflare.com/bpf-the-forgotten-bytecode/
  6. BPF ಟೂಲ್ ಅನ್ನು ಪರಿಚಯಿಸಲಾಗುತ್ತಿದೆ: https://blog.cloudflare.com/introducing-the-bpf-tools/
  7. bpf_cls: http://man7.org/linux/man-pages/man8/tc-bpf.8.html
  8. ಒಂದು seccomp ಅವಲೋಕನ: https://lwn.net/Articles/656307/
  9. https://github.com/torvalds/linux/blob/master/Documentation/userspace-api/seccomp_filter.rst
  10. habr: ಕಂಟೈನರ್‌ಗಳು ಮತ್ತು ಭದ್ರತೆ: seccomp
  11. habr: systemd ನೊಂದಿಗೆ ಡೀಮನ್‌ಗಳನ್ನು ಪ್ರತ್ಯೇಕಿಸುವುದು ಅಥವಾ "ಇದಕ್ಕಾಗಿ ನಿಮಗೆ ಡಾಕರ್ ಅಗತ್ಯವಿಲ್ಲ!"
  12. ಪಾಲ್ ಚೈಗ್ನಾನ್, "strace --seccomp-bpf: ಎ ಲುಕ್ ಅಂಡರ್ ದಿ ಹುಡ್", https://fosdem.org/2020/schedule/event/debugging_strace_bpf/
  13. netsniff-ng: http://netsniff-ng.org/

ಮೂಲ: www.habr.com

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ