
في هذه الجلسة التدريبية، سنستخرج البرنامج الثابت من شاحن المركبات الكهربائية، ونتعمق في البرنامج الثابت، ثم نحاكيه في النهاية لنتمكن من التفاعل مع الخدمات في الوقت الفعلي.
انضم إلينا في هذا العرض العملي لـ Unblob، أداة استخراج البرامج الثابتة المرنة. خلال جلسة ورشة العمل هذه، سنستخرج البرامج الثابتة من شاحن مركبات كهربائية، ونحفر في البرامج الثابتة، ثم نحاكيها في النهاية لنتمكن من التفاعل مع الخدمات في الوقت الفعلي. يعمل Unblob على كل من النسخ المادية والنسخ القابلة للتنزيل من البرامج الثابتة، لذا لدينا بيئة غنية بالأهداف. لا حاجة لخبرة سابقة، هذه الجلسة مناسبة لجميع مستويات المهارة، ونتطلع إلى رؤيتكم هناك.
هدفنا هو وحدة تحكم في محطة شحن المركبات الكهربائية من فينيكس كونتاكت. يمكنك العثور على مزيد من التفاصيل حولها هنا.
CHARX control modular، وحدة تحكم شحن AC، مع نظام Embedded Linux، IEC 61851-1، وضع التشغيل: Stand-Alone، Client، Server،
الواجهات:
- Ethernet (2x)
- الاتصال الخلوي (4G/2G)
- ناقل نظام CHARX control modular
- MICRO-USB type C
بروتوكولات الاتصال:
- OCPP 1.6J
- Modbus/TCP
- MQTT
الأجهزة الطرفية القابلة للتوصيل:
- عداد الطاقة
- RFID
- كشف تيار التسرب المتبقي DC
- تركيب على سكة DIN
هناك بعض الأدوات التي نحتاجها في ورشة العمل هذه. يمكنك تثبيتها عن طريق
تشغيل سكربت install-prerequisites كما يلي:```sh
./install-prerequisites
## الحصول على البرنامج الثابت
يمكن الحصول على البرنامج الثابت من موقع البائع. يوجد نص برمجي باسم
`download-firmware` في هذا المستودع يمكنك استخدامه لسحب البرنامج الثابت
بدون الحاجة إلى فتح متصفح.
تركيزنا اليوم على البرنامج الثابت المقدم من البائع لأنه يحتوي على كل ما
نحتاجه. لكن يمكن تطبيق سير عمل مشابه على تفريغ ذاكرة مستخرج من
جهاز حقيقي. الشيء المثير هنا هو أننا نستطيع الاستخراج والاستكشاف والمحاكاة
حتى دون الحاجة إلى جهاز حقيقي.
## الاستخراج باستخدام Unblob
لنبدأ بالتأكد من توفر جميع التبعيات:```
unblob --show-external-dependencies
The following executables found installed, which are needed by unblob:
7z ✓
debugfs ✓
jefferson ✓
lz4 ✓
lziprecover ✓
lzop ✓
sasquatch ✓
sasquatch-v4be ✓
simg2img ✓
ubireader_extract_files ✓
ubireader_extract_images ✓
unar ✓
zstd ✓
الآن يمكننا استخراج البرنامج الثابت باستخدام unblob:``` unblob CHARXSEC3XXXSoftwareBundleV190.raucb
يستغرق الاستخراج حوالي 3 دقائق على جهاز كمبيوتر لائق. يجب أن ترى شريط تقدم يتحرك للأعلى:

بمجرد اكتمال الاستخراج، يجب أن يكون دليل باسم
`CHARXSEC3XXXSoftwareBundleV190.raucb_extract` مرئيًا. يمكنك الدخول
إليه وسرد المحتوى.
### المقاطع، المقاطع غير المعروفة
يعمل Unblob عن طريق تحديد مقاطع البيانات داخل الملفات. إذا كان المقطع
دفقًا مضغوطًا، يتم فك ضغطه. إذا كان نظام ملفات أو أرشيفًا، يتم استخراجه.
إذا نجح الاستخراج أو فك الضغط، يتم حذف المقطع الذي تم عزله على القرص
لتوفير المساحة.
هنا، تم عزل مقطع SquashFS الإصدار 4 ذو النهاية الصغرى على القرص، واستخراجه،
وحذفه. تتم تسمية الملفات (وبالتالي أدلة الاستخراج) وفقًا لتسمية
`{start_offset}-{end_offset}.{type}`.
يمكننا أن نرى أن 11 كيلوبايت من مقطع "unknown" تظهر بعد نظام ملفات squashfs.```
./0-132173824.squashfs_v4_le_extract
./132173824-132184833.unknown
يمكنك تشغيل binwalk عليه لمعرفة ما يحتويه:```
binwalk 132173824-132184833.unknown
0 0x0 Object signature in DER format (PKCS header length: 4, sequence length: 10997 58 0x3A Certificate in DER format (x509 v3), header length: 4, sequence length: 4372 4434 0x1152 Certificate in DER format (x509 v3), header length: 4, sequence length: 4387
يمكنك التحقق من الشهادات باستخدام openssl:```
dd if=132173824-132184833.unknown bs=1 skip=58 | openssl x509 -in /dev/stdin -inform der -noout -text
dd if=132173824-132184833.unknown bs=1 skip=4434 | openssl x509 -in /dev/stdin -inform der -noout -text
هذا يعني أن البرامج الثابتة موقّعة على الأرجح باستخدام المفتاح الخاص للمورّد حتى تتمكن الأجهزة من التأكد من صحتها.
تلك إحدى مزايا unblob، إذ تحوّل المجهولات المجهولة إلى مجهولات معروفة يمكن التحقيق فيها.
لنلقِ نظرة على محتوى نظام الملفات squashfs لدينا:``` ls -al 0-132173824.squashfs_v4_le_extract total 460532 drwxrwxr-x 4 kali kali 4096 dec 5 09:51 . drwxrwxr-x 3 kali kali 4096 dec 5 09:51 .. -rw-rw-r-- 1 kali kali 20971520 sep 8 09:59 bootimg.vfat drwxrwxr-x 3 kali kali 4096 dec 5 09:51 bootimg.vfat_extract -rwxrwxr-x 1 kali kali 2654 sep 19 2022 hook -rw-rw-r-- 1 kali kali 442 sep 8 09:59 manifest.raucm -rw-rw-r-- 1 kali kali 450584576 sep 8 09:59 root.ext4 drwxrwxr-x 22 kali kali 4096 sep 8 09:57 root.ext4_extract
يمكننا رؤية قائمة نصية عادية، وسكربت شل، وMBR واحد، ونظام ملفات EXT4:```
find -maxdepth 1 -type f -exec file {} \;
./manifest.raucm: ASCII text
./hook: a /usr/bin/env sh script, ASCII text executable
./bootimg.vfat: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "mkfs.fat", sectors/cluster 4, reserved sectors 4, root entries 512, sectors 40960 (volumes <=32 MB), Media descriptor 0xf8, sectors/FAT 40, sectors/track 63, heads 255, hidden sectors 163158016, reserved 0x1, serial number 0xd09aad9c, label: "KERNEL ", FAT (16 bit)
./root.ext4: Linux rev 1.0 ext4 filesystem data, UUID=8ed19606-02c4-42e7-9cfb-1a2839f93ec4 (extents) (large files) (huge files)
تمت معالجة كل من bootimg.vfat وroot.ext4 واستخراجهما بواسطة unblob.
يحتوي قسم VFAT على كل ما يتعلق بالإقلاع ونظام التشغيل (نواة لينكس، DTB، TEE):```
oftree: Device Tree Blob version 17, size=27469, boot CPU=0, string block size=1657, DT structure block size=25756
tee.bin: data
zImage: Linux kernel ARM boot executable zImage (little-endian)
zImage-imx6ul-ksp0632.dtb: Device Tree Blob version 17, size=27469, boot CPU=0, string block size=1657, DT structure block size=25756
سترى أن unblob جشع بعض الشيء وسيستخرج ملف ELF وأرشيف CPIO
من نواة لينكس (`zImage`)، وهذان يتوافقان مع
النواة الدنيا وقرص الرام.
يحتوي نظام ملفات EXT4 على نظام الملفات الجذر الذي تقوم نواة لينكس
بتركيبه عند الإقلاع:```
ls -alh root.ext4_extract
total 88K
drwxrwxr-x 22 kali kali 4,0K sep 8 09:57 .
drwxrwxr-x 4 kali kali 4,0K dec 5 09:51 ..
drwxrwxr-x 2 kali kali 4,0K dec 5 09:51 bin
drwxrwxr-x 3 kali kali 4,0K dec 5 09:51 boot
drwxrwxr-x 16 kali kali 4,0K sep 8 09:56 data
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 dev
drwxrwxr-x 53 kali kali 4,0K dec 5 09:51 etc
drwxrwxr-x 18 kali kali 4,0K sep 8 09:56 home
drwxrwxr-x 2 kali kali 4,0K jul 18 03:13 identity
drwxrwxr-x 9 kali kali 4,0K dec 5 09:51 lib
drwxrwxr-x 2 kali kali 4,0K jul 18 03:14 log
drwxrwxr-x 2 kali kali 4,0K sep 8 09:57 lost+found
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 media
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 mnt
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 proc
drwxrwxr-x 2 kali kali 4,0K sep 8 09:57 run
drwxrwxr-x 2 kali kali 4,0K dec 5 09:51 sbin
drwxrwxr-x 2 kali kali 4,0K jul 18 03:14 sdcard
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 sys
drwxrwxrwx 2 kali kali 4,0K jul 18 00:09 tmp
drwxrwxr-x 11 kali kali 4,0K sep 8 09:56 usr
drwxrwxr-x 11 kali kali 4,0K dec 5 09:51 var
لنقم ببعض الاستكشاف باستخدام مجموعة مختلفة من خيارات unblob:```
unblob -e /tmp/out -f -k -d 3 --report /tmp/report.json
--log /tmp/unblob.log CHARXSEC3XXXSoftwareBundleV190.raucb
هنا نستمر في الاستخراج (`-e`) إلى `/tmp/out` لكننا نفرض (`-f`) الكتابة فوق مع الاحتفاظ (`-k`) بالقطع المستخرجة مع تحديد عمق التكرار (`-d`) إلى 3. نكتب تقريرًا مفصلاً (`--report`) إلى `/tmp/report.json` وملف سجل (`--log`) إلى `/tmp/unblob.log`.
ألقِ نظرة على ملف السجل، سترى آلية عمل unblob الداخلية.
يحتوي ملف التقرير على معلومات مفصلة حول الملفات التي تم تحليلها (الحجم، نوع الملف، المسار، التوقيع السحري، نوع MIME، تجزئات MD5/SHA1/SHA256)، والقطع (الحجم، الإزاحات، توزيع الإنتروبيا)، والمهام (الاستخراج، فك الضغط، القص). من الممكن توليد تصورات رائعة من هذه الملفات بقليل من Python.
يمكنك إنشاؤها بنفسك باستخدام سكربت بايثون `diagram.py` المتوفر في هذا المستودع:```
python3 diagram.py /tmp/report.json sunburst
python3 diagram.py /tmp/report.json treemap
ستفتح هذه الأوامر المتصفح على صفحة تحتوي على تصوّر مبني على plotly مثل التصورات أدناه:


الآن بعد أن أصبح لدينا فهم أفضل لما بداخل الجهاز، حان الوقت لسرد ما نحتاجه للقيام بمحاكاة صحيحة للجهاز.
من الناحية المثالية، نحتاج إلى جمع هذه المعلومات:
للحصول على بعض التفاصيل حول المنصة والمعالج والبنية، يمكننا الاطلاع على كائنات شجرة الجهاز المدمجة داخل البرنامج الثابت.
في قسم VFAT، لدينا ملفات DTB التالية:``` oftree: Device Tree Blob version 17, size=27469, boot CPU=0, string block size=1657, DT structure block size=25756 zImage-imx6ul-ksp0632.dtb: Device Tree Blob version 17, size=27469, boot CPU=0, string block size=1657, DT structure block size=25756
هذه الملفات هي تمثيل ثنائي لأشجار الأجهزة. يمكننا استعادة مصدر النص العادي الخاص بها باستخدام `device-tree-compiler`:```
dtc -I dtb -o zImage-imx6ul-ksp0632.dts zImage-imx6ul-ksp0632.dtb
dtc -I dtb -o oftree.dts oftree
ألقِ نظرةً على DTS، وستجد قريبًا تفاصيل مثيرة للاهتمام مثل الطراز:``` /dts-v1/;
/ { #address-cells = <0x01>; #size-cells = <0x01>; model = "Phytec phyBOARD-Segin i.MX6 UltraLite"; <----- right here compatible = "phytec,imx6ul-pbacd-10\0phytec,imx6ul-pcl063\0fsl,imx6ul";
المعالج:```
cpus {
#address-cells = <0x01>;
#size-cells = <0x00>;
cpu@0 {
compatible = "arm,cortex-a7"; <---- here
device_type = "cpu";
reg = <0x00>;
clock-latency = <0xee6c>;
operating-points = <0xa9ec0 0x137478 0x80e80 0x11edd8 0x60ae0 0xfa3e8 0x30570 0xe7ef0>;
fsl,soc-operating-points = <0xa9ec0 0x137478 0x80e80 0x11edd8 0x60ae0 0x11edd8 0x30570 0x11edd8>;
clocks = <0x01 0x5d 0x01 0x1a 0x01 0x26 0x01 0xdb 0x01 0x38 0x01 0x39 0x01 0x19>;
clock-names = "arm\0pll2_bus\0pll2_pfd2_396m\0secondary_sel\0step\0pll1_sw\0pll1_sys";
arm-supply = <0x02>;
soc-supply = <0x03>;
dc-supply = <0x04>;
};
};
أو حتى الأجهزة الطرفية:``` --snip-- ethernet@2188000 { compatible = "fsl,imx6ul-fec\0fsl,imx6q-fec"; reg = <0x2188000 0x4000>; interrupts = <0x00 0x76 0x04 0x00 0x77 0x04>; clocks = <0x01 0x90 0x01 0x91 0x01 0x30 0x01 0x2c 0x01 0x2c>; clock-names = "ipg\0ahb\0ptp\0enet_clk_ref\0enet_out"; fsl,num-tx-queues = <0x01>; fsl,num-rx-queues = <0x01>; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <0x23>; phy-mode = "rmii"; phy-handle = <0x24>;
mdio {
#address-cells = <0x01>;
#size-cells = <0x00>;
ethernet-phy@1 {
reg = <0x01>;
interrupt-parent = <0x0b>;
interrupts = <0x02 0x08>;
micrel,led-mode = <0x01>;
clocks = <0x01 0x2c>;
clock-names = "rmii-ref";
status = "okay";
linux,phandle = <0x24>;
phandle = <0x24>;
};
ethernet-phy@2 {
reg = <0x03>;
micrel,led-mode = <0x01>;
clocks = <0x01 0x2d>;
clock-names = "rmii-ref";
status = "okay";
linux,phandle = <0x13>;
phandle = <0x13>;
};
};
};
--snip-- flexcan@2090000 { compatible = "fsl,imx6ul-flexcan\0fsl,imx6q-flexcan"; reg = <0x2090000 0x4000>; interrupts = <0x00 0x6e 0x04>; clocks = <0x01 0x94 0x01 0x95>; clock-names = "ipg\0per"; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <0x0f>; xceiver-supply = <0x10>; };
flexcan@2094000 { compatible = "fsl,imx6ul-flexcan\0fsl,imx6q-flexcan"; reg = <0x2094000 0x4000>; interrupts = <0x00 0x6f 0x04>; clocks = <0x01 0x96 0x01 0x97>; clock-names = "ipg\0per"; status = "disabled"; };
### معلومات إصدار نواة Linux
يمكننا تحديد إصدار نواة Linux عن طريق البحث بـ `grep` داخل قسم VFAT الذي يحتوي على النواة المضغوطة:```
grep 'Linux version' . -ra
./zImage_extract/7296-6371487.lzo_extract/7296-6371487:
Linux version 5.15.195 (oe-user@oe-host) (gcc version 8.3.0 (GCC)) #1 SMP PREEMPT
./zImage_extract/7296-6371487.lzo_extract/7296-6371487:
Linux version %s (%s)Bluetooth subsystem version %u.%uHCI socket registration failed
طريقة أخرى هي النظر إلى وحدات النواة داخل نظام الملفات الجذر EXT4:```
modinfo ./CHARXSEC3XXXSoftwareBundleV190.raucb_extract/0-138014720.squashfs_v4_le_extract/root.ext4_extract/lib/modules/5.15.195/kernel/net/bluetooth/bnep/bnep.ko.xz
filename: ./CHARXSEC3XXXSoftwareBundleV190.raucb_extract/0-138014720.squashfs_v4_le_extract/root.ext4_extract/lib/modules/5.15.195/kernel/net/bluetooth/bnep/bnep.ko.xz
alias: bt-proto-4
license: GPL
version: 1.3
description: Bluetooth BNEP ver 1.3
author: Marcel Holtmann [email protected]
srcversion: 86266D360814678CE0C94E9
depends:
intree: Y
name: bnep
vermagic: 5.15.195 preempt mod_unload modversions ARMv7 thumb2 p2v8
parm: compress_src:Compress sources headers (bool)
parm: compress_dst:Compress destination headers (bool)
## المحاكاة
قد يكون لدينا بالفعل نواة مُجمّعة ضمن حزمة البرنامج الثابت، لكن هذه النواة مُجمّعة خصيصًا لجهاز معيّن (Phytec phyBOARD-Segin i.MX6 UltraLite).
لاستخدام هذه النواة بشكل صحيح، سنحتاج إلى القدرة على تشغيل هذه النواة على محاكاة لذلك الجهاز المحدد الذي تم تجميعها له. هذا يستغرق وقتًا طويلاً إذا لم يكن مدرجًا بالفعل في قائمة أجهزة QEMU. ملاحظة: يتوفر جهاز لوحة تقييم في QEMU (`mcimx6ul-evk - Freescale i.MX6UL Evaluation Kit (Cortex-A7)`) لكنه لا يطابق تمامًا.
بدلاً من ذلك، من الناحية النظرية، يمكننا اختيار جهاز QEMU، واستخدام بيانات وصفية متنوعة نجدها في صورة البرنامج الثابت لتهيئة وبناء نواة لهذا الجهاز، والتي ستكون قادرة أيضًا على تشغيل كل شيء في نظام الملفات لدينا، بأقرب ما يمكن من الأصل.
من هنا، لدينا عدة خيارات:
- *محاكاة مساحة المستخدم*: يمكننا الإقلاع إلى ramfs/rootfs مخصصة خاصة بنا، ثم تحميل rootfs للبرنامج الثابت المستهدف والدخول إليه (chroot) لمحاكاته.
- *محاكاة النظام الكامل*: يمكننا محاولة الإقلاع مباشرة من rootfs للبرنامج الثابت المستهدف (تمريره مباشرة إلى جهاز QEMU).
محاكاة مساحة المستخدم عادةً ما تكون محدودة لكنها طريقة رائعة للتحقيق وتصحيح الأخطاء واستغلال برامج ثنائية محددة. نوصي بشدة بإلقاء نظرة على [EMUX](https://github.com/therealsaumil/emux) من Saumil Shah لجميع احتياجات محاكاة مساحة المستخدم.
على أي حال، ما زلنا بحاجة إلى نواة ستقلع داخل جهاز QEMU، وتطابق ما يتوقعه البرنامج الثابت المستهدف، بأقرب ما يمكن.
### أجهزة QEMU
لا يوجد سوى عدد قليل من المرشحين للأجهزة العامة التي توفر مرونة. بعد قدر كبير من التجارب، يبدو أن `virt` (https://qemu.readthedocs.io/en/latest/system/arm/virt.html) يتمتع بنسبة مرونة/قوة جيدة لأغراضنا.
عند بناء النواة لجهاز QEMU معيّن، من الأفضل على الأرجح أن نضمن قدرتنا على استخدام جهاز virtio العام الذي توفره QEMU. في الإعدادات، قد يعني هذا واحدًا أو أكثر من التالي:```
CONFIG_VIRTIO=y
CONFIG_SCSI_VIRTIO=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BLK=y
والمزيد! هذه القائمة غير مكتملة.
من المفيد لنا استخدام نواة تحتوي على سلسلة vermagic مطابقة (أو على الأقل مشابهة جداً). جميع أنواع المكونات داخل النظام قد تتحقق من vermagic النواة، وتفشل إذا كانت مختلفة عن المتوقع. هذا أكثر شيوعاً في وحدات النواة - عادةً ما ترفض النواة تحميل وحدة لا يحتوي vermagic الخاص بها على تطابق مع خاصيتها. بينما يمكننا تعديل النواة لتتجاهل هذا على مستوى النواة، ما زلنا بحاجة إلى أن يتطابق الجزء الأولي “kernel release” من السلسلة مع سلسلة إصدار وحدات النواة، لأنه يُستخدم كمسار بحث لـ modules.dep.
في البرنامج الثابت لـ Phoenix Contact، يكون vermagic هو 5.15.195 preempt mod_unload modversions ARMv7 thumb2 p2v8.
سلسلة vermagic تكون بتنسيق مثل (من include/linux/vermagic.h):```c
#define VERMAGIC_STRING
UTS_RELEASE " "
MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT
MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS
MODULE_ARCH_VERMAGIC
- Kernel release = إصدار النواة + سلسلة `CONFIG_LOCALVERSION`.
- SMP = `CONFIG_SMP`
- PREEMPT = `CONFIG_PREEMPT`
- mod_unload = `CONFIG_MODULE_UNLOAD`
- modversions = `CONFIG_MODVERSIONS`
- ARMv7 thumb2 p2v8 = `MODULE_ARCH_VERMAGIC` (مرتبط بالبنية المعمارية التي يُجمَّع لها النواة، وبالتالي مرتبط بخيار المترجم/البنية المعمارية المُمرَّر.)
بمجرد أن نحصل على الكود المصدري للنواة المستخرج، يمكننا تعديله بحيث لا يكون قاسيًا إلى هذا الحد عند مقارنة سلاسل vermagic. في kernel/module.c، يمكننا ببساطة التعليق على return -ENOEXEC:```diff
} else if (!same_magic(modmagic, vermagic, info->index.vers)) {
pr_err("%s: version magic '%s' should be '%s'\n", info->name, modmagic, vermagic);
- return -ENOEXEC;
+ // return -ENOEXEC;
}
if (!get_modinfo(info, "intree")) {
قد لا يكون مفيدًا على المدى الطويل، لكنه جيّد للاختبار، طالما توجد اختلافات طفيفة بين vermagic لنواتنا وvermagic للوصلة. الوحدات (في الغالب) ستُحمَّل على أي حال.
ملاحظة: هنا نوفر نواة مبنية مسبقًا تطابق متطلبات الهدف حتى لا تحتاج إلى تجميع واحدة بنفسك. لقد بُنيت باستخدام سكربت داخلي يقوم بـ:
multi_v7_defconfig لتعيين الإعدادات الأوليةkernel/module.cVIRTIO والأنظمة الفرعية المحددة مثل
USB أو CANBUSلنستعرض المعاملات المختلفة لأمر qemu-system-arm الخاص بنا. نوفر النواة بهذه الطريقة:```sh
qemu-system-arm -M virt,highmem=off
-m ${AVAILABLE_MEM_GB}G -smp ${CPU_CORES} -cpu cortex-a15
-kernel zImage
صورة نظام الملفات EXT4 مرفقة كقرص SCSI:```sh
-device virtio-scsi-device \
-device scsi-hd,drive=SystemDisk \
-drive file=${FIRMWARE_IMAGE},format=raw,if=none,id=SystemDisk
نضبط مخرجات وحدة التحكم بشكل صحيح بهذه الطريقة:```sh
-append "${BOOT_PARAMS}"
-no-reboot
-nographic
-serial mon:stdio \
تم ضبط `BOOT_PARAMS` في `config.ini` وهي تطابق أمر إقلاع النواة الفعلي، مع تكييفين صغيرين (مسار وحدة التحكم ومسار نظام الجذر).
### الشبكات
الآن بعد أن أصبح لدينا نظام محاكى يعمل، حان الوقت لإعداد الشبكات. الهدف يحتوي على ما يلي:
- واجهتا إيثرنت (`eth0` و `eth1`)
- واجهة CANbus واحدة (`can0`)
- واجهة USB واحدة يمكنها العمل كإيثرنت عبر USB (`usb0`)
- مودم خلوي Qualcomm High Sierra (`ppp0`)
محاكاة المودم الخلوي وواجهات USB أمر شاق مع QEMU، وغير مطلوب حقًا لتشغيل الجهاز لأن تلك الواجهات "اختيارية". واجهة CAN موجودة للسماح لوحدة التحكم بالتحدث مع وحدات تحكم أخرى أو محطات شحن. توفر واجهة `eth0` اتصالًا بالشبكة العلوية عبر طلب عنوان DHCP افتراضيًا، بينما يتم ضبط `eth1` على 192.168.4.1 وهي موجودة إذا كنت تريد توصيل وحدات تحكم متعددة بتسلسل (daisy chain).
تم ضبط واجهات الإيثرنت كواجهات TAP وإرفاقها على النحو التالي:```
-netdev tap,id=tap0net,ifname=${ETH_1},script=no,downscript=no \
-device virtio-net-device,netdev=tap0net,mac=${ETH_1_MAC} \
-netdev tap,id=tap1net,ifname=${ETH_0},script=no,downscript=no \
-device virtio-net-device,netdev=tap1net,mac=${ETH_0_MAC} \
واجهة CANBUS هي ببساطة واجهة PCI، تُوصَّل على النحو التالي:```
-object can-bus,id=canbus0
-device kvaser_pci,canbus=canbus0
-object can-host-socketcan,id=canhost0,if=can0,canbus=canbus0 \
The diagram below present what the network setup looks like:

If you wanted to try inter-controller communication by daisy-chaining them as
recommended by Phoenix Contact, you could use something like this:

## جاهز ? استعد. انطلق !
الآن بعد أن أصبح كل شيء في مكانه، حان وقت تشغيله !
أولاً، تحتاج إلى إعداد جميع واجهات الشبكة على النحو التالي:```
sudo ./ifup.sh
تأكد من أن الواجهة الأولية لديك مضبوطة بشكل صحيح في config.ini:```
OUT_IF="eth0"
يمكنك بعد ذلك تشغيل المحاكي:```
sudo ./launch.sh
سترى العناوين التي تم الحصول عليها في السجلات:``` Dec 5 10:07:46 ev3000 daemon.info avahi-daemon[1047]: Registering new address record for 192.168.4.1 on eth1.IPv4. Dec 5 10:07:46 ev3000 daemon.info avahi-daemon[1047]: Registering new address record for 192.168.88.181 on eth0.IPv4.
### الوصول عبر SSH
يمكنك بعد ذلك استخدام SSH للوصول إلى الجهاز المُحاكى باستخدام مستخدم `user-app`:```sh
ssh [email protected]
كلمة المرور هي "user". سيتم إجبارك على تغييرها عند أول تسجيل دخول:```sh ssh [email protected] The authenticity of host '192.168.88.181 (192.168.88.181)' can't be established. ED25519 key fingerprint is SHA256:qMupzEehNFpx6eaGZ4d3AY5Jlms3Pmxh3/yg9OGA28o. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '192.168.88.181' (ED25519) to the list of known hosts. [email protected]'s password: WARNING: Your password has expired. You must change your password now and login again! Changing password for user-app Old password: Enter the new password (minimum of 5 characters) Please use a combination of upper and lower case letters and numbers. New password: Re-enter new password: passwd: password changed. Connection to 192.168.88.181 closed.
### واجهة الويب
يمكنك الوصول إلى واجهة الويب على http://192.168.4.1. قد تظهر رسالة خطأ
أثناء تشغيل الجهاز. بمجرد أن يصبح كل شيء جاهزًا ويعمل،
يجب أن ترى هذا:

يمكنك تسجيل الدخول باستخدام الحسابات التالية:
| اسم المستخدم | كلمة المرور |
|----------|----------|
| manufacturer | manufacturer |
| operator | operator |
### حركة مرور CAN
عندما يكون كل شيء قيد التشغيل، يمكنك التقاط حركة مرور CAN المنبعثة من
وحدة التحكم:```
candump -i can0
can0 701 [1] 00000101
can0 701 [1] 00000101
can0 701 [1] 00000101
can0 701 [1] 00000101
can0 701 [1] 00000101
can0 701 [1] 00000101
ملاحظة: يبدو أن إصدار QEMU 8.x يواجه بعض الصعوبات في إرفاق وحدة تحكم CAN لسبب ما.