From 7ee9806fbab28744b1d2bc1a859e44888a73573c Mon Sep 17 00:00:00 2001 From: Fr4nzD13trich Date: Thu, 20 Nov 2025 14:05:12 +0100 Subject: [PATCH] Repo created --- CHANGELOG.md | 950 + CODE_OF_CONDUCT.md | 76 + CONTRIBUTING.md | 169 + LICENSE.md | 674 + README.md | 120 +- RELEASING.md | 92 + Resources/XDADevelopers.png | Bin 0 -> 10800 bytes Resources/adaway_screenshot.png | Bin 0 -> 682527 bytes Resources/certificate/generate.sh | 9 + Resources/certificate/ssl.conf | 15 + Resources/device-2013-06-19-105150.png | Bin 0 -> 104885 bytes Resources/device-2013-06-19-105158.png | Bin 0 -> 92833 bytes Resources/device-2013-06-19-105215.png | Bin 0 -> 139762 bytes Resources/download_fdroid.png | Bin 0 -> 5575 bytes Resources/download_google_play.png | Bin 0 -> 4095 bytes Resources/get-it-on-adaway.png | Bin 0 -> 18110 bytes Resources/get-it-on-fdroid.png | Bin 0 -> 14224 bytes Resources/icon.svg | 112 + Resources/icon.xcf | Bin 0 -> 88240 bytes Resources/icon_background.png | Bin 0 -> 2649 bytes Resources/icon_background.xcf | Bin 0 -> 62904 bytes Resources/icon_foreground.png | Bin 0 -> 3335 bytes Resources/icon_foreground.xcf | Bin 0 -> 26898 bytes Resources/icon_old.svg | 356 + Resources/logo_googlecode.png | Bin 0 -> 4448 bytes Resources/logo_market.png | Bin 0 -> 75754 bytes Resources/paypal_donate_button.gif | Bin 0 -> 1714 bytes Resources/screenshot1.png | Bin 0 -> 30562 bytes Resources/screenshot2.png | Bin 0 -> 30276 bytes Resources/screenshot3.png | Bin 0 -> 38527 bytes Resources/screenshot4.png | Bin 0 -> 16717 bytes Resources/screenshot5.png | Bin 0 -> 27802 bytes Resources/screenshot6.png | Bin 0 -> 44273 bytes Resources/status_bar_icon.svg | 358 + Resources/symlink_hosts_to_data.zip | Bin 0 -> 141823 bytes Resources/tasker/1-create-tasks.jpg | Bin 0 -> 43448 bytes Resources/tasker/2-enable-adblock-task.jpg | Bin 0 -> 48077 bytes .../tasker/3-enable-adblock-task-details1.jpg | Bin 0 -> 91067 bytes .../tasker/4-enable-adblock-task-details2.jpg | Bin 0 -> 95768 bytes Resources/tasker/5-disable-adblock-task.jpg | Bin 0 -> 48273 bytes .../6-disable-adblock-task-details1.jpg | Bin 0 -> 90967 bytes .../7-disable-adblock-task-details2.jpg | Bin 0 -> 94214 bytes Resources/test-webserver.sh | 16 + THIRD_PARTY_LICENSES.md | 78 + TRANSLATING.md | 39 + app/.gitignore | 36 + app/build.gradle | 149 + app/lint.xml | 10 + app/proguard-rules.pro | 38 + app/schemas/org.adaway.db.AppDatabase/1.json | 90 + app/schemas/org.adaway.db.AppDatabase/2.json | 146 + app/schemas/org.adaway.db.AppDatabase/3.json | 151 + app/schemas/org.adaway.db.AppDatabase/4.json | 187 + app/schemas/org.adaway.db.AppDatabase/5.json | 187 + app/schemas/org.adaway.db.AppDatabase/6.json | 211 + app/schemas/org.adaway.db.AppDatabase/7.json | 221 + .../java/org/adaway/db/DbTest.java | 151 + .../java/org/adaway/db/HostDbTest.java | 90 + .../java/org/adaway/db/SourceDbTest.java | 113 + .../java/org/adaway/db/UserListTest.java | 157 + app/src/main/AndroidManifest.xml | 177 + app/src/main/assets/icon.svg | 113 + app/src/main/assets/localhost-2410.crt | 20 + app/src/main/assets/localhost-2410.key | 28 + app/src/main/assets/test.html | 13 + app/src/main/icon-web.png | Bin 0 -> 15501 bytes .../java/org/adaway/AdAwayApplication.java | 76 + .../org/adaway/broadcast/BootReceiver.java | 64 + .../java/org/adaway/broadcast/Command.java | 57 + .../org/adaway/broadcast/CommandReceiver.java | 53 + .../org/adaway/broadcast/UpdateReceiver.java | 28 + .../main/java/org/adaway/db/AppDatabase.java | 134 + .../main/java/org/adaway/db/Migrations.java | 123 + .../db/converter/ListTypeConverter.java | 26 + .../db/converter/ZonedDateTimeConverter.java | 30 + .../java/org/adaway/db/dao/HostEntryDao.java | 78 + .../org/adaway/db/dao/HostListItemDao.java | 63 + .../org/adaway/db/dao/HostsSourceDao.java | 80 + .../java/org/adaway/db/entity/HostEntry.java | 50 + .../org/adaway/db/entity/HostListItem.java | 121 + .../org/adaway/db/entity/HostsSource.java | 187 + .../java/org/adaway/db/entity/ListType.java | 31 + .../java/org/adaway/db/entity/SourceType.java | 21 + .../org/adaway/helper/NotificationHelper.java | 167 + .../org/adaway/helper/PreferenceHelper.java | 361 + .../java/org/adaway/helper/ThemeHelper.java | 29 + .../model/adblocking/AdBlockMethod.java | 40 + .../adaway/model/adblocking/AdBlockModel.java | 140 + .../model/adblocking/UndefinedBlockModel.java | 59 + .../adaway/model/backup/AppBackupAgent.java | 82 + .../adaway/model/backup/BackupExporter.java | 141 + .../org/adaway/model/backup/BackupFormat.java | 84 + .../adaway/model/backup/BackupImporter.java | 136 + .../org/adaway/model/error/HostError.java | 44 + .../model/error/HostErrorException.java | 43 + .../org/adaway/model/git/GistHostsSource.java | 61 + .../model/git/GitHostsJsonApiSource.java | 53 + .../org/adaway/model/git/GitHostsSource.java | 65 + .../adaway/model/git/GitHubHostsSource.java | 84 + .../adaway/model/git/GitLabHostsSource.java | 81 + .../adaway/model/root/CommandException.java | 30 + .../java/org/adaway/model/root/MountType.java | 31 + .../java/org/adaway/model/root/RootModel.java | 319 + .../org/adaway/model/root/ShellUtils.java | 99 + .../org/adaway/model/root/TcpdumpUtils.java | 202 + .../org/adaway/model/root/package-info.java | 9 + .../org/adaway/model/source/SourceLoader.java | 267 + .../org/adaway/model/source/SourceModel.java | 508 + .../model/source/SourceUpdateService.java | 176 + .../model/update/ApkDownloadReceiver.java | 48 + .../adaway/model/update/ApkUpdateService.java | 112 + .../org/adaway/model/update/Manifest.java | 24 + .../org/adaway/model/update/UpdateModel.java | 203 + .../org/adaway/model/update/UpdateStore.java | 120 + .../java/org/adaway/model/vpn/VpnModel.java | 124 + .../adaway/tile/AdBlockingTileService.java | 81 + .../main/java/org/adaway/ui/Animations.java | 104 + .../ApplyConfigurationSnackbar.java | 191 + .../org/adaway/ui/adware/AdwareFragment.java | 145 + .../org/adaway/ui/adware/AdwareInstall.java | 43 + .../org/adaway/ui/adware/AdwareLiveData.java | 154 + .../org/adaway/ui/adware/AdwareViewModel.java | 37 + .../ui/dialog/AlertDialogValidator.java | 55 + .../adaway/ui/dialog/MissingAppDialog.java | 110 + .../java/org/adaway/ui/help/HelpActivity.java | 108 + .../org/adaway/ui/help/HelpFragmentHtml.java | 96 + .../java/org/adaway/ui/home/HomeActivity.java | 366 + .../org/adaway/ui/home/HomeViewModel.java | 182 + .../adaway/ui/hosts/HostsSourcesActivity.java | 41 + .../adaway/ui/hosts/HostsSourcesAdapter.java | 208 + .../adaway/ui/hosts/HostsSourcesFragment.java | 119 + .../ui/hosts/HostsSourcesViewCallback.java | 33 + .../ui/hosts/HostsSourcesViewModel.java | 38 + .../org/adaway/ui/lists/ListsActivity.java | 185 + .../java/org/adaway/ui/lists/ListsFilter.java | 33 + .../ui/lists/ListsFragmentPagerAdapter.java | 110 + .../adaway/ui/lists/ListsViewCallback.java | 36 + .../org/adaway/ui/lists/ListsViewModel.java | 160 + .../ui/lists/type/AbstractListFragment.java | 203 + .../ui/lists/type/AllowedHostsFragment.java | 132 + .../ui/lists/type/BlockedHostsFragment.java | 131 + .../adaway/ui/lists/type/ListsAdapter.java | 131 + .../lists/type/RedirectedHostsFragment.java | 156 + .../java/org/adaway/ui/log/LogActivity.java | 235 + .../java/org/adaway/ui/log/LogAdapter.java | 107 + .../main/java/org/adaway/ui/log/LogEntry.java | 61 + .../java/org/adaway/ui/log/LogEntrySort.java | 70 + .../org/adaway/ui/log/LogViewCallback.java | 49 + .../java/org/adaway/ui/log/LogViewModel.java | 151 + .../org/adaway/ui/prefs/PrefsActivity.java | 96 + .../ui/prefs/PrefsBackupRestoreFragment.java | 115 + .../adaway/ui/prefs/PrefsMainFragment.java | 81 + .../adaway/ui/prefs/PrefsRootFragment.java | 284 + .../adaway/ui/prefs/PrefsUpdateFragment.java | 127 + .../org/adaway/ui/prefs/PrefsVpnFragment.java | 81 + .../exclusion/ExcludedAppController.java | 26 + .../PrefsVpnExcludedAppsActivity.java | 131 + .../adaway/ui/prefs/exclusion/UserApp.java | 27 + .../exclusion/UserAppRecycleViewAdapter.java | 83 + .../adaway/ui/source/SourceEditActivity.java | 257 + .../adaway/ui/support/SupportActivity.java | 87 + .../ui/update/CompleteDownloadStatus.java | 22 + .../org/adaway/ui/update/DownloadStatus.java | 23 + .../ui/update/PendingDownloadStatus.java | 52 + .../org/adaway/ui/update/UpdateActivity.java | 86 + .../org/adaway/ui/update/UpdateViewModel.java | 105 + .../adaway/ui/welcome/WelcomeActivity.java | 155 + .../adaway/ui/welcome/WelcomeFragment.java | 30 + .../ui/welcome/WelcomeMethodFragment.java | 126 + .../adaway/ui/welcome/WelcomeNavigable.java | 11 + .../ui/welcome/WelcomePagerAdapter.java | 43 + .../ui/welcome/WelcomeSupportFragment.java | 76 + .../ui/welcome/WelcomeSyncFragment.java | 117 + .../java/org/adaway/util/AppExecutors.java | 82 + .../main/java/org/adaway/util/Clipboard.java | 38 + .../main/java/org/adaway/util/Constants.java | 39 + .../main/java/org/adaway/util/RegexUtils.java | 125 + .../java/org/adaway/util/WebServerUtils.java | 192 + .../org/adaway/util/log/ApplicationLog.java | 44 + .../java/org/adaway/util/log/SentryLog.java | 81 + .../main/java/org/adaway/vpn/VpnService.java | 371 + .../org/adaway/vpn/VpnServiceControls.java | 100 + .../org/adaway/vpn/VpnServiceHeartbeat.java | 92 + .../main/java/org/adaway/vpn/VpnStatus.java | 47 + .../org/adaway/vpn/dns/DnsPacketProxy.java | 278 + .../java/org/adaway/vpn/dns/DnsQuery.java | 100 + .../org/adaway/vpn/dns/DnsQueryQueue.java | 106 + .../org/adaway/vpn/dns/DnsServerMapper.java | 307 + .../org/adaway/vpn/dns/DohPacketProxy.java | 299 + .../main/java/org/adaway/vpn/dns/Subnet.java | 67 + .../org/adaway/vpn/worker/VpnBuilder.java | 137 + .../vpn/worker/VpnConnectionMonitor.java | 139 + .../vpn/worker/VpnConnectionThrottler.java | 74 + .../vpn/worker/VpnNetworkException.java | 12 + .../org/adaway/vpn/worker/VpnWatchdog.java | 182 + .../java/org/adaway/vpn/worker/VpnWorker.java | 341 + .../res/animator/fragment_close_enter.xml | 46 + .../main/res/animator/fragment_close_exit.xml | 46 + .../main/res/animator/fragment_open_enter.xml | 47 + .../main/res/animator/fragment_open_exit.xml | 46 + .../main/res/drawable/baseline_block_24.xml | 10 + .../main/res/drawable/baseline_check_24.xml | 10 + .../res/drawable/baseline_clear_all_24.xml | 10 + .../drawable/baseline_compare_arrows_24.xml | 10 + .../main/res/drawable/baseline_edit_24.xml | 10 + .../res/drawable/baseline_favorite_24.xml | 10 + .../main/res/drawable/baseline_search_24.xml | 10 + .../drawable/baseline_sort_by_alpha_24.xml | 10 + app/src/main/res/drawable/dot.xml | 4 + app/src/main/res/drawable/dot_outline.xml | 6 + .../main/res/drawable/ic_add_black_24px.xml | 9 + .../drawable/ic_add_circle_outline_24dp.xml | 10 + .../drawable/ic_brightness_medium_24dp.xml | 10 + .../main/res/drawable/ic_bug_report_24dp.xml | 10 + .../main/res/drawable/ic_cloud_off_24dp.xml | 10 + .../drawable/ic_collections_bookmark_24dp.xml | 10 + .../res/drawable/ic_error_outline_24dp.xml | 10 + app/src/main/res/drawable/ic_get_app_24dp.xml | 10 + app/src/main/res/drawable/ic_github_24dp.xml | 11 + app/src/main/res/drawable/ic_github_32dp.xml | 11 + app/src/main/res/drawable/ic_help_24dp.xml | 10 + app/src/main/res/drawable/ic_ipv6_24dp.xml | 22 + .../main/res/drawable/ic_language_24dp.xml | 10 + app/src/main/res/drawable/ic_language_red.xml | 16 + app/src/main/res/drawable/ic_list_red.xml | 16 + app/src/main/res/drawable/ic_menu_24dp.xml | 10 + .../main/res/drawable/ic_outline_rule_24.xml | 10 + app/src/main/res/drawable/ic_pause_24dp.xml | 10 + .../res/drawable/ic_playlist_add_24dp.xml | 10 + app/src/main/res/drawable/ic_record_24dp.xml | 10 + .../ic_remove_circle_outline_24dp.xml | 10 + app/src/main/res/drawable/ic_save_24dp.xml | 10 + .../main/res/drawable/ic_sd_storage_24dp.xml | 10 + .../main/res/drawable/ic_settings_24dp.xml | 10 + .../ic_settings_backup_restore_24dp.xml | 10 + app/src/main/res/drawable/ic_settings_red.xml | 16 + .../main/res/drawable/ic_superuser_24dp.xml | 10 + app/src/main/res/drawable/ic_sync_24dp.xml | 10 + app/src/main/res/drawable/ic_vpn_key_24dp.xml | 10 + app/src/main/res/drawable/icon_monochrome.xml | 9 + app/src/main/res/drawable/logo.xml | 10 + .../res/drawable/notifications_off_24.xml | 10 + .../res/drawable/outline_cloud_upload_24.xml | 10 + .../main/res/drawable/outline_create_24.xml | 10 + .../main/res/drawable/outline_delete_24.xml | 10 + app/src/main/res/drawable/paypal.xml | 19 + app/src/main/res/drawable/shadow.xml | 7 + app/src/main/res/layout/adware_fragment.xml | 60 + .../main/res/layout/checkbox_list_entry.xml | 40 + .../res/layout/checkbox_list_two_entries.xml | 55 + app/src/main/res/layout/drawer_list_item.xml | 11 + app/src/main/res/layout/help_activity.xml | 18 + app/src/main/res/layout/help_fragment.xml | 12 + app/src/main/res/layout/home_activity.xml | 48 + app/src/main/res/layout/home_content.xml | 565 + .../res/layout/hosts_content_fragment.xml | 80 + .../main/res/layout/hosts_lists_fragment.xml | 16 + .../res/layout/hosts_sources_activity.xml | 7 + .../main/res/layout/hosts_sources_card.xml | 89 + .../main/res/layout/hosts_sources_dialog.xml | 25 + .../res/layout/hosts_sources_fragment.xml | 29 + app/src/main/res/layout/list_two_entries.xml | 42 + app/src/main/res/layout/lists_activity.xml | 7 + .../main/res/layout/lists_allowed_dialog.xml | 29 + .../main/res/layout/lists_blocked_dialog.xml | 24 + app/src/main/res/layout/lists_fragment.xml | 57 + .../res/layout/lists_redirected_dialog.xml | 40 + app/src/main/res/layout/log_activity.xml | 55 + app/src/main/res/layout/log_entry.xml | 63 + .../main/res/layout/log_redirect_dialog.xml | 24 + .../main/res/layout/pref_edittext_dialog.xml | 16 + app/src/main/res/layout/prefs_activity.xml | 7 + app/src/main/res/layout/reboot_dialog.xml | 23 + .../main/res/layout/source_edit_activity.xml | 156 + app/src/main/res/layout/support_activity.xml | 99 + app/src/main/res/layout/update_actity.xml | 167 + .../res/layout/vpn_excluded_app_activity.xml | 8 + .../res/layout/vpn_excluded_app_entry.xml | 58 + app/src/main/res/layout/welcome_activity.xml | 86 + .../main/res/layout/welcome_method_layout.xml | 300 + .../res/layout/welcome_support_layout.xml | 140 + .../main/res/layout/welcome_sync_layout.xml | 115 + .../main/res/menu/checkbox_list_context.xml | 11 + app/src/main/res/menu/home_drawer.xml | 14 + app/src/main/res/menu/list_menu.xml | 15 + app/src/main/res/menu/lists_navigation.xml | 17 + app/src/main/res/menu/log_menu.xml | 13 + app/src/main/res/menu/next_actions.xml | 14 + app/src/main/res/menu/source_edit_menu.xml | 14 + .../main/res/menu/vpn_excluded_app_menu.xml | 11 + app/src/main/res/mipmap-anydpi/icon.xml | 6 + app/src/main/res/mipmap-anydpi/icon_round.xml | 6 + .../mipmap-anydpi/shortcut_dns_requests.xml | 5 + .../mipmap-anydpi/shortcut_preferences.xml | 5 + .../res/mipmap-anydpi/shortcut_your_lists.xml | 5 + app/src/main/res/mipmap-hdpi/icon.png | Bin 0 -> 1923 bytes .../main/res/mipmap-hdpi/icon_foreground.png | Bin 0 -> 1653 bytes app/src/main/res/mipmap-hdpi/icon_round.png | Bin 0 -> 3503 bytes app/src/main/res/mipmap-mdpi/icon.png | Bin 0 -> 1155 bytes .../main/res/mipmap-mdpi/icon_foreground.png | Bin 0 -> 1114 bytes app/src/main/res/mipmap-mdpi/icon_round.png | Bin 0 -> 2235 bytes app/src/main/res/mipmap-xhdpi/icon.png | Bin 0 -> 2274 bytes .../main/res/mipmap-xhdpi/icon_foreground.png | Bin 0 -> 2181 bytes app/src/main/res/mipmap-xhdpi/icon_round.png | Bin 0 -> 5016 bytes app/src/main/res/mipmap-xxhdpi/icon.png | Bin 0 -> 5384 bytes .../res/mipmap-xxhdpi/icon_foreground.png | Bin 0 -> 3400 bytes app/src/main/res/mipmap-xxhdpi/icon_round.png | Bin 0 -> 7721 bytes app/src/main/res/mipmap-xxxhdpi/icon.png | Bin 0 -> 4715 bytes .../res/mipmap-xxxhdpi/icon_foreground.png | Bin 0 -> 4944 bytes .../main/res/mipmap-xxxhdpi/icon_round.png | Bin 0 -> 10956 bytes app/src/main/res/raw-af/help_faq.html | 32 + app/src/main/res/raw-af/help_problems.html | 36 + app/src/main/res/raw-af/help_s_on_s_off.html | 31 + app/src/main/res/raw-ar/help_faq.html | 32 + app/src/main/res/raw-ar/help_problems.html | 36 + app/src/main/res/raw-ar/help_s_on_s_off.html | 31 + app/src/main/res/raw-ast/help_faq.html | 32 + app/src/main/res/raw-ast/help_problems.html | 36 + app/src/main/res/raw-ast/help_s_on_s_off.html | 31 + app/src/main/res/raw-az/help_faq.html | 32 + app/src/main/res/raw-az/help_problems.html | 36 + app/src/main/res/raw-az/help_s_on_s_off.html | 31 + app/src/main/res/raw-be/help_faq.html | 32 + app/src/main/res/raw-be/help_problems.html | 37 + app/src/main/res/raw-be/help_s_on_s_off.html | 31 + app/src/main/res/raw-bg/help_faq.html | 32 + app/src/main/res/raw-bg/help_problems.html | 36 + app/src/main/res/raw-bg/help_s_on_s_off.html | 32 + app/src/main/res/raw-bn/help_faq.html | 32 + app/src/main/res/raw-bn/help_problems.html | 36 + app/src/main/res/raw-bn/help_s_on_s_off.html | 31 + app/src/main/res/raw-ca/help_faq.html | 32 + app/src/main/res/raw-ca/help_problems.html | 36 + app/src/main/res/raw-ca/help_s_on_s_off.html | 31 + app/src/main/res/raw-cs/help_faq.html | 32 + app/src/main/res/raw-cs/help_problems.html | 36 + app/src/main/res/raw-cs/help_s_on_s_off.html | 31 + app/src/main/res/raw-da/help_faq.html | 32 + app/src/main/res/raw-da/help_problems.html | 36 + app/src/main/res/raw-da/help_s_on_s_off.html | 31 + app/src/main/res/raw-de/help_faq.html | 32 + app/src/main/res/raw-de/help_problems.html | 36 + app/src/main/res/raw-de/help_s_on_s_off.html | 31 + app/src/main/res/raw-el/help_faq.html | 30 + app/src/main/res/raw-el/help_problems.html | 36 + app/src/main/res/raw-el/help_s_on_s_off.html | 31 + app/src/main/res/raw-en-rUS/help_faq.html | 32 + .../main/res/raw-en-rUS/help_problems.html | 36 + .../main/res/raw-en-rUS/help_s_on_s_off.html | 31 + app/src/main/res/raw-eo/help_faq.html | 32 + app/src/main/res/raw-eo/help_problems.html | 36 + app/src/main/res/raw-eo/help_s_on_s_off.html | 31 + app/src/main/res/raw-es-rMX/help_faq.html | 31 + .../main/res/raw-es-rMX/help_problems.html | 36 + .../main/res/raw-es-rMX/help_s_on_s_off.html | 31 + app/src/main/res/raw-es/help_faq.html | 32 + app/src/main/res/raw-es/help_problems.html | 36 + app/src/main/res/raw-es/help_s_on_s_off.html | 31 + app/src/main/res/raw-et/help_faq.html | 32 + app/src/main/res/raw-et/help_problems.html | 36 + app/src/main/res/raw-et/help_s_on_s_off.html | 31 + app/src/main/res/raw-eu/help_faq.html | 32 + app/src/main/res/raw-eu/help_problems.html | 36 + app/src/main/res/raw-eu/help_s_on_s_off.html | 31 + app/src/main/res/raw-fa/help_faq.html | 31 + app/src/main/res/raw-fa/help_problems.html | 37 + app/src/main/res/raw-fa/help_s_on_s_off.html | 31 + app/src/main/res/raw-fi/help_faq.html | 32 + app/src/main/res/raw-fi/help_problems.html | 36 + app/src/main/res/raw-fi/help_s_on_s_off.html | 32 + app/src/main/res/raw-fil/help_faq.html | 32 + app/src/main/res/raw-fil/help_problems.html | 36 + app/src/main/res/raw-fil/help_s_on_s_off.html | 31 + app/src/main/res/raw-fr/help_faq.html | 32 + app/src/main/res/raw-fr/help_problems.html | 36 + app/src/main/res/raw-fr/help_s_on_s_off.html | 31 + app/src/main/res/raw-gl/help_faq.html | 32 + app/src/main/res/raw-gl/help_problems.html | 36 + app/src/main/res/raw-gl/help_s_on_s_off.html | 31 + app/src/main/res/raw-hi/help_faq.html | 32 + app/src/main/res/raw-hi/help_problems.html | 36 + app/src/main/res/raw-hi/help_s_on_s_off.html | 31 + app/src/main/res/raw-hr/help_faq.html | 32 + app/src/main/res/raw-hr/help_problems.html | 36 + app/src/main/res/raw-hr/help_s_on_s_off.html | 31 + app/src/main/res/raw-hu/help_faq.html | 32 + app/src/main/res/raw-hu/help_problems.html | 36 + app/src/main/res/raw-hu/help_s_on_s_off.html | 31 + app/src/main/res/raw-in/help_faq.html | 32 + app/src/main/res/raw-in/help_problems.html | 36 + app/src/main/res/raw-in/help_s_on_s_off.html | 31 + app/src/main/res/raw-is/help_faq.html | 32 + app/src/main/res/raw-is/help_problems.html | 36 + app/src/main/res/raw-is/help_s_on_s_off.html | 31 + app/src/main/res/raw-it/help_faq.html | 32 + app/src/main/res/raw-it/help_problems.html | 36 + app/src/main/res/raw-it/help_s_on_s_off.html | 31 + app/src/main/res/raw-iw/help_faq.html | 32 + app/src/main/res/raw-iw/help_problems.html | 36 + app/src/main/res/raw-iw/help_s_on_s_off.html | 31 + app/src/main/res/raw-ja/help_faq.html | 32 + app/src/main/res/raw-ja/help_problems.html | 35 + app/src/main/res/raw-ja/help_s_on_s_off.html | 33 + app/src/main/res/raw-km/help_faq.html | 32 + app/src/main/res/raw-km/help_problems.html | 36 + app/src/main/res/raw-km/help_s_on_s_off.html | 31 + app/src/main/res/raw-ko/help_faq.html | 32 + app/src/main/res/raw-ko/help_problems.html | 36 + app/src/main/res/raw-ko/help_s_on_s_off.html | 33 + app/src/main/res/raw-ku/help_faq.html | 32 + app/src/main/res/raw-ku/help_problems.html | 36 + app/src/main/res/raw-ku/help_s_on_s_off.html | 31 + app/src/main/res/raw-lt/help_faq.html | 32 + app/src/main/res/raw-lt/help_problems.html | 36 + app/src/main/res/raw-lt/help_s_on_s_off.html | 31 + app/src/main/res/raw-ml/help_faq.html | 32 + app/src/main/res/raw-ml/help_problems.html | 36 + app/src/main/res/raw-ml/help_s_on_s_off.html | 31 + app/src/main/res/raw-ms/help_faq.html | 32 + app/src/main/res/raw-ms/help_problems.html | 36 + app/src/main/res/raw-ms/help_s_on_s_off.html | 31 + app/src/main/res/raw-my/help_faq.html | 32 + app/src/main/res/raw-my/help_problems.html | 36 + app/src/main/res/raw-my/help_s_on_s_off.html | 31 + app/src/main/res/raw-nb-rNO/help_faq.html | 32 + .../main/res/raw-nb-rNO/help_problems.html | 36 + .../main/res/raw-nb-rNO/help_s_on_s_off.html | 31 + app/src/main/res/raw-ne/help_faq.html | 32 + app/src/main/res/raw-ne/help_problems.html | 36 + app/src/main/res/raw-ne/help_s_on_s_off.html | 31 + app/src/main/res/raw-nl/help_faq.html | 32 + app/src/main/res/raw-nl/help_problems.html | 36 + app/src/main/res/raw-nl/help_s_on_s_off.html | 31 + app/src/main/res/raw-no/help_faq.html | 32 + app/src/main/res/raw-no/help_problems.html | 36 + app/src/main/res/raw-no/help_s_on_s_off.html | 31 + app/src/main/res/raw-pa/help_faq.html | 32 + app/src/main/res/raw-pa/help_problems.html | 36 + app/src/main/res/raw-pa/help_s_on_s_off.html | 31 + app/src/main/res/raw-pl/help_faq.html | 32 + app/src/main/res/raw-pl/help_problems.html | 36 + app/src/main/res/raw-pl/help_s_on_s_off.html | 31 + app/src/main/res/raw-ps/help_faq.html | 32 + app/src/main/res/raw-ps/help_problems.html | 36 + app/src/main/res/raw-ps/help_s_on_s_off.html | 31 + app/src/main/res/raw-pt-rBR/help_faq.html | 32 + .../main/res/raw-pt-rBR/help_problems.html | 36 + .../main/res/raw-pt-rBR/help_s_on_s_off.html | 31 + app/src/main/res/raw-pt/help_faq.html | 32 + app/src/main/res/raw-pt/help_problems.html | 36 + app/src/main/res/raw-pt/help_s_on_s_off.html | 31 + app/src/main/res/raw-ro/help_faq.html | 32 + app/src/main/res/raw-ro/help_problems.html | 36 + app/src/main/res/raw-ro/help_s_on_s_off.html | 31 + app/src/main/res/raw-ru/help_faq.html | 32 + app/src/main/res/raw-ru/help_problems.html | 37 + app/src/main/res/raw-ru/help_s_on_s_off.html | 31 + app/src/main/res/raw-si/help_faq.html | 32 + app/src/main/res/raw-si/help_problems.html | 36 + app/src/main/res/raw-si/help_s_on_s_off.html | 31 + app/src/main/res/raw-sk/help_faq.html | 32 + app/src/main/res/raw-sk/help_problems.html | 36 + app/src/main/res/raw-sk/help_s_on_s_off.html | 31 + app/src/main/res/raw-sl/help_faq.html | 32 + app/src/main/res/raw-sl/help_problems.html | 36 + app/src/main/res/raw-sl/help_s_on_s_off.html | 31 + app/src/main/res/raw-sq/help_faq.html | 32 + app/src/main/res/raw-sq/help_problems.html | 36 + app/src/main/res/raw-sq/help_s_on_s_off.html | 31 + app/src/main/res/raw-sr/help_faq.html | 32 + app/src/main/res/raw-sr/help_problems.html | 36 + app/src/main/res/raw-sr/help_s_on_s_off.html | 31 + app/src/main/res/raw-sv/help_faq.html | 32 + app/src/main/res/raw-sv/help_problems.html | 36 + app/src/main/res/raw-sv/help_s_on_s_off.html | 31 + app/src/main/res/raw-ta/help_faq.html | 32 + app/src/main/res/raw-ta/help_problems.html | 36 + app/src/main/res/raw-ta/help_s_on_s_off.html | 31 + app/src/main/res/raw-th/help_faq.html | 31 + app/src/main/res/raw-th/help_problems.html | 36 + app/src/main/res/raw-th/help_s_on_s_off.html | 33 + app/src/main/res/raw-tl/help_faq.html | 32 + app/src/main/res/raw-tl/help_problems.html | 36 + app/src/main/res/raw-tl/help_s_on_s_off.html | 31 + app/src/main/res/raw-tr/help_faq.html | 32 + app/src/main/res/raw-tr/help_problems.html | 36 + app/src/main/res/raw-tr/help_s_on_s_off.html | 33 + app/src/main/res/raw-uk/help_faq.html | 32 + app/src/main/res/raw-uk/help_problems.html | 36 + app/src/main/res/raw-uk/help_s_on_s_off.html | 31 + app/src/main/res/raw-ur/help_faq.html | 32 + app/src/main/res/raw-ur/help_problems.html | 36 + app/src/main/res/raw-ur/help_s_on_s_off.html | 31 + app/src/main/res/raw-uz/help_faq.html | 32 + app/src/main/res/raw-uz/help_problems.html | 36 + app/src/main/res/raw-uz/help_s_on_s_off.html | 31 + app/src/main/res/raw-vi/help_faq.html | 32 + app/src/main/res/raw-vi/help_problems.html | 36 + app/src/main/res/raw-vi/help_s_on_s_off.html | 31 + app/src/main/res/raw-zh-rTW/help_faq.html | 32 + .../main/res/raw-zh-rTW/help_problems.html | 36 + .../main/res/raw-zh-rTW/help_s_on_s_off.html | 31 + app/src/main/res/raw-zh/help_faq.html | 32 + app/src/main/res/raw-zh/help_problems.html | 36 + app/src/main/res/raw-zh/help_s_on_s_off.html | 31 + app/src/main/res/raw/help_faq.html | 32 + app/src/main/res/raw/help_problems.html | 36 + app/src/main/res/raw/help_s_on_s_off.html | 32 + app/src/main/res/values-af/strings.xml | 97 + app/src/main/res/values-af/strings_app.xml | 4 + app/src/main/res/values-af/strings_errors.xml | 6 + app/src/main/res/values-af/strings_home.xml | 9 + app/src/main/res/values-af/strings_hosts.xml | 6 + app/src/main/res/values-af/strings_lists.xml | 6 + app/src/main/res/values-af/strings_log.xml | 5 + .../res/values-af/strings_notification.xml | 4 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-af/strings_prefs_main.xml | 6 + .../main/res/values-af/strings_prefs_root.xml | 19 + .../res/values-af/strings_prefs_update.xml | 5 + .../main/res/values-af/strings_prefs_vpn.xml | 3 + .../main/res/values-af/strings_support.xml | 3 + app/src/main/res/values-af/strings_update.xml | 4 + .../main/res/values-af/strings_welcome.xml | 4 + app/src/main/res/values-ar/strings.xml | 279 + app/src/main/res/values-ar/strings_app.xml | 6 + app/src/main/res/values-ar/strings_errors.xml | 22 + app/src/main/res/values-ar/strings_home.xml | 54 + app/src/main/res/values-ar/strings_hosts.xml | 17 + app/src/main/res/values-ar/strings_lists.xml | 24 + app/src/main/res/values-ar/strings_log.xml | 12 + .../res/values-ar/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-ar/strings_prefs_main.xml | 26 + .../main/res/values-ar/strings_prefs_root.xml | 38 + .../res/values-ar/strings_prefs_update.xml | 17 + .../main/res/values-ar/strings_prefs_vpn.xml | 24 + .../res/values-ar/strings_source_edit.xml | 21 + .../main/res/values-ar/strings_support.xml | 5 + app/src/main/res/values-ar/strings_update.xml | 21 + .../main/res/values-ar/strings_welcome.xml | 53 + app/src/main/res/values-ast/strings.xml | 145 + app/src/main/res/values-ast/strings_app.xml | 4 + .../main/res/values-ast/strings_errors.xml | 6 + app/src/main/res/values-ast/strings_home.xml | 19 + app/src/main/res/values-ast/strings_hosts.xml | 7 + app/src/main/res/values-ast/strings_lists.xml | 11 + app/src/main/res/values-ast/strings_log.xml | 6 + .../res/values-ast/strings_notification.xml | 6 + .../strings_prefs_backup_restore.xml | 3 + .../res/values-ast/strings_prefs_main.xml | 9 + .../res/values-ast/strings_prefs_root.xml | 13 + .../res/values-ast/strings_prefs_update.xml | 3 + .../main/res/values-ast/strings_prefs_vpn.xml | 9 + .../main/res/values-ast/strings_support.xml | 3 + .../main/res/values-ast/strings_update.xml | 4 + .../main/res/values-ast/strings_welcome.xml | 4 + app/src/main/res/values-az/strings.xml | 147 + app/src/main/res/values-az/strings_app.xml | 4 + app/src/main/res/values-az/strings_errors.xml | 6 + app/src/main/res/values-az/strings_home.xml | 16 + app/src/main/res/values-az/strings_hosts.xml | 10 + app/src/main/res/values-az/strings_lists.xml | 15 + app/src/main/res/values-az/strings_log.xml | 5 + .../res/values-az/strings_notification.xml | 7 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-az/strings_prefs_main.xml | 4 + .../main/res/values-az/strings_prefs_root.xml | 13 + .../res/values-az/strings_prefs_update.xml | 4 + .../main/res/values-az/strings_prefs_vpn.xml | 8 + .../main/res/values-az/strings_support.xml | 3 + app/src/main/res/values-az/strings_update.xml | 4 + .../main/res/values-az/strings_welcome.xml | 4 + app/src/main/res/values-be/strings.xml | 267 + app/src/main/res/values-be/strings_app.xml | 6 + app/src/main/res/values-be/strings_errors.xml | 22 + app/src/main/res/values-be/strings_home.xml | 50 + app/src/main/res/values-be/strings_hosts.xml | 17 + app/src/main/res/values-be/strings_lists.xml | 23 + app/src/main/res/values-be/strings_log.xml | 8 + .../res/values-be/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-be/strings_prefs_main.xml | 26 + .../main/res/values-be/strings_prefs_root.xml | 37 + .../res/values-be/strings_prefs_update.xml | 15 + .../main/res/values-be/strings_prefs_vpn.xml | 24 + .../main/res/values-be/strings_support.xml | 5 + app/src/main/res/values-be/strings_update.xml | 21 + .../main/res/values-be/strings_welcome.xml | 52 + app/src/main/res/values-bg/strings.xml | 262 + app/src/main/res/values-bg/strings_app.xml | 6 + app/src/main/res/values-bg/strings_errors.xml | 22 + app/src/main/res/values-bg/strings_home.xml | 46 + app/src/main/res/values-bg/strings_hosts.xml | 17 + app/src/main/res/values-bg/strings_lists.xml | 24 + app/src/main/res/values-bg/strings_log.xml | 11 + .../res/values-bg/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-bg/strings_prefs_main.xml | 26 + .../main/res/values-bg/strings_prefs_root.xml | 37 + .../res/values-bg/strings_prefs_update.xml | 17 + .../main/res/values-bg/strings_prefs_vpn.xml | 24 + .../res/values-bg/strings_source_edit.xml | 21 + .../main/res/values-bg/strings_support.xml | 5 + app/src/main/res/values-bg/strings_update.xml | 22 + .../main/res/values-bg/strings_welcome.xml | 55 + app/src/main/res/values-bn/strings.xml | 22 + app/src/main/res/values-bn/strings_app.xml | 4 + app/src/main/res/values-bn/strings_errors.xml | 5 + app/src/main/res/values-bn/strings_home.xml | 16 + app/src/main/res/values-bn/strings_hosts.xml | 4 + app/src/main/res/values-bn/strings_lists.xml | 4 + app/src/main/res/values-bn/strings_log.xml | 5 + .../res/values-bn/strings_notification.xml | 4 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-bn/strings_prefs_main.xml | 4 + .../main/res/values-bn/strings_prefs_root.xml | 10 + .../res/values-bn/strings_prefs_update.xml | 3 + .../main/res/values-bn/strings_prefs_vpn.xml | 8 + .../main/res/values-bn/strings_support.xml | 3 + app/src/main/res/values-bn/strings_update.xml | 4 + .../main/res/values-bn/strings_welcome.xml | 3 + app/src/main/res/values-ca/strings.xml | 262 + app/src/main/res/values-ca/strings_app.xml | 6 + app/src/main/res/values-ca/strings_errors.xml | 22 + app/src/main/res/values-ca/strings_home.xml | 46 + app/src/main/res/values-ca/strings_hosts.xml | 17 + app/src/main/res/values-ca/strings_lists.xml | 24 + app/src/main/res/values-ca/strings_log.xml | 11 + .../res/values-ca/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-ca/strings_prefs_main.xml | 26 + .../main/res/values-ca/strings_prefs_root.xml | 37 + .../res/values-ca/strings_prefs_update.xml | 15 + .../main/res/values-ca/strings_prefs_vpn.xml | 24 + .../res/values-ca/strings_source_edit.xml | 21 + .../main/res/values-ca/strings_support.xml | 5 + app/src/main/res/values-ca/strings_update.xml | 21 + .../main/res/values-ca/strings_welcome.xml | 52 + app/src/main/res/values-cs/strings.xml | 270 + app/src/main/res/values-cs/strings_app.xml | 6 + app/src/main/res/values-cs/strings_errors.xml | 22 + app/src/main/res/values-cs/strings_home.xml | 50 + app/src/main/res/values-cs/strings_hosts.xml | 17 + app/src/main/res/values-cs/strings_lists.xml | 24 + app/src/main/res/values-cs/strings_log.xml | 11 + .../res/values-cs/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-cs/strings_prefs_main.xml | 26 + .../main/res/values-cs/strings_prefs_root.xml | 37 + .../res/values-cs/strings_prefs_update.xml | 17 + .../main/res/values-cs/strings_prefs_vpn.xml | 24 + .../main/res/values-cs/strings_support.xml | 5 + app/src/main/res/values-cs/strings_update.xml | 21 + .../main/res/values-cs/strings_welcome.xml | 53 + app/src/main/res/values-da/strings.xml | 190 + app/src/main/res/values-da/strings_app.xml | 4 + app/src/main/res/values-da/strings_errors.xml | 6 + app/src/main/res/values-da/strings_home.xml | 9 + app/src/main/res/values-da/strings_hosts.xml | 11 + app/src/main/res/values-da/strings_lists.xml | 15 + app/src/main/res/values-da/strings_log.xml | 8 + .../res/values-da/strings_notification.xml | 5 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-da/strings_prefs_main.xml | 12 + .../main/res/values-da/strings_prefs_root.xml | 14 + .../res/values-da/strings_prefs_update.xml | 6 + .../main/res/values-da/strings_prefs_vpn.xml | 8 + .../main/res/values-da/strings_support.xml | 3 + app/src/main/res/values-da/strings_update.xml | 4 + .../main/res/values-da/strings_welcome.xml | 4 + app/src/main/res/values-de/strings.xml | 262 + app/src/main/res/values-de/strings_app.xml | 6 + app/src/main/res/values-de/strings_errors.xml | 22 + app/src/main/res/values-de/strings_home.xml | 46 + app/src/main/res/values-de/strings_hosts.xml | 17 + app/src/main/res/values-de/strings_lists.xml | 24 + app/src/main/res/values-de/strings_log.xml | 11 + .../res/values-de/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-de/strings_prefs_main.xml | 26 + .../main/res/values-de/strings_prefs_root.xml | 37 + .../res/values-de/strings_prefs_update.xml | 17 + .../main/res/values-de/strings_prefs_vpn.xml | 24 + .../res/values-de/strings_source_edit.xml | 21 + .../main/res/values-de/strings_support.xml | 5 + app/src/main/res/values-de/strings_update.xml | 21 + .../main/res/values-de/strings_welcome.xml | 53 + app/src/main/res/values-el/strings.xml | 284 + app/src/main/res/values-el/strings_app.xml | 6 + app/src/main/res/values-el/strings_errors.xml | 22 + app/src/main/res/values-el/strings_home.xml | 46 + app/src/main/res/values-el/strings_hosts.xml | 17 + app/src/main/res/values-el/strings_lists.xml | 24 + app/src/main/res/values-el/strings_log.xml | 11 + .../res/values-el/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-el/strings_prefs_main.xml | 26 + .../main/res/values-el/strings_prefs_root.xml | 37 + .../res/values-el/strings_prefs_update.xml | 17 + .../main/res/values-el/strings_prefs_vpn.xml | 24 + .../res/values-el/strings_source_edit.xml | 21 + .../main/res/values-el/strings_support.xml | 5 + app/src/main/res/values-el/strings_update.xml | 21 + .../main/res/values-el/strings_welcome.xml | 53 + app/src/main/res/values-en-rUS/strings.xml | 258 + .../main/res/values-en-rUS/strings_app.xml | 6 + .../main/res/values-en-rUS/strings_errors.xml | 22 + .../main/res/values-en-rUS/strings_home.xml | 46 + .../main/res/values-en-rUS/strings_hosts.xml | 17 + .../main/res/values-en-rUS/strings_lists.xml | 23 + .../main/res/values-en-rUS/strings_log.xml | 8 + .../values-en-rUS/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../res/values-en-rUS/strings_prefs_main.xml | 26 + .../res/values-en-rUS/strings_prefs_root.xml | 37 + .../values-en-rUS/strings_prefs_update.xml | 15 + .../res/values-en-rUS/strings_prefs_vpn.xml | 24 + .../res/values-en-rUS/strings_support.xml | 5 + .../main/res/values-en-rUS/strings_update.xml | 18 + .../res/values-en-rUS/strings_welcome.xml | 52 + app/src/main/res/values-eo/strings.xml | 17 + app/src/main/res/values-eo/strings_app.xml | 4 + app/src/main/res/values-eo/strings_errors.xml | 3 + app/src/main/res/values-eo/strings_home.xml | 16 + app/src/main/res/values-eo/strings_hosts.xml | 4 + app/src/main/res/values-eo/strings_lists.xml | 4 + app/src/main/res/values-eo/strings_log.xml | 5 + .../res/values-eo/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-eo/strings_prefs_main.xml | 4 + .../main/res/values-eo/strings_prefs_root.xml | 10 + .../res/values-eo/strings_prefs_update.xml | 3 + .../main/res/values-eo/strings_prefs_vpn.xml | 8 + .../main/res/values-eo/strings_support.xml | 3 + app/src/main/res/values-eo/strings_update.xml | 3 + .../main/res/values-eo/strings_welcome.xml | 3 + app/src/main/res/values-es-rMX/strings.xml | 266 + .../main/res/values-es-rMX/strings_app.xml | 6 + .../main/res/values-es-rMX/strings_errors.xml | 22 + .../main/res/values-es-rMX/strings_home.xml | 40 + .../main/res/values-es-rMX/strings_hosts.xml | 16 + .../main/res/values-es-rMX/strings_lists.xml | 23 + .../main/res/values-es-rMX/strings_log.xml | 8 + .../values-es-rMX/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../res/values-es-rMX/strings_prefs_main.xml | 26 + .../res/values-es-rMX/strings_prefs_root.xml | 35 + .../values-es-rMX/strings_prefs_update.xml | 15 + .../res/values-es-rMX/strings_prefs_vpn.xml | 22 + .../res/values-es-rMX/strings_support.xml | 5 + .../main/res/values-es-rMX/strings_update.xml | 17 + .../res/values-es-rMX/strings_welcome.xml | 48 + app/src/main/res/values-es/strings.xml | 266 + app/src/main/res/values-es/strings_app.xml | 6 + app/src/main/res/values-es/strings_errors.xml | 22 + app/src/main/res/values-es/strings_home.xml | 48 + app/src/main/res/values-es/strings_hosts.xml | 17 + app/src/main/res/values-es/strings_lists.xml | 24 + app/src/main/res/values-es/strings_log.xml | 11 + .../res/values-es/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-es/strings_prefs_main.xml | 26 + .../main/res/values-es/strings_prefs_root.xml | 37 + .../res/values-es/strings_prefs_update.xml | 17 + .../main/res/values-es/strings_prefs_vpn.xml | 24 + .../res/values-es/strings_source_edit.xml | 21 + .../main/res/values-es/strings_support.xml | 5 + app/src/main/res/values-es/strings_update.xml | 21 + .../main/res/values-es/strings_welcome.xml | 53 + app/src/main/res/values-et/strings.xml | 166 + app/src/main/res/values-et/strings_app.xml | 6 + app/src/main/res/values-et/strings_errors.xml | 6 + app/src/main/res/values-et/strings_home.xml | 35 + app/src/main/res/values-et/strings_hosts.xml | 11 + app/src/main/res/values-et/strings_lists.xml | 19 + app/src/main/res/values-et/strings_log.xml | 8 + .../res/values-et/strings_notification.xml | 8 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-et/strings_prefs_main.xml | 11 + .../main/res/values-et/strings_prefs_root.xml | 21 + .../res/values-et/strings_prefs_update.xml | 6 + .../main/res/values-et/strings_prefs_vpn.xml | 8 + .../main/res/values-et/strings_support.xml | 4 + app/src/main/res/values-et/strings_update.xml | 4 + .../main/res/values-et/strings_welcome.xml | 52 + app/src/main/res/values-eu/strings.xml | 236 + app/src/main/res/values-eu/strings_app.xml | 6 + app/src/main/res/values-eu/strings_errors.xml | 22 + app/src/main/res/values-eu/strings_home.xml | 46 + app/src/main/res/values-eu/strings_hosts.xml | 17 + app/src/main/res/values-eu/strings_lists.xml | 24 + app/src/main/res/values-eu/strings_log.xml | 8 + .../res/values-eu/strings_notification.xml | 9 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-eu/strings_prefs_main.xml | 6 + .../main/res/values-eu/strings_prefs_root.xml | 21 + .../res/values-eu/strings_prefs_update.xml | 17 + .../main/res/values-eu/strings_prefs_vpn.xml | 24 + .../res/values-eu/strings_source_edit.xml | 21 + .../main/res/values-eu/strings_support.xml | 5 + app/src/main/res/values-eu/strings_update.xml | 21 + .../main/res/values-eu/strings_welcome.xml | 53 + app/src/main/res/values-fa/strings.xml | 139 + app/src/main/res/values-fa/strings_app.xml | 6 + app/src/main/res/values-fa/strings_errors.xml | 22 + app/src/main/res/values-fa/strings_home.xml | 46 + app/src/main/res/values-fa/strings_hosts.xml | 17 + app/src/main/res/values-fa/strings_lists.xml | 24 + app/src/main/res/values-fa/strings_log.xml | 11 + .../res/values-fa/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-fa/strings_prefs_main.xml | 26 + .../main/res/values-fa/strings_prefs_root.xml | 37 + .../res/values-fa/strings_prefs_update.xml | 17 + .../main/res/values-fa/strings_prefs_vpn.xml | 24 + .../res/values-fa/strings_source_edit.xml | 21 + .../main/res/values-fa/strings_support.xml | 5 + app/src/main/res/values-fa/strings_update.xml | 22 + .../main/res/values-fa/strings_welcome.xml | 53 + app/src/main/res/values-fi/strings.xml | 182 + app/src/main/res/values-fi/strings_app.xml | 6 + app/src/main/res/values-fi/strings_errors.xml | 9 + app/src/main/res/values-fi/strings_home.xml | 46 + app/src/main/res/values-fi/strings_hosts.xml | 17 + app/src/main/res/values-fi/strings_lists.xml | 10 + app/src/main/res/values-fi/strings_log.xml | 5 + .../res/values-fi/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 6 + .../main/res/values-fi/strings_prefs_main.xml | 20 + .../main/res/values-fi/strings_prefs_root.xml | 21 + .../res/values-fi/strings_prefs_update.xml | 15 + .../main/res/values-fi/strings_prefs_vpn.xml | 24 + .../main/res/values-fi/strings_support.xml | 5 + app/src/main/res/values-fi/strings_update.xml | 21 + .../main/res/values-fi/strings_welcome.xml | 53 + app/src/main/res/values-fil/strings.xml | 39 + app/src/main/res/values-fil/strings_app.xml | 4 + .../main/res/values-fil/strings_errors.xml | 5 + app/src/main/res/values-fil/strings_home.xml | 16 + app/src/main/res/values-fil/strings_hosts.xml | 4 + app/src/main/res/values-fil/strings_lists.xml | 5 + app/src/main/res/values-fil/strings_log.xml | 5 + .../res/values-fil/strings_notification.xml | 4 + .../strings_prefs_backup_restore.xml | 3 + .../res/values-fil/strings_prefs_main.xml | 4 + .../res/values-fil/strings_prefs_root.xml | 10 + .../res/values-fil/strings_prefs_update.xml | 3 + .../main/res/values-fil/strings_prefs_vpn.xml | 8 + .../main/res/values-fil/strings_support.xml | 3 + .../main/res/values-fil/strings_update.xml | 4 + .../main/res/values-fil/strings_welcome.xml | 4 + app/src/main/res/values-fr/strings.xml | 266 + app/src/main/res/values-fr/strings_app.xml | 6 + app/src/main/res/values-fr/strings_errors.xml | 22 + app/src/main/res/values-fr/strings_home.xml | 48 + app/src/main/res/values-fr/strings_hosts.xml | 17 + app/src/main/res/values-fr/strings_lists.xml | 24 + app/src/main/res/values-fr/strings_log.xml | 11 + .../res/values-fr/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-fr/strings_prefs_main.xml | 26 + .../main/res/values-fr/strings_prefs_root.xml | 37 + .../res/values-fr/strings_prefs_update.xml | 17 + .../main/res/values-fr/strings_prefs_vpn.xml | 24 + .../res/values-fr/strings_source_edit.xml | 21 + .../main/res/values-fr/strings_support.xml | 5 + app/src/main/res/values-fr/strings_update.xml | 22 + .../main/res/values-fr/strings_welcome.xml | 53 + app/src/main/res/values-gl/strings.xml | 81 + app/src/main/res/values-gl/strings_app.xml | 5 + app/src/main/res/values-gl/strings_errors.xml | 16 + app/src/main/res/values-gl/strings_home.xml | 33 + app/src/main/res/values-gl/strings_hosts.xml | 4 + app/src/main/res/values-gl/strings_lists.xml | 14 + app/src/main/res/values-gl/strings_log.xml | 5 + .../res/values-gl/strings_notification.xml | 11 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-gl/strings_prefs_main.xml | 5 + .../main/res/values-gl/strings_prefs_root.xml | 11 + .../res/values-gl/strings_prefs_update.xml | 4 + .../main/res/values-gl/strings_prefs_vpn.xml | 17 + .../main/res/values-gl/strings_support.xml | 3 + app/src/main/res/values-gl/strings_update.xml | 3 + .../main/res/values-gl/strings_welcome.xml | 23 + app/src/main/res/values-hi/strings.xml | 15 + app/src/main/res/values-hi/strings_app.xml | 4 + app/src/main/res/values-hi/strings_errors.xml | 3 + app/src/main/res/values-hi/strings_home.xml | 16 + app/src/main/res/values-hi/strings_hosts.xml | 4 + app/src/main/res/values-hi/strings_lists.xml | 4 + app/src/main/res/values-hi/strings_log.xml | 5 + .../res/values-hi/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-hi/strings_prefs_main.xml | 4 + .../main/res/values-hi/strings_prefs_root.xml | 10 + .../res/values-hi/strings_prefs_update.xml | 3 + .../main/res/values-hi/strings_prefs_vpn.xml | 8 + .../main/res/values-hi/strings_support.xml | 3 + app/src/main/res/values-hi/strings_update.xml | 3 + .../main/res/values-hi/strings_welcome.xml | 3 + app/src/main/res/values-hr/strings.xml | 266 + app/src/main/res/values-hr/strings_app.xml | 6 + app/src/main/res/values-hr/strings_errors.xml | 22 + app/src/main/res/values-hr/strings_home.xml | 48 + app/src/main/res/values-hr/strings_hosts.xml | 17 + app/src/main/res/values-hr/strings_lists.xml | 24 + app/src/main/res/values-hr/strings_log.xml | 11 + .../res/values-hr/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-hr/strings_prefs_main.xml | 26 + .../main/res/values-hr/strings_prefs_root.xml | 37 + .../res/values-hr/strings_prefs_update.xml | 15 + .../main/res/values-hr/strings_prefs_vpn.xml | 24 + .../main/res/values-hr/strings_support.xml | 5 + app/src/main/res/values-hr/strings_update.xml | 21 + .../main/res/values-hr/strings_welcome.xml | 52 + app/src/main/res/values-hu/strings.xml | 264 + app/src/main/res/values-hu/strings_app.xml | 6 + app/src/main/res/values-hu/strings_errors.xml | 22 + app/src/main/res/values-hu/strings_home.xml | 46 + app/src/main/res/values-hu/strings_hosts.xml | 17 + app/src/main/res/values-hu/strings_lists.xml | 24 + app/src/main/res/values-hu/strings_log.xml | 8 + .../res/values-hu/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-hu/strings_prefs_main.xml | 26 + .../main/res/values-hu/strings_prefs_root.xml | 37 + .../res/values-hu/strings_prefs_update.xml | 15 + .../main/res/values-hu/strings_prefs_vpn.xml | 24 + .../main/res/values-hu/strings_support.xml | 5 + app/src/main/res/values-hu/strings_update.xml | 21 + .../main/res/values-hu/strings_welcome.xml | 52 + app/src/main/res/values-in/strings.xml | 258 + app/src/main/res/values-in/strings_app.xml | 6 + app/src/main/res/values-in/strings_errors.xml | 22 + app/src/main/res/values-in/strings_home.xml | 44 + app/src/main/res/values-in/strings_hosts.xml | 17 + app/src/main/res/values-in/strings_lists.xml | 24 + app/src/main/res/values-in/strings_log.xml | 11 + .../res/values-in/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-in/strings_prefs_main.xml | 26 + .../main/res/values-in/strings_prefs_root.xml | 37 + .../res/values-in/strings_prefs_update.xml | 17 + .../main/res/values-in/strings_prefs_vpn.xml | 24 + .../res/values-in/strings_source_edit.xml | 21 + .../main/res/values-in/strings_support.xml | 5 + app/src/main/res/values-in/strings_update.xml | 21 + .../main/res/values-in/strings_welcome.xml | 54 + app/src/main/res/values-is/strings.xml | 14 + app/src/main/res/values-is/strings_app.xml | 4 + app/src/main/res/values-is/strings_errors.xml | 3 + app/src/main/res/values-is/strings_home.xml | 16 + app/src/main/res/values-is/strings_hosts.xml | 4 + app/src/main/res/values-is/strings_lists.xml | 4 + app/src/main/res/values-is/strings_log.xml | 5 + .../res/values-is/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-is/strings_prefs_main.xml | 4 + .../main/res/values-is/strings_prefs_root.xml | 10 + .../res/values-is/strings_prefs_update.xml | 3 + .../main/res/values-is/strings_prefs_vpn.xml | 8 + .../main/res/values-is/strings_support.xml | 3 + app/src/main/res/values-is/strings_update.xml | 3 + .../main/res/values-is/strings_welcome.xml | 3 + app/src/main/res/values-it/strings.xml | 267 + app/src/main/res/values-it/strings_app.xml | 6 + app/src/main/res/values-it/strings_errors.xml | 22 + app/src/main/res/values-it/strings_home.xml | 48 + app/src/main/res/values-it/strings_hosts.xml | 17 + app/src/main/res/values-it/strings_lists.xml | 24 + app/src/main/res/values-it/strings_log.xml | 11 + .../res/values-it/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-it/strings_prefs_main.xml | 26 + .../main/res/values-it/strings_prefs_root.xml | 37 + .../res/values-it/strings_prefs_update.xml | 17 + .../main/res/values-it/strings_prefs_vpn.xml | 24 + .../res/values-it/strings_source_edit.xml | 21 + .../main/res/values-it/strings_support.xml | 5 + app/src/main/res/values-it/strings_update.xml | 22 + .../main/res/values-it/strings_welcome.xml | 53 + app/src/main/res/values-iw/strings.xml | 272 + app/src/main/res/values-iw/strings_app.xml | 6 + app/src/main/res/values-iw/strings_errors.xml | 22 + app/src/main/res/values-iw/strings_home.xml | 50 + app/src/main/res/values-iw/strings_hosts.xml | 17 + app/src/main/res/values-iw/strings_lists.xml | 24 + app/src/main/res/values-iw/strings_log.xml | 11 + .../res/values-iw/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-iw/strings_prefs_main.xml | 26 + .../main/res/values-iw/strings_prefs_root.xml | 37 + .../res/values-iw/strings_prefs_update.xml | 17 + .../main/res/values-iw/strings_prefs_vpn.xml | 24 + .../res/values-iw/strings_source_edit.xml | 21 + .../main/res/values-iw/strings_support.xml | 5 + app/src/main/res/values-iw/strings_update.xml | 21 + .../main/res/values-iw/strings_welcome.xml | 53 + app/src/main/res/values-ja/strings.xml | 258 + app/src/main/res/values-ja/strings_app.xml | 6 + app/src/main/res/values-ja/strings_errors.xml | 22 + app/src/main/res/values-ja/strings_home.xml | 44 + app/src/main/res/values-ja/strings_hosts.xml | 17 + app/src/main/res/values-ja/strings_lists.xml | 24 + app/src/main/res/values-ja/strings_log.xml | 11 + .../res/values-ja/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-ja/strings_prefs_main.xml | 26 + .../main/res/values-ja/strings_prefs_root.xml | 37 + .../res/values-ja/strings_prefs_update.xml | 17 + .../main/res/values-ja/strings_prefs_vpn.xml | 24 + .../res/values-ja/strings_source_edit.xml | 21 + .../main/res/values-ja/strings_support.xml | 5 + app/src/main/res/values-ja/strings_update.xml | 21 + .../main/res/values-ja/strings_welcome.xml | 52 + app/src/main/res/values-km/strings.xml | 57 + app/src/main/res/values-km/strings_app.xml | 4 + app/src/main/res/values-km/strings_errors.xml | 6 + app/src/main/res/values-km/strings_home.xml | 9 + app/src/main/res/values-km/strings_hosts.xml | 6 + app/src/main/res/values-km/strings_lists.xml | 4 + app/src/main/res/values-km/strings_log.xml | 5 + .../res/values-km/strings_notification.xml | 4 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-km/strings_prefs_main.xml | 6 + .../main/res/values-km/strings_prefs_root.xml | 11 + .../res/values-km/strings_prefs_update.xml | 3 + .../main/res/values-km/strings_prefs_vpn.xml | 8 + .../main/res/values-km/strings_support.xml | 3 + app/src/main/res/values-km/strings_update.xml | 4 + .../main/res/values-km/strings_welcome.xml | 4 + app/src/main/res/values-ko/strings.xml | 258 + app/src/main/res/values-ko/strings_app.xml | 6 + app/src/main/res/values-ko/strings_errors.xml | 22 + app/src/main/res/values-ko/strings_home.xml | 44 + app/src/main/res/values-ko/strings_hosts.xml | 17 + app/src/main/res/values-ko/strings_lists.xml | 24 + app/src/main/res/values-ko/strings_log.xml | 11 + .../res/values-ko/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-ko/strings_prefs_main.xml | 26 + .../main/res/values-ko/strings_prefs_root.xml | 37 + .../res/values-ko/strings_prefs_update.xml | 15 + .../main/res/values-ko/strings_prefs_vpn.xml | 24 + .../main/res/values-ko/strings_support.xml | 5 + app/src/main/res/values-ko/strings_update.xml | 21 + .../main/res/values-ko/strings_welcome.xml | 52 + app/src/main/res/values-ku/strings.xml | 20 + app/src/main/res/values-ku/strings_app.xml | 4 + app/src/main/res/values-ku/strings_errors.xml | 3 + app/src/main/res/values-ku/strings_home.xml | 16 + app/src/main/res/values-ku/strings_hosts.xml | 4 + app/src/main/res/values-ku/strings_lists.xml | 4 + app/src/main/res/values-ku/strings_log.xml | 5 + .../res/values-ku/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-ku/strings_prefs_main.xml | 4 + .../main/res/values-ku/strings_prefs_root.xml | 10 + .../res/values-ku/strings_prefs_update.xml | 3 + .../main/res/values-ku/strings_prefs_vpn.xml | 8 + .../main/res/values-ku/strings_support.xml | 3 + app/src/main/res/values-ku/strings_update.xml | 3 + .../main/res/values-ku/strings_welcome.xml | 3 + app/src/main/res/values-lt/strings.xml | 266 + app/src/main/res/values-lt/strings_app.xml | 6 + app/src/main/res/values-lt/strings_errors.xml | 22 + app/src/main/res/values-lt/strings_home.xml | 44 + app/src/main/res/values-lt/strings_hosts.xml | 17 + app/src/main/res/values-lt/strings_lists.xml | 23 + app/src/main/res/values-lt/strings_log.xml | 8 + .../res/values-lt/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-lt/strings_prefs_main.xml | 26 + .../main/res/values-lt/strings_prefs_root.xml | 36 + .../res/values-lt/strings_prefs_update.xml | 12 + .../main/res/values-lt/strings_prefs_vpn.xml | 22 + .../main/res/values-lt/strings_support.xml | 5 + app/src/main/res/values-lt/strings_update.xml | 18 + .../main/res/values-lt/strings_welcome.xml | 52 + app/src/main/res/values-ml/strings.xml | 196 + app/src/main/res/values-ml/strings_app.xml | 4 + app/src/main/res/values-ml/strings_errors.xml | 6 + app/src/main/res/values-ml/strings_home.xml | 19 + app/src/main/res/values-ml/strings_hosts.xml | 11 + app/src/main/res/values-ml/strings_lists.xml | 15 + app/src/main/res/values-ml/strings_log.xml | 8 + .../res/values-ml/strings_notification.xml | 6 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-ml/strings_prefs_main.xml | 7 + .../main/res/values-ml/strings_prefs_root.xml | 26 + .../res/values-ml/strings_prefs_update.xml | 4 + .../main/res/values-ml/strings_prefs_vpn.xml | 8 + .../main/res/values-ml/strings_support.xml | 3 + app/src/main/res/values-ml/strings_update.xml | 4 + .../main/res/values-ml/strings_welcome.xml | 4 + app/src/main/res/values-ms/strings.xml | 14 + app/src/main/res/values-ms/strings_app.xml | 4 + app/src/main/res/values-ms/strings_errors.xml | 3 + app/src/main/res/values-ms/strings_home.xml | 6 + app/src/main/res/values-ms/strings_hosts.xml | 4 + app/src/main/res/values-ms/strings_lists.xml | 4 + app/src/main/res/values-ms/strings_log.xml | 5 + .../res/values-ms/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-ms/strings_prefs_main.xml | 4 + .../main/res/values-ms/strings_prefs_root.xml | 10 + .../res/values-ms/strings_prefs_update.xml | 3 + .../main/res/values-ms/strings_prefs_vpn.xml | 8 + .../main/res/values-ms/strings_support.xml | 3 + app/src/main/res/values-ms/strings_update.xml | 3 + .../main/res/values-ms/strings_welcome.xml | 3 + app/src/main/res/values-my/strings.xml | 14 + app/src/main/res/values-my/strings_app.xml | 4 + app/src/main/res/values-my/strings_errors.xml | 3 + app/src/main/res/values-my/strings_home.xml | 6 + app/src/main/res/values-my/strings_hosts.xml | 4 + app/src/main/res/values-my/strings_lists.xml | 4 + app/src/main/res/values-my/strings_log.xml | 5 + .../res/values-my/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-my/strings_prefs_main.xml | 4 + .../main/res/values-my/strings_prefs_root.xml | 10 + .../res/values-my/strings_prefs_update.xml | 3 + .../main/res/values-my/strings_prefs_vpn.xml | 8 + .../main/res/values-my/strings_support.xml | 3 + app/src/main/res/values-my/strings_update.xml | 3 + .../main/res/values-my/strings_welcome.xml | 3 + app/src/main/res/values-nb-rNO/strings.xml | 109 + .../main/res/values-nb-rNO/strings_app.xml | 4 + .../main/res/values-nb-rNO/strings_errors.xml | 6 + .../main/res/values-nb-rNO/strings_home.xml | 19 + .../main/res/values-nb-rNO/strings_hosts.xml | 6 + .../main/res/values-nb-rNO/strings_lists.xml | 6 + .../main/res/values-nb-rNO/strings_log.xml | 5 + .../values-nb-rNO/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../res/values-nb-rNO/strings_prefs_main.xml | 6 + .../res/values-nb-rNO/strings_prefs_root.xml | 13 + .../values-nb-rNO/strings_prefs_update.xml | 3 + .../res/values-nb-rNO/strings_prefs_vpn.xml | 8 + .../res/values-nb-rNO/strings_support.xml | 3 + .../main/res/values-nb-rNO/strings_update.xml | 4 + .../res/values-nb-rNO/strings_welcome.xml | 4 + app/src/main/res/values-ne/strings.xml | 14 + app/src/main/res/values-ne/strings_app.xml | 4 + app/src/main/res/values-ne/strings_errors.xml | 3 + app/src/main/res/values-ne/strings_home.xml | 6 + app/src/main/res/values-ne/strings_hosts.xml | 4 + app/src/main/res/values-ne/strings_lists.xml | 4 + app/src/main/res/values-ne/strings_log.xml | 5 + .../res/values-ne/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-ne/strings_prefs_main.xml | 4 + .../main/res/values-ne/strings_prefs_root.xml | 10 + .../res/values-ne/strings_prefs_update.xml | 3 + .../main/res/values-ne/strings_prefs_vpn.xml | 8 + .../main/res/values-ne/strings_support.xml | 3 + app/src/main/res/values-ne/strings_update.xml | 3 + .../main/res/values-ne/strings_welcome.xml | 3 + app/src/main/res/values-night/colors.xml | 10 + app/src/main/res/values-night/styles.xml | 6 + app/src/main/res/values-nl/strings.xml | 272 + app/src/main/res/values-nl/strings_app.xml | 6 + app/src/main/res/values-nl/strings_errors.xml | 22 + app/src/main/res/values-nl/strings_home.xml | 46 + app/src/main/res/values-nl/strings_hosts.xml | 17 + app/src/main/res/values-nl/strings_lists.xml | 24 + app/src/main/res/values-nl/strings_log.xml | 11 + .../res/values-nl/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-nl/strings_prefs_main.xml | 26 + .../main/res/values-nl/strings_prefs_root.xml | 37 + .../res/values-nl/strings_prefs_update.xml | 17 + .../main/res/values-nl/strings_prefs_vpn.xml | 24 + .../res/values-nl/strings_source_edit.xml | 21 + .../main/res/values-nl/strings_support.xml | 5 + app/src/main/res/values-nl/strings_update.xml | 21 + .../main/res/values-nl/strings_welcome.xml | 54 + app/src/main/res/values-no/strings.xml | 24 + app/src/main/res/values-no/strings_app.xml | 4 + app/src/main/res/values-no/strings_errors.xml | 3 + app/src/main/res/values-no/strings_home.xml | 16 + app/src/main/res/values-no/strings_hosts.xml | 4 + app/src/main/res/values-no/strings_lists.xml | 4 + app/src/main/res/values-no/strings_log.xml | 5 + .../res/values-no/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-no/strings_prefs_main.xml | 4 + .../main/res/values-no/strings_prefs_root.xml | 10 + .../res/values-no/strings_prefs_update.xml | 3 + .../main/res/values-no/strings_prefs_vpn.xml | 8 + .../main/res/values-no/strings_support.xml | 3 + app/src/main/res/values-no/strings_update.xml | 3 + .../main/res/values-no/strings_welcome.xml | 3 + app/src/main/res/values-pa/strings.xml | 14 + app/src/main/res/values-pa/strings_app.xml | 4 + app/src/main/res/values-pa/strings_errors.xml | 3 + app/src/main/res/values-pa/strings_home.xml | 16 + app/src/main/res/values-pa/strings_hosts.xml | 4 + app/src/main/res/values-pa/strings_lists.xml | 4 + app/src/main/res/values-pa/strings_log.xml | 5 + .../res/values-pa/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-pa/strings_prefs_main.xml | 4 + .../main/res/values-pa/strings_prefs_root.xml | 10 + .../res/values-pa/strings_prefs_update.xml | 3 + .../main/res/values-pa/strings_prefs_vpn.xml | 8 + .../main/res/values-pa/strings_support.xml | 3 + app/src/main/res/values-pa/strings_update.xml | 3 + .../main/res/values-pa/strings_welcome.xml | 3 + app/src/main/res/values-pl/strings.xml | 270 + app/src/main/res/values-pl/strings_app.xml | 6 + app/src/main/res/values-pl/strings_errors.xml | 22 + app/src/main/res/values-pl/strings_home.xml | 50 + app/src/main/res/values-pl/strings_hosts.xml | 17 + app/src/main/res/values-pl/strings_lists.xml | 24 + app/src/main/res/values-pl/strings_log.xml | 11 + .../res/values-pl/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-pl/strings_prefs_main.xml | 26 + .../main/res/values-pl/strings_prefs_root.xml | 37 + .../res/values-pl/strings_prefs_update.xml | 17 + .../main/res/values-pl/strings_prefs_vpn.xml | 24 + .../res/values-pl/strings_source_edit.xml | 21 + .../main/res/values-pl/strings_support.xml | 5 + app/src/main/res/values-pl/strings_update.xml | 21 + .../main/res/values-pl/strings_welcome.xml | 53 + app/src/main/res/values-ps/strings.xml | 211 + app/src/main/res/values-ps/strings_app.xml | 5 + app/src/main/res/values-ps/strings_errors.xml | 9 + app/src/main/res/values-ps/strings_home.xml | 15 + app/src/main/res/values-ps/strings_hosts.xml | 11 + app/src/main/res/values-ps/strings_lists.xml | 8 + app/src/main/res/values-ps/strings_log.xml | 6 + .../res/values-ps/strings_notification.xml | 6 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-ps/strings_prefs_main.xml | 4 + .../main/res/values-ps/strings_prefs_root.xml | 10 + .../res/values-ps/strings_prefs_update.xml | 3 + .../main/res/values-ps/strings_prefs_vpn.xml | 3 + .../main/res/values-ps/strings_support.xml | 4 + app/src/main/res/values-ps/strings_update.xml | 3 + .../main/res/values-ps/strings_welcome.xml | 14 + app/src/main/res/values-pt-rBR/strings.xml | 266 + .../main/res/values-pt-rBR/strings_app.xml | 6 + .../main/res/values-pt-rBR/strings_errors.xml | 22 + .../main/res/values-pt-rBR/strings_home.xml | 46 + .../main/res/values-pt-rBR/strings_hosts.xml | 17 + .../main/res/values-pt-rBR/strings_lists.xml | 24 + .../main/res/values-pt-rBR/strings_log.xml | 11 + .../values-pt-rBR/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../res/values-pt-rBR/strings_prefs_main.xml | 26 + .../res/values-pt-rBR/strings_prefs_root.xml | 37 + .../values-pt-rBR/strings_prefs_update.xml | 17 + .../res/values-pt-rBR/strings_prefs_vpn.xml | 24 + .../res/values-pt-rBR/strings_source_edit.xml | 21 + .../res/values-pt-rBR/strings_support.xml | 5 + .../main/res/values-pt-rBR/strings_update.xml | 21 + .../res/values-pt-rBR/strings_welcome.xml | 53 + app/src/main/res/values-pt/strings.xml | 267 + app/src/main/res/values-pt/strings_app.xml | 6 + app/src/main/res/values-pt/strings_errors.xml | 22 + app/src/main/res/values-pt/strings_home.xml | 48 + app/src/main/res/values-pt/strings_hosts.xml | 17 + app/src/main/res/values-pt/strings_lists.xml | 24 + app/src/main/res/values-pt/strings_log.xml | 11 + .../res/values-pt/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-pt/strings_prefs_main.xml | 26 + .../main/res/values-pt/strings_prefs_root.xml | 37 + .../res/values-pt/strings_prefs_update.xml | 17 + .../main/res/values-pt/strings_prefs_vpn.xml | 24 + .../res/values-pt/strings_source_edit.xml | 21 + .../main/res/values-pt/strings_support.xml | 5 + app/src/main/res/values-pt/strings_update.xml | 21 + .../main/res/values-pt/strings_welcome.xml | 53 + app/src/main/res/values-ro/strings.xml | 266 + app/src/main/res/values-ro/strings_app.xml | 6 + app/src/main/res/values-ro/strings_errors.xml | 22 + app/src/main/res/values-ro/strings_home.xml | 42 + app/src/main/res/values-ro/strings_hosts.xml | 17 + app/src/main/res/values-ro/strings_lists.xml | 23 + app/src/main/res/values-ro/strings_log.xml | 8 + .../res/values-ro/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-ro/strings_prefs_main.xml | 26 + .../main/res/values-ro/strings_prefs_root.xml | 36 + .../res/values-ro/strings_prefs_update.xml | 15 + .../main/res/values-ro/strings_prefs_vpn.xml | 24 + .../main/res/values-ro/strings_support.xml | 5 + app/src/main/res/values-ro/strings_update.xml | 18 + .../main/res/values-ro/strings_welcome.xml | 53 + app/src/main/res/values-ru/strings.xml | 290 + app/src/main/res/values-ru/strings_app.xml | 6 + app/src/main/res/values-ru/strings_errors.xml | 22 + app/src/main/res/values-ru/strings_home.xml | 50 + app/src/main/res/values-ru/strings_hosts.xml | 17 + app/src/main/res/values-ru/strings_lists.xml | 24 + app/src/main/res/values-ru/strings_log.xml | 11 + .../res/values-ru/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-ru/strings_prefs_main.xml | 26 + .../main/res/values-ru/strings_prefs_root.xml | 37 + .../res/values-ru/strings_prefs_update.xml | 17 + .../main/res/values-ru/strings_prefs_vpn.xml | 24 + .../res/values-ru/strings_source_edit.xml | 21 + .../main/res/values-ru/strings_support.xml | 5 + app/src/main/res/values-ru/strings_update.xml | 21 + .../main/res/values-ru/strings_welcome.xml | 53 + app/src/main/res/values-si/strings.xml | 14 + app/src/main/res/values-si/strings_app.xml | 4 + app/src/main/res/values-si/strings_errors.xml | 3 + app/src/main/res/values-si/strings_home.xml | 16 + app/src/main/res/values-si/strings_hosts.xml | 4 + app/src/main/res/values-si/strings_lists.xml | 4 + app/src/main/res/values-si/strings_log.xml | 5 + .../res/values-si/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-si/strings_prefs_main.xml | 4 + .../main/res/values-si/strings_prefs_root.xml | 10 + .../res/values-si/strings_prefs_update.xml | 3 + .../main/res/values-si/strings_prefs_vpn.xml | 8 + .../main/res/values-si/strings_support.xml | 3 + app/src/main/res/values-si/strings_update.xml | 3 + .../main/res/values-si/strings_welcome.xml | 3 + app/src/main/res/values-sk/strings.xml | 270 + app/src/main/res/values-sk/strings_app.xml | 6 + app/src/main/res/values-sk/strings_errors.xml | 22 + app/src/main/res/values-sk/strings_home.xml | 50 + app/src/main/res/values-sk/strings_hosts.xml | 17 + app/src/main/res/values-sk/strings_lists.xml | 24 + app/src/main/res/values-sk/strings_log.xml | 11 + .../res/values-sk/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-sk/strings_prefs_main.xml | 26 + .../main/res/values-sk/strings_prefs_root.xml | 37 + .../res/values-sk/strings_prefs_update.xml | 17 + .../main/res/values-sk/strings_prefs_vpn.xml | 24 + .../res/values-sk/strings_source_edit.xml | 21 + .../main/res/values-sk/strings_support.xml | 5 + app/src/main/res/values-sk/strings_update.xml | 22 + .../main/res/values-sk/strings_welcome.xml | 53 + app/src/main/res/values-sl/strings.xml | 270 + app/src/main/res/values-sl/strings_app.xml | 6 + app/src/main/res/values-sl/strings_errors.xml | 22 + app/src/main/res/values-sl/strings_home.xml | 50 + app/src/main/res/values-sl/strings_hosts.xml | 17 + app/src/main/res/values-sl/strings_lists.xml | 24 + app/src/main/res/values-sl/strings_log.xml | 11 + .../res/values-sl/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-sl/strings_prefs_main.xml | 26 + .../main/res/values-sl/strings_prefs_root.xml | 37 + .../res/values-sl/strings_prefs_update.xml | 17 + .../main/res/values-sl/strings_prefs_vpn.xml | 24 + .../res/values-sl/strings_source_edit.xml | 21 + .../main/res/values-sl/strings_support.xml | 5 + app/src/main/res/values-sl/strings_update.xml | 21 + .../main/res/values-sl/strings_welcome.xml | 53 + app/src/main/res/values-sq/strings.xml | 14 + app/src/main/res/values-sq/strings_app.xml | 4 + app/src/main/res/values-sq/strings_errors.xml | 3 + app/src/main/res/values-sq/strings_home.xml | 16 + app/src/main/res/values-sq/strings_hosts.xml | 4 + app/src/main/res/values-sq/strings_lists.xml | 4 + app/src/main/res/values-sq/strings_log.xml | 5 + .../res/values-sq/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-sq/strings_prefs_main.xml | 4 + .../main/res/values-sq/strings_prefs_root.xml | 10 + .../res/values-sq/strings_prefs_update.xml | 3 + .../main/res/values-sq/strings_prefs_vpn.xml | 8 + .../main/res/values-sq/strings_support.xml | 3 + app/src/main/res/values-sq/strings_update.xml | 3 + .../main/res/values-sq/strings_welcome.xml | 3 + app/src/main/res/values-sr/strings.xml | 110 + app/src/main/res/values-sr/strings_app.xml | 4 + app/src/main/res/values-sr/strings_errors.xml | 6 + app/src/main/res/values-sr/strings_home.xml | 9 + app/src/main/res/values-sr/strings_hosts.xml | 6 + app/src/main/res/values-sr/strings_lists.xml | 6 + app/src/main/res/values-sr/strings_log.xml | 5 + .../res/values-sr/strings_notification.xml | 4 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-sr/strings_prefs_main.xml | 6 + .../main/res/values-sr/strings_prefs_root.xml | 14 + .../res/values-sr/strings_prefs_update.xml | 3 + .../main/res/values-sr/strings_prefs_vpn.xml | 8 + .../main/res/values-sr/strings_support.xml | 3 + app/src/main/res/values-sr/strings_update.xml | 4 + .../main/res/values-sr/strings_welcome.xml | 4 + app/src/main/res/values-sv/strings.xml | 262 + app/src/main/res/values-sv/strings_app.xml | 6 + app/src/main/res/values-sv/strings_errors.xml | 22 + app/src/main/res/values-sv/strings_home.xml | 46 + app/src/main/res/values-sv/strings_hosts.xml | 17 + app/src/main/res/values-sv/strings_lists.xml | 24 + app/src/main/res/values-sv/strings_log.xml | 11 + .../res/values-sv/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-sv/strings_prefs_main.xml | 26 + .../main/res/values-sv/strings_prefs_root.xml | 37 + .../res/values-sv/strings_prefs_update.xml | 15 + .../main/res/values-sv/strings_prefs_vpn.xml | 24 + .../main/res/values-sv/strings_support.xml | 5 + app/src/main/res/values-sv/strings_update.xml | 21 + .../main/res/values-sv/strings_welcome.xml | 52 + app/src/main/res/values-ta/strings.xml | 45 + app/src/main/res/values-ta/strings_app.xml | 6 + app/src/main/res/values-ta/strings_errors.xml | 3 + app/src/main/res/values-ta/strings_home.xml | 40 + app/src/main/res/values-ta/strings_hosts.xml | 14 + app/src/main/res/values-ta/strings_lists.xml | 11 + app/src/main/res/values-ta/strings_log.xml | 5 + .../res/values-ta/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-ta/strings_prefs_main.xml | 4 + .../main/res/values-ta/strings_prefs_root.xml | 11 + .../res/values-ta/strings_prefs_update.xml | 3 + .../main/res/values-ta/strings_prefs_vpn.xml | 8 + .../main/res/values-ta/strings_support.xml | 5 + app/src/main/res/values-ta/strings_update.xml | 3 + .../main/res/values-ta/strings_welcome.xml | 5 + app/src/main/res/values-th/strings.xml | 213 + app/src/main/res/values-th/strings_app.xml | 4 + app/src/main/res/values-th/strings_errors.xml | 6 + app/src/main/res/values-th/strings_home.xml | 9 + app/src/main/res/values-th/strings_hosts.xml | 11 + app/src/main/res/values-th/strings_lists.xml | 13 + app/src/main/res/values-th/strings_log.xml | 8 + .../res/values-th/strings_notification.xml | 8 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-th/strings_prefs_main.xml | 6 + .../main/res/values-th/strings_prefs_root.xml | 14 + .../res/values-th/strings_prefs_update.xml | 4 + .../main/res/values-th/strings_prefs_vpn.xml | 8 + .../main/res/values-th/strings_support.xml | 3 + app/src/main/res/values-th/strings_update.xml | 4 + .../main/res/values-th/strings_welcome.xml | 4 + app/src/main/res/values-tl/strings.xml | 14 + app/src/main/res/values-tl/strings_app.xml | 4 + app/src/main/res/values-tl/strings_errors.xml | 3 + app/src/main/res/values-tl/strings_home.xml | 16 + app/src/main/res/values-tl/strings_hosts.xml | 4 + app/src/main/res/values-tl/strings_lists.xml | 4 + app/src/main/res/values-tl/strings_log.xml | 5 + .../res/values-tl/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-tl/strings_prefs_main.xml | 4 + .../main/res/values-tl/strings_prefs_root.xml | 10 + .../res/values-tl/strings_prefs_update.xml | 3 + .../main/res/values-tl/strings_prefs_vpn.xml | 3 + .../main/res/values-tl/strings_support.xml | 3 + app/src/main/res/values-tl/strings_update.xml | 3 + .../main/res/values-tl/strings_welcome.xml | 3 + app/src/main/res/values-tr/strings.xml | 262 + app/src/main/res/values-tr/strings_app.xml | 6 + app/src/main/res/values-tr/strings_errors.xml | 22 + app/src/main/res/values-tr/strings_home.xml | 46 + app/src/main/res/values-tr/strings_hosts.xml | 17 + app/src/main/res/values-tr/strings_lists.xml | 24 + app/src/main/res/values-tr/strings_log.xml | 11 + .../res/values-tr/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-tr/strings_prefs_main.xml | 26 + .../main/res/values-tr/strings_prefs_root.xml | 37 + .../res/values-tr/strings_prefs_update.xml | 17 + .../main/res/values-tr/strings_prefs_vpn.xml | 24 + .../res/values-tr/strings_source_edit.xml | 21 + .../main/res/values-tr/strings_support.xml | 5 + app/src/main/res/values-tr/strings_update.xml | 21 + .../main/res/values-tr/strings_welcome.xml | 53 + app/src/main/res/values-uk/strings.xml | 270 + app/src/main/res/values-uk/strings_app.xml | 6 + app/src/main/res/values-uk/strings_errors.xml | 22 + app/src/main/res/values-uk/strings_home.xml | 50 + app/src/main/res/values-uk/strings_hosts.xml | 17 + app/src/main/res/values-uk/strings_lists.xml | 24 + app/src/main/res/values-uk/strings_log.xml | 11 + .../res/values-uk/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-uk/strings_prefs_main.xml | 26 + .../main/res/values-uk/strings_prefs_root.xml | 37 + .../res/values-uk/strings_prefs_update.xml | 15 + .../main/res/values-uk/strings_prefs_vpn.xml | 24 + .../main/res/values-uk/strings_support.xml | 5 + app/src/main/res/values-uk/strings_update.xml | 21 + .../main/res/values-uk/strings_welcome.xml | 53 + app/src/main/res/values-ur/strings.xml | 30 + app/src/main/res/values-ur/strings_app.xml | 4 + app/src/main/res/values-ur/strings_errors.xml | 3 + app/src/main/res/values-ur/strings_home.xml | 6 + app/src/main/res/values-ur/strings_hosts.xml | 4 + app/src/main/res/values-ur/strings_lists.xml | 4 + app/src/main/res/values-ur/strings_log.xml | 5 + .../res/values-ur/strings_notification.xml | 3 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-ur/strings_prefs_main.xml | 4 + .../main/res/values-ur/strings_prefs_root.xml | 10 + .../res/values-ur/strings_prefs_update.xml | 3 + .../main/res/values-ur/strings_prefs_vpn.xml | 8 + .../main/res/values-ur/strings_support.xml | 3 + app/src/main/res/values-ur/strings_update.xml | 3 + .../main/res/values-ur/strings_welcome.xml | 3 + app/src/main/res/values-uz/strings.xml | 53 + app/src/main/res/values-uz/strings_app.xml | 4 + app/src/main/res/values-uz/strings_errors.xml | 3 + app/src/main/res/values-uz/strings_home.xml | 6 + app/src/main/res/values-uz/strings_hosts.xml | 4 + app/src/main/res/values-uz/strings_lists.xml | 4 + app/src/main/res/values-uz/strings_log.xml | 5 + .../res/values-uz/strings_notification.xml | 5 + .../strings_prefs_backup_restore.xml | 3 + .../main/res/values-uz/strings_prefs_main.xml | 4 + .../main/res/values-uz/strings_prefs_root.xml | 11 + .../res/values-uz/strings_prefs_update.xml | 3 + .../main/res/values-uz/strings_prefs_vpn.xml | 8 + .../main/res/values-uz/strings_support.xml | 3 + app/src/main/res/values-uz/strings_update.xml | 3 + .../main/res/values-uz/strings_welcome.xml | 3 + app/src/main/res/values-vi/strings.xml | 258 + app/src/main/res/values-vi/strings_app.xml | 6 + app/src/main/res/values-vi/strings_errors.xml | 22 + app/src/main/res/values-vi/strings_home.xml | 44 + app/src/main/res/values-vi/strings_hosts.xml | 17 + app/src/main/res/values-vi/strings_lists.xml | 24 + app/src/main/res/values-vi/strings_log.xml | 12 + .../res/values-vi/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-vi/strings_prefs_main.xml | 26 + .../main/res/values-vi/strings_prefs_root.xml | 37 + .../res/values-vi/strings_prefs_update.xml | 17 + .../main/res/values-vi/strings_prefs_vpn.xml | 24 + .../main/res/values-vi/strings_support.xml | 5 + app/src/main/res/values-vi/strings_update.xml | 21 + .../main/res/values-vi/strings_welcome.xml | 53 + app/src/main/res/values-zh-rTW/strings.xml | 258 + .../main/res/values-zh-rTW/strings_app.xml | 6 + .../main/res/values-zh-rTW/strings_errors.xml | 22 + .../main/res/values-zh-rTW/strings_home.xml | 44 + .../main/res/values-zh-rTW/strings_hosts.xml | 17 + .../main/res/values-zh-rTW/strings_lists.xml | 24 + .../main/res/values-zh-rTW/strings_log.xml | 11 + .../values-zh-rTW/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../res/values-zh-rTW/strings_prefs_main.xml | 26 + .../res/values-zh-rTW/strings_prefs_root.xml | 37 + .../values-zh-rTW/strings_prefs_update.xml | 17 + .../res/values-zh-rTW/strings_prefs_vpn.xml | 24 + .../res/values-zh-rTW/strings_source_edit.xml | 21 + .../res/values-zh-rTW/strings_support.xml | 5 + .../main/res/values-zh-rTW/strings_update.xml | 21 + .../res/values-zh-rTW/strings_welcome.xml | 53 + app/src/main/res/values-zh/strings.xml | 259 + app/src/main/res/values-zh/strings_app.xml | 6 + app/src/main/res/values-zh/strings_errors.xml | 22 + app/src/main/res/values-zh/strings_home.xml | 44 + app/src/main/res/values-zh/strings_hosts.xml | 17 + app/src/main/res/values-zh/strings_lists.xml | 24 + app/src/main/res/values-zh/strings_log.xml | 11 + .../res/values-zh/strings_notification.xml | 13 + .../strings_prefs_backup_restore.xml | 8 + .../main/res/values-zh/strings_prefs_main.xml | 26 + .../main/res/values-zh/strings_prefs_root.xml | 37 + .../res/values-zh/strings_prefs_update.xml | 17 + .../main/res/values-zh/strings_prefs_vpn.xml | 24 + .../res/values-zh/strings_source_edit.xml | 21 + .../main/res/values-zh/strings_support.xml | 5 + app/src/main/res/values-zh/strings_update.xml | 22 + .../main/res/values-zh/strings_welcome.xml | 53 + app/src/main/res/values/colors.xml | 23 + app/src/main/res/values/dimens.xml | 10 + app/src/main/res/values/preferences.xml | 70 + app/src/main/res/values/strings.xml | 262 + app/src/main/res/values/strings_app.xml | 6 + app/src/main/res/values/strings_errors.xml | 22 + app/src/main/res/values/strings_home.xml | 46 + app/src/main/res/values/strings_hosts.xml | 17 + app/src/main/res/values/strings_lists.xml | 24 + app/src/main/res/values/strings_log.xml | 11 + .../main/res/values/strings_notification.xml | 13 + .../values/strings_prefs_backup_restore.xml | 8 + .../main/res/values/strings_prefs_main.xml | 26 + .../main/res/values/strings_prefs_root.xml | 37 + .../main/res/values/strings_prefs_update.xml | 17 + app/src/main/res/values/strings_prefs_vpn.xml | 24 + .../main/res/values/strings_source_edit.xml | 21 + app/src/main/res/values/strings_static.xml | 5 + app/src/main/res/values/strings_support.xml | 5 + app/src/main/res/values/strings_update.xml | 22 + app/src/main/res/values/strings_welcome.xml | 53 + app/src/main/res/values/styles.xml | 41 + app/src/main/res/xml/list_searchable.xml | 5 + .../main/res/xml/network_security_config.xml | 9 + .../res/xml/preferences_backup_restore.xml | 16 + app/src/main/res/xml/preferences_main.xml | 57 + app/src/main/res/xml/preferences_root.xml | 59 + app/src/main/res/xml/preferences_update.xml | 47 + app/src/main/res/xml/preferences_vpn.xml | 42 + app/src/main/res/xml/shortcuts.xml | 41 + .../adaway/model/git/GitHostsSourceTest.java | 86 + .../adaway/model/source/SourceLoaderTest.java | 171 + .../org/adaway/ui/log/LogEntrySortTest.java | 69 + build.gradle | 31 + gradle.properties | 14 + gradle/libs.versions.toml | 52 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 185 + gradlew.bat | 89 + metadata/af/full_description.txt | 9 + metadata/af/short_description.txt | 1 + metadata/af/title.txt | 1 + metadata/ar/full_description.txt | 9 + metadata/ar/short_description.txt | 1 + metadata/ar/title.txt | 1 + metadata/ast/full_description.txt | 9 + metadata/ast/short_description.txt | 1 + metadata/ast/title.txt | 1 + metadata/az/full_description.txt | 9 + metadata/az/short_description.txt | 1 + metadata/az/title.txt | 1 + metadata/be/full_description.txt | 9 + metadata/be/short_description.txt | 1 + metadata/be/title.txt | 1 + metadata/bg/full_description.txt | 9 + metadata/bg/short_description.txt | 1 + metadata/bg/title.txt | 1 + metadata/bn/full_description.txt | 9 + metadata/bn/short_description.txt | 1 + metadata/bn/title.txt | 1 + metadata/ca/full_description.txt | 9 + metadata/ca/short_description.txt | 1 + metadata/ca/title.txt | 1 + metadata/cs/full_description.txt | 9 + metadata/cs/short_description.txt | 1 + metadata/cs/title.txt | 1 + metadata/da/full_description.txt | 9 + metadata/da/short_description.txt | 1 + metadata/da/title.txt | 1 + metadata/de/full_description.txt | 9 + metadata/de/short_description.txt | 1 + metadata/de/title.txt | 1 + metadata/el/full_description.txt | 9 + metadata/el/short_description.txt | 1 + metadata/el/title.txt | 1 + metadata/en-US/full_description.txt | 9 + metadata/en-US/images/featureGraphic.png | Bin 0 -> 20917 bytes metadata/en-US/images/icon.png | Bin 0 -> 1923 bytes .../en-US/phoneScreenshots/screenshot1.png | Bin 0 -> 102017 bytes .../en-US/phoneScreenshots/screenshot2.png | Bin 0 -> 94277 bytes .../en-US/phoneScreenshots/screenshot3.png | Bin 0 -> 108017 bytes .../en-US/phoneScreenshots/screenshot4.png | Bin 0 -> 47915 bytes .../en-US/phoneScreenshots/screenshot5.png | Bin 0 -> 289324 bytes metadata/en-US/short_description.txt | 1 + metadata/en-US/title.txt | 1 + metadata/en/full_description.txt | 9 + metadata/en/short_description.txt | 1 + metadata/en/title.txt | 1 + metadata/eo/full_description.txt | 9 + metadata/eo/short_description.txt | 1 + metadata/eo/title.txt | 1 + metadata/es-MX/full_description.txt | 9 + metadata/es-MX/short_description.txt | 1 + metadata/es-MX/title.txt | 1 + metadata/es-rMX/full_description.txt | 9 + metadata/es-rMX/short_description.txt | 1 + metadata/es/full_description.txt | 9 + metadata/es/short_description.txt | 1 + metadata/es/title.txt | 1 + metadata/et/full_description.txt | 9 + metadata/et/short_description.txt | 1 + metadata/et/title.txt | 1 + metadata/eu/full_description.txt | 9 + metadata/eu/short_description.txt | 1 + metadata/eu/title.txt | 1 + metadata/fa/full_description.txt | 9 + metadata/fa/short_description.txt | 1 + metadata/fa/title.txt | 1 + metadata/fi/full_description.txt | 9 + metadata/fi/short_description.txt | 1 + metadata/fi/title.txt | 1 + metadata/fil/full_description.txt | 9 + metadata/fil/short_description.txt | 1 + metadata/fil/title.txt | 1 + metadata/fr/full_description.txt | 9 + metadata/fr/short_description.txt | 1 + metadata/fr/title.txt | 1 + metadata/gl/full_description.txt | 9 + metadata/gl/short_description.txt | 1 + metadata/gl/title.txt | 1 + metadata/he/short_description.txt | 1 + metadata/hi/full_description.txt | 9 + metadata/hi/short_description.txt | 1 + metadata/hi/title.txt | 1 + metadata/hr/full_description.txt | 9 + metadata/hr/short_description.txt | 1 + metadata/hr/title.txt | 1 + metadata/hu/full_description.txt | 9 + metadata/hu/short_description.txt | 1 + metadata/hu/title.txt | 1 + metadata/id/full_description.txt | 9 + metadata/id/short_description.txt | 1 + metadata/id/title.txt | 1 + metadata/in/full_description.txt | 9 + metadata/in/short_description.txt | 1 + metadata/is/full_description.txt | 9 + metadata/is/short_description.txt | 1 + metadata/is/title.txt | 1 + metadata/it/full_description.txt | 9 + metadata/it/short_description.txt | 1 + metadata/it/title.txt | 1 + metadata/iw/full_description.txt | 9 + metadata/iw/short_description.txt | 1 + metadata/iw/title.txt | 1 + metadata/ja/full_description.txt | 9 + metadata/ja/short_description.txt | 1 + metadata/ja/title.txt | 1 + metadata/km/full_description.txt | 9 + metadata/km/short_description.txt | 1 + metadata/km/title.txt | 1 + metadata/ko/full_description.txt | 9 + metadata/ko/short_description.txt | 1 + metadata/ko/title.txt | 1 + metadata/ku/full_description.txt | 9 + metadata/ku/short_description.txt | 1 + metadata/ku/title.txt | 1 + metadata/lt/full_description.txt | 9 + metadata/lt/short_description.txt | 1 + metadata/lt/title.txt | 1 + metadata/ml/full_description.txt | 9 + metadata/ml/short_description.txt | 1 + metadata/ml/title.txt | 1 + metadata/ms/full_description.txt | 9 + metadata/ms/short_description.txt | 1 + metadata/ms/title.txt | 1 + metadata/my/full_description.txt | 9 + metadata/my/short_description.txt | 1 + metadata/my/title.txt | 1 + metadata/nb-NO/full_description.txt | 9 + metadata/nb-NO/short_description.txt | 1 + metadata/nb-NO/title.txt | 1 + metadata/nb-rNO/full_description.txt | 9 + metadata/nb-rNO/short_description.txt | 1 + metadata/ne/full_description.txt | 9 + metadata/ne/short_description.txt | 1 + metadata/ne/title.txt | 1 + metadata/nl/full_description.txt | 9 + metadata/nl/short_description.txt | 1 + metadata/nl/title.txt | 1 + metadata/no/full_description.txt | 9 + metadata/no/short_description.txt | 1 + metadata/no/title.txt | 1 + metadata/pa/full_description.txt | 9 + metadata/pa/short_description.txt | 1 + metadata/pa/title.txt | 1 + metadata/pl/full_description.txt | 9 + metadata/pl/short_description.txt | 1 + metadata/pl/title.txt | 1 + metadata/ps/full_description.txt | 9 + metadata/ps/short_description.txt | 1 + metadata/ps/title.txt | 1 + metadata/pt-BR/full_description.txt | 9 + metadata/pt-BR/short_description.txt | 1 + metadata/pt-BR/title.txt | 1 + metadata/pt/full_description.txt | 9 + metadata/pt/short_description.txt | 1 + metadata/pt/title.txt | 1 + metadata/ro/full_description.txt | 9 + metadata/ro/short_description.txt | 1 + metadata/ro/title.txt | 1 + metadata/ru/full_description.txt | 9 + metadata/ru/short_description.txt | 1 + metadata/ru/title.txt | 1 + metadata/si/full_description.txt | 9 + metadata/si/short_description.txt | 1 + metadata/si/title.txt | 1 + metadata/sk/full_description.txt | 9 + metadata/sk/short_description.txt | 1 + metadata/sk/title.txt | 1 + metadata/sl/full_description.txt | 9 + metadata/sl/short_description.txt | 1 + metadata/sl/title.txt | 1 + metadata/sq/full_description.txt | 9 + metadata/sq/short_description.txt | 1 + metadata/sq/title.txt | 1 + metadata/sr/full_description.txt | 9 + metadata/sr/short_description.txt | 1 + metadata/sr/title.txt | 1 + metadata/sv/full_description.txt | 9 + metadata/sv/short_description.txt | 1 + metadata/sv/title.txt | 1 + metadata/ta/full_description.txt | 9 + metadata/ta/short_description.txt | 1 + metadata/ta/title.txt | 1 + metadata/th/full_description.txt | 9 + metadata/th/short_description.txt | 1 + metadata/th/title.txt | 1 + metadata/tl/full_description.txt | 9 + metadata/tl/short_description.txt | 1 + metadata/tl/title.txt | 1 + metadata/tr/full_description.txt | 9 + metadata/tr/short_description.txt | 1 + metadata/tr/title.txt | 1 + metadata/uk/full_description.txt | 9 + metadata/uk/short_description.txt | 1 + metadata/uk/title.txt | 1 + metadata/ur/full_description.txt | 9 + metadata/ur/short_description.txt | 1 + metadata/ur/title.txt | 1 + metadata/uz/full_description.txt | 9 + metadata/uz/short_description.txt | 1 + metadata/uz/title.txt | 1 + metadata/vi/full_description.txt | 9 + metadata/vi/short_description.txt | 1 + metadata/vi/title.txt | 1 + metadata/zh-TW/full_description.txt | 9 + metadata/zh-TW/short_description.txt | 1 + metadata/zh-TW/title.txt | 1 + metadata/zh-rTW/full_description.txt | 9 + metadata/zh-rTW/short_description.txt | 1 + metadata/zh/full_description.txt | 9 + metadata/zh/short_description.txt | 1 + metadata/zh/title.txt | 1 + sentrystub/.gitignore | 1 + sentrystub/build.gradle | 20 + sentrystub/src/main/AndroidManifest.xml | 1 + .../src/main/java/io/sentry/Breadcrumb.java | 11 + .../src/main/java/io/sentry/Integration.java | 4 + sentrystub/src/main/java/io/sentry/Scope.java | 7 + .../main/java/io/sentry/ScopeCallback.java | 5 + .../src/main/java/io/sentry/Sentry.java | 18 + .../src/main/java/io/sentry/SentryLevel.java | 7 + .../main/java/io/sentry/SentryOptions.java | 7 + .../io/sentry/android/core/SentryAndroid.java | 12 + .../FragmentLifecycleIntegration.java | 11 + .../timber/SentryTimberIntegration.java | 10 + settings.gradle | 1 + tcpdump/build.gradle | 66 + tcpdump/jni/Android.mk | 3 + tcpdump/jni/libpcap/Android.mk | 24 + tcpdump/jni/libpcap/CHANGES | 791 + tcpdump/jni/libpcap/CREDITS | 180 + tcpdump/jni/libpcap/ChmodBPF/ChmodBPF | 33 + .../libpcap/ChmodBPF/StartupParameters.plist | 4 + tcpdump/jni/libpcap/CleanSpec.mk | 49 + tcpdump/jni/libpcap/INSTALL.txt | 395 + tcpdump/jni/libpcap/LICENSE | 19 + tcpdump/jni/libpcap/Makefile-devel-adds | 22 + tcpdump/jni/libpcap/Makefile.in | 748 + tcpdump/jni/libpcap/README | 106 + tcpdump/jni/libpcap/README.Win32 | 46 + tcpdump/jni/libpcap/README.aix | 88 + tcpdump/jni/libpcap/README.dag | 122 + tcpdump/jni/libpcap/README.hpux | 254 + tcpdump/jni/libpcap/README.linux | 108 + tcpdump/jni/libpcap/README.macosx | 74 + tcpdump/jni/libpcap/README.septel | 50 + tcpdump/jni/libpcap/README.sita | 64 + tcpdump/jni/libpcap/README.tru64 | 49 + tcpdump/jni/libpcap/SUNOS4/nit_if.o.sparc | Bin 0 -> 5212 bytes tcpdump/jni/libpcap/SUNOS4/nit_if.o.sun3 | Bin 0 -> 4267 bytes .../jni/libpcap/SUNOS4/nit_if.o.sun4c.4.0.3c | Bin 0 -> 5291 bytes tcpdump/jni/libpcap/TODO | 35 + tcpdump/jni/libpcap/VERSION | 1 + tcpdump/jni/libpcap/Win32/Include/Gnuc.h | 44 + tcpdump/jni/libpcap/Win32/Include/addrinfo.h | 144 + .../jni/libpcap/Win32/Include/arpa/nameser.h | 349 + tcpdump/jni/libpcap/Win32/Include/bittypes.h | 89 + tcpdump/jni/libpcap/Win32/Include/cdecl_ext.h | 37 + .../jni/libpcap/Win32/Include/inetprivate.h | 67 + tcpdump/jni/libpcap/Win32/Include/ip6_misc.h | 161 + tcpdump/jni/libpcap/Win32/Include/net/if.h | 230 + tcpdump/jni/libpcap/Win32/Include/net/netdb.h | 166 + tcpdump/jni/libpcap/Win32/Include/net/paths.h | 105 + .../jni/libpcap/Win32/Include/sockstorage.h | 38 + tcpdump/jni/libpcap/Win32/Prj/libpcap.dsp | 168 + tcpdump/jni/libpcap/Win32/Prj/libpcap.dsw | 29 + tcpdump/jni/libpcap/Win32/Src/ffs.c | 54 + tcpdump/jni/libpcap/Win32/Src/gai_strerror.c | 83 + tcpdump/jni/libpcap/Win32/Src/getaddrinfo.c | 1124 + tcpdump/jni/libpcap/Win32/Src/getnetbynm.c | 44 + tcpdump/jni/libpcap/Win32/Src/getnetent.c | 119 + tcpdump/jni/libpcap/Win32/Src/getopt.c | 121 + tcpdump/jni/libpcap/Win32/Src/getservent.c | 125 + tcpdump/jni/libpcap/Win32/Src/inet_aton.c | 54 + tcpdump/jni/libpcap/Win32/Src/inet_net.c | 101 + tcpdump/jni/libpcap/Win32/Src/inet_pton.c | 64 + tcpdump/jni/libpcap/aclocal.m4 | 1293 ++ tcpdump/jni/libpcap/arcnet.h | 50 + tcpdump/jni/libpcap/atmuni31.h | 85 + tcpdump/jni/libpcap/bpf/net/bpf_filter.c | 759 + tcpdump/jni/libpcap/bpf_dump.c | 58 + tcpdump/jni/libpcap/bpf_filter.c | 1 + tcpdump/jni/libpcap/bpf_image.c | 320 + tcpdump/jni/libpcap/chmod_bpf | 19 + tcpdump/jni/libpcap/config.guess | 1435 ++ tcpdump/jni/libpcap/config.h | 338 + tcpdump/jni/libpcap/config.h.in | 349 + tcpdump/jni/libpcap/config.sub | 1807 ++ tcpdump/jni/libpcap/configure | 9914 +++++++++ tcpdump/jni/libpcap/configure.in | 1768 ++ tcpdump/jni/libpcap/dlpisubs.c | 367 + tcpdump/jni/libpcap/dlpisubs.h | 38 + tcpdump/jni/libpcap/doc/pcap.html | 997 + tcpdump/jni/libpcap/doc/pcap.txt | 1680 ++ tcpdump/jni/libpcap/doc/pcap.xml | 746 + tcpdump/jni/libpcap/etherent.c | 169 + tcpdump/jni/libpcap/ethertype.h | 120 + tcpdump/jni/libpcap/fad-getad.c | 280 + tcpdump/jni/libpcap/fad-gifc.c | 417 + tcpdump/jni/libpcap/fad-glifc.c | 369 + tcpdump/jni/libpcap/fad-null.c | 60 + tcpdump/jni/libpcap/fad-sita.c | 59 + tcpdump/jni/libpcap/fad-win32.c | 248 + tcpdump/jni/libpcap/gencode.c | 8904 ++++++++ tcpdump/jni/libpcap/gencode.h | 365 + tcpdump/jni/libpcap/grammar.c | 3976 ++++ tcpdump/jni/libpcap/grammar.y | 753 + tcpdump/jni/libpcap/ieee80211.h | 146 + tcpdump/jni/libpcap/inet.c | 1101 + tcpdump/jni/libpcap/install-sh | 250 + tcpdump/jni/libpcap/lbl/os-aix4.h | 23 + tcpdump/jni/libpcap/lbl/os-hpux11.h | 23 + tcpdump/jni/libpcap/lbl/os-osf4.h | 26 + tcpdump/jni/libpcap/lbl/os-osf5.h | 30 + tcpdump/jni/libpcap/lbl/os-solaris2.h | 24 + tcpdump/jni/libpcap/lbl/os-sunos4.h | 213 + tcpdump/jni/libpcap/lbl/os-ultrix4.h | 37 + tcpdump/jni/libpcap/llc.h | 98 + tcpdump/jni/libpcap/missing/snprintf.c | 625 + tcpdump/jni/libpcap/mkdep | 112 + tcpdump/jni/libpcap/msdos/bin2c.c | 43 + tcpdump/jni/libpcap/msdos/common.dj | 79 + tcpdump/jni/libpcap/msdos/makefile | 184 + tcpdump/jni/libpcap/msdos/makefile.dj | 151 + tcpdump/jni/libpcap/msdos/makefile.wc | 131 + tcpdump/jni/libpcap/msdos/ndis2.c | 860 + tcpdump/jni/libpcap/msdos/ndis2.h | 559 + tcpdump/jni/libpcap/msdos/ndis_0.asm | 188 + tcpdump/jni/libpcap/msdos/pkt_rx0.asm | 197 + tcpdump/jni/libpcap/msdos/pkt_rx1.s | 155 + tcpdump/jni/libpcap/msdos/pktdrvr.c | 1436 ++ tcpdump/jni/libpcap/msdos/pktdrvr.h | 153 + tcpdump/jni/libpcap/msdos/readme.dos | 160 + tcpdump/jni/libpcap/nametoaddr.c | 509 + tcpdump/jni/libpcap/nlpid.h | 56 + tcpdump/jni/libpcap/optimize.c | 2355 +++ .../jni/libpcap/org.tcpdump.chmod_bpf.plist | 16 + tcpdump/jni/libpcap/packaging/pcap.spec.in | 77 + tcpdump/jni/libpcap/pcap-bpf.c | 2752 +++ tcpdump/jni/libpcap/pcap-bpf.h | 45 + tcpdump/jni/libpcap/pcap-bt-linux.c | 411 + tcpdump/jni/libpcap/pcap-bt-linux.h | 38 + tcpdump/jni/libpcap/pcap-bt-monitor-linux.c | 242 + tcpdump/jni/libpcap/pcap-bt-monitor-linux.h | 32 + tcpdump/jni/libpcap/pcap-can-linux.c | 319 + tcpdump/jni/libpcap/pcap-can-linux.h | 36 + tcpdump/jni/libpcap/pcap-canusb-linux.c | 474 + tcpdump/jni/libpcap/pcap-canusb-linux.h | 37 + tcpdump/jni/libpcap/pcap-common.c | 1386 ++ tcpdump/jni/libpcap/pcap-common.h | 25 + tcpdump/jni/libpcap/pcap-config.1 | 72 + tcpdump/jni/libpcap/pcap-config.in | 89 + tcpdump/jni/libpcap/pcap-dag.c | 1262 ++ tcpdump/jni/libpcap/pcap-dag.h | 106 + tcpdump/jni/libpcap/pcap-dbus.c | 279 + tcpdump/jni/libpcap/pcap-dbus.h | 2 + tcpdump/jni/libpcap/pcap-dlpi.c | 1763 ++ tcpdump/jni/libpcap/pcap-dos.c | 1496 ++ tcpdump/jni/libpcap/pcap-dos.h | 225 + tcpdump/jni/libpcap/pcap-enet.c | 231 + tcpdump/jni/libpcap/pcap-filter.manmisc.in | 1033 + tcpdump/jni/libpcap/pcap-int.h | 463 + tcpdump/jni/libpcap/pcap-libdlpi.c | 422 + tcpdump/jni/libpcap/pcap-linktype.manmisc.in | 48 + tcpdump/jni/libpcap/pcap-linux.c | 6605 ++++++ tcpdump/jni/libpcap/pcap-namedb.h | 40 + tcpdump/jni/libpcap/pcap-netfilter-linux.c | 655 + tcpdump/jni/libpcap/pcap-netfilter-linux.h | 35 + tcpdump/jni/libpcap/pcap-nit.c | 367 + tcpdump/jni/libpcap/pcap-null.c | 49 + tcpdump/jni/libpcap/pcap-pf.c | 609 + tcpdump/jni/libpcap/pcap-savefile.manfile.in | 133 + tcpdump/jni/libpcap/pcap-septel.c | 293 + tcpdump/jni/libpcap/pcap-septel.h | 13 + tcpdump/jni/libpcap/pcap-sita.c | 1019 + tcpdump/jni/libpcap/pcap-sita.h | 8 + tcpdump/jni/libpcap/pcap-sita.html | 943 + tcpdump/jni/libpcap/pcap-snf.c | 497 + tcpdump/jni/libpcap/pcap-snf.h | 2 + tcpdump/jni/libpcap/pcap-snit.c | 445 + tcpdump/jni/libpcap/pcap-snoop.c | 418 + tcpdump/jni/libpcap/pcap-stdinc.h | 83 + tcpdump/jni/libpcap/pcap-tstamp.manmisc.in | 175 + tcpdump/jni/libpcap/pcap-usb-linux.c | 939 + tcpdump/jni/libpcap/pcap-usb-linux.h | 38 + tcpdump/jni/libpcap/pcap-win32.c | 951 + tcpdump/jni/libpcap/pcap.3pcap.in | 937 + tcpdump/jni/libpcap/pcap.c | 2029 ++ tcpdump/jni/libpcap/pcap.h | 43 + tcpdump/jni/libpcap/pcap/bluetooth.h | 55 + tcpdump/jni/libpcap/pcap/bpf.h | 1514 ++ tcpdump/jni/libpcap/pcap/ipnet.h | 43 + tcpdump/jni/libpcap/pcap/namedb.h | 87 + tcpdump/jni/libpcap/pcap/nflog.h | 92 + tcpdump/jni/libpcap/pcap/pcap.h | 485 + tcpdump/jni/libpcap/pcap/sll.h | 127 + tcpdump/jni/libpcap/pcap/usb.h | 141 + tcpdump/jni/libpcap/pcap/vlan.h | 44 + tcpdump/jni/libpcap/pcap1.h | 306 + tcpdump/jni/libpcap/pcap_activate.3pcap | 95 + tcpdump/jni/libpcap/pcap_breakloop.3pcap | 98 + tcpdump/jni/libpcap/pcap_can_set_rfmon.3pcap | 62 + tcpdump/jni/libpcap/pcap_close.3pcap | 39 + tcpdump/jni/libpcap/pcap_compile.3pcap.in | 70 + tcpdump/jni/libpcap/pcap_create.3pcap | 72 + tcpdump/jni/libpcap/pcap_datalink.3pcap.in | 68 + .../libpcap/pcap_datalink_name_to_val.3pcap | 46 + .../libpcap/pcap_datalink_val_to_name.3pcap | 46 + tcpdump/jni/libpcap/pcap_dump.3pcap | 51 + tcpdump/jni/libpcap/pcap_dump_close.3pcap | 37 + tcpdump/jni/libpcap/pcap_dump_file.3pcap | 38 + tcpdump/jni/libpcap/pcap_dump_flush.3pcap | 43 + tcpdump/jni/libpcap/pcap_dump_ftell.3pcap | 42 + tcpdump/jni/libpcap/pcap_dump_open.3pcap.in | 96 + tcpdump/jni/libpcap/pcap_file.3pcap | 57 + tcpdump/jni/libpcap/pcap_fileno.3pcap | 66 + tcpdump/jni/libpcap/pcap_findalldevs.3pcap | 190 + tcpdump/jni/libpcap/pcap_freecode.3pcap | 43 + .../jni/libpcap/pcap_get_selectable_fd.3pcap | 133 + .../pcap_get_tstamp_precision.3pcap.in | 52 + tcpdump/jni/libpcap/pcap_geterr.3pcap | 51 + tcpdump/jni/libpcap/pcap_inject.3pcap | 88 + tcpdump/jni/libpcap/pcap_is_swapped.3pcap | 51 + tcpdump/jni/libpcap/pcap_lib_version.3pcap | 39 + .../jni/libpcap/pcap_list_datalinks.3pcap.in | 73 + .../libpcap/pcap_list_tstamp_types.3pcap.in | 70 + tcpdump/jni/libpcap/pcap_lookupdev.3pcap | 60 + tcpdump/jni/libpcap/pcap_lookupnet.3pcap | 63 + tcpdump/jni/libpcap/pcap_loop.3pcap | 199 + tcpdump/jni/libpcap/pcap_major_version.3pcap | 54 + tcpdump/jni/libpcap/pcap_next_ex.3pcap | 141 + tcpdump/jni/libpcap/pcap_offline_filter.3pcap | 55 + tcpdump/jni/libpcap/pcap_open_dead.3pcap.in | 79 + tcpdump/jni/libpcap/pcap_open_live.3pcap | 87 + .../jni/libpcap/pcap_open_offline.3pcap.in | 109 + .../jni/libpcap/pcap_set_buffer_size.3pcap | 45 + tcpdump/jni/libpcap/pcap_set_datalink.3pcap | 51 + .../jni/libpcap/pcap_set_immediate_mode.3pcap | 47 + tcpdump/jni/libpcap/pcap_set_promisc.3pcap | 46 + tcpdump/jni/libpcap/pcap_set_rfmon.3pcap | 47 + tcpdump/jni/libpcap/pcap_set_snaplen.3pcap | 44 + tcpdump/jni/libpcap/pcap_set_timeout.3pcap | 45 + .../pcap_set_tstamp_precision.3pcap.in | 61 + .../jni/libpcap/pcap_set_tstamp_type.3pcap.in | 65 + tcpdump/jni/libpcap/pcap_setdirection.3pcap | 69 + tcpdump/jni/libpcap/pcap_setfilter.3pcap | 52 + tcpdump/jni/libpcap/pcap_setnonblock.3pcap | 81 + tcpdump/jni/libpcap/pcap_snapshot.3pcap | 52 + tcpdump/jni/libpcap/pcap_stats.3pcap | 97 + tcpdump/jni/libpcap/pcap_statustostr.3pcap | 41 + tcpdump/jni/libpcap/pcap_strerror.3pcap | 40 + .../pcap_tstamp_type_name_to_val.3pcap | 45 + .../pcap_tstamp_type_val_to_name.3pcap | 49 + tcpdump/jni/libpcap/ppp.h | 57 + tcpdump/jni/libpcap/runlex.sh | 233 + tcpdump/jni/libpcap/savefile.c | 416 + tcpdump/jni/libpcap/scanner.c | 4819 +++++ tcpdump/jni/libpcap/scanner.c.top | 3 + tcpdump/jni/libpcap/scanner.h | 6 + tcpdump/jni/libpcap/scanner.l | 457 + tcpdump/jni/libpcap/sf-pcap-ng.c | 1274 ++ tcpdump/jni/libpcap/sf-pcap-ng.h | 32 + tcpdump/jni/libpcap/sf-pcap.c | 894 + tcpdump/jni/libpcap/sf-pcap.h | 37 + tcpdump/jni/libpcap/sunatmpos.h | 43 + tcpdump/jni/libpcap/tests/BPF/1.txt | 2 + tcpdump/jni/libpcap/tests/BPF/2.txt | 2 + tcpdump/jni/libpcap/tests/BPF/3.txt | 1 + tcpdump/jni/libpcap/tests/BPF/4.txt | 2 + tcpdump/jni/libpcap/tests/BPF/5.txt | 1 + tcpdump/jni/libpcap/tests/BPF/6.txt | 1 + tcpdump/jni/libpcap/tests/BPF/7.txt | 1 + tcpdump/jni/libpcap/tests/capturetest.c | 287 + tcpdump/jni/libpcap/tests/filtertest.c | 315 + tcpdump/jni/libpcap/tests/findalldevstest.c | 142 + tcpdump/jni/libpcap/tests/nonblocktest.c | 226 + tcpdump/jni/libpcap/tests/opentest.c | 216 + tcpdump/jni/libpcap/tests/pcap_compile_test.c | 11 + tcpdump/jni/libpcap/tests/reactivatetest.c | 84 + tcpdump/jni/libpcap/tests/selpolltest.c | 350 + tcpdump/jni/libpcap/tests/valgrindtest.c | 406 + tcpdump/jni/libpcap/tests/visopts.py | 309 + tcpdump/jni/libpcap/tokdefs.h | 316 + tcpdump/jni/libpcap/version.c | 1 + tcpdump/jni/libpcap/version.h | 1 + tcpdump/jni/stub/Android.mk | 10 + tcpdump/jni/stub/stub.c | 0 tcpdump/jni/tcpdump/Android.mk | 57 + tcpdump/jni/tcpdump/CHANGES | 1136 + tcpdump/jni/tcpdump/CREDITS | 229 + tcpdump/jni/tcpdump/CleanSpec.mk | 49 + tcpdump/jni/tcpdump/INSTALL.txt | 213 + tcpdump/jni/tcpdump/LICENSE | 19 + tcpdump/jni/tcpdump/Makefile-devel-adds | 22 + tcpdump/jni/tcpdump/Makefile.in | 454 + tcpdump/jni/tcpdump/PLATFORMS | 9 + tcpdump/jni/tcpdump/README | 1 + tcpdump/jni/tcpdump/README.md | 243 + tcpdump/jni/tcpdump/Readme.Win32 | 24 + tcpdump/jni/tcpdump/TODO | 6 + tcpdump/jni/tcpdump/VERSION | 1 + tcpdump/jni/tcpdump/aclocal.m4 | 1438 ++ tcpdump/jni/tcpdump/addrtoname.c | 1229 ++ tcpdump/jni/tcpdump/addrtoname.h | 59 + tcpdump/jni/tcpdump/af.c | 59 + tcpdump/jni/tcpdump/af.h | 55 + tcpdump/jni/tcpdump/ah.h | 57 + tcpdump/jni/tcpdump/aodv.h | 191 + tcpdump/jni/tcpdump/appletalk.h | 166 + tcpdump/jni/tcpdump/arcnet.h | 101 + tcpdump/jni/tcpdump/atime.awk | 18 + tcpdump/jni/tcpdump/atm.h | 31 + tcpdump/jni/tcpdump/atmuni31.h | 85 + tcpdump/jni/tcpdump/bgp.h | 17 + tcpdump/jni/tcpdump/bootp.h | 231 + tcpdump/jni/tcpdump/bpf_dump.c | 62 + tcpdump/jni/tcpdump/chdlc.h | 26 + tcpdump/jni/tcpdump/checksum.c | 190 + tcpdump/jni/tcpdump/config.guess | 1435 ++ tcpdump/jni/tcpdump/config.h | 370 + tcpdump/jni/tcpdump/config.h.in | 397 + tcpdump/jni/tcpdump/config.sub | 1807 ++ tcpdump/jni/tcpdump/configure | 9731 +++++++++ tcpdump/jni/tcpdump/configure.in | 1174 ++ tcpdump/jni/tcpdump/cpack.c | 156 + tcpdump/jni/tcpdump/cpack.h | 56 + tcpdump/jni/tcpdump/dccp.h | 139 + tcpdump/jni/tcpdump/decnet.h | 461 + tcpdump/jni/tcpdump/decode_prefix.h | 41 + tcpdump/jni/tcpdump/enc.h | 47 + tcpdump/jni/tcpdump/esp.h | 68 + tcpdump/jni/tcpdump/ether.h | 58 + tcpdump/jni/tcpdump/ethertype.h | 200 + tcpdump/jni/tcpdump/extract.h | 217 + tcpdump/jni/tcpdump/fddi.h | 76 + tcpdump/jni/tcpdump/getopt_long.h | 66 + tcpdump/jni/tcpdump/gmpls.c | 193 + tcpdump/jni/tcpdump/gmpls.h | 33 + tcpdump/jni/tcpdump/gmt2local.c | 67 + tcpdump/jni/tcpdump/gmt2local.h | 25 + tcpdump/jni/tcpdump/icmp6.h | 473 + tcpdump/jni/tcpdump/ieee802_11.h | 347 + tcpdump/jni/tcpdump/ieee802_11_radio.h | 297 + tcpdump/jni/tcpdump/igrp.h | 33 + tcpdump/jni/tcpdump/in_cksum.c | 201 + tcpdump/jni/tcpdump/install-sh | 250 + tcpdump/jni/tcpdump/interface.h | 229 + tcpdump/jni/tcpdump/ip.h | 166 + tcpdump/jni/tcpdump/ip6.h | 201 + tcpdump/jni/tcpdump/ipfc.h | 29 + tcpdump/jni/tcpdump/ipnet.h | 13 + tcpdump/jni/tcpdump/ipproto.c | 57 + tcpdump/jni/tcpdump/ipproto.h | 145 + tcpdump/jni/tcpdump/ipsec_doi.h | 151 + tcpdump/jni/tcpdump/ipx.h | 31 + tcpdump/jni/tcpdump/isakmp.h | 501 + tcpdump/jni/tcpdump/l2tp.h | 62 + tcpdump/jni/tcpdump/l2vpn.c | 54 + tcpdump/jni/tcpdump/l2vpn.h | 16 + tcpdump/jni/tcpdump/lane.h | 41 + tcpdump/jni/tcpdump/lbl/os-osf4.h | 24 + tcpdump/jni/tcpdump/lbl/os-solaris2.h | 28 + tcpdump/jni/tcpdump/lbl/os-sunos4.h | 213 + tcpdump/jni/tcpdump/lbl/os-ultrix4.h | 37 + tcpdump/jni/tcpdump/llc.h | 122 + tcpdump/jni/tcpdump/machdep.c | 74 + tcpdump/jni/tcpdump/machdep.h | 25 + tcpdump/jni/tcpdump/makemib | 247 + tcpdump/jni/tcpdump/mib.h | 1460 ++ tcpdump/jni/tcpdump/missing/addrinfo.h | 117 + tcpdump/jni/tcpdump/missing/datalinks.c | 62 + tcpdump/jni/tcpdump/missing/dlnames.c | 170 + tcpdump/jni/tcpdump/missing/getnameinfo.c | 276 + tcpdump/jni/tcpdump/missing/getopt_long.c | 612 + tcpdump/jni/tcpdump/missing/inet_aton.c | 53 + tcpdump/jni/tcpdump/missing/inet_ntop.c | 216 + tcpdump/jni/tcpdump/missing/inet_pton.c | 49 + tcpdump/jni/tcpdump/missing/snprintf.c | 625 + tcpdump/jni/tcpdump/missing/sockstorage.h | 38 + tcpdump/jni/tcpdump/missing/strdup.c | 52 + tcpdump/jni/tcpdump/missing/strlcat.c | 73 + tcpdump/jni/tcpdump/missing/strlcpy.c | 70 + tcpdump/jni/tcpdump/missing/strsep.c | 80 + tcpdump/jni/tcpdump/mkdep | 112 + tcpdump/jni/tcpdump/mpls.h | 41 + tcpdump/jni/tcpdump/mptcp.h | 151 + tcpdump/jni/tcpdump/nameser.h | 314 + tcpdump/jni/tcpdump/netbios.h | 16 + tcpdump/jni/tcpdump/netdissect.h | 632 + tcpdump/jni/tcpdump/nfs.h | 438 + tcpdump/jni/tcpdump/nfsfh.h | 66 + tcpdump/jni/tcpdump/nlpid.c | 42 + tcpdump/jni/tcpdump/nlpid.h | 32 + tcpdump/jni/tcpdump/ntp.h | 127 + tcpdump/jni/tcpdump/oakley.h | 126 + tcpdump/jni/tcpdump/openflow.h | 51 + tcpdump/jni/tcpdump/ospf.h | 325 + tcpdump/jni/tcpdump/ospf6.h | 265 + tcpdump/jni/tcpdump/oui.c | 104 + tcpdump/jni/tcpdump/oui.h | 90 + tcpdump/jni/tcpdump/packetdat.awk | 61 + tcpdump/jni/tcpdump/parsenfsfh.c | 467 + tcpdump/jni/tcpdump/pcap-missing.h | 58 + tcpdump/jni/tcpdump/pcap_dump_ftell.c | 31 + tcpdump/jni/tcpdump/pmap_prot.h | 89 + tcpdump/jni/tcpdump/ppi.h | 9 + tcpdump/jni/tcpdump/ppp.h | 68 + tcpdump/jni/tcpdump/print-802_11.c | 3011 +++ tcpdump/jni/tcpdump/print-802_15_4.c | 180 + tcpdump/jni/tcpdump/print-ah.c | 64 + tcpdump/jni/tcpdump/print-ahcp.c | 421 + tcpdump/jni/tcpdump/print-aodv.c | 585 + tcpdump/jni/tcpdump/print-aoe.c | 432 + tcpdump/jni/tcpdump/print-ap1394.c | 113 + tcpdump/jni/tcpdump/print-arcnet.c | 359 + tcpdump/jni/tcpdump/print-arp.c | 414 + tcpdump/jni/tcpdump/print-ascii.c | 208 + tcpdump/jni/tcpdump/print-atalk.c | 622 + tcpdump/jni/tcpdump/print-atm.c | 461 + tcpdump/jni/tcpdump/print-babel.c | 606 + tcpdump/jni/tcpdump/print-beep.c | 59 + tcpdump/jni/tcpdump/print-bfd.c | 282 + tcpdump/jni/tcpdump/print-bgp.c | 2783 +++ tcpdump/jni/tcpdump/print-bootp.c | 1088 + tcpdump/jni/tcpdump/print-bt.c | 70 + tcpdump/jni/tcpdump/print-calm-fast.c | 60 + tcpdump/jni/tcpdump/print-carp.c | 82 + tcpdump/jni/tcpdump/print-cdp.c | 405 + tcpdump/jni/tcpdump/print-cfm.c | 637 + tcpdump/jni/tcpdump/print-chdlc.c | 205 + tcpdump/jni/tcpdump/print-cip.c | 107 + tcpdump/jni/tcpdump/print-cnfp.c | 476 + tcpdump/jni/tcpdump/print-dccp.c | 671 + tcpdump/jni/tcpdump/print-decnet.c | 1345 ++ tcpdump/jni/tcpdump/print-dhcp6.c | 810 + tcpdump/jni/tcpdump/print-domain.c | 750 + tcpdump/jni/tcpdump/print-dtp.c | 118 + tcpdump/jni/tcpdump/print-dvmrp.c | 366 + tcpdump/jni/tcpdump/print-eap.c | 296 + tcpdump/jni/tcpdump/print-egp.c | 356 + tcpdump/jni/tcpdump/print-eigrp.c | 474 + tcpdump/jni/tcpdump/print-enc.c | 137 + tcpdump/jni/tcpdump/print-esp.c | 722 + tcpdump/jni/tcpdump/print-ether.c | 445 + tcpdump/jni/tcpdump/print-fddi.c | 349 + tcpdump/jni/tcpdump/print-forces.c | 1760 ++ tcpdump/jni/tcpdump/print-fr.c | 929 + tcpdump/jni/tcpdump/print-frag6.c | 71 + tcpdump/jni/tcpdump/print-ftp.c | 35 + tcpdump/jni/tcpdump/print-geneve.c | 223 + tcpdump/jni/tcpdump/print-geonet.c | 279 + tcpdump/jni/tcpdump/print-gre.c | 396 + tcpdump/jni/tcpdump/print-hsrp.c | 134 + tcpdump/jni/tcpdump/print-http.c | 80 + tcpdump/jni/tcpdump/print-icmp.c | 697 + tcpdump/jni/tcpdump/print-icmp6.c | 1974 ++ tcpdump/jni/tcpdump/print-igmp.c | 340 + tcpdump/jni/tcpdump/print-igrp.c | 154 + tcpdump/jni/tcpdump/print-ip.c | 706 + tcpdump/jni/tcpdump/print-ip6.c | 277 + tcpdump/jni/tcpdump/print-ip6opts.c | 214 + tcpdump/jni/tcpdump/print-ipcomp.c | 83 + tcpdump/jni/tcpdump/print-ipfc.c | 135 + tcpdump/jni/tcpdump/print-ipnet.c | 116 + tcpdump/jni/tcpdump/print-ipx.c | 238 + tcpdump/jni/tcpdump/print-isakmp.c | 2996 +++ tcpdump/jni/tcpdump/print-isoclns.c | 3118 +++ tcpdump/jni/tcpdump/print-juniper.c | 1464 ++ tcpdump/jni/tcpdump/print-krb.c | 257 + tcpdump/jni/tcpdump/print-l2tp.c | 748 + tcpdump/jni/tcpdump/print-lane.c | 123 + tcpdump/jni/tcpdump/print-ldp.c | 699 + tcpdump/jni/tcpdump/print-llc.c | 538 + tcpdump/jni/tcpdump/print-lldp.c | 1613 ++ tcpdump/jni/tcpdump/print-lmp.c | 880 + tcpdump/jni/tcpdump/print-loopback.c | 136 + tcpdump/jni/tcpdump/print-lspping.c | 889 + tcpdump/jni/tcpdump/print-lwapp.c | 348 + tcpdump/jni/tcpdump/print-lwres.c | 596 + tcpdump/jni/tcpdump/print-m3ua.c | 339 + tcpdump/jni/tcpdump/print-mobile.c | 102 + tcpdump/jni/tcpdump/print-mobility.c | 334 + tcpdump/jni/tcpdump/print-mpcp.c | 260 + tcpdump/jni/tcpdump/print-mpls.c | 211 + tcpdump/jni/tcpdump/print-mptcp.c | 429 + tcpdump/jni/tcpdump/print-msdp.c | 102 + tcpdump/jni/tcpdump/print-msnlb.c | 64 + tcpdump/jni/tcpdump/print-netbios.c | 91 + tcpdump/jni/tcpdump/print-nflog.c | 167 + tcpdump/jni/tcpdump/print-nfs.c | 1734 ++ tcpdump/jni/tcpdump/print-ntp.c | 427 + tcpdump/jni/tcpdump/print-null.c | 146 + tcpdump/jni/tcpdump/print-olsr.c | 644 + tcpdump/jni/tcpdump/print-openflow-1.0.c | 2560 +++ tcpdump/jni/tcpdump/print-openflow.c | 142 + tcpdump/jni/tcpdump/print-ospf.c | 1141 + tcpdump/jni/tcpdump/print-ospf6.c | 1009 + tcpdump/jni/tcpdump/print-otv.c | 65 + tcpdump/jni/tcpdump/print-pflog.c | 185 + tcpdump/jni/tcpdump/print-pgm.c | 820 + tcpdump/jni/tcpdump/print-pim.c | 1093 + tcpdump/jni/tcpdump/print-pktap.c | 169 + tcpdump/jni/tcpdump/print-ppi.c | 119 + tcpdump/jni/tcpdump/print-ppp.c | 1851 ++ tcpdump/jni/tcpdump/print-pppoe.c | 200 + tcpdump/jni/tcpdump/print-pptp.c | 1005 + tcpdump/jni/tcpdump/print-radius.c | 989 + tcpdump/jni/tcpdump/print-raw.c | 44 + tcpdump/jni/tcpdump/print-rip.c | 272 + tcpdump/jni/tcpdump/print-ripng.c | 176 + tcpdump/jni/tcpdump/print-rpki-rtr.c | 368 + tcpdump/jni/tcpdump/print-rrcp.c | 130 + tcpdump/jni/tcpdump/print-rsvp.c | 1935 ++ tcpdump/jni/tcpdump/print-rt6.c | 111 + tcpdump/jni/tcpdump/print-rtsp.c | 50 + tcpdump/jni/tcpdump/print-rx.c | 2884 +++ tcpdump/jni/tcpdump/print-sctp.c | 760 + tcpdump/jni/tcpdump/print-sflow.c | 941 + tcpdump/jni/tcpdump/print-sip.c | 53 + tcpdump/jni/tcpdump/print-sl.c | 248 + tcpdump/jni/tcpdump/print-sll.c | 308 + tcpdump/jni/tcpdump/print-slow.c | 658 + tcpdump/jni/tcpdump/print-smb.c | 1493 ++ tcpdump/jni/tcpdump/print-smtp.c | 30 + tcpdump/jni/tcpdump/print-snmp.c | 1909 ++ tcpdump/jni/tcpdump/print-stp.c | 464 + tcpdump/jni/tcpdump/print-sunatm.c | 107 + tcpdump/jni/tcpdump/print-sunrpc.c | 255 + tcpdump/jni/tcpdump/print-symantec.c | 113 + tcpdump/jni/tcpdump/print-syslog.c | 145 + tcpdump/jni/tcpdump/print-tcp.c | 897 + tcpdump/jni/tcpdump/print-telnet.c | 547 + tcpdump/jni/tcpdump/print-tftp.c | 185 + tcpdump/jni/tcpdump/print-timed.c | 147 + tcpdump/jni/tcpdump/print-tipc.c | 385 + tcpdump/jni/tcpdump/print-token.c | 250 + tcpdump/jni/tcpdump/print-udld.c | 167 + tcpdump/jni/tcpdump/print-udp.c | 708 + tcpdump/jni/tcpdump/print-usb.c | 175 + tcpdump/jni/tcpdump/print-vjc.c | 110 + tcpdump/jni/tcpdump/print-vqp.c | 200 + tcpdump/jni/tcpdump/print-vrrp.c | 182 + tcpdump/jni/tcpdump/print-vtp.c | 373 + tcpdump/jni/tcpdump/print-vxlan.c | 62 + tcpdump/jni/tcpdump/print-wb.c | 452 + tcpdump/jni/tcpdump/print-zephyr.c | 317 + tcpdump/jni/tcpdump/print-zeromq.c | 219 + tcpdump/jni/tcpdump/route6d.h | 77 + tcpdump/jni/tcpdump/rpc_auth.h | 78 + tcpdump/jni/tcpdump/rpc_msg.h | 127 + tcpdump/jni/tcpdump/rpl.h | 174 + tcpdump/jni/tcpdump/rx.h | 113 + tcpdump/jni/tcpdump/sctpConstants.h | 571 + tcpdump/jni/tcpdump/sctpHeader.h | 323 + tcpdump/jni/tcpdump/send-ack.awk | 68 + tcpdump/jni/tcpdump/setsignal.c | 90 + tcpdump/jni/tcpdump/setsignal.h | 25 + tcpdump/jni/tcpdump/signature.c | 158 + tcpdump/jni/tcpdump/signature.h | 27 + tcpdump/jni/tcpdump/slcompress.h | 85 + tcpdump/jni/tcpdump/slip.h | 34 + tcpdump/jni/tcpdump/sll.h | 127 + tcpdump/jni/tcpdump/smb.h | 122 + tcpdump/jni/tcpdump/smbutil.c | 1894 ++ tcpdump/jni/tcpdump/stime.awk | 19 + tcpdump/jni/tcpdump/strcasecmp.c | 88 + tcpdump/jni/tcpdump/tcp.h | 136 + tcpdump/jni/tcpdump/tcpdump-stdinc.h | 352 + tcpdump/jni/tcpdump/tcpdump.1.in | 1976 ++ tcpdump/jni/tcpdump/tcpdump.c | 2729 +++ tcpdump/jni/tcpdump/telnet.h | 348 + tcpdump/jni/tcpdump/tftp.h | 82 + tcpdump/jni/tcpdump/timed.h | 97 + tcpdump/jni/tcpdump/token.h | 52 + tcpdump/jni/tcpdump/udp.h | 103 + tcpdump/jni/tcpdump/util.c | 890 + tcpdump/jni/tcpdump/version.c | 1 + tcpdump/jni/tcpdump/vfprintf.c | 54 + tcpdump/jni/tcpdump/win32/Include/bittypes.h | 89 + tcpdump/jni/tcpdump/win32/Include/errno.h | 132 + tcpdump/jni/tcpdump/win32/Include/getopt.h | 138 + tcpdump/jni/tcpdump/win32/Include/w32_fzs.h | 48 + tcpdump/jni/tcpdump/win32/Src/getopt.c | 117 + tcpdump/jni/tcpdump/win32/prj/GNUmakefile | 175 + tcpdump/jni/tcpdump/win32/prj/WinDump.dsp | 643 + tcpdump/jni/tcpdump/win32/prj/WinDump.dsw | 29 + tcpdump/jni/tcpdump/win32/prj/WinDump.sln | 20 + tcpdump/jni/tcpdump/win32/prj/WinDump.vcproj | 3254 +++ tcpdump/jni/tcpdump/win32/src/ether_ntohost.c | 219 + tcpdump/src/main/AndroidManifest.xml | 1 + webserver/build.gradle | 67 + webserver/jni/Android.mk | 39 + webserver/jni/Application.mk | 2 + webserver/jni/mongoose/LICENSE | 16 + webserver/jni/mongoose/README.md | 178 + webserver/jni/mongoose/mongoose.c | 17594 ++++++++++++++++ webserver/jni/mongoose/mongoose.h | 3013 +++ webserver/jni/stub.c | 0 webserver/jni/webserver.c | 159 + webserver/src/main/AndroidManifest.xml | 1 + 2415 files changed, 312708 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 RELEASING.md create mode 100644 Resources/XDADevelopers.png create mode 100644 Resources/adaway_screenshot.png create mode 100644 Resources/certificate/generate.sh create mode 100644 Resources/certificate/ssl.conf create mode 100644 Resources/device-2013-06-19-105150.png create mode 100644 Resources/device-2013-06-19-105158.png create mode 100644 Resources/device-2013-06-19-105215.png create mode 100644 Resources/download_fdroid.png create mode 100644 Resources/download_google_play.png create mode 100644 Resources/get-it-on-adaway.png create mode 100644 Resources/get-it-on-fdroid.png create mode 100644 Resources/icon.svg create mode 100644 Resources/icon.xcf create mode 100644 Resources/icon_background.png create mode 100644 Resources/icon_background.xcf create mode 100644 Resources/icon_foreground.png create mode 100644 Resources/icon_foreground.xcf create mode 100644 Resources/icon_old.svg create mode 100644 Resources/logo_googlecode.png create mode 100644 Resources/logo_market.png create mode 100644 Resources/paypal_donate_button.gif create mode 100644 Resources/screenshot1.png create mode 100644 Resources/screenshot2.png create mode 100644 Resources/screenshot3.png create mode 100644 Resources/screenshot4.png create mode 100644 Resources/screenshot5.png create mode 100644 Resources/screenshot6.png create mode 100644 Resources/status_bar_icon.svg create mode 100644 Resources/symlink_hosts_to_data.zip create mode 100644 Resources/tasker/1-create-tasks.jpg create mode 100644 Resources/tasker/2-enable-adblock-task.jpg create mode 100644 Resources/tasker/3-enable-adblock-task-details1.jpg create mode 100644 Resources/tasker/4-enable-adblock-task-details2.jpg create mode 100644 Resources/tasker/5-disable-adblock-task.jpg create mode 100644 Resources/tasker/6-disable-adblock-task-details1.jpg create mode 100644 Resources/tasker/7-disable-adblock-task-details2.jpg create mode 100644 Resources/test-webserver.sh create mode 100644 THIRD_PARTY_LICENSES.md create mode 100644 TRANSLATING.md create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/lint.xml create mode 100644 app/proguard-rules.pro create mode 100644 app/schemas/org.adaway.db.AppDatabase/1.json create mode 100644 app/schemas/org.adaway.db.AppDatabase/2.json create mode 100644 app/schemas/org.adaway.db.AppDatabase/3.json create mode 100644 app/schemas/org.adaway.db.AppDatabase/4.json create mode 100644 app/schemas/org.adaway.db.AppDatabase/5.json create mode 100644 app/schemas/org.adaway.db.AppDatabase/6.json create mode 100644 app/schemas/org.adaway.db.AppDatabase/7.json create mode 100644 app/src/androidTest/java/org/adaway/db/DbTest.java create mode 100644 app/src/androidTest/java/org/adaway/db/HostDbTest.java create mode 100644 app/src/androidTest/java/org/adaway/db/SourceDbTest.java create mode 100644 app/src/androidTest/java/org/adaway/db/UserListTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/assets/icon.svg create mode 100644 app/src/main/assets/localhost-2410.crt create mode 100644 app/src/main/assets/localhost-2410.key create mode 100644 app/src/main/assets/test.html create mode 100644 app/src/main/icon-web.png create mode 100644 app/src/main/java/org/adaway/AdAwayApplication.java create mode 100644 app/src/main/java/org/adaway/broadcast/BootReceiver.java create mode 100644 app/src/main/java/org/adaway/broadcast/Command.java create mode 100644 app/src/main/java/org/adaway/broadcast/CommandReceiver.java create mode 100644 app/src/main/java/org/adaway/broadcast/UpdateReceiver.java create mode 100644 app/src/main/java/org/adaway/db/AppDatabase.java create mode 100644 app/src/main/java/org/adaway/db/Migrations.java create mode 100644 app/src/main/java/org/adaway/db/converter/ListTypeConverter.java create mode 100644 app/src/main/java/org/adaway/db/converter/ZonedDateTimeConverter.java create mode 100644 app/src/main/java/org/adaway/db/dao/HostEntryDao.java create mode 100644 app/src/main/java/org/adaway/db/dao/HostListItemDao.java create mode 100644 app/src/main/java/org/adaway/db/dao/HostsSourceDao.java create mode 100644 app/src/main/java/org/adaway/db/entity/HostEntry.java create mode 100644 app/src/main/java/org/adaway/db/entity/HostListItem.java create mode 100644 app/src/main/java/org/adaway/db/entity/HostsSource.java create mode 100644 app/src/main/java/org/adaway/db/entity/ListType.java create mode 100644 app/src/main/java/org/adaway/db/entity/SourceType.java create mode 100644 app/src/main/java/org/adaway/helper/NotificationHelper.java create mode 100644 app/src/main/java/org/adaway/helper/PreferenceHelper.java create mode 100644 app/src/main/java/org/adaway/helper/ThemeHelper.java create mode 100644 app/src/main/java/org/adaway/model/adblocking/AdBlockMethod.java create mode 100644 app/src/main/java/org/adaway/model/adblocking/AdBlockModel.java create mode 100644 app/src/main/java/org/adaway/model/adblocking/UndefinedBlockModel.java create mode 100644 app/src/main/java/org/adaway/model/backup/AppBackupAgent.java create mode 100644 app/src/main/java/org/adaway/model/backup/BackupExporter.java create mode 100644 app/src/main/java/org/adaway/model/backup/BackupFormat.java create mode 100644 app/src/main/java/org/adaway/model/backup/BackupImporter.java create mode 100644 app/src/main/java/org/adaway/model/error/HostError.java create mode 100644 app/src/main/java/org/adaway/model/error/HostErrorException.java create mode 100644 app/src/main/java/org/adaway/model/git/GistHostsSource.java create mode 100644 app/src/main/java/org/adaway/model/git/GitHostsJsonApiSource.java create mode 100644 app/src/main/java/org/adaway/model/git/GitHostsSource.java create mode 100644 app/src/main/java/org/adaway/model/git/GitHubHostsSource.java create mode 100644 app/src/main/java/org/adaway/model/git/GitLabHostsSource.java create mode 100644 app/src/main/java/org/adaway/model/root/CommandException.java create mode 100644 app/src/main/java/org/adaway/model/root/MountType.java create mode 100644 app/src/main/java/org/adaway/model/root/RootModel.java create mode 100644 app/src/main/java/org/adaway/model/root/ShellUtils.java create mode 100644 app/src/main/java/org/adaway/model/root/TcpdumpUtils.java create mode 100644 app/src/main/java/org/adaway/model/root/package-info.java create mode 100644 app/src/main/java/org/adaway/model/source/SourceLoader.java create mode 100644 app/src/main/java/org/adaway/model/source/SourceModel.java create mode 100644 app/src/main/java/org/adaway/model/source/SourceUpdateService.java create mode 100644 app/src/main/java/org/adaway/model/update/ApkDownloadReceiver.java create mode 100644 app/src/main/java/org/adaway/model/update/ApkUpdateService.java create mode 100644 app/src/main/java/org/adaway/model/update/Manifest.java create mode 100644 app/src/main/java/org/adaway/model/update/UpdateModel.java create mode 100644 app/src/main/java/org/adaway/model/update/UpdateStore.java create mode 100644 app/src/main/java/org/adaway/model/vpn/VpnModel.java create mode 100644 app/src/main/java/org/adaway/tile/AdBlockingTileService.java create mode 100644 app/src/main/java/org/adaway/ui/Animations.java create mode 100644 app/src/main/java/org/adaway/ui/adblocking/ApplyConfigurationSnackbar.java create mode 100644 app/src/main/java/org/adaway/ui/adware/AdwareFragment.java create mode 100644 app/src/main/java/org/adaway/ui/adware/AdwareInstall.java create mode 100644 app/src/main/java/org/adaway/ui/adware/AdwareLiveData.java create mode 100644 app/src/main/java/org/adaway/ui/adware/AdwareViewModel.java create mode 100644 app/src/main/java/org/adaway/ui/dialog/AlertDialogValidator.java create mode 100644 app/src/main/java/org/adaway/ui/dialog/MissingAppDialog.java create mode 100644 app/src/main/java/org/adaway/ui/help/HelpActivity.java create mode 100644 app/src/main/java/org/adaway/ui/help/HelpFragmentHtml.java create mode 100644 app/src/main/java/org/adaway/ui/home/HomeActivity.java create mode 100644 app/src/main/java/org/adaway/ui/home/HomeViewModel.java create mode 100644 app/src/main/java/org/adaway/ui/hosts/HostsSourcesActivity.java create mode 100644 app/src/main/java/org/adaway/ui/hosts/HostsSourcesAdapter.java create mode 100644 app/src/main/java/org/adaway/ui/hosts/HostsSourcesFragment.java create mode 100644 app/src/main/java/org/adaway/ui/hosts/HostsSourcesViewCallback.java create mode 100644 app/src/main/java/org/adaway/ui/hosts/HostsSourcesViewModel.java create mode 100644 app/src/main/java/org/adaway/ui/lists/ListsActivity.java create mode 100644 app/src/main/java/org/adaway/ui/lists/ListsFilter.java create mode 100644 app/src/main/java/org/adaway/ui/lists/ListsFragmentPagerAdapter.java create mode 100644 app/src/main/java/org/adaway/ui/lists/ListsViewCallback.java create mode 100644 app/src/main/java/org/adaway/ui/lists/ListsViewModel.java create mode 100644 app/src/main/java/org/adaway/ui/lists/type/AbstractListFragment.java create mode 100644 app/src/main/java/org/adaway/ui/lists/type/AllowedHostsFragment.java create mode 100644 app/src/main/java/org/adaway/ui/lists/type/BlockedHostsFragment.java create mode 100644 app/src/main/java/org/adaway/ui/lists/type/ListsAdapter.java create mode 100644 app/src/main/java/org/adaway/ui/lists/type/RedirectedHostsFragment.java create mode 100644 app/src/main/java/org/adaway/ui/log/LogActivity.java create mode 100644 app/src/main/java/org/adaway/ui/log/LogAdapter.java create mode 100644 app/src/main/java/org/adaway/ui/log/LogEntry.java create mode 100644 app/src/main/java/org/adaway/ui/log/LogEntrySort.java create mode 100644 app/src/main/java/org/adaway/ui/log/LogViewCallback.java create mode 100644 app/src/main/java/org/adaway/ui/log/LogViewModel.java create mode 100644 app/src/main/java/org/adaway/ui/prefs/PrefsActivity.java create mode 100644 app/src/main/java/org/adaway/ui/prefs/PrefsBackupRestoreFragment.java create mode 100644 app/src/main/java/org/adaway/ui/prefs/PrefsMainFragment.java create mode 100644 app/src/main/java/org/adaway/ui/prefs/PrefsRootFragment.java create mode 100644 app/src/main/java/org/adaway/ui/prefs/PrefsUpdateFragment.java create mode 100644 app/src/main/java/org/adaway/ui/prefs/PrefsVpnFragment.java create mode 100644 app/src/main/java/org/adaway/ui/prefs/exclusion/ExcludedAppController.java create mode 100644 app/src/main/java/org/adaway/ui/prefs/exclusion/PrefsVpnExcludedAppsActivity.java create mode 100644 app/src/main/java/org/adaway/ui/prefs/exclusion/UserApp.java create mode 100644 app/src/main/java/org/adaway/ui/prefs/exclusion/UserAppRecycleViewAdapter.java create mode 100644 app/src/main/java/org/adaway/ui/source/SourceEditActivity.java create mode 100644 app/src/main/java/org/adaway/ui/support/SupportActivity.java create mode 100644 app/src/main/java/org/adaway/ui/update/CompleteDownloadStatus.java create mode 100644 app/src/main/java/org/adaway/ui/update/DownloadStatus.java create mode 100644 app/src/main/java/org/adaway/ui/update/PendingDownloadStatus.java create mode 100644 app/src/main/java/org/adaway/ui/update/UpdateActivity.java create mode 100644 app/src/main/java/org/adaway/ui/update/UpdateViewModel.java create mode 100644 app/src/main/java/org/adaway/ui/welcome/WelcomeActivity.java create mode 100644 app/src/main/java/org/adaway/ui/welcome/WelcomeFragment.java create mode 100644 app/src/main/java/org/adaway/ui/welcome/WelcomeMethodFragment.java create mode 100644 app/src/main/java/org/adaway/ui/welcome/WelcomeNavigable.java create mode 100644 app/src/main/java/org/adaway/ui/welcome/WelcomePagerAdapter.java create mode 100644 app/src/main/java/org/adaway/ui/welcome/WelcomeSupportFragment.java create mode 100644 app/src/main/java/org/adaway/ui/welcome/WelcomeSyncFragment.java create mode 100644 app/src/main/java/org/adaway/util/AppExecutors.java create mode 100644 app/src/main/java/org/adaway/util/Clipboard.java create mode 100644 app/src/main/java/org/adaway/util/Constants.java create mode 100644 app/src/main/java/org/adaway/util/RegexUtils.java create mode 100644 app/src/main/java/org/adaway/util/WebServerUtils.java create mode 100644 app/src/main/java/org/adaway/util/log/ApplicationLog.java create mode 100644 app/src/main/java/org/adaway/util/log/SentryLog.java create mode 100644 app/src/main/java/org/adaway/vpn/VpnService.java create mode 100644 app/src/main/java/org/adaway/vpn/VpnServiceControls.java create mode 100644 app/src/main/java/org/adaway/vpn/VpnServiceHeartbeat.java create mode 100644 app/src/main/java/org/adaway/vpn/VpnStatus.java create mode 100644 app/src/main/java/org/adaway/vpn/dns/DnsPacketProxy.java create mode 100644 app/src/main/java/org/adaway/vpn/dns/DnsQuery.java create mode 100644 app/src/main/java/org/adaway/vpn/dns/DnsQueryQueue.java create mode 100644 app/src/main/java/org/adaway/vpn/dns/DnsServerMapper.java create mode 100644 app/src/main/java/org/adaway/vpn/dns/DohPacketProxy.java create mode 100644 app/src/main/java/org/adaway/vpn/dns/Subnet.java create mode 100644 app/src/main/java/org/adaway/vpn/worker/VpnBuilder.java create mode 100644 app/src/main/java/org/adaway/vpn/worker/VpnConnectionMonitor.java create mode 100644 app/src/main/java/org/adaway/vpn/worker/VpnConnectionThrottler.java create mode 100644 app/src/main/java/org/adaway/vpn/worker/VpnNetworkException.java create mode 100644 app/src/main/java/org/adaway/vpn/worker/VpnWatchdog.java create mode 100644 app/src/main/java/org/adaway/vpn/worker/VpnWorker.java create mode 100644 app/src/main/res/animator/fragment_close_enter.xml create mode 100644 app/src/main/res/animator/fragment_close_exit.xml create mode 100644 app/src/main/res/animator/fragment_open_enter.xml create mode 100644 app/src/main/res/animator/fragment_open_exit.xml create mode 100644 app/src/main/res/drawable/baseline_block_24.xml create mode 100644 app/src/main/res/drawable/baseline_check_24.xml create mode 100644 app/src/main/res/drawable/baseline_clear_all_24.xml create mode 100644 app/src/main/res/drawable/baseline_compare_arrows_24.xml create mode 100644 app/src/main/res/drawable/baseline_edit_24.xml create mode 100644 app/src/main/res/drawable/baseline_favorite_24.xml create mode 100644 app/src/main/res/drawable/baseline_search_24.xml create mode 100644 app/src/main/res/drawable/baseline_sort_by_alpha_24.xml create mode 100644 app/src/main/res/drawable/dot.xml create mode 100644 app/src/main/res/drawable/dot_outline.xml create mode 100644 app/src/main/res/drawable/ic_add_black_24px.xml create mode 100644 app/src/main/res/drawable/ic_add_circle_outline_24dp.xml create mode 100644 app/src/main/res/drawable/ic_brightness_medium_24dp.xml create mode 100644 app/src/main/res/drawable/ic_bug_report_24dp.xml create mode 100644 app/src/main/res/drawable/ic_cloud_off_24dp.xml create mode 100644 app/src/main/res/drawable/ic_collections_bookmark_24dp.xml create mode 100644 app/src/main/res/drawable/ic_error_outline_24dp.xml create mode 100644 app/src/main/res/drawable/ic_get_app_24dp.xml create mode 100644 app/src/main/res/drawable/ic_github_24dp.xml create mode 100644 app/src/main/res/drawable/ic_github_32dp.xml create mode 100644 app/src/main/res/drawable/ic_help_24dp.xml create mode 100644 app/src/main/res/drawable/ic_ipv6_24dp.xml create mode 100644 app/src/main/res/drawable/ic_language_24dp.xml create mode 100644 app/src/main/res/drawable/ic_language_red.xml create mode 100644 app/src/main/res/drawable/ic_list_red.xml create mode 100644 app/src/main/res/drawable/ic_menu_24dp.xml create mode 100644 app/src/main/res/drawable/ic_outline_rule_24.xml create mode 100644 app/src/main/res/drawable/ic_pause_24dp.xml create mode 100644 app/src/main/res/drawable/ic_playlist_add_24dp.xml create mode 100644 app/src/main/res/drawable/ic_record_24dp.xml create mode 100644 app/src/main/res/drawable/ic_remove_circle_outline_24dp.xml create mode 100644 app/src/main/res/drawable/ic_save_24dp.xml create mode 100644 app/src/main/res/drawable/ic_sd_storage_24dp.xml create mode 100644 app/src/main/res/drawable/ic_settings_24dp.xml create mode 100644 app/src/main/res/drawable/ic_settings_backup_restore_24dp.xml create mode 100644 app/src/main/res/drawable/ic_settings_red.xml create mode 100644 app/src/main/res/drawable/ic_superuser_24dp.xml create mode 100644 app/src/main/res/drawable/ic_sync_24dp.xml create mode 100644 app/src/main/res/drawable/ic_vpn_key_24dp.xml create mode 100644 app/src/main/res/drawable/icon_monochrome.xml create mode 100644 app/src/main/res/drawable/logo.xml create mode 100644 app/src/main/res/drawable/notifications_off_24.xml create mode 100644 app/src/main/res/drawable/outline_cloud_upload_24.xml create mode 100644 app/src/main/res/drawable/outline_create_24.xml create mode 100644 app/src/main/res/drawable/outline_delete_24.xml create mode 100644 app/src/main/res/drawable/paypal.xml create mode 100644 app/src/main/res/drawable/shadow.xml create mode 100644 app/src/main/res/layout/adware_fragment.xml create mode 100644 app/src/main/res/layout/checkbox_list_entry.xml create mode 100644 app/src/main/res/layout/checkbox_list_two_entries.xml create mode 100644 app/src/main/res/layout/drawer_list_item.xml create mode 100644 app/src/main/res/layout/help_activity.xml create mode 100644 app/src/main/res/layout/help_fragment.xml create mode 100644 app/src/main/res/layout/home_activity.xml create mode 100644 app/src/main/res/layout/home_content.xml create mode 100644 app/src/main/res/layout/hosts_content_fragment.xml create mode 100644 app/src/main/res/layout/hosts_lists_fragment.xml create mode 100644 app/src/main/res/layout/hosts_sources_activity.xml create mode 100644 app/src/main/res/layout/hosts_sources_card.xml create mode 100644 app/src/main/res/layout/hosts_sources_dialog.xml create mode 100644 app/src/main/res/layout/hosts_sources_fragment.xml create mode 100644 app/src/main/res/layout/list_two_entries.xml create mode 100644 app/src/main/res/layout/lists_activity.xml create mode 100644 app/src/main/res/layout/lists_allowed_dialog.xml create mode 100644 app/src/main/res/layout/lists_blocked_dialog.xml create mode 100644 app/src/main/res/layout/lists_fragment.xml create mode 100644 app/src/main/res/layout/lists_redirected_dialog.xml create mode 100644 app/src/main/res/layout/log_activity.xml create mode 100644 app/src/main/res/layout/log_entry.xml create mode 100644 app/src/main/res/layout/log_redirect_dialog.xml create mode 100644 app/src/main/res/layout/pref_edittext_dialog.xml create mode 100644 app/src/main/res/layout/prefs_activity.xml create mode 100644 app/src/main/res/layout/reboot_dialog.xml create mode 100644 app/src/main/res/layout/source_edit_activity.xml create mode 100644 app/src/main/res/layout/support_activity.xml create mode 100644 app/src/main/res/layout/update_actity.xml create mode 100644 app/src/main/res/layout/vpn_excluded_app_activity.xml create mode 100644 app/src/main/res/layout/vpn_excluded_app_entry.xml create mode 100644 app/src/main/res/layout/welcome_activity.xml create mode 100644 app/src/main/res/layout/welcome_method_layout.xml create mode 100644 app/src/main/res/layout/welcome_support_layout.xml create mode 100644 app/src/main/res/layout/welcome_sync_layout.xml create mode 100644 app/src/main/res/menu/checkbox_list_context.xml create mode 100644 app/src/main/res/menu/home_drawer.xml create mode 100644 app/src/main/res/menu/list_menu.xml create mode 100644 app/src/main/res/menu/lists_navigation.xml create mode 100644 app/src/main/res/menu/log_menu.xml create mode 100644 app/src/main/res/menu/next_actions.xml create mode 100644 app/src/main/res/menu/source_edit_menu.xml create mode 100644 app/src/main/res/menu/vpn_excluded_app_menu.xml create mode 100644 app/src/main/res/mipmap-anydpi/icon.xml create mode 100644 app/src/main/res/mipmap-anydpi/icon_round.xml create mode 100644 app/src/main/res/mipmap-anydpi/shortcut_dns_requests.xml create mode 100644 app/src/main/res/mipmap-anydpi/shortcut_preferences.xml create mode 100644 app/src/main/res/mipmap-anydpi/shortcut_your_lists.xml create mode 100755 app/src/main/res/mipmap-hdpi/icon.png create mode 100644 app/src/main/res/mipmap-hdpi/icon_foreground.png create mode 100755 app/src/main/res/mipmap-hdpi/icon_round.png create mode 100755 app/src/main/res/mipmap-mdpi/icon.png create mode 100644 app/src/main/res/mipmap-mdpi/icon_foreground.png create mode 100755 app/src/main/res/mipmap-mdpi/icon_round.png create mode 100755 app/src/main/res/mipmap-xhdpi/icon.png create mode 100644 app/src/main/res/mipmap-xhdpi/icon_foreground.png create mode 100755 app/src/main/res/mipmap-xhdpi/icon_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/icon.png create mode 100644 app/src/main/res/mipmap-xxhdpi/icon_foreground.png create mode 100755 app/src/main/res/mipmap-xxhdpi/icon_round.png create mode 100755 app/src/main/res/mipmap-xxxhdpi/icon.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/icon_foreground.png create mode 100755 app/src/main/res/mipmap-xxxhdpi/icon_round.png create mode 100644 app/src/main/res/raw-af/help_faq.html create mode 100644 app/src/main/res/raw-af/help_problems.html create mode 100644 app/src/main/res/raw-af/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ar/help_faq.html create mode 100644 app/src/main/res/raw-ar/help_problems.html create mode 100644 app/src/main/res/raw-ar/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ast/help_faq.html create mode 100644 app/src/main/res/raw-ast/help_problems.html create mode 100644 app/src/main/res/raw-ast/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-az/help_faq.html create mode 100644 app/src/main/res/raw-az/help_problems.html create mode 100644 app/src/main/res/raw-az/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-be/help_faq.html create mode 100644 app/src/main/res/raw-be/help_problems.html create mode 100644 app/src/main/res/raw-be/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-bg/help_faq.html create mode 100644 app/src/main/res/raw-bg/help_problems.html create mode 100644 app/src/main/res/raw-bg/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-bn/help_faq.html create mode 100644 app/src/main/res/raw-bn/help_problems.html create mode 100644 app/src/main/res/raw-bn/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ca/help_faq.html create mode 100644 app/src/main/res/raw-ca/help_problems.html create mode 100644 app/src/main/res/raw-ca/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-cs/help_faq.html create mode 100644 app/src/main/res/raw-cs/help_problems.html create mode 100644 app/src/main/res/raw-cs/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-da/help_faq.html create mode 100644 app/src/main/res/raw-da/help_problems.html create mode 100644 app/src/main/res/raw-da/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-de/help_faq.html create mode 100644 app/src/main/res/raw-de/help_problems.html create mode 100644 app/src/main/res/raw-de/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-el/help_faq.html create mode 100644 app/src/main/res/raw-el/help_problems.html create mode 100644 app/src/main/res/raw-el/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-en-rUS/help_faq.html create mode 100644 app/src/main/res/raw-en-rUS/help_problems.html create mode 100644 app/src/main/res/raw-en-rUS/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-eo/help_faq.html create mode 100644 app/src/main/res/raw-eo/help_problems.html create mode 100644 app/src/main/res/raw-eo/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-es-rMX/help_faq.html create mode 100644 app/src/main/res/raw-es-rMX/help_problems.html create mode 100644 app/src/main/res/raw-es-rMX/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-es/help_faq.html create mode 100644 app/src/main/res/raw-es/help_problems.html create mode 100644 app/src/main/res/raw-es/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-et/help_faq.html create mode 100644 app/src/main/res/raw-et/help_problems.html create mode 100644 app/src/main/res/raw-et/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-eu/help_faq.html create mode 100644 app/src/main/res/raw-eu/help_problems.html create mode 100644 app/src/main/res/raw-eu/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-fa/help_faq.html create mode 100644 app/src/main/res/raw-fa/help_problems.html create mode 100644 app/src/main/res/raw-fa/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-fi/help_faq.html create mode 100644 app/src/main/res/raw-fi/help_problems.html create mode 100644 app/src/main/res/raw-fi/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-fil/help_faq.html create mode 100644 app/src/main/res/raw-fil/help_problems.html create mode 100644 app/src/main/res/raw-fil/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-fr/help_faq.html create mode 100644 app/src/main/res/raw-fr/help_problems.html create mode 100644 app/src/main/res/raw-fr/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-gl/help_faq.html create mode 100644 app/src/main/res/raw-gl/help_problems.html create mode 100644 app/src/main/res/raw-gl/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-hi/help_faq.html create mode 100644 app/src/main/res/raw-hi/help_problems.html create mode 100644 app/src/main/res/raw-hi/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-hr/help_faq.html create mode 100644 app/src/main/res/raw-hr/help_problems.html create mode 100644 app/src/main/res/raw-hr/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-hu/help_faq.html create mode 100644 app/src/main/res/raw-hu/help_problems.html create mode 100644 app/src/main/res/raw-hu/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-in/help_faq.html create mode 100644 app/src/main/res/raw-in/help_problems.html create mode 100644 app/src/main/res/raw-in/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-is/help_faq.html create mode 100644 app/src/main/res/raw-is/help_problems.html create mode 100644 app/src/main/res/raw-is/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-it/help_faq.html create mode 100644 app/src/main/res/raw-it/help_problems.html create mode 100644 app/src/main/res/raw-it/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-iw/help_faq.html create mode 100644 app/src/main/res/raw-iw/help_problems.html create mode 100644 app/src/main/res/raw-iw/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ja/help_faq.html create mode 100644 app/src/main/res/raw-ja/help_problems.html create mode 100644 app/src/main/res/raw-ja/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-km/help_faq.html create mode 100644 app/src/main/res/raw-km/help_problems.html create mode 100644 app/src/main/res/raw-km/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ko/help_faq.html create mode 100644 app/src/main/res/raw-ko/help_problems.html create mode 100644 app/src/main/res/raw-ko/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ku/help_faq.html create mode 100644 app/src/main/res/raw-ku/help_problems.html create mode 100644 app/src/main/res/raw-ku/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-lt/help_faq.html create mode 100644 app/src/main/res/raw-lt/help_problems.html create mode 100644 app/src/main/res/raw-lt/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ml/help_faq.html create mode 100644 app/src/main/res/raw-ml/help_problems.html create mode 100644 app/src/main/res/raw-ml/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ms/help_faq.html create mode 100644 app/src/main/res/raw-ms/help_problems.html create mode 100644 app/src/main/res/raw-ms/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-my/help_faq.html create mode 100644 app/src/main/res/raw-my/help_problems.html create mode 100644 app/src/main/res/raw-my/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-nb-rNO/help_faq.html create mode 100644 app/src/main/res/raw-nb-rNO/help_problems.html create mode 100644 app/src/main/res/raw-nb-rNO/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ne/help_faq.html create mode 100644 app/src/main/res/raw-ne/help_problems.html create mode 100644 app/src/main/res/raw-ne/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-nl/help_faq.html create mode 100644 app/src/main/res/raw-nl/help_problems.html create mode 100644 app/src/main/res/raw-nl/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-no/help_faq.html create mode 100644 app/src/main/res/raw-no/help_problems.html create mode 100644 app/src/main/res/raw-no/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-pa/help_faq.html create mode 100644 app/src/main/res/raw-pa/help_problems.html create mode 100644 app/src/main/res/raw-pa/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-pl/help_faq.html create mode 100644 app/src/main/res/raw-pl/help_problems.html create mode 100644 app/src/main/res/raw-pl/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ps/help_faq.html create mode 100644 app/src/main/res/raw-ps/help_problems.html create mode 100644 app/src/main/res/raw-ps/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-pt-rBR/help_faq.html create mode 100644 app/src/main/res/raw-pt-rBR/help_problems.html create mode 100644 app/src/main/res/raw-pt-rBR/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-pt/help_faq.html create mode 100644 app/src/main/res/raw-pt/help_problems.html create mode 100644 app/src/main/res/raw-pt/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ro/help_faq.html create mode 100644 app/src/main/res/raw-ro/help_problems.html create mode 100644 app/src/main/res/raw-ro/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ru/help_faq.html create mode 100644 app/src/main/res/raw-ru/help_problems.html create mode 100644 app/src/main/res/raw-ru/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-si/help_faq.html create mode 100644 app/src/main/res/raw-si/help_problems.html create mode 100644 app/src/main/res/raw-si/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-sk/help_faq.html create mode 100644 app/src/main/res/raw-sk/help_problems.html create mode 100644 app/src/main/res/raw-sk/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-sl/help_faq.html create mode 100644 app/src/main/res/raw-sl/help_problems.html create mode 100644 app/src/main/res/raw-sl/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-sq/help_faq.html create mode 100644 app/src/main/res/raw-sq/help_problems.html create mode 100644 app/src/main/res/raw-sq/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-sr/help_faq.html create mode 100644 app/src/main/res/raw-sr/help_problems.html create mode 100644 app/src/main/res/raw-sr/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-sv/help_faq.html create mode 100644 app/src/main/res/raw-sv/help_problems.html create mode 100644 app/src/main/res/raw-sv/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ta/help_faq.html create mode 100644 app/src/main/res/raw-ta/help_problems.html create mode 100644 app/src/main/res/raw-ta/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-th/help_faq.html create mode 100644 app/src/main/res/raw-th/help_problems.html create mode 100644 app/src/main/res/raw-th/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-tl/help_faq.html create mode 100644 app/src/main/res/raw-tl/help_problems.html create mode 100644 app/src/main/res/raw-tl/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-tr/help_faq.html create mode 100644 app/src/main/res/raw-tr/help_problems.html create mode 100644 app/src/main/res/raw-tr/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-uk/help_faq.html create mode 100644 app/src/main/res/raw-uk/help_problems.html create mode 100644 app/src/main/res/raw-uk/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-ur/help_faq.html create mode 100644 app/src/main/res/raw-ur/help_problems.html create mode 100644 app/src/main/res/raw-ur/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-uz/help_faq.html create mode 100644 app/src/main/res/raw-uz/help_problems.html create mode 100644 app/src/main/res/raw-uz/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-vi/help_faq.html create mode 100644 app/src/main/res/raw-vi/help_problems.html create mode 100644 app/src/main/res/raw-vi/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-zh-rTW/help_faq.html create mode 100644 app/src/main/res/raw-zh-rTW/help_problems.html create mode 100644 app/src/main/res/raw-zh-rTW/help_s_on_s_off.html create mode 100644 app/src/main/res/raw-zh/help_faq.html create mode 100644 app/src/main/res/raw-zh/help_problems.html create mode 100644 app/src/main/res/raw-zh/help_s_on_s_off.html create mode 100644 app/src/main/res/raw/help_faq.html create mode 100644 app/src/main/res/raw/help_problems.html create mode 100644 app/src/main/res/raw/help_s_on_s_off.html create mode 100644 app/src/main/res/values-af/strings.xml create mode 100644 app/src/main/res/values-af/strings_app.xml create mode 100644 app/src/main/res/values-af/strings_errors.xml create mode 100644 app/src/main/res/values-af/strings_home.xml create mode 100644 app/src/main/res/values-af/strings_hosts.xml create mode 100644 app/src/main/res/values-af/strings_lists.xml create mode 100644 app/src/main/res/values-af/strings_log.xml create mode 100644 app/src/main/res/values-af/strings_notification.xml create mode 100644 app/src/main/res/values-af/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-af/strings_prefs_main.xml create mode 100644 app/src/main/res/values-af/strings_prefs_root.xml create mode 100644 app/src/main/res/values-af/strings_prefs_update.xml create mode 100644 app/src/main/res/values-af/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-af/strings_support.xml create mode 100644 app/src/main/res/values-af/strings_update.xml create mode 100644 app/src/main/res/values-af/strings_welcome.xml create mode 100644 app/src/main/res/values-ar/strings.xml create mode 100644 app/src/main/res/values-ar/strings_app.xml create mode 100644 app/src/main/res/values-ar/strings_errors.xml create mode 100644 app/src/main/res/values-ar/strings_home.xml create mode 100644 app/src/main/res/values-ar/strings_hosts.xml create mode 100644 app/src/main/res/values-ar/strings_lists.xml create mode 100644 app/src/main/res/values-ar/strings_log.xml create mode 100644 app/src/main/res/values-ar/strings_notification.xml create mode 100644 app/src/main/res/values-ar/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ar/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ar/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ar/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ar/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ar/strings_source_edit.xml create mode 100644 app/src/main/res/values-ar/strings_support.xml create mode 100644 app/src/main/res/values-ar/strings_update.xml create mode 100644 app/src/main/res/values-ar/strings_welcome.xml create mode 100644 app/src/main/res/values-ast/strings.xml create mode 100644 app/src/main/res/values-ast/strings_app.xml create mode 100644 app/src/main/res/values-ast/strings_errors.xml create mode 100644 app/src/main/res/values-ast/strings_home.xml create mode 100644 app/src/main/res/values-ast/strings_hosts.xml create mode 100644 app/src/main/res/values-ast/strings_lists.xml create mode 100644 app/src/main/res/values-ast/strings_log.xml create mode 100644 app/src/main/res/values-ast/strings_notification.xml create mode 100644 app/src/main/res/values-ast/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ast/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ast/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ast/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ast/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ast/strings_support.xml create mode 100644 app/src/main/res/values-ast/strings_update.xml create mode 100644 app/src/main/res/values-ast/strings_welcome.xml create mode 100644 app/src/main/res/values-az/strings.xml create mode 100644 app/src/main/res/values-az/strings_app.xml create mode 100644 app/src/main/res/values-az/strings_errors.xml create mode 100644 app/src/main/res/values-az/strings_home.xml create mode 100644 app/src/main/res/values-az/strings_hosts.xml create mode 100644 app/src/main/res/values-az/strings_lists.xml create mode 100644 app/src/main/res/values-az/strings_log.xml create mode 100644 app/src/main/res/values-az/strings_notification.xml create mode 100644 app/src/main/res/values-az/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-az/strings_prefs_main.xml create mode 100644 app/src/main/res/values-az/strings_prefs_root.xml create mode 100644 app/src/main/res/values-az/strings_prefs_update.xml create mode 100644 app/src/main/res/values-az/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-az/strings_support.xml create mode 100644 app/src/main/res/values-az/strings_update.xml create mode 100644 app/src/main/res/values-az/strings_welcome.xml create mode 100644 app/src/main/res/values-be/strings.xml create mode 100644 app/src/main/res/values-be/strings_app.xml create mode 100644 app/src/main/res/values-be/strings_errors.xml create mode 100644 app/src/main/res/values-be/strings_home.xml create mode 100644 app/src/main/res/values-be/strings_hosts.xml create mode 100644 app/src/main/res/values-be/strings_lists.xml create mode 100644 app/src/main/res/values-be/strings_log.xml create mode 100644 app/src/main/res/values-be/strings_notification.xml create mode 100644 app/src/main/res/values-be/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-be/strings_prefs_main.xml create mode 100644 app/src/main/res/values-be/strings_prefs_root.xml create mode 100644 app/src/main/res/values-be/strings_prefs_update.xml create mode 100644 app/src/main/res/values-be/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-be/strings_support.xml create mode 100644 app/src/main/res/values-be/strings_update.xml create mode 100644 app/src/main/res/values-be/strings_welcome.xml create mode 100644 app/src/main/res/values-bg/strings.xml create mode 100644 app/src/main/res/values-bg/strings_app.xml create mode 100644 app/src/main/res/values-bg/strings_errors.xml create mode 100644 app/src/main/res/values-bg/strings_home.xml create mode 100644 app/src/main/res/values-bg/strings_hosts.xml create mode 100644 app/src/main/res/values-bg/strings_lists.xml create mode 100644 app/src/main/res/values-bg/strings_log.xml create mode 100644 app/src/main/res/values-bg/strings_notification.xml create mode 100644 app/src/main/res/values-bg/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-bg/strings_prefs_main.xml create mode 100644 app/src/main/res/values-bg/strings_prefs_root.xml create mode 100644 app/src/main/res/values-bg/strings_prefs_update.xml create mode 100644 app/src/main/res/values-bg/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-bg/strings_source_edit.xml create mode 100644 app/src/main/res/values-bg/strings_support.xml create mode 100644 app/src/main/res/values-bg/strings_update.xml create mode 100644 app/src/main/res/values-bg/strings_welcome.xml create mode 100644 app/src/main/res/values-bn/strings.xml create mode 100644 app/src/main/res/values-bn/strings_app.xml create mode 100644 app/src/main/res/values-bn/strings_errors.xml create mode 100644 app/src/main/res/values-bn/strings_home.xml create mode 100644 app/src/main/res/values-bn/strings_hosts.xml create mode 100644 app/src/main/res/values-bn/strings_lists.xml create mode 100644 app/src/main/res/values-bn/strings_log.xml create mode 100644 app/src/main/res/values-bn/strings_notification.xml create mode 100644 app/src/main/res/values-bn/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-bn/strings_prefs_main.xml create mode 100644 app/src/main/res/values-bn/strings_prefs_root.xml create mode 100644 app/src/main/res/values-bn/strings_prefs_update.xml create mode 100644 app/src/main/res/values-bn/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-bn/strings_support.xml create mode 100644 app/src/main/res/values-bn/strings_update.xml create mode 100644 app/src/main/res/values-bn/strings_welcome.xml create mode 100644 app/src/main/res/values-ca/strings.xml create mode 100644 app/src/main/res/values-ca/strings_app.xml create mode 100644 app/src/main/res/values-ca/strings_errors.xml create mode 100644 app/src/main/res/values-ca/strings_home.xml create mode 100644 app/src/main/res/values-ca/strings_hosts.xml create mode 100644 app/src/main/res/values-ca/strings_lists.xml create mode 100644 app/src/main/res/values-ca/strings_log.xml create mode 100644 app/src/main/res/values-ca/strings_notification.xml create mode 100644 app/src/main/res/values-ca/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ca/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ca/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ca/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ca/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ca/strings_source_edit.xml create mode 100644 app/src/main/res/values-ca/strings_support.xml create mode 100644 app/src/main/res/values-ca/strings_update.xml create mode 100644 app/src/main/res/values-ca/strings_welcome.xml create mode 100644 app/src/main/res/values-cs/strings.xml create mode 100644 app/src/main/res/values-cs/strings_app.xml create mode 100644 app/src/main/res/values-cs/strings_errors.xml create mode 100644 app/src/main/res/values-cs/strings_home.xml create mode 100644 app/src/main/res/values-cs/strings_hosts.xml create mode 100644 app/src/main/res/values-cs/strings_lists.xml create mode 100644 app/src/main/res/values-cs/strings_log.xml create mode 100644 app/src/main/res/values-cs/strings_notification.xml create mode 100644 app/src/main/res/values-cs/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-cs/strings_prefs_main.xml create mode 100644 app/src/main/res/values-cs/strings_prefs_root.xml create mode 100644 app/src/main/res/values-cs/strings_prefs_update.xml create mode 100644 app/src/main/res/values-cs/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-cs/strings_support.xml create mode 100644 app/src/main/res/values-cs/strings_update.xml create mode 100644 app/src/main/res/values-cs/strings_welcome.xml create mode 100644 app/src/main/res/values-da/strings.xml create mode 100644 app/src/main/res/values-da/strings_app.xml create mode 100644 app/src/main/res/values-da/strings_errors.xml create mode 100644 app/src/main/res/values-da/strings_home.xml create mode 100644 app/src/main/res/values-da/strings_hosts.xml create mode 100644 app/src/main/res/values-da/strings_lists.xml create mode 100644 app/src/main/res/values-da/strings_log.xml create mode 100644 app/src/main/res/values-da/strings_notification.xml create mode 100644 app/src/main/res/values-da/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-da/strings_prefs_main.xml create mode 100644 app/src/main/res/values-da/strings_prefs_root.xml create mode 100644 app/src/main/res/values-da/strings_prefs_update.xml create mode 100644 app/src/main/res/values-da/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-da/strings_support.xml create mode 100644 app/src/main/res/values-da/strings_update.xml create mode 100644 app/src/main/res/values-da/strings_welcome.xml create mode 100644 app/src/main/res/values-de/strings.xml create mode 100644 app/src/main/res/values-de/strings_app.xml create mode 100644 app/src/main/res/values-de/strings_errors.xml create mode 100644 app/src/main/res/values-de/strings_home.xml create mode 100644 app/src/main/res/values-de/strings_hosts.xml create mode 100644 app/src/main/res/values-de/strings_lists.xml create mode 100644 app/src/main/res/values-de/strings_log.xml create mode 100644 app/src/main/res/values-de/strings_notification.xml create mode 100644 app/src/main/res/values-de/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-de/strings_prefs_main.xml create mode 100644 app/src/main/res/values-de/strings_prefs_root.xml create mode 100644 app/src/main/res/values-de/strings_prefs_update.xml create mode 100644 app/src/main/res/values-de/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-de/strings_source_edit.xml create mode 100644 app/src/main/res/values-de/strings_support.xml create mode 100644 app/src/main/res/values-de/strings_update.xml create mode 100644 app/src/main/res/values-de/strings_welcome.xml create mode 100644 app/src/main/res/values-el/strings.xml create mode 100644 app/src/main/res/values-el/strings_app.xml create mode 100644 app/src/main/res/values-el/strings_errors.xml create mode 100644 app/src/main/res/values-el/strings_home.xml create mode 100644 app/src/main/res/values-el/strings_hosts.xml create mode 100644 app/src/main/res/values-el/strings_lists.xml create mode 100644 app/src/main/res/values-el/strings_log.xml create mode 100644 app/src/main/res/values-el/strings_notification.xml create mode 100644 app/src/main/res/values-el/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-el/strings_prefs_main.xml create mode 100644 app/src/main/res/values-el/strings_prefs_root.xml create mode 100644 app/src/main/res/values-el/strings_prefs_update.xml create mode 100644 app/src/main/res/values-el/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-el/strings_source_edit.xml create mode 100644 app/src/main/res/values-el/strings_support.xml create mode 100644 app/src/main/res/values-el/strings_update.xml create mode 100644 app/src/main/res/values-el/strings_welcome.xml create mode 100644 app/src/main/res/values-en-rUS/strings.xml create mode 100644 app/src/main/res/values-en-rUS/strings_app.xml create mode 100644 app/src/main/res/values-en-rUS/strings_errors.xml create mode 100644 app/src/main/res/values-en-rUS/strings_home.xml create mode 100644 app/src/main/res/values-en-rUS/strings_hosts.xml create mode 100644 app/src/main/res/values-en-rUS/strings_lists.xml create mode 100644 app/src/main/res/values-en-rUS/strings_log.xml create mode 100644 app/src/main/res/values-en-rUS/strings_notification.xml create mode 100644 app/src/main/res/values-en-rUS/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-en-rUS/strings_prefs_main.xml create mode 100644 app/src/main/res/values-en-rUS/strings_prefs_root.xml create mode 100644 app/src/main/res/values-en-rUS/strings_prefs_update.xml create mode 100644 app/src/main/res/values-en-rUS/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-en-rUS/strings_support.xml create mode 100644 app/src/main/res/values-en-rUS/strings_update.xml create mode 100644 app/src/main/res/values-en-rUS/strings_welcome.xml create mode 100644 app/src/main/res/values-eo/strings.xml create mode 100644 app/src/main/res/values-eo/strings_app.xml create mode 100644 app/src/main/res/values-eo/strings_errors.xml create mode 100644 app/src/main/res/values-eo/strings_home.xml create mode 100644 app/src/main/res/values-eo/strings_hosts.xml create mode 100644 app/src/main/res/values-eo/strings_lists.xml create mode 100644 app/src/main/res/values-eo/strings_log.xml create mode 100644 app/src/main/res/values-eo/strings_notification.xml create mode 100644 app/src/main/res/values-eo/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-eo/strings_prefs_main.xml create mode 100644 app/src/main/res/values-eo/strings_prefs_root.xml create mode 100644 app/src/main/res/values-eo/strings_prefs_update.xml create mode 100644 app/src/main/res/values-eo/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-eo/strings_support.xml create mode 100644 app/src/main/res/values-eo/strings_update.xml create mode 100644 app/src/main/res/values-eo/strings_welcome.xml create mode 100644 app/src/main/res/values-es-rMX/strings.xml create mode 100644 app/src/main/res/values-es-rMX/strings_app.xml create mode 100644 app/src/main/res/values-es-rMX/strings_errors.xml create mode 100644 app/src/main/res/values-es-rMX/strings_home.xml create mode 100644 app/src/main/res/values-es-rMX/strings_hosts.xml create mode 100644 app/src/main/res/values-es-rMX/strings_lists.xml create mode 100644 app/src/main/res/values-es-rMX/strings_log.xml create mode 100644 app/src/main/res/values-es-rMX/strings_notification.xml create mode 100644 app/src/main/res/values-es-rMX/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-es-rMX/strings_prefs_main.xml create mode 100644 app/src/main/res/values-es-rMX/strings_prefs_root.xml create mode 100644 app/src/main/res/values-es-rMX/strings_prefs_update.xml create mode 100644 app/src/main/res/values-es-rMX/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-es-rMX/strings_support.xml create mode 100644 app/src/main/res/values-es-rMX/strings_update.xml create mode 100644 app/src/main/res/values-es-rMX/strings_welcome.xml create mode 100644 app/src/main/res/values-es/strings.xml create mode 100644 app/src/main/res/values-es/strings_app.xml create mode 100644 app/src/main/res/values-es/strings_errors.xml create mode 100644 app/src/main/res/values-es/strings_home.xml create mode 100644 app/src/main/res/values-es/strings_hosts.xml create mode 100644 app/src/main/res/values-es/strings_lists.xml create mode 100644 app/src/main/res/values-es/strings_log.xml create mode 100644 app/src/main/res/values-es/strings_notification.xml create mode 100644 app/src/main/res/values-es/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-es/strings_prefs_main.xml create mode 100644 app/src/main/res/values-es/strings_prefs_root.xml create mode 100644 app/src/main/res/values-es/strings_prefs_update.xml create mode 100644 app/src/main/res/values-es/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-es/strings_source_edit.xml create mode 100644 app/src/main/res/values-es/strings_support.xml create mode 100644 app/src/main/res/values-es/strings_update.xml create mode 100644 app/src/main/res/values-es/strings_welcome.xml create mode 100644 app/src/main/res/values-et/strings.xml create mode 100644 app/src/main/res/values-et/strings_app.xml create mode 100644 app/src/main/res/values-et/strings_errors.xml create mode 100644 app/src/main/res/values-et/strings_home.xml create mode 100644 app/src/main/res/values-et/strings_hosts.xml create mode 100644 app/src/main/res/values-et/strings_lists.xml create mode 100644 app/src/main/res/values-et/strings_log.xml create mode 100644 app/src/main/res/values-et/strings_notification.xml create mode 100644 app/src/main/res/values-et/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-et/strings_prefs_main.xml create mode 100644 app/src/main/res/values-et/strings_prefs_root.xml create mode 100644 app/src/main/res/values-et/strings_prefs_update.xml create mode 100644 app/src/main/res/values-et/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-et/strings_support.xml create mode 100644 app/src/main/res/values-et/strings_update.xml create mode 100644 app/src/main/res/values-et/strings_welcome.xml create mode 100644 app/src/main/res/values-eu/strings.xml create mode 100644 app/src/main/res/values-eu/strings_app.xml create mode 100644 app/src/main/res/values-eu/strings_errors.xml create mode 100644 app/src/main/res/values-eu/strings_home.xml create mode 100644 app/src/main/res/values-eu/strings_hosts.xml create mode 100644 app/src/main/res/values-eu/strings_lists.xml create mode 100644 app/src/main/res/values-eu/strings_log.xml create mode 100644 app/src/main/res/values-eu/strings_notification.xml create mode 100644 app/src/main/res/values-eu/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-eu/strings_prefs_main.xml create mode 100644 app/src/main/res/values-eu/strings_prefs_root.xml create mode 100644 app/src/main/res/values-eu/strings_prefs_update.xml create mode 100644 app/src/main/res/values-eu/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-eu/strings_source_edit.xml create mode 100644 app/src/main/res/values-eu/strings_support.xml create mode 100644 app/src/main/res/values-eu/strings_update.xml create mode 100644 app/src/main/res/values-eu/strings_welcome.xml create mode 100644 app/src/main/res/values-fa/strings.xml create mode 100644 app/src/main/res/values-fa/strings_app.xml create mode 100644 app/src/main/res/values-fa/strings_errors.xml create mode 100644 app/src/main/res/values-fa/strings_home.xml create mode 100644 app/src/main/res/values-fa/strings_hosts.xml create mode 100644 app/src/main/res/values-fa/strings_lists.xml create mode 100644 app/src/main/res/values-fa/strings_log.xml create mode 100644 app/src/main/res/values-fa/strings_notification.xml create mode 100644 app/src/main/res/values-fa/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-fa/strings_prefs_main.xml create mode 100644 app/src/main/res/values-fa/strings_prefs_root.xml create mode 100644 app/src/main/res/values-fa/strings_prefs_update.xml create mode 100644 app/src/main/res/values-fa/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-fa/strings_source_edit.xml create mode 100644 app/src/main/res/values-fa/strings_support.xml create mode 100644 app/src/main/res/values-fa/strings_update.xml create mode 100644 app/src/main/res/values-fa/strings_welcome.xml create mode 100644 app/src/main/res/values-fi/strings.xml create mode 100644 app/src/main/res/values-fi/strings_app.xml create mode 100644 app/src/main/res/values-fi/strings_errors.xml create mode 100644 app/src/main/res/values-fi/strings_home.xml create mode 100644 app/src/main/res/values-fi/strings_hosts.xml create mode 100644 app/src/main/res/values-fi/strings_lists.xml create mode 100644 app/src/main/res/values-fi/strings_log.xml create mode 100644 app/src/main/res/values-fi/strings_notification.xml create mode 100644 app/src/main/res/values-fi/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-fi/strings_prefs_main.xml create mode 100644 app/src/main/res/values-fi/strings_prefs_root.xml create mode 100644 app/src/main/res/values-fi/strings_prefs_update.xml create mode 100644 app/src/main/res/values-fi/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-fi/strings_support.xml create mode 100644 app/src/main/res/values-fi/strings_update.xml create mode 100644 app/src/main/res/values-fi/strings_welcome.xml create mode 100644 app/src/main/res/values-fil/strings.xml create mode 100644 app/src/main/res/values-fil/strings_app.xml create mode 100644 app/src/main/res/values-fil/strings_errors.xml create mode 100644 app/src/main/res/values-fil/strings_home.xml create mode 100644 app/src/main/res/values-fil/strings_hosts.xml create mode 100644 app/src/main/res/values-fil/strings_lists.xml create mode 100644 app/src/main/res/values-fil/strings_log.xml create mode 100644 app/src/main/res/values-fil/strings_notification.xml create mode 100644 app/src/main/res/values-fil/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-fil/strings_prefs_main.xml create mode 100644 app/src/main/res/values-fil/strings_prefs_root.xml create mode 100644 app/src/main/res/values-fil/strings_prefs_update.xml create mode 100644 app/src/main/res/values-fil/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-fil/strings_support.xml create mode 100644 app/src/main/res/values-fil/strings_update.xml create mode 100644 app/src/main/res/values-fil/strings_welcome.xml create mode 100644 app/src/main/res/values-fr/strings.xml create mode 100644 app/src/main/res/values-fr/strings_app.xml create mode 100644 app/src/main/res/values-fr/strings_errors.xml create mode 100644 app/src/main/res/values-fr/strings_home.xml create mode 100644 app/src/main/res/values-fr/strings_hosts.xml create mode 100644 app/src/main/res/values-fr/strings_lists.xml create mode 100644 app/src/main/res/values-fr/strings_log.xml create mode 100644 app/src/main/res/values-fr/strings_notification.xml create mode 100644 app/src/main/res/values-fr/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-fr/strings_prefs_main.xml create mode 100644 app/src/main/res/values-fr/strings_prefs_root.xml create mode 100644 app/src/main/res/values-fr/strings_prefs_update.xml create mode 100644 app/src/main/res/values-fr/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-fr/strings_source_edit.xml create mode 100644 app/src/main/res/values-fr/strings_support.xml create mode 100644 app/src/main/res/values-fr/strings_update.xml create mode 100644 app/src/main/res/values-fr/strings_welcome.xml create mode 100644 app/src/main/res/values-gl/strings.xml create mode 100644 app/src/main/res/values-gl/strings_app.xml create mode 100644 app/src/main/res/values-gl/strings_errors.xml create mode 100644 app/src/main/res/values-gl/strings_home.xml create mode 100644 app/src/main/res/values-gl/strings_hosts.xml create mode 100644 app/src/main/res/values-gl/strings_lists.xml create mode 100644 app/src/main/res/values-gl/strings_log.xml create mode 100644 app/src/main/res/values-gl/strings_notification.xml create mode 100644 app/src/main/res/values-gl/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-gl/strings_prefs_main.xml create mode 100644 app/src/main/res/values-gl/strings_prefs_root.xml create mode 100644 app/src/main/res/values-gl/strings_prefs_update.xml create mode 100644 app/src/main/res/values-gl/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-gl/strings_support.xml create mode 100644 app/src/main/res/values-gl/strings_update.xml create mode 100644 app/src/main/res/values-gl/strings_welcome.xml create mode 100644 app/src/main/res/values-hi/strings.xml create mode 100644 app/src/main/res/values-hi/strings_app.xml create mode 100644 app/src/main/res/values-hi/strings_errors.xml create mode 100644 app/src/main/res/values-hi/strings_home.xml create mode 100644 app/src/main/res/values-hi/strings_hosts.xml create mode 100644 app/src/main/res/values-hi/strings_lists.xml create mode 100644 app/src/main/res/values-hi/strings_log.xml create mode 100644 app/src/main/res/values-hi/strings_notification.xml create mode 100644 app/src/main/res/values-hi/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-hi/strings_prefs_main.xml create mode 100644 app/src/main/res/values-hi/strings_prefs_root.xml create mode 100644 app/src/main/res/values-hi/strings_prefs_update.xml create mode 100644 app/src/main/res/values-hi/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-hi/strings_support.xml create mode 100644 app/src/main/res/values-hi/strings_update.xml create mode 100644 app/src/main/res/values-hi/strings_welcome.xml create mode 100644 app/src/main/res/values-hr/strings.xml create mode 100644 app/src/main/res/values-hr/strings_app.xml create mode 100644 app/src/main/res/values-hr/strings_errors.xml create mode 100644 app/src/main/res/values-hr/strings_home.xml create mode 100644 app/src/main/res/values-hr/strings_hosts.xml create mode 100644 app/src/main/res/values-hr/strings_lists.xml create mode 100644 app/src/main/res/values-hr/strings_log.xml create mode 100644 app/src/main/res/values-hr/strings_notification.xml create mode 100644 app/src/main/res/values-hr/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-hr/strings_prefs_main.xml create mode 100644 app/src/main/res/values-hr/strings_prefs_root.xml create mode 100644 app/src/main/res/values-hr/strings_prefs_update.xml create mode 100644 app/src/main/res/values-hr/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-hr/strings_support.xml create mode 100644 app/src/main/res/values-hr/strings_update.xml create mode 100644 app/src/main/res/values-hr/strings_welcome.xml create mode 100644 app/src/main/res/values-hu/strings.xml create mode 100644 app/src/main/res/values-hu/strings_app.xml create mode 100644 app/src/main/res/values-hu/strings_errors.xml create mode 100644 app/src/main/res/values-hu/strings_home.xml create mode 100644 app/src/main/res/values-hu/strings_hosts.xml create mode 100644 app/src/main/res/values-hu/strings_lists.xml create mode 100644 app/src/main/res/values-hu/strings_log.xml create mode 100644 app/src/main/res/values-hu/strings_notification.xml create mode 100644 app/src/main/res/values-hu/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-hu/strings_prefs_main.xml create mode 100644 app/src/main/res/values-hu/strings_prefs_root.xml create mode 100644 app/src/main/res/values-hu/strings_prefs_update.xml create mode 100644 app/src/main/res/values-hu/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-hu/strings_support.xml create mode 100644 app/src/main/res/values-hu/strings_update.xml create mode 100644 app/src/main/res/values-hu/strings_welcome.xml create mode 100644 app/src/main/res/values-in/strings.xml create mode 100644 app/src/main/res/values-in/strings_app.xml create mode 100644 app/src/main/res/values-in/strings_errors.xml create mode 100644 app/src/main/res/values-in/strings_home.xml create mode 100644 app/src/main/res/values-in/strings_hosts.xml create mode 100644 app/src/main/res/values-in/strings_lists.xml create mode 100644 app/src/main/res/values-in/strings_log.xml create mode 100644 app/src/main/res/values-in/strings_notification.xml create mode 100644 app/src/main/res/values-in/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-in/strings_prefs_main.xml create mode 100644 app/src/main/res/values-in/strings_prefs_root.xml create mode 100644 app/src/main/res/values-in/strings_prefs_update.xml create mode 100644 app/src/main/res/values-in/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-in/strings_source_edit.xml create mode 100644 app/src/main/res/values-in/strings_support.xml create mode 100644 app/src/main/res/values-in/strings_update.xml create mode 100644 app/src/main/res/values-in/strings_welcome.xml create mode 100644 app/src/main/res/values-is/strings.xml create mode 100644 app/src/main/res/values-is/strings_app.xml create mode 100644 app/src/main/res/values-is/strings_errors.xml create mode 100644 app/src/main/res/values-is/strings_home.xml create mode 100644 app/src/main/res/values-is/strings_hosts.xml create mode 100644 app/src/main/res/values-is/strings_lists.xml create mode 100644 app/src/main/res/values-is/strings_log.xml create mode 100644 app/src/main/res/values-is/strings_notification.xml create mode 100644 app/src/main/res/values-is/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-is/strings_prefs_main.xml create mode 100644 app/src/main/res/values-is/strings_prefs_root.xml create mode 100644 app/src/main/res/values-is/strings_prefs_update.xml create mode 100644 app/src/main/res/values-is/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-is/strings_support.xml create mode 100644 app/src/main/res/values-is/strings_update.xml create mode 100644 app/src/main/res/values-is/strings_welcome.xml create mode 100644 app/src/main/res/values-it/strings.xml create mode 100644 app/src/main/res/values-it/strings_app.xml create mode 100644 app/src/main/res/values-it/strings_errors.xml create mode 100644 app/src/main/res/values-it/strings_home.xml create mode 100644 app/src/main/res/values-it/strings_hosts.xml create mode 100644 app/src/main/res/values-it/strings_lists.xml create mode 100644 app/src/main/res/values-it/strings_log.xml create mode 100644 app/src/main/res/values-it/strings_notification.xml create mode 100644 app/src/main/res/values-it/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-it/strings_prefs_main.xml create mode 100644 app/src/main/res/values-it/strings_prefs_root.xml create mode 100644 app/src/main/res/values-it/strings_prefs_update.xml create mode 100644 app/src/main/res/values-it/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-it/strings_source_edit.xml create mode 100644 app/src/main/res/values-it/strings_support.xml create mode 100644 app/src/main/res/values-it/strings_update.xml create mode 100644 app/src/main/res/values-it/strings_welcome.xml create mode 100644 app/src/main/res/values-iw/strings.xml create mode 100644 app/src/main/res/values-iw/strings_app.xml create mode 100644 app/src/main/res/values-iw/strings_errors.xml create mode 100644 app/src/main/res/values-iw/strings_home.xml create mode 100644 app/src/main/res/values-iw/strings_hosts.xml create mode 100644 app/src/main/res/values-iw/strings_lists.xml create mode 100644 app/src/main/res/values-iw/strings_log.xml create mode 100644 app/src/main/res/values-iw/strings_notification.xml create mode 100644 app/src/main/res/values-iw/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-iw/strings_prefs_main.xml create mode 100644 app/src/main/res/values-iw/strings_prefs_root.xml create mode 100644 app/src/main/res/values-iw/strings_prefs_update.xml create mode 100644 app/src/main/res/values-iw/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-iw/strings_source_edit.xml create mode 100644 app/src/main/res/values-iw/strings_support.xml create mode 100644 app/src/main/res/values-iw/strings_update.xml create mode 100644 app/src/main/res/values-iw/strings_welcome.xml create mode 100644 app/src/main/res/values-ja/strings.xml create mode 100644 app/src/main/res/values-ja/strings_app.xml create mode 100644 app/src/main/res/values-ja/strings_errors.xml create mode 100644 app/src/main/res/values-ja/strings_home.xml create mode 100644 app/src/main/res/values-ja/strings_hosts.xml create mode 100644 app/src/main/res/values-ja/strings_lists.xml create mode 100644 app/src/main/res/values-ja/strings_log.xml create mode 100644 app/src/main/res/values-ja/strings_notification.xml create mode 100644 app/src/main/res/values-ja/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ja/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ja/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ja/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ja/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ja/strings_source_edit.xml create mode 100644 app/src/main/res/values-ja/strings_support.xml create mode 100644 app/src/main/res/values-ja/strings_update.xml create mode 100644 app/src/main/res/values-ja/strings_welcome.xml create mode 100644 app/src/main/res/values-km/strings.xml create mode 100644 app/src/main/res/values-km/strings_app.xml create mode 100644 app/src/main/res/values-km/strings_errors.xml create mode 100644 app/src/main/res/values-km/strings_home.xml create mode 100644 app/src/main/res/values-km/strings_hosts.xml create mode 100644 app/src/main/res/values-km/strings_lists.xml create mode 100644 app/src/main/res/values-km/strings_log.xml create mode 100644 app/src/main/res/values-km/strings_notification.xml create mode 100644 app/src/main/res/values-km/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-km/strings_prefs_main.xml create mode 100644 app/src/main/res/values-km/strings_prefs_root.xml create mode 100644 app/src/main/res/values-km/strings_prefs_update.xml create mode 100644 app/src/main/res/values-km/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-km/strings_support.xml create mode 100644 app/src/main/res/values-km/strings_update.xml create mode 100644 app/src/main/res/values-km/strings_welcome.xml create mode 100644 app/src/main/res/values-ko/strings.xml create mode 100644 app/src/main/res/values-ko/strings_app.xml create mode 100644 app/src/main/res/values-ko/strings_errors.xml create mode 100644 app/src/main/res/values-ko/strings_home.xml create mode 100644 app/src/main/res/values-ko/strings_hosts.xml create mode 100644 app/src/main/res/values-ko/strings_lists.xml create mode 100644 app/src/main/res/values-ko/strings_log.xml create mode 100644 app/src/main/res/values-ko/strings_notification.xml create mode 100644 app/src/main/res/values-ko/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ko/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ko/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ko/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ko/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ko/strings_support.xml create mode 100644 app/src/main/res/values-ko/strings_update.xml create mode 100644 app/src/main/res/values-ko/strings_welcome.xml create mode 100644 app/src/main/res/values-ku/strings.xml create mode 100644 app/src/main/res/values-ku/strings_app.xml create mode 100644 app/src/main/res/values-ku/strings_errors.xml create mode 100644 app/src/main/res/values-ku/strings_home.xml create mode 100644 app/src/main/res/values-ku/strings_hosts.xml create mode 100644 app/src/main/res/values-ku/strings_lists.xml create mode 100644 app/src/main/res/values-ku/strings_log.xml create mode 100644 app/src/main/res/values-ku/strings_notification.xml create mode 100644 app/src/main/res/values-ku/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ku/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ku/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ku/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ku/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ku/strings_support.xml create mode 100644 app/src/main/res/values-ku/strings_update.xml create mode 100644 app/src/main/res/values-ku/strings_welcome.xml create mode 100644 app/src/main/res/values-lt/strings.xml create mode 100644 app/src/main/res/values-lt/strings_app.xml create mode 100644 app/src/main/res/values-lt/strings_errors.xml create mode 100644 app/src/main/res/values-lt/strings_home.xml create mode 100644 app/src/main/res/values-lt/strings_hosts.xml create mode 100644 app/src/main/res/values-lt/strings_lists.xml create mode 100644 app/src/main/res/values-lt/strings_log.xml create mode 100644 app/src/main/res/values-lt/strings_notification.xml create mode 100644 app/src/main/res/values-lt/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-lt/strings_prefs_main.xml create mode 100644 app/src/main/res/values-lt/strings_prefs_root.xml create mode 100644 app/src/main/res/values-lt/strings_prefs_update.xml create mode 100644 app/src/main/res/values-lt/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-lt/strings_support.xml create mode 100644 app/src/main/res/values-lt/strings_update.xml create mode 100644 app/src/main/res/values-lt/strings_welcome.xml create mode 100644 app/src/main/res/values-ml/strings.xml create mode 100644 app/src/main/res/values-ml/strings_app.xml create mode 100644 app/src/main/res/values-ml/strings_errors.xml create mode 100644 app/src/main/res/values-ml/strings_home.xml create mode 100644 app/src/main/res/values-ml/strings_hosts.xml create mode 100644 app/src/main/res/values-ml/strings_lists.xml create mode 100644 app/src/main/res/values-ml/strings_log.xml create mode 100644 app/src/main/res/values-ml/strings_notification.xml create mode 100644 app/src/main/res/values-ml/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ml/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ml/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ml/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ml/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ml/strings_support.xml create mode 100644 app/src/main/res/values-ml/strings_update.xml create mode 100644 app/src/main/res/values-ml/strings_welcome.xml create mode 100644 app/src/main/res/values-ms/strings.xml create mode 100644 app/src/main/res/values-ms/strings_app.xml create mode 100644 app/src/main/res/values-ms/strings_errors.xml create mode 100644 app/src/main/res/values-ms/strings_home.xml create mode 100644 app/src/main/res/values-ms/strings_hosts.xml create mode 100644 app/src/main/res/values-ms/strings_lists.xml create mode 100644 app/src/main/res/values-ms/strings_log.xml create mode 100644 app/src/main/res/values-ms/strings_notification.xml create mode 100644 app/src/main/res/values-ms/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ms/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ms/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ms/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ms/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ms/strings_support.xml create mode 100644 app/src/main/res/values-ms/strings_update.xml create mode 100644 app/src/main/res/values-ms/strings_welcome.xml create mode 100644 app/src/main/res/values-my/strings.xml create mode 100644 app/src/main/res/values-my/strings_app.xml create mode 100644 app/src/main/res/values-my/strings_errors.xml create mode 100644 app/src/main/res/values-my/strings_home.xml create mode 100644 app/src/main/res/values-my/strings_hosts.xml create mode 100644 app/src/main/res/values-my/strings_lists.xml create mode 100644 app/src/main/res/values-my/strings_log.xml create mode 100644 app/src/main/res/values-my/strings_notification.xml create mode 100644 app/src/main/res/values-my/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-my/strings_prefs_main.xml create mode 100644 app/src/main/res/values-my/strings_prefs_root.xml create mode 100644 app/src/main/res/values-my/strings_prefs_update.xml create mode 100644 app/src/main/res/values-my/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-my/strings_support.xml create mode 100644 app/src/main/res/values-my/strings_update.xml create mode 100644 app/src/main/res/values-my/strings_welcome.xml create mode 100644 app/src/main/res/values-nb-rNO/strings.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_app.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_errors.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_home.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_hosts.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_lists.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_log.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_notification.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_prefs_main.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_prefs_root.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_prefs_update.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_support.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_update.xml create mode 100644 app/src/main/res/values-nb-rNO/strings_welcome.xml create mode 100644 app/src/main/res/values-ne/strings.xml create mode 100644 app/src/main/res/values-ne/strings_app.xml create mode 100644 app/src/main/res/values-ne/strings_errors.xml create mode 100644 app/src/main/res/values-ne/strings_home.xml create mode 100644 app/src/main/res/values-ne/strings_hosts.xml create mode 100644 app/src/main/res/values-ne/strings_lists.xml create mode 100644 app/src/main/res/values-ne/strings_log.xml create mode 100644 app/src/main/res/values-ne/strings_notification.xml create mode 100644 app/src/main/res/values-ne/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ne/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ne/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ne/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ne/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ne/strings_support.xml create mode 100644 app/src/main/res/values-ne/strings_update.xml create mode 100644 app/src/main/res/values-ne/strings_welcome.xml create mode 100644 app/src/main/res/values-night/colors.xml create mode 100644 app/src/main/res/values-night/styles.xml create mode 100644 app/src/main/res/values-nl/strings.xml create mode 100644 app/src/main/res/values-nl/strings_app.xml create mode 100644 app/src/main/res/values-nl/strings_errors.xml create mode 100644 app/src/main/res/values-nl/strings_home.xml create mode 100644 app/src/main/res/values-nl/strings_hosts.xml create mode 100644 app/src/main/res/values-nl/strings_lists.xml create mode 100644 app/src/main/res/values-nl/strings_log.xml create mode 100644 app/src/main/res/values-nl/strings_notification.xml create mode 100644 app/src/main/res/values-nl/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-nl/strings_prefs_main.xml create mode 100644 app/src/main/res/values-nl/strings_prefs_root.xml create mode 100644 app/src/main/res/values-nl/strings_prefs_update.xml create mode 100644 app/src/main/res/values-nl/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-nl/strings_source_edit.xml create mode 100644 app/src/main/res/values-nl/strings_support.xml create mode 100644 app/src/main/res/values-nl/strings_update.xml create mode 100644 app/src/main/res/values-nl/strings_welcome.xml create mode 100644 app/src/main/res/values-no/strings.xml create mode 100644 app/src/main/res/values-no/strings_app.xml create mode 100644 app/src/main/res/values-no/strings_errors.xml create mode 100644 app/src/main/res/values-no/strings_home.xml create mode 100644 app/src/main/res/values-no/strings_hosts.xml create mode 100644 app/src/main/res/values-no/strings_lists.xml create mode 100644 app/src/main/res/values-no/strings_log.xml create mode 100644 app/src/main/res/values-no/strings_notification.xml create mode 100644 app/src/main/res/values-no/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-no/strings_prefs_main.xml create mode 100644 app/src/main/res/values-no/strings_prefs_root.xml create mode 100644 app/src/main/res/values-no/strings_prefs_update.xml create mode 100644 app/src/main/res/values-no/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-no/strings_support.xml create mode 100644 app/src/main/res/values-no/strings_update.xml create mode 100644 app/src/main/res/values-no/strings_welcome.xml create mode 100644 app/src/main/res/values-pa/strings.xml create mode 100644 app/src/main/res/values-pa/strings_app.xml create mode 100644 app/src/main/res/values-pa/strings_errors.xml create mode 100644 app/src/main/res/values-pa/strings_home.xml create mode 100644 app/src/main/res/values-pa/strings_hosts.xml create mode 100644 app/src/main/res/values-pa/strings_lists.xml create mode 100644 app/src/main/res/values-pa/strings_log.xml create mode 100644 app/src/main/res/values-pa/strings_notification.xml create mode 100644 app/src/main/res/values-pa/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-pa/strings_prefs_main.xml create mode 100644 app/src/main/res/values-pa/strings_prefs_root.xml create mode 100644 app/src/main/res/values-pa/strings_prefs_update.xml create mode 100644 app/src/main/res/values-pa/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-pa/strings_support.xml create mode 100644 app/src/main/res/values-pa/strings_update.xml create mode 100644 app/src/main/res/values-pa/strings_welcome.xml create mode 100644 app/src/main/res/values-pl/strings.xml create mode 100644 app/src/main/res/values-pl/strings_app.xml create mode 100644 app/src/main/res/values-pl/strings_errors.xml create mode 100644 app/src/main/res/values-pl/strings_home.xml create mode 100644 app/src/main/res/values-pl/strings_hosts.xml create mode 100644 app/src/main/res/values-pl/strings_lists.xml create mode 100644 app/src/main/res/values-pl/strings_log.xml create mode 100644 app/src/main/res/values-pl/strings_notification.xml create mode 100644 app/src/main/res/values-pl/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-pl/strings_prefs_main.xml create mode 100644 app/src/main/res/values-pl/strings_prefs_root.xml create mode 100644 app/src/main/res/values-pl/strings_prefs_update.xml create mode 100644 app/src/main/res/values-pl/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-pl/strings_source_edit.xml create mode 100644 app/src/main/res/values-pl/strings_support.xml create mode 100644 app/src/main/res/values-pl/strings_update.xml create mode 100644 app/src/main/res/values-pl/strings_welcome.xml create mode 100644 app/src/main/res/values-ps/strings.xml create mode 100644 app/src/main/res/values-ps/strings_app.xml create mode 100644 app/src/main/res/values-ps/strings_errors.xml create mode 100644 app/src/main/res/values-ps/strings_home.xml create mode 100644 app/src/main/res/values-ps/strings_hosts.xml create mode 100644 app/src/main/res/values-ps/strings_lists.xml create mode 100644 app/src/main/res/values-ps/strings_log.xml create mode 100644 app/src/main/res/values-ps/strings_notification.xml create mode 100644 app/src/main/res/values-ps/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ps/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ps/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ps/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ps/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ps/strings_support.xml create mode 100644 app/src/main/res/values-ps/strings_update.xml create mode 100644 app/src/main/res/values-ps/strings_welcome.xml create mode 100644 app/src/main/res/values-pt-rBR/strings.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_app.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_errors.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_home.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_hosts.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_lists.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_log.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_notification.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_prefs_main.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_prefs_root.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_prefs_update.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_source_edit.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_support.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_update.xml create mode 100644 app/src/main/res/values-pt-rBR/strings_welcome.xml create mode 100644 app/src/main/res/values-pt/strings.xml create mode 100644 app/src/main/res/values-pt/strings_app.xml create mode 100644 app/src/main/res/values-pt/strings_errors.xml create mode 100644 app/src/main/res/values-pt/strings_home.xml create mode 100644 app/src/main/res/values-pt/strings_hosts.xml create mode 100644 app/src/main/res/values-pt/strings_lists.xml create mode 100644 app/src/main/res/values-pt/strings_log.xml create mode 100644 app/src/main/res/values-pt/strings_notification.xml create mode 100644 app/src/main/res/values-pt/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-pt/strings_prefs_main.xml create mode 100644 app/src/main/res/values-pt/strings_prefs_root.xml create mode 100644 app/src/main/res/values-pt/strings_prefs_update.xml create mode 100644 app/src/main/res/values-pt/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-pt/strings_source_edit.xml create mode 100644 app/src/main/res/values-pt/strings_support.xml create mode 100644 app/src/main/res/values-pt/strings_update.xml create mode 100644 app/src/main/res/values-pt/strings_welcome.xml create mode 100644 app/src/main/res/values-ro/strings.xml create mode 100644 app/src/main/res/values-ro/strings_app.xml create mode 100644 app/src/main/res/values-ro/strings_errors.xml create mode 100644 app/src/main/res/values-ro/strings_home.xml create mode 100644 app/src/main/res/values-ro/strings_hosts.xml create mode 100644 app/src/main/res/values-ro/strings_lists.xml create mode 100644 app/src/main/res/values-ro/strings_log.xml create mode 100644 app/src/main/res/values-ro/strings_notification.xml create mode 100644 app/src/main/res/values-ro/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ro/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ro/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ro/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ro/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ro/strings_support.xml create mode 100644 app/src/main/res/values-ro/strings_update.xml create mode 100644 app/src/main/res/values-ro/strings_welcome.xml create mode 100644 app/src/main/res/values-ru/strings.xml create mode 100644 app/src/main/res/values-ru/strings_app.xml create mode 100644 app/src/main/res/values-ru/strings_errors.xml create mode 100644 app/src/main/res/values-ru/strings_home.xml create mode 100644 app/src/main/res/values-ru/strings_hosts.xml create mode 100644 app/src/main/res/values-ru/strings_lists.xml create mode 100644 app/src/main/res/values-ru/strings_log.xml create mode 100644 app/src/main/res/values-ru/strings_notification.xml create mode 100644 app/src/main/res/values-ru/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ru/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ru/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ru/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ru/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ru/strings_source_edit.xml create mode 100644 app/src/main/res/values-ru/strings_support.xml create mode 100644 app/src/main/res/values-ru/strings_update.xml create mode 100644 app/src/main/res/values-ru/strings_welcome.xml create mode 100644 app/src/main/res/values-si/strings.xml create mode 100644 app/src/main/res/values-si/strings_app.xml create mode 100644 app/src/main/res/values-si/strings_errors.xml create mode 100644 app/src/main/res/values-si/strings_home.xml create mode 100644 app/src/main/res/values-si/strings_hosts.xml create mode 100644 app/src/main/res/values-si/strings_lists.xml create mode 100644 app/src/main/res/values-si/strings_log.xml create mode 100644 app/src/main/res/values-si/strings_notification.xml create mode 100644 app/src/main/res/values-si/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-si/strings_prefs_main.xml create mode 100644 app/src/main/res/values-si/strings_prefs_root.xml create mode 100644 app/src/main/res/values-si/strings_prefs_update.xml create mode 100644 app/src/main/res/values-si/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-si/strings_support.xml create mode 100644 app/src/main/res/values-si/strings_update.xml create mode 100644 app/src/main/res/values-si/strings_welcome.xml create mode 100644 app/src/main/res/values-sk/strings.xml create mode 100644 app/src/main/res/values-sk/strings_app.xml create mode 100644 app/src/main/res/values-sk/strings_errors.xml create mode 100644 app/src/main/res/values-sk/strings_home.xml create mode 100644 app/src/main/res/values-sk/strings_hosts.xml create mode 100644 app/src/main/res/values-sk/strings_lists.xml create mode 100644 app/src/main/res/values-sk/strings_log.xml create mode 100644 app/src/main/res/values-sk/strings_notification.xml create mode 100644 app/src/main/res/values-sk/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-sk/strings_prefs_main.xml create mode 100644 app/src/main/res/values-sk/strings_prefs_root.xml create mode 100644 app/src/main/res/values-sk/strings_prefs_update.xml create mode 100644 app/src/main/res/values-sk/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-sk/strings_source_edit.xml create mode 100644 app/src/main/res/values-sk/strings_support.xml create mode 100644 app/src/main/res/values-sk/strings_update.xml create mode 100644 app/src/main/res/values-sk/strings_welcome.xml create mode 100644 app/src/main/res/values-sl/strings.xml create mode 100644 app/src/main/res/values-sl/strings_app.xml create mode 100644 app/src/main/res/values-sl/strings_errors.xml create mode 100644 app/src/main/res/values-sl/strings_home.xml create mode 100644 app/src/main/res/values-sl/strings_hosts.xml create mode 100644 app/src/main/res/values-sl/strings_lists.xml create mode 100644 app/src/main/res/values-sl/strings_log.xml create mode 100644 app/src/main/res/values-sl/strings_notification.xml create mode 100644 app/src/main/res/values-sl/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-sl/strings_prefs_main.xml create mode 100644 app/src/main/res/values-sl/strings_prefs_root.xml create mode 100644 app/src/main/res/values-sl/strings_prefs_update.xml create mode 100644 app/src/main/res/values-sl/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-sl/strings_source_edit.xml create mode 100644 app/src/main/res/values-sl/strings_support.xml create mode 100644 app/src/main/res/values-sl/strings_update.xml create mode 100644 app/src/main/res/values-sl/strings_welcome.xml create mode 100644 app/src/main/res/values-sq/strings.xml create mode 100644 app/src/main/res/values-sq/strings_app.xml create mode 100644 app/src/main/res/values-sq/strings_errors.xml create mode 100644 app/src/main/res/values-sq/strings_home.xml create mode 100644 app/src/main/res/values-sq/strings_hosts.xml create mode 100644 app/src/main/res/values-sq/strings_lists.xml create mode 100644 app/src/main/res/values-sq/strings_log.xml create mode 100644 app/src/main/res/values-sq/strings_notification.xml create mode 100644 app/src/main/res/values-sq/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-sq/strings_prefs_main.xml create mode 100644 app/src/main/res/values-sq/strings_prefs_root.xml create mode 100644 app/src/main/res/values-sq/strings_prefs_update.xml create mode 100644 app/src/main/res/values-sq/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-sq/strings_support.xml create mode 100644 app/src/main/res/values-sq/strings_update.xml create mode 100644 app/src/main/res/values-sq/strings_welcome.xml create mode 100644 app/src/main/res/values-sr/strings.xml create mode 100644 app/src/main/res/values-sr/strings_app.xml create mode 100644 app/src/main/res/values-sr/strings_errors.xml create mode 100644 app/src/main/res/values-sr/strings_home.xml create mode 100644 app/src/main/res/values-sr/strings_hosts.xml create mode 100644 app/src/main/res/values-sr/strings_lists.xml create mode 100644 app/src/main/res/values-sr/strings_log.xml create mode 100644 app/src/main/res/values-sr/strings_notification.xml create mode 100644 app/src/main/res/values-sr/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-sr/strings_prefs_main.xml create mode 100644 app/src/main/res/values-sr/strings_prefs_root.xml create mode 100644 app/src/main/res/values-sr/strings_prefs_update.xml create mode 100644 app/src/main/res/values-sr/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-sr/strings_support.xml create mode 100644 app/src/main/res/values-sr/strings_update.xml create mode 100644 app/src/main/res/values-sr/strings_welcome.xml create mode 100644 app/src/main/res/values-sv/strings.xml create mode 100644 app/src/main/res/values-sv/strings_app.xml create mode 100644 app/src/main/res/values-sv/strings_errors.xml create mode 100644 app/src/main/res/values-sv/strings_home.xml create mode 100644 app/src/main/res/values-sv/strings_hosts.xml create mode 100644 app/src/main/res/values-sv/strings_lists.xml create mode 100644 app/src/main/res/values-sv/strings_log.xml create mode 100644 app/src/main/res/values-sv/strings_notification.xml create mode 100644 app/src/main/res/values-sv/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-sv/strings_prefs_main.xml create mode 100644 app/src/main/res/values-sv/strings_prefs_root.xml create mode 100644 app/src/main/res/values-sv/strings_prefs_update.xml create mode 100644 app/src/main/res/values-sv/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-sv/strings_support.xml create mode 100644 app/src/main/res/values-sv/strings_update.xml create mode 100644 app/src/main/res/values-sv/strings_welcome.xml create mode 100644 app/src/main/res/values-ta/strings.xml create mode 100644 app/src/main/res/values-ta/strings_app.xml create mode 100644 app/src/main/res/values-ta/strings_errors.xml create mode 100644 app/src/main/res/values-ta/strings_home.xml create mode 100644 app/src/main/res/values-ta/strings_hosts.xml create mode 100644 app/src/main/res/values-ta/strings_lists.xml create mode 100644 app/src/main/res/values-ta/strings_log.xml create mode 100644 app/src/main/res/values-ta/strings_notification.xml create mode 100644 app/src/main/res/values-ta/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ta/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ta/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ta/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ta/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ta/strings_support.xml create mode 100644 app/src/main/res/values-ta/strings_update.xml create mode 100644 app/src/main/res/values-ta/strings_welcome.xml create mode 100644 app/src/main/res/values-th/strings.xml create mode 100644 app/src/main/res/values-th/strings_app.xml create mode 100644 app/src/main/res/values-th/strings_errors.xml create mode 100644 app/src/main/res/values-th/strings_home.xml create mode 100644 app/src/main/res/values-th/strings_hosts.xml create mode 100644 app/src/main/res/values-th/strings_lists.xml create mode 100644 app/src/main/res/values-th/strings_log.xml create mode 100644 app/src/main/res/values-th/strings_notification.xml create mode 100644 app/src/main/res/values-th/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-th/strings_prefs_main.xml create mode 100644 app/src/main/res/values-th/strings_prefs_root.xml create mode 100644 app/src/main/res/values-th/strings_prefs_update.xml create mode 100644 app/src/main/res/values-th/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-th/strings_support.xml create mode 100644 app/src/main/res/values-th/strings_update.xml create mode 100644 app/src/main/res/values-th/strings_welcome.xml create mode 100644 app/src/main/res/values-tl/strings.xml create mode 100644 app/src/main/res/values-tl/strings_app.xml create mode 100644 app/src/main/res/values-tl/strings_errors.xml create mode 100644 app/src/main/res/values-tl/strings_home.xml create mode 100644 app/src/main/res/values-tl/strings_hosts.xml create mode 100644 app/src/main/res/values-tl/strings_lists.xml create mode 100644 app/src/main/res/values-tl/strings_log.xml create mode 100644 app/src/main/res/values-tl/strings_notification.xml create mode 100644 app/src/main/res/values-tl/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-tl/strings_prefs_main.xml create mode 100644 app/src/main/res/values-tl/strings_prefs_root.xml create mode 100644 app/src/main/res/values-tl/strings_prefs_update.xml create mode 100644 app/src/main/res/values-tl/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-tl/strings_support.xml create mode 100644 app/src/main/res/values-tl/strings_update.xml create mode 100644 app/src/main/res/values-tl/strings_welcome.xml create mode 100644 app/src/main/res/values-tr/strings.xml create mode 100644 app/src/main/res/values-tr/strings_app.xml create mode 100644 app/src/main/res/values-tr/strings_errors.xml create mode 100644 app/src/main/res/values-tr/strings_home.xml create mode 100644 app/src/main/res/values-tr/strings_hosts.xml create mode 100644 app/src/main/res/values-tr/strings_lists.xml create mode 100644 app/src/main/res/values-tr/strings_log.xml create mode 100644 app/src/main/res/values-tr/strings_notification.xml create mode 100644 app/src/main/res/values-tr/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-tr/strings_prefs_main.xml create mode 100644 app/src/main/res/values-tr/strings_prefs_root.xml create mode 100644 app/src/main/res/values-tr/strings_prefs_update.xml create mode 100644 app/src/main/res/values-tr/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-tr/strings_source_edit.xml create mode 100644 app/src/main/res/values-tr/strings_support.xml create mode 100644 app/src/main/res/values-tr/strings_update.xml create mode 100644 app/src/main/res/values-tr/strings_welcome.xml create mode 100644 app/src/main/res/values-uk/strings.xml create mode 100644 app/src/main/res/values-uk/strings_app.xml create mode 100644 app/src/main/res/values-uk/strings_errors.xml create mode 100644 app/src/main/res/values-uk/strings_home.xml create mode 100644 app/src/main/res/values-uk/strings_hosts.xml create mode 100644 app/src/main/res/values-uk/strings_lists.xml create mode 100644 app/src/main/res/values-uk/strings_log.xml create mode 100644 app/src/main/res/values-uk/strings_notification.xml create mode 100644 app/src/main/res/values-uk/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-uk/strings_prefs_main.xml create mode 100644 app/src/main/res/values-uk/strings_prefs_root.xml create mode 100644 app/src/main/res/values-uk/strings_prefs_update.xml create mode 100644 app/src/main/res/values-uk/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-uk/strings_support.xml create mode 100644 app/src/main/res/values-uk/strings_update.xml create mode 100644 app/src/main/res/values-uk/strings_welcome.xml create mode 100644 app/src/main/res/values-ur/strings.xml create mode 100644 app/src/main/res/values-ur/strings_app.xml create mode 100644 app/src/main/res/values-ur/strings_errors.xml create mode 100644 app/src/main/res/values-ur/strings_home.xml create mode 100644 app/src/main/res/values-ur/strings_hosts.xml create mode 100644 app/src/main/res/values-ur/strings_lists.xml create mode 100644 app/src/main/res/values-ur/strings_log.xml create mode 100644 app/src/main/res/values-ur/strings_notification.xml create mode 100644 app/src/main/res/values-ur/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-ur/strings_prefs_main.xml create mode 100644 app/src/main/res/values-ur/strings_prefs_root.xml create mode 100644 app/src/main/res/values-ur/strings_prefs_update.xml create mode 100644 app/src/main/res/values-ur/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-ur/strings_support.xml create mode 100644 app/src/main/res/values-ur/strings_update.xml create mode 100644 app/src/main/res/values-ur/strings_welcome.xml create mode 100644 app/src/main/res/values-uz/strings.xml create mode 100644 app/src/main/res/values-uz/strings_app.xml create mode 100644 app/src/main/res/values-uz/strings_errors.xml create mode 100644 app/src/main/res/values-uz/strings_home.xml create mode 100644 app/src/main/res/values-uz/strings_hosts.xml create mode 100644 app/src/main/res/values-uz/strings_lists.xml create mode 100644 app/src/main/res/values-uz/strings_log.xml create mode 100644 app/src/main/res/values-uz/strings_notification.xml create mode 100644 app/src/main/res/values-uz/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-uz/strings_prefs_main.xml create mode 100644 app/src/main/res/values-uz/strings_prefs_root.xml create mode 100644 app/src/main/res/values-uz/strings_prefs_update.xml create mode 100644 app/src/main/res/values-uz/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-uz/strings_support.xml create mode 100644 app/src/main/res/values-uz/strings_update.xml create mode 100644 app/src/main/res/values-uz/strings_welcome.xml create mode 100644 app/src/main/res/values-vi/strings.xml create mode 100644 app/src/main/res/values-vi/strings_app.xml create mode 100644 app/src/main/res/values-vi/strings_errors.xml create mode 100644 app/src/main/res/values-vi/strings_home.xml create mode 100644 app/src/main/res/values-vi/strings_hosts.xml create mode 100644 app/src/main/res/values-vi/strings_lists.xml create mode 100644 app/src/main/res/values-vi/strings_log.xml create mode 100644 app/src/main/res/values-vi/strings_notification.xml create mode 100644 app/src/main/res/values-vi/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-vi/strings_prefs_main.xml create mode 100644 app/src/main/res/values-vi/strings_prefs_root.xml create mode 100644 app/src/main/res/values-vi/strings_prefs_update.xml create mode 100644 app/src/main/res/values-vi/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-vi/strings_support.xml create mode 100644 app/src/main/res/values-vi/strings_update.xml create mode 100644 app/src/main/res/values-vi/strings_welcome.xml create mode 100644 app/src/main/res/values-zh-rTW/strings.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_app.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_errors.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_home.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_hosts.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_lists.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_log.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_notification.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_prefs_main.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_prefs_root.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_prefs_update.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_source_edit.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_support.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_update.xml create mode 100644 app/src/main/res/values-zh-rTW/strings_welcome.xml create mode 100644 app/src/main/res/values-zh/strings.xml create mode 100644 app/src/main/res/values-zh/strings_app.xml create mode 100644 app/src/main/res/values-zh/strings_errors.xml create mode 100644 app/src/main/res/values-zh/strings_home.xml create mode 100644 app/src/main/res/values-zh/strings_hosts.xml create mode 100644 app/src/main/res/values-zh/strings_lists.xml create mode 100644 app/src/main/res/values-zh/strings_log.xml create mode 100644 app/src/main/res/values-zh/strings_notification.xml create mode 100644 app/src/main/res/values-zh/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values-zh/strings_prefs_main.xml create mode 100644 app/src/main/res/values-zh/strings_prefs_root.xml create mode 100644 app/src/main/res/values-zh/strings_prefs_update.xml create mode 100644 app/src/main/res/values-zh/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values-zh/strings_source_edit.xml create mode 100644 app/src/main/res/values-zh/strings_support.xml create mode 100644 app/src/main/res/values-zh/strings_update.xml create mode 100644 app/src/main/res/values-zh/strings_welcome.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/preferences.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/strings_app.xml create mode 100644 app/src/main/res/values/strings_errors.xml create mode 100644 app/src/main/res/values/strings_home.xml create mode 100644 app/src/main/res/values/strings_hosts.xml create mode 100644 app/src/main/res/values/strings_lists.xml create mode 100644 app/src/main/res/values/strings_log.xml create mode 100644 app/src/main/res/values/strings_notification.xml create mode 100644 app/src/main/res/values/strings_prefs_backup_restore.xml create mode 100644 app/src/main/res/values/strings_prefs_main.xml create mode 100644 app/src/main/res/values/strings_prefs_root.xml create mode 100644 app/src/main/res/values/strings_prefs_update.xml create mode 100644 app/src/main/res/values/strings_prefs_vpn.xml create mode 100644 app/src/main/res/values/strings_source_edit.xml create mode 100644 app/src/main/res/values/strings_static.xml create mode 100644 app/src/main/res/values/strings_support.xml create mode 100644 app/src/main/res/values/strings_update.xml create mode 100644 app/src/main/res/values/strings_welcome.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/main/res/xml/list_searchable.xml create mode 100644 app/src/main/res/xml/network_security_config.xml create mode 100644 app/src/main/res/xml/preferences_backup_restore.xml create mode 100644 app/src/main/res/xml/preferences_main.xml create mode 100644 app/src/main/res/xml/preferences_root.xml create mode 100644 app/src/main/res/xml/preferences_update.xml create mode 100644 app/src/main/res/xml/preferences_vpn.xml create mode 100644 app/src/main/res/xml/shortcuts.xml create mode 100644 app/src/test/java/org/adaway/model/git/GitHostsSourceTest.java create mode 100644 app/src/test/java/org/adaway/model/source/SourceLoaderTest.java create mode 100644 app/src/test/java/org/adaway/ui/log/LogEntrySortTest.java create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 metadata/af/full_description.txt create mode 100644 metadata/af/short_description.txt create mode 100644 metadata/af/title.txt create mode 100644 metadata/ar/full_description.txt create mode 100644 metadata/ar/short_description.txt create mode 100644 metadata/ar/title.txt create mode 100644 metadata/ast/full_description.txt create mode 100644 metadata/ast/short_description.txt create mode 100644 metadata/ast/title.txt create mode 100644 metadata/az/full_description.txt create mode 100644 metadata/az/short_description.txt create mode 100644 metadata/az/title.txt create mode 100644 metadata/be/full_description.txt create mode 100644 metadata/be/short_description.txt create mode 100644 metadata/be/title.txt create mode 100644 metadata/bg/full_description.txt create mode 100644 metadata/bg/short_description.txt create mode 100644 metadata/bg/title.txt create mode 100644 metadata/bn/full_description.txt create mode 100644 metadata/bn/short_description.txt create mode 100644 metadata/bn/title.txt create mode 100644 metadata/ca/full_description.txt create mode 100644 metadata/ca/short_description.txt create mode 100644 metadata/ca/title.txt create mode 100644 metadata/cs/full_description.txt create mode 100644 metadata/cs/short_description.txt create mode 100644 metadata/cs/title.txt create mode 100644 metadata/da/full_description.txt create mode 100644 metadata/da/short_description.txt create mode 100644 metadata/da/title.txt create mode 100644 metadata/de/full_description.txt create mode 100644 metadata/de/short_description.txt create mode 100644 metadata/de/title.txt create mode 100644 metadata/el/full_description.txt create mode 100644 metadata/el/short_description.txt create mode 100644 metadata/el/title.txt create mode 100644 metadata/en-US/full_description.txt create mode 100644 metadata/en-US/images/featureGraphic.png create mode 100644 metadata/en-US/images/icon.png create mode 100644 metadata/en-US/phoneScreenshots/screenshot1.png create mode 100644 metadata/en-US/phoneScreenshots/screenshot2.png create mode 100644 metadata/en-US/phoneScreenshots/screenshot3.png create mode 100644 metadata/en-US/phoneScreenshots/screenshot4.png create mode 100644 metadata/en-US/phoneScreenshots/screenshot5.png create mode 100644 metadata/en-US/short_description.txt create mode 100644 metadata/en-US/title.txt create mode 100644 metadata/en/full_description.txt create mode 100644 metadata/en/short_description.txt create mode 100644 metadata/en/title.txt create mode 100644 metadata/eo/full_description.txt create mode 100644 metadata/eo/short_description.txt create mode 100644 metadata/eo/title.txt create mode 100644 metadata/es-MX/full_description.txt create mode 100644 metadata/es-MX/short_description.txt create mode 100644 metadata/es-MX/title.txt create mode 100644 metadata/es-rMX/full_description.txt create mode 100644 metadata/es-rMX/short_description.txt create mode 100644 metadata/es/full_description.txt create mode 100644 metadata/es/short_description.txt create mode 100644 metadata/es/title.txt create mode 100644 metadata/et/full_description.txt create mode 100644 metadata/et/short_description.txt create mode 100644 metadata/et/title.txt create mode 100644 metadata/eu/full_description.txt create mode 100644 metadata/eu/short_description.txt create mode 100644 metadata/eu/title.txt create mode 100644 metadata/fa/full_description.txt create mode 100644 metadata/fa/short_description.txt create mode 100644 metadata/fa/title.txt create mode 100644 metadata/fi/full_description.txt create mode 100644 metadata/fi/short_description.txt create mode 100644 metadata/fi/title.txt create mode 100644 metadata/fil/full_description.txt create mode 100644 metadata/fil/short_description.txt create mode 100644 metadata/fil/title.txt create mode 100644 metadata/fr/full_description.txt create mode 100644 metadata/fr/short_description.txt create mode 100644 metadata/fr/title.txt create mode 100644 metadata/gl/full_description.txt create mode 100644 metadata/gl/short_description.txt create mode 100644 metadata/gl/title.txt create mode 100644 metadata/he/short_description.txt create mode 100644 metadata/hi/full_description.txt create mode 100644 metadata/hi/short_description.txt create mode 100644 metadata/hi/title.txt create mode 100644 metadata/hr/full_description.txt create mode 100644 metadata/hr/short_description.txt create mode 100644 metadata/hr/title.txt create mode 100644 metadata/hu/full_description.txt create mode 100644 metadata/hu/short_description.txt create mode 100644 metadata/hu/title.txt create mode 100644 metadata/id/full_description.txt create mode 100644 metadata/id/short_description.txt create mode 100644 metadata/id/title.txt create mode 100644 metadata/in/full_description.txt create mode 100644 metadata/in/short_description.txt create mode 100644 metadata/is/full_description.txt create mode 100644 metadata/is/short_description.txt create mode 100644 metadata/is/title.txt create mode 100644 metadata/it/full_description.txt create mode 100644 metadata/it/short_description.txt create mode 100644 metadata/it/title.txt create mode 100644 metadata/iw/full_description.txt create mode 100644 metadata/iw/short_description.txt create mode 100644 metadata/iw/title.txt create mode 100644 metadata/ja/full_description.txt create mode 100644 metadata/ja/short_description.txt create mode 100644 metadata/ja/title.txt create mode 100644 metadata/km/full_description.txt create mode 100644 metadata/km/short_description.txt create mode 100644 metadata/km/title.txt create mode 100644 metadata/ko/full_description.txt create mode 100644 metadata/ko/short_description.txt create mode 100644 metadata/ko/title.txt create mode 100644 metadata/ku/full_description.txt create mode 100644 metadata/ku/short_description.txt create mode 100644 metadata/ku/title.txt create mode 100644 metadata/lt/full_description.txt create mode 100644 metadata/lt/short_description.txt create mode 100644 metadata/lt/title.txt create mode 100644 metadata/ml/full_description.txt create mode 100644 metadata/ml/short_description.txt create mode 100644 metadata/ml/title.txt create mode 100644 metadata/ms/full_description.txt create mode 100644 metadata/ms/short_description.txt create mode 100644 metadata/ms/title.txt create mode 100644 metadata/my/full_description.txt create mode 100644 metadata/my/short_description.txt create mode 100644 metadata/my/title.txt create mode 100644 metadata/nb-NO/full_description.txt create mode 100644 metadata/nb-NO/short_description.txt create mode 100644 metadata/nb-NO/title.txt create mode 100644 metadata/nb-rNO/full_description.txt create mode 100644 metadata/nb-rNO/short_description.txt create mode 100644 metadata/ne/full_description.txt create mode 100644 metadata/ne/short_description.txt create mode 100644 metadata/ne/title.txt create mode 100644 metadata/nl/full_description.txt create mode 100644 metadata/nl/short_description.txt create mode 100644 metadata/nl/title.txt create mode 100644 metadata/no/full_description.txt create mode 100644 metadata/no/short_description.txt create mode 100644 metadata/no/title.txt create mode 100644 metadata/pa/full_description.txt create mode 100644 metadata/pa/short_description.txt create mode 100644 metadata/pa/title.txt create mode 100644 metadata/pl/full_description.txt create mode 100644 metadata/pl/short_description.txt create mode 100644 metadata/pl/title.txt create mode 100644 metadata/ps/full_description.txt create mode 100644 metadata/ps/short_description.txt create mode 100644 metadata/ps/title.txt create mode 100644 metadata/pt-BR/full_description.txt create mode 100644 metadata/pt-BR/short_description.txt create mode 100644 metadata/pt-BR/title.txt create mode 100644 metadata/pt/full_description.txt create mode 100644 metadata/pt/short_description.txt create mode 100644 metadata/pt/title.txt create mode 100644 metadata/ro/full_description.txt create mode 100644 metadata/ro/short_description.txt create mode 100644 metadata/ro/title.txt create mode 100644 metadata/ru/full_description.txt create mode 100644 metadata/ru/short_description.txt create mode 100644 metadata/ru/title.txt create mode 100644 metadata/si/full_description.txt create mode 100644 metadata/si/short_description.txt create mode 100644 metadata/si/title.txt create mode 100644 metadata/sk/full_description.txt create mode 100644 metadata/sk/short_description.txt create mode 100644 metadata/sk/title.txt create mode 100644 metadata/sl/full_description.txt create mode 100644 metadata/sl/short_description.txt create mode 100644 metadata/sl/title.txt create mode 100644 metadata/sq/full_description.txt create mode 100644 metadata/sq/short_description.txt create mode 100644 metadata/sq/title.txt create mode 100644 metadata/sr/full_description.txt create mode 100644 metadata/sr/short_description.txt create mode 100644 metadata/sr/title.txt create mode 100644 metadata/sv/full_description.txt create mode 100644 metadata/sv/short_description.txt create mode 100644 metadata/sv/title.txt create mode 100644 metadata/ta/full_description.txt create mode 100644 metadata/ta/short_description.txt create mode 100644 metadata/ta/title.txt create mode 100644 metadata/th/full_description.txt create mode 100644 metadata/th/short_description.txt create mode 100644 metadata/th/title.txt create mode 100644 metadata/tl/full_description.txt create mode 100644 metadata/tl/short_description.txt create mode 100644 metadata/tl/title.txt create mode 100644 metadata/tr/full_description.txt create mode 100644 metadata/tr/short_description.txt create mode 100644 metadata/tr/title.txt create mode 100644 metadata/uk/full_description.txt create mode 100644 metadata/uk/short_description.txt create mode 100644 metadata/uk/title.txt create mode 100644 metadata/ur/full_description.txt create mode 100644 metadata/ur/short_description.txt create mode 100644 metadata/ur/title.txt create mode 100644 metadata/uz/full_description.txt create mode 100644 metadata/uz/short_description.txt create mode 100644 metadata/uz/title.txt create mode 100644 metadata/vi/full_description.txt create mode 100644 metadata/vi/short_description.txt create mode 100644 metadata/vi/title.txt create mode 100644 metadata/zh-TW/full_description.txt create mode 100644 metadata/zh-TW/short_description.txt create mode 100644 metadata/zh-TW/title.txt create mode 100644 metadata/zh-rTW/full_description.txt create mode 100644 metadata/zh-rTW/short_description.txt create mode 100644 metadata/zh/full_description.txt create mode 100644 metadata/zh/short_description.txt create mode 100644 metadata/zh/title.txt create mode 100644 sentrystub/.gitignore create mode 100644 sentrystub/build.gradle create mode 100644 sentrystub/src/main/AndroidManifest.xml create mode 100644 sentrystub/src/main/java/io/sentry/Breadcrumb.java create mode 100644 sentrystub/src/main/java/io/sentry/Integration.java create mode 100644 sentrystub/src/main/java/io/sentry/Scope.java create mode 100644 sentrystub/src/main/java/io/sentry/ScopeCallback.java create mode 100644 sentrystub/src/main/java/io/sentry/Sentry.java create mode 100644 sentrystub/src/main/java/io/sentry/SentryLevel.java create mode 100644 sentrystub/src/main/java/io/sentry/SentryOptions.java create mode 100644 sentrystub/src/main/java/io/sentry/android/core/SentryAndroid.java create mode 100644 sentrystub/src/main/java/io/sentry/android/fragment/FragmentLifecycleIntegration.java create mode 100644 sentrystub/src/main/java/io/sentry/android/timber/SentryTimberIntegration.java create mode 100644 settings.gradle create mode 100644 tcpdump/build.gradle create mode 100644 tcpdump/jni/Android.mk create mode 100644 tcpdump/jni/libpcap/Android.mk create mode 100644 tcpdump/jni/libpcap/CHANGES create mode 100644 tcpdump/jni/libpcap/CREDITS create mode 100755 tcpdump/jni/libpcap/ChmodBPF/ChmodBPF create mode 100644 tcpdump/jni/libpcap/ChmodBPF/StartupParameters.plist create mode 100644 tcpdump/jni/libpcap/CleanSpec.mk create mode 100644 tcpdump/jni/libpcap/INSTALL.txt create mode 100644 tcpdump/jni/libpcap/LICENSE create mode 100644 tcpdump/jni/libpcap/Makefile-devel-adds create mode 100644 tcpdump/jni/libpcap/Makefile.in create mode 100644 tcpdump/jni/libpcap/README create mode 100644 tcpdump/jni/libpcap/README.Win32 create mode 100644 tcpdump/jni/libpcap/README.aix create mode 100644 tcpdump/jni/libpcap/README.dag create mode 100644 tcpdump/jni/libpcap/README.hpux create mode 100644 tcpdump/jni/libpcap/README.linux create mode 100644 tcpdump/jni/libpcap/README.macosx create mode 100644 tcpdump/jni/libpcap/README.septel create mode 100644 tcpdump/jni/libpcap/README.sita create mode 100644 tcpdump/jni/libpcap/README.tru64 create mode 100644 tcpdump/jni/libpcap/SUNOS4/nit_if.o.sparc create mode 100644 tcpdump/jni/libpcap/SUNOS4/nit_if.o.sun3 create mode 100644 tcpdump/jni/libpcap/SUNOS4/nit_if.o.sun4c.4.0.3c create mode 100644 tcpdump/jni/libpcap/TODO create mode 100644 tcpdump/jni/libpcap/VERSION create mode 100644 tcpdump/jni/libpcap/Win32/Include/Gnuc.h create mode 100644 tcpdump/jni/libpcap/Win32/Include/addrinfo.h create mode 100644 tcpdump/jni/libpcap/Win32/Include/arpa/nameser.h create mode 100644 tcpdump/jni/libpcap/Win32/Include/bittypes.h create mode 100644 tcpdump/jni/libpcap/Win32/Include/cdecl_ext.h create mode 100644 tcpdump/jni/libpcap/Win32/Include/inetprivate.h create mode 100644 tcpdump/jni/libpcap/Win32/Include/ip6_misc.h create mode 100644 tcpdump/jni/libpcap/Win32/Include/net/if.h create mode 100644 tcpdump/jni/libpcap/Win32/Include/net/netdb.h create mode 100644 tcpdump/jni/libpcap/Win32/Include/net/paths.h create mode 100644 tcpdump/jni/libpcap/Win32/Include/sockstorage.h create mode 100644 tcpdump/jni/libpcap/Win32/Prj/libpcap.dsp create mode 100644 tcpdump/jni/libpcap/Win32/Prj/libpcap.dsw create mode 100644 tcpdump/jni/libpcap/Win32/Src/ffs.c create mode 100644 tcpdump/jni/libpcap/Win32/Src/gai_strerror.c create mode 100644 tcpdump/jni/libpcap/Win32/Src/getaddrinfo.c create mode 100644 tcpdump/jni/libpcap/Win32/Src/getnetbynm.c create mode 100644 tcpdump/jni/libpcap/Win32/Src/getnetent.c create mode 100644 tcpdump/jni/libpcap/Win32/Src/getopt.c create mode 100644 tcpdump/jni/libpcap/Win32/Src/getservent.c create mode 100644 tcpdump/jni/libpcap/Win32/Src/inet_aton.c create mode 100644 tcpdump/jni/libpcap/Win32/Src/inet_net.c create mode 100644 tcpdump/jni/libpcap/Win32/Src/inet_pton.c create mode 100644 tcpdump/jni/libpcap/aclocal.m4 create mode 100644 tcpdump/jni/libpcap/arcnet.h create mode 100644 tcpdump/jni/libpcap/atmuni31.h create mode 100644 tcpdump/jni/libpcap/bpf/net/bpf_filter.c create mode 100644 tcpdump/jni/libpcap/bpf_dump.c create mode 100644 tcpdump/jni/libpcap/bpf_filter.c create mode 100644 tcpdump/jni/libpcap/bpf_image.c create mode 100755 tcpdump/jni/libpcap/chmod_bpf create mode 100644 tcpdump/jni/libpcap/config.guess create mode 100644 tcpdump/jni/libpcap/config.h create mode 100644 tcpdump/jni/libpcap/config.h.in create mode 100644 tcpdump/jni/libpcap/config.sub create mode 100755 tcpdump/jni/libpcap/configure create mode 100644 tcpdump/jni/libpcap/configure.in create mode 100644 tcpdump/jni/libpcap/dlpisubs.c create mode 100644 tcpdump/jni/libpcap/dlpisubs.h create mode 100644 tcpdump/jni/libpcap/doc/pcap.html create mode 100644 tcpdump/jni/libpcap/doc/pcap.txt create mode 100644 tcpdump/jni/libpcap/doc/pcap.xml create mode 100644 tcpdump/jni/libpcap/etherent.c create mode 100644 tcpdump/jni/libpcap/ethertype.h create mode 100644 tcpdump/jni/libpcap/fad-getad.c create mode 100644 tcpdump/jni/libpcap/fad-gifc.c create mode 100644 tcpdump/jni/libpcap/fad-glifc.c create mode 100644 tcpdump/jni/libpcap/fad-null.c create mode 100644 tcpdump/jni/libpcap/fad-sita.c create mode 100644 tcpdump/jni/libpcap/fad-win32.c create mode 100644 tcpdump/jni/libpcap/gencode.c create mode 100644 tcpdump/jni/libpcap/gencode.h create mode 100644 tcpdump/jni/libpcap/grammar.c create mode 100644 tcpdump/jni/libpcap/grammar.y create mode 100644 tcpdump/jni/libpcap/ieee80211.h create mode 100644 tcpdump/jni/libpcap/inet.c create mode 100755 tcpdump/jni/libpcap/install-sh create mode 100644 tcpdump/jni/libpcap/lbl/os-aix4.h create mode 100644 tcpdump/jni/libpcap/lbl/os-hpux11.h create mode 100644 tcpdump/jni/libpcap/lbl/os-osf4.h create mode 100644 tcpdump/jni/libpcap/lbl/os-osf5.h create mode 100644 tcpdump/jni/libpcap/lbl/os-solaris2.h create mode 100644 tcpdump/jni/libpcap/lbl/os-sunos4.h create mode 100644 tcpdump/jni/libpcap/lbl/os-ultrix4.h create mode 100644 tcpdump/jni/libpcap/llc.h create mode 100644 tcpdump/jni/libpcap/missing/snprintf.c create mode 100755 tcpdump/jni/libpcap/mkdep create mode 100644 tcpdump/jni/libpcap/msdos/bin2c.c create mode 100644 tcpdump/jni/libpcap/msdos/common.dj create mode 100644 tcpdump/jni/libpcap/msdos/makefile create mode 100644 tcpdump/jni/libpcap/msdos/makefile.dj create mode 100644 tcpdump/jni/libpcap/msdos/makefile.wc create mode 100644 tcpdump/jni/libpcap/msdos/ndis2.c create mode 100644 tcpdump/jni/libpcap/msdos/ndis2.h create mode 100644 tcpdump/jni/libpcap/msdos/ndis_0.asm create mode 100644 tcpdump/jni/libpcap/msdos/pkt_rx0.asm create mode 100644 tcpdump/jni/libpcap/msdos/pkt_rx1.s create mode 100644 tcpdump/jni/libpcap/msdos/pktdrvr.c create mode 100644 tcpdump/jni/libpcap/msdos/pktdrvr.h create mode 100644 tcpdump/jni/libpcap/msdos/readme.dos create mode 100644 tcpdump/jni/libpcap/nametoaddr.c create mode 100644 tcpdump/jni/libpcap/nlpid.h create mode 100644 tcpdump/jni/libpcap/optimize.c create mode 100644 tcpdump/jni/libpcap/org.tcpdump.chmod_bpf.plist create mode 100644 tcpdump/jni/libpcap/packaging/pcap.spec.in create mode 100644 tcpdump/jni/libpcap/pcap-bpf.c create mode 100644 tcpdump/jni/libpcap/pcap-bpf.h create mode 100644 tcpdump/jni/libpcap/pcap-bt-linux.c create mode 100644 tcpdump/jni/libpcap/pcap-bt-linux.h create mode 100644 tcpdump/jni/libpcap/pcap-bt-monitor-linux.c create mode 100644 tcpdump/jni/libpcap/pcap-bt-monitor-linux.h create mode 100644 tcpdump/jni/libpcap/pcap-can-linux.c create mode 100644 tcpdump/jni/libpcap/pcap-can-linux.h create mode 100644 tcpdump/jni/libpcap/pcap-canusb-linux.c create mode 100644 tcpdump/jni/libpcap/pcap-canusb-linux.h create mode 100644 tcpdump/jni/libpcap/pcap-common.c create mode 100644 tcpdump/jni/libpcap/pcap-common.h create mode 100644 tcpdump/jni/libpcap/pcap-config.1 create mode 100644 tcpdump/jni/libpcap/pcap-config.in create mode 100644 tcpdump/jni/libpcap/pcap-dag.c create mode 100644 tcpdump/jni/libpcap/pcap-dag.h create mode 100644 tcpdump/jni/libpcap/pcap-dbus.c create mode 100644 tcpdump/jni/libpcap/pcap-dbus.h create mode 100644 tcpdump/jni/libpcap/pcap-dlpi.c create mode 100644 tcpdump/jni/libpcap/pcap-dos.c create mode 100644 tcpdump/jni/libpcap/pcap-dos.h create mode 100644 tcpdump/jni/libpcap/pcap-enet.c create mode 100644 tcpdump/jni/libpcap/pcap-filter.manmisc.in create mode 100644 tcpdump/jni/libpcap/pcap-int.h create mode 100644 tcpdump/jni/libpcap/pcap-libdlpi.c create mode 100644 tcpdump/jni/libpcap/pcap-linktype.manmisc.in create mode 100644 tcpdump/jni/libpcap/pcap-linux.c create mode 100644 tcpdump/jni/libpcap/pcap-namedb.h create mode 100644 tcpdump/jni/libpcap/pcap-netfilter-linux.c create mode 100644 tcpdump/jni/libpcap/pcap-netfilter-linux.h create mode 100644 tcpdump/jni/libpcap/pcap-nit.c create mode 100644 tcpdump/jni/libpcap/pcap-null.c create mode 100644 tcpdump/jni/libpcap/pcap-pf.c create mode 100644 tcpdump/jni/libpcap/pcap-savefile.manfile.in create mode 100644 tcpdump/jni/libpcap/pcap-septel.c create mode 100644 tcpdump/jni/libpcap/pcap-septel.h create mode 100644 tcpdump/jni/libpcap/pcap-sita.c create mode 100644 tcpdump/jni/libpcap/pcap-sita.h create mode 100644 tcpdump/jni/libpcap/pcap-sita.html create mode 100644 tcpdump/jni/libpcap/pcap-snf.c create mode 100644 tcpdump/jni/libpcap/pcap-snf.h create mode 100644 tcpdump/jni/libpcap/pcap-snit.c create mode 100644 tcpdump/jni/libpcap/pcap-snoop.c create mode 100644 tcpdump/jni/libpcap/pcap-stdinc.h create mode 100644 tcpdump/jni/libpcap/pcap-tstamp.manmisc.in create mode 100644 tcpdump/jni/libpcap/pcap-usb-linux.c create mode 100644 tcpdump/jni/libpcap/pcap-usb-linux.h create mode 100644 tcpdump/jni/libpcap/pcap-win32.c create mode 100644 tcpdump/jni/libpcap/pcap.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap.c create mode 100644 tcpdump/jni/libpcap/pcap.h create mode 100644 tcpdump/jni/libpcap/pcap/bluetooth.h create mode 100644 tcpdump/jni/libpcap/pcap/bpf.h create mode 100644 tcpdump/jni/libpcap/pcap/ipnet.h create mode 100644 tcpdump/jni/libpcap/pcap/namedb.h create mode 100644 tcpdump/jni/libpcap/pcap/nflog.h create mode 100644 tcpdump/jni/libpcap/pcap/pcap.h create mode 100644 tcpdump/jni/libpcap/pcap/sll.h create mode 100644 tcpdump/jni/libpcap/pcap/usb.h create mode 100644 tcpdump/jni/libpcap/pcap/vlan.h create mode 100644 tcpdump/jni/libpcap/pcap1.h create mode 100644 tcpdump/jni/libpcap/pcap_activate.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_breakloop.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_can_set_rfmon.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_close.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_compile.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap_create.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_datalink.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap_datalink_name_to_val.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_datalink_val_to_name.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_dump.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_dump_close.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_dump_file.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_dump_flush.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_dump_ftell.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_dump_open.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap_file.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_fileno.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_findalldevs.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_freecode.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_get_selectable_fd.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_get_tstamp_precision.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap_geterr.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_inject.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_is_swapped.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_lib_version.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_list_datalinks.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap_list_tstamp_types.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap_lookupdev.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_lookupnet.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_loop.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_major_version.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_next_ex.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_offline_filter.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_open_dead.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap_open_live.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_open_offline.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap_set_buffer_size.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_set_datalink.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_set_immediate_mode.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_set_promisc.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_set_rfmon.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_set_snaplen.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_set_timeout.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_set_tstamp_precision.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap_set_tstamp_type.3pcap.in create mode 100644 tcpdump/jni/libpcap/pcap_setdirection.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_setfilter.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_setnonblock.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_snapshot.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_stats.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_statustostr.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_strerror.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_tstamp_type_name_to_val.3pcap create mode 100644 tcpdump/jni/libpcap/pcap_tstamp_type_val_to_name.3pcap create mode 100644 tcpdump/jni/libpcap/ppp.h create mode 100755 tcpdump/jni/libpcap/runlex.sh create mode 100644 tcpdump/jni/libpcap/savefile.c create mode 100644 tcpdump/jni/libpcap/scanner.c create mode 100644 tcpdump/jni/libpcap/scanner.c.top create mode 100644 tcpdump/jni/libpcap/scanner.h create mode 100644 tcpdump/jni/libpcap/scanner.l create mode 100644 tcpdump/jni/libpcap/sf-pcap-ng.c create mode 100644 tcpdump/jni/libpcap/sf-pcap-ng.h create mode 100644 tcpdump/jni/libpcap/sf-pcap.c create mode 100644 tcpdump/jni/libpcap/sf-pcap.h create mode 100644 tcpdump/jni/libpcap/sunatmpos.h create mode 100644 tcpdump/jni/libpcap/tests/BPF/1.txt create mode 100644 tcpdump/jni/libpcap/tests/BPF/2.txt create mode 100644 tcpdump/jni/libpcap/tests/BPF/3.txt create mode 100644 tcpdump/jni/libpcap/tests/BPF/4.txt create mode 100644 tcpdump/jni/libpcap/tests/BPF/5.txt create mode 100644 tcpdump/jni/libpcap/tests/BPF/6.txt create mode 100644 tcpdump/jni/libpcap/tests/BPF/7.txt create mode 100644 tcpdump/jni/libpcap/tests/capturetest.c create mode 100644 tcpdump/jni/libpcap/tests/filtertest.c create mode 100644 tcpdump/jni/libpcap/tests/findalldevstest.c create mode 100644 tcpdump/jni/libpcap/tests/nonblocktest.c create mode 100644 tcpdump/jni/libpcap/tests/opentest.c create mode 100644 tcpdump/jni/libpcap/tests/pcap_compile_test.c create mode 100644 tcpdump/jni/libpcap/tests/reactivatetest.c create mode 100644 tcpdump/jni/libpcap/tests/selpolltest.c create mode 100644 tcpdump/jni/libpcap/tests/valgrindtest.c create mode 100755 tcpdump/jni/libpcap/tests/visopts.py create mode 100644 tcpdump/jni/libpcap/tokdefs.h create mode 100644 tcpdump/jni/libpcap/version.c create mode 100644 tcpdump/jni/libpcap/version.h create mode 100644 tcpdump/jni/stub/Android.mk create mode 100644 tcpdump/jni/stub/stub.c create mode 100644 tcpdump/jni/tcpdump/Android.mk create mode 100644 tcpdump/jni/tcpdump/CHANGES create mode 100644 tcpdump/jni/tcpdump/CREDITS create mode 100644 tcpdump/jni/tcpdump/CleanSpec.mk create mode 100644 tcpdump/jni/tcpdump/INSTALL.txt create mode 100644 tcpdump/jni/tcpdump/LICENSE create mode 100644 tcpdump/jni/tcpdump/Makefile-devel-adds create mode 100644 tcpdump/jni/tcpdump/Makefile.in create mode 100644 tcpdump/jni/tcpdump/PLATFORMS create mode 100644 tcpdump/jni/tcpdump/README create mode 100644 tcpdump/jni/tcpdump/README.md create mode 100644 tcpdump/jni/tcpdump/Readme.Win32 create mode 100644 tcpdump/jni/tcpdump/TODO create mode 100644 tcpdump/jni/tcpdump/VERSION create mode 100644 tcpdump/jni/tcpdump/aclocal.m4 create mode 100644 tcpdump/jni/tcpdump/addrtoname.c create mode 100644 tcpdump/jni/tcpdump/addrtoname.h create mode 100644 tcpdump/jni/tcpdump/af.c create mode 100644 tcpdump/jni/tcpdump/af.h create mode 100644 tcpdump/jni/tcpdump/ah.h create mode 100644 tcpdump/jni/tcpdump/aodv.h create mode 100644 tcpdump/jni/tcpdump/appletalk.h create mode 100644 tcpdump/jni/tcpdump/arcnet.h create mode 100644 tcpdump/jni/tcpdump/atime.awk create mode 100644 tcpdump/jni/tcpdump/atm.h create mode 100644 tcpdump/jni/tcpdump/atmuni31.h create mode 100644 tcpdump/jni/tcpdump/bgp.h create mode 100644 tcpdump/jni/tcpdump/bootp.h create mode 100644 tcpdump/jni/tcpdump/bpf_dump.c create mode 100644 tcpdump/jni/tcpdump/chdlc.h create mode 100644 tcpdump/jni/tcpdump/checksum.c create mode 100644 tcpdump/jni/tcpdump/config.guess create mode 100644 tcpdump/jni/tcpdump/config.h create mode 100644 tcpdump/jni/tcpdump/config.h.in create mode 100644 tcpdump/jni/tcpdump/config.sub create mode 100755 tcpdump/jni/tcpdump/configure create mode 100644 tcpdump/jni/tcpdump/configure.in create mode 100644 tcpdump/jni/tcpdump/cpack.c create mode 100644 tcpdump/jni/tcpdump/cpack.h create mode 100644 tcpdump/jni/tcpdump/dccp.h create mode 100644 tcpdump/jni/tcpdump/decnet.h create mode 100644 tcpdump/jni/tcpdump/decode_prefix.h create mode 100644 tcpdump/jni/tcpdump/enc.h create mode 100644 tcpdump/jni/tcpdump/esp.h create mode 100644 tcpdump/jni/tcpdump/ether.h create mode 100644 tcpdump/jni/tcpdump/ethertype.h create mode 100644 tcpdump/jni/tcpdump/extract.h create mode 100644 tcpdump/jni/tcpdump/fddi.h create mode 100644 tcpdump/jni/tcpdump/getopt_long.h create mode 100644 tcpdump/jni/tcpdump/gmpls.c create mode 100644 tcpdump/jni/tcpdump/gmpls.h create mode 100644 tcpdump/jni/tcpdump/gmt2local.c create mode 100644 tcpdump/jni/tcpdump/gmt2local.h create mode 100644 tcpdump/jni/tcpdump/icmp6.h create mode 100644 tcpdump/jni/tcpdump/ieee802_11.h create mode 100644 tcpdump/jni/tcpdump/ieee802_11_radio.h create mode 100644 tcpdump/jni/tcpdump/igrp.h create mode 100644 tcpdump/jni/tcpdump/in_cksum.c create mode 100755 tcpdump/jni/tcpdump/install-sh create mode 100644 tcpdump/jni/tcpdump/interface.h create mode 100644 tcpdump/jni/tcpdump/ip.h create mode 100644 tcpdump/jni/tcpdump/ip6.h create mode 100644 tcpdump/jni/tcpdump/ipfc.h create mode 100644 tcpdump/jni/tcpdump/ipnet.h create mode 100644 tcpdump/jni/tcpdump/ipproto.c create mode 100644 tcpdump/jni/tcpdump/ipproto.h create mode 100644 tcpdump/jni/tcpdump/ipsec_doi.h create mode 100644 tcpdump/jni/tcpdump/ipx.h create mode 100644 tcpdump/jni/tcpdump/isakmp.h create mode 100644 tcpdump/jni/tcpdump/l2tp.h create mode 100644 tcpdump/jni/tcpdump/l2vpn.c create mode 100644 tcpdump/jni/tcpdump/l2vpn.h create mode 100644 tcpdump/jni/tcpdump/lane.h create mode 100644 tcpdump/jni/tcpdump/lbl/os-osf4.h create mode 100644 tcpdump/jni/tcpdump/lbl/os-solaris2.h create mode 100644 tcpdump/jni/tcpdump/lbl/os-sunos4.h create mode 100644 tcpdump/jni/tcpdump/lbl/os-ultrix4.h create mode 100644 tcpdump/jni/tcpdump/llc.h create mode 100644 tcpdump/jni/tcpdump/machdep.c create mode 100644 tcpdump/jni/tcpdump/machdep.h create mode 100755 tcpdump/jni/tcpdump/makemib create mode 100644 tcpdump/jni/tcpdump/mib.h create mode 100644 tcpdump/jni/tcpdump/missing/addrinfo.h create mode 100644 tcpdump/jni/tcpdump/missing/datalinks.c create mode 100644 tcpdump/jni/tcpdump/missing/dlnames.c create mode 100644 tcpdump/jni/tcpdump/missing/getnameinfo.c create mode 100644 tcpdump/jni/tcpdump/missing/getopt_long.c create mode 100644 tcpdump/jni/tcpdump/missing/inet_aton.c create mode 100644 tcpdump/jni/tcpdump/missing/inet_ntop.c create mode 100644 tcpdump/jni/tcpdump/missing/inet_pton.c create mode 100644 tcpdump/jni/tcpdump/missing/snprintf.c create mode 100644 tcpdump/jni/tcpdump/missing/sockstorage.h create mode 100644 tcpdump/jni/tcpdump/missing/strdup.c create mode 100644 tcpdump/jni/tcpdump/missing/strlcat.c create mode 100644 tcpdump/jni/tcpdump/missing/strlcpy.c create mode 100644 tcpdump/jni/tcpdump/missing/strsep.c create mode 100755 tcpdump/jni/tcpdump/mkdep create mode 100644 tcpdump/jni/tcpdump/mpls.h create mode 100644 tcpdump/jni/tcpdump/mptcp.h create mode 100644 tcpdump/jni/tcpdump/nameser.h create mode 100644 tcpdump/jni/tcpdump/netbios.h create mode 100644 tcpdump/jni/tcpdump/netdissect.h create mode 100644 tcpdump/jni/tcpdump/nfs.h create mode 100644 tcpdump/jni/tcpdump/nfsfh.h create mode 100644 tcpdump/jni/tcpdump/nlpid.c create mode 100644 tcpdump/jni/tcpdump/nlpid.h create mode 100644 tcpdump/jni/tcpdump/ntp.h create mode 100644 tcpdump/jni/tcpdump/oakley.h create mode 100644 tcpdump/jni/tcpdump/openflow.h create mode 100644 tcpdump/jni/tcpdump/ospf.h create mode 100644 tcpdump/jni/tcpdump/ospf6.h create mode 100644 tcpdump/jni/tcpdump/oui.c create mode 100644 tcpdump/jni/tcpdump/oui.h create mode 100644 tcpdump/jni/tcpdump/packetdat.awk create mode 100644 tcpdump/jni/tcpdump/parsenfsfh.c create mode 100644 tcpdump/jni/tcpdump/pcap-missing.h create mode 100644 tcpdump/jni/tcpdump/pcap_dump_ftell.c create mode 100644 tcpdump/jni/tcpdump/pmap_prot.h create mode 100644 tcpdump/jni/tcpdump/ppi.h create mode 100644 tcpdump/jni/tcpdump/ppp.h create mode 100644 tcpdump/jni/tcpdump/print-802_11.c create mode 100644 tcpdump/jni/tcpdump/print-802_15_4.c create mode 100644 tcpdump/jni/tcpdump/print-ah.c create mode 100644 tcpdump/jni/tcpdump/print-ahcp.c create mode 100644 tcpdump/jni/tcpdump/print-aodv.c create mode 100644 tcpdump/jni/tcpdump/print-aoe.c create mode 100644 tcpdump/jni/tcpdump/print-ap1394.c create mode 100644 tcpdump/jni/tcpdump/print-arcnet.c create mode 100644 tcpdump/jni/tcpdump/print-arp.c create mode 100644 tcpdump/jni/tcpdump/print-ascii.c create mode 100644 tcpdump/jni/tcpdump/print-atalk.c create mode 100644 tcpdump/jni/tcpdump/print-atm.c create mode 100644 tcpdump/jni/tcpdump/print-babel.c create mode 100644 tcpdump/jni/tcpdump/print-beep.c create mode 100644 tcpdump/jni/tcpdump/print-bfd.c create mode 100644 tcpdump/jni/tcpdump/print-bgp.c create mode 100644 tcpdump/jni/tcpdump/print-bootp.c create mode 100644 tcpdump/jni/tcpdump/print-bt.c create mode 100644 tcpdump/jni/tcpdump/print-calm-fast.c create mode 100644 tcpdump/jni/tcpdump/print-carp.c create mode 100644 tcpdump/jni/tcpdump/print-cdp.c create mode 100644 tcpdump/jni/tcpdump/print-cfm.c create mode 100644 tcpdump/jni/tcpdump/print-chdlc.c create mode 100644 tcpdump/jni/tcpdump/print-cip.c create mode 100644 tcpdump/jni/tcpdump/print-cnfp.c create mode 100644 tcpdump/jni/tcpdump/print-dccp.c create mode 100644 tcpdump/jni/tcpdump/print-decnet.c create mode 100644 tcpdump/jni/tcpdump/print-dhcp6.c create mode 100644 tcpdump/jni/tcpdump/print-domain.c create mode 100644 tcpdump/jni/tcpdump/print-dtp.c create mode 100644 tcpdump/jni/tcpdump/print-dvmrp.c create mode 100644 tcpdump/jni/tcpdump/print-eap.c create mode 100644 tcpdump/jni/tcpdump/print-egp.c create mode 100644 tcpdump/jni/tcpdump/print-eigrp.c create mode 100644 tcpdump/jni/tcpdump/print-enc.c create mode 100644 tcpdump/jni/tcpdump/print-esp.c create mode 100644 tcpdump/jni/tcpdump/print-ether.c create mode 100644 tcpdump/jni/tcpdump/print-fddi.c create mode 100644 tcpdump/jni/tcpdump/print-forces.c create mode 100644 tcpdump/jni/tcpdump/print-fr.c create mode 100644 tcpdump/jni/tcpdump/print-frag6.c create mode 100644 tcpdump/jni/tcpdump/print-ftp.c create mode 100644 tcpdump/jni/tcpdump/print-geneve.c create mode 100644 tcpdump/jni/tcpdump/print-geonet.c create mode 100644 tcpdump/jni/tcpdump/print-gre.c create mode 100644 tcpdump/jni/tcpdump/print-hsrp.c create mode 100644 tcpdump/jni/tcpdump/print-http.c create mode 100644 tcpdump/jni/tcpdump/print-icmp.c create mode 100644 tcpdump/jni/tcpdump/print-icmp6.c create mode 100644 tcpdump/jni/tcpdump/print-igmp.c create mode 100644 tcpdump/jni/tcpdump/print-igrp.c create mode 100644 tcpdump/jni/tcpdump/print-ip.c create mode 100644 tcpdump/jni/tcpdump/print-ip6.c create mode 100644 tcpdump/jni/tcpdump/print-ip6opts.c create mode 100644 tcpdump/jni/tcpdump/print-ipcomp.c create mode 100644 tcpdump/jni/tcpdump/print-ipfc.c create mode 100644 tcpdump/jni/tcpdump/print-ipnet.c create mode 100644 tcpdump/jni/tcpdump/print-ipx.c create mode 100644 tcpdump/jni/tcpdump/print-isakmp.c create mode 100644 tcpdump/jni/tcpdump/print-isoclns.c create mode 100644 tcpdump/jni/tcpdump/print-juniper.c create mode 100644 tcpdump/jni/tcpdump/print-krb.c create mode 100644 tcpdump/jni/tcpdump/print-l2tp.c create mode 100644 tcpdump/jni/tcpdump/print-lane.c create mode 100644 tcpdump/jni/tcpdump/print-ldp.c create mode 100644 tcpdump/jni/tcpdump/print-llc.c create mode 100644 tcpdump/jni/tcpdump/print-lldp.c create mode 100644 tcpdump/jni/tcpdump/print-lmp.c create mode 100644 tcpdump/jni/tcpdump/print-loopback.c create mode 100644 tcpdump/jni/tcpdump/print-lspping.c create mode 100644 tcpdump/jni/tcpdump/print-lwapp.c create mode 100644 tcpdump/jni/tcpdump/print-lwres.c create mode 100644 tcpdump/jni/tcpdump/print-m3ua.c create mode 100644 tcpdump/jni/tcpdump/print-mobile.c create mode 100644 tcpdump/jni/tcpdump/print-mobility.c create mode 100644 tcpdump/jni/tcpdump/print-mpcp.c create mode 100644 tcpdump/jni/tcpdump/print-mpls.c create mode 100644 tcpdump/jni/tcpdump/print-mptcp.c create mode 100644 tcpdump/jni/tcpdump/print-msdp.c create mode 100644 tcpdump/jni/tcpdump/print-msnlb.c create mode 100644 tcpdump/jni/tcpdump/print-netbios.c create mode 100644 tcpdump/jni/tcpdump/print-nflog.c create mode 100644 tcpdump/jni/tcpdump/print-nfs.c create mode 100644 tcpdump/jni/tcpdump/print-ntp.c create mode 100644 tcpdump/jni/tcpdump/print-null.c create mode 100644 tcpdump/jni/tcpdump/print-olsr.c create mode 100644 tcpdump/jni/tcpdump/print-openflow-1.0.c create mode 100644 tcpdump/jni/tcpdump/print-openflow.c create mode 100644 tcpdump/jni/tcpdump/print-ospf.c create mode 100644 tcpdump/jni/tcpdump/print-ospf6.c create mode 100644 tcpdump/jni/tcpdump/print-otv.c create mode 100644 tcpdump/jni/tcpdump/print-pflog.c create mode 100644 tcpdump/jni/tcpdump/print-pgm.c create mode 100644 tcpdump/jni/tcpdump/print-pim.c create mode 100644 tcpdump/jni/tcpdump/print-pktap.c create mode 100644 tcpdump/jni/tcpdump/print-ppi.c create mode 100644 tcpdump/jni/tcpdump/print-ppp.c create mode 100644 tcpdump/jni/tcpdump/print-pppoe.c create mode 100644 tcpdump/jni/tcpdump/print-pptp.c create mode 100644 tcpdump/jni/tcpdump/print-radius.c create mode 100644 tcpdump/jni/tcpdump/print-raw.c create mode 100644 tcpdump/jni/tcpdump/print-rip.c create mode 100644 tcpdump/jni/tcpdump/print-ripng.c create mode 100644 tcpdump/jni/tcpdump/print-rpki-rtr.c create mode 100644 tcpdump/jni/tcpdump/print-rrcp.c create mode 100644 tcpdump/jni/tcpdump/print-rsvp.c create mode 100644 tcpdump/jni/tcpdump/print-rt6.c create mode 100644 tcpdump/jni/tcpdump/print-rtsp.c create mode 100644 tcpdump/jni/tcpdump/print-rx.c create mode 100644 tcpdump/jni/tcpdump/print-sctp.c create mode 100644 tcpdump/jni/tcpdump/print-sflow.c create mode 100644 tcpdump/jni/tcpdump/print-sip.c create mode 100644 tcpdump/jni/tcpdump/print-sl.c create mode 100644 tcpdump/jni/tcpdump/print-sll.c create mode 100644 tcpdump/jni/tcpdump/print-slow.c create mode 100644 tcpdump/jni/tcpdump/print-smb.c create mode 100644 tcpdump/jni/tcpdump/print-smtp.c create mode 100644 tcpdump/jni/tcpdump/print-snmp.c create mode 100644 tcpdump/jni/tcpdump/print-stp.c create mode 100644 tcpdump/jni/tcpdump/print-sunatm.c create mode 100644 tcpdump/jni/tcpdump/print-sunrpc.c create mode 100644 tcpdump/jni/tcpdump/print-symantec.c create mode 100644 tcpdump/jni/tcpdump/print-syslog.c create mode 100644 tcpdump/jni/tcpdump/print-tcp.c create mode 100644 tcpdump/jni/tcpdump/print-telnet.c create mode 100644 tcpdump/jni/tcpdump/print-tftp.c create mode 100644 tcpdump/jni/tcpdump/print-timed.c create mode 100644 tcpdump/jni/tcpdump/print-tipc.c create mode 100644 tcpdump/jni/tcpdump/print-token.c create mode 100644 tcpdump/jni/tcpdump/print-udld.c create mode 100644 tcpdump/jni/tcpdump/print-udp.c create mode 100644 tcpdump/jni/tcpdump/print-usb.c create mode 100644 tcpdump/jni/tcpdump/print-vjc.c create mode 100644 tcpdump/jni/tcpdump/print-vqp.c create mode 100644 tcpdump/jni/tcpdump/print-vrrp.c create mode 100644 tcpdump/jni/tcpdump/print-vtp.c create mode 100644 tcpdump/jni/tcpdump/print-vxlan.c create mode 100644 tcpdump/jni/tcpdump/print-wb.c create mode 100644 tcpdump/jni/tcpdump/print-zephyr.c create mode 100644 tcpdump/jni/tcpdump/print-zeromq.c create mode 100644 tcpdump/jni/tcpdump/route6d.h create mode 100644 tcpdump/jni/tcpdump/rpc_auth.h create mode 100644 tcpdump/jni/tcpdump/rpc_msg.h create mode 100644 tcpdump/jni/tcpdump/rpl.h create mode 100644 tcpdump/jni/tcpdump/rx.h create mode 100644 tcpdump/jni/tcpdump/sctpConstants.h create mode 100644 tcpdump/jni/tcpdump/sctpHeader.h create mode 100644 tcpdump/jni/tcpdump/send-ack.awk create mode 100644 tcpdump/jni/tcpdump/setsignal.c create mode 100644 tcpdump/jni/tcpdump/setsignal.h create mode 100644 tcpdump/jni/tcpdump/signature.c create mode 100644 tcpdump/jni/tcpdump/signature.h create mode 100644 tcpdump/jni/tcpdump/slcompress.h create mode 100644 tcpdump/jni/tcpdump/slip.h create mode 100644 tcpdump/jni/tcpdump/sll.h create mode 100644 tcpdump/jni/tcpdump/smb.h create mode 100644 tcpdump/jni/tcpdump/smbutil.c create mode 100644 tcpdump/jni/tcpdump/stime.awk create mode 100644 tcpdump/jni/tcpdump/strcasecmp.c create mode 100644 tcpdump/jni/tcpdump/tcp.h create mode 100644 tcpdump/jni/tcpdump/tcpdump-stdinc.h create mode 100644 tcpdump/jni/tcpdump/tcpdump.1.in create mode 100644 tcpdump/jni/tcpdump/tcpdump.c create mode 100644 tcpdump/jni/tcpdump/telnet.h create mode 100644 tcpdump/jni/tcpdump/tftp.h create mode 100644 tcpdump/jni/tcpdump/timed.h create mode 100644 tcpdump/jni/tcpdump/token.h create mode 100644 tcpdump/jni/tcpdump/udp.h create mode 100644 tcpdump/jni/tcpdump/util.c create mode 100644 tcpdump/jni/tcpdump/version.c create mode 100644 tcpdump/jni/tcpdump/vfprintf.c create mode 100644 tcpdump/jni/tcpdump/win32/Include/bittypes.h create mode 100644 tcpdump/jni/tcpdump/win32/Include/errno.h create mode 100644 tcpdump/jni/tcpdump/win32/Include/getopt.h create mode 100644 tcpdump/jni/tcpdump/win32/Include/w32_fzs.h create mode 100644 tcpdump/jni/tcpdump/win32/Src/getopt.c create mode 100644 tcpdump/jni/tcpdump/win32/prj/GNUmakefile create mode 100644 tcpdump/jni/tcpdump/win32/prj/WinDump.dsp create mode 100644 tcpdump/jni/tcpdump/win32/prj/WinDump.dsw create mode 100644 tcpdump/jni/tcpdump/win32/prj/WinDump.sln create mode 100644 tcpdump/jni/tcpdump/win32/prj/WinDump.vcproj create mode 100644 tcpdump/jni/tcpdump/win32/src/ether_ntohost.c create mode 100644 tcpdump/src/main/AndroidManifest.xml create mode 100644 webserver/build.gradle create mode 100644 webserver/jni/Android.mk create mode 100644 webserver/jni/Application.mk create mode 100644 webserver/jni/mongoose/LICENSE create mode 100644 webserver/jni/mongoose/README.md create mode 100644 webserver/jni/mongoose/mongoose.c create mode 100644 webserver/jni/mongoose/mongoose.h create mode 100644 webserver/jni/stub.c create mode 100644 webserver/jni/webserver.c create mode 100644 webserver/src/main/AndroidManifest.xml diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a6ea871 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,950 @@ +# Changelog + +## [6.1.4] - 2024-10-27 + +- Renew web server TLS certificate +- Update Android gradle plugin + +Special thanks to masudscloud for its bug report. + +## [6.1.3] - 2024-07-06 + +- Fix mongoose web server +- Update translations + +Special thanks to mbangi for its bug report. + +## [6.1.2] - 2024-06-17 + +- Fix VPN restart on network interface change +- Fix crash when update is instantly download +- Update mongoose web server +- Update third party libraries +- Update Android gradle plugin +- Update translations + +Special thanks to @Fs00 and @gallegonovato for their bug reports. + +## [6.1.1] - 2023-06-20 + +- Improve adaptive launcher icon +- Update AndroidX libraries +- Update third party libraries +- Update libsu +- Update mongoose web server +- Update Android gradle plugin +- Update build tools +- Update translations + +Special thanks to AzusaHana for its contribution. + +## [6.1.0] - 2023-03-26 + +- Add adaptive launcher icon +- Add POST_NOTIFCATIONS runtime permission support +- Improve settings UI +- Update target SDK to Android 13 +- Update libsu +- Update mongoose web server +- Update AndroidX libraries +- Update third party libraries +- Update Android gradle plugin +- Update NDK + +## [6.0.3] - 2022-07-25 + +- Improve hosts source cache to reduce bandwidth usage +- Improve GitHub API usage to reduce bandwidth usage +- Update AndroidX libraries +- Update translations + +Special thanks to yoshimo for its bug report. + +## [6.0.2] - 2022-06-16 + +*This version is a pre-release* + +- Fix wizard ad-block method check +- Update translations + +Special thanks to Dandu32, ipdev and zhmstar0310 for their bug reports. + +## [6.0.1] - 2022-06-03 + +*This version is a pre-release* + +- Improve screen rotation handling on home screen +- Update libsu +- Update mongoose web server +- Update Android gradle plugin +- Update third party libraries +- Update translations + +Special thanks to kubalav and zgfg for their bug reports. + +## [6.0.0] - 2022-05-18 + +*This version is a pre-release* + +- Add a new VPN ad-blocker implementation +- Add initial DOH (DNS Over HTTPS) support +- Add VPN connection monitor, heartbeat and throttler to improve reliability +- Add long press action to copy hostname from user lists and DNS log to clipboard +- Fix VPN state on network connectivity change and lost +- Fix VPN restart when system kills it +- Fix wrong DNS read on VPN restart +- Fix VPN unwanted restart while paused +- Fix crash on application update unknown size +- Improve VPN user control reliability +- Update logging system +- Update libsu +- Update Android gradle plugin +- Update AndroidX libraries +- Update NDK +- Update third party libraries + +## [5.12.1] - 2022-05-14 + +- Fix hosts file install on Android 13 + +Special thanks to AAGaming00 and KieronQuinn for their bug reports. + +## [5.12.0] - 2022-02-28 + +- Implement key-value pairs backup service support +- Improve VPN application exclusion UI +- Update AndroidX libraries +- Update mongoose web server +- Update translations +- Update gradle +- Update build tools + +## [5.11.0] - 2021-12-20 + +- Improve home screen with icon color and decoration +- Improve settings UI elements +- Improve search filter performance in hosts list +- Improve resource clean up after parsing hosts source +- Improve logs with Timber +- Improve button descriptions +- Update Android gradle plugin +- Update AndroidX libraries +- Update third party libraries +- Update mongoose web server +- Update translations + +Special thanks to brijrajparmar27 for its contribution. + +## [5.10.0] - 2021-12-01 + +- Fix connectivity change detection in VPN mode +- Update mongoose web server +- Update target SDK to Android 12 +- Update dependencies +- Update translations + +Special thanks to 8asuj6m2 for its contribution. + +## [5.9.0] - 2021-11-05 + +- Improve update activity to add support links and open from notification +- Update web server certificate to comply with maximum validity time +- Update dependencies +- Update Android gradle plugin +- Update NDK + +Special thanks to rany2 for its bug report. + +## [5.8.0] - 2021-08-08 + +- Improve command receiver for task automation +- Update mongoose web server +- Update dependencies +- Update Android gradle plugin +- Update translations + +Special thanks to Faedelity for its bug report. + +## [5.7.0] - 2021-06-27 + +- Add quick settings tile to toggle ad-blocking +- Fix crash on TLS and timeout issue during source update +- Fix backup not listed for restoration on older devices +- Update dependencies +- Update translations + +Special thanks to gwolf2u, opusforlife2, Vstory for their bug reports. + +## [5.6.0] - 2021-04-30 + +- Improve navigation by moving DNS logs to home screen +- Improve DNS logs usage by explaining usage and limitation +- Update dependencies +- Update translations + +## [5.5.1] - 2021-04-02 + +- Add redirection validation +- Improve application update screen +- Update Android gradle plugin +- Update NDK +- Update dependencies +- Fix VPN crash when the only system DNS server available uses IPv6 and IPv6 is disabled from settings +- Remove html-textview dependency and jcenter repository + +Special thanks to FrostbiterTy, SapphireExile, zgfg for their bug reports. + +## [5.5.0] - 2021-03-17 + +- Add allow list support +- Improve source edition UI +- Improve source update check +- Improve animations +- Update mongoose web server +- Update dependencies +- Fix web server TLS issue + +Special thanks to gallegonovato, jawz101 and zgfg for their bug reports. + +## [5.4.0] - 2021-02-28 + +- Add VPN monitor option to prevent disconnection +- Update source update status indicator +- Update Android gradle plugin +- Update Sentry DSN to support older TLS versions +- Update mongoose web server +- Update dependencies +- Fix welcome screen telemetry preference +- Fix VPN authorization check at startup + +Special thanks to BearTM, elvissteinjr, ipdev99, patkarmandar, RobBeyer for their bug reports. + +## [5.3.0] - 2021-01-17 + +- Add new unique source parser with parallel processing +- Add an option to disable app update check at startup +- Fix crash with source file when SAF permission is removed +- Fix metered status vpn on Android 11 + +Special thanks to andy356, fusionneur and sr1canskhsia for their bug reports. + +## [5.2.1] - 2021-01-06 + +- Fix F-Droid store detection + +Special thanks to TheLonelyGhost, bdtipsntricks, faraz-b bege10, Nathan-Nesbitt and gallegonovato for their bug reports. + +## [5.2.0] - 2021-01-03 + +- Add beta channel opt-in preferences +- Update mongoose to latest stable version and rewrite web server +- Update source parser to prevent stack overflow +- Update dependencies +- Update build tools +- Update NDK +- Update translations + +## [5.1.0] - 2020-11-12 + +- Add application update UI +- Add F-Droid apk support to built-in updater +- Add custom hosts file parser for big hosts file (1M+ entries, way slower but memory friendly) +- Fix VPN app exclusion on Android 11 +- Update AndroidX and Sentry dependencies +- Update translations + +Special thanks to spiou, drothenberger and gallegonovato for their bug reports. + +## [5.0.10] - 2020-10-10 + +*This version is a pre-release* + +- Fix online modification date for unavailable source +- Prevent missing url at source creation +- Prevent invalid source url to be restored +- Fix web server certificate install on Android 11 + +Special thanks to zgfg, ipdev99 and ingenium13 for their bug reports. + +## [5.0.9] - 2020-09-13 + +*This version is a pre-release* + +- Fix no hosts to block from 4.x to 5.x migration +- Fix wrong source type in source edition UI +- Update AndroidX dependencies +- Update mongoose web server + +Special thanks to auanasgheps, lukjod, ridobe, sacrificialpawn for their bug reports. + +## [5.0.8] - 2020-08-30 + +*This version is a pre-release* + +- Fix source not updated on automatic update +- Fix user list not sync until source update +- Update hosts source creation to disable allowed hosts by default +- Update AndroidX dependencies + +Special thanks to jeanrivera for its bug report. + +## [5.0.7] - 2020-08-16 + +*This version is a pre-release* + +- Add hosts sources Storage Access Framework support +- Add hosts sources label and host counter +- Improve host sources list and edition UI +- Improve allowed and redirected hosts settings by applying them per source +- Fix file based hosts sources not installed due to missing permission +- Update AndroidX dependencies + +Special thanks to zgfg for its bug report. + +## [5.0.6] - 2020-08-02 + +*This version is a pre-release* + +- Fix crash on domain enable/disable action +- Fix source not applied if disabled and enabled back +- Update target SDK to Android 11 + +Special thanks to ipdev99 and zgfg for their bug reports. + +## [5.0.5] - 2020-06-28 + +*This version is a pre-release* + +- Improve hosts source server handling with future time +- Improve hosts update by skipping already up-to-date sources +- Fix hosts source disable action +- Fix hosts list apply notification from non-user changes +- Fix user excluded application settings +- Remove navigation bar color customization +- Update AndroidX dependencies and NDK version + +Special thanks to CobalTitan, ipdev99, zgfg and sunmybun for their bug reports. + +## [4.3.5] - 2020-06-27 + +- Fix project Fastlane description for F-Droid store + +Special thanks to linsui and IzzySoft for their bug reports and Vankog for translations. + +## [5.0.4] - 2020-05-24 + +*This version is a pre-release* + +- Improve overall host list computation +- Add host redirected feature in VPN ad blocking +- Remove WRITE_EXTERNAL_STORAGE permission (use Storage Access Framework instead) +- Fix duplicate entries in generated hosts file +- Fix allowed hosts settings in VPN ad blocking +- Fix backup not exported as sdcard not writable +- Fix source update period task preference +- Fix host list paging + +Special thanks to holysnipz, ipdev99, QingKongBaiYu, and zgfg for their bug reports. + +## [5.0.3] - 2020-05-10 + +*This version is a pre-release* + +- Add TLS support for web server +- Add web server status in preferences +- Add option to install self signed certificate +- Add option to display app icon instead of blank page +- Add full timezone support for source date +- Add workaround for negative source update time when server time is not accurate +- Add follow system dark theme mode +- Fix user host list lost on source update +- Fix import failed toast +- Fix web server not start on install +- Fix duplicate host entry on backup import +- Update mongoose server +- Update translations + +Special thanks to saltylemondrops, zgfg, ipdev99 and mickrussom for their bug reports. + +## [5.0.2] - 2020-04-25 + +*This version is a pre-release* + +- Fix timezone issues with source modification date +- Fix domain not removed when sources are disabled +- Fix inverted host and ip while generating hosts file +- Fix periodical hosts update check initialization +- Improve overall search feature in list UI +- Improve last online modification date after retrieval +- Fix install snackbar not hiding +- Fix potential deadlock in VPN +- Add missing text on successful VPN update +- Update translations + +Special thanks to damoasda for its contribution, Vankog for all translations he merged and Ps24u and dhacke for theirs bug reports. + +## [4.3.4] - 2020-04-25 + +- Fix crash in tcpdump log view on Lollipop +- Fix timezone issues with source modification date +- Fix NDK version + +Special thanks to Ps24u and Indranil012 for their bug reports. + +## [5.0.1] - 2020-04-15 + +*This version is a pre-release* + +- Fix redirect label from home screen +- Fix preference screen duplication on screen orientation change +- Improve hosts list readability +- Update dependencies +- Fix ndk configuration + +Special thanks to TacoTheDank for its contribution and rmw98 and Luniz2k1 for its bug reports. + +## [4.3.3] - 2020-04-10 + +hpHosts service is down. +If you are looking for a replacement, give a try at [StevenBlack's one](https://github.com/StevenBlack/hosts). + +- Replace hpHosts default hosts file by StevenBlack hosts file +- Improve tcpdump icons +- Update translations + +Special thanks to damoasda its contribution and gallegonovato for its bug report. + +## [5.0.0] - 2020-04-07 + +*This version is a pre-release* + +- Add new home screen + - Provides all main controls from one screen + - Displays currently blocked, allowed and redirected domains + - Displays current hosts sources status and control to force apply +- Add non root ad-blocking feature + - Uses a builtin local VPN to filter DNS request to blocked domains + - Based on the work of [dns66 by julian-klode](https://github.com/julian-klode/dns66/issues/39) + - Allows to excluded system applications and per user applications +- Add builtin updater with changelog display +- Add feature to quickly pause and resume ad-blocking +- Add wizard screen for first run setup +- Add feature to display and filter all blocked, allowed, redirect domains +- Improve preferences screen +- Add broadcast receiver to control ad-blocking from third party applications +- Update Android target to Android 10 +- Improve root and shell support +- Split translation files to easier understand their context +- Add GitHub action test and build tasks + +## [4.3.2] - 2019-12-29 + +- Fix GitLab source hosting +- Update translations + +## [4.3.1] - 2019-12-21 + +- Update help to include Magisk systemless module for read-only system partition +- Update translations + +## [4.3.0] - 2019-11-01 + +- Fix root not requested +- Improve support for systemless hosts Magisk module +- Update translations + +## [4.2.9] - 2019-08-31 + +- Improve hosts file parsing +- Improve hosts file install error message (add more details than _not enough space_) +- Fix menu drawer translation issue +- Update translations +- Remove the start (opt-in only) telemetry messages + +## [4.2.8] - 2019-07-28 + +- Fix TravisCI build issues +- Update translations + +## [4.2.7] - 2019-07-04 + +- Revert Android gradle plugin to fix F-Droid build issue + +## [4.2.6] - 2019-06-23 + +- Improve backup feature (user lists and hosts source using JSON format) +- Fix F-Droid build issue +- Update translations + +Special thanks to RichyHBM its contribution and andy356 for its bug report. + +## [4.2.5] - 2019-06-06 + +- Add Gist and GitLab hosting support for hosts file +- Add option to set default IPv6 redirection +- Improve reboot command +- Improve UI for overlays +- Update translations + +Special thanks to MSF-Jarvis and Ralayax for their contributions + +## [4.2.4] - 2019-03-23 + +- Add dedicated no root error message +- Fix connection requirement for automatic update +- Fix crash on TCP dump views when root access is denied +- Fix icon resources and colors +- Improve exception reporting +- Update translations +- Update Android X dependencies +- Update Android Gradle plugin and NDK versions + +## [4.2.3] - 2019-03-02 + +- Fix update check on disabled sources +- Fix cropped label on home screen +- Prevent app installation on external storage (can't launch tcpdump or web server binary) +- Update work manager and material dependencies + +## [4.2.2] - 2019-02-16 + +- Improve Material Theming +- Update build tools + +## [4.2.1] - 2019-02-03 + +- Fix two buttons line when text too long + +## [4.2.0] - 2019-02-02 + +- Add hosts source download cache +- Add snackbar notification to update host from DNS request listing +- Update UI from Material Design to Material Theming +- Update gradle, plugins and dependencies +- Fix crash parsing not defined host source last modified date +- Fix native modules build script (required for F-Droid build server) +- Fix Transifex issues + +## [4.1.0] - 2018-12-13 + +- Add [telemetry feature](https://github.com/AdAway/AdAway/wiki/Telemetry) +- Add snackbar notification to update host when editing hosts sources or lists +- Update translations and fix english locale issues + +## [4.0.12] - 2018-11-21 + +- Fix issue when getting last modified date on file:// hosts source +- Fix excluded hostnames from source due to parser failure + +Special thanks to DiamondJohn and Vankog for theirs helpful bug reports. + +## [4.0.11] - 2018.11.06 + +- Update translations from Transifex +- Fix crash using file:// protocol for hosts source +- Fix redirect list import + +Special thanks to ipdev, ktmom and shaqman89 for theirs helpful bug reports and Vankog for the locales update. + +## [4.0.10] - 2018.10.14 + +- Last update time now works with GitHub hosted files (on https://raw.githubusercontent.com/ domain) +- Fix infinite "update available" status when at least one host source failed to download +- Fix hosts not installed by the background update service +- Fix hosts source update time when reverting to default hosts file +- Fix "download failed" status when no host source enabled +- Fix a bunch of translation issues + +Special thanks to Alain-Olivier and Vankog for theirs contributions and MarcAnt01 for its helpful bug report. + +## [4.0.9] - 2018.09.26 + +- Fix missing reboot and error dialog when installing and checking for hosts update +- Block http hosts source for security +- Add project and support links to the menu +- Fix missing notification channel for Oreo and later +- Fix host name validation to add more complex domain name in black/white lists +- Improve HTTP client connection pool +- Add new internal architecture for hosts installation +- Fix Indonesian locale code +- Clean up a lot a unused resource (texts and graphics) +- Clean up help from unrelated help elements +- Update gradle itself, plugin, ndk and dependencies versions + +Special thanks to adem4ik TacoTheDank and @Vankog for theirs contributions and towlie, ipdev for theirs helpful bug reports. + +## [4.0.8] - 2018.08.22 + +- Add option to dismiss welcome card +- Improve hosts update status +- Change background job dependency from Evernote Android Job to Jetpack Work manager +- Update translations + +## [4.0.7] - 2018.08.08 + +- Fix host lists import +- Fix default DNS requests when no log entry +- Update translations from Transifex + +Special thanks to Vankog for the translation update and GuardianUSMC and DiamondJohn for the bug reports. + +## [4.0.6] - 2018.08.05 + +- Add web server status (icon and text) in the home card UI +- Fix black and while list inversion bug + +## [4.0.5] - 2018.07.02 + +- Change database to room: + - Add migration from previous database +- Update hosts source UI: + - New animations + - Dialogs validate user data so you do no more loose your input if format is wrong +- New DNS logging UI: + - Add new sort feature: + - by name (old behavior) + - by top level domain name (group entries by DNS so google.com, ads.google.com and www.google.com appears next to each other) + - New controls and animations: + - Block, allow or redirect from the directly from DNS logs + - Currently set up domains (in your lists UI) will be displayed accordingly + - Swipe to refresh! +- Update build tools, target SDK (28) and dependencies + +## [4.0.4] - 2018.06.03 + +- A new light (white) theme +- A new adware UI (using LiveData and ViewModel for the 1st time!) +- A fix for the overlapping status texts in the home screen + +## [4.0.3] - 2018.05.20 + +- Fix tcpdump failed to start after being stopped + +## [4.0.2] - 2018.05.09 + +- Add adaptive launcher icons (8+) +- Add adaptive app shortcut (7.1+) +- Add new hosts content screen +- Fix application title not restored on configuration change +- Fix screen change when opening hosts file + +## [4.0.1] - 2018.05.07 + +- Fix redirection IP and custom target dialogs in preferences +- Fix multiple lines in home card hedear. + +## [4.0.0] - 2018.05.06 + +This version is a major update. +First, There is a new design: + +- The home is now card based (webserver card is added if enabled) +- The navigation menu is now an humbugger menu +- The hosts source UI is updated (floating add button, actionbar edition) +- Your lists UI is updated (bottom navigation bar, same controls add, edit, remove like hosts sources) +- Permission request at runtime to access storage to import or export your list +- All other views are updated to use the latest support libraries + +And a lot of changes under the hood including: + +- Oreo support +- Battery improvement and host update fix +- Better support of root and systemless mode + +## [3.3] - 2018.03.05 +- Add support for ChainFire's SuperSU "bind sbin" systemless mode - by PerfectSlayer +- Improve systemless activation error handling - by PerfectSlayer +- Improve su location detection - by tstaylor7 +- Update Mongoose webserver - by MrRobinson +- Replace CyanogenMod references by LineageOS - by experience7 +- Update translations - by Mattter, mission712, ThomasSmallert and muzena +- Fix translation attributes - by Vankog +- Fix Magisk 15.x support - by pec0ra + +## [3.2] +- Systemless root support - extensive work by PerfectSlayer +- Improvements to root mounter - by sanjay900 +- Translations updates +- Various updates for support on Android 7.x + +## [3.1.2] +- Update hosts-file.net source to use https +- Translations updates + +## [3.1.1] +- Minor bugfixes +- Update mongoose internal webserver to 6.4 release +- Translations updates +- Update pgl.yoyo.org default source to use https +- Add generated timestamp into header of hosts file + +## [3.1] +- Add 64bit arch which allows tcpdump to run on those devices +- Adjust scan adware list and stop it from crashing +- Update libpcap to 1.7.4 release +- Update tcpdump to 4.7.4 release +- Update mongoose internal webserver to 6.0 release and add IPv6 support +- Add enable IPv6 option which adds ::1 to all hosts entries +- Improve building hosts file speed by up to 2.5x +- RevertService uses Target hosts file preference +- Updates to support Android 6.0 SDK (23) + +## [3.0.2] +- Disable autocorrect/autocomplete for hosts input on whilelist and redirection inputs +- Allow two pane layout as long as min of 600dp width available regardless of orientation +- Add material colored status icons +- Adjust asset layout per latest development guidelines +- Minor other adjustments + +## [3.0.1] +- Make some text fields single line - by Phoenix09 +- Make daily update time randomized within a range +- Minor fixes +- Adjust hosts-file.net default source URL + +## [3.0] +This release has mainly been done by 0-kaladin. + +- Min Android version increased to Android 4.1 to support Position Independent Executables (PIE) +- Material design + +## [2.9.2] +This release has mainly been done by DÄvis MoÅ¡enkovs. + +- Added Trove library for high performance collections +- Adware scan improvements +- Separate whitelisting and redirections options - "Allow whitelisting" defaults to checked; "Allow redirections" defaults to state of "Allow redirections and whitelisting" (or unchecked on new installations) +- Fix tcpdump logging upon file deletion +- Fix possible crash on DB update +- Fix AdAway's default hosts source + +## [2.9.1] +- Fixing regression bugs + +## [2.9] +This release has mainly been done by DÄvis MoÅ¡enkovs, thanks! + +- Workaround for Android 4.4 (see Help) +- Fixed Hide reboot dialog setting being ignored after symlink creation +- Fix crashes +- Change AdAway's default hosts source to https + +## [2.8.1] +- Fix mobile hosts source + +## [2.8] +- Higher timeout for root commands +- New version of RootCommands library (If you experience problems install busybox, AdAway will then use it!) +- Remove unused billing permission + +## [2.7] +- Reduce apk size by switching from HtmlSpanner to HtmlTextView library + +## [2.6] +- Improve build for F-Droid + +## [2.5] +- Fix URLs in-app + +## [2.4] +- Fix Remounter for Android 4.3 +- Fix auto update on ethernet connection + +## [2.3] +- AdAway was removed from Google Play! +- Because http://www.ismeh.com/HOSTS is down, a alternative source has been added + +## [2.2] +- Introduce SUPERUSER permission for new Superuser app +- Allow backups of AdAway (for Carbon) +- Logo reworked thanks to Alin Å¢oÅ£ea-Radu + +## [2.1] +- Allow whitelist entries from hosts sources if enabled in preferences +- Fixed missing menu entry for hosts sources on tablets +- Webserver on boot should work more reliable +- Webserver should not be killed on low memory + +## [2.0] +IF YOU HAVE PROBLEMS WITH 2.0: Please uninstall and then reinstall AdAway! +- New library for root access: RootCommands +- Tcpdump and Webserver now included for ARM, x86, MIPS (Please test and report problems!) +- Google forced me to remove the possibility to donate via Flattr and PayPal +- Hopefully fixes DNS logging for Android 4.1 + +## [1.37] +- Skip unreachable hosts sources and show number of successful sources +- Fix for crash on donations screen (Android 4.1) +- Fix crash on help screen (Android 4.1) +- Bind local webserver https only to localhost (thanks to Stebalien for finding that bug) + +## [1.36] +- Help and About screens reworked +- Simple scanner for bad Adware apps like Airpush Notifications (derived from open source Airpush-Detector, thanks!) + +## [1.35] +- New method for background update checking +- AdAway will now reschedule the update check to execute it when the Internet connection is established +- New preference to update only when on Wifi +- AdAway now allows empty hosts sources for people who only want to maintain their own lists + +## [1.34] +- In-app PayPal donations are now possible +- Disabled hardware acceleration on ICS, caused black screens and glitches on some custom roms + +## [1.33] +- Fixed rare problems on some devices regarding remounting /system as read/write + +## [1.32] +- Fixes crashes with 1.31 + +## [1.31] +- Check for APN proxy + +## [1.30] +- Design improvements for Android 4 +- Layout fixes for "Your Lists" + +## [1.29] +- Languages updated +- Fixed copying when no cp command is available + +## [1.28] +- Now works on devices without cp command +- New debug setting + +## [1.27] +- No longer needs busybox +- Fixed problems with reverting +- Method to restart Android changed + +## [1.26] +- Usability improvements: Buttons will now be disabled while applying, reverting is improved +- Faster due to improved hosts parsing +- Now including tcpdump + +## [1.25] +- Better tcpdump integration +- Wildcard characters * and ? can be used in your whitelist +- Updated translations +- Fixes stuck on applying hopefully + +## [1.24] +- Tcpdump DNS request logging +- Preference to allow redirection rules from Hosts Sources +- New hosts source for mobile ads: http://www.ismeh.com/HOSTS +- Webserver binary now updates correctly from old AdAway versions + +## [1.23] +- Fix for import/export + +## [1.22] +- More notification and status bug fixes +- Fixed preference bug causing automatic update to be enabled +- Fixed color of notifications +- Fixed a crash under Android 3.2 + +## [1.21] +- Fixed staying notification when update was failing +- Hopefully fixes webserver crashes + +## [1.20] +- Fixed staying notification + +## [1.19] +- Automatic updating in background can be enabled in preferences +- New method for checking for symlink, should fix some problems +- Fixes for exporting entries +- Fixes for donation screen, when no Google Android Market is available + +## [1.18] +- Local webserver now answers with blank page instead of 404 error page +- Import and Export of Your Lists +- Bug fix for symlink check +- Last entry in hosts file is now working (missed new line at end of hosts file) +- Fixes for daily update check +- Allow hostnames without TLD ending + +## [1.17] +- Fix for translation problems + +## [1.16] +- Translations: German, French, Spanish + Thanks to all contributors! +- Better check for symlink +- Newer version of web server mongoose +- Better handling of AdAway database +- Fixed "Not enough space available" bug +- Fixed problem with applying + +## [1.15] +- Added permission for Google Android Market donations + +## [1.14] +- Force close on open hosts file fixed +- Donations with Google Android Market added + +## [1.13] +- Webserver now hears on all local IP address (0.0.0.0) +- Custom target can be set in preferences, for example to /data/etc/hosts +- Hosts file can be opened from menu + +## [1.12] +- Delayed starting of webserver on boot +- Disabled debug logging + +## [1.11] +- Fixed bugs in layout + +## [1.10] +- Webserver is now a preference, disabled by default +- Fixed daily update again. Should schedule now correctly +- Fixed crash on Android 3.0 and 3.1 in Your Lists +- Fixed preferences on Android 3.x +- Fixed rotation bug on Android 3.x + +## [1.09] +- New design for tablet sizes +- New hosts source: http://pgl.yoyo.org/adservers +- fixed crash on Android 3 Honeycomb +- Fix for daily update check +- Removed hosts source sysctl.org because of false positives + +## [1.08] +- AdAway got a redesign +- AdAway ships with a webserver, that listens on localhost +- Dates of all hosts sources are saved and can be seen in Hosts sources +- Preference to hide reboot question dialog +- Help page with information about AdAway +- Added new hosts source sysctl.org +- Daily update check can be enabled in preferences +- Should now work on roms which doesn't symlink busybox commands + +## [1.07] +- AdAway can now create a symlink +- better error handling +- No update check on orientation change + +## [1.06] +- hosts file target can be choosen +- Donation button +- Fixed SQLite bug occuring on Android 2.1 + +## [1.05] +- Update Check implemented +- Fixed bug when changing orientation of device while downloading +- better error handling when downloading +- Fixed localhost entry again + +## [1.04] +- Implemented Redirection List +- Fixed Layout bugs + +## [1.03] +- Implemented Blacklist and Whitelist + +## [1.02] +- Fixed localhost entry + +## [1.01] +- Fixed permissions on /system/etc/hosts diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d8f6545 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at report [at] adaway.org. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e8d2c90 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,169 @@ +# Contributing to AdAway + +:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: + +The following is a set of guidelines for contributing to AdAway. +These are mostly guidelines, not rules. +It will help you to understand the project, find answers, deal with the source code and interact with maitainers. +The project is open to any kind of contribution so feel free to share your ideas and participate to the development. + +#### Table of contents + +[I don't want to read this whole thing, I just have a question!!!](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question) + +[What should I know before I get started?](#what-should-i-know-before-i-get-started) +* [Discovering the project structure](#discovering-the-project-structure) +* [Building the project](#building-the-project) + +[How can I contribute?](#how-can-i-contribute) +* [Reporting bugs](#reporting-bugs) +* [Suggesting enhancements](#suggesting-enhancements) +* [Translating to your language](#translating-to-your-language) +* [Your first code contribution](#your-first-code-contribution) + +[Styleguides](#styleguides) +* [Git commit messages](#git-commit-messages) +* [Java styleguide](#java-styleguide) +* [XML styleguide](#xml-styleguide) + +[Additional notes](#additional-notes) +* [tcpdump and webserver modules](#tcpdump-and-webserver-modules) + +## I don't want to read this whole thing I just have a question!!! + +> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below. + +We have a dedicated forum with a welcoming community and a wiki to answer your questions: + +* [Check the common issues and solutions on the wiki](https://github.com/AdAway/AdAway/wiki/Solutions) +* [Read and post on the dedicated developer forum](https://forum.xda-developers.com/showthread.php?t=2190753) + +## What should I know before I get started? + +### Discovering the project structure + +The AdAway source code is an Android project organized in modules. +There are four main modules: +* `app`: The Android application itself +* `tcpdump`: A module dedicated to build the `pcap` library and the `tcpdump` binary +* `webserver`: A module dedicated to build a simple HTTP server binary based on `mongoose` +* `libraries/RootCommands`: A vendorize Android library to run root shell commands + +The three last modules are independent and used by the `app` module. +Modularizing the application allows for faster build times and simplier maintainance. + +### Building the project + +Building the project will require the latest versions of the Android SDK (Software Development Kit) and NDK (Native Development kit). +They can easily be installed or updated using [Android Studio](https://developer.android.com/studio/). + +#### Building with Gradle +1. Ensure you have Android SDK and NDK installed. +If not: + * Option 1: [Install Android Studio](https://developer.android.com/studio/index.html) or, + * Option 2: Install command line tools, build tools and ndk bundle with sdk manager: + `tools/bin/sdkmanager "build-tools;x.y.z" ndk-bundle` where `x.y.z` is the latest version +2. Export `ANDROID_HOME` environment variable pointing to your Android SDK: +`export ANDROID_HOME=/path/to/your/sdk` +3. Launch a build: +`./gradlew assembleRelease` + +The first full build of the apk can take a lot of time, about 20 minutes, whereas an incremental build of the `app` module takes less than a dozen seconds. + +#### Running on an emulator + +In order to test the application on an emulator, disable [the root check in the Constants source file](https://github.com/AdAway/AdAway/blob/c90336cb9b062220540317bc6c7cfedb19927c63/app/src/main/java/org/adaway/util/Constants.java#L28). + +## How can I contribute? + +### Reporting bugs + +> **Note:** Before submitting a bug report, please use [the GitHub search on Issues page](https://github.com/AdAway/AdAway/issues) to check if there is already similar reports. + +#### How do I submit a (good) bug report? + +* **Use a clear and descriptive title** for the issue to identify the problem. +* **Describe the exact steps which reproduce the problem** in the most detailed way possible. +* **Provide specific examples to demonstrate the steps**. +Include hosts sources or domains you use, web pages URL you test. +* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. +* **Explain which behavior you expected to see instead and why.** +* **If you're reporting that AdAway crashed**, include a logcat. +Use `adb logcat` if you have developer settings enabled on your device or use any application like [CatLog](https://play.google.com/store/apps/details?id=com.nolanlawson.logcat) to save logs. +Include the crash report in the issue in a [code block](https://help.github.com/articles/markdown-basics/#multiple-lines), a [file attachment](https://help.github.com/articles/file-attachments-on-issues-and-pull-requests/), or put it in a [gist](https://gist.github.com/) and provide link to it. +* **Specify which version of AdAway you're using.** +You can get the exact version by opening in-app help and checking the _About_ tab. +* **Specify the Android version and the ROM you're using.** +You can also include any root or customization related information like _Magisk_ or _SuperSU_ version and _Xposed_ modules is installed. + + +### Suggesting enhancements + +#### How do I submit a (good) enhancement suggestion? + +Enhancement suggestions are welcome. +After refining your idea or discussing it on the [development forum](https://forum.xda-developers.com/showthread.php?t=2190753), create an issue and provide the following information: + +* **Use a clear and descriptive title** for the issue to identify the suggestion. +* **Provide a step-by-step description of the suggested enhancement** in the most detailed way possible, including specific examples. +* **Describe the current behavior** and **explain which behavior you expected to see instead** and why. +* **Explain why this enhancement would be useful** to most users. + +### Translating to your language + +Translations are also welcome. +Moreover, they do not require a development environment, only a web browser. +So if you want to complete or edit your language support for the application, check [the translation guide](TRANSLATING.md). + +### Your first code contribution + +Unsure where to begin contributing? + You can start by looking through these `good first issue` and `help wanted` issues: + +* [Good first issues](https://github.com/AdAway/AdAway/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) - issues which should only require a few lines of code, and a test or two. +* [Help wanted issues](https://github.com/AdAway/AdAway/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) - issues which should be a bit more involved than `beginner` issues. + +Both issue lists are sorted by total number of comments. While not perfect, the number of comments is a reasonable way of determining the impact a given change will have. + +## Style guidelines + +### Git commit messages + +* Use the present tense ("Add feature" not "Added feature") +* Use the imperative mood ("Move cursor to..." not "Moves cursor to...") +* Limit the first line to 80 characters or less +* Reference issues and pull requests liberally after the first line + +### Java style guidelines +* Indentation: 4 spaces, no tabs +* Maximum line width for code and comments: 100 +* Opening braces don't go on their own line +* Field names: Non-public, non-static fields start with m. +* Acronyms are words: Treat acronyms as words in names, yielding !XmlHttpRequest, getUrl(), etc. + +See https://source.android.com/source/code-style.html + +### XML style guidelines +* No maximum line width +* Split multiple attributes each on a new line +* Indent using spaces with Indention size 4 + +## Additional notes + +### `tcpdump` and `webserver` modules + +#### Origin + +Forked from the following sources and slightly modified to compile: + +* dnsmasq: https://github.com/CyanogenMod/android_external_dnsmasq +* libpcap: https://github.com/the-tcpdump-group/libpcap/tree/libpcap-1.7.4 +* tcpdump: https://github.com/the-tcpdump-group/tcpdump/tree/tcpdump-4.7.4 + +#### Changes + +Please review the following commits for the changes made to the sources above in order for them to compile in this project: + +* Commit: https://github.com/AdAway/AdAway/commit/1f4ccb3cec3758757341ad90813506fc2a8fdf7b +* Commit: https://github.com/AdAway/AdAway/commit/289df896c0ac4f96bd862e8a5054f1011ec07cac +* Commit: https://github.com/AdAway/AdAway/commit/08da0745b0732b94221c0f5746160fef8126fd99 diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index 53c4640..65070b2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,119 @@ -# adaway +# ![AdAway logo](app/src/main/res/mipmap-mdpi/icon.png) AdAway -Android Ad Blocker \ No newline at end of file +[![Build Status](https://github.com/adaway/adaway/actions/workflows/android-ci.yml/badge.svg)](https://github.com/AdAway/AdAway/actions/workflows/android-ci.yml) +[![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=org.adaway&metric=security_rating)](https://sonarcloud.io/project/overview?id=org.adaway) +[![GitHub Downloads](https://img.shields.io/github/downloads/adaway/adaway/total?logo=github)](https://github.com/AdAway/AdAway/releases) +[![GitHub Sponsors](https://img.shields.io/github/sponsors/perfectslayer?logo=github)](https://github.com/sponsors/PerfectSlayer) +[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](/LICENSE.md) + +AdAway is an open source ad blocker for Android using the hosts file and local vpn. + +[Home screen](metadata/en-US/phoneScreenshots/screenshot1.png) +[Preferences screen](metadata/en-US/phoneScreenshots/screenshot2.png) +[Root based ad blocker screen](metadata/en-US/phoneScreenshots/screenshot3.png) +[Backup and restore screen](metadata/en-US/phoneScreenshots/screenshot4.png) +[Help screen](metadata/en-US/phoneScreenshots/screenshot5.png) + +For more information visit https://adaway.org + +## Installing + +There are two kinds of release: +* The preview builds: on the bleeding edge of development - for testers or adventurous +* The stable builds: ready for every day usage - for end users + +### Preview builds + +**Requirements:** Android 8 _Oreo_ or above + +For users with bugs, there may be preview builds available from the [XDA development thread](https://forum.xda-developers.com/showthread.php?t=2190753) and [AdAway official website](https://app.adaway.org/beta.apk). +It is recommended to try those builds to see if your issue is resolved before creating an issue. +The preview builds may contain bug fixes or new features for new android versions. + +[Get it on official AdAway website](https://app.adaway.org/beta.apk) +[Get it on XDA forum](https://forum.xda-developers.com/showthread.php?t=2190753) + +### Stable builds + +**Requirements:** +* Android Android 8 _Oreo_ or above + +After preview builds have been tested by the more technical or responsive community within the forums, we will then post the stable build to F-Droid. + +[Get it on official AdAway website](https://app.adaway.org/adaway.apk) +[Get it on F-Droid](https://f-droid.org/app/org.adaway) + +For devices older than Android 8 _Oreo_, use the version 4 of AdAway. + +## Get Host File Sources + +See the [Wiki](https://github.com/AdAway/AdAway/wiki), in particular the page [HostsSources](https://github.com/AdAway/AdAway/wiki/HostsSources) for an assorted list of sources you can use in AdAway. +Add the ones you like to the AdAway "Hosts sources" section. + +## Getting Help + +You can post [Issues](https://github.com/AdAway/AdAway/issues) here or obtain more detailed community support via the [XDA developer thread](http://forum.xda-developers.com/showthread.php?t=2190753). + +## Contributing + +You want to be involved in the project? Welcome onboard! +Check [the contributing guide](CONTRIBUTING.md) to learn how to report bugs, suggest features and make you first code contribution :+1: + +If you are looking for translating the application in your language, [the translating guide](TRANSLATING.md) is for you. + +## Project Status + +AdAway is actively developed by: +* Bruce Bujon ([@PerfectSlayer](https://github.com/PerfectSlayer)) - Developer +[PayPal](https://paypal.me/BruceBUJON) | [GitHub Sponsorship](https://github.com/sponsors/PerfectSlayer) +* Daniel Mönch ([@Vankog](https://github.com/Vankog)) - Translations +* Jawz101 ([@jawz101](https://github.com/jawz101)) - Hosts list +* Anxhelo Lushka ([@AnXh3L0](https://github.com/AnXh3L0)) - Web site + +We do not forget the past maintainers: +* DÄvis MoÅ¡enkovs ([@DavisNT](https://github.com/DavisNT)) - Developer +[Paypal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5GUHNXYE58RZS&lc=US&item_name=AdAway%20Donation&no_note=0&no_shipping=1) +* [@0-kaladin](https://github.com/0-kaladin) - Developer and XDA OP +* Sanjay Govind ([@sanjay900](https://github.com/sanjay900)) - Developer + +And we thank a lot to the original author: +* Dominik Schürmann ([@dschuermann](https://github.com/dschuermann)) - Original developer +[Paypal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=android%40schuermann.eu&lc=US&item_name=AdAway%20Donation&no_note=0&no_shipping=1¤cy_code=EUR) | [Flattr](https://flattr.com/thing/369138/AdAway-Ad-blocker-for-Android) | BTC: `173kZxbkKuvnF5fa5b7t21kqU5XfEvvwTs` + +## Permissions + +AdAway requires the following permissions: + +* `INTERNET` to download hosts files and application updates. It can send bug reports and telemetry [if the user wants to (opt-in only)](https://github.com/AdAway/AdAway/wiki/Telemetry) +* `ACCESS_NETWORK_STATE` to restart VPN on network connection change +* `RECEIVE_BOOT_COMPLETED` to start the VPN on boot +* `FOREGROUND_SERVICE` to run the VPN service in foreground +* `POST_NOTIFICATIONS` to post notifications about hosts source update, application update and VPN controls. All notifications can be enabled or disabled independently. +* `REQUEST_INSTALL_PACKAGES` to update the application using the builtin updater +* `QUERY_ALL_PACKAGES` to let the user pick the applications to exclude from VPN + +## Licenses + +AdAway is licensed under the GPLv3+. +The file LICENSE includes the full license text. +For more details, check [the license notes](LICENSE.md). diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..be4cea1 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,92 @@ +# Releasing + +## 1. Checking bugs and technical debt + +### Lint checks + +Android development tools provide linter to check common errors. +Use `./gradlew :app:lint` to run the linter and produce (human readable) reports as HTML file located at `app/build/reports/lint-results.html`. + +> [!IMPORTANT] +> Check no new warning was introduced before releasing. + +### SonarCloud analysis + +The AdAway application source code is [analyzed by SonarCloud](https://sonarcloud.io/dashboard?id=org.adaway) to find bugs, code smells and compute technical debt. +While the overall score may be not perfect, each new release should not increase it. + +> [!IMPORTANT] +> Check no new bug nor debt was introduced before releasing. + +## 2. Updating application version + +Each version has its own number that follows the [Semantic Versioning](https://semver.org/) principle (starting from version 4). + +> [!IMPORTANT] +> Update application version name (`appName`) and code (`appCode`) from the `gradle/libs.versions.toml` catalog file. + +## 3. Updating the changelog + +The AdAway project provides [a global changelog](CHANGELOG.md). + +> [!IMPORTANT] +> Update the changelog to let users know what is inside each new version before releasing it. + +## 4. Building release APK + +The release apk must be built using the `release` flavor (not `debug`). +Check the [contributing guide for building instructions](CONTRIBUTING.md#building-the-project). + +> [!IMPORTANT] +> Rename to release apk file to follow the format: `AdAway--.apk` + +Example: _AdAway-6.1.2-20220817.apk_ for the version 6.1.2 built the 08/17/22. + +## 5. Distributing release + +Before sharing the any release, remember to test it. +Release variant apk does not behave like debug variant. +Same goes for real device versus emulator. + +> [!IMPORTANT] +> Final tests should be done with release apk variant on real device. + +Once tested, releases are posted on XDA development thread using the following template: +``` +Hi all, + + + +[U][SIZE="4"]Changelog:[/SIZE][/U] +[LIST] +[*] Item 1 +[*] Item 2 +[*] ... +[*] Item n +[/LIST] + +[U][SIZE="4"]Thanks:[/SIZE][/U] + +Special thanks to for theirs contributions and for theirs helpful bug reports. + +[U][SIZE="4"]Download:[/SIZE][/U] + +[URL="https://app.adaway.org/adaway.apk"]AdAway [/URL] +``` + +### Beta releases + +The beta releases are only announced in the XDA development thread. + +### Stable releases + +The stable releases are distributed through [GitHub releases](https://github.com/AdAway/AdAway/releases) and [F-Droid store](https://f-droid.org/packages/org.adaway/) and are posted of the first post of XDA development thread. +Once ready, create and push a tag on GitHub repository using `vX.Y.Z` format (or `vX.Y.Zb` for pre-releases). +To publish the application in GitHub: + +* Create a new version based on this tag, +* Copy the changelog part related to the version as description of the release, +* Upload apk binary to the release. + +Pushing a tag will publish the application to F-Droid store. +It might takes some days to update but if it does not, build logs are available at the following address: `https://monitor.f-droid.org/builds/log/org.adaway/`. diff --git a/Resources/XDADevelopers.png b/Resources/XDADevelopers.png new file mode 100644 index 0000000000000000000000000000000000000000..5779f683c349ab44c12895f0e2656cadaa8149ab GIT binary patch literal 10800 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 literal 0 HcmV?d00001 diff --git a/Resources/adaway_screenshot.png b/Resources/adaway_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..6ac4018bd62d8ae47f2ea7d920efabc765289cd3 GIT binary patch literal 682527 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 z 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

asU`hUJIPze+T*^E^dWcu@ev=27eD;~apx@g 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�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

uuQ)meVzm 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 z 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�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 yES@ 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 dpCI#l`vOmW0{xb_@9R%7u3fdaCR^Qp_{x5 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

8qmFTi=hHDXo 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%0Au9+R@mFIeq+oaI;exFn#4WPR3}N*)H;} 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

B;6hp? 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 RnM9;{c^O6NyvsN4{0}=g7v%r| literal 0 HcmV?d00001 diff --git a/Resources/device-2013-06-19-105158.png b/Resources/device-2013-06-19-105158.png new file mode 100644 index 0000000000000000000000000000000000000000..b5ede4d99faa7508279cd55101781bee3815e286 GIT binary patch literal 92833 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 SbK1;NY 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

    F_>^itNzod1JgO!5 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 literal 0 HcmV?d00001 diff --git a/Resources/device-2013-06-19-105215.png b/Resources/device-2013-06-19-105215.png new file mode 100644 index 0000000000000000000000000000000000000000..e49c07e7d8dbb1919c6791f717c21a9748c8d883 GIT binary patch literal 139762 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�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 PYK_bX#rKsG#)1DI8nZ8! literal 0 HcmV?d00001 diff --git a/Resources/download_fdroid.png b/Resources/download_fdroid.png new file mode 100644 index 0000000000000000000000000000000000000000..90014d6b0c9c1ff9e2212f990dba849cb73e1848 GIT binary patch literal 5575 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 ViP%=Gb+iBg002ovPDHLkV1j-?cZ&c3 literal 0 HcmV?d00001 diff --git a/Resources/download_google_play.png b/Resources/download_google_play.png new file mode 100644 index 0000000000000000000000000000000000000000..a46bf3538c4ef76ba874a97e1a62777fa2c848bd GIT binary patch literal 4095 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 literal 0 HcmV?d00001 diff --git a/Resources/get-it-on-fdroid.png b/Resources/get-it-on-fdroid.png new file mode 100644 index 0000000000000000000000000000000000000000..afa603cf6df6cb9f13a4d4cd568e279caa5b0e6e GIT binary patch literal 14224 zcmc(Gg;!Kj*EcCOqyr2g(kap)DxgCnF?7cOA|;)Y5<_<*Al(fjT|-MtmjVh%H%Pu0 ze4h2b|G>9CW-ZpNJNKTw&ptbT`*+R_fhkJk<5J?HprGK(%1Ef7pr9du?-$q)fd4N~ z5Su6{LYlG?uhra8w>v%p*HC;juZzfw(C)tezyCAai+sJ}mi;Vp?|NjnO*1S3S8m)j zBlB&rELE_iQI&4#+a&_?CE(`KfTq> zZdon0G_kg}<`WbYq;w*gQP>*$0+{zk$=TE#%TueuLJLY~KKk)-^19OD1i%)cesYsR z$0QN832;OMvDa(D$&^?R;DP-=KY#xG7@C?%ECdgiJ?_?HW2OhxC6hAyRzi4o9 zaG~K9Ae3LV-g=q0=RNAd$%f9i+E{(o!T9s3sVP%W&*nov;08Mi6ECmpI=gcljOAz} ztvZ$ZuU}d4@bJXBumO49-I7Tn1D(rMq?5{=T+ctV#b+-r>I>n$%0ff&_23f_aE^O@ zrRSi;7c>Z2Yl^D4g2`+_P<)BAzUYw=R3MslQ}p})>Mf`I5H-sq05nfLU59luhfxD8X%5*!c&R16S`-xQ;mytBHt~ku@?W@bwWr3g<~3ti zB_0BgV|?sD^aGgRZ)`=!4qZ9q}ip@r0!WS z8w)jn!Lmz}ekcJ73Wk-p_YxuEF*ahd0T#RJKLy-t{{8!R zZ|*BO?$TjGCUkphRj0cF(iM9N5kGJclYh%hGZ$_CT{JN<@#fxs2r6Na^qF~qS6DcH z6V)~jA7wJ$vdY;?tahowHGW^US01?dsAAC=Zc<*|YW3ZyX<6s|>(nkiHMH{ba$RVB zFs*^R@At5NJ@Te?-BS?JkQCx!CVG{z{#PXMdd+)974^r-HO3B_W#_LR!C2XpLS9Qba!I#a%!Qnse4<2?kW;r#qBruMIWhS$JXImY`X+B}b!sZqbCA)GL!-1kfkQJ|)1b{e zLbX5@8Xhwo0M?0KJv!9jD&=wc0H?(D0N;o z_qTW2tggcV`xW22;jRY9^-Qk4A8ndqUqc?UbPf+I9=m&adOC>gcKBn3iFz+KI?t_c zxUQcIBe|a-o*>fw2TUwVv1GFn6Am(Fs&73&857WDa>noP2H$Cse@E>gUSkZ@;Yq9c zhVdSKhxA0NrMbD%iqYmicnUglZ@i?->-<~T*~{&TcH+XS-gT>-VuQ@Z)LDCjh|UI zhJ4%2G$7BL%2%_9q)t$AmHMBvxkEu%Rwb8x(=g_xO{(K9fJ z^XEuKjB7L=HgL%*ee|Ag@i;Rj7pF`d+Orq+xuH&N_Bea`<5F5mit?D|)2B}*C6U68 zr`y^myVwlUkzE^OIm9F+e&3R~7~XA&GBYz{l8WQ1v-~C!N5Hi}+93S_9TSO4AwO5O zKDwZCt(smc_<ROLt!N0Nf`CQg*fIOLuI9y)#40dLbhZcS*@o6=L7ZgSpmPPG3HHT@E=w>48 zq#XgaoUN}Q)wnu*9RFk}3^m>_qDoK>PuG`c$bkX&wpDX)x*;agK@scux-tk)?jZfo{|J}II4%ti;n*^APlJJE!N^meK-sVttVRhO;(Hx^DMOWlb&vdV1~F8gadl$& zlh=ngAA?~D1imRxC==2V?GY@Eh~Hfk*qj3FApcOK(ySr zD_W!4>Tq+CqZs;)4go?|LaHIDy2+W-=ak8HRg^ecz6l2gGu3Tat-F7fi4A?_3m#jV zi0f%S39ps3%ME!2lIC)47eX!=*(gJaqY}t4M)xb2iHV63pOd;__QubgHeefT-?-YI z>oQV=mF<{&-yF;bA4dK~`k-GyFhkJ`nLQdbaCBuwaff${L zlzy1XC&Lkk=SD#3GBwPU*VWq_Mur638;5LmqDVF9zaq2E#67|denm(UXHc?DRC`wt zP9e^G!#v=7tAo#;>6*-P=~umMB*V#i1$t-wvNbNi0i%&Ar|+Wqp%<$CG9ruyAM!@@zX5_$k$SW#Gd*X zBHWqU3Wl}PU6AVcPRepqdHFX+<116x5$_Y<;I8lTc4xZNn6K<**7kC0IYABkoOBOJ z#L2|P#Kee^edFwdwW<2KkZ~_ezqxvQlZLKnID`!N`C**T@+I-){ttoMVI~B}$~Ssz zLs~zn3-I_VypixPWNQ_zl6F9a7I9SFZ6^`T*9da@mMHyJ#H^U0)%{4yiHfA5n_Ezj zZ2qe)d3PeGt`>-i*Y4-54Mb}4o88F$*>|G~1&ZksVRTi_TN>tvmwRnB|8dl`_&T9p zUy3h0j*bb`4jbVK2kJ!LD_EuTKhW$oukHAEtkMQAo)Wf__6vPDe@@PFe3(Gf_$RBx zclE=c?4aR>{t0Oo)Lve6iE$qCwvsu9LlwNz&`WCFD3_iUR_WN+sH+t4vnSa%v|&(>@~Q%b#mW!0=TNb|8_GJRuSgUyEsMYVxP| zY+dP&#>U4d-L8keDEe<8ho9HFcK1o1RB|tfa|X5*IB`SS;CV-Bi&>2V$|}M z*@;N)`6pwx8p8b6+B#K_!4oq&LX2#IYzT!^{;Uj_>_V+7dSI&gis`tE=9lDhnGU}P zMsapN>lyJp(XA^r;%K*RyH5PCd)pK)lo?8fYim$>*nVZCQ2Vy97p3#_)d$Y50uOq@ zMNA$GMPa)^g<^k$Y}K6;qk0LuszrVC+U1hjRnSIR}#3LlynfaGyV{}n+48ONXMO^oX1+VMwf@jph z>1n<`w*!jA)&{7b-Kz8gKmkNjnpg=W~1W zUwJ}w%Mk~?IU2!l9Ajt$d$c*@4M9Upp>*(AFCSIv;d6|mI(Mq>pzd=0rp*4uCRc4x zSQg~NhYwI8lb-Mx&vK?WiP&piD&MWxjAi80o)M>xK4ujZ6m$rs`v)BCh304lhtzG@ z_%(RqX#){qbXlTnhwHeFf?c)=8g1TQWJqIXMAy#z*R1~jI2NXK|5K?}*F743VTWJX zi%+#d7Ud=m4!rynLN;k>Kt8#vOv^X5jr4i2DOY-XI6@Zsc(`)yWF zXVQPs8sL)hwsGsd4KcKtH~QYKqUBQ#no8%0`1~}XYwE=mwvZM`0i&y^c09-2oUXk@ zvm&#<(RoYjZgRuPJm`&o0ZfJG8R_ebvXO85qm`r^<`dN&9uCqWVu}L-|8A*d!f1cR zK@-I5P#TSg`m3=;vciHAKMyz2zntx0Ma0NrYqHFkbn{@D3tLvaRrh;@lP$x;KcorD zQF$M+hJFV%{Jg9!40XwnD@=%|PoKIStYGrX%E)BmW^SyOm6h4A_TZaCM^bF~U?7XJ zke|(tYlAUwK>tu=xUAz8R{&;wCu;(OV1_d}_VQfZ?}MX1QI(=up|1$0nd?o~y|5(1 z;4=y1jDBc>jB4E%0Rw2ldfpQRpSb4bXr#!pugBG2GMcNEjWP1@#ArOOfsirqFq%i1 zro+TuD~sUEF1hS2;V)ufVvdb~$i!EGoEOAAk|Bcp^S$6V@qge8ep2U#HNOhPWsa)g zVG`~2Us9C4tp2d+qWa=FL~z)RrLdmk_@kz{?YuWxPCSE#xD|;iVLyvk%bz(pV(-4Y z3H`cf0F49w{aniNf97U_qCw-R@(n)YOeNkO&0S20@8jdsAzG)D@v;LzQeW`UL?v22 zoD^>6*a0ri&&Q`af;WM~DS83Bq}-%qi}uEqrN5Sc%9C3syFQ%m&keZSKQ|l?gnhd$ zZ!FH+A9)dXaIwSpE9ujpv6*Ptqb;Q-dbzw(%jL*RK`r+M;up7;{?c4F^liCfZK3bi zQ_aG1AJvIf^2>l+OXMIwyhj$BN;Fe95$qw1gp4oMW)DtI)X&PdfJ(emm{qik&FgjH zq-^YVbLGDIku?>lja3lJ;JCPlk&j+HSbXVq0iLgWud0a(6dFRHra50G@9*1n?DH{+ zie}VJ#HoUCF47PGt99f9S-4s#`V@0~cV5sZ6PyB#7A zCYU}c_><6H2Hk}UdFcyHxy~!-Dw(+7#khX68?lPR`tYO86qYlC{<*Yg_I};42Zgxu zu?pkNg0@S|uVrL{>xjQB7|Xx}RK0mjA&BniZdfdM9M@FG+Tm&!BqMtm7dPY96USKD zR~#5nr*q!^V18JjW9zGu@@VsiONj2UXZWKKvRi(h34)z5!M8yKk4QAaj{{s@hD1i@ zla}zS$@X&S0!SCLDH$e^oR9yD)DqhA_8ZwmskW+H^Odp8bkKhTI}3wuLXNI#2a4XD zwVB#Q-5^4LXmnKnaOzhKyGEfUMcG_OE>< zfnAvDte~OU_-^A|nEPFB`sZsT0kAjL18sEDiXzl3Ibb<*WIPKC+?>Yrk)ZLNh5sQI z92FUA#cMQ&U(lXx=&o*|A*jY+$uFzl&3^V7P{{rxmkB#7(cc1}R(klIJlCNmUChl2 z8Yp5@+Yij97JrwB?h|5`#)EEnP(8m;v&StZVolA=mZY7&jEsaZqo-qZ!M*xB>;D~* z4qm|Y`>!oGBhdeKFCB-H-X z=u^q*BkN?z&_9@Se!G4-HKY{OIJ#*MSU!B=(j&vv$rCo zK`NidN0@fPN|ivadC5jDrOspecy|kXS7c`1)rkn|+ey~SWrJ|@xF5?A%R!*S1v<$O z9lfvvMn@Y0twyw$gV^+V_@6=$2Zx8yuQrRg;pyq=#u@%V))8UWF4Fz_G%O243q<#%XV+W;$>T6vc zA|e8xf#Eonayp6WE`=R0)Z3$9U!3@-q)@zxH-_`%j(iy$l)rxhnHJBgjAn3>ihS2D zcRnN*>iaus%wkdj71dZfMeLE7?`wU9b$_OXbx3xsyrV)gmowJZnIJ1RaA31U;+B`-^p6EyfDSfYBWYP z@^M+bRRY`)iklafb)_QXw$b4gp13`|PM^xvoKK_SQhw90BF4(DR_Ob~`x0MUTl)z@ zvI`)_?5;1IPm&UNg37a`A}Fie?z`tF2)UKG%(t6aW0b0q)QF|Rm^q)wq94cif6xdn0t#Ku9x7V9(YUj|S>)1EPKrG^N9+m4ackzUT8z-h< z!q?`w9qEHPE2p36R`H83?4Vdo7ewwAtRL(PrJFkVEp4n+&g{Cx9LlyE{VHpz zB+%H7ivrPzIls^djKR7V&NrNSc5E9n*(+C|2Lqk*x?=>H7EV}++n!Nxl;kP&+iG%~S zn*woR0&__i4J*^;G$4A4iGhxQc8$lKulMVZf}1%_=|JKl{s~VISua6vKcVKhS6NR^ zPVz`R%g4K)VLUSPs?J`SDg*PFB4GHJr9*xxv+L=Dw^lRhKV;+_sNxMB2a$;g)5C&&J*QQzi=fJIR$Av>o^mN9A z!iJKBhNgVsMZtI3f;0zQWMu_6pdbBiI4T{9NX=|myPPwa`AJ^k!iP}KT_O*#<+dtB ze?f7$6yG$Y0t`F%VPnzsuE7@fhxKt!h+z@Zm_i<)B4liAp7w*e#f-axQGa+lIq_eg zRQODCY~U4n%j`w@t_+s zA3nEU0MA283I<1a8~A3X#+-;eXAP9ZqsEE9v z?F^4YJK6GRfTJS1ZE|W#>P_Mk;!1{3(lqV?PUXG=g147HZWYzl)sF!(IVSO9v!o(^ zL=vDtLE^xI!(2hQv|tTfb>)p@HSwx27j(Z5*)W-7zjRYsy(tzDL(d2Mm)-q8()I_wPq1r>IF$q8GuQMdSu<9ThlGt%$4LrahUxi^FeR2e;&P z=~yD51NnoR5mCIZzb|^J%E}>t10u389^^46bq&sj?wFtk1arI>z;9~i_{k~}U$(NM zSY1#GEb6VQV)?A@)vG(N?Bnh#rpwRo181P~VIw-(nMSkU(wqZiK<@4kP}~wGdtQO&^ynhx{6n zU;SU!2ytMkzJ$bmHUCQPwV2BM=^5|T2QEU;8AG%lw+kOK>qsv$@E9&A zSwwp$i#2t}KicQQq~91%DzmEbmd7rN z0yjd%=YJRv;$8M}-|LKG@i4-J*ZHWZsMxT(?;i{LR)FPcF2Ybw)}smAUJ)s#l~`yv znUh+;A@(4BUirbz{j25Y&ceS?lmzkj?_bkbJV0s!A(wBYJvA!p{i(f5$r>F6i+zdyJYbe28pwhLi@Yx* z|F~G(g8TlDGa3*<8qrqvpD+My3z%{l2toyt!2GdmMYO-ydp;HX&aG!l9z|cis6Ugn zew9Uc<~vkoAKeok$a&*)bMzVA`)dDU^w*0QFFpZrC2B3XYJi1_a1%Xj|A>Acz}zs3 zat`c3BZm-Qs62m2Q?sg99(TcOl0YmA$Qnh%*a{Ru@k&b&IUUWrNg;Bxv@T59U($Wc&Gv{#OUE>qrR zDC>-!t3JbKa8#iKAZ zEKqKFQc8-f)a2>T{H2$nP0NW!Y?;^Psj{&#J<-(OwwZOA@l}rXP^!S23zJWYiDnSc z!5+Bc`{zqx@2hj~sxZ}KkF(vk|Gb|_O=IYKKYrYJc%ITJ}#;`K@JeW!UdLq|sh0`UN2U)4*DTZJ%ZiV^oHN^0e5Cp$nJpq5t>zTo)5)3DJ^jv}@a2-p55V^Ky7R$Eqa4>u7L(9sFF%YVD8=Wv3 z-_3}kM{!n|5UHUhdS9Z~pI=|yyaF&l_=&-lGY&2Id&Es38g6&I>cq;aD13v}n$!rA zqK4l7FC<>$B7vCsj!CZf^UO+$Bl+tO?@y+iv2UKnv_AD^Q3WV9J^@gfMv0SB$Hau% zpG$26gJD2f0#3*#Ce&WH9)0v7iSGE=diZK#N?B_r>}>)}#9S!{(YgQa!q#ZVVBu-| z{xQ$nUpnI*z+=21EIN?S`7+kUblXi{ua%UoIJz(MTK#IIss{C2%U^vl`GIr9{C#L@rWxgWxk!M!FB@(%)#5P|(j+YMN|HXjp&qBuE>RmwrGOX}Bm z)FiV=_A1;%Utoag6D>+2p>)Pv=5PoB4`j|-khj>*2z{p| z9!tbyw{}F&x^zRJ-#dxo>`X8Cjk}|OS~)=nLO#3oOXTmY<0eRg_(OSOaK8Dznyg>j zLBR-|sTM@>m+nq&h`ER3ydZUd;V#~zEc=z&+pTYpCuZ7w+SuT318fDXSbnur86qCF ztu*(^9J}jJ3Qc=MwGb|MIJ@~FdcYy8gmuxDnsPAdYianKAKZhpjP0Yb2EF&oLxCu! z5U>Qxg6n+!y+?p!B??&L^7=7s*6Vk^-V+3$Vfm#;u_Xx^wicic2p+F|-t?L@Fj%Cb zXk=}&u9=w_QDk+WGXa!xrrnw&9W}L+v8pYZLdjSLq+W~NFQG7fYk>z=ZDcnH= z$WaKmxSfc08xtvo8W_ykrX2vsy+;71kYcPLEmK@h?c>JvcWL$yWWg}2=a8p*_0guA zdp@@>fV&`t+@LSz#|_nj*zeyhU@9Q|D_QDlPl{P3s4+RwaEX`X2wsBPE_YuXN8)My zN(J+Qej~X(5BphUt-SvJPHJ3o3?GOq+Nx+#k z1+)(DpF>1%&R27*?AUeJGVa4o-1iBQJ-Hwrw^MGpIwpJ~?a{A{CVhc1$sI6f2z2@? z{W_C~jlosf<1;KQtxm_6t}f}`npu19$79m6*>;oyjPQE1Ac%+2rhO(WO@sq(6vaEZ?8* z=31t-{VwI3;Uc;7>(POz)L+2C#5jEIOhG@J>-28|Kv?p@vh6$gY1d1~021{^u_y1a7SR$_VV zYU^GGWWAI182OBjrmnKv4X;t6l^FG7wk~~+O}gQJyQNeARVjD&oi!N@k^v)y0M$q# zJx=jC4ksT7r(7V}$Zfl-cZDc=aPVhz;Bv8giHsGzwQA|?=4XdLU^ee_IAFHAx7Ea8($S1MjT2aiNDcuCHTP6eNq>u76g&1Jo=e~Z8T_Ecs)&=S6x||*pEB@$Hm?0A?LO;psx_IC~Mkn{N}`6T3Q;P zveJ1c3JCWlpix<37v+1Fs8V2kL9oy0J-dB908ghpF*1&0>-A z<(O9wr096d)6&A`E~Ipnu?X^lN63d4?grxp3FKyG`kGpfWlPfGA$w^&!fU6d4SmYC zyn1`p^2;06D8F~?|0(#)Ty_F<_jmd9BR&$AJp>}~mM;a{1+U{w&JEY&>Q26%@$q~B z;Hw6O;#W0hLfAf{)}BlaVNLf90NnShy7KLLuNagR(Vj3il7uUKxm_chUtLq9fQ9tf zZ3wC*;|?;2yz3QE;SeFCOiYZG zPj{ZuzLV1m$Z@@4`fy+nO3hV{^1OQM(n93BwY5l z;0q?c+kB)L%ew6Nwy=XJXU5cWZ7}8h^0odKjJ2T$NMI{6mTfT1>>h*6(SH=#c_?RH zWQ75dimb>4I*Uo&5fpPaD`$Ns3A@ZL^@So_zMov%)eg&hI6-O``1hGBJSbe93TX(eiOIB6^c={fYB4TmyQN>EH}j{@Mp%fl{)2;3dwV51d*Pkp(NR zXTMdFK@tIHtq3j30Ez%Q15FBf50qm9CEoBapJN%R>a~B%0U9>ZPHA)LOIIY=ds-( zOKz(Xujg;lgluX0)x5o1+2Fy=2R&4|UwlodH|`22I>6)CTFW)|#cEBie*_ys@FsZB6>2R+A*WpbNvq(%hV2|9xfcYy2G{T+KH;x`LSuY zxptX$ex-d$*#66D&bg}4Qmww7+@RhflqFZHed3kPZEY>l)N#u>$*4mJr0d z40mP$0f88?la(;8alq-t%#DJ<Aabl z+G$kh-0wE2?F!S@71qH`Pwyvsxy=__R97eH(6lIOh$nK1BA4=E=gYK2{3j5iFO-x+ zrjEw#C+cS^gU7B5_D+B;IOew~L+>LM&AqxRuUu730!T>K!uVPu6ORMB(`Q`BdKOP` zHHagmfqkoBIAl15F9;V8?-IX`)xHqJ&}eIG>krT>(5K^0_g;!^7zLw1ssrDTYS);J z^|O2~y*O18yLMt{V^fye>?f8eBi}JzpUwGLnGgpBkIk zuM^Ojrox}AQ`0XWyy?%FE*x2o%2xbM(Y22=g6?x&3bqvaILQ6-cf9I`;q3+aP=?4S z)4PUyKyWIUm;vG%OCjo6&-*94swxIrM&om3zqpG&muf^>Q(YZviaQc_y)Je;cEUXj zbjotTNf^Pus>v8NE;~Anw>OvemY3M0Le?{xUo>-Jz`?vclPD35O#?&EgKjlt<=4E< z^Y6co0Vhd)c@#$8ySTW-wmEN%(*3?osIKPyu#pwC0d!{_Ua*EFhsn7)xr2iPW2D{D z9bp;Y`x)aw;LK4ftEaX0ZP~jXb=ERd>Y6$hk&;wE&3B-720v>t7D{Pgt=lPOoPeD`fuqVCG9dSs>)L#(G_`HVi+anAN^|rol+4F5tj3%Z3(2rTOt;FBmzapEV~4xuml_&m@h4Qd&4 z@AHsx>7!KZv-##^IO{PgCp&vKKy0!Sm3%RmfBMt2vV-WZeedo6F)7}xc>EZ=bmNDK zhxq3c4|BYw$7(cGkFB`~!cMu-{P*>;dOh|;_%y$V>^k11SXJcyyltEM1+#I270?Hp zGvZ^f;1!+Dwt~d7q|Je2&SiQHB-fbN7Z7z#O;r_@Snf3&qE1+!*v$bUf4Ro4f8t!5 zk68Z1PhXg!EqTQEf6gf0C3vdCMKH~JFla?PvhwH`n@z9G^PW$;e-6=_)3eFmvy7xE z7!Z{!8&fzkG2Q*~{t=Czg3^XT6Vo!r6ESgoLydB>mlL6@flXeotNfZo|cG5Qio1 z==O_iQhObhJxb6~UwjHhOUqj+O*1oX;DmNQdYmq^_I@>JiB!J9vguZc{BTNeNOs9{ z3+(pKXw%1Y~hs+KyhA>CA2aZ!m7ot2-B zhnClZ3=`@^R)5zbCHF$VCUz(H%=Adb?M{Qye7V8ED?ptv2pS5uI2;>=78FQ_@_#QP zy)Rkb;0j&_f|j>ilXffrLqIW%$sSZ$roou*hI{Z{=)cg~psK<`J8yBy^b zodU%Fk^%;bZ_C+Ilc(I9z1*Bv{ToT0=%69sO2>C~m4+QgGnPaVf4SlPfLZ#kDrO7>BMS zHi}bie&xC6LO&;qjVMlD;0c1utO)$V&$y{x77wMClafJEitW;*188VI26d$(*AVe43!0E5?LB~_vYJM- zt{s!IIN6+J{(yrLEETK~Y!>XIHBST_18|!q|1A~AS6ys+)Nk#|;giUO;`{UowQP;6 z1`g8uIoqwWp&1U!PoG0c%^=PBgoV!6Gr~ksLv23>eHILvxll&^+Ny=Jc^VDhm`A`l zq;kd(e+ge&!ne+`X1~sI&5CKWqo7>XjN<;7a=!L + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + diff --git a/Resources/icon.xcf b/Resources/icon.xcf new file mode 100644 index 0000000000000000000000000000000000000000..3fb64d5d76ec94059b2b314492f3846727f2b60f GIT binary patch literal 88240 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�+_vC7u5r^Z^PfN?UDM%hkF}HaLj*Iq zJG=sjW=<^Hh;Bd<_l-1;h$N_hRX%nIL350*JygI*(+lSOE1qkuF#UNk=X-+pJqnLm z(BFwN*d!!xCy2L*#ojy6d(*3&%ihEJCXoEq0H@s^PJ}T#5XSoxS%AlW;46^!kAbVe zFHSvw@bAqI5}I|0fQdtGpbzW^dBC-YZUA?J*MWC}4}<>(n#f%k(4!Kc6z;2Yq3;Kyc1 zTfkbd0~`ZagX_Sp;ML$w;Qio1@G0;F_y+hM_%UVB0@i{ZDvRk=B>O#wWzzbHJ$2<{ zPd;`f<3i(alYw~~)X4EGX{3!`X)xIy)81p+ds2H(Rvc?e_0`Z)EK7;JWyudGnHgDr zb*jQ;b#xBvXqArUg_iwAn3@JRHBw4FAh9yCR<&Sd{y>7oe?#Snu1YI2G;H?L9}*hI z!IQ1=b;if$t|ijxS|XjUCDQ3y zBAuT5Ewksn$LyD1ZFb$m0LygU7Xg;(x*vdXvln62Uh+A!8%M$0!2{qE;4~opn}^8j zmEf1a&ERfuFW|W^{eAGq;B(-Af`2gnF0|GxnCr4=sVPJ78h+Q%yZUT}ELzIPt<|Zo zwx-&UYA>pdsP-YPk_oo3+J}P2_+-&iS+rCZEtN$}se^(J6>a7f}UlFVh?QcR~ICFcQXlusOiEcj@qSi~&&NTZ94 zR8EY|YkXcKj|mlBWA&n%Y2069_7E@p8_~C-??x20WbB@vOXn281e`+8#4~c5rZ@_M z&Wo!6u`mlh%7Txa#4479NUvf!sJlE1J`$gnuVo_WC?V2j!AH-~;G;?I?zu=*B20G5wMF~xb6w0E6CRc|Tg}*E4??f4F5^}R& zxbzNIExP`Wo38Ke+sip-8;t)N*bst~>XH{=k!|d(B?? z4zpLi6?_0Z3?2htG<)@*nZ4#8%zi`oq1kI20MC5wX23IFd!^aE;ElpBft$hI;9l?^ z@cU+O1#f@U>>WJw9X#_LW8ep1-0WTd$Lzia&|&tw+s)p;3mga6nEl>Sv-^4G{Wk-i zdH=m;5Agc|_8)i;^%w{Oa9I zAG_A)&L$m#Ar%y<$^R8Yd*1h6F%IR|HeF`pp{9=x3DgalVI_pm9m4Al;b4StGD5f+ zA&ixfL6?w0n2;f>kfE!PVXP45N=VRW$aJkC#O9D`a6>{ctE*TNA&>|GA_RyKAVPo$ z0U`v55FkQ;2mvAlh!7w`fCvF11c(qILVySXA_RyKAVPIDwMInH+;DLav!;xr6nv@> zkzquR5lMzp@X10bg^BrhHED?E$)ywseP8MEuattv!fIaK3;mX0t%vwoAzo*Q_Zi}G zgv9KIu-Zc=We92BhS1+aCO-(F!i7-cLMB%U={5gp9+4be)8Z#e|H-giz~3 z8o?n{yO3^^kS>#u?vjwf@{kEALe`%M$N7Al?%~7g4M;v9`GDjDk`G8eAo+mg1CkF& zJ|OvkfaC*`4@f>B`GDjDk`G8eAo+mg1CkF&J|Ovk}nHsa(jtPZCA$eVR~m@3XgQ@= zG2JP-_nBM7R3P`vaq5$ulKTi<5Q3nLvwm-&W^ANp^ieZ5Q8W6f8JnpYTc{aZsTtd- z8QZBDJE$2usTl**j9t`>-PDXd)Qr8YQ_O-#zAVvA!^29YQ_<2#!+g< zF>1yTHDj2XaXhXWBjE<>#YXByAN67r^`f78v6*_Yg?h1-da;dqv7LIcgL<)(dNDw~ z*hRhAO}*Gdz1T~=*hjtCPrVqVUL2ra9Hd?xqFx-PUL2ub9Hm|yqh1VAFNUcX$K!f2 z5~Q2>S@S@XbLvDq5i~hx9xu&Aq5(h6P@)-2G#QvCGSQ?an%qS5lxfZr&3&TDXf-*l zW=9b#MGO_ORm5D;e79NaY*>*oOw}LnHQ~ z3H#8DeOQ8hXu&=##Xc;{auA68)>+OQ9+u@6-nTnQ3LkN`oj5{t1C zby$gdtV9D=q7f_6gq3KBZ7kWVp}7^&Wv%cq!2 z)QSkz`4f~tdG6b}*=GJky6#LZ`xBYJk@*{Q;&05Y?TGD=J3iI=8*^(xVrx`ef>i5o z%#9V9YL(&_G#@Yh8S~6J^;F_|HXn62d*(cq?VS2(Q@^hH_+sbwndkExF7^B~Mhnbo zlc_?hX4++r+k*3?1?KBLEokkspP6AZ4e$)BvGesMEY#;NXbo_w{=@n1&$LUXT^4l9 zXhCb2`SCAA%n(6CL=6!(MBEU8LqrY{Iz;TyARcSsg{(Li$;p{><0fi`C>o+_h_WH- zhA14Oa){C)YKI2!5F)54A?Cb7QW8$n5M4vG4be9!38!<2)A##LB5+X~8G$HbYNE9Mdh*TkRg-8}6TZnWa@`XqkB4db@A##RD8X{|m zv?20_NE{+_h}0o+he#eGduWgb0W{jJVeet5MTj0DnuO>QqD_cCAsU6~6rxp#ULl%= z=oX?~h<+g&hUgfgWr&_3nuh2aqHT!2AsUD19HMoI-XWTY#z(}vs09Hu>aF4LVW&oj zB0&lGf;W_aQz%5G5T$|=U^so|1-B^yr)G$vK?(RWTaRgphR7KrX^5;L(uT+zB5{b!AyS9P9U^&%>><*J$R8qshzufLM!HF>#v}^` zCsThUQ+^~X0gG@kx#$eJhL9m*M!eDtx%SoC;-zJhh1udYWVCQhymCUk8XLKW9HfQ8 z=gWr_g+o*hQ94BJ5XD1O4^ciu{SXC2R1mi!)hlm^^bcom?f`^D6B7BJW zAp(eqAZ|x$M~peQBa{ZuoP7mjtt3WiU{6E>aa(fsS~YNFoxv+6uNb{z_KM*vrmq;k zV*ZK&EGDpsn<8+E$SFdnh@B#Mis&iAr-+{j=ioz)>rzoAGc8cODs;4NQqJFBLRPArniV#j+7KNFTa7r^J;Y*lM5);dq zh_*>du%c0$(>X=!6unb4PtiRo38#Omj%5Bu=5P4IWOM3oWd6j{?#iU)Pbj8Au?>oG zP^^Pu9u)ha7zo8eC?-O&5sHxzbyE~hQ8`8F6tz|sbgnOzozDnm(V~eW$wnmn1r!`#7XK;~sR8_f@#`)g+MJyrHoWvn2Uabdc6`7oV z@J9e#+QEoMRZsptbVIzC1Q<%T553OpYmwR4S)=Rgom0<$_-$q%z8^ed_K{bD`#@;+ z(Ki70Kl(Ai?~i@P?BkCE0v|vAEwcx|Z1&KTW)HJ^%qLi*><^cN^wGr_9tL%TR6MPF4RTk%~ zFdiIOU7T1JfS3g!s{NS-AgTd8FENnS1q>j9w?wl5#4G?Y3qZ^Q5VHWpEC8{dvCam@ zJR2GNY$9a6nXypyVXN(#1t4lvT%+R}CD&-Vda-59=Nef6A|*;AH=EEP&G{6v0K{y< zgKB46pw4KVyAOth#=ZMtOw{&-2lFu+Ut4j1H4_P$1t88xWvlv`bMCFowfB=fZ|*(H ziZY!irpw$03d;YR51d83JI};P)m~rq*EnB+fN4E9(=PMS9<2C!YrTBu<*S_!O)x*t zn~J$eWqQWLAEf{G;^am+5y|e?zso=VDx(m;(QLV{XMyK{7fe0> z&33bI_JiLs8~Z5ubMPIrzx|Qfw_gL^0@(k~y8-9F^GASdzVkO`-#rPwZ}xrRr)EDO z81@J2zyKHq&o=uf@I&DR;5P6Y@D}iU;32c8z_{>f@C9%Nd>{OjRVJ5NZZT*S)`0=Q zv{;SL1}^}&S*}I+w&j-pCU`gaDEK4r=ay?DzinRtXDqjx{f<`vuIb?Xnm?s14yY^` z9hr*O$7fsaZbYYMUWV>`r)G|t8fkbjVfATpkaOdq3z6#DX1Vd8c7zZmJT+EwZaf-k zIAJ5rr+F>DrDUdTFX+5N%F|npEf=})ic(K+Wwc!6C083lP^UC2S30caTojG8o;de1 zZGOSINW2$z!MWJCY3f-`cd2PFHT|Wgr6Q)rnJjZ1CY-V+pDlD~uH%5oW@^iDVk;I- zHhpqXO%h6_ozFF0Q?+-O$c}xwR+voHo<3cxSEg#O7e*$Zrl8ja?{CzC&DV^|X`vRZ zq$YGu3t9dfQg4Xp*A{~GWwG&Sz@rD3a!tGM`}o!OTcZymAOm;Jtg zld~+7&7C8;)9Egg{d74mWHjC7xSuXBWg%rW-Q~rfF@DFQ%hFoL{ONKXMiyO`)^h1j zmv^u*vY6U(tyRTNUc8Mz*YfYJ_ndQC_6s=85;0mTrVe{QeHnA^ru{Jm3)bK80I^!| z2Wm}_^zCUmcJGp6`OuW<*}IX37g?&Rx>f{8Pm`+zYDv#t#4^5(aTL9xt&>H36`!uZ zWLpc1`7Vn^;(xAtPrP3dMxX2c1cudhjmG?F9#fkAP2t z&w{@O{|o$!<&J=1aJ&wz2AjYjxB@)aa+iZEg&VR`LI2ivTJ>0>*CEw(1W?+Wm{0{pH3zbnA+Vp`yy0KY51?>fg!d}-6P()LzT&wt8} zOu8i4^l9j6`WEH1vmlW4f}!B1nw}PzYky+;^J;;Ho~jJBP{T7B($jDYTDxTa zMVfsFS=wp0Ebo`H9!_dU+zVmZkOlqcNRuZ7&Tg^FIa0EgTPlcdb$GTYM}*@>NEnW zY8SpO($B)^AxVlXDbl3KlOj=yOes>O$dw{lifk#;rO1~eVTz0?Ql`k6B58`ODbl9M zn<8;aZKdtJETri21v6hj`eA>)))Q^8bxYx^h@r?NHeUk$LXM=g^C_3nyBcaqK%3^x+dIgo#7Vi2)9~$c=0pv zq#C$L7GYk9fgvV_7#U(_h@l~-h8P=SZivAlCWjauVs?n(A*P2IA7Xxp0U{=d7$IVY zh#?}Th!`VcPArTprWbt4Ta0*%Ovts4FFN3hUdtEV%@^Ip7rllrx|1)ugD<+BFZ!a_ zw;M1& literal 0 HcmV?d00001 diff --git a/Resources/icon_background.png b/Resources/icon_background.png new file mode 100644 index 0000000000000000000000000000000000000000..2da26758b0b7165ad8ec52fc9de86e320cfa8337 GIT binary patch literal 2649 zcmd6pUq}>D6voetv+iVwV?i!f?6d~Ggboq(51cVZR;fh7pq?6v{y>36B|a28B*X?A zLPhjq1QERn^%4c;KExVfWz>riC~YMPMWPQ|tYhD~t8MD4yG787%yQ>^=lh-S?%vsp z%}wFblFAYyDs61AcN58YE0bD`%Xs^nAGj1B*b%mAlK*Z#x^o39OHMTGJ4IAo#s5izE(|FReepPlpd^vW;_pEz()QnL))uEE)j{3_%o-7NILW!VFD#gqwX%vWP zl1_%F%N9B5Iz<-(i&)^25J*BG3jvEYiN(6iVhaMpb5#~g5X4hOA>n2Vx2SOYT`=ty z@01y4x_7c{ZfU{2vw}c`0AqLr2Y}fEEGob>iDS^^%p~0f;U|J@5i@z-*%l;Y_PG|8 z!eO~8hehS=Mj;Uvm<*2_s=(pPXilKP@E90m7#QNYZcMX) z;8$9IBA(yP+Jr$Vq^}TDYfD80QJ*k*lEFQYVZY0XMcusu(pvwoWQRkJ=-pQzZ(ytI zm)wsG;MB_3ih<>}+VOjg@~unV4D|6;P2x1rh+HCk%1OsXB7CpN!aE!k3*0KOJliR+ z?%DDzQ?9keIibq7$gA9?=`bwXEajI*F1B22c>(AE$afoNnB>*nMfcg8muqd2{hud>N7XiL^f1NWNh=QBwZ$_E!`_y3dP^0I*VPE z+y@mOdk0^jA~5OTh@ej=#GZDVX}rBCiWA;iuDjfL?kpcJXr{QLI9ef60YLxe?y3wj1Y(@ zLZQxM(V3qGGgZKW`7}KJ!_1WIWTr%rncxNoxPi&==5w1fP;Rj;(kQ@frhuc=aq3qA zFAvn2;v9lx8PApo@@z3v#RlP54#MC$*JUh_0MZaulBkkJl`>VO;q0Hygoh};{e`_+ YCaB-PweL{<*aa3g);HPR+nw`20hjz0bpQYW literal 0 HcmV?d00001 diff --git a/Resources/icon_background.xcf b/Resources/icon_background.xcf new file mode 100644 index 0000000000000000000000000000000000000000..355a16e17edf3ab44d02b679a327fbe9d6b0be01 GIT binary patch literal 62904 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 a(-s-!R=8RCd{A3ah~E!4l3$MD^ZyST+-V#D literal 0 HcmV?d00001 diff --git a/Resources/icon_foreground.png b/Resources/icon_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..20bf4430624c24a1ffffba519d248c44f7af95bf GIT binary patch literal 3335 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 literal 0 HcmV?d00001 diff --git a/Resources/icon_foreground.xcf b/Resources/icon_foreground.xcf new file mode 100644 index 0000000000000000000000000000000000000000..738db0bb121828619798f06cc320413cca8069cd GIT binary patch literal 26898 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 literal 0 HcmV?d00001 diff --git a/Resources/icon_old.svg b/Resources/icon_old.svg new file mode 100644 index 0000000..8c60fe1 --- /dev/null +++ b/Resources/icon_old.svg @@ -0,0 +1,356 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + Dominik Schürmann + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/logo_googlecode.png b/Resources/logo_googlecode.png new file mode 100644 index 0000000000000000000000000000000000000000..eb6e1993f61dedee3456171bb100d06b6c51ca80 GIT binary patch literal 4448 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 R`SK9>p^$AXO3l3){|EQfapwR4 literal 0 HcmV?d00001 diff --git a/Resources/paypal_donate_button.gif b/Resources/paypal_donate_button.gif new file mode 100644 index 0000000000000000000000000000000000000000..43cef691e583af713ecbdb66e3a3884817eafb73 GIT binary patch literal 1714 zcmdVZ|3A}t0KoD0K8aD{ip$|@E`4*Ak8?>!^=T_?$aJpj+vQWcPB&#!A(Aay9r+wG zN?&Y*XtAjwP3*HFUD%Gxl}Enb^+l@fk-AFpdEevyjC=hB&tG1_>>&TuyLSRt@Xi6i zR}bOTd+JFoRQtlJ<;skxKOojoi=O79~2B(Og$RX~TubPr`OSgDs%ySn@JCemD&_Z_h3u;FU#k#jmix zGCMzWNU<6h#0&R@GuUwq<}OjD6x$Iu_`A|PsD)2kV0|zaxiy2*PHUc zW(4zfxmZpj%Tl@w!;dnU(eR!OPY{cUEZDT&+*<;xyf+$tBFc13oxy?)95`~_*jkR^DNyC35Ceq@$#qoAkK9hfE{izcGc+MC6Kl7Ndq57?+HMMU_Ra5pIfMx(C2vV zyi-%s^2rju z_Why!p`*TfN9{K9472yDYM}AR>#>238|ooliq2{0hO0FrEg25&;I>Pl&ARooL*-%T zw&c1L_%3+cBO{gDidk9nmY>h!E#AZcyp7tr=l2DHoyp;i3Cj@YYyJk$;v1GB@|X;H zQoPEsw=^w4SnSaN>}QEV^k9FI3tp7U@;2Z4XkjJHG(dcPg?Qri=pTw0Vl;IIe!Ww{ z?P_RC!8eZ{%8Qu)!1ndjl}Id&XmZR*ptDvRGTEL?t z*_*!6TM^DmFJ$k&PdJKHS6D_?)f)LHXDB?2pQ{=#0m7>BQyMYbHUxA!=#f$u(u{Px zP}@!d!gKZp5VlA=2EyFhX1VEa42^rmAuDPkW2>#d^C7h_>Yv9o64e3BdBk!bY!;c1 z8o+`L2+{OPg$(O{ik6mRN$^R$O76V=%H$T2mxt<{4!r3OaT}mb3-b-v zI|r{C39=^NVC%a>eUGo4wjCm&4xe!`+BCLPIIXv0vZwX)C|S{)hk|#WVfMoN2i^@F zd0L$`ure@bA>l2yS@C{YIydh9NXBAS!w7CGvGUFhUNP|~|NFR!$AvMf)sI8O-*wNt zDP8elwCrr$hi8=)st;qOrs3qR9{pc@d{KKp?&Hgbr>c+UTOIQZ&!^kROP06J6->Um zvsgVj-nq&&Y0m<>9w#oHM*j04Mm_bmKglxnZaBu<%IVt>%bX3P6>92(&6PJ81_J&C DPfQA9 literal 0 HcmV?d00001 diff --git a/Resources/screenshot1.png b/Resources/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..c1e809f5b84d9240ed55195e778e0ac7eafc558a GIT binary patch literal 30562 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 literal 0 HcmV?d00001 diff --git a/Resources/screenshot2.png b/Resources/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..fefdbfb7211ce3a1755c651256dc324c635cdaf1 GIT binary patch literal 30276 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 T>&9gN03JJQN2^CLU(A02)&o{D literal 0 HcmV?d00001 diff --git a/Resources/screenshot4.png b/Resources/screenshot4.png new file mode 100644 index 0000000000000000000000000000000000000000..a16ba7540b209a603a71ca6b4a42b14e4511363a GIT binary patch literal 16717 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 R{v~M)bWI=DJb3=@zX5fx7w`Z8 literal 0 HcmV?d00001 diff --git a/Resources/screenshot5.png b/Resources/screenshot5.png new file mode 100644 index 0000000000000000000000000000000000000000..157745ab05c8342ff6bc3b4d954fdbf1d15fe098 GIT binary patch literal 27802 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 F|6ee!a(Vy& literal 0 HcmV?d00001 diff --git a/Resources/screenshot6.png b/Resources/screenshot6.png new file mode 100644 index 0000000000000000000000000000000000000000..93ee3b4803059d31f6c5b502ab3409ce98290eb3 GIT binary patch literal 44273 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

    kpr_W7F0?H_tgaxMVl?+~~ai^_B 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 literal 0 HcmV?d00001 diff --git a/Resources/tasker/5-disable-adblock-task.jpg b/Resources/tasker/5-disable-adblock-task.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e6ad84aeecd83b4e979788c8bd3de49d905c6459 GIT binary patch literal 48273 zcmeFY2UJs8+b|ks6w9Dy5LBwd2nvG65K3s{NU;zYCIqApi6n&31EGU6Hb5XMs1P8T zK};YtA%qqIrA3h<#1IHgjC4XLbhvTedFLztzyAB)wcd5ty=#3t>zwoC?7g3Tc6s(w z_fF5wC%}4dp$5g&oQTkp%Nm*$} zjAWO%s^nhDL;Lm}QaTDes`URj?Yss6_W^zf{3NkU1+W{qO9HrSrxBna?!j(}U0-MK zpJ~tDT@v3&?%OTS)jI;%B_ScPYtP<2yT8ua*Z%I7_+}4q?{}v_(lRQSY$cDXdOXUO z{TXieYv3RIj-3Yoc=3uXpeIM&eIwf8KU|#klv9$I(-u z9X{Y&32{D90the#tZDRKKN{G|-#}Q+1g!d@-V+p*&zlgo4orji=1q^cm5V}7zQ8LV ze)UPzXn6S0o4Mbd*<=&%82kXErolKZ`3JoiU8rxny^ zoxQ)Z0>0VBmZbMWK6ZE7UzWY~{ALPd`rwFr1pOv^qX6#!+rAx0qduDV z3I2KHLs@Lqy~?b{HP0TwXoYv>QvZ_m1K7kyp+dI6DDg4f$F95Pat4!}z|nPq~p1{n1xc8|)k`Xtf>vliHI3g5j( zpLn?*GPHCFku0zu|318cFB0GmO2&n6$=tj5_(b7LhnS1M=cK(f_|VezJ#HaP{?eyk zf&#+F^AhYe3pG#O^ke+=iuvnZHo-MSa?4dtxY4VlE% z8T|e2Yl(F>wmv?7*<4!}ifVta@lb$N^M$MW>INom*IgMuIp$4hoSo8nQeM!C*2-W$ zdTd#f_6zpiagX`ncgsH??zTT>(H#4X6y`G?c`b3d<9k!em_~N_6t}aDKl#pO=*J-0 z+T~*9m90MUZO?remp?i9X_UFpI@fV%AAogSU7c*HP{6@y!i;^M0LO9raDRaI z5xqvszGMmT@%><;wd6ic<0;qm9e|hha?w_7nI?q5U~&=WKkFb8(mO%ZK+el@b-(88 zq#$b$+sJe1TnNQW_8AyelZCy^(Vo6}==*PPKAfqobu>N#XLYldw?Ab410B5jfnA@U z=xwf`OV%0nJTQP1UySMx_~G66W4Y^x$=#o{o8NF+a1wQ-9w@)`vqk3Z?`JT z4KVL6K6=CN{Broj@=w(}0CP7T*Jh~mbJXLrzXr=3dF*&nF=An#;N*INeu#-$ySV^W z>N0k(bv;&HO8U`LS&yhcrpx(LT>evzcXqUEh|6zhP75?y31QHQNJa=bY<)wfM1njD#_5AnX`UPI|aA%w9LrZ#tChkOl z?;9pOp}9p(T6DkcJBf$Ffly55vU6IWcKPHK!ZD}nr#8!@*CVRBVfZThKJ~0N`N6)s+E;Kt9LKqj13m@)c35@c&fCrB8^tXr*YkV! z7L|S+@AH*D{amJeJQ4hJ`zP?bhS%TUR2Wn3(73;?76Qqxc{(NY?Ht06)4DbmY<uB4@QT17+kjE0JahKBm-^QX_Ki=S#5>RKvV>KD$R z);e=qOZ$R4L`(gm`mO^94jleY=7_Y+QN0t&%4hYAP4#pkTE-xVF-RY(X{xKIr*&HU zECiyf1=iEOpr;49r~$dCcOC)(omYeCoj3lI!|e*&c8dj-zd4+(r1YgnGAciN1pa#QkCJ^yb@hG>!k500J*Eml{`UBJ zeWyAYZg=x`N;acwcuq(EGUCqh?;GY*Kc7Z%#Hi)OobJDJR)Cn#N$mQ{ST6#pC8Q!{a4QT{D=QwpZ_mGlGA2f zqxkrE$xq@2O$z&pgc0V@j!I?KSc@iK7(uV*Sfq8$fO~(JJ0tXP=+$f_D$@#kvRPbM zs{5_ajHWlZ#TPDUkFZRKmDufFWN%CN(QO4`ANmW4L$Se^|z z`JbYo7}>v=(Dfe00uTtMW5osMm{~BuC+p8?@}%>IyonXNS zg&x46KF>%n-)A!4!DOC1O3zErk0D|3H@cB(x%tn|a)|fxGgeZ1h899i`B#jZp}xQO zNagjmN`{B-(djHoG5p8{7Hfri=i4M!J^W{jfMDl?sb8v^@j64zq4uBC>E7KcXe3e( zyrqZStA=1StcJYE2638*wi4}icy)gkGF-TE-MvLHcyT6iITtF3Oez+u!@^zncP zZmT^FdS2+sr>Y<`;0h63glXw%J1xI@@T(NHV(B5|L`4k@WX+(K$oKIh1@{jtOI?D_ z`c<4|K|N(hA;VL#osEQF%eg|TN`L!z8Ig}blkL@0IZMgOV_H=`?WWSQwW2Dy_D4Z^ zMJnhp{NV5+RkbMjJX0zzABnG|YLW_h(ugW@ltJT$;J)(lG)Yk0d(f)OX$bdz5y^X9 z1_nOLol8$r|1u-e)0|#8_z)f`^MFnt#jMI8=$ASIP4^AKFon-V?KgM8CE<#4d9FI~>71)s z7+2LB2}r5*whOK$H$w~E>TO|@s!p0z=u}Q~bt@LsoP}0Xf3J&q#1~p3rw427hG%T$ z%tOrl9HeQAYRFIw42gm1Pt+*5r=5E`wa$nUHCMNj zW?ma@Ai(BMUYjwkt?%amyO#Y19Q@480?9{S<~#X2qIWBHQkr&#FnG= z)64f}AcW;|8Y6?9#Y=zm5ZK1E-X+J>KX&!U>anLjDyQ&^h6c93JDb!IQVj2)bWbd7 z#$4}HLLjQA;r=q_P>x;L#Bys0H5`Ap4cY!(;oCRPyh==Ig=ok7F!F zPG;+ju-K6!z+BB&gzvT`bzfV)iK?~p$F&)Fakt8RXBoSkziO#y5=Aa6K_?ogQC06)JX-ih z>czWh%-U%JJz2(rvOjFYxTWNTny)MUc@h{j&tZ>>vQsvGCtUOEO@ti{8paO~o8F9i zV+H`6_O$EE*QqGhS`S&p$=&XXCir?fhIEHhaH442y?`&9~&m{4ou?-iA7%PTh-hhYw&;Lk6gw2y@9=@fnJxZ47a z3SYH3Lq1%t^`NA*w++%q{N&fzrg%1O%(_OukzF1AUVay&=bXT_(P?&qI?{j6LTx|? zXRfCX)9h9cy+L`m+M?`hfM}(a_8V6h%_96pj{0M%)wV8?>y~k6e)xOK_}2hQ*h_hM zT(8k$Or|lUwUGk^u^mT1Mgn3c?vN*s0K3gh67FrZ3P`A^doFDk9dOWDzcs-5;2jz; zA$j9O5F|T&#GidFya{BJVy)(kN- z!KXi2%kXJ-W@IG|Ra99GWRuX#P8KDuc$gDzhKf`j$XTs)dsq5OS2n+Ls%!_a=Ux(a z8`1GDZl$?oF8xK#JN!B8z}~$mLN$}lDnYoL%uXiTDjhk5E0ucoT6ieh)dA&f?=`DQ z+&>{bGYmEk?kvwQH~c7AN~AX4;91Y&lV@sTlB;9YZGvo&wl*`Ei&OpV$$=ff^Z1^c zCrsusTzspR(?A?$SREz|8EH1~lB&R^Yr~$7*}0S;j0YxFDyeGfK~bnHyenPE;JNg) zWI1d-bfC5;a^nP|Fwl;7Oa+}z)yK+(Pvt)b9D9Zucp9x>t-`D2RuMJm#8OJ;s>E37 zp_UbD=6`v+ef%;OMnP9E!PM@#c6o0g1YAkhbk(^8izNgMPs^Yj`RxJt3fb zGA*tfb3G7hW_g1A=yNs!<;%!ChFv+2xJ74G)ZKo7xBtSaK^T@4aEw&W#tDE0f$5T1 zN<{3+{koO*mB<=vR{zqh7w7S>5w!A}*ociCz~m0#^M{3(e-pw%%8c(0pb1%bky!rX zg3wU6ucP0%kFi1vA2hS%3~*qvDfX|nUVk3&YoFHE^U}2!sXX{7p5mf1tRW}I+^Ly7 zK{*>_{mi4B1MYd%jH}3La?#8VM*u}uVK)3jK?5=_MJlR}WFWBJ!NH#!DsT8(cHZ`P zDxuYL)HI60#t|P;UTK>1me3Gl<~mkX)@ZgIpAfP(@m;Yl3%jUT*p3#qJa@Be45F&0 zT5ioh#7YJ-BO@_hy1LCu7mjx7R)o;i$wIKrzAl|Xo}<7hqB6i`>-o0ooT+^5+!Vsl z5O+A%>m0|uGb7d9eLr0#hGtn789q^SzvS))C$x%$iH&s?^3jy%EIC|J-8GjRS{>E8 zB3<3bTkJCIR8&-A#XA7! z2ZySyd|7Z`8D|MO5@=Jekw(lD&&`PoD@7i&O}0=g>yiaGgJj9`LL$bi%AAjFa;9CI zAj|Clx-d!L;ey6oYLqNk=2l~qoh!*Z87`f}Zr_E3Gotf`3s!(I;h>XwOi`8|b68mq z&IsQtQR-7vV6E~6wif>&*ldbg3+%=;hns~sl!<8NWjzB+Pux3c?#2TywVr7Lyp{Fx zd#;0n6U}jb`!(1qdXsapXaqjxV8=B*@i_rtid6Glee`UIb}*S*2pOQOTUT5EzQjWr zo|ZRY*doLX&Dgu9b6Cmg+8g`h+Wd0wfRe)M&%sHkD;yzaYn|ZUTQ#CQc<|IQo!7ms z3+shkxh7kXw&co0Z!CH&H8ye~65AU_e2#B1eWeuJ_wBvyHsKyI$AeF9d=6uO>|(`m zMRohjPb@<^{g5Q=KvH;zqRS5e367z1d0KS-^yoA!w!RZh_p^9~xu&L9E4_UEdhZHG zU*SD!df>TYOj`(NQ#}-aCI1>#zp-&OcKxRw7kgF7P$xeaIH$P;8j#k78V1#S4EpeJ zeU}+k5LqnK8=I{|iy$$_itpO;emCAG^fKg8U>N%j8->=oPur}u8XV21Y4)uQJGN-+I{sB&RCeH02RufaJW)$)=- z($q)bE;Stij{?CndPhANRfT%K{ay4Zsu2>^tp1$dqr?GAJt-ML_-Xf&gKh4;TEP%a z<$@HVLzs4z}(NdPUL7xS>$3g=??QONs#j zix^$r>6~n8UBrya5*Gmng9}>Q8DOK)o5x>E1~QCk=stso<_Q5$HL}$(yzIR6^sKN6 zJF|_-U`J=einRVv^zj0-PX*@olW_^i{wA5|!!N8w45JA4neb&&qP@yMJXPBYZX|H* ziUGA;LWyjdVH&!%n{ETyiFODXY(2@Fjz;QFy)Y@`$Srh3<}bGzD)t>bk<)1{r%7|S zuPjQVq6(%!VigKI$GgW|h|ZkVEx9+4==qlRblQck`rdVyhiD{L3O9Ql7(vQs;0V)j zXcPDaXe)iV<7tT;oj2Xu%JOTScRuw5tvI7rO{HU2p(;sO9zVZ`3|yoDLbHe>2iDQg zfwDEC!q#wvU3BW^NSG#Zh=Gc2aoGW2)MtB3>PEC<84qtv{>^agr&gxLy3;e$-j-Lw zXZ}H2#bOoJn@+_Rd1qlc_ei^`03~*h&FiT1<61E7RU3AfO`D^pm!iss1 zxE+AQ4nX$)6NmfWigX{*2cHmvuYVh&&1j-aqxD!DcyiQ^R+lc7q(8ooEZgJ_7w`Bi`mMa-o8ZQdRONU z(qO@~8)6F>d-&v{r~P@j%?FAagjYWBVtNK&TH$Mph~!#4DwMO-Cwu=S{^GqZYD%N$ zWndr$?=-3j7IXf8Sxkoc!;uizDsg5Oq^pvQKg!;>@;)`MBInT$=)x329n+Y-iZX0BcRs|)9^V6t+iMV2JQ zUtjrL{FO%A-~GBV>qD!+uPZN0lBbwK{ee`}mo>-e0^cGVra^SIFT%cz3x;xN`khXI z30<7WVjJ~!8=;V+)8x!3v{gW=L`8EB`9>2YS5@&#ob}Y*kJ>M`+QZTjewAHx%(b$t zD9G4iv;~Z0E%9ojYjmul%CN4BW3k9Q-!QcU$WqQfs4?W70kM8JGt<5U2xSe-%<*6Y zkafd4M#Jl)H?#{2rWu&hBoZr#ROD}K#+BpB;S{59?9up_r~6+nc;4-G>|Vd^XB#^C zGd(+i;|?)LV_s-VzEpmbQTJlIO=F|nv{`28u5#WLgEsQJz{pD(9PhYgIwjRCFr5u0+VHRhV!K~pFvceA1VTg70At{$B!(88YExh z9~yGX&VPzbqqzEwR?x+ieqC`n~~VKVcykb)8oGg50-8Y>2~DTc#lB*=Sk>by84wQ70ey> zp%U6jKYURu0p)eEZA1E~RdX2v=G5uXtlvzL(pkxSMU#v@-zOi8uzmuMAbAs`9F9!9 zJTb@@h5VX+ZVWq8OwLM?(W$AnDLzf0g5b`5fpxwl5 zmwx1j#ZA9szle0vgYq}BRnAfka7GY%1g;sw9zArpEVCG?Yjb{pw##aeZhU2^m`n7I z_H$Kjj`0pW4{0q4uk}E*%-|64f{v|)xDnu|xZVFjb4OMF1KxE*RJ{78Zl1P$Hpu4M zSo9x0%`lSK(uA+G&KS(;(2pOROI03n5DRLE?eg))e`A5>D6*VZA68kJVPJ$>^0Avm7?R|wgsKYQQ-mPl*RB! z={QzGBMgB6i@VjjC^p~p*lTaAqv#3w=?Q*qI#a{)W$hFx^d&pdi`D4Z#plZ&-kjd; zmiD(RlyHj`d`;1o%L;@yfo($&{#hW#c2#l*z}^AO|CT+?-c@qr6{)I`>mM6?Ewl&* zX0eojAVIOrP?qy+w-($3hGIXvxL`sqa_k=2U$w@Pul&hGbt&k815-iiy$48a4JYZO z<;N1L@`+NAZj8;bZ~s@KHYs$jikLPNs{v3mGaMK^eB|&W&uJd2svPC5!6ImxZCht> zHwAa#V_>BV!ho8j=_Zmsmyox@1B%QfIzF$p8XkM=Z##+9wl$G!MJPF$?EqdCl~*ua z7SX~sC-e7#?R3<$F?hR)5fXa)!QUSs@A3cxPWrv-MS&Iq+a3;AmZM!E>LC;#`nrb{ z3G43d0F)Uv1qy&ZOdmLNdO5V?%XqzxQpoE}Wy>oN=vy1tR3EaP}pj8lb7&)WV*x@kIY?+Fzv&PwD_` z`1Vy4BBI^aDEo*fBu=*kR*ibXScGMIasCi^7%0$e(Y5g`Kaa#cn3wUloO^<>sUW9cRDA~SHw0UOhnkxlq&<%g;v;4Ly zvBIpa4XIH?LZb*|s8z!~q4SBmY+)Nemj$zHwaww!Sy`vT6$Cd%rPv<5y7C~tcRoFh zJeh@!7g2-b*DUIc)!%dz8p?ZXI|N=#@4|t}(8>HO=>o8vMRjA4pur9F&Y6H`+LlIM zs?%xhwDaqa8>1PchNPFhS&MSIVBfjmHV0oGuqAZGo92F}$#(9cLv*UI^@lNePZ;F$ z6g`ViMTQ3?OPlJB&HT2lS+ceq{cvEUxBJcXJ!ppRRJK}G7d^WWnWci^6`_L#4X`j= zi^8mL)l+!JP2JH!C>IZlLT03Lp;k7ED(LV=iF>^@clc4fJ+LVqixe=+&Lsh@riLo8 z3cSaW;FG&=J{wJ#q}KG3(3;6c`d0pMTIOU&uZ@>1AxN#Qmpp@U^5(d{BS)}}dsl)e z#DkI-d$WGy7g$CP+Ja55d9i@S%__mXVyTGRs1j$J+kFMed6_08YhjCecYHTwt#M=c zI_89V;sfRxrcEbxxr#O*1A|}}c;-yE*piH0sW90YI4>xnf=-WKESQ*2A67`s#5jPX zE2+zPU=1OGMm&JjAfA|uOOE*zaoKzEeWbxdhX}9qfw*BMF!(5&2P#;?5{`La$OvI@ z&4b}JKo)_xKYpGV%ubz>vhikJevB%Y73!db2)h|9Oz&)ZmL@gataaftRb=QjZ+M=} zA&_12X?$upTbP`3WWRH4X+^n>G0C9Qq0ldaZIc*8NnNd?W$QM`lsbDdoEho831x#7 z;Gi^;H>X)GBqq1$APj!eQ?nK%)E(KrZ&@XWuW~^RUDiJiUl3 z63NkNnQi=#EL9s^w&`=$1<}hoA$A9lrW6{H0jk*eqsKctomay!tdq+dUZy8^Utp=C z&Q`3v>KztUA<6Irf>5zi6)P#p6Z@q3-T5jth&WCiIi5IZI!|c?Bx#67M&*`Mx z{Hu3YdbFy?d)7y>V}v|nY`$4^324C=9G%(oZT;q8m2Blai8ateiJIX8O_gP%?)#Qs z8|_y~X+Y2PklsPIXe2`j$vZB3i!4u_pIr@&oN24O94dZJ&x z780CmYz_!EJ>}-95o{++eGI%&@k}A>C!uU&LVqvQz5+90bGMQr3??4Jf9mMrZv9dB z&}uMCZ0{a#gBva?8Le@;Fhpa0uR}IW;VtGfTm1*ROEmXkuVlNaHCrVhxE@s>%(+*M zIQ$Fpr6@4WJCB})rK@Qqml&NMk;-nFdWY|ON?Q=yY@@<#+I1e{ZvEMPMGSgF)xLWy z!n(vSN$ty4D!aCruHyNwW>-)0cio4PYBeTVAqemcjk}dHcJc``1N(S-@1YF48}W2i zZiUT0DwJy!%%dcBbRc4l%Y?^biw8x)6D)_mnvTg8eFXuiE@PD0PY>gX?XaeY?^y0z zId!|!P`SduWMFu-?LAPYH88tKho@x7m>Hw#kI7AdW%RHaiiYZ$>(wiWDcv!e6FPcO zS|F_i6>rpvvFBRPRKc7O=C*cG&v-rrEwn3ng%o`vyE-<@u+G!{7o*j`X7w;1ORp}A zTQyajMV+vhyvQFXO(pp@ZyoJ`(&s2Kv!=;px!be`k*4?dWwUk-y1y09VIN5alS~RA zD=@pm<~xa=hDy!D46h=QO4b>=TH5pE?UdpZX-TRhV54yDpV2CSAKOd&44UDtbZT%> zIu&iuTnj2r)K6StZr;{vhUs)7+6>yD=B8)Kv5Gnq7x~loz0%b_4)#;g37cp0t&Ky` zka!Ml|H|%H#U)m}E|P_I@@!vP*6jH5Hi3dV=4G7b*xUM>b{`Aj%y=;nJYqzTiyH(=i=^=)u^X;CJvq>HWpsMcnp>W6v1PQMYYuIGf`EZ#titBIk&qQLi3d$i)OL;B z1ZG@%9J$&?_vBx*0RTu2WJC+clg5+Ks*c0J;=~OysYmPKYo8*7JVVC8&Wz{IoFRT$ znra(8{j4|Ci+S@&QwDd+I}GlyX1W6?p4{AZ(>La|hlrslz8mwc2X&njEy+#rJm zV3F5{?S*jlwUMEf*eY;YOgr4AM{eiOt9oUP#e0!kQ$O&%rd9=dHi{{x1Q$ zLZUmKViRk(+`tInh_orwH_yFl;{r9&cf)Dx47GCGr`2Za$H{Nb2{hhd97F79oCm2z zfg7kC_MKNl6pz5jJxnGXC*Mp)z>Sa^o22JYYf!^RMq1V%4b7jcROtF53VYY#!+z=; zuBr{0s|JVK4fU(a+#B2nXT}_j9#ao>|1>p6H^S1P%S5HXnQDTv&jmx* zr?c?-${oN7i&t23Nq71jC3Rl%+9JhQ?477!b}(Vmrk!zHL<^&L{A3Sn&k6^s`W-7< z<<>ZAOy$F%-~Sx8gF`Q)y1LcTQ_NyH&2-KhWCzf#K4~je+v0l&j0ThZI*03X=jiEU z(p%foIk(k%eYUnp`~$)^BS?3=D31)^P|s;>xUv+T==YA0@x&Yqgjg!}W{Jh@Sw-Xd z0vn>m(@5!ehC6^w*MUKDQEf!bYdd+(M@RzEIGd}pNO6iLp)xz_jmECby9`vK?E~ab z!E(uZ8gX&kFa>lBoTaSWozGJ3ed+*`GwZm=;^DTc!{JJ!56XP+H2ETmYqdUW(8Wf1CVlwzKh}sc;k;|ZU_y3Ye0;Z>`qlWA z>%&|^XsL4b<{&mh?0A#sZouUxUVt{Dj6bn9F0{{AZNKHXwq$#EW79dX;CV`XHegj7RX+G2KO7N;bTXX%Q4Lux(VmYQ{4wDMQ!jLgo1hw z`#2@FFph`xP!vP_UcNw*J17W-WkWx z)9so}NMoBgwg}V`yaT9pQ+W8ppF_5bBl3MTOt_EBt#I!YAZ&$x&DBwx(fk?-lFz+M z=_7c*fM7Fh4os&JX0nbpu!@d>zG`?fdc1&kfjS~HfdChRcK}hJ!>z&^SZ#(L9rL{| zowB*vXdTi7&wX^tNPUQHBlW$^wnoR`Dm{l8*roIDM-g3X4BfQM02IKH?C070ug~4piM;#HAk;pnt!BU>2$3syP`Adc=f`sc< zA4eDompLNb(j|7Q)s?NH>LLfRJE`LYx%l-znh@W2efXq%9@=^#m)`s$HZ_Q|_?`#HUh=4<+_bbYX}K$)cmwqAZA>yX0o9%VtWR`t%+Xr&G~3Ss zSVWo=dq^&QJ?H_DG-qy{-^l3S0nF%CtkkK8!Ul{Ni}j!Ys1@5YW}!F1e`~%-G@H+& zW(;n{{$lV_T*tG1c;@rG4#x@yu`-Lo+yY6F!ygJ3pc4t>af3XVx*O~lfVjSO%ZmKj zXx{5z_^IzS%(kq+yV6a`%kSIR%2ykK0I}Do z;^v$*3|P=1N2k1Sut^QG6sG(4$M6X8kERFmk{2|qhRwmn$|E)!F+&00i*7S@%NM!%_g^Z~KI`Ho zbZ2ZKoj~IuC7q7D(2g%18?|x^fsP{IxDI@TSTU$^nSxq8QUWfAEmDsB@YgJfuA9^` z9G8z_=l-0e%%5HU2HFHyEK0G3iL?hXQFR}%NaGB4V^t0fUkyJVt$dZDLlw$k5#WO036RM|@^>Y8Yd-#*y@O8YZEC`(4ryhXGX#TLq;MRw zj6W3w+GC{R=~>}c?9}mQtJb%Fwf^59THjh|Y#%ON_ojZ~fM8+*OTKNX?e!jwYrs#Va0Ddc8JqzXN6_Ibm{ z?GO5i34_oXUo+?YYsY zYtd{M$Hv(vX2n#=&r*f&!aLcz1GtlsVlx7_uiivOrcNGmLn56MpP|7%lSy98$qhKv zax2El&^)<*)Ugf0@xvyRWvLevwHZwxMk5i)Z7=QkCHITsXm^^RtrNpa1vsGSx4o#B zYooiHS3+dW@B>+B6BqS&Z3WT4W@R^wvMSD0Re?;c)vu(DbUd?EEx!>N=1OA$&jW&jeIU1aJ;+RVC-bsPk1yy=9= zU?HMw6zN5imH=4q?|}A~!!myMRZ)br94C%3iUuy0u3k zinNjLx%6oSa7o~}%HF?~RQqB3oNv^bJ$S!?P(L$sFxW^%HM2U(&*2` zZ+5mR-Zc}~!m5p_Td`I8c2uc(9(P<;nIcuC3*WUCKT#3|7UjpVyV1Z?= z0lVFVtx5J=_H?Wvh(izN#+2=EHQajrnW10>H?N}S%@H?-=Yt(0O*@3WyrA?IbC+1w zl)p$V!%?ldztL~XZi==TW)^$3iC0#|4XfD!)M@f4U0Fs|*qINC<$>NK$?x;xX;+ha z(#U~RFGZKdy2NIOkSf%M&Up5|asV~wW@D^bo%>uL?f}FtA@Ig8V?k~49bg3`glu*i z*_k6|J>XFu#_%;@LE`uW z@l~)W9PLK@N+Zr{``y%{q;YTPu+FxpyAQqP_iL7&q^ za)?U;YAk2B+I2=RImF~eA=03AE^e)(SL*3sw2_-%G(BbFq84MF;>Wlq!fRI`KhDf` zqYWk$43^Wo(cx9m8TCTCKec-Ht9 zRk6~956;TL_sJv8ctt2=-Lxd!D)dR2S-Ma=^fs4BPaP-Xw^%N?ua57m12Qu_?qFRloUOdkm?G zKn=S)D^8TGbBe?9_^}*|RCY5uro48L z>+|$bq1Su$2m>6<)Q^e%GDdiYo$tGZCmujO0lgO(-&A&%0vkHx1g1Bsg!EN}X@*S? zXL`^Br_phy%Fe0@44vpmWhYa-Eqc(aQL|97B!$$86Hs57NSk`8W6M}4%&bL1h|Ruk z4Qh-_@M^_|X*sa$_*+KgL9^L___*OB(tJFxUH!Iuity=Pk%Mf>@#xiLAQboh=_}fe zDQUXBvKPVh`}~OR@A8TpT*IO!(>Wu6F%dBQqn$msc; z#^#z`i!U=SXQ5e_j`Cu>X#{kb<@;322U&d`^?h~6w{8Tdxt70O$h3mvBtaInuO_B! z4$0w+!d6=sc()&m$>LxJ=7~$TMqIwNjG5UK5I79}ph(1(Ph}7=*1$SxQ^f(3cMAc% zN^+xMg9k){m_#v@9fp;%O0S#Sc-+R1TFVuefrL4{V z55 zvK%|vIV}oJcpJE}G%wb+HHaG{CWk7d$TALJ6PiumM+AF+7#Rn7KM`q|pzmI`7;!L%nQ6b$f4|SdOp0@jDby{SqMf=|g zq~xK5_FXrRyZDFT4?<=pj8xQAZ>+Qib~gK%gg^aqoSt7Kj=$HT5mbVc@$IPoPIOqy z;IF^%Nw&dPTN;C{sxgPxuvjdhsbwUYp?K+ie}!v) zinN?qN>bEuRLtV&D?X_S3NxDm%~2_{pKe=xn5O!I5YtDSI!+`7=eMAyh?&{G_C1d5 zk*&6T=km=cNSxR|VJo^lRytdc-E67tF>m+pyer)8O|~1LVn#q`Hcn&?m!1>E(7n?J z(w31B0nITv&R`qb?U~7QF`KZPl3QG7N;>nKzpHH3>gU|yuomOf*O%8b?Irf(6_coO z$zS!a0m9Yt8&0K_jJT3ItAO}1sHGO_zIF+edV>#3dAm$+|C=z=)_zbd{CsBC*S7e0 z0yQSWEc$U9KUz8Fi^z{H7ba$$K#)k^sPAIqXwOEUM#e_c+1R0jdG~z%7SZMXsiS6bQnc2R21Y{Lg zd^igZjY29A!ZVQgf@T~&tYaTh{JZ7E@-3?%L^Rd(1%mBXmuRpUd=Yu{wog!j$%he8 zJX5Zn{3@)~Qb=PLM4h7c6;j{$O6jhgq3enD#<=8&pe{_dNwcrHvuRu!UCo!XAM=pab@+kzI1c3h_trK%; zM%KDBseBSG$D&vbDL$V$ZPsz~g49$0$EeZ>>=0Eo(pA+Jb1!pgm05f?g0F%zZ0P$L zXK3Yn@-XeILaXNK=w_(THfIsg)wEQz*uh7$QuP{>;si;Sv$Q<SQ&IW<|9w&0H=2o?3FuW=^* zVfk)tW5toBLif#(;=As>0oohP*!k{SnOM))RdaQ3o5rTJGc6ZO!y^Faz8YVY?oNju zyxm*d>WAE@!IAtNjDsr*%uU9-(T2P?ZVW~N(03w91*4#dQ}{UE98g;0d$=2tL)KZ6+4&a;$wzrKAYc7TVry>p8NRK z+ma~7?9uRh_?4QCjU}$t48lP_EeWj_g+#eUg#;+lzv#oreb-Z+IYEV**{V-K4*F}> z)sbap{G@w)t*3&}gCLsr!X7cV70VH`!_?Zui%6=JQm!M%TT^X|4h8c5bL%6KZt%U>xp?!Kywp~ z>7kSH1Kp6gxG|SyIywelu_fksBW3O)|{5tmguJLy9 zAzhiL;vfLtWXo^wN~73D&3;ZL5H7Xa()d)2XlS*dVy(N*9wD~wuC2yy)9cC~2KGch z;wxDDBS-;|ww7S=UNJr;*UV@!3CbdgLYci5-{Fe2>1UI{Ado$IZ6H0382ekN(7EiD zb?exZo`yauX%!Lig(D5Nw{^biBp_=#Meq zO2S#XK3sf+IcnF~t3^-z0EHpr`i5&}H6d*RZY!ww2t3~Z4FF1lAmFFI!LL!tWLaH@Sq1rQRRoCKRZ}lq-82H@bxt zfi>eTWt)>B3xmALpvqP?b%}VACR2y2pr(#oE%=%hh)?eV;bivksr9Sq?h@MclB1 z$mL+|-@M?A%lQRR_RL(-bWS!@8 ztIrZYO;&kVqjC^-IOTn5S;l;<0--z^z&lbmjQS7r&SLt+`&HgmbP@6sB z53vu0;;X?jYZro!I+Nib8zRdwJ#EG7;8@w_qUS|#-{|FEGalKC#`44`=l!OZs5-nG ztK*+`0EDf_vC}Er&BV1VMaYP2>Gb#T!6v=jE==M7)!v(jrFE|Dqh@EfX`885O`;~+ zt-Bh{Xb|V2*>%VOT8oIYQ4Ejf+6>Op)R+K@w3+I^fN-r)1;lgRy#8B5X(B-YIyibKQ5 zta@b1Tj>Q1#h9tl_bS`;U5Up&fWnm3nMTH}-3U+$DCvN#m!Uv^Tv^xD9;dGi*fCb) z?A-~1Z51dpY-@KxRk}bvYV=!jzwY=Kl&;FTkL`x-k8RkS;YD}v_8X3ksBZgE7N-&1 z7dVr7T(~adkYYZ*)w3-uS7E(dp9qE|$o$lWYEzKgf(6g;MhuJX^xB7^dZ+LqH6$a0 zYTO%-48jsKCe*YP!zofbK@2yq#W5b4E1?fj(G0%?$a1gg=>Fh9Rv4ouPq4efiMd)M zR98&JOe0+VOmn91{#*I_)S^^lJGrUy z+tZQk%1vOxpB`T;(nV9!Hz~cMb&lY_`SOS10l^L%zI|$B=~SY8x{-exRzuE$2W8)H zdLoUfyd#3cof@ss?ndEN{aw;vX3x?1Sf&Abh~e*@Vs)GRzcY{R6KRMdxItLLxLVKh zADqse$Zqe79Hv)TM#4cfl7&r1#$3k0T$dp1v5*iP@@hU_6rr%{F23~AG00r3;gonJ+ETq7F6xXQvI3MB|^!B`|Q#XK~%X% z0f!?zST-rJ<&*`}*XI_z+Yk-{TL~4s$urujeQWO3Es}qnjJf)JW;QP$!I(I1_t>|^ zhQDI13hfH-kl{-;eCbc|hg3l($1T8bRrcP<6RecC0BKDtIkueygLlxWrW4J`;2-P) z2;H1jarXLzp6NcQv~3g0;2Bbz{S0^dWlZI zPZdYz(}0U(P1)e;ZFAbjqWUxGoLad13W*AYM{PX6hIWEd1V(h^@YxA=adH9QN+ymA zcE@Zm$IkKL2#|Xh9|q`Z1)4;FO%3Yyd%79)vA^ppAw=mv=ZjbJDE!OlqH@fv2`RH*I z8s6FKevkIiXCi;X?vaJhYWYnh>=#vgxu>bIPxk21TW?mMbu;J$j6n5oBB zd}@D}nVR9kTu^c+&NjHkUn^me&}(4FA3+k$96insbwmLyT{MYa>Y_e7v$`m*Jda2$ z_RH?5VmV^b?&xxi8nvoCy3f*_h~vMl^3nC%YIlG`x*seqE>cdQUOkg*^*P39`gNG( z!v`v_lr2*AOeu#C>RFadan9W7sQZg(ez`(X_`(9M-2?ueMDpdk^vl)S`k4}|$@qBNxc6Q7;Zhxv939(p*{Z%^H?mK-Ql`*AWqf*I9r*c_Ay zNgLUR$e;VDsPje{$0CzTuO*715_Be^FD21A;Pab*dEHqDx*mfjotcbnCq5NalgPRIgMdxB4H1s!etrr+t~oIk=d z+C>^MgpwdVO5B>8N7IQv9mQDhFFpK_pAZIxL!3ATG7w@?1c7O-X6D&mQ~z-;`TW3f zv;Oci9vC*-P`P#ao>T2YxZtgyIGA0~Yl+deqInyY6XKgqOO5(2JXHsE5L@4wEQ zPqyI_)^p=OMV1YfB#03wB*8AA$4)HXr3_&}yrx%7za3xN;^1O8zq(8g$sq0w4dHx7 z&L_U}PbhAQp8HsU@JoC1gX+2$rkO9(VCVn#+@ z45;}}@$XXay*+)S%KwzEslYM|NeZH1MeZ(*Zu4To$({tcZXn@G_3O%mIrK82CzYL< zrR;&5xa14(w65KCW)<4wC8yU5O<}WeE0-5#8B?HM{oSHh^Z;8@9KaV^f91`MISBIe z+3r@ltzzheQ8m?$Kb;j{Q`n+D(%w{XhJw&ka%ztWXn8oEbCk6o9Kmo}J&Fdip@ahN1HWF>>qg1_rFaU47{W__~bY+U??=mq>W zgS`+B+@Dmr?l*H2qVjMmPe1y8z#O%iTF;Hg$=!txuy(Qq-+OUftwVnS$;|{a; zDhr+f^RB_D1Xa|QgtoQ8Zoag<7#jCvpzdmw*Fmr_lMUQt)LY>kDhUE)i7AIGs`__Z zpSIsHiC4>_XAp+7(7gtPsR}r}+(9-47v8TD$Zd7Of3eNwKiA@ zwT#Kkvw~p6_~P$**&vqx>m_ZU+Y1r?q%#ni%l%md?NfsIj?)Y9c%{yvk)!=~f`Ar? z4{s=|w7rb_R6L>z1+D$?{a+bt?n0=Q$i2;!=SA$bT%4SaOTQLJK`x${nA4G4wOK9n zAT%eMNz@c8YZrmStlmjHRHED};b{2Ka}7)@y@;7>r8zEh(c|5QS(8$J;mdFj=ON!F zQy5nRqo!)r>U!A6b7>z%@nwHeeb~y?`_XG|>M%79q!sGjT{PvdI^NQ*RouId`m{P3 z0jHmXy2~`28Za)6YSbcNHu*FiI?&w`7(;&6D$NO(=<#9d2uC*!NF>w-<$4Ui&r*Wx zmJU=f=^}GR8Ss&aoWeq>rS=$&MQj-l9iCG4ZF3jR_Yr8Wc|U!2468U%J^V;YI$t0Ew2xj^2{kVx0YS6ayqh&q zem}fD*<~cub@$02GDC&Q0iWclsxA=4E$LtX(zaC`ckm(nVOM{!A7~G+f@whA{Mcl@=eZWE zbc=a`3rJ0L+fFH+>x<#WP0V11`%VG81Jn?rhp>@S6Q_Vl4(j7O34J*5W=vxRviFrALg(o0NUONYK!5w5GfSBYgPAEb3nEB>(K58J-7 zD>A7`P*&1HA|pmxWy1*06S$1JDx(%_?Jbk~w=XI{tfS}J1K}_Shxv^ttyy=Nz-#7p zb!v9t`fa4#e>K;gk6l0ywaQk8?}ig6lP_DON(tGD+5`kV$)zX}Zgo{SL_k0ryU(wH zn$OJId)ibMPgs;^n=?gN8C>nLVjH0FSnwMB1V}%kmo%k>lb=H}#|-wK92Vbkc`?r5 z$fvG{@T)W0q`9FbwyE~UBNmJij(C75J3xtve_OF2Obhzay=E?zE!SPJZ!~mSiAjsc zpNSO)NLcpUxaPF^+O%r?R*^_|>+XA%cdq^OyVEu;+KP|a_i zoJ{(}QE*l~EeXxIOz15ee=Gx{aqXmpPDN>4QoF7iMipuWP3nmmG0_s*p8#iWIQ-$E zidwaA>4{<_R#G1t$}AhztxIx95d1LNVZEo`BBYR=vyjlHzKAFL?)+jnANe}mt-!Cz zbXx=;658q!vS_Y3U6`$BW7a-WU#W?7{{vVSy)ceWGNO{G`rZk^8pCo}jK8xtzSi$< z@Uvr=neC@u^nwTJWMj&mRvBo%7x1#Chn7?r9M!!}F7xU*|LDwERRPrGv4oh#AWU(A z$Ro`tH!&*IZt2%LL0wXE*>G+2Q+5EuWEDNkG$r7lm@e(S#f6;EH%xr2(UuZz$`t?g*uaW|aXP3V{o(`_EcKWdlXR8!?yb zJ}|8wEQj$Je?a?7Rw`AphW&(fO4AqMZ%|=R#?m%pqbf53Qp@m@5wp4rnB_k303cbKt$@Z?Wjw+;JhTrPT_7( z^2w?ysr87H6=to3Yyjk)H)m~+91Uitav#n~BH_m)Fwr<&r;M!?eD@8-&uKuofA*yE z=amcn{dPQitO5+3Sz7kb#taTCGit&oZfVGX;Hg+8^AB#}s+*NqiVboR1W2`U;AI~sRn^IL<+E-x4_%oMP_)Rn)R^H=r-!{0&wcFq;MYWf$^~IWp z<$V6oc73eS&(8ME89gfm-tOm%j9< ze5VOFm-|lZ4ei{(xVZb9Oz!qcWuE;!W>>#y`%0R-YJ^fyXOO2^GrLe*x&F&bxd3T7 z|Eu>1`Bc4JIJ(sXh@FFn3nlk@QSA7T`mvl;Nf4>@Qg(rZGXt_Lc72$gT%Af~*IS=( z_oo`uiG}eNH<^IUl6Tg`%C!-^@6pGAVO7Y0vW$!JS4Wt*P71VeW%mgG(?V~b<1_Xj zr?%EiyOJJki+1!|rflrA*rH$VaGcuW5;aaVIn3ncY!LwGF<;`!*!XJ!Rth;fd`wFCFY@gvB_SNyEJ(yw%n5M=9oK!EF*;uXXF~B#FB$ub#ztG z(R?azf_V}mO)h?2Wo9-kqEGieWfJM&%!%1e%<+7MXPc8gh6>(R7rL%D)f}Af7kgYB zkQbURj%18%EDkfe%kYmrLZ`E%`+z)L4g``C{8LZYVu8H7MN$}}7Cn3)ZYASE4J?+$ zmk8ol^no*Xc!4X&I5b?q}j!uDtW%fFzVs-dWd)%W?%i~ z=hi1#@S$ha*lkl0Xo92guBdB;WlB1QI)l8`)PVjOg*FR%bitRfZQ6=i>O-vs`j1t@ zGh0PKGzExqSl#}jZSLqk)KQ5B$Yk{-^ZDi?O>spgT#u~5hSl}^aO|CP&F#&A$TBdq ze*J7$c3Pk&+kYgU79WQpEE0)Bxj3zxvhuo-m^e&k>%>tx6lN-=6H5aQD&;}85+SpA z3wz>mn2v4@M1%2g3ESr0Ixku+W0Ib);4LWlPP^8*zJLK-r!Rfd*wAZ)?N4(4q}M28 z%5FiExbIZeb88EoktHBC<}?9MnVp}dFmEswKd)z7ybS+{;U2^&$(uh#pqA0RNc23A z7G#lXdQa!q7!sgPnBAb7jsVOwZ0?Mn{)E@eNRR zu}@EP@VL9{;d{krX_3j=47Ax#jJ~D&PP_TOP>@ZKX`d-YCm(p~|6cg6etso<*(YjRi*6@=ii`bTia~_3Gw8psxK9d` zkg;TxXR+>Co20!zbVQ7wMm~UYlYgZX>mOsRCEE=Svuakd7Dst*|Cw@$%};hpK^c`m zmJfAcsn}jH-CW<_ZWHkw^6|bv>uV)hl^93HgKgoc224%OzL2Z6^HuD6S=Dp?^Vb!^ zNDZiUZDf=OBeF{fnlCn4xrMQtKHjO8DJ`B4B}=g|j*gZ{TWGH-hNix$SLn9| zw8sS^0T9WOaW69J3b3SJ&d3P0hR)F|s=AH1PR1u0aYjr7au9X`h$)>g-EcMxsJ1lF zMXrBWs6ITL9pw%I633y8^mNUMw}-9QT_eMyymGODCaMlDb3=4A6%EWBVo!Ps3g{}% zZx=mqH?v!BT^}8E4$|h$H|=RBoAw$!ouJ+M=IEf5c&)4@pq8r|9hx;}6H0?x#10jw zg0D#OcvS=Q5;3m4nNSaRbDvdf0!V}S*S&hCnd0=XvE&Ar+CarfZj<;)`P?aOrMzHNx=AG#GOGkv>F1yLJq&C2s@_blk?{3a;ig@H{O$1) z{xxwMpoo~FqJC7q5nITh9cA^1mFZH~jn(a;ksH>Z`nQapb@U|AIfX0}*OOVX8A5+h zcY;jkGv~TXoOHR>&QfMyX6EhfQPF2W9lw=|h?!ao^mNmUkY8A4|FJU8{ldgE@k5reF{&|J_ghW5$QyUvYELS43X0Cl(R(w1xR z=HQV*C%wr)NDp*)-EskLE$z|3G+V5YQ325bLnk5{>Z}H3&F7q&tWNFwrnW%D;{GHa z>Mnd}LGtjs1bZ7u?JORmOBtTj)K zSZLtrn07hc_b67Hmv%P$?zXS%r+37lnab_6fWb3VoAr2h+)9w{()cAaCcKJM$BDnk z_Ru03kmNnh$k<$E3hqK(<8;8wW6CqSH?Gu2E^*9%kbfbL3e5^1pyzItSis%kTmOkWNyMK3avW%D1fO}`wyGyd-|yFY4{{Ko?*QM5ZNf&N zGMne*j41b3UuOL3QdW?KE5}Rh3J9&)9B`|UJj~)+=SRK}HXD%2XzA_7-lhvRF{=$BsD)5xGY(riG3s?Fj<^7`y3@ zZ=1gwXjb;r8R*M;!0@H{dDuGalO}AVf%3>RV3y_BzU#s?Bh5{Tn;5GU?-!5IXXJ>; zx_Q{DUTDckBPm?Wo3aw{?dOSrbQxF|`@B~f-{-txJ$5dj-@7D~IK+jU0_)eTniV32 zbVsTcL}s=+0}4v^_A<9|O7~?pg~nJrL*HpahKEOD5apueID<7AF)s-QhdlzEXN`el?j^%x>oZ%>BM z>B#ufyg8Xd+vR1`(FeOfHPv<_hwk`xfv!HXJ*C>@2S*RiQdhfVOn|k091+U>Wz=l^ zaHvrW+&LZ$B-pGL(89NzWSboiFXe$<(dAlY&fq{r5j(lp&Ep*qW%0(8x5f;UEmwU~ zi*ct;@7_xbvDA6B-jFk5SoGEFKDz#I;^m5EQmUdsMq`=u`r%Q9M%I7YXnVe`;Wtvd z#e&@21d`oNmncUcRv(vY+()VVl~fp)#NyLDDOld88&~_aLB)Y)c>R(!wdUty*JH&n zwS~;LpM8PfX$H*r4Cmqku#etyDZTGikTh-Q-M}hX-{qB12;$u>*@D0@XAY+0uzwE`(Wf={EpR8co>hf<)6TU5%m@M*VTRM%`uXc>nJH)B6%rU$nE~x|33|W0)Fvl8@T`MNf#2>S z%2cY+ZjP%COC`I1KGOfqV0*y&!gk|K5Fsmg!X>NkZ!wOm^@_sxDt~0|k^u7`Rn&Wx z^OT)T#h;HLFavEq*14|&#CMNUjdvtvy_FlWp$bg@_BvksF54lB{+#8`V<9RuQjFGK zjMxLiwe7!#>*fB*M9tl1pT1bScriB3d|I%IwAi^wm!mG!7L48`cw59j3U4Q$tcP1U z7cV@hPJLq!Fi_SW;6$i8uMHX}q~64%M#_y4>GGN26-L0rY|#AoI{S{bX*q=^*)hovHXdUd4Y;g#6*vObN4lri5eV zR~Y5L@aYg65((rDk1PFxoBiYFDwi_vDGlceWCKS-EVy;7xU+7K;2skbb%$0c7>5JthN~A= zm%ZnEIfC_+nQOi}Qr|}!ztdw6NS!;9Oez1I3)K4k2a@*N&Y!B>v=+8J0WW9n#`gd| zGhh4KJ`tL(2jWZt8+3gCc;jT#7~nSXn6~EE6graq!gUhYAEg@;uyg|WJ8b*sa_fMd z>p}K_Nm2oM13bVi%2)L$GH3|00}8sVHzP%HAnnVwh;!Y+9E~oB@W>jWSI_R@2B$c; zJG^La>bk=4h>SogF^tZQWj4^3>B0w??g~@korJGX&i6BWl55Hxc;3NNKxSgCB_}?W z9M)!ABKPawP%~);E?4Rr44i-|ch>AfU7qeo0eZ~n-QKWKbX)gCe^xyWIuqR2X9(3p z#wWPk@6!0WCK)={vbQ=vD13}g-~_~*_>)=%c~z<{m4}X7(BiUz@($IUugsseiNP=+ z8SO!Wb4^?sj~#fL;>*O*r~i|QCaN{q#FK$-L(u6)xkj0Eq*31e%99)4sQkfY|M~Wb zHJ6F)GI6mS=F;e`uc9Q9XoZoOP|&PJYCq3cxI&Xp3U6(*qdD~k$TDJajLpQUGklXR z`0K*>87itcpW3AJ^x9V<;`j`2gRJz~?OSd0t(iKWcysgon90#91h9@IQ4;|#Z+pw2 zJ*V~%f}^F9o+LV|+=a3`uyTCEjDNEC1sv{txmd@S^j7njI z`=3+G<#PQb^x|4b*H-5zpL+W8PTa0FanWlC!aabwx4Nbu%M1BgMMe5f>RS8`i^iOY z&X8%i6#F(NnM`S4EJ77HC+9G^zY}6q7xUcS^{Es*LVE5ncmGE9==m?I2iYPTH|bRz zNE*&!24R>%rkPAOJ;+j40kg3X{PF7(2xKAXo`g%MiV|`=uq0Yu0i5`bE16a#W*_pJ_#3jy4CwWLrwn+T{@QC>tqGcPS-h1ESWYL4*fih#M^afCfi z0Z%N4+zNlDfKo;y;HHy6dWz;fc~+$6zTAf`1}!{nI-1oQ90h{MhtkWYe)nHrB95Q_ z(tI<#PLgwWe{@mz9E^Hjd!^Y{*lqV+_8ke}Nd6HjE~kCXq`dpV5MAGE%F1DdqPY}$ z>qbk^xxmOa_d%d2feDbhN-?l#i6O{~g~$Zkjuq_!*tnXn%wDI-?9RuMb)o#Doj><1GTkTeZyD7``lf}velz|U1jwL|+v;cFJN$1FW&fr}X; z4s-nAH>tt*8f!Ke^IZI@eqDLdiCP+(V5~TLqs!49DHgLjDyw8{pyJeAV{l_19Zeos zXCjy+=S#%p%;L(kaCZ^HOl&8C%!V*qhucK{MYYAMiy6K8uggB})TK;m<{cuPYWJm+ zaJgUvNOc)_T3*e4G`>WPFg{hEL^sZZK>^d3PhOf6sbaZKxPxO?^MspPxznnwJSwx- zbX-U6Egmm{Y+PuG808Mc&$(ps#`myCA_W_ z_^FuaOG*jG1sRT0Njrm^dy@;~4|^vppq+`i9q7dj#-0BfIAJ&0>oK?6M1B_12ciJ2 z8R~=^+}{RpIZRj@!xNCl20K-`(Mq_eGwE-Hr(+*?8VXn`KXJo@W=s8(YatH5vxNp& zxn%-YXObV!muUrsaV9!v&@WN1fcfcwJHk;?Mz;h6`%t&aLx587=34=A%90vMOU`D; z#QP0xPga1ZsH=c`iPp}a{`hg{8OecJ<0?+%iMT9e?C*rJR>2u8H3;0Rk8e<|7+-o= zHS{ikeoCC2mK0xG46+_vD{d%NDI`q}RrlO?qZZR+Os6{)vkGctv)G2f{S+>l-*--t60AD{1WX^;U#x!fd~nrbDt zV$Zo=KwWrgqbUV3jA8DsF3gIP{bDy}25@tA48U}`HLbou4=5VO}PwZD0ltZ{4kYuac>|OyT(d zn$~qDZRgT^m4c~f+Nl+-6Px@e95`L?3_r%y0mf0)(WyLWcYy8DA8z0l95);sO-j*E z!s73^ROuSze9SWkPX9bNVr;h3#YY722K5r0Uo%y%cE+5>!83;I0d8jlK(ez(^h<;5 z#zUhvQzbyGyv2U|vGAP4X5)0rytM0VkE^XDLIjE0aA*Zzy8y?ndFINu zhQ)rd3b2d|Dp5I@=R-kR!im&jE4eDDyzQtl z)gTe`1av%gPL&uuetrSBS@}Zjr<9F|nd=R+3nKN8c^3q%BFS%#U9pleL(i;vxVytz z1|5~Xa#{dNp=M?$NFRjo!LdCaUM<{1KfeIc#zSfgaY+|z}E^b&7*`Jr3 zUIDet5AueXz+}WIfNSyc@<9i$9poy@B&VIULKq;fX&2g*FQFP(K_D_3`|0o4KzM+n z#-~;6(1iv$#z4Aagx*MtWa5(MZfqvtjORJa^0WU-8QWdt3Irzb`QCejiKv0@@KC); zD>*m{|qL2Z?pghy`=Hl6|op5{GL=krc{tZ`}z(UB1>C(=}pLZxX2; zoly)@_oWjkd2{U*2?vLg18X&eJhP@p%n|D@#5M%*qdh zAhoH(FFeqMV9=rEa>p3|Dr=!T-Cq`Fr4$P9YE7YfzxkhXNdM9A_ldxK`(4VH7vgKN_>2ImJRw_Xp6 zdToAQ2$ku4+rHN@8F6X(Hka`@@tb1@$Z|jZjzjCr`x6JQefXCTi2eU{!2GfTj{y`1 zf0c>;N3XvRjekJk0|Flq_<+C%1U?|}0f7$)d_dp>0v{0gfWQX?J|OS`fe#3LK;Q!c z9}xI}zy}0AAn*Z!4+wlf-~$355cq(=2LwJK@Bx7j2z)@`0|Flq_zxm*!IKrQ8mC7x zKqfjkRYUF{2(Ikl*mo^ORm3`~P9YxLTp_1+)Al~IJgZ|HLT7Ju-=A=y_;zs2HH1P| zAt}w3o4<5(a6>*Zv8kLdYnuqx>$thP*zBe}Chkt4N^2v2yGhj_{lsIucAnQn>HTi@ zRmDjD`u5X3xZ&o}1)g@4{jp5Ul8^aMV`byFODD9O{H(4@mL&1xgq8Oy_%p96hY~1F z;6I<xV*n@*s|*J8G7HfW<`-YMk!;j}fyz<#sa zw$?}vZ+hyRAB*n&2jNpuX7qX3@xtIoLb4x)^f9qLHl-torlHYs-h*%tIswCvTpPPj z69$}NhxUYZw*{?uW-~6BA{{G zaBaYOGpRO?*%k~nsJlb!B7vgu5TALyt;V%B;P6i$Gt$R9U+`Fwx}@(Gel zuPF3dARU_TXZJC{7!(l8o3vuS+Um%{F&fQE1GB*q5vtZc+DO&2AD_v z{PP-a?l%d`luz*~h9R-}_Z06{!q&d&LkFLUTgc1$@=DjDdG%nbJN!7BY-ejYYSOOi zV#Y8^OO%hYER zDU+VoiT48FY8_7ro5{Przd>hX2RJ4s?S_{(TVSthkM~dJ_ci{+UkW>3pUvAyYE<#1 z-}+~x|9hYIjI6`&WU}M9Rxn*V(E49mqEm^I`Soa2MU1_>^IU9Bz!yzsVNH*>!7uEJ zo>wW?R4zh*y`Ru&pV)*n%ai-odi7l^ON(N;l(andB5j>^Q_{u?&deRJ?>QWR&hauZ zL~qw5UrevP+kJ{k!e$V9?YfArvZk$ zYEI2U&hJh}+oP0QyBqqo_Pn*7;JJHcopwzJ{Fkf}$W+|6RbbBz(s#i&?Mu3;KDH%* zyR%oh5OTBECUz0C$MvTkjCYV(W^uM}EUB*w)cEpH6Ta|`>q*A&eQo?)8T|NT-^(fi+JAY+CbcA9-W9R*`+?Rak0$xEXD8w<#y}N0B`e zSvI*7(}~0QOT%9@1k=u7fD;^(dP_y+GkgsMF{172j#&*d+OBULC}1VYkDTVitQ;J= zcJ#9{cw_W-;A|#}+(lDXl@>Z@7Lqre>6D!7k_VMJ+xoYJpqGC?r2p0T?b>J#LJu(d zBL}~GQEk(nBQ>TzU&^zSO_)rU3{g;;@2)KgL(A4M6vPlhnV1r!;p=mCldx4G$82|R#dUfAr5?*t}bxKE3w$W>r-7*7v&z zBIV4hN%V8A2%yAo5H8odwVSk(Ioh1SYav*CZ*AEDI)K+To9`zX<3GhS4Il6tEw22d zQ0Rfp(>jK_nOPzAV8B*PRjW&;)qQ{Q)-_$08e|!#@@b-nPY!?Ovv6rW*Dt`yBB~d> z)NA>*-of=ZVR3K5Cbf*YcSuIWp-f_CA6D$5X7~Ar^@2(XA*- zJ2;Q~p;BD8deg?%PeaPMocquE4&|iZ?Jm3Mv>&v5M+?_c$4(NY!%D zWoEa2CzLxctVP~}Reb%o{UL0Bk)QUbhxOR#rQIn8%tV)$0IxwZO3v&T-l2v|D*Gnj zZd-QKyNIS`oDIV%{q9ZK@P%PJ)t#LODOdeYJeS#P?%G{D_}TB*<3C;j0Wq#iafT~T z6~^B(W`R00XIpn;b#HuKQ}+m2olAQe;a8>Md}o8g_O>Yok6P!hu%meh`}!BU@xNv%o0;jqr>%cbdleXOd5b{E|h zy7J2Rp~_zSAO2d0sW>4?cmDp41`8-d;=c0o9|->2hqL5+@^r%i{)1X%`I!O0RGOGO zWav#zz?j$>S;M6+SIJ>Rv+kp3TL(+%L8$mk#9Ry6x!l`xw^8f(>lOY$c}V(mB7sT| zvVfbkcpIcxJ(foXYg_&_$Dgek1MH6hsd=l&iPVbWUD3mC{m?MSz$_*otpWQnMQ}%t z$y_6$ACexrL>Qf^a2;9s^1aFh?(V`)M}2kp{mykk$ZT!&L=?oEG!{b01d7*EIR+oa0%nHeQ?#!-@68$Bm>(^pG)69E zP-xCMxN8=>zgd6RQO84$iH>0&bSuFa4-#6{WE3QVof#HcpL=a)j|`G?#DLo z&>MtmCZYUKz(4;tsQ+#A03mtfrnm&C3kuXzI6j(V@JYcVmUSXZLlrt?#CQPT0xhkh zMmpch%jhIopW)k;mB^pu2B>^jMvQ13m21Dc6;dKv43#Da6?-kt`^uh|i$mY#0uCB$ zeHMd^n$tkta^I4W;-)JUMoyw@+i%xcr;pfCzEgrz3=D8l-RfR7>?p-=gw?IHQK3=S zH^Ljf{bc^F%E5?0%7kTnZ>vyE=!fb6Q_5Z=he~0pPZ;*yj9pJ9Yx!zR2|s^`Mu|2H z_dkwXYm6Az%xQUha|MpjBj7bDioVogV?ez=Id4TQ>8k+>I!(YAWxBqK=PeJrST+&p zv?LD8UFil`9xOWqOm9L>jM!WS@>c3l`p zEkDk2)66wAWdg1wjE`FXJRcJ#+>?I|InmkUXwr>LTkw*pw)>~bzp2eKE8K4u9yrbs z=f(=v;NA&BHRcpghQr*EiHQFCzj^}{G~c~&^Sufg zG2=e&_bB+iN=}je6nwj2FW_Q{A-;`HIWWjhI!Ogw|CO`0dKQA)0&YoMTVD5CZF=8O zBMf0Yi=X2)SO{`>$39AzoWocm`3}CM#j;1F#pjCCI-;Hi@&hnZxEz-IfYsMcjHZJXcHlRGWZk#weoz~#I=pm4$Rlx-R z0^R?8V+{{nC|J%@;+=Zu@&1_7@Se(j?2Vo!ejX&G4G0UO;s>^#zDS zD^N~aoWsj$NmKNNH|-7}R?FV25HuCxJE$Og(R-EVUuJCf?S4$* zy#Y0{d8sEEoI$t59H)NO(=&jRh#ep|YNIA*VSp#j*?vMIsGC3r=f7rq{__XKX&%F4}X}LI~P(-CJpRB<0IQlxK89yvhgS+hN!T?!oEJu zZ@p+9bLGx&(>TFPeq$4r1{~?tJu% zq#o^sl)U@Rr}VHN2%0Peqk-ZA36M4T+rRJc-`@{=uG??cwd{rmRDPEh@?PbZC#46m zelnFHPq!H8x|eM_8qPO$XoW0bthxjz4D{OyZRIqp?rO|Kdb4*18zKa0OIji57O#)f z*u2HDscBZX}$^}c>ZZ#Ss^o%UVP@j?b(h${XsW0&_%`9nmYG{}9ut$OurC@aDZ9D~Q{#G6L z5MNCrk>{mxPe|c;&>_UVdPtT88~Q;xZy)`zzHxnI zC~t*3I5NCbN#j8i6VTLKKc~~uUOn1Ayk@w0;l0Ym-N!mXI^_2%9|ug^|3-P+sob~y zV`4^9{ElYY&+k>fOS^q;Rd?p%y3lq$9)Q8%FW* m3*pLvc|`?Zx$t`XI95!#N1FNUAFG%DW2fO?cf9ZY!2bnL^x2~T literal 0 HcmV?d00001 diff --git a/Resources/tasker/6-disable-adblock-task-details1.jpg b/Resources/tasker/6-disable-adblock-task-details1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..90263b8be4bbe54c3548951f773d9fa3ab9d9832 GIT binary patch literal 90967 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 literal 0 HcmV?d00001 diff --git a/Resources/tasker/7-disable-adblock-task-details2.jpg b/Resources/tasker/7-disable-adblock-task-details2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d28911eadc5ec168aa7e23e3c5b50ef71af4c67a GIT binary patch literal 94214 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 literal 0 HcmV?d00001 diff --git a/Resources/test-webserver.sh b/Resources/test-webserver.sh new file mode 100644 index 0000000..8622857 --- /dev/null +++ b/Resources/test-webserver.sh @@ -0,0 +1,16 @@ +# +# Launch web server from a root shell. +# + +APP_FOLDER=$(find /data/app -type d -name "org.adaway-*") +LIB_FOLDER="${APP_FOLDER}/lib/arm64" +WEBSERVER_EXEC="$LIB_FOLDER/libwebserver_exec.so" +WEBSERVER_ARGS="--resources /data/user/0/org.adaway/files/webserver --debug" + +if [ ! -e $WEBSERVER_EXEC ]; then + echo "Web server exec not found" >&2 + exit 1 +fi + +echo "Running LD_LIBRARY_PATH=$LIB_FOLDER $WEBSERVER_EXEC $WEBSERVER_ARGS" +LD_LIBRARY_PATH=$LIB_FOLDER $WEBSERVER_EXEC $WEBSERVER_ARGS diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md new file mode 100644 index 0000000..3d80b5c --- /dev/null +++ b/THIRD_PARTY_LICENSES.md @@ -0,0 +1,78 @@ +# Licenses + +AdAway is licensed under the GPLv3+. +The file [LICENSE.md](LICENSE.md) includes the full license text. + +## AdAway Application + +AdAway is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +AdAway is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with AdAway. +If not, see . + +## Third-Party Libraries + +* Android Jetpack + https://developer.android.com/jetpack/ + Apache License v2 + +* DNS66 + https://github.com/julian-klode/dns66 + GPLv3 + +* dnsjava + https://github.com/dnsjava/dnsjava + BSD-3-Clause License + +* Guava + https://github.com/google/guava + Apache License v2 + +* libsu + https://github.com/topjohnwu/libsu + Apache License v2 + +* Material Components for Android + https://github.com/material-components/material-components-android + Apache License v2 + +* Mongoose Webserver + https://github.com/cesanta/mongoose + GPLv2 License + +* OkHttp + https://github.com/square/okhttp + Apache License v2 + +* Openssl + https://www.openssl.org/ + [OpenSSL license](https://www.openssl.org/source/license-openssl-ssleay.txt) + +* Pcap4J + https://github.com/kaitoy/pcap4j + MIT License + +* Sentry Java + https://github.com/getsentry/sentry-java + BSD 3-Clause License + +* SLF4J + https://www.slf4j.org/ + MIT License + +* Tcpdump/Libpcap + https://www.tcpdump.org/ + BSD 3-Clause License + +## Images + +* icon.svg, banner.svg + AdAway by Dominik Schürmann + New version by Alin Ţoţea-Radu + GPLv3 + +* Menu Icons + Original Android Icons diff --git a/TRANSLATING.md b/TRANSLATING.md new file mode 100644 index 0000000..c156ee8 --- /dev/null +++ b/TRANSLATING.md @@ -0,0 +1,39 @@ +# Translating to your language + +You can help us with your translation efforts! + +Please have a look at ticket No. [AdAway/AdAway#1050](https://github.com/AdAway/AdAway/issues/1050) for more detailed information, questions and discussions! +We apreciate new contributors and translations are perfect for getting started with contributing at Github in general. + +Here is the gist: +Translations are managed via the **transifex.com website**! (and Transifex' website alone, that is) + +Unfortunately, we cannot merge translations via Github directly. Please follow the steps below instead. +Sorry, but this causes some major synchronization issues if not followed. We have to consolidate many contributions by translators and sync them up to the latest state. That is just not possible via Github. + +1. Please go to **https://www.transifex.com/free-software-for-android/adaway/** +1. Login or create a new account (you can conveniently login via Github as well) +1. Enroll into the language you want to contribute to or even submit a request for a new language. + * Please keep in mind that we want to stick to the basic languages where possible (e.g. `sr` for Serbian). + Please refrain to request regional localizations (like `sr_RS`). +1. In your language section, you can browse all available resources and start **translating strings right in your browser**. + * You don't have to download anything. Just click "Translate". The downloads are meant for more advanced use cases. + +## Here are some tips for using Transifex: +* Make sure to have an eye on the **"Suggestions", "History", "Context" and "Glossary" tabs** on every entry. + * Mind translation efforts that were already done or suggested. + Basically, »*stand on the shoulders of giants*« where possible. + * Sometimes source strings change only marginally, but their translations get cleared anyway. + You can easily **recover their previous translations** by looking at the "Suggestions" tab. Just make sure they really fit the new source text and edit the translation if needed. +* Help us validate translations by **reviewing others'**. +* Some strings contain **placeholders** - like for HTML tags or numbers. +You can click on them to add them or use keyboard shortcuts (see the page settings for an overview). +* You can point out issues to the Translation Organizers via the **"Comments" tab** or just start a discussion. +* Don't forget to save your work! +* Please don't create any Translation Pull Request here on Github. + * We will integrate your contributions from time to time into the code by exporting from Transifex directly. No need to provide any files from your side. ;-) +* For more information about how to use Transifex, see https://docs.transifex.com/ + + +We will add all Transifex translations from time to time to the app. +For our Translation Organizers: You can use the CLI tool for this to retrieve translated resources from the Transifex server and add them to the Github repo. (See https://docs.transifex.com/client/ for more details about the client tool.) diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..e1d831c --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,36 @@ +#Android specific +bin +gen +obj +libs/armeabi +libs/armeabi-v7a +libs/arm64-v8a +libs/mips +libs/mips64 +libs/x86 +libs/x86_64 +local.properties +release.properties +ant.properties +*.class +*.apk + +#Gradle +.gradle +build +gradle.properties + +#Maven +target +pom.xml.* + +#Eclipse +.project +.classpath +.settings +.metadata + +#IntelliJ IDEA +.idea +*.iml +/.externalNativeBuild/ diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..b6c549e --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,149 @@ +plugins { + id 'com.android.application' +} + +boolean keyStoreDefined = project.hasProperty('signingStoreLocation') && + project.hasProperty('signingStorePassword') && + project.hasProperty('signingKeyAlias') && + project.hasProperty('signingKeyPassword') + +repositories { + maven { + url 'https://jitpack.io' + } +} + +android { + compileSdk 34 + ndkVersion '25.2.9519653' + namespace 'org.adaway' + + defaultConfig { + minSdk 26 + targetSdk 33 + versionCode libs.versions.appCode.get() as int + versionName libs.versions.appName.get() + + javaCompileOptions { + annotationProcessorOptions { + arguments = [ + "room.schemaLocation": "$projectDir/schemas".toString(), + "room.incremental" : "true" + ] + } + } + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + /* + * To sign release build, create file gradle.properties in ~/.gradle/ with this content: + * + * signingStoreLocation=/home/key.store + * signingStorePassword=xxx + * signingKeyAlias=alias + * signingKeyPassword=xxx + */ + if (keyStoreDefined) { + println "Found signature properties in gradle.properties. Build will be signed." + + signingConfigs { + release { + storeFile file(signingStoreLocation) + storePassword signingStorePassword + keyAlias signingKeyAlias + keyPassword signingKeyPassword + } + } + + buildTypes.debug.signingConfig = signingConfigs.release + buildTypes.release.signingConfig = signingConfigs.release + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + buildFeatures { + viewBinding true + } + + packagingOptions { + jniLibs { + useLegacyPackaging = true + } + } + + buildTypes { +// debug { +// shrinkResources false +// minifyEnabled false +// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' +// } + release { + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + // Do not abort build if lint finds errors + lint { + disable 'MissingTranslation' + } +} + +dependencies { + // Native modules + implementation project(':tcpdump') + implementation project(':webserver') + + // AndroidX components + implementation 'androidx.appcompat:appcompat:1.7.0' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.fragment:fragment:1.8.1' + // "fragment-ktx" is not used but was added to fix the following dependency error: + // Duplicate class androidx.lifecycle.ViewModelLazy found in modules lifecycle-viewmodel-2.5.0-runtime (androidx.lifecycle:lifecycle-viewmodel:2.5.0) and lifecycle-viewmodel-ktx-2.3.1-runtime + implementation 'androidx.fragment:fragment-ktx:1.8.1' + implementation 'androidx.paging:paging-runtime:3.3.0' + implementation 'androidx.preference:preference:1.2.1' + implementation 'androidx.recyclerview:recyclerview:1.3.2' + implementation 'androidx.room:room-runtime:2.6.1' + implementation 'androidx.room:room-paging:2.6.1' + annotationProcessor 'androidx.room:room-compiler:2.6.1' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' + implementation 'androidx.work:work-runtime:2.8.1' + implementation 'com.google.android.material:material:1.9.0' + + // Collections related + implementation libs.guava + // Network related + implementation libs.okhttp3.okhttp + // Logging related + implementation libs.timber + if (keyStoreDefined) { + implementation project(':sentrystub') + } else { + implementation platform('io.sentry:sentry-bom:7.8.0') + implementation('io.sentry:sentry-android') + implementation('io.sentry:sentry-android-fragment') + implementation('io.sentry:sentry-android-timber') + } + + // Root related + implementation libs.libsu + + // VPN related + implementation libs.bundles.pcap4j + implementation libs.dnsjava + implementation libs.slf4j.android + implementation libs.okhttp.dnsoverhttps + + // Test related + testImplementation libs.junit + testImplementation libs.json + androidTestImplementation libs.bundles.androidx.test + androidTestImplementation libs.junit +} diff --git a/app/lint.xml b/app/lint.xml new file mode 100644 index 0000000..c9b3b56 --- /dev/null +++ b/app/lint.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..9e595c1 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,38 @@ +-keep public class * extends android.content.ContentProvider + +# Temporary fix for androidx preference fragement reference +# See https://issuetracker.google.com/issues/145316223 +-keep public class org.adaway.ui.prefs.PrefsBackupRestoreFragment +-keep public class org.adaway.ui.prefs.PrefsRootFragment +-keep public class org.adaway.ui.prefs.PrefsUpdateFragment +-keep public class org.adaway.ui.prefs.PrefsVpnFragment + +-keepclassmembers class io.sentry.Sentry { + public static final boolean STUB; +} + +-dontobfuscate + +### Android Jetpack ### +-dontwarn com.google.** + +### Sentry ### +-dontwarn io.sentry.** + +### OkHttp ### +# JSR 305 annotations are for embedding nullability information. +-dontwarn javax.annotation.** +# A resource is loaded with a relative path so the package of this class must be preserved. +-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase +# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. +-dontwarn org.codehaus.mojo.animal_sniffer.* +# OkHttp platform used only on JVM and when Conscrypt dependency is available. +-dontwarn okhttp3.internal.platform.ConscryptPlatform +# Generated rules from R8 +-dontwarn org.bouncycastle.jsse.** +-dontwarn org.conscrypt.** +-dontwarn org.openjsse.** + +### dnsjava ### +-dontwarn lombok.Generated +-dontwarn sun.net.spi.nameservice.NameServiceDescriptor diff --git a/app/schemas/org.adaway.db.AppDatabase/1.json b/app/schemas/org.adaway.db.AppDatabase/1.json new file mode 100644 index 0000000..730547f --- /dev/null +++ b/app/schemas/org.adaway.db.AppDatabase/1.json @@ -0,0 +1,90 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "5175df445bc75bbbb5ea672750d7b425", + "entities": [ + { + "tableName": "hosts_sources", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `last_modified_local` INTEGER, `last_modified_online` INTEGER, PRIMARY KEY(`url`))", + "fields": [ + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastLocalModification", + "columnName": "last_modified_local", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastOnlineModification", + "columnName": "last_modified_online", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "url" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "hosts_lists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `type` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `redirection` TEXT, PRIMARY KEY(`host`))", + "fields": [ + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "host" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"5175df445bc75bbbb5ea672750d7b425\")" + ] + } +} \ No newline at end of file diff --git a/app/schemas/org.adaway.db.AppDatabase/2.json b/app/schemas/org.adaway.db.AppDatabase/2.json new file mode 100644 index 0000000..27a6560 --- /dev/null +++ b/app/schemas/org.adaway.db.AppDatabase/2.json @@ -0,0 +1,146 @@ +{ + "formatVersion": 1, + "database": { + "version": 2, + "identityHash": "e9b86296a34de1d881f8530fdf2c535d", + "entities": [ + { + "tableName": "hosts_sources", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `last_modified_local` INTEGER, `last_modified_online` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastLocalModification", + "columnName": "last_modified_local", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastOnlineModification", + "columnName": "last_modified_online", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_sources_url", + "unique": true, + "columnNames": [ + "url" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_hosts_sources_url` ON `${TABLE_NAME}` (`url`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "hosts_lists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `host` TEXT NOT NULL, `type` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `redirection` TEXT, `source_id` INTEGER NOT NULL, FOREIGN KEY(`source_id`) REFERENCES `hosts_sources`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sourceId", + "columnName": "source_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_lists_host", + "unique": true, + "columnNames": [ + "host" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_hosts_lists_host` ON `${TABLE_NAME}` (`host`)" + }, + { + "name": "index_hosts_lists_source_id", + "unique": false, + "columnNames": [ + "source_id" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_source_id` ON `${TABLE_NAME}` (`source_id`)" + } + ], + "foreignKeys": [ + { + "table": "hosts_sources", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "source_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e9b86296a34de1d881f8530fdf2c535d')" + ] + } +} \ No newline at end of file diff --git a/app/schemas/org.adaway.db.AppDatabase/3.json b/app/schemas/org.adaway.db.AppDatabase/3.json new file mode 100644 index 0000000..070e8d9 --- /dev/null +++ b/app/schemas/org.adaway.db.AppDatabase/3.json @@ -0,0 +1,151 @@ +{ + "formatVersion": 1, + "database": { + "version": 3, + "identityHash": "ace31b365ff79d4497319c74157538d7", + "entities": [ + { + "tableName": "hosts_sources", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `last_modified_local` INTEGER, `last_modified_online` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastLocalModification", + "columnName": "last_modified_local", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastOnlineModification", + "columnName": "last_modified_online", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_sources_url", + "unique": true, + "columnNames": [ + "url" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_hosts_sources_url` ON `${TABLE_NAME}` (`url`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "hosts_lists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `host` TEXT NOT NULL, `type` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `redirection` TEXT, `source_id` INTEGER NOT NULL, FOREIGN KEY(`source_id`) REFERENCES `hosts_sources`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sourceId", + "columnName": "source_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_lists_host", + "unique": false, + "columnNames": [ + "host" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_host` ON `${TABLE_NAME}` (`host`)" + }, + { + "name": "index_hosts_lists_source_id", + "unique": false, + "columnNames": [ + "source_id" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_source_id` ON `${TABLE_NAME}` (`source_id`)" + } + ], + "foreignKeys": [ + { + "table": "hosts_sources", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "source_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + } + ], + "views": [ + { + "viewName": "host_entries", + "createSql": "CREATE VIEW `${VIEW_NAME}` AS SELECT `host`, `type`, `redirection` FROM `hosts_lists` WHERE `enabled` = 1 AND ((`type` = 0 AND `host` NOT LIKE (SELECT `host` FROM `hosts_lists` WHERE `enabled` = 1 and `type` = 1)) OR `type` = 2) ORDER BY `host` ASC, `type` DESC, `redirection` ASC" + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ace31b365ff79d4497319c74157538d7')" + ] + } +} \ No newline at end of file diff --git a/app/schemas/org.adaway.db.AppDatabase/4.json b/app/schemas/org.adaway.db.AppDatabase/4.json new file mode 100644 index 0000000..3a90484 --- /dev/null +++ b/app/schemas/org.adaway.db.AppDatabase/4.json @@ -0,0 +1,187 @@ +{ + "formatVersion": 1, + "database": { + "version": 4, + "identityHash": "80b1c1d47fbd109a4f052817c9faf980", + "entities": [ + { + "tableName": "hosts_sources", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `last_modified_local` INTEGER, `last_modified_online` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localModificationDate", + "columnName": "last_modified_local", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "onlineModificationDate", + "columnName": "last_modified_online", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_sources_url", + "unique": true, + "columnNames": [ + "url" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_hosts_sources_url` ON `${TABLE_NAME}` (`url`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "hosts_lists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `host` TEXT NOT NULL, `type` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `redirection` TEXT, `source_id` INTEGER NOT NULL, FOREIGN KEY(`source_id`) REFERENCES `hosts_sources`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sourceId", + "columnName": "source_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_lists_host", + "unique": false, + "columnNames": [ + "host" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_host` ON `${TABLE_NAME}` (`host`)" + }, + { + "name": "index_hosts_lists_source_id", + "unique": false, + "columnNames": [ + "source_id" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_source_id` ON `${TABLE_NAME}` (`source_id`)" + } + ], + "foreignKeys": [ + { + "table": "hosts_sources", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "source_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "host_entries", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `type` INTEGER NOT NULL, `redirection` TEXT, PRIMARY KEY(`host`))", + "fields": [ + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "host" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_host_entries_host", + "unique": true, + "columnNames": [ + "host" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_host_entries_host` ON `${TABLE_NAME}` (`host`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '80b1c1d47fbd109a4f052817c9faf980')" + ] + } +} \ No newline at end of file diff --git a/app/schemas/org.adaway.db.AppDatabase/5.json b/app/schemas/org.adaway.db.AppDatabase/5.json new file mode 100644 index 0000000..5ec1659 --- /dev/null +++ b/app/schemas/org.adaway.db.AppDatabase/5.json @@ -0,0 +1,187 @@ +{ + "formatVersion": 1, + "database": { + "version": 5, + "identityHash": "80b1c1d47fbd109a4f052817c9faf980", + "entities": [ + { + "tableName": "hosts_sources", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `last_modified_local` INTEGER, `last_modified_online` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localModificationDate", + "columnName": "last_modified_local", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "onlineModificationDate", + "columnName": "last_modified_online", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_sources_url", + "unique": true, + "columnNames": [ + "url" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_hosts_sources_url` ON `${TABLE_NAME}` (`url`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "hosts_lists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `host` TEXT NOT NULL, `type` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `redirection` TEXT, `source_id` INTEGER NOT NULL, FOREIGN KEY(`source_id`) REFERENCES `hosts_sources`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sourceId", + "columnName": "source_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_lists_host", + "unique": false, + "columnNames": [ + "host" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_host` ON `${TABLE_NAME}` (`host`)" + }, + { + "name": "index_hosts_lists_source_id", + "unique": false, + "columnNames": [ + "source_id" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_source_id` ON `${TABLE_NAME}` (`source_id`)" + } + ], + "foreignKeys": [ + { + "table": "hosts_sources", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "source_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "host_entries", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `type` INTEGER NOT NULL, `redirection` TEXT, PRIMARY KEY(`host`))", + "fields": [ + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "host" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_host_entries_host", + "unique": true, + "columnNames": [ + "host" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_host_entries_host` ON `${TABLE_NAME}` (`host`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '80b1c1d47fbd109a4f052817c9faf980')" + ] + } +} \ No newline at end of file diff --git a/app/schemas/org.adaway.db.AppDatabase/6.json b/app/schemas/org.adaway.db.AppDatabase/6.json new file mode 100644 index 0000000..112de3d --- /dev/null +++ b/app/schemas/org.adaway.db.AppDatabase/6.json @@ -0,0 +1,211 @@ +{ + "formatVersion": 1, + "database": { + "version": 6, + "identityHash": "c53f309b3cbcdeda90c9f22573023ac2", + "entities": [ + { + "tableName": "hosts_sources", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `label` TEXT NOT NULL, `url` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `allowEnabled` INTEGER NOT NULL, `redirectEnabled` INTEGER NOT NULL, `last_modified_local` INTEGER, `last_modified_online` INTEGER, `size` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "allowEnabled", + "columnName": "allowEnabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirectEnabled", + "columnName": "redirectEnabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localModificationDate", + "columnName": "last_modified_local", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "onlineModificationDate", + "columnName": "last_modified_online", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_sources_url", + "unique": true, + "columnNames": [ + "url" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_hosts_sources_url` ON `${TABLE_NAME}` (`url`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "hosts_lists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `host` TEXT NOT NULL, `type` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `redirection` TEXT, `source_id` INTEGER NOT NULL, FOREIGN KEY(`source_id`) REFERENCES `hosts_sources`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sourceId", + "columnName": "source_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_lists_host", + "unique": false, + "columnNames": [ + "host" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_host` ON `${TABLE_NAME}` (`host`)" + }, + { + "name": "index_hosts_lists_source_id", + "unique": false, + "columnNames": [ + "source_id" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_source_id` ON `${TABLE_NAME}` (`source_id`)" + } + ], + "foreignKeys": [ + { + "table": "hosts_sources", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "source_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "host_entries", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `type` INTEGER NOT NULL, `redirection` TEXT, PRIMARY KEY(`host`))", + "fields": [ + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "host" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_host_entries_host", + "unique": true, + "columnNames": [ + "host" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_host_entries_host` ON `${TABLE_NAME}` (`host`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c53f309b3cbcdeda90c9f22573023ac2')" + ] + } +} \ No newline at end of file diff --git a/app/schemas/org.adaway.db.AppDatabase/7.json b/app/schemas/org.adaway.db.AppDatabase/7.json new file mode 100644 index 0000000..4775b2c --- /dev/null +++ b/app/schemas/org.adaway.db.AppDatabase/7.json @@ -0,0 +1,221 @@ +{ + "formatVersion": 1, + "database": { + "version": 7, + "identityHash": "dccd6211bcef97caed75ea42d7df1b32", + "entities": [ + { + "tableName": "hosts_sources", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `label` TEXT NOT NULL, `url` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `allowEnabled` INTEGER NOT NULL, `redirectEnabled` INTEGER NOT NULL, `last_modified_local` INTEGER, `last_modified_online` INTEGER, `entityTag` TEXT, `size` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "allowEnabled", + "columnName": "allowEnabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirectEnabled", + "columnName": "redirectEnabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localModificationDate", + "columnName": "last_modified_local", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "onlineModificationDate", + "columnName": "last_modified_online", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "entityTag", + "columnName": "entityTag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_sources_url", + "unique": true, + "columnNames": [ + "url" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_hosts_sources_url` ON `${TABLE_NAME}` (`url`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "hosts_lists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `host` TEXT NOT NULL, `type` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `redirection` TEXT, `source_id` INTEGER NOT NULL, FOREIGN KEY(`source_id`) REFERENCES `hosts_sources`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sourceId", + "columnName": "source_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_hosts_lists_host", + "unique": false, + "columnNames": [ + "host" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_host` ON `${TABLE_NAME}` (`host`)" + }, + { + "name": "index_hosts_lists_source_id", + "unique": false, + "columnNames": [ + "source_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_hosts_lists_source_id` ON `${TABLE_NAME}` (`source_id`)" + } + ], + "foreignKeys": [ + { + "table": "hosts_sources", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "source_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "host_entries", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `type` INTEGER NOT NULL, `redirection` TEXT, PRIMARY KEY(`host`))", + "fields": [ + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redirection", + "columnName": "redirection", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "host" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_host_entries_host", + "unique": true, + "columnNames": [ + "host" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_host_entries_host` ON `${TABLE_NAME}` (`host`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'dccd6211bcef97caed75ea42d7df1b32')" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/org/adaway/db/DbTest.java b/app/src/androidTest/java/org/adaway/db/DbTest.java new file mode 100644 index 0000000..39b7210 --- /dev/null +++ b/app/src/androidTest/java/org/adaway/db/DbTest.java @@ -0,0 +1,151 @@ +package org.adaway.db; + +import static org.adaway.db.entity.HostsSource.USER_SOURCE_ID; +import static org.adaway.db.entity.HostsSource.USER_SOURCE_URL; +import static org.adaway.db.entity.ListType.ALLOWED; +import static org.adaway.db.entity.ListType.BLOCKED; +import static org.adaway.db.entity.ListType.REDIRECTED; +import static org.junit.Assert.fail; + +import android.content.Context; + +import androidx.annotation.Nullable; +import androidx.arch.core.executor.testing.InstantTaskExecutorRule; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.Observer; +import androidx.room.Room; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.adaway.db.dao.HostEntryDao; +import org.adaway.db.dao.HostListItemDao; +import org.adaway.db.dao.HostsSourceDao; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.HostsSource; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * This class is a base class for testing database feature. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +@RunWith(AndroidJUnit4.class) +public abstract class DbTest { + protected static final int EXTERNAL_SOURCE_ID = 2; + @Rule + public TestRule rule = new InstantTaskExecutorRule(); + protected AppDatabase db; + protected HostsSourceDao hostsSourceDao; + protected HostListItemDao hostListItemDao; + protected HostEntryDao hostEntryDao; + protected LiveData blockedHostCount; + protected LiveData allowedHostCount; + protected LiveData redirectedHostCount; + protected HostsSource externalHostSource; + + protected static T getOrAwaitValue(final LiveData liveData) throws InterruptedException { + final Object[] data = new Object[1]; + final CountDownLatch latch = new CountDownLatch(1); + Observer observer = new Observer() { + @Override + public void onChanged(@Nullable T o) { + data[0] = o; + latch.countDown(); + liveData.removeObserver(this); + } + }; + liveData.observeForever(observer); + if (!latch.await(2, TimeUnit.SECONDS)) { + fail("Failed to get LiveData value in time"); + } + //noinspection unchecked + return (T) data[0]; + } + + @Before + public void init() { + createDb(); + loadDao(); + createSources(); + } + + protected void createDb() { + Context context = ApplicationProvider.getApplicationContext(); + this.db = Room.inMemoryDatabaseBuilder(context, AppDatabase.class) + .allowMainThreadQueries() + .build(); + } + + protected void loadDao() { + this.hostsSourceDao = this.db.hostsSourceDao(); + this.hostListItemDao = this.db.hostsListItemDao(); + this.hostEntryDao = this.db.hostEntryDao(); + this.blockedHostCount = this.hostListItemDao.getBlockedHostCount(); + this.allowedHostCount = this.hostListItemDao.getAllowedHostCount(); + this.redirectedHostCount = this.hostListItemDao.getRedirectHostCount(); + } + + protected void createSources() { + // Insert at least user source and external source to allow duplicate hosts to be inserted + insertSource(USER_SOURCE_ID, USER_SOURCE_URL); + insertSource(EXTERNAL_SOURCE_ID, "https://adaway.org/hosts.txt"); + this.externalHostSource = getSourceFromId(EXTERNAL_SOURCE_ID); + } + + @After + public void closeDb() { + this.db.close(); + } + + protected void insertSource(int id, String url) { + HostsSource source = new HostsSource(); + source.setId(id); + source.setLabel(url); + source.setUrl(url); + source.setEnabled(true); + this.hostsSourceDao.insert(source); + } + + protected void insertBlockedHost(String host, int sourceId) { + HostListItem item = new HostListItem(); + item.setType(BLOCKED); + item.setHost(host); + item.setEnabled(true); + item.setSourceId(sourceId); + this.hostListItemDao.insert(item); + } + + protected void insertAllowedHost(String host, int sourceId) { + HostListItem item = new HostListItem(); + item.setType(ALLOWED); + item.setHost(host); + item.setEnabled(true); + item.setSourceId(sourceId); + this.hostListItemDao.insert(item); + } + + protected void insertRedirectedHost(String host, String redirection, int sourceId) { + HostListItem item = new HostListItem(); + item.setType(REDIRECTED); + item.setHost(host); + item.setEnabled(true); + item.setRedirection(redirection); + item.setSourceId(sourceId); + this.hostListItemDao.insert(item); + } + + protected HostsSource getSourceFromId(int id) { + return this.hostsSourceDao.getAll() + .stream() + .filter(hostsSource -> hostsSource.getId() == id) + .findAny() + .orElse(null); + } +} diff --git a/app/src/androidTest/java/org/adaway/db/HostDbTest.java b/app/src/androidTest/java/org/adaway/db/HostDbTest.java new file mode 100644 index 0000000..5c1bd44 --- /dev/null +++ b/app/src/androidTest/java/org/adaway/db/HostDbTest.java @@ -0,0 +1,90 @@ +package org.adaway.db; + +import static org.adaway.db.entity.HostsSource.USER_SOURCE_ID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.adaway.db.entity.HostEntry; +import org.junit.Test; + +import java.util.List; + +/** + * This class tests {@link org.adaway.db.entity.HostListItem} database manipulations. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class HostDbTest extends DbTest { + @Test + public void testEmptyByDefault() throws InterruptedException { + assertEquals(0, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(0, getOrAwaitValue(this.allowedHostCount).intValue()); + assertEquals(0, getOrAwaitValue(this.redirectedHostCount).intValue()); + assertEquals(0, this.hostEntryDao.getAll().size()); + } + + @Test + public void testInsertThenDeleteHosts() throws InterruptedException { + // Insert blocked hosts + insertBlockedHost("advertising.apple.com", USER_SOURCE_ID); + insertBlockedHost("an.facebook.com", USER_SOURCE_ID); + this.hostEntryDao.sync(); + // Check inserting + assertEquals(2, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(0, getOrAwaitValue(this.allowedHostCount).intValue()); + assertEquals(0, getOrAwaitValue(this.redirectedHostCount).intValue()); + assertEquals(2, this.hostEntryDao.getAll().size()); + // Remove block hosts + this.hostListItemDao.deleteUserFromHost("advertising.apple.com"); + this.hostEntryDao.sync(); + // Check deletion + assertEquals(1, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(0, getOrAwaitValue(this.allowedHostCount).intValue()); + assertEquals(0, getOrAwaitValue(this.redirectedHostCount).intValue()); + assertEquals(1, this.hostEntryDao.getAll().size()); + } + + @Test + public void testDuplicateBlockedHosts() throws InterruptedException { + insertBlockedHost("advertising.apple.com", USER_SOURCE_ID); + insertBlockedHost("advertising.apple.com", EXTERNAL_SOURCE_ID); + this.hostEntryDao.sync(); + assertEquals(1, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(1, this.hostEntryDao.getAll().size()); + } + + @Test + public void testDuplicateAllowedHosts() throws InterruptedException { + insertAllowedHost("adaway.org", USER_SOURCE_ID); + insertAllowedHost("adaway.org", EXTERNAL_SOURCE_ID); + this.hostEntryDao.sync(); + assertEquals(1, getOrAwaitValue(this.allowedHostCount).intValue()); + assertEquals(0, this.hostEntryDao.getAll().size()); + } + + @Test + public void testDuplicateRedirectedHosts() throws InterruptedException { + insertRedirectedHost("github.com", "1.1.1.1", USER_SOURCE_ID); + insertRedirectedHost("github.com", "2.2.2.2", EXTERNAL_SOURCE_ID); + this.hostEntryDao.sync(); + assertEquals(1, getOrAwaitValue(this.redirectedHostCount).intValue()); + assertEquals(1, this.hostEntryDao.getAll().size()); + } + + @Test + public void testRedirectionPriority() throws InterruptedException { + // Insert two redirects for the same host + insertRedirectedHost("adaway.org", "1.1.1.1", USER_SOURCE_ID); + insertRedirectedHost("adaway.org", "2.2.2.2", EXTERNAL_SOURCE_ID); + this.hostEntryDao.sync(); + // Test inserted redirected hosts + assertEquals(1, getOrAwaitValue(this.redirectedHostCount).intValue()); + // Test inserted redirect + List entries = this.hostEntryDao.getAll(); + assertEquals(1, entries.size()); + // Test user redirect is applied in priority + HostEntry entry = this.hostEntryDao.getEntry("adaway.org"); + assertNotNull(entry); + assertEquals("1.1.1.1", entry.getRedirection()); + } +} diff --git a/app/src/androidTest/java/org/adaway/db/SourceDbTest.java b/app/src/androidTest/java/org/adaway/db/SourceDbTest.java new file mode 100644 index 0000000..075ba1e --- /dev/null +++ b/app/src/androidTest/java/org/adaway/db/SourceDbTest.java @@ -0,0 +1,113 @@ +package org.adaway.db; + +import static org.adaway.db.entity.HostsSource.USER_SOURCE_ID; +import static org.junit.Assert.assertEquals; + +import org.adaway.db.entity.HostsSource; +import org.junit.Test; + +import java.util.List; + +/** + * This class tests {@link HostsSource} database manipulations. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class SourceDbTest extends DbTest { + @Test + public void testSourceCount() { + // Test only external source is found + List sources = this.hostsSourceDao.getAll(); + assertEquals(1, sources.size()); + assertEquals("https://adaway.org/hosts.txt", sources.get(0).getUrl()); + } + + @Test + public void testSourceDeletion() throws InterruptedException { + // Insert blocked hosts + insertBlockedHost("bingads.microsoft.com", EXTERNAL_SOURCE_ID); + insertBlockedHost("ads.yahoo.com", EXTERNAL_SOURCE_ID); + this.hostEntryDao.sync(); + // Test inserted blocked hosts + assertEquals(2, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(2, this.hostEntryDao.getAll().size()); + // Delete source + this.hostsSourceDao.delete(this.externalHostSource); + this.hostEntryDao.sync(); + List sources = this.hostsSourceDao.getAll(); + assertEquals(0, sources.size()); + // Check related hosts cleaning + assertEquals(0, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(0, this.hostEntryDao.getAll().size()); + + } + + @Test + public void testBlockedHostsFromDisabledSource() throws InterruptedException { + // Insert blocked hosts + insertBlockedHost("advertising.apple.com", USER_SOURCE_ID); + insertBlockedHost("an.facebook.com", USER_SOURCE_ID); + insertBlockedHost("ads.google.com", USER_SOURCE_ID); + insertBlockedHost("bingads.microsoft.com", EXTERNAL_SOURCE_ID); + insertBlockedHost("ads.yahoo.com", EXTERNAL_SOURCE_ID); + this.hostEntryDao.sync(); + // Test inserted blocked hosts + assertEquals(5, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(5, this.hostEntryDao.getAll().size()); + // Disabled external source + this.hostsSourceDao.toggleEnabled(this.externalHostSource); + this.hostEntryDao.sync(); + assertEquals(3, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(3, this.hostEntryDao.getAll().size()); + // Re-enable external source + this.hostsSourceDao.toggleEnabled(this.externalHostSource); + this.hostEntryDao.sync(); + assertEquals(5, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(5, this.hostEntryDao.getAll().size()); + } + + @Test + public void testAllowedHostsFromDisabledSource() throws InterruptedException { + // Insert blocked and allowed host + insertBlockedHost("adaway.org", USER_SOURCE_ID); + insertAllowedHost("adaway.org", EXTERNAL_SOURCE_ID); + this.hostEntryDao.sync(); + // Test inserted blocked hosts + assertEquals(1, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(1, getOrAwaitValue(this.allowedHostCount).intValue()); + assertEquals(0, this.hostEntryDao.getAll().size()); + // Disabled a source + this.hostsSourceDao.toggleEnabled(this.externalHostSource); + this.hostEntryDao.sync(); + assertEquals(1, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(0, getOrAwaitValue(this.allowedHostCount).intValue()); + assertEquals(1, this.hostEntryDao.getAll().size()); + // Re-enable a source + this.hostsSourceDao.toggleEnabled(this.externalHostSource); + this.hostEntryDao.sync(); + assertEquals(1, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(1, getOrAwaitValue(this.allowedHostCount).intValue()); + assertEquals(0, this.hostEntryDao.getAll().size()); + } + + @Test + public void testRedirectedHostsFromDisabledSource() throws InterruptedException { + // Insert redirected hosts + insertRedirectedHost("github.com", "1.1.1.1", USER_SOURCE_ID); + insertRedirectedHost("github.com", "2.2.2.2", EXTERNAL_SOURCE_ID); + this.hostEntryDao.sync(); + // Test inserted blocked hosts + assertEquals(1, getOrAwaitValue(this.redirectedHostCount).intValue()); + assertEquals(1, this.hostEntryDao.getAll().size()); + // Disabled a source + this.hostsSourceDao.toggleEnabled(this.externalHostSource); + this.hostEntryDao.sync(); + assertEquals(1, getOrAwaitValue(this.redirectedHostCount).intValue()); + assertEquals(1, this.hostEntryDao.getAll().size()); + // Re-enable a source + this.hostsSourceDao.toggleEnabled(this.externalHostSource); + this.hostEntryDao.sync(); + assertEquals(1, getOrAwaitValue(this.redirectedHostCount).intValue()); + assertEquals(1, this.hostEntryDao.getAll().size()); + } +} diff --git a/app/src/androidTest/java/org/adaway/db/UserListTest.java b/app/src/androidTest/java/org/adaway/db/UserListTest.java new file mode 100644 index 0000000..4bbb2e6 --- /dev/null +++ b/app/src/androidTest/java/org/adaway/db/UserListTest.java @@ -0,0 +1,157 @@ +package org.adaway.db; + +import static org.adaway.db.entity.HostsSource.USER_SOURCE_ID; +import static org.adaway.db.entity.ListType.ALLOWED; +import static org.adaway.db.entity.ListType.BLOCKED; +import static org.adaway.db.entity.ListType.REDIRECTED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.adaway.db.entity.HostEntry; +import org.junit.Test; + +/** + * This class the user lists use case where user can freely add blocked, allowed and redirected hosts. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class UserListTest extends DbTest { + @Test + public void testUserList() throws InterruptedException { + testUserBlockedHosts(); + testUserAllowedHosts(); + testUserRedirectedHosts(); + } + + protected void testUserBlockedHosts() throws InterruptedException { + // Insert blocked hosts + insertBlockedHost("advertising.apple.com", USER_SOURCE_ID); + insertBlockedHost("an.facebook.com", USER_SOURCE_ID); + insertBlockedHost("ads.google.com", USER_SOURCE_ID); + insertBlockedHost("bingads.microsoft.com", USER_SOURCE_ID); + insertBlockedHost("ads.yahoo.com", USER_SOURCE_ID); + this.hostEntryDao.sync(); + // Test inserted blocked hosts + assertEquals(5, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(5, this.hostEntryDao.getAll().size()); + // Test each host type + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("advertising.apple.com")); + HostEntry entry = this.hostEntryDao.getEntry("advertising.apple.com"); + assertNotNull(entry); + assertEquals("advertising.apple.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("an.facebook.com")); + entry = this.hostEntryDao.getEntry("an.facebook.com"); + assertNotNull(entry); + assertEquals("an.facebook.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("ads.google.com")); + entry = this.hostEntryDao.getEntry("ads.google.com"); + assertNotNull(entry); + assertEquals("ads.google.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("bingads.microsoft.com")); + entry = this.hostEntryDao.getEntry("bingads.microsoft.com"); + assertNotNull(entry); + assertEquals("bingads.microsoft.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("ads.yahoo.com")); + entry = this.hostEntryDao.getEntry("ads.yahoo.com"); + assertNotNull(entry); + assertEquals("ads.yahoo.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + } + + protected void testUserAllowedHosts() throws InterruptedException { + // Insert allowed hosts + insertAllowedHost("*.google.com", USER_SOURCE_ID); + insertAllowedHost("ads.yahoo.com", USER_SOURCE_ID); + insertAllowedHost("adaway.org", USER_SOURCE_ID); + this.hostEntryDao.sync(); + // Test inserted allowed hosts + assertEquals(3, getOrAwaitValue(this.allowedHostCount).intValue()); + // Test overall list + assertEquals(5, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(3, this.hostEntryDao.getAll().size()); + // Test each host type + assertEquals(ALLOWED, this.hostEntryDao.getTypeForHost("adaway.org")); + HostEntry entry = this.hostEntryDao.getEntry("adaway.org"); + assertNull(entry); + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("advertising.apple.com")); + entry = this.hostEntryDao.getEntry("advertising.apple.com"); + assertNotNull(entry); + assertEquals("advertising.apple.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("an.facebook.com")); + entry = this.hostEntryDao.getEntry("an.facebook.com"); + assertNotNull(entry); + assertEquals("an.facebook.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + assertEquals(ALLOWED, this.hostEntryDao.getTypeForHost("ads.google.com")); + entry = this.hostEntryDao.getEntry("ads.google.com"); + assertNull(entry); + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("bingads.microsoft.com")); + entry = this.hostEntryDao.getEntry("bingads.microsoft.com"); + assertNotNull(entry); + assertEquals("bingads.microsoft.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + assertEquals(ALLOWED, this.hostEntryDao.getTypeForHost("ads.yahoo.com")); + entry = this.hostEntryDao.getEntry("ads.yahoo.com"); + assertNull(entry); + + } + + protected void testUserRedirectedHosts() throws InterruptedException { + // Insert redirected hosts + insertRedirectedHost("ads.yahoo.com", "1.2.3.4", USER_SOURCE_ID); + insertRedirectedHost("github.com", "1.2.3.4", USER_SOURCE_ID); + this.hostEntryDao.sync(); + // Test inserted redirected hosts + assertEquals(2, getOrAwaitValue(this.redirectedHostCount).intValue()); + // Test overall list + assertEquals(5, getOrAwaitValue(this.blockedHostCount).intValue()); + assertEquals(3, getOrAwaitValue(this.allowedHostCount).intValue()); + assertEquals(5, this.hostEntryDao.getAll().size()); // 3 blocked, 2 redirected + // Test each host type + assertEquals(ALLOWED, this.hostEntryDao.getTypeForHost("adaway.org")); + HostEntry entry = this.hostEntryDao.getEntry("adaway.org"); + assertNull(entry); + + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("advertising.apple.com")); + entry = this.hostEntryDao.getEntry("advertising.apple.com"); + assertNotNull(entry); + assertEquals("advertising.apple.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("an.facebook.com")); + entry = this.hostEntryDao.getEntry("an.facebook.com"); + assertNotNull(entry); + assertEquals("an.facebook.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + + assertEquals(REDIRECTED, this.hostEntryDao.getTypeForHost("github.com")); + entry = this.hostEntryDao.getEntry("github.com"); + assertNotNull(entry); + assertEquals("github.com", entry.getHost()); + assertEquals(REDIRECTED, entry.getType()); + assertEquals("1.2.3.4", entry.getRedirection()); + + assertEquals(ALLOWED, this.hostEntryDao.getTypeForHost("ads.google.com")); + entry = this.hostEntryDao.getEntry("ads.google.com"); + assertNull(entry); + + assertEquals(BLOCKED, this.hostEntryDao.getTypeForHost("bingads.microsoft.com")); + entry = this.hostEntryDao.getEntry("bingads.microsoft.com"); + assertNotNull(entry); + assertEquals("bingads.microsoft.com", entry.getHost()); + assertEquals(BLOCKED, entry.getType()); + + assertEquals(REDIRECTED, this.hostEntryDao.getTypeForHost("ads.yahoo.com")); + entry = this.hostEntryDao.getEntry("ads.yahoo.com"); + assertNotNull(entry); + assertEquals("ads.yahoo.com", entry.getHost()); + assertEquals(REDIRECTED, entry.getType()); + assertEquals("1.2.3.4", entry.getRedirection()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..14530b4 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/icon.svg b/app/src/main/assets/icon.svg new file mode 100644 index 0000000..198a5f1 --- /dev/null +++ b/app/src/main/assets/icon.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + diff --git a/app/src/main/assets/localhost-2410.crt b/app/src/main/assets/localhost-2410.crt new file mode 100644 index 0000000..c39068c --- /dev/null +++ b/app/src/main/assets/localhost-2410.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDTTCCAjWgAwIBAgIUR9ZJhU2vy/hB7LChIPgUuBEzqkQwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MTAyNzA2NTEwNVoXDTI3MTEy +NzA2NTEwNVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAoVNvAzvXCjH07lgGTwBRMOFNuvsIBzi5rtJw8EQI1+np +h8jZjGmTq759VoqsRSrzPSb8W4XNmGlg8gm0nRN9VJXE9IccWQmpbl61MG6zu9Ae +/RZ8iAuydztn16/sOVQMT3Y0dXl3Fz9VtSEAMWZG9iATlVuugShLbod+Smw3mQow +2Z6Mfg6u4vpPCLG13Hdilv+UGs19dUKlFJdsz2M/gsk0vIlyhaFc9PcyzKJG4Tk2 +XZOHEWMj7VjmEMZoUogihi9EWPLpBoi86dIWBBQfhu9HTwzl1BE33TMtYLPdKdxD +9I9QPg59wbquiVYZ3sPVISdks4qmg4NgzBJVB/tWhQIDAQABo4GWMIGTMEIGA1Ud +EQQ7MDmCCWxvY2FsaG9zdIIRKi5kb3VibGVjbGljay5uZXSCEyouZy5kb3VibGVj +bGljay5uZXSHBH8AAAEwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMB +MAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFPyh/TOOyMqOumAhxn1Jsyb09CQ3MA0G +CSqGSIb3DQEBCwUAA4IBAQAdxRNksyLjIwVaKjmC+Yx87zKw8bSmH2mm85KJ0Y7z +uoWLdiw5Lc7/uZoXEl4KGJEnAXb83lo2042WCn49bOhAtYv7tOBTvTGhCHCZ6p7u +Lk+dN8eOkfKgIpKv+tyt0y+Dl+K9m0TegBqky03xf+gjfMaNctwkxxl7Ls4CR9Lz +Bufvt1HxJkmSILmTy8ByJPG5ePN6By4YiEwg9h2Hdx7zEqAKkgHvr4Yn/c4GzDQ+ +UZZW9NCIsKkaV32UfpCSodlpc+xeayX8jxZW2GnXs31IjJd4KuNfK5g7ZuOIZN0S +iKvTwJkScrfvLlmbCqEJ7Nu4l/XR+5EAy21YNlV+mo7D +-----END CERTIFICATE----- diff --git a/app/src/main/assets/localhost-2410.key b/app/src/main/assets/localhost-2410.key new file mode 100644 index 0000000..cc6250f --- /dev/null +++ b/app/src/main/assets/localhost-2410.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQChU28DO9cKMfTu +WAZPAFEw4U26+wgHOLmu0nDwRAjX6emHyNmMaZOrvn1WiqxFKvM9Jvxbhc2YaWDy +CbSdE31UlcT0hxxZCaluXrUwbrO70B79FnyIC7J3O2fXr+w5VAxPdjR1eXcXP1W1 +IQAxZkb2IBOVW66BKEtuh35KbDeZCjDZnox+Dq7i+k8IsbXcd2KW/5QazX11QqUU +l2zPYz+CyTS8iXKFoVz09zLMokbhOTZdk4cRYyPtWOYQxmhSiCKGL0RY8ukGiLzp +0hYEFB+G70dPDOXUETfdMy1gs90p3EP0j1A+Dn3Buq6JVhnew9UhJ2SziqaDg2DM +ElUH+1aFAgMBAAECggEAErRYPjE9dP6mzc2h6Z35S+gLeZ7qZt/yU20t0AWrWtFR +lL86Tffdub9ry9FnONvKePAguUHRvRaWuWlbqgyc7uYwgEN8C2y92sCbVGK5bxCp +zyFAzgtBJWbbWtwYUOtIRBxJ58buAmGC/+20FoYruxSsAJixKmNwH4ARKfLTHWis +bwzULTA4fhmvPgv+DWg7rxOTZP+7Jl5xFQnj4lXQaTt44B9DQF7ArtVjwHJWGbAN +muc4Ij/2lzD1EFNv9hXRvPjnhdN8WuDXZ52BTNj3ZXEYYyjw6Mvy7Qtsiz4FovpT +UvIsQgUyvkyukKX+8rQb+JAcfZQHnfXFSoZyIJ/KDwKBgQDQAY7L6o/ZwQ2FjyyN +K0Zu4oozQh1VM6C8eGtOsa6b+1y1d3RQg0JYb4ay1KwyFAUVnDSx/dNVg8LxVbL+ +st0EAUYmyNtozAerkAAdbYLr/mDKM4pYp9OzamqJYaUVXDa70zEOe/Q86a4KKa8l +mr6jfd2+OHhBjFfc/UWfZKWAiwKBgQDGjJXM8KvFIqkBnNqcy1NhhtUUAwzV9oye +HsagZBiTDXeCq2FUOJRh1474az+X12PTCDHNobvhGwz+eYe8yfDmILE9RmjbtCwO +YzTFuEyzFxG4aWAVV9/u+qWu8LQFeXRVOyztNFmIXqWaaCg0tahaVKI0dukMk+/1 +M4b/fGzXLwKBgCBxfcJUjadbMy63zC0gqNW2w/OGxmh5qwJ6jdIyaJevtyAex6ef +MYP1sT7HaSxObxSVzqpMeuAFsyxNP6P2Zf6v7C80ePR5jmC2Dy6H3DnO7W3caCG3 +249Kc9+FuWgBgA//utEViFzP3fN72PO2lTGO+j0nNaqTp0iywF9CJYZNAoGAXo/k +ZKgXVxuL3K3E3Lpl6uQZpZ9SRLFZBZHozcj+f0MBsWVIRKFx4iuU9zG1Ju85pu+X +MLWf0rVcefKNuFeBeUkGwQVAuarU9MFBCA4f0YfiM69USLYCfEI6GNihFJ5kzpcR +baPqJG3Xd3O1+myuUt9OJaiglBH9Tg4NdK7g85cCgYAYL3r9a8LosXGwtqiahX9o +Hyu/lRrKDH6yvUN2YeHN10pyY8rkdLAZ6E6imgxHqA8n8AibhkoaGpTrBlKRgP1/ +MMjeqy3C3hYjBQdfs+Vv6YtsufhegHs84/tgDxyfkWcljeXg2GoZvPQxANNZe8QE +JTaivHj2kiF8ZakITrXT+A== +-----END PRIVATE KEY----- diff --git a/app/src/main/assets/test.html b/app/src/main/assets/test.html new file mode 100644 index 0000000..9ed02ca --- /dev/null +++ b/app/src/main/assets/test.html @@ -0,0 +1,13 @@ + + + + + + Web server test page + + +

    Web server works fine

    +AdAway logo when option is enabled +

    If you can see this page, that means the web server is working fine and its certificate is installed.

    + + \ No newline at end of file diff --git a/app/src/main/icon-web.png b/app/src/main/icon-web.png new file mode 100644 index 0000000000000000000000000000000000000000..efbe973043d36c16f929d78ef20e6ac6fec5c460 GIT binary patch literal 15501 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 literal 0 HcmV?d00001 diff --git a/app/src/main/java/org/adaway/AdAwayApplication.java b/app/src/main/java/org/adaway/AdAwayApplication.java new file mode 100644 index 0000000..2e8671f --- /dev/null +++ b/app/src/main/java/org/adaway/AdAwayApplication.java @@ -0,0 +1,76 @@ +package org.adaway; + +import android.app.Application; + +import org.adaway.helper.NotificationHelper; +import org.adaway.helper.PreferenceHelper; +import org.adaway.model.adblocking.AdBlockMethod; +import org.adaway.model.adblocking.AdBlockModel; +import org.adaway.model.source.SourceModel; +import org.adaway.model.update.UpdateModel; +import org.adaway.util.log.ApplicationLog; + +/** + * This class is a custom {@link Application} for AdAway app. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class AdAwayApplication extends Application { + /** + * The common source model for the whole application. + */ + private SourceModel sourceModel; + /** + * The common ad block model for the whole application. + */ + private AdBlockModel adBlockModel; + /** + * The common update model for the whole application. + */ + private UpdateModel updateModel; + + @Override + public void onCreate() { + // Delegate application creation + super.onCreate(); + // Initialize logging + ApplicationLog.init(this); + // Create notification channels + NotificationHelper.createNotificationChannels(this); + // Create models + this.sourceModel = new SourceModel(this); + this.updateModel = new UpdateModel(this); + } + + /** + * Get the source model. + * + * @return The common source model for the whole application. + */ + public SourceModel getSourceModel() { + return this.sourceModel; + } + + /** + * Get the ad block model. + * + * @return The common ad block model for the whole application. + */ + public AdBlockModel getAdBlockModel() { + // Check cached model + AdBlockMethod method = PreferenceHelper.getAdBlockMethod(this); + if (this.adBlockModel == null || this.adBlockModel.getMethod() != method) { + this.adBlockModel = AdBlockModel.build(this, method); + } + return this.adBlockModel; + } + + /** + * Get the update model. + * + * @return Teh common update model for the whole application. + */ + public UpdateModel getUpdateModel() { + return this.updateModel; + } +} diff --git a/app/src/main/java/org/adaway/broadcast/BootReceiver.java b/app/src/main/java/org/adaway/broadcast/BootReceiver.java new file mode 100644 index 0000000..cc0ba35 --- /dev/null +++ b/app/src/main/java/org/adaway/broadcast/BootReceiver.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.broadcast; + +import static android.content.Intent.ACTION_BOOT_COMPLETED; +import static org.adaway.model.adblocking.AdBlockMethod.ROOT; +import static org.adaway.model.adblocking.AdBlockMethod.VPN; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import org.adaway.helper.PreferenceHelper; +import org.adaway.model.adblocking.AdBlockMethod; +import org.adaway.util.WebServerUtils; +import org.adaway.vpn.VpnServiceControls; + +import timber.log.Timber; + +/** + * This broadcast receiver is executed after boot. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class BootReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_BOOT_COMPLETED.equals(intent.getAction())) { + Timber.d("BootReceiver invoked."); + AdBlockMethod adBlockMethod = PreferenceHelper.getAdBlockMethod(context); + // Start web server on boot if enabled in preferences + if (adBlockMethod == ROOT && PreferenceHelper.getWebServerEnabled(context)) { + WebServerUtils.startWebServer(context); + } + if (adBlockMethod == VPN && PreferenceHelper.getVpnServiceOnBoot(context)) { + // Ensure VPN is prepared + Intent prepareIntent = android.net.VpnService.prepare(context); + if (prepareIntent != null) { + context.startActivity(prepareIntent); + } + // Start VPN service if enabled in preferences + VpnServiceControls.start(context); + } + } + } +} diff --git a/app/src/main/java/org/adaway/broadcast/Command.java b/app/src/main/java/org/adaway/broadcast/Command.java new file mode 100644 index 0000000..a3a541a --- /dev/null +++ b/app/src/main/java/org/adaway/broadcast/Command.java @@ -0,0 +1,57 @@ +package org.adaway.broadcast; + +import android.content.Intent; + +import timber.log.Timber; + +/** + * This enumerate lists the commands of {@link CommandReceiver}. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public enum Command { + /** + * Start the ad-blocking. + */ + START, + /** + * Stop the ad-blocking. + */ + STOP, + /** + * Unknown command. + */ + UNKNOWN; + + private static final String INTENT_EXTRA_COMMAND = "COMMAND"; + + /** + * Read command from intent. + * + * @param intent The intent to read command from. + * @return The read intent. + */ + public static Command readFromIntent(Intent intent) { + Command command = UNKNOWN; + if (intent != null && intent.hasExtra(INTENT_EXTRA_COMMAND)) { + String commandName = intent.getStringExtra(INTENT_EXTRA_COMMAND); + if (commandName != null) { + try { + command = Command.valueOf(commandName); + } catch (IllegalArgumentException e) { + Timber.w("Failed to read command named %s.", commandName); + } + } + } + return command; + } + + /** + * Append command to intent. + * + * @param intent The intent to append command to. + */ + public void appendToIntent(Intent intent) { + intent.putExtra(INTENT_EXTRA_COMMAND, name()); + } +} diff --git a/app/src/main/java/org/adaway/broadcast/CommandReceiver.java b/app/src/main/java/org/adaway/broadcast/CommandReceiver.java new file mode 100644 index 0000000..7588474 --- /dev/null +++ b/app/src/main/java/org/adaway/broadcast/CommandReceiver.java @@ -0,0 +1,53 @@ +package org.adaway.broadcast; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import org.adaway.AdAwayApplication; +import org.adaway.model.adblocking.AdBlockModel; +import org.adaway.model.error.HostErrorException; +import org.adaway.util.AppExecutors; + +import timber.log.Timber; + +/** + * This broadcast receiver listens to commands from broadcast. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class CommandReceiver extends BroadcastReceiver { + /** + * This action allows to send commands to the application. See {@link Command} for extra values. + */ + public static final String SEND_COMMAND_ACTION = "org.adaway.action.SEND_COMMAND"; + private static final AppExecutors EXECUTORS = AppExecutors.getInstance(); + + @Override + public void onReceive(Context context, Intent intent) { + if (SEND_COMMAND_ACTION.equals(intent.getAction())) { + AdBlockModel adBlockModel = ((AdAwayApplication) context.getApplicationContext()).getAdBlockModel(); + Command command = Command.readFromIntent(intent); + Timber.i("CommandReceiver invoked with command %s.", command); + EXECUTORS.diskIO().execute(() -> executeCommand(adBlockModel, command)); + } + } + + private void executeCommand(AdBlockModel adBlockModel, Command command) { + try { + switch (command) { + case START: + adBlockModel.apply(); + break; + case STOP: + adBlockModel.revert(); + break; + case UNKNOWN: + Timber.i("Failed to run an unsupported command."); + break; + } + } catch (HostErrorException e) { + Timber.w(e, "Failed to apply ad block command " + command + "."); + } + } +} diff --git a/app/src/main/java/org/adaway/broadcast/UpdateReceiver.java b/app/src/main/java/org/adaway/broadcast/UpdateReceiver.java new file mode 100644 index 0000000..9951438 --- /dev/null +++ b/app/src/main/java/org/adaway/broadcast/UpdateReceiver.java @@ -0,0 +1,28 @@ +package org.adaway.broadcast; + +import static android.content.Intent.ACTION_MY_PACKAGE_REPLACED; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import org.adaway.AdAwayApplication; + +import timber.log.Timber; + +/** + * This broadcast receiver is executed at application update. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class UpdateReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_MY_PACKAGE_REPLACED.equals(intent.getAction())) { + AdAwayApplication application = (AdAwayApplication) context.getApplicationContext(); + String versionName = application.getUpdateModel().getVersionName(); + Timber.d("UpdateReceiver invoked"); + Timber.i("Application update to version %s", versionName); + } + } +} diff --git a/app/src/main/java/org/adaway/db/AppDatabase.java b/app/src/main/java/org/adaway/db/AppDatabase.java new file mode 100644 index 0000000..2a5fbea --- /dev/null +++ b/app/src/main/java/org/adaway/db/AppDatabase.java @@ -0,0 +1,134 @@ +package org.adaway.db; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; +import androidx.room.TypeConverters; +import androidx.sqlite.db.SupportSQLiteDatabase; + +import org.adaway.R; +import org.adaway.db.converter.ListTypeConverter; +import org.adaway.db.converter.ZonedDateTimeConverter; +import org.adaway.db.dao.HostEntryDao; +import org.adaway.db.dao.HostListItemDao; +import org.adaway.db.dao.HostsSourceDao; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.HostsSource; +import org.adaway.db.entity.HostEntry; +import org.adaway.util.AppExecutors; + +import static org.adaway.db.Migrations.MIGRATION_1_2; +import static org.adaway.db.Migrations.MIGRATION_2_3; +import static org.adaway.db.Migrations.MIGRATION_3_4; +import static org.adaway.db.Migrations.MIGRATION_4_5; +import static org.adaway.db.Migrations.MIGRATION_5_6; +import static org.adaway.db.Migrations.MIGRATION_6_7; +import static org.adaway.db.entity.HostsSource.USER_SOURCE_ID; +import static org.adaway.db.entity.HostsSource.USER_SOURCE_URL; + +/** + * This class is the application database based on Room. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +@Database(entities = {HostsSource.class, HostListItem.class, HostEntry.class}, version = 7) +@TypeConverters({ListTypeConverter.class, ZonedDateTimeConverter.class}) +public abstract class AppDatabase extends RoomDatabase { + /** + * The database singleton instance. + */ + private static volatile AppDatabase instance; + + /** + * Get the database instance. + * + * @param context The application context. + * @return The database instance. + */ + public static AppDatabase getInstance(Context context) { + if (instance == null) { + synchronized (AppDatabase.class) { + if (instance == null) { + instance = Room.databaseBuilder( + context.getApplicationContext(), + AppDatabase.class, + "app.db" + ).addCallback(new Callback() { + @Override + public void onCreate(@NonNull SupportSQLiteDatabase db) { + AppExecutors.getInstance().diskIO().execute( + () -> AppDatabase.initialize(context, instance) + ); + } + }).addMigrations( + MIGRATION_1_2, + MIGRATION_2_3, + MIGRATION_3_4, + MIGRATION_4_5, + MIGRATION_5_6, + MIGRATION_6_7 + ).build(); + } + } + } + return instance; + } + + /** + * Initialize the database content. + */ + private static void initialize(Context context, AppDatabase database) { + // Check if there is no hosts source + HostsSourceDao hostsSourceDao = database.hostsSourceDao(); + if (!hostsSourceDao.getAll().isEmpty()) { + return; + } + // User list + HostsSource userSource = new HostsSource(); + userSource.setLabel(context.getString(R.string.hosts_user_source)); + userSource.setId(USER_SOURCE_ID); + userSource.setUrl(USER_SOURCE_URL); + userSource.setAllowEnabled(true); + userSource.setRedirectEnabled(true); + hostsSourceDao.insert(userSource); + // AdAway official + HostsSource source1 = new HostsSource(); + source1.setLabel(context.getString(R.string.hosts_adaway_source)); + source1.setUrl("https://adaway.org/hosts.txt"); + hostsSourceDao.insert(source1); + // StevenBlack + HostsSource source2 = new HostsSource(); + source2.setLabel(context.getString(R.string.hosts_stevenblack_source)); + source2.setUrl("https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"); + hostsSourceDao.insert(source2); + // Pete Lowe + HostsSource source3 = new HostsSource(); + source3.setLabel(context.getString(R.string.hosts_peterlowe_source)); + source3.setUrl("https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext"); + hostsSourceDao.insert(source3); + } + + /** + * Get the hosts source DAO. + * + * @return The hosts source DAO. + */ + public abstract HostsSourceDao hostsSourceDao(); + + /** + * Get the hosts list item DAO. + * + * @return The hosts list item DAO. + */ + public abstract HostListItemDao hostsListItemDao(); + + /** + * Get the hosts entry DAO. + * + * @return The hosts entry DAO. + */ + public abstract HostEntryDao hostEntryDao(); +} diff --git a/app/src/main/java/org/adaway/db/Migrations.java b/app/src/main/java/org/adaway/db/Migrations.java new file mode 100644 index 0000000..69c0b36 --- /dev/null +++ b/app/src/main/java/org/adaway/db/Migrations.java @@ -0,0 +1,123 @@ +package org.adaway.db; + +import static org.adaway.db.entity.HostsSource.USER_SOURCE_ID; +import static org.adaway.db.entity.HostsSource.USER_SOURCE_URL; + +import androidx.annotation.NonNull; +import androidx.room.migration.Migration; +import androidx.sqlite.db.SupportSQLiteDatabase; + +/** + * This class declares database schema migrations. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +final class Migrations { + /** + * Private constructor of utility class. + */ + private Migrations() { + + } + + /** + * The migration script from v1 to v2. + */ + static final Migration MIGRATION_1_2 = new Migration(1, 2) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + // Add hosts sources id column and migrate data + database.execSQL("CREATE TABLE `hosts_sources_new` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `last_modified_local` INTEGER, `last_modified_online` INTEGER)"); + database.execSQL("INSERT INTO `hosts_sources_new` (`id`, `url`, `enabled`) VALUES (" + USER_SOURCE_ID + ", '" + USER_SOURCE_URL + "', 1)"); + database.execSQL("INSERT INTO `hosts_sources_new` (`url`, `enabled`, `last_modified_local`, `last_modified_online`) SELECT `url`, `enabled`, `last_modified_local`, `last_modified_online` FROM `hosts_sources`"); + database.execSQL("DROP TABLE `hosts_sources`"); + database.execSQL("ALTER TABLE `hosts_sources_new` RENAME TO `hosts_sources`"); + // Add hosts list source id and migrate data + database.execSQL("CREATE TABLE `hosts_lists_new` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `host` TEXT NOT NULL, `type` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `redirection` TEXT, `source_id` INTEGER NOT NULL, FOREIGN KEY(`source_id`) REFERENCES `hosts_sources`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )"); + database.execSQL("INSERT INTO `hosts_lists_new` (`host`, `type`, `enabled`, `redirection`, `source_id`) SELECT `host`, `type`, `enabled`, `redirection`, " + USER_SOURCE_ID + " FROM `hosts_lists`"); + database.execSQL("DROP TABLE `hosts_lists`"); + database.execSQL("ALTER TABLE `hosts_lists_new` RENAME TO `hosts_lists`"); + // Create index + database.execSQL("CREATE UNIQUE INDEX `index_hosts_sources_url` ON `hosts_sources` (`url`)"); + database.execSQL("CREATE UNIQUE INDEX `index_hosts_lists_host` ON `hosts_lists` (`host`)"); + database.execSQL("CREATE INDEX `index_hosts_lists_source_id` ON `hosts_lists` (`source_id`)"); + } + }; + /** + * The migration script from v2 to v3. + */ + static final Migration MIGRATION_2_3 = new Migration(2, 3) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + database.execSQL("CREATE VIEW `host_entries` AS SELECT `host`, `type`, `redirection` FROM `hosts_lists` WHERE `enabled` = 1 AND ((`type` = 0 AND `host` NOT LIKE (SELECT `host` FROM `hosts_lists` WHERE `enabled` = 1 and `type` = 1)) OR `type` = 2) ORDER BY `host` ASC, `type` DESC, `redirection` ASC"); + } + }; + + /** + * Migration script from v3 to v4. + */ + static final Migration MIGRATION_3_4 = new Migration(3, 4) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + // Remove unique constraint to hosts_lists.host column + database.execSQL("DROP INDEX `index_hosts_lists_host`"); + database.execSQL("CREATE INDEX `index_hosts_lists_host` ON `hosts_lists` (`host`)"); + // Update host_entries view + database.execSQL("DROP VIEW `host_entries`"); + database.execSQL("CREATE VIEW `host_entries` AS SELECT `host`, `type`, `redirection` FROM `hosts_lists` WHERE `enabled` = 1 AND ((`type` = 0 AND `host` NOT LIKE (SELECT `host` FROM `hosts_lists` WHERE `enabled` = 1 and `type` = 1)) OR `type` = 2) GROUP BY `host` ORDER BY `host` ASC, `type` DESC, `redirection` ASC"); + } + }; + + /** + * Migration script from v4 to v5. + */ + static final Migration MIGRATION_4_5 = new Migration(4, 5) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + // Remove host_entries view + database.execSQL("DROP VIEW `host_entries`"); + // Create new host_entries table + database.execSQL("CREATE TABLE IF NOT EXISTS `host_entries` (`host` TEXT NOT NULL, `type` INTEGER NOT NULL, `redirection` TEXT, PRIMARY KEY(`host`))"); + database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_host_entries_host` ON `host_entries` (`host`)"); + } + }; + + /** + * Migration script from v5 to v6. + */ + static final Migration MIGRATION_5_6 = new Migration(5, 6) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + // Update hosts_sources table + database.execSQL("ALTER TABLE `hosts_sources` ADD `label` TEXT NOT NULL DEFAULT \"\""); + database.execSQL("ALTER TABLE `hosts_sources` ADD `allowEnabled` INTEGER NOT NULL DEFAULT 0"); + database.execSQL("ALTER TABLE `hosts_sources` ADD `redirectEnabled` INTEGER NOT NULL DEFAULT 0"); + database.execSQL("ALTER TABLE `hosts_sources` ADD `size` INTEGER NOT NULL DEFAULT 0"); + // Set default values to new source attributes + database.execSQL("UPDATE `hosts_sources` SET `label` = `url`"); + // Update user hosts list + database.execSQL("UPDATE `hosts_sources` SET `url` = \"content://org.adaway/user/hosts\", `allowEnabled` = 1, `redirectEnabled` = 1 WHERE `url` = \"file://app/user/hosts\""); + // Update default hosts source label + database.execSQL("UPDATE `hosts_sources` SET `label` = \"AdAway official hosts\" WHERE `url` = \"https://adaway.org/hosts.txt\""); + database.execSQL("UPDATE `hosts_sources` SET `label` = \"StevenBlack Unified hosts\" WHERE `url` = \"https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts\""); + database.execSQL("UPDATE `hosts_sources` SET `label` = \"Pete Lowe blocklist hosts\" WHERE `url` = \"https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext\""); + // Reset local date to rebuild cache + database.execSQL("UPDATE `hosts_sources` SET `last_modified_local` = NULL"); + // Update hosts source date format + database.execSQL("UPDATE `hosts_sources` SET `last_modified_online` = `last_modified_online` / 1000"); + // Clear previous file type hosts sources + database.execSQL("DELETE FROM `hosts_sources` WHERE `url` LIKE \"file://%\""); + } + }; + + /** + * Migration script from v6 to v7. + */ + static final Migration MIGRATION_6_7 = new Migration(6, 7) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + // Update hosts_sources table + database.execSQL("ALTER TABLE `hosts_sources` ADD `entityTag` TEXT DEFAULT NULL"); + } + }; +} diff --git a/app/src/main/java/org/adaway/db/converter/ListTypeConverter.java b/app/src/main/java/org/adaway/db/converter/ListTypeConverter.java new file mode 100644 index 0000000..d3e74f1 --- /dev/null +++ b/app/src/main/java/org/adaway/db/converter/ListTypeConverter.java @@ -0,0 +1,26 @@ +package org.adaway.db.converter; + +import androidx.room.TypeConverter; + +import org.adaway.db.entity.ListType; + +/** + * This class is a type converter for Room to support {@link ListType} type. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class ListTypeConverter { + private ListTypeConverter() { + // Prevent instantiation + } + + @TypeConverter + public static ListType fromValue(Integer value) { + return value == null ? null : ListType.fromValue(value); + } + + @TypeConverter + public static Integer typeToValue(ListType type) { + return type == null ? null : type.getValue(); + } +} diff --git a/app/src/main/java/org/adaway/db/converter/ZonedDateTimeConverter.java b/app/src/main/java/org/adaway/db/converter/ZonedDateTimeConverter.java new file mode 100644 index 0000000..3621187 --- /dev/null +++ b/app/src/main/java/org/adaway/db/converter/ZonedDateTimeConverter.java @@ -0,0 +1,30 @@ +package org.adaway.db.converter; + +import androidx.room.TypeConverter; + +import java.time.LocalDateTime; +import java.time.ZonedDateTime; + +import static java.time.ZoneOffset.UTC; + +/** + * This class is a type converter for Room to support {@link java.time.ZonedDateTime} type. + * It is stored as a Unix epoc timestamp. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class ZonedDateTimeConverter { + private ZonedDateTimeConverter() { + // Prevent instantiation + } + + @TypeConverter + public static ZonedDateTime fromTimestamp(Long value) { + return value == null ? null : ZonedDateTime.of(LocalDateTime.ofEpochSecond(value, 0, UTC), UTC); + } + + @TypeConverter + public static Long toTimestamp(ZonedDateTime zonedDateTime) { + return zonedDateTime == null ? null : zonedDateTime.toEpochSecond(); + } +} diff --git a/app/src/main/java/org/adaway/db/dao/HostEntryDao.java b/app/src/main/java/org/adaway/db/dao/HostEntryDao.java new file mode 100644 index 0000000..9cdf694 --- /dev/null +++ b/app/src/main/java/org/adaway/db/dao/HostEntryDao.java @@ -0,0 +1,78 @@ +package org.adaway.db.dao; + +import androidx.annotation.Nullable; +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.Query; + +import org.adaway.db.entity.HostEntry; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.ListType; + +import java.util.List; +import java.util.regex.Pattern; + +import static androidx.room.OnConflictStrategy.REPLACE; +import static org.adaway.db.entity.ListType.REDIRECTED; + +/** + * This interface is the DAO for {@link HostEntry} records. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +@Dao +public interface HostEntryDao { + Pattern ANY_CHAR_PATTERN = Pattern.compile("\\*"); + Pattern A_CHAR_PATTERN = Pattern.compile("\\?"); + + @Query("DELETE FROM `host_entries`") + void clear(); + + @Query("INSERT INTO `host_entries` SELECT DISTINCT `host`, `type`, `redirection` FROM `hosts_lists` WHERE `type` = 0 AND `enabled` = 1") + void importBlocked(); + + @Query("SELECT host FROM hosts_lists WHERE type = 1 AND enabled = 1") + List getEnabledAllowedHosts(); + + @Query("DELETE FROM `host_entries` WHERE `host` LIKE :hostPattern") + void allowHost(String hostPattern); + + @Query("SELECT * FROM hosts_lists WHERE type = 2 AND enabled = 1 ORDER BY host ASC, source_id DESC") + List getEnabledRedirectedHosts(); + + @Insert(onConflict = REPLACE) + void redirectHost(HostEntry redirection); + + /** + * Synchronize the host entries based on the current hosts lists table records. + */ + default void sync() { + clear(); + importBlocked(); + for (String allowedHost : getEnabledAllowedHosts()) { + allowedHost = ANY_CHAR_PATTERN.matcher(allowedHost).replaceAll("%"); + allowedHost = A_CHAR_PATTERN.matcher(allowedHost).replaceAll("_"); + allowHost(allowedHost); + } + for (HostListItem redirectedHost : getEnabledRedirectedHosts()) { + HostEntry entry = new HostEntry(); + entry.setHost(redirectedHost.getHost()); + entry.setType(REDIRECTED); + entry.setRedirection(redirectedHost.getRedirection()); + redirectHost(entry); + } + } + + @Query("SELECT * FROM `host_entries` ORDER BY `host`") + List getAll(); + + @Query("SELECT `type` FROM `host_entries` WHERE `host` == :host LIMIT 1") + ListType getTypeOfHost(String host); + + @Query("SELECT IFNULL((SELECT `type` FROM `host_entries` WHERE `host` == :host LIMIT 1), 1)") + ListType getTypeForHost(String host); + + @Nullable + @Query("SELECT * FROM `host_entries` WHERE `host` == :host LIMIT 1") + HostEntry getEntry(String host); +} diff --git a/app/src/main/java/org/adaway/db/dao/HostListItemDao.java b/app/src/main/java/org/adaway/db/dao/HostListItemDao.java new file mode 100644 index 0000000..cc92a31 --- /dev/null +++ b/app/src/main/java/org/adaway/db/dao/HostListItemDao.java @@ -0,0 +1,63 @@ +package org.adaway.db.dao; + +import androidx.lifecycle.LiveData; +import androidx.paging.PagingSource; +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.Query; +import androidx.room.Update; + +import org.adaway.db.entity.HostListItem; + +import java.util.List; +import java.util.Optional; + +import static androidx.room.OnConflictStrategy.REPLACE; + +/** + * This interface is the DAO for {@link HostListItem} entities. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +@Dao +public interface HostListItemDao { + @Insert(onConflict = REPLACE) + void insert(HostListItem... item); + + @Insert(onConflict = REPLACE) + void insert(List items); + + @Update + void update(HostListItem item); + + @Delete + void delete(HostListItem item); + + @Query("DELETE FROM hosts_lists WHERE source_id = 1 AND host = :host") + void deleteUserFromHost(String host); + + @Query("SELECT * FROM hosts_lists WHERE type = :type AND host LIKE :query AND ((:includeSources == 0 AND source_id == 1) || (:includeSources == 1)) GROUP BY host ORDER BY host ASC") + PagingSource loadList(int type, boolean includeSources, String query); + + @Query("SELECT * FROM hosts_lists ORDER BY host ASC") + List getAll(); + + @Query("SELECT * FROM hosts_lists WHERE source_id = 1") + List getUserList(); + + @Query("SELECT id FROM hosts_lists WHERE host = :host AND source_id = 1 LIMIT 1") + Optional getHostId(String host); + + @Query("SELECT COUNT(DISTINCT host) FROM hosts_lists WHERE type = 0 AND enabled = 1") + LiveData getBlockedHostCount(); + + @Query("SELECT COUNT(DISTINCT host) FROM hosts_lists WHERE type = 1 AND enabled = 1") + LiveData getAllowedHostCount(); + + @Query("SELECT COUNT(DISTINCT host) FROM hosts_lists WHERE type = 2 AND enabled = 1") + LiveData getRedirectHostCount(); + + @Query("DELETE FROM hosts_lists WHERE source_id = :sourceId") + void clearSourceHosts(int sourceId); +} diff --git a/app/src/main/java/org/adaway/db/dao/HostsSourceDao.java b/app/src/main/java/org/adaway/db/dao/HostsSourceDao.java new file mode 100644 index 0000000..6905a93 --- /dev/null +++ b/app/src/main/java/org/adaway/db/dao/HostsSourceDao.java @@ -0,0 +1,80 @@ +package org.adaway.db.dao; + +import androidx.lifecycle.LiveData; +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.Query; +import androidx.room.Update; + +import org.adaway.db.entity.HostsSource; + +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Optional; + +import static androidx.room.OnConflictStrategy.IGNORE; + +/** + * This interface is the DAO for {@link HostsSource} entities. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +@Dao +public interface HostsSourceDao { + @Insert(onConflict = IGNORE) + void insert(HostsSource source); + + @Update + void update(HostsSource source); + + @Delete + void delete(HostsSource source); + + @Query("SELECT * FROM hosts_sources WHERE enabled = 1 AND id != 1 ORDER BY url ASC") + List getEnabled(); + + default void toggleEnabled(HostsSource source) { + int id = source.getId(); + boolean enabled = !source.isEnabled(); + source.setEnabled(enabled); + setSourceEnabled(id, enabled); + setSourceItemsEnabled(id, enabled); + } + + @Query("UPDATE hosts_sources SET enabled = :enabled WHERE id =:id") + void setSourceEnabled(int id, boolean enabled); + + @Query("UPDATE hosts_lists SET enabled = :enabled WHERE source_id =:id") + void setSourceItemsEnabled(int id, boolean enabled); + + @Query("SELECT * FROM hosts_sources WHERE id = :id") + Optional getById(int id); + + @Query("SELECT * FROM hosts_sources WHERE id != 1 ORDER BY label ASC") + List getAll(); + + @Query("SELECT * FROM hosts_sources WHERE id != 1 ORDER BY label ASC") + LiveData> loadAll(); + + @Query("UPDATE hosts_sources SET last_modified_online = :dateTime WHERE id = :id") + void updateOnlineModificationDate(int id, ZonedDateTime dateTime); + + @Query("UPDATE hosts_sources SET last_modified_local = :localModificationDate, last_modified_online = :onlineModificationDate WHERE id = :id") + void updateModificationDates(int id, ZonedDateTime localModificationDate, ZonedDateTime onlineModificationDate); + + @Query("UPDATE hosts_sources SET entityTag = :entityTag WHERE id = :id") + void updateEntityTag(int id, String entityTag); + + @Query("UPDATE hosts_sources SET size = (SELECT count(id) FROM hosts_lists WHERE source_id = :id) WHERE id = :id") + void updateSize(int id); + + @Query("SELECT count(id) FROM hosts_sources WHERE enabled = 1 AND last_modified_online > last_modified_local") + LiveData countOutdated(); + + @Query("SELECT count(id) FROM hosts_sources WHERE enabled = 1 AND last_modified_online <= last_modified_local") + LiveData countUpToDate(); + + @Query("UPDATE hosts_sources SET last_modified_local = NULL, last_modified_online = NULL, entityTag = NULL, size = 0 WHERE id = :id") + void clearProperties(int id); +} diff --git a/app/src/main/java/org/adaway/db/entity/HostEntry.java b/app/src/main/java/org/adaway/db/entity/HostEntry.java new file mode 100644 index 0000000..b68749e --- /dev/null +++ b/app/src/main/java/org/adaway/db/entity/HostEntry.java @@ -0,0 +1,50 @@ +package org.adaway.db.entity; + +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; + +/** + * This entity represents an entry of the built hosts file. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +@Entity( + tableName = "host_entries", + indices = {@Index(value = "host", unique = true)} +) +public class HostEntry { + @PrimaryKey + @NonNull + private String host; + @NonNull + private ListType type; + private String redirection; + + @NonNull + public String getHost() { + return host; + } + + public void setHost(@NonNull String host) { + this.host = host; + } + + @NonNull + public ListType getType() { + return type; + } + + public void setType(@NonNull ListType type) { + this.type = type; + } + + public String getRedirection() { + return redirection; + } + + public void setRedirection(String redirection) { + this.redirection = redirection; + } +} diff --git a/app/src/main/java/org/adaway/db/entity/HostListItem.java b/app/src/main/java/org/adaway/db/entity/HostListItem.java new file mode 100644 index 0000000..e1f9226 --- /dev/null +++ b/app/src/main/java/org/adaway/db/entity/HostListItem.java @@ -0,0 +1,121 @@ +package org.adaway.db.entity; + +import androidx.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.ForeignKey; +import androidx.room.Index; +import androidx.room.PrimaryKey; + +import java.util.Objects; + +import static androidx.room.ForeignKey.CASCADE; + +/** + * This entity represents a black, white or redirect list item. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +@Entity( + tableName = "hosts_lists", + indices = { + @Index(value = "host"), + @Index(value = "source_id") + }, + foreignKeys = @ForeignKey( + entity = HostsSource.class, + parentColumns = "id", + childColumns = "source_id", + onUpdate = CASCADE, + onDelete = CASCADE + ) +) +public class HostListItem { + @PrimaryKey(autoGenerate = true) + private int id; + @NonNull + private String host; + @NonNull + private ListType type; + private boolean enabled; + private String redirection; + @ColumnInfo(name = "source_id") + private int sourceId; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @NonNull + public String getHost() { + return host; + } + + public void setHost(@NonNull String host) { + this.host = host; + } + + @NonNull + public ListType getType() { + return type; + } + + public void setType(@NonNull ListType type) { + this.type = type; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getRedirection() { + return redirection; + } + + public void setRedirection(String redirection) { + this.redirection = redirection; + } + + public int getSourceId() { + return sourceId; + } + + public void setSourceId(int sourceId) { + this.sourceId = sourceId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + HostListItem item = (HostListItem) o; + + if (id != item.id) return false; + if (enabled != item.enabled) return false; + if (sourceId != item.sourceId) return false; + if (!host.equals(item.host)) return false; + if (type != item.type) return false; + return Objects.equals(redirection, item.redirection); + + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + host.hashCode(); + result = 31 * result + type.hashCode(); + result = 31 * result + (enabled ? 1 : 0); + result = 31 * result + (redirection != null ? redirection.hashCode() : 0); + result = 31 * result + sourceId; + return result; + } +} diff --git a/app/src/main/java/org/adaway/db/entity/HostsSource.java b/app/src/main/java/org/adaway/db/entity/HostsSource.java new file mode 100644 index 0000000..1edacd5 --- /dev/null +++ b/app/src/main/java/org/adaway/db/entity/HostsSource.java @@ -0,0 +1,187 @@ +package org.adaway.db.entity; + +import android.webkit.URLUtil; + +import androidx.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; + +import java.time.ZonedDateTime; +import java.util.Objects; + +import static org.adaway.db.entity.SourceType.FILE; +import static org.adaway.db.entity.SourceType.UNSUPPORTED; +import static org.adaway.db.entity.SourceType.URL; + +/** + * This entity represents a source to get hosts list. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +@Entity( + tableName = "hosts_sources", + indices = {@Index(value = "url", unique = true)} +) +public class HostsSource { + /** + * The user source ID. + */ + public static final int USER_SOURCE_ID = 1; + /** + * The user source URL. + */ + public static final String USER_SOURCE_URL = "content://org.adaway/user/hosts"; + + @PrimaryKey(autoGenerate = true) + private int id; + @NonNull + private String label; + @NonNull + private String url; + private boolean enabled = true; + private boolean allowEnabled = false; + private boolean redirectEnabled = false; + @ColumnInfo(name = "last_modified_local") + private ZonedDateTime localModificationDate; + @ColumnInfo(name = "last_modified_online") + private ZonedDateTime onlineModificationDate; + /** + * The HTTP ETag (strong from, may be null). + */ + private String entityTag; + /** + * The number of hosts list items (0 until synced). + */ + private int size; + + /** + * Check whether an URL is valid for as host source.
    + * A valid URL is a HTTPS URL or file URL. + * + * @param url The URL to check. + * @return {@code true} if the URL is valid, {@code false} otherwise. + */ + public static boolean isValidUrl(String url) { + return (!"https://".equals(url) && URLUtil.isHttpsUrl(url)) || URLUtil.isContentUrl(url); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @NonNull + public String getLabel() { + return label; + } + + public void setLabel(@NonNull String label) { + this.label = label; + } + + @NonNull + public String getUrl() { + return url; + } + + public void setUrl(@NonNull String url) { + this.url = url; + } + + public SourceType getType() { + if (this.url.startsWith("https://")) { + return URL; + } else if (this.url.startsWith("content://")) { + return FILE; + } else { + return UNSUPPORTED; + } + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isAllowEnabled() { + return allowEnabled; + } + + public void setAllowEnabled(boolean allowEnabled) { + this.allowEnabled = allowEnabled; + } + + public boolean isRedirectEnabled() { + return redirectEnabled; + } + + public void setRedirectEnabled(boolean redirectEnabled) { + this.redirectEnabled = redirectEnabled; + } + + public ZonedDateTime getLocalModificationDate() { + return localModificationDate; + } + + public void setLocalModificationDate(ZonedDateTime localModificationDate) { + this.localModificationDate = localModificationDate; + } + + public ZonedDateTime getOnlineModificationDate() { + return onlineModificationDate; + } + + public void setOnlineModificationDate(ZonedDateTime lastOnlineModification) { + this.onlineModificationDate = lastOnlineModification; + } + + public String getEntityTag() { + return this.entityTag; + } + + public void setEntityTag(String entityTag) { + this.entityTag = entityTag; + } + + public int getSize() { + return this.size; + } + + public void setSize(int size) { + this.size = size; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + HostsSource that = (HostsSource) o; + + if (id != that.id) return false; + if (enabled != that.enabled) return false; + if (!url.equals(that.url)) return false; + if (!Objects.equals(localModificationDate, that.localModificationDate)) + return false; + return Objects.equals(onlineModificationDate, that.onlineModificationDate); + + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + url.hashCode(); + result = 31 * result + (enabled ? 1 : 0); + result = 31 * result + (localModificationDate != null ? localModificationDate.hashCode() : 0); + result = 31 * result + (onlineModificationDate != null ? onlineModificationDate.hashCode() : 0); + return result; + } +} diff --git a/app/src/main/java/org/adaway/db/entity/ListType.java b/app/src/main/java/org/adaway/db/entity/ListType.java new file mode 100644 index 0000000..781d848 --- /dev/null +++ b/app/src/main/java/org/adaway/db/entity/ListType.java @@ -0,0 +1,31 @@ +package org.adaway.db.entity; + +/** + * This enumerate specifies the type of {@link HostListItem}. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public enum ListType { + BLOCKED(0), + ALLOWED(1), + REDIRECTED(2); + + private final int value; + + ListType(int value) { + this.value = value; + } + + public static ListType fromValue(int value) { + for (ListType listType : ListType.values()) { + if (listType.value == value) { + return listType; + } + } + throw new IllegalArgumentException("Invalid value for list type: " + value); + } + + public int getValue() { + return value; + } +} diff --git a/app/src/main/java/org/adaway/db/entity/SourceType.java b/app/src/main/java/org/adaway/db/entity/SourceType.java new file mode 100644 index 0000000..cb9ec65 --- /dev/null +++ b/app/src/main/java/org/adaway/db/entity/SourceType.java @@ -0,0 +1,21 @@ +package org.adaway.db.entity; + +/** + * This enumerate specifies the type of {@link HostsSource}. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public enum SourceType { + /** + * The URL type represents online source to download from URL. + */ + URL, + /** + * The FILE type represents file stored source to retrieve using SAF API. + */ + FILE, + /** + * The UNSUPPORTED type represents unhandled source type. + */ + UNSUPPORTED +} diff --git a/app/src/main/java/org/adaway/helper/NotificationHelper.java b/app/src/main/java/org/adaway/helper/NotificationHelper.java new file mode 100644 index 0000000..8a2aade --- /dev/null +++ b/app/src/main/java/org/adaway/helper/NotificationHelper.java @@ -0,0 +1,167 @@ +package org.adaway.helper; + +import static android.app.PendingIntent.FLAG_IMMUTABLE; +import static android.app.PendingIntent.getActivity; +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static androidx.core.app.NotificationCompat.PRIORITY_LOW; + +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; + +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; + +import org.adaway.R; +import org.adaway.ui.home.HomeActivity; +import org.adaway.ui.update.UpdateActivity; + +/** + * This class is an helper class to deals with notifications. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class NotificationHelper { + /** + * The notification channel for updates. + */ + public static final String UPDATE_NOTIFICATION_CHANNEL = "UpdateChannel"; + /** + * The notification channel for VPN service. + */ + public static final String VPN_SERVICE_NOTIFICATION_CHANNEL = "VpnServiceChannel"; + /** + * The update hosts notification identifier. + */ + private static final int UPDATE_HOSTS_NOTIFICATION_ID = 10; + /** + * The update application notification identifier. + */ + private static final int UPDATE_APP_NOTIFICATION_ID = 11; + /** + * The VPN running service notification identifier. + */ + public static final int VPN_RUNNING_SERVICE_NOTIFICATION_ID = 20; + /** + * The VPN resume service notification identifier. + */ + public static final int VPN_RESUME_SERVICE_NOTIFICATION_ID = 21; + + /** + * Private constructor. + */ + private NotificationHelper() { + + } + + /** + * Create the application notification channel. + * + * @param context The application context. + */ + public static void createNotificationChannels(@NonNull Context context) { + // Create update notification channel + NotificationChannel updateChannel = new NotificationChannel( + UPDATE_NOTIFICATION_CHANNEL, + context.getString(R.string.notification_update_channel_name), + NotificationManager.IMPORTANCE_LOW + ); + updateChannel.setDescription(context.getString(R.string.notification_update_channel_description)); + // Create VPN service notification channel + NotificationChannel vpnServiceChannel = new NotificationChannel( + VPN_SERVICE_NOTIFICATION_CHANNEL, + context.getString(R.string.notification_vpn_channel_name), + NotificationManager.IMPORTANCE_LOW + ); + updateChannel.setDescription(context.getString(R.string.notification_vpn_channel_description)); + // Register the channels with the system; you can't change the importance or other notification behaviors after this + NotificationManager notificationManager = context.getSystemService(NotificationManager.class); + if (notificationManager != null) { + notificationManager.createNotificationChannel(updateChannel); + notificationManager.createNotificationChannel(vpnServiceChannel); + } + } + + /** + * Show the notification about new hosts update available. + * + * @param context The application context. + */ + public static void showUpdateHostsNotification(@NonNull Context context) { + // Get notification manager + NotificationManager notificationManager = context.getSystemService(NotificationManager.class); + if (notificationManager == null || !notificationManager.areNotificationsEnabled()) { + return; + } + // Build notification + int color = context.getColor(R.color.notification); + String title = context.getString(R.string.notification_update_host_available_title); + String text = context.getString(R.string.notification_update_host_available_text); + Intent intent = new Intent(context, HomeActivity.class); + intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); + PendingIntent pendingIntent = getActivity(context, 0, intent, FLAG_IMMUTABLE); + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, UPDATE_NOTIFICATION_CHANNEL) + .setSmallIcon(R.drawable.logo) + .setColorized(true) + .setColor(color) + .setShowWhen(false) + .setContentTitle(title) + .setContentText(text) + .setContentIntent(pendingIntent) + .setPriority(PRIORITY_LOW) + .setAutoCancel(true); + // Notify the built notification + notificationManager.notify(UPDATE_HOSTS_NOTIFICATION_ID, builder.build()); + } + + /** + * Show the notification about new application update available. + * + * @param context The application context. + */ + public static void showUpdateApplicationNotification(@NonNull Context context) { + // Get notification manager + NotificationManager notificationManager = context.getSystemService(NotificationManager.class); + if (notificationManager == null || !notificationManager.areNotificationsEnabled()) { + return; + } + // Build notification + int color = context.getColor(R.color.notification); + String title = context.getString(R.string.notification_update_app_available_title); + String text = context.getString(R.string.notification_update_app_available_text); + Intent intent = new Intent(context, UpdateActivity.class); + intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); + PendingIntent pendingIntent = getActivity(context, 0, intent, FLAG_IMMUTABLE); + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, UPDATE_NOTIFICATION_CHANNEL) + .setSmallIcon(R.drawable.logo) + .setColorized(true) + .setColor(color) + .setShowWhen(false) + .setContentTitle(title) + .setContentText(text) + .setContentIntent(pendingIntent) + .setPriority(PRIORITY_LOW) + .setAutoCancel(true); + // Notify the built notification + notificationManager.notify(UPDATE_HOSTS_NOTIFICATION_ID, builder.build()); + } + + /** + * Hide the notification about new hosts update available. + * + * @param context The application context. + */ + public static void clearUpdateNotifications(@NonNull Context context) { + // Get notification manager + NotificationManager notificationManager = context.getSystemService(NotificationManager.class); + if (notificationManager == null) { + return; + } + // Cancel the notification + notificationManager.cancel(UPDATE_HOSTS_NOTIFICATION_ID); + notificationManager.cancel(UPDATE_APP_NOTIFICATION_ID); + } +} diff --git a/app/src/main/java/org/adaway/helper/PreferenceHelper.java b/app/src/main/java/org/adaway/helper/PreferenceHelper.java new file mode 100644 index 0000000..d3d0bc9 --- /dev/null +++ b/app/src/main/java/org/adaway/helper/PreferenceHelper.java @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.helper; + +import android.content.Context; +import android.content.SharedPreferences; + +import androidx.appcompat.app.AppCompatDelegate; + +import org.adaway.R; +import org.adaway.model.adblocking.AdBlockMethod; +import org.adaway.util.Constants; +import org.adaway.vpn.VpnStatus; + +import java.util.Collections; +import java.util.Set; + +public final class PreferenceHelper { + private PreferenceHelper() { + + } + + public static int getDarkThemeMode(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + String pref = prefs.getString( + context.getString(R.string.pref_dark_theme_mode_key), + context.getResources().getString(R.string.pref_dark_theme_mode_def) + ); + switch (pref) { + case "MODE_NIGHT_NO": + return AppCompatDelegate.MODE_NIGHT_NO; + case "MODE_NIGHT_YES": + return AppCompatDelegate.MODE_NIGHT_YES; + default: + return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM; + } + } + + public static boolean getUpdateCheck(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_update_check_key), + context.getResources().getBoolean(R.bool.pref_update_check_def) + ); + } + + public static boolean getNeverReboot(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_never_reboot_key), + context.getResources().getBoolean(R.bool.pref_never_reboot_def) + ); + } + + public static void setNeverReboot(Context context, boolean value) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(context.getString(R.string.pref_never_reboot_key), value); + editor.apply(); + } + + public static boolean getEnableIpv6(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_enable_ipv6_key), + context.getResources().getBoolean(R.bool.pref_enable_ipv6_def) + ); + } + + public static boolean getUpdateCheckAppStartup(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_update_check_app_startup_key), + context.getResources().getBoolean(R.bool.pref_update_check_app_startup_def) + ); + } + + public static boolean getUpdateCheckAppDaily(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_update_check_app_daily_key), + context.getResources().getBoolean(R.bool.pref_update_check_app_daily_def) + ); + } + + public static boolean getIncludeBetaReleases(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_update_include_beta_releases_key), + context.getResources().getBoolean(R.bool.pref_update_include_beta_releases_def) + ); + } + + public static boolean getUpdateCheckHostsDaily(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_update_check_hosts_daily_key), + context.getResources().getBoolean(R.bool.pref_update_check_hosts_daily_def) + ); + } + + public static boolean getAutomaticUpdateDaily(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_automatic_update_daily_key), + context.getResources().getBoolean(R.bool.pref_automatic_update_daily_def) + ); + } + + public static boolean getUpdateOnlyOnWifi(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_update_only_on_wifi_key), + context.getResources().getBoolean(R.bool.pref_update_only_on_wifi_def) + ); + } + + public static String getRedirectionIpv4(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getString( + context.getString(R.string.pref_redirection_ipv4_key), + context.getString(R.string.pref_redirection_ipv4_def) + ); + } + + public static String getRedirectionIpv6(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getString( + context.getString(R.string.pref_redirection_ipv6_key), + context.getString(R.string.pref_redirection_ipv6_def) + ); + } + + public static boolean getWebServerEnabled(Context context) { + SharedPreferences prefs = context.getApplicationContext().getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_webserver_enabled_key), + context.getResources().getBoolean(R.bool.pref_webserver_enabled_def) + ); + } + + public static boolean getWebServerIcon(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_webserver_icon_key), + context.getResources().getBoolean(R.bool.pref_webserver_icon_def) + ); + } + + public static AdBlockMethod getAdBlockMethod(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return AdBlockMethod.fromCode(prefs.getInt( + context.getString(R.string.pref_ad_block_method_key), + context.getResources().getInteger(R.integer.pref_ad_block_method_key_def) + )); + } + + public static void setAbBlockMethod(Context context, AdBlockMethod method) { + SharedPreferences prefs = context.getApplicationContext().getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt(context.getString(R.string.pref_ad_block_method_key), method.toCode()); + editor.apply(); + } + + public static VpnStatus getVpnServiceStatus(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return VpnStatus.fromCode(prefs.getInt( + context.getString(R.string.pref_vpn_service_status_key), + context.getResources().getInteger(R.integer.pref_vpn_service_status_def) + )); + } + + public static void setVpnServiceStatus(Context context, VpnStatus status) { + SharedPreferences prefs = context.getApplicationContext().getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt(context.getString(R.string.pref_vpn_service_status_key), status.toCode()); + editor.apply(); + } + + public static boolean getVpnServiceOnBoot(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_vpn_service_on_boot_key), + context.getResources().getBoolean(R.bool.pref_vpn_service_on_boot_def) + ); + } + + public static boolean getVpnWatchdogEnabled(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_vpn_watchdog_enabled_key), + context.getResources().getBoolean(R.bool.pref_vpn_watchdog_enabled_def) + ); + } + + public static boolean getDebugEnabled(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_enable_debug_key), + context.getResources().getBoolean(R.bool.pref_enable_debug_def) + ); + } + + public static boolean getTelemetryEnabled(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_enable_telemetry_key), + context.getResources().getBoolean(R.bool.pref_enable_telemetry_def) + ); + } + + public static void setTelemetryEnabled(Context context, boolean enabled) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(context.getString(R.string.pref_enable_telemetry_key), enabled); + editor.apply(); + } + + public static boolean getDisplayTelemetryConsent(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getBoolean( + context.getString(R.string.pref_display_telemetry_consent_key), + context.getResources().getBoolean(R.bool.pref_display_telemetry_consent_def) + ); + } + + public static void setDisplayTelemetryConsent(Context context, boolean displayTelemetryConsent) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(context.getString(R.string.pref_display_telemetry_consent_key), displayTelemetryConsent); + editor.apply(); + } + + public static String getVpnExcludedSystemApps(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getString( + context.getString(R.string.pref_vpn_excluded_system_apps_key), + context.getString(R.string.pref_vpn_excluded_system_apps_default) + ); + } + + public static Set getVpnExcludedApps(Context context) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + return prefs.getStringSet( + context.getString(R.string.pref_vpn_excluded_user_apps_key), + Collections.emptySet() + ); + } + + public static void setVpnExcludedApps(Context context, Set excludedApplicationPackageNames) { + SharedPreferences prefs = context.getSharedPreferences( + Constants.PREFS_NAME, + Context.MODE_PRIVATE + ); + SharedPreferences.Editor editor = prefs.edit(); + editor.putStringSet(context.getString(R.string.pref_vpn_excluded_user_apps_key), excludedApplicationPackageNames); + editor.apply(); + } +} diff --git a/app/src/main/java/org/adaway/helper/ThemeHelper.java b/app/src/main/java/org/adaway/helper/ThemeHelper.java new file mode 100644 index 0000000..a1e3233 --- /dev/null +++ b/app/src/main/java/org/adaway/helper/ThemeHelper.java @@ -0,0 +1,29 @@ +package org.adaway.helper; + +import android.content.Context; + +import androidx.appcompat.app.AppCompatDelegate; + +/** + * This class is a helper to apply user selected theme on the application activity. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class ThemeHelper { + + /** + * Private constructor. + */ + private ThemeHelper() { + + } + + /** + * Apply the user selected theme. + * + * @param context The context to apply theme. + */ + public static void applyTheme(Context context) { + AppCompatDelegate.setDefaultNightMode(PreferenceHelper.getDarkThemeMode(context)); + } +} diff --git a/app/src/main/java/org/adaway/model/adblocking/AdBlockMethod.java b/app/src/main/java/org/adaway/model/adblocking/AdBlockMethod.java new file mode 100644 index 0000000..e379cea --- /dev/null +++ b/app/src/main/java/org/adaway/model/adblocking/AdBlockMethod.java @@ -0,0 +1,40 @@ +package org.adaway.model.adblocking; + +import java.util.Arrays; + +/** + * This enum represents the ad blocking methods. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public enum AdBlockMethod { + /** + * Not defined ad block method. + */ + UNDEFINED(0), + /** + * The system hosts file ad block method. + */ + ROOT(1), + /** + * The VPN based ad block method. + */ + VPN(2); + + private int code; + + AdBlockMethod(int code) { + this.code = code; + } + + public static AdBlockMethod fromCode(int code) { + return Arrays.stream(AdBlockMethod.values()) + .filter(method -> method.code == code) + .findAny() + .orElse(UNDEFINED); + } + + public int toCode() { + return this.code; + } +} diff --git a/app/src/main/java/org/adaway/model/adblocking/AdBlockModel.java b/app/src/main/java/org/adaway/model/adblocking/AdBlockModel.java new file mode 100644 index 0000000..c04f3ee --- /dev/null +++ b/app/src/main/java/org/adaway/model/adblocking/AdBlockModel.java @@ -0,0 +1,140 @@ +package org.adaway.model.adblocking; + +import android.content.Context; + +import androidx.annotation.StringRes; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import org.adaway.model.error.HostErrorException; +import org.adaway.model.root.RootModel; +import org.adaway.model.vpn.VpnModel; + +import java.util.List; + +import timber.log.Timber; + +/** + * This class is the base model for all ad block model. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public abstract class AdBlockModel { + /** + * The application context. + */ + protected final Context context; + /** + * The hosts installation status: + *
      + *
    • {@code null} if not defined,
    • + *
    • {@code true} if hosts list is installed,
    • + *
    • {@code false} if default hosts file.
    • + *
    + */ + protected final MutableLiveData applied; + /** + * The model state. + */ + private final MutableLiveData state; + + /** + * Constructor. + * + * @param context The application context. + */ + protected AdBlockModel(Context context) { + this.context = context; + this.state = new MutableLiveData<>(); + this.applied = new MutableLiveData<>(); + } + + /** + * Instantiate ad block model. + * + * @param context The application context. + * @param method The ad block method to get model. + * @return The instantiated model. + */ + public static AdBlockModel build(Context context, AdBlockMethod method) { + switch (method) { + case ROOT: + return new RootModel(context); + case VPN: + return new VpnModel(context); + default: + return new UndefinedBlockModel(context); + } + } + + /** + * Get ad block method. + * + * @return The ad block method of this model. + */ + public abstract AdBlockMethod getMethod(); + + /** + * Checks if hosts list is applied. + * + * @return {@code true} if applied, {@code false} if default. + */ + public LiveData isApplied() { + return this.applied; + } + + /** + * Apply hosts list. + * + * @throws HostErrorException If the model configuration could not be applied. + */ + public abstract void apply() throws HostErrorException; + + /** + * Revert the hosts list to the default one. + * + * @throws HostErrorException If the model configuration could not be revert. + */ + public abstract void revert() throws HostErrorException; + + /** + * Get the model state. + * + * @return The model state. + */ + public LiveData getState() { + return this.state; + } + + protected void setState(@StringRes int stateResId, Object... details) { + String state = this.context.getString(stateResId, details); + Timber.d(state); + this.state.postValue(state); + } + + /** + * Get whether log are recoding or not. + * + * @return {@code true} if logs are recoding, {@code false} otherwise. + */ + public abstract boolean isRecordingLogs(); + + /** + * Set log recoding. + * + * @param recording {@code true} to record logs, {@code false} otherwise. + */ + public abstract void setRecordingLogs(boolean recording); + + /** + * Get logs. + * + * @return The logs unique and sorted by date, older first. + */ + public abstract List getLogs(); + + /** + * Clear logs. + */ + public abstract void clearLogs(); +} diff --git a/app/src/main/java/org/adaway/model/adblocking/UndefinedBlockModel.java b/app/src/main/java/org/adaway/model/adblocking/UndefinedBlockModel.java new file mode 100644 index 0000000..40ab163 --- /dev/null +++ b/app/src/main/java/org/adaway/model/adblocking/UndefinedBlockModel.java @@ -0,0 +1,59 @@ +package org.adaway.model.adblocking; + +import static org.adaway.model.adblocking.AdBlockMethod.UNDEFINED; +import static java.util.Collections.emptyList; + +import android.content.Context; + +import java.util.List; + +/** + * This class is a stub model when no ad block method is defined. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class UndefinedBlockModel extends AdBlockModel { + /** + * Constructor. + * + * @param context The application context. + */ + public UndefinedBlockModel(Context context) { + super(context); + } + + @Override + public AdBlockMethod getMethod() { + return UNDEFINED; + } + + @Override + public void apply() { + // Unsupported operation + } + + @Override + public void revert() { + // Unsupported operation + } + + @Override + public boolean isRecordingLogs() { + return false; + } + + @Override + public void setRecordingLogs(boolean recording) { + // Unsupported operation + } + + @Override + public List getLogs() { + return emptyList(); + } + + @Override + public void clearLogs() { + // Unsupported operation + } +} diff --git a/app/src/main/java/org/adaway/model/backup/AppBackupAgent.java b/app/src/main/java/org/adaway/model/backup/AppBackupAgent.java new file mode 100644 index 0000000..9f12734 --- /dev/null +++ b/app/src/main/java/org/adaway/model/backup/AppBackupAgent.java @@ -0,0 +1,82 @@ +package org.adaway.model.backup; + +import static org.adaway.util.Constants.PREFS_NAME; + +import android.app.backup.BackupAgentHelper; +import android.app.backup.BackupDataInputStream; +import android.app.backup.BackupDataOutput; +import android.app.backup.FileBackupHelper; +import android.app.backup.SharedPreferencesBackupHelper; +import android.content.Context; +import android.net.Uri; +import android.os.ParcelFileDescriptor; + +import java.io.File; +import java.io.IOException; + +import timber.log.Timber; + +/** + * This class is a {@link android.app.backup.BackupAgent} to backup and restore application state + * using Android Backup Service. It is based on key-value pairs backup to prevent killing the + * application during the backup (leaving the VPN foreground service always running). It backs up + * and restores the application preferences and the user rules. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class AppBackupAgent extends BackupAgentHelper { + private static final String PREFS_BACKUP_KEY = "prefs"; + private static final String RULES_BACKUP_KEY = "rules"; + + @Override + public void onCreate() { + super.onCreate(); + addHelper(PREFS_BACKUP_KEY, new SharedPreferencesBackupHelper(this, PREFS_NAME)); + addHelper(RULES_BACKUP_KEY, new SourceBackupHelper(this)); + } + + /** + * This class is a {@link android.app.backup.BackupHelper} to backup and restore user rules. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ + private static class SourceBackupHelper extends FileBackupHelper { + private static final String RULES_FILE_NAME = "rules-backup.json"; + private final Context context; + + /** + * Constructor. + * + * @param context The application context. + */ + public SourceBackupHelper(Context context) { + super(context, RULES_FILE_NAME); + this.context = context; + } + + @Override + public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) { + try { + BackupExporter.exportBackup(this.context, getRulesFileUri()); + super.performBackup(oldState, data, newState); + } catch (IOException e) { + Timber.w(e, "Failed to export rules to backup."); + } + } + + @Override + public void restoreEntity(BackupDataInputStream data) { + super.restoreEntity(data); + try { + BackupImporter.importBackup(this.context, getRulesFileUri()); + } catch (IOException e) { + Timber.w(e, "Failed to import rules from backup."); + } + } + + private Uri getRulesFileUri() { + File ruleFile = new File(this.context.getFilesDir(), RULES_FILE_NAME); + return Uri.fromFile(ruleFile); + } + } +} diff --git a/app/src/main/java/org/adaway/model/backup/BackupExporter.java b/app/src/main/java/org/adaway/model/backup/BackupExporter.java new file mode 100644 index 0000000..819f655 --- /dev/null +++ b/app/src/main/java/org/adaway/model/backup/BackupExporter.java @@ -0,0 +1,141 @@ +package org.adaway.model.backup; + +import android.content.Context; +import android.net.Uri; +import android.widget.Toast; + +import androidx.annotation.UiThread; + +import org.adaway.R; +import org.adaway.db.AppDatabase; +import org.adaway.db.dao.HostListItemDao; +import org.adaway.db.dao.HostsSourceDao; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.HostsSource; +import org.adaway.util.AppExecutors; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.List; +import java.util.concurrent.Executor; + +import static java.util.stream.Collectors.toList; +import static org.adaway.db.entity.ListType.ALLOWED; +import static org.adaway.db.entity.ListType.BLOCKED; +import static org.adaway.db.entity.ListType.REDIRECTED; +import static org.adaway.model.backup.BackupFormat.ALLOWED_KEY; +import static org.adaway.model.backup.BackupFormat.BLOCKED_KEY; +import static org.adaway.model.backup.BackupFormat.REDIRECTED_KEY; +import static org.adaway.model.backup.BackupFormat.SOURCES_KEY; +import static org.adaway.model.backup.BackupFormat.hostToJson; +import static org.adaway.model.backup.BackupFormat.sourceToJson; + +import timber.log.Timber; + +/** + * This class is a helper class to export user lists and hosts sources to a backup file. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class BackupExporter { + private static final Executor DISK_IO_EXECUTOR = AppExecutors.getInstance().diskIO(); + private static final Executor MAIN_THREAD_EXECUTOR = AppExecutors.getInstance().mainThread(); + + private BackupExporter() { + + } + + /** + * Export all user lists and hosts sources to a backup file on the external storage. + * + * @param context The application context. + */ + public static void exportToBackup(Context context, Uri backupUri) { + DISK_IO_EXECUTOR.execute(() -> { + boolean imported = true; + try { + exportBackup(context, backupUri); + } catch (IOException e) { + Timber.e(e, "Failed to import backup."); + imported = false; + } + boolean successful = imported; + String fileName = getFileNameFromUri(backupUri); + MAIN_THREAD_EXECUTOR.execute(() -> notifyExportEnd(context, successful, fileName)); + }); + } + + private static String getFileNameFromUri(Uri backupUri) { + String path = backupUri.getPath(); + return path == null ? "" : new File(path).getName(); + } + + @UiThread + private static void notifyExportEnd(Context context, boolean successful, String backupUri) { + Toast.makeText( + context, + context.getString(successful ? R.string.export_success : R.string.export_failed, backupUri), + Toast.LENGTH_LONG + ).show(); + } + + static void exportBackup(Context context, Uri backupUri) throws IOException { + // Open writer on the export file + try (OutputStream outputStream = context.getContentResolver().openOutputStream(backupUri); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream))) { + JSONObject backup = makeBackup(context); + writer.write(backup.toString(4)); + } catch (JSONException e) { + throw new IOException("Failed to generate backup.", e); + } catch (IOException e) { + throw new IOException("Could not write file.", e); + } + } + + private static JSONObject makeBackup(Context context) throws JSONException { + AppDatabase database = AppDatabase.getInstance(context); + HostsSourceDao hostsSourceDao = database.hostsSourceDao(); + HostListItemDao hostListItemDao = database.hostsListItemDao(); + + List userHosts = hostListItemDao.getUserList(); + List blockedHosts = userHosts.stream() + .filter(value -> value.getType() == BLOCKED) + .collect(toList()); + List allowedHosts = userHosts.stream() + .filter(value -> value.getType() == ALLOWED) + .collect(toList()); + List redirectedHosts = userHosts.stream() + .filter(value -> value.getType() == REDIRECTED) + .collect(toList()); + + JSONObject backupObject = new JSONObject(); + backupObject.put(SOURCES_KEY, buildSourcesBackup(hostsSourceDao.getAll())); + backupObject.put(BLOCKED_KEY, buildListBackup(blockedHosts)); + backupObject.put(ALLOWED_KEY, buildListBackup(allowedHosts)); + backupObject.put(REDIRECTED_KEY, buildListBackup(redirectedHosts)); + + return backupObject; + } + + private static JSONArray buildSourcesBackup(List sources) throws JSONException { + JSONArray sourceArray = new JSONArray(); + for (HostsSource source : sources) { + sourceArray.put(sourceToJson(source)); + } + return sourceArray; + } + + private static JSONArray buildListBackup(List hosts) throws JSONException { + JSONArray listArray = new JSONArray(); + for (HostListItem host : hosts) { + listArray.put(hostToJson(host)); + } + return listArray; + } +} diff --git a/app/src/main/java/org/adaway/model/backup/BackupFormat.java b/app/src/main/java/org/adaway/model/backup/BackupFormat.java new file mode 100644 index 0000000..68316d3 --- /dev/null +++ b/app/src/main/java/org/adaway/model/backup/BackupFormat.java @@ -0,0 +1,84 @@ +package org.adaway.model.backup; + +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.HostsSource; +import org.json.JSONException; +import org.json.JSONObject; + +import static org.adaway.db.entity.HostsSource.USER_SOURCE_ID; + +/** + * This class defines user lists and hosts sources file format. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +final class BackupFormat { + /* + * Source backup format. + */ + static final String SOURCES_KEY = "sources"; + static final String SOURCE_LABEL_ATTRIBUTE = "label"; + static final String SOURCE_URL_ATTRIBUTE = "url"; + static final String SOURCE_ENABLED_ATTRIBUTE = "enabled"; + static final String SOURCE_ALLOW_ATTRIBUTE = "allow"; + static final String SOURCE_REDIRECT_ATTRIBUTE = "redirect"; + /* + * User source backup format. + */ + static final String BLOCKED_KEY = "blocked"; + static final String ALLOWED_KEY = "allowed"; + static final String REDIRECTED_KEY = "redirected"; + static final String ENABLED_ATTRIBUTE = "enabled"; + static final String HOST_ATTRIBUTE = "host"; + static final String REDIRECT_ATTRIBUTE = "redirect"; + + BackupFormat() { + + } + + static JSONObject sourceToJson(HostsSource source) throws JSONException { + JSONObject sourceObject = new JSONObject(); + sourceObject.put(SOURCE_LABEL_ATTRIBUTE, source.getLabel()); + sourceObject.put(SOURCE_URL_ATTRIBUTE, source.getUrl()); + sourceObject.put(SOURCE_ENABLED_ATTRIBUTE, source.isEnabled()); + sourceObject.put(SOURCE_ALLOW_ATTRIBUTE, source.isAllowEnabled()); + sourceObject.put(SOURCE_REDIRECT_ATTRIBUTE, source.isRedirectEnabled()); + return sourceObject; + } + + static HostsSource sourceFromJson(JSONObject sourceObject) throws JSONException { + HostsSource source = new HostsSource(); + source.setLabel(sourceObject.getString(SOURCE_LABEL_ATTRIBUTE)); + String url = sourceObject.getString(SOURCE_URL_ATTRIBUTE); + if (!HostsSource.isValidUrl(url)) { + throw new JSONException("Invalid source URL: "+url); + } + source.setUrl(url); + source.setEnabled(sourceObject.getBoolean(SOURCE_ENABLED_ATTRIBUTE)); + source.setAllowEnabled(sourceObject.getBoolean(SOURCE_ALLOW_ATTRIBUTE)); + source.setRedirectEnabled(sourceObject.getBoolean(SOURCE_REDIRECT_ATTRIBUTE)); + return source; + } + + static JSONObject hostToJson(HostListItem host) throws JSONException { + JSONObject hostObject = new JSONObject(); + hostObject.put(HOST_ATTRIBUTE, host.getHost()); + String redirection = host.getRedirection(); + if (redirection != null && !redirection.isEmpty()) { + hostObject.put(REDIRECT_ATTRIBUTE, redirection); + } + hostObject.put(ENABLED_ATTRIBUTE, host.isEnabled()); + return hostObject; + } + + static HostListItem hostFromJson(JSONObject hostObject) throws JSONException { + HostListItem host = new HostListItem(); + host.setHost(hostObject.getString(HOST_ATTRIBUTE)); + if (hostObject.has(REDIRECT_ATTRIBUTE)) { + host.setRedirection(hostObject.getString(REDIRECT_ATTRIBUTE)); + } + host.setEnabled(hostObject.getBoolean(ENABLED_ATTRIBUTE)); + host.setSourceId(USER_SOURCE_ID); + return host; + } +} diff --git a/app/src/main/java/org/adaway/model/backup/BackupImporter.java b/app/src/main/java/org/adaway/model/backup/BackupImporter.java new file mode 100644 index 0000000..41944c6 --- /dev/null +++ b/app/src/main/java/org/adaway/model/backup/BackupImporter.java @@ -0,0 +1,136 @@ +package org.adaway.model.backup; + +import android.content.Context; +import android.net.Uri; +import android.widget.Toast; + +import androidx.annotation.UiThread; + +import org.adaway.R; +import org.adaway.db.AppDatabase; +import org.adaway.db.dao.HostListItemDao; +import org.adaway.db.dao.HostsSourceDao; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.ListType; +import org.adaway.util.AppExecutors; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Optional; +import java.util.concurrent.Executor; + +import static org.adaway.db.entity.ListType.ALLOWED; +import static org.adaway.db.entity.ListType.BLOCKED; +import static org.adaway.db.entity.ListType.REDIRECTED; +import static org.adaway.model.backup.BackupFormat.ALLOWED_KEY; +import static org.adaway.model.backup.BackupFormat.BLOCKED_KEY; +import static org.adaway.model.backup.BackupFormat.REDIRECTED_KEY; +import static org.adaway.model.backup.BackupFormat.SOURCES_KEY; +import static org.adaway.model.backup.BackupFormat.hostFromJson; +import static org.adaway.model.backup.BackupFormat.sourceFromJson; + +import timber.log.Timber; + +/** + * This class is a helper class to import user lists and hosts sources to a backup file.
    + * Importing a file source will no restore read access from Storage Access Framework. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class BackupImporter { + + private BackupImporter() { + + } + + private static final Executor DISK_IO_EXECUTOR = AppExecutors.getInstance().diskIO(); + private static final Executor MAIN_THREAD_EXECUTOR = AppExecutors.getInstance().mainThread(); + + /** + * Import a backup file. + * + * @param context The application context. + * @param backupUri The URI of a backup file. + */ + @UiThread + public static void importFromBackup(Context context, Uri backupUri) { + DISK_IO_EXECUTOR.execute(() -> { + boolean imported = true; + try { + importBackup(context, backupUri); + } catch (IOException e) { + Timber.e(e, "Failed to import backup."); + imported = false; + } + boolean successful = imported; + MAIN_THREAD_EXECUTOR.execute(() -> notifyImportEnd(context, successful)); + }); + } + + @UiThread + private static void notifyImportEnd(Context context, boolean successful) { + Toast.makeText( + context, + context.getString(successful ? R.string.import_success : R.string.import_failed), + Toast.LENGTH_LONG + ).show(); + } + + static void importBackup(Context context, Uri backupUri) throws IOException { + try (InputStream inputStream = context.getContentResolver().openInputStream(backupUri); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + StringBuilder contentBuilder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + contentBuilder.append(line); + } + JSONObject backupObject = new JSONObject(contentBuilder.toString()); + importBackup(context, backupObject); + } catch (JSONException exception) { + throw new IOException("Failed to parse backup file.", exception); + } catch (FileNotFoundException exception) { + throw new IOException("Failed to find backup file.", exception); + } catch (IOException exception) { + throw new IOException("Failed to read backup file.", exception); + } + } + + private static void importBackup(Context context, JSONObject backupObject) throws JSONException { + AppDatabase database = AppDatabase.getInstance(context); + HostsSourceDao hostsSourceDao = database.hostsSourceDao(); + HostListItemDao hostListItemDao = database.hostsListItemDao(); + + importSourceBackup(hostsSourceDao, backupObject.getJSONArray(SOURCES_KEY)); + importListBackup(hostListItemDao, BLOCKED, backupObject.getJSONArray(BLOCKED_KEY)); + importListBackup(hostListItemDao, ALLOWED, backupObject.getJSONArray(ALLOWED_KEY)); + importListBackup(hostListItemDao, REDIRECTED, backupObject.getJSONArray(REDIRECTED_KEY)); + } + + private static void importSourceBackup(HostsSourceDao hostsSourceDao, JSONArray sources) throws JSONException { + for (int index = 0; index < sources.length(); index++) { + JSONObject sourceObject = sources.getJSONObject(index); + hostsSourceDao.insert(sourceFromJson(sourceObject)); + } + } + + private static void importListBackup(HostListItemDao hostListItemDao, ListType type, JSONArray hosts) throws JSONException { + for (int index = 0; index < hosts.length(); index++) { + JSONObject hostObject = hosts.getJSONObject(index); + HostListItem host = hostFromJson(hostObject); + host.setType(type); + Optional id = hostListItemDao.getHostId(host.getHost()); + if (id.isPresent()) { + host.setId(id.get()); + hostListItemDao.update(host); + } else { + hostListItemDao.insert(host); + } + } + } +} diff --git a/app/src/main/java/org/adaway/model/error/HostError.java b/app/src/main/java/org/adaway/model/error/HostError.java new file mode 100644 index 0000000..de2106d --- /dev/null +++ b/app/src/main/java/org/adaway/model/error/HostError.java @@ -0,0 +1,44 @@ +package org.adaway.model.error; + +import androidx.annotation.StringRes; + +import org.adaway.R; + +/** + * This enumeration represents the hosts error case. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public enum HostError { + // Source model errors + NO_CONNECTION(R.string.error_no_connection_message, R.string.error_no_connection_details), + DOWNLOAD_FAILED(R.string.error_download_failed_message, R.string.error_no_connection_details), + // Host install model errors + PRIVATE_FILE_FAILED(R.string.error_private_file_failed_message, R.string.error_private_file_failed_details), + NOT_ENOUGH_SPACE(R.string.error_not_enough_space_message, R.string.error_not_enough_space_details), + COPY_FAIL(R.string.error_copy_failed_message, R.string.error_copy_failed_details), + REVERT_FAIL(R.string.error_revert_failed_message, R.string.error_revert_failed_details), + // VPN model error + ENABLE_VPN_FAIL(R.string.error_enable_vpn_failed_message, R.string.error_enable_vpn_failed_details), + DISABLE_VPN_FAIL(R.string.error_disable_vpn_failed_message, R.string.error_disable_vpn_failed_details); + + @StringRes + private final int messageKey; + @StringRes + private final int detailsKey; + + HostError(int messageKey, int detailsKey) { + this.messageKey = messageKey; + this.detailsKey = detailsKey; + } + + @StringRes + public int getMessageKey() { + return this.messageKey; + } + + @StringRes + public int getDetailsKey() { + return this.detailsKey; + } +} diff --git a/app/src/main/java/org/adaway/model/error/HostErrorException.java b/app/src/main/java/org/adaway/model/error/HostErrorException.java new file mode 100644 index 0000000..50550f1 --- /dev/null +++ b/app/src/main/java/org/adaway/model/error/HostErrorException.java @@ -0,0 +1,43 @@ +package org.adaway.model.error; + +/** + * This class in an {@link Exception} thrown on hosts error. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class HostErrorException extends Exception { + /** + * The exception error type. + */ + private final HostError error; + + /** + * Constructor. + * + * @param error The exception error type. + */ + public HostErrorException(HostError error) { + super("An host error " + error.name() + " occurred"); + this.error = error; + } + + /** + * Constructor. + * + * @param error The exception error type. + * @param cause The cause of this exception. + */ + public HostErrorException(HostError error, Throwable cause) { + super("An host error " + error.name() + " occurred", cause); + this.error = error; + } + + /** + * Get the error type. + * + * @return The exception error type + */ + public HostError getError() { + return this.error; + } +} diff --git a/app/src/main/java/org/adaway/model/git/GistHostsSource.java b/app/src/main/java/org/adaway/model/git/GistHostsSource.java new file mode 100644 index 0000000..31d0afc --- /dev/null +++ b/app/src/main/java/org/adaway/model/git/GistHostsSource.java @@ -0,0 +1,61 @@ +package org.adaway.model.git; + +import androidx.annotation.Nullable; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.net.MalformedURLException; +import java.net.URL; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; + +import timber.log.Timber; + +/** + * This class is an utility class to get information from GitHub gist hosting. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class GistHostsSource extends GitHostsJsonApiSource { + /** + * The gist identifier. + */ + private final String gistIdentifier; + + /** + * Constructor. + * + * @param url The hosts file URL hosted on GitHub gist. + * @throws MalformedURLException If the URl is not a gist URL. + */ + GistHostsSource(String url) throws MalformedURLException { + // Check URL path + URL parsedUrl = new URL(url); + String path = parsedUrl.getPath(); + String[] pathParts = path.split("/"); + if (pathParts.length < 2) { + throw new MalformedURLException("The GitHub gist URL " + url + " is not valid."); + } + // Extract gist identifier from path + this.gistIdentifier = pathParts[2]; + } + + @Override + protected String getCommitApiUrl() { + return "https://api.github.com/gists/" + this.gistIdentifier; + } + + @Nullable + protected ZonedDateTime parseJsonBody(String body) throws JSONException { + JSONObject gistObject = new JSONObject(body); + String dateString = gistObject.getString("updated_at"); + ZonedDateTime date = null; + try { + date = ZonedDateTime.parse(dateString); + } catch (DateTimeParseException exception) { + Timber.w(exception, "Failed to parse commit date: " + dateString + "."); + } + return date; + } +} diff --git a/app/src/main/java/org/adaway/model/git/GitHostsJsonApiSource.java b/app/src/main/java/org/adaway/model/git/GitHostsJsonApiSource.java new file mode 100644 index 0000000..a61962b --- /dev/null +++ b/app/src/main/java/org/adaway/model/git/GitHostsJsonApiSource.java @@ -0,0 +1,53 @@ +package org.adaway.model.git; + +import androidx.annotation.Nullable; + +import org.json.JSONException; + +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.time.ZonedDateTime; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import timber.log.Timber; + +/** + * This class is an utility class to get information from Git hosted hosts sources from JSON API. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public abstract class GitHostsJsonApiSource extends GitHostsSource { + @Override + @Nullable + public ZonedDateTime getLastUpdate() { + return getLastUpdateFromApi(getCommitApiUrl()); + } + + protected abstract String getCommitApiUrl(); + + @Nullable + protected ZonedDateTime getLastUpdateFromApi(String commitApiUrl) { + // Create client and request + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder().url(commitApiUrl).build(); + try (Response response = client.newCall(request).execute(); + ResponseBody body = response.body()) { + if (response.isSuccessful()) { + return parseJsonBody(body.string()); + } + } catch (UnknownHostException | SocketTimeoutException exception) { + Timber.i(exception, "Unable to reach API backend."); + } catch (IOException | JSONException exception) { + Timber.e(exception, "Unable to get commits from API."); + } + // Return failed + return null; + } + + @Nullable + protected abstract ZonedDateTime parseJsonBody(String body) throws JSONException; +} diff --git a/app/src/main/java/org/adaway/model/git/GitHostsSource.java b/app/src/main/java/org/adaway/model/git/GitHostsSource.java new file mode 100644 index 0000000..f1fad34 --- /dev/null +++ b/app/src/main/java/org/adaway/model/git/GitHostsSource.java @@ -0,0 +1,65 @@ +package org.adaway.model.git; + +import androidx.annotation.Nullable; + +import java.net.MalformedURLException; +import java.time.ZonedDateTime; + +/** + * This class is an utility class to get information from Git hosted hosts sources. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public abstract class GitHostsSource { + /** + * The GitHub repository URL. + */ + private static final String GITHUB_REPO_URL = "https://raw.githubusercontent.com/"; + /** + * The GitHub gist URL. + */ + private static final String GITHUB_GIST_URL = "https://gist.githubusercontent.com"; + /** + * The GitLab URL. + */ + private static final String GITLAB_URL = "https://gitlab.com/"; + + /** + * Check if a hosts file url is hosted on Git hosting. + * + * @param url The url to check. + * @return {@code true} if the hosts file is hosted on Git hosting, {@code false} otherwise. + */ + public static boolean isHostedOnGit(String url) { + return url.startsWith(GITHUB_REPO_URL) || + url.startsWith(GITHUB_GIST_URL) || + url.startsWith(GITLAB_URL); + } + + /** + * Get the GitHub hosts source. + * + * @param url The URL to get source from. + * @return The GitHub hosts source. + * @throws MalformedURLException If the URL is not a GitHub URL or not a supported GitHub URL. + */ + public static GitHostsSource getSource(String url) throws MalformedURLException { + if (url.startsWith(GITHUB_REPO_URL)) { + return new GitHubHostsSource(url); + } else if (url.startsWith(GITHUB_GIST_URL)) { + return new GistHostsSource(url); + } else if (url.startsWith(GITLAB_URL)) { + return new GitLabHostsSource(url); + } else { + throw new MalformedURLException("URL is not a supported Git hosting URL"); + } + } + + /** + * Get last update of the hosts file. + * + * @return The last update date, {@code null} if the date could not be retrieved. + */ + @Nullable + public abstract ZonedDateTime getLastUpdate(); +} diff --git a/app/src/main/java/org/adaway/model/git/GitHubHostsSource.java b/app/src/main/java/org/adaway/model/git/GitHubHostsSource.java new file mode 100644 index 0000000..890e8d4 --- /dev/null +++ b/app/src/main/java/org/adaway/model/git/GitHubHostsSource.java @@ -0,0 +1,84 @@ +package org.adaway.model.git; + +import static java.util.stream.Collectors.joining; + +import androidx.annotation.Nullable; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.net.MalformedURLException; +import java.net.URL; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.Arrays; + +import timber.log.Timber; + +/** + * This class is an utility class to get information from GitHub repository hosting. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class GitHubHostsSource extends GitHostsJsonApiSource { + /** + * The GitHub owner name. + */ + private final String owner; + /** + * The GitHub repository name. + */ + private final String repo; + /** + * The GitHub blob (hosts file) path. + */ + private final String blobPath; + + /** + * Constructor. + * + * @param url The hosts file URL hosted on GitHub. + * @throws MalformedURLException If the URl is not a GitHub URL. + */ + GitHubHostsSource(String url) throws MalformedURLException { + // Check URL path + URL parsedUrl = new URL(url); + String path = parsedUrl.getPath(); + String[] pathParts = path.split("/"); + if (pathParts.length < 5) { + throw new MalformedURLException("The GitHub user content URL " + url + " is not valid."); + } + // Extract components from path + this.owner = pathParts[1]; + this.repo = pathParts[2]; + this.blobPath = Arrays.stream(pathParts) + .skip(4) + .collect(joining("/")); + } + + @Override + protected String getCommitApiUrl() { + return "https://api.github.com/repos/" + this.owner + "/" + this.repo + + "/commits?per_page=1&path=" + this.blobPath; + } + + @Nullable + protected ZonedDateTime parseJsonBody(String body) throws JSONException { + JSONArray commitArray = new JSONArray(body); + int nbrOfCommits = commitArray.length(); + ZonedDateTime date = null; + for (int i = 0; i < nbrOfCommits && date == null; i++) { + JSONObject commitItemObject = commitArray.getJSONObject(i); + JSONObject commitObject = commitItemObject.getJSONObject("commit"); + JSONObject committerObject = commitObject.getJSONObject("committer"); + String dateString = committerObject.getString("date"); + try { + date = ZonedDateTime.parse(dateString); + } catch (DateTimeParseException exception) { + Timber.w(exception, "Failed to parse commit date: " + dateString + "."); + } + } + return date; + } +} diff --git a/app/src/main/java/org/adaway/model/git/GitLabHostsSource.java b/app/src/main/java/org/adaway/model/git/GitLabHostsSource.java new file mode 100644 index 0000000..cd35f67 --- /dev/null +++ b/app/src/main/java/org/adaway/model/git/GitLabHostsSource.java @@ -0,0 +1,81 @@ +package org.adaway.model.git; + +import static java.util.stream.Collectors.joining; + +import androidx.annotation.Nullable; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.net.MalformedURLException; +import java.net.URL; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.Arrays; + +import timber.log.Timber; + +/** + * This class is an utility class to get information from GitLab hosts source hosting. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class GitLabHostsSource extends GitHostsJsonApiSource { + /** + * The GitHub owner name. + */ + private final String owner; + /** + * The GitHub repository name. + */ + private final String repo; + /** + * The GitLab reference name. + */ + private final String ref; + /** + * The GitLab (hosts) file path. + */ + private final String path; + + GitLabHostsSource(String url) throws MalformedURLException { + // Check URL path + URL parsedUrl = new URL(url); + String path = parsedUrl.getPath(); + String[] pathParts = path.split("/"); + if (pathParts.length < 5) { + throw new MalformedURLException("The GitLab user content URL " + url + " is not valid."); + } + // Extract components from path + this.owner = pathParts[1]; + this.repo = pathParts[2]; + this.ref = pathParts[4]; + this.path = Arrays.stream(pathParts) + .skip(5) + .collect(joining("/")); + } + + @Override + protected String getCommitApiUrl() { + return "https://gitlab.com/api/v4/projects/" + this.owner + "%2F" + this.repo + + "/repository/commits?path=" + this.path + "&ref_name=" + this.ref; + } + + @Nullable + protected ZonedDateTime parseJsonBody(String body) throws JSONException { + JSONArray commitArray = new JSONArray(body); + int nbrOfCommits = commitArray.length(); + ZonedDateTime date = null; + for (int i = 0; i < nbrOfCommits && date == null; i++) { + JSONObject commitItemObject = commitArray.getJSONObject(i); + String dateString = commitItemObject.getString("committed_date"); + try { + date = ZonedDateTime.parse(dateString); + } catch (DateTimeParseException exception) { + Timber.w(exception, "Failed to parse commit date: " + dateString + "."); + } + } + return date; + } +} diff --git a/app/src/main/java/org/adaway/model/root/CommandException.java b/app/src/main/java/org/adaway/model/root/CommandException.java new file mode 100644 index 0000000..b755592 --- /dev/null +++ b/app/src/main/java/org/adaway/model/root/CommandException.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.model.root; + +class CommandException extends Exception { + + private static final long serialVersionUID = -4014185620880841310L; + + CommandException(String msg) { + super(msg); + } +} diff --git a/app/src/main/java/org/adaway/model/root/MountType.java b/app/src/main/java/org/adaway/model/root/MountType.java new file mode 100644 index 0000000..f32e2dc --- /dev/null +++ b/app/src/main/java/org/adaway/model/root/MountType.java @@ -0,0 +1,31 @@ +package org.adaway.model.root; + +/** + * This class is an enum to define mount type. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public enum MountType { + /** + * Mount as read only. + */ + READ_ONLY("ro"), + /** + * Mount as read/write. + */ + READ_WRITE("rw"); + + private final String option; + + MountType(String option) { + this.option = option; + } + + /** + * Get related command line option. + * @return The related command line option. + */ + public String getOption() { + return this.option; + } +} diff --git a/app/src/main/java/org/adaway/model/root/RootModel.java b/app/src/main/java/org/adaway/model/root/RootModel.java new file mode 100644 index 0000000..6dc4cf1 --- /dev/null +++ b/app/src/main/java/org/adaway/model/root/RootModel.java @@ -0,0 +1,319 @@ +package org.adaway.model.root; + +import static android.content.Context.MODE_PRIVATE; +import static org.adaway.db.entity.ListType.REDIRECTED; +import static org.adaway.model.adblocking.AdBlockMethod.ROOT; +import static org.adaway.model.error.HostError.COPY_FAIL; +import static org.adaway.model.error.HostError.NOT_ENOUGH_SPACE; +import static org.adaway.model.error.HostError.PRIVATE_FILE_FAILED; +import static org.adaway.model.error.HostError.REVERT_FAIL; +import static org.adaway.model.root.ShellUtils.isWritable; +import static org.adaway.util.Constants.ANDROID_SYSTEM_ETC_HOSTS; +import static org.adaway.util.Constants.COMMAND_CHMOD_644; +import static org.adaway.util.Constants.COMMAND_CHOWN; +import static org.adaway.util.Constants.DEFAULT_HOSTS_FILENAME; +import static org.adaway.util.Constants.HOSTS_FILENAME; +import static org.adaway.util.Constants.LINE_SEPARATOR; +import static org.adaway.util.Constants.LOCALHOST_HOSTNAME; +import static org.adaway.util.Constants.LOCALHOST_IPV4; +import static org.adaway.util.Constants.LOCALHOST_IPV6; +import static org.adaway.model.root.MountType.READ_ONLY; +import static org.adaway.model.root.MountType.READ_WRITE; +import static org.adaway.model.root.ShellUtils.mergeAllLines; + +import android.content.Context; + +import com.topjohnwu.superuser.Shell; + +import org.adaway.R; +import org.adaway.db.AppDatabase; +import org.adaway.db.dao.HostEntryDao; +import org.adaway.db.dao.HostsSourceDao; +import org.adaway.db.entity.HostEntry; +import org.adaway.db.entity.HostsSource; +import org.adaway.helper.PreferenceHelper; +import org.adaway.model.adblocking.AdBlockMethod; +import org.adaway.model.adblocking.AdBlockModel; +import org.adaway.model.error.HostErrorException; +import org.adaway.util.AppExecutors; +import org.adaway.util.WebServerUtils; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.Executor; + +import timber.log.Timber; + +/** + * This class is the model to represent hosts file installation. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class RootModel extends AdBlockModel { + private static final String HEADER1 = "# This hosts file has been generated by AdAway on: "; + private static final String HEADER2 = "# Please do not modify it directly, it will be overwritten when AdAway is applied again."; + private static final String HEADER_SOURCES = "# This file is generated from the following sources:"; + private final HostsSourceDao hostsSourceDao; + private final HostEntryDao hostEntryDao; + + /** + * Constructor. + * + * @param context The application context. + */ + public RootModel(Context context) { + super(context); + // Get DOA + AppDatabase database = AppDatabase.getInstance(this.context); + this.hostsSourceDao = database.hostsSourceDao(); + this.hostEntryDao = database.hostEntryDao(); + // Check if host list is applied + Executor executor = AppExecutors.getInstance().diskIO(); + executor.execute(this::checkApplied); + executor.execute(() -> syncPreferences(context)); + } + + @Override + public AdBlockMethod getMethod() { + return ROOT; + } + + @Override + public void apply() throws HostErrorException { + setState(R.string.status_apply_sources); + setState(R.string.status_create_new_hosts); + createNewHostsFile(); + setState(R.string.status_copy_new_hosts); + copyNewHostsFile(); + setState(R.string.status_check_copy); + setState(R.string.status_hosts_updated); + this.applied.postValue(true); + } + + /** + * Revert to the default hosts file. + * + * @throws HostErrorException If the hosts file could not be reverted. + */ + @Override + public void revert() throws HostErrorException { + // Update status + setState(R.string.status_revert); + try { + // Revert hosts file + revertHostFile(); + setState(R.string.status_revert_done); + this.applied.postValue(false); + } catch (IOException exception) { + throw new HostErrorException(REVERT_FAIL, exception); + } + } + + @Override + public boolean isRecordingLogs() { + return TcpdumpUtils.isTcpdumpRunning(); + } + + @Override + public void setRecordingLogs(boolean recording) { + if (recording) { + TcpdumpUtils.startTcpdump(this.context); + } else { + TcpdumpUtils.stopTcpdump(); + } + } + + @Override + public List getLogs() { + return TcpdumpUtils.getLogs(this.context); + } + + @Override + public void clearLogs() { + TcpdumpUtils.clearLogFile(this.context); + } + + private void checkApplied() { + boolean applied = false; + + Shell.Result result = Shell.cmd("head -n 1 " + ANDROID_SYSTEM_ETC_HOSTS).exec(); + if (!result.isSuccess()) { + Timber.e("Failed to read first line of hosts file. Error code: %s", result.getCode()); + } else { + applied = mergeAllLines(result.getOut()).startsWith(HEADER1); + } + + this.applied.postValue(applied); + } + + private void syncPreferences(Context context) { + if (PreferenceHelper.getWebServerEnabled(context) && !WebServerUtils.isWebServerRunning()) { + WebServerUtils.startWebServer(context); + } + } + + private void deleteNewHostsFile() { + // delete generated hosts file from private storage + this.context.deleteFile(HOSTS_FILENAME); + } + + private void copyNewHostsFile() throws HostErrorException { + try { + copyHostsFile(HOSTS_FILENAME); + } catch (CommandException exception) { + throw new HostErrorException(COPY_FAIL, exception); + } + } + + /** + * Create a new hosts files in a private file from downloaded hosts sources. + * + * @throws HostErrorException If the new hosts file could not be created. + */ + private void createNewHostsFile() throws HostErrorException { + deleteNewHostsFile(); + try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(this.context.openFileOutput(HOSTS_FILENAME, MODE_PRIVATE)))) { + writeHostsHeader(writer); + writeLoopbackToHosts(writer); + writeHosts(writer); + } catch (IOException exception) { + throw new HostErrorException(PRIVATE_FILE_FAILED, exception); + } + } + + private void writeHostsHeader(BufferedWriter writer) throws IOException { + // Format current date + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); + Date now = new Date(); + String date = formatter.format(now); + // Write header + writer.write(HEADER1); + writer.write(date); + writer.newLine(); + writer.write(HEADER2); + writer.newLine(); + // Write hosts source + writer.write(HEADER_SOURCES); + writer.newLine(); + for (HostsSource hostsSource : this.hostsSourceDao.getEnabled()) { + writer.write("# - " + hostsSource.getLabel() + ":" + hostsSource.getUrl()); + writer.newLine(); + } + // Write empty line separator + writer.newLine(); + } + + private void writeLoopbackToHosts(BufferedWriter writer) throws IOException { + writer.write(LOCALHOST_IPV4 + " " + LOCALHOST_HOSTNAME); + writer.newLine(); + writer.write(LOCALHOST_IPV6 + " " + LOCALHOST_HOSTNAME); + writer.newLine(); + } + + private void writeHosts(BufferedWriter writer) throws IOException { + // Get user preferences + String redirectionIpv4 = PreferenceHelper.getRedirectionIpv4(this.context); + String redirectionIpv6 = PreferenceHelper.getRedirectionIpv6(this.context); + boolean enableIpv6 = PreferenceHelper.getEnableIpv6(this.context); + // Write each hostname + for (HostEntry entry : this.hostEntryDao.getAll()) { + String hostname = entry.getHost(); + if (entry.getType() == REDIRECTED) { + writer.write(entry.getRedirection() + " " + hostname); + writer.newLine(); + } else { + writer.write(redirectionIpv4 + " " + hostname); + writer.newLine(); + if (enableIpv6) { + writer.write(redirectionIpv6 + " " + hostname); + writer.newLine(); + } + } + } + } + + /** + * Revert to default hosts file. + * + * @throws IOException If the hosts file could not be reverted. + */ + private void revertHostFile() throws IOException { + // Create private file + try (FileOutputStream fos = this.context.openFileOutput(DEFAULT_HOSTS_FILENAME, MODE_PRIVATE)) { + // Write default localhost as hosts file + String localhost = LOCALHOST_IPV4 + " " + LOCALHOST_HOSTNAME + LINE_SEPARATOR + + LOCALHOST_IPV6 + " " + LOCALHOST_HOSTNAME + LINE_SEPARATOR; + fos.write(localhost.getBytes()); + // Copy generated hosts file to target location + copyHostsFile(DEFAULT_HOSTS_FILENAME); + // Delete generated hosts file after applying it + this.context.deleteFile(DEFAULT_HOSTS_FILENAME); + } catch (Exception exception) { + throw new IOException("Unable to revert hosts file.", exception); + } + } + + /** + * Copy source file from private storage of AdAway to hosts file target using root commands. + */ + private void copyHostsFile(String source) throws HostErrorException, CommandException { + String privateDir = this.context.getFilesDir().getAbsolutePath(); + String privateFile = privateDir + File.separator + source; + + // if the target has a trailing slash, it is not a valid target! + String target = ANDROID_SYSTEM_ETC_HOSTS; + File targetFile = new File(target); + + /* check for space on partition */ + long size = new File(privateFile).length(); + Timber.i("Size of hosts file: %s.", size); + if (!hasEnoughSpaceOnPartition(targetFile, size)) { + throw new HostErrorException(NOT_ENOUGH_SPACE); + } + + /* Execute commands */ + boolean writable = isWritable(targetFile); + try { + if (!writable) { + // remount for write access + Timber.i("Remounting for RW…"); + if (!ShellUtils.remountPartition(targetFile, READ_WRITE)) { + throw new CommandException("Failed to remount hosts file partition as read-write."); + } + } + // Copy hosts file then set owner and permissions + Shell.Result result = Shell.cmd( + "dd if=" + privateFile + " of=" + target, + COMMAND_CHOWN + " " + target, + COMMAND_CHMOD_644 + " " + target + ).exec(); + if (!result.isSuccess()) { + throw new CommandException("Failed to copy hosts file: " + mergeAllLines(result.getErr())); + } + } finally { + if (!writable) { + // after all remount target back as read only + ShellUtils.remountPartition(targetFile, READ_ONLY); + } + } + } + + /** + * Check if there is enough space on partition where target is located + * + * @param size size of file to put on partition + * @param target path where to put the file + * @return true if it will fit on partition of target, false if it will not fit. + */ + private boolean hasEnoughSpaceOnPartition(File target, long size) { + long freeSpace = target.getFreeSpace(); + return (freeSpace == 0 || freeSpace > size); + } +} diff --git a/app/src/main/java/org/adaway/model/root/ShellUtils.java b/app/src/main/java/org/adaway/model/root/ShellUtils.java new file mode 100644 index 0000000..f50f30b --- /dev/null +++ b/app/src/main/java/org/adaway/model/root/ShellUtils.java @@ -0,0 +1,99 @@ +package org.adaway.model.root; + +import static com.topjohnwu.superuser.ShellUtils.escapedString; + +import android.content.Context; + +import com.topjohnwu.superuser.Shell; + +import java.io.File; +import java.util.List; +import java.util.Optional; + +import timber.log.Timber; + +/** + * This class is an utility class to help with shell commands. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class ShellUtils { + private static final String EXECUTABLE_PREFIX = "lib"; + private static final String EXECUTABLE_SUFFIX = "_exec.so"; + + /** + * Private constructor. + */ + private ShellUtils() { + + } + + public static String mergeAllLines(List lines) { + return String.join("\n", lines); + } + + public static boolean isBundledExecutableRunning(String executable) { + return Shell.cmd("ps -A | grep " + EXECUTABLE_PREFIX + executable + EXECUTABLE_SUFFIX).exec().isSuccess(); + } + + public static boolean runBundledExecutable(Context context, String executable, String parameters) { + String nativeLibraryDir = context.getApplicationInfo().nativeLibraryDir; + String command = "LD_LIBRARY_PATH=" + nativeLibraryDir + " " + + nativeLibraryDir + File.separator + EXECUTABLE_PREFIX + executable + EXECUTABLE_SUFFIX + " " + + parameters + " &"; + return Shell.cmd(command).exec().isSuccess(); + } + + public static void killBundledExecutable(String executable) { + Shell.cmd("killall " + EXECUTABLE_PREFIX + executable + EXECUTABLE_SUFFIX).exec(); + } + + + + /** + * Check if a path is writable. + * + * @param file The file to check. + * @return true if the path is writable, false otherwise. + */ + public static boolean isWritable(File file) { + // Check first if file can be written without privileges + if (file.canWrite()) { + return true; + } + return Shell.cmd("test -w " + escapedString(file.getAbsolutePath())) + .exec() + .isSuccess(); + } + + public static boolean remountPartition(File file, MountType type) { + Optional partitionOptional = findPartition(file); + if (!partitionOptional.isPresent()) { + return false; + } + String partition = partitionOptional.get(); + Shell.Result result = Shell.cmd("mount -o " + type.getOption() + ",remount " + partition).exec(); + boolean success = result.isSuccess(); + if (!success) { + Timber.w("Failed to remount partition %s as %s: %s.", partition, type.getOption(), mergeAllLines(result.getErr())); + } + return success; + } + + private static Optional findPartition(File file) { + // Get mount points + Shell.Result result = Shell.cmd("cat /proc/mounts | cut -d ' ' -f2").exec(); + List out = result.getOut(); + // Check file and each parent against mount points + while (file != null) { + String path = file.getAbsolutePath(); + for (String mount : out) { + if (path.equals(mount)) { + return Optional.of(mount); + } + } + file = file.getParentFile(); + } + return Optional.empty(); + } +} diff --git a/app/src/main/java/org/adaway/model/root/TcpdumpUtils.java b/app/src/main/java/org/adaway/model/root/TcpdumpUtils.java new file mode 100644 index 0000000..664a99d --- /dev/null +++ b/app/src/main/java/org/adaway/model/root/TcpdumpUtils.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.model.root; + +import android.content.Context; + +import com.topjohnwu.superuser.Shell; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.util.Collections.emptyList; +import static org.adaway.model.root.ShellUtils.isBundledExecutableRunning; +import static org.adaway.model.root.ShellUtils.killBundledExecutable; +import static org.adaway.model.root.ShellUtils.mergeAllLines; +import static org.adaway.model.root.ShellUtils.runBundledExecutable; + +import timber.log.Timber; + +class TcpdumpUtils { + private static final String TCPDUMP_EXECUTABLE = "tcpdump"; + private static final String TCPDUMP_LOG = "dns_log.txt"; + private static final String TCPDUMP_HOSTNAME_REGEX = "(?:A\\?|AAAA\\?)\\s(\\S+)\\.\\s"; + private static final Pattern TCPDUMP_HOSTNAME_PATTERN = Pattern.compile(TCPDUMP_HOSTNAME_REGEX); + + /** + * Private constructor. + */ + private TcpdumpUtils() { + + } + + /** + * Checks if tcpdump is running + * + * @return true if tcpdump is running + */ + static boolean isTcpdumpRunning() { + return isBundledExecutableRunning(TCPDUMP_EXECUTABLE); + } + + /** + * Start tcpdump tool. + * + * @param context The application context. + * @return returns true if starting worked + */ + static boolean startTcpdump(Context context) { + Timber.d("Starting tcpdump..."); + checkSystemTcpdump(); + + File file = getLogFile(context); + try { + // Create log file before using it with tcpdump if not exists + if (!file.exists() && !file.createNewFile()) { + return false; + } + } catch (IOException e) { + Timber.e(e, "Problem while getting cache directory!"); + return false; + } + + // "-i any": listen on any network interface + // "-p": disable promiscuous mode (doesn't work anyway) + // "-l": Make stdout line buffered. Useful if you want to see the data while + // capturing it. + // "-v": verbose + // "-t": don't print a timestamp + // "-s 0": capture first 512 bit of packet to get DNS content + String parameters = "-i any -p -l -v -t -s 512 'udp dst port 53' >> " + file + " 2>&1"; + + return runBundledExecutable(context, TCPDUMP_EXECUTABLE, parameters); + } + + /** + * Stop tcpdump. + */ + static void stopTcpdump() { + killBundledExecutable(TCPDUMP_EXECUTABLE); + } + + /** + * Check if tcpdump binary in bundled in the system. + */ + static void checkSystemTcpdump() { + try { + Shell.Result result = Shell.cmd("tcpdump --version").exec(); + int exitCode = result.getCode(); + String output = mergeAllLines(result.getOut()); + String msg = "Tcpdump " + ( + exitCode == 0 ? + "present" : + "missing (" + exitCode + ")" + ) + "\n" + output; + Timber.i(msg); + } catch (Exception exception) { + Timber.w(exception, "Failed to check system tcpdump binary."); + } + } + + /** + * Get the tcpdump log file. + * + * @param context The application context. + * @return The tcpdump log file. + */ + static File getLogFile(Context context) { + return new File(context.getCacheDir(), TCPDUMP_LOG); + } + + /** + * Get the tcpdump log content. + * + * @param context The application context. + * @return The tcpdump log file content. + */ + static List getLogs(Context context) { + Path logPath = getLogFile(context).toPath(); + // Check if the log file exists + if (!Files.exists(logPath)) { + return emptyList(); + } + try (Stream lines = Files.lines(logPath)) { + return lines + .map(TcpdumpUtils::getTcpdumpHostname) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + } catch (IOException exception) { + Timber.e(exception, "Can not get cache directory."); + return emptyList(); + } + } + + /** + * Delete log file of tcpdump. + * + * @param context The application context. + */ + static boolean clearLogFile(Context context) { + // Get the log file + File file = getLogFile(context); + // Check if file exists + if (!file.exists()) { + return true; + } + // Truncate the file content + try (FileOutputStream outputStream = new FileOutputStream(file, false)) { + // Only truncate the file + outputStream.close(); // Useless but help lint + } catch (IOException exception) { + Timber.e(exception, "Error while truncating the tcpdump file!"); + // Return failed to clear the log file + return false; + } + // Return successfully clear the log file + return true; + } + + /** + * Gets hostname out of tcpdump log line. + * + * @param input One line from dns log. + * @return A hostname or {code null} if no DNS query in the input. + */ + private static String getTcpdumpHostname(String input) { + Matcher tcpdumpHostnameMatcher = TCPDUMP_HOSTNAME_PATTERN.matcher(input); + if (tcpdumpHostnameMatcher.find()) { + return tcpdumpHostnameMatcher.group(1); + } else { + Timber.d("Does not find: %s.", input); + return null; + } + } +} diff --git a/app/src/main/java/org/adaway/model/root/package-info.java b/app/src/main/java/org/adaway/model/root/package-info.java new file mode 100644 index 0000000..224ddbd --- /dev/null +++ b/app/src/main/java/org/adaway/model/root/package-info.java @@ -0,0 +1,9 @@ +/** + * The root ad-blocker related implementations. + * + * It relies on libsu from John Wu and shell commands. + * Supported shell commands are described here: https://chromium.googlesource.com/aosp/platform/system/core/+/upstream/shell_and_utilities/#android-8_0-oreo + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +package org.adaway.model.root; \ No newline at end of file diff --git a/app/src/main/java/org/adaway/model/source/SourceLoader.java b/app/src/main/java/org/adaway/model/source/SourceLoader.java new file mode 100644 index 0000000..bc2cfdd --- /dev/null +++ b/app/src/main/java/org/adaway/model/source/SourceLoader.java @@ -0,0 +1,267 @@ +package org.adaway.model.source; + +import static org.adaway.db.entity.ListType.ALLOWED; +import static org.adaway.db.entity.ListType.BLOCKED; +import static org.adaway.db.entity.ListType.REDIRECTED; +import static org.adaway.util.Constants.BOGUS_IPV4; +import static org.adaway.util.Constants.LOCALHOST_HOSTNAME; +import static org.adaway.util.Constants.LOCALHOST_IPV4; +import static org.adaway.util.Constants.LOCALHOST_IPV6; + +import org.adaway.db.dao.HostListItemDao; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.HostsSource; +import org.adaway.db.entity.ListType; +import org.adaway.util.RegexUtils; + +import java.io.BufferedReader; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import timber.log.Timber; + +/** + * This class is an {@link HostsSource} loader.
    + * It parses a source and loads it to database. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class SourceLoader { + private static final String TAG = "SourceLoader"; + private static final String END_OF_QUEUE_MARKER = "#EndOfQueueMarker"; + private static final int INSERT_BATCH_SIZE = 100; + private static final String HOSTS_PARSER = "^\\s*([^#\\s]+)\\s+([^#\\s]+).*$"; + static final Pattern HOSTS_PARSER_PATTERN = Pattern.compile(HOSTS_PARSER); + + private final HostsSource source; + + SourceLoader(HostsSource hostsSource) { + this.source = hostsSource; + } + + void parse(BufferedReader reader, HostListItemDao hostListItemDao) { + // Clear current hosts + hostListItemDao.clearSourceHosts(this.source.getId()); + // Create batch + int parserCount = 3; + LinkedBlockingQueue hostsLineQueue = new LinkedBlockingQueue<>(); + LinkedBlockingQueue hostsListItemQueue = new LinkedBlockingQueue<>(); + SourceReader sourceReader = new SourceReader(reader, hostsLineQueue, parserCount); + ItemInserter inserter = new ItemInserter(hostsListItemQueue, hostListItemDao, parserCount); + ExecutorService executorService = Executors.newFixedThreadPool( + parserCount + 2, + r -> new Thread(r, TAG) + ); + executorService.execute(sourceReader); + for (int i = 0; i < parserCount; i++) { + executorService.execute(new HostListItemParser(this.source, hostsLineQueue, hostsListItemQueue)); + } + Future inserterFuture = executorService.submit(inserter); + try { + Integer inserted = inserterFuture.get(); + Timber.i("%s host list items inserted.", inserted); + } catch (ExecutionException e) { + Timber.w(e, "Failed to parse hosts sources."); + } catch (InterruptedException e) { + Timber.w(e, "Interrupted while parsing sources."); + Thread.currentThread().interrupt(); + } + executorService.shutdown(); + } + + private static class SourceReader implements Runnable { + private final BufferedReader reader; + private final BlockingQueue queue; + private final int parserCount; + + private SourceReader(BufferedReader reader, BlockingQueue queue, int parserCount) { + this.reader = reader; + this.queue = queue; + this.parserCount = parserCount; + } + + @Override + public void run() { + try { + this.reader.lines().forEach(this.queue::add); + } catch (Throwable t) { + Timber.w(t, "Failed to read hosts source."); + } finally { + // Send end of queue marker to parsers + for (int i = 0; i < this.parserCount; i++) { + this.queue.add(END_OF_QUEUE_MARKER); + } + } + } + } + + private static class HostListItemParser implements Runnable { + private final HostsSource source; + private final BlockingQueue lineQueue; + private final BlockingQueue itemQueue; + + private HostListItemParser(HostsSource source, BlockingQueue lineQueue, BlockingQueue itemQueue) { + this.source = source; + this.lineQueue = lineQueue; + this.itemQueue = itemQueue; + } + + @Override + public void run() { + boolean allowedList = this.source.isAllowEnabled(); + boolean endOfSource = false; + while (!endOfSource) { + try { + String line = this.lineQueue.take(); + // Check end of queue marker + //noinspection StringEquality + if (line == END_OF_QUEUE_MARKER) { + endOfSource = true; + // Send end of queue marker to inserter + HostListItem endItem = new HostListItem(); + endItem.setHost(line); + this.itemQueue.add(endItem); + } // Check comments + else if (line.isEmpty() || line.charAt(0) == '#') { + Timber.d("Skip comment: %s.", line); + } else { + HostListItem item = allowedList ? parseAllowListItem(line) : parseHostListItem(line); + if (item != null && isRedirectionValid(item) && isHostValid(item)) { + this.itemQueue.add(item); + } + } + } catch (InterruptedException e) { + Timber.w(e, "Interrupted while parsing hosts list item."); + endOfSource = true; + Thread.currentThread().interrupt(); + } + } + } + + private HostListItem parseHostListItem(String line) { + Matcher matcher = HOSTS_PARSER_PATTERN.matcher(line); + if (!matcher.matches()) { + Timber.d("Does not match: %s.", line); + return null; + } + // Check IP address validity or while list entry (if allowed) + String ip = matcher.group(1); + String hostname = matcher.group(2); + assert hostname != null; + // Skip localhost name + if (LOCALHOST_HOSTNAME.equals(hostname)) { + return null; + } + // check if ip is 127.0.0.1 or 0.0.0.0 + ListType type; + if (LOCALHOST_IPV4.equals(ip) + || BOGUS_IPV4.equals(ip) + || LOCALHOST_IPV6.equals(ip)) { + type = BLOCKED; + } else if (this.source.isRedirectEnabled()) { + type = REDIRECTED; + } else { + return null; + } + HostListItem item = new HostListItem(); + item.setType(type); + item.setHost(hostname); + item.setEnabled(true); + if (type == REDIRECTED) { + item.setRedirection(ip); + } + item.setSourceId(this.source.getId()); + return item; + } + + private HostListItem parseAllowListItem(String line) { + // Extract hostname + int indexOf = line.indexOf('#'); + if (indexOf == 1) { + line = line.substring(0, indexOf); + } + line = line.trim(); + // Create item + HostListItem item = new HostListItem(); + item.setType(ALLOWED); + item.setHost(line); + item.setEnabled(true); + item.setSourceId(this.source.getId()); + return item; + } + + private boolean isRedirectionValid(HostListItem item) { + return item.getType() != REDIRECTED || RegexUtils.isValidIP(item.getRedirection()); + } + + private boolean isHostValid(HostListItem item) { + String hostname = item.getHost(); + if (item.getType() == BLOCKED) { + if (hostname.indexOf('?') != -1 || hostname.indexOf('*') != -1) { + return false; + } + return RegexUtils.isValidHostname(hostname); + } + return RegexUtils.isValidWildcardHostname(hostname); + } + } + + private static class ItemInserter implements Callable { + private final BlockingQueue hostListItemQueue; + private final HostListItemDao hostListItemDao; + private final int parserCount; + + private ItemInserter(BlockingQueue itemQueue, HostListItemDao hostListItemDao, int parserCount) { + this.hostListItemQueue = itemQueue; + this.hostListItemDao = hostListItemDao; + this.parserCount = parserCount; + } + + @Override + public Integer call() { + int inserted = 0; + int workerStopped = 0; + HostListItem[] batch = new HostListItem[INSERT_BATCH_SIZE]; + int cacheSize = 0; + boolean queueEmptied = false; + while (!queueEmptied) { + try { + HostListItem item = this.hostListItemQueue.take(); + // Check end of queue marker + //noinspection StringEquality + if (item.getHost() == END_OF_QUEUE_MARKER) { + workerStopped++; + if (workerStopped >= this.parserCount) { + queueEmptied = true; + } + } else { + batch[cacheSize++] = item; + if (cacheSize >= batch.length) { + this.hostListItemDao.insert(batch); + inserted += cacheSize; + cacheSize = 0; + } + } + } catch (InterruptedException e) { + Timber.w(e, "Interrupted while inserted hosts list item."); + queueEmptied = true; + Thread.currentThread().interrupt(); + } + } + // Flush current batch + HostListItem[] remaining = new HostListItem[cacheSize]; + System.arraycopy(batch, 0, remaining, 0, remaining.length); + this.hostListItemDao.insert(remaining); + inserted += cacheSize; + // Return number of inserted items + return inserted; + } + } +} diff --git a/app/src/main/java/org/adaway/model/source/SourceModel.java b/app/src/main/java/org/adaway/model/source/SourceModel.java new file mode 100644 index 0000000..91fccb2 --- /dev/null +++ b/app/src/main/java/org/adaway/model/source/SourceModel.java @@ -0,0 +1,508 @@ +package org.adaway.model.source; + +import static android.content.Context.CONNECTIVITY_SERVICE; +import static android.provider.DocumentsContract.Document.COLUMN_LAST_MODIFIED; +import static org.adaway.model.error.HostError.DOWNLOAD_FAILED; +import static org.adaway.model.error.HostError.NO_CONNECTION; +import static java.net.HttpURLConnection.HTTP_NOT_MODIFIED; +import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; +import static java.time.format.FormatStyle.MEDIUM; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.util.Objects.requireNonNull; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import org.adaway.R; +import org.adaway.db.AppDatabase; +import org.adaway.db.converter.ZonedDateTimeConverter; +import org.adaway.db.dao.HostEntryDao; +import org.adaway.db.dao.HostListItemDao; +import org.adaway.db.dao.HostsSourceDao; +import org.adaway.db.entity.HostEntry; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.HostsSource; +import org.adaway.model.error.HostErrorException; +import org.adaway.model.git.GitHostsSource; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.MalformedURLException; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.List; + +import okhttp3.Cache; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import timber.log.Timber; + +/** + * This class is the model to represent hosts source management. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class SourceModel { + /** + * The HTTP client cache size (100Mo). + */ + private static final long CACHE_SIZE = 100L * 1024L * 1024L; + private static final String LAST_MODIFIED_HEADER = "Last-Modified"; + private static final String IF_NONE_MATCH_HEADER = "If-None-Match"; + private static final String IF_MODIFIED_SINCE_HEADER = "If-Modified-Since"; + private static final String ENTITY_TAG_HEADER = "ETag"; + private static final String WEAK_ENTITY_TAG_PREFIX = "W/"; + /** + * The application context. + */ + private final Context context; + /** + * The {@link HostsSource} DAO. + */ + private final HostsSourceDao hostsSourceDao; + /** + * The {@link HostListItem} DAO. + */ + private final HostListItemDao hostListItemDao; + /** + * The {@link HostEntry} DAO. + */ + private final HostEntryDao hostEntryDao; + /** + * The update available status. + */ + private final MutableLiveData updateAvailable; + /** + * The model state. + */ + private final MutableLiveData state; + /** + * The HTTP client to download hosts sources ({@code null} until initialized by {@link #getHttpClient()}). + */ + private OkHttpClient cachedHttpClient; + + /** + * Constructor. + * + * @param context The application context. + */ + public SourceModel(Context context) { + this.context = context; + AppDatabase database = AppDatabase.getInstance(this.context); + this.hostsSourceDao = database.hostsSourceDao(); + this.hostListItemDao = database.hostsListItemDao(); + this.hostEntryDao = database.hostEntryDao(); + this.state = new MutableLiveData<>(""); + this.updateAvailable = new MutableLiveData<>(); + this.updateAvailable.setValue(false); + SourceUpdateService.syncPreferences(context); + } + + /** + * Get the model state. + * + * @return The model state. + */ + public LiveData getState() { + return this.state; + } + + /** + * Get the update available status. + * + * @return {@code true} if source update is available, {@code false} otherwise. + */ + public LiveData isUpdateAvailable() { + return this.updateAvailable; + } + + /** + * Check if there is update available for hosts sources. + * + * @throws HostErrorException If the hosts sources could not be checked. + */ + public boolean checkForUpdate() throws HostErrorException { + // Check current connection + if (isDeviceOffline()) { + throw new HostErrorException(NO_CONNECTION); + } + // Initialize update status + boolean updateAvailable = false; + // Get enabled hosts sources + List sources = this.hostsSourceDao.getEnabled(); + if (sources.isEmpty()) { + // Return no update as no source + this.updateAvailable.postValue(false); + return false; + } + // Update state + setState(R.string.status_check); + // Check each source + for (HostsSource source : sources) { + // Get URL and lastModified from db + ZonedDateTime lastModifiedLocal = source.getLocalModificationDate(); + // Update state + setState(R.string.status_check_source, source.getLabel()); + // Get hosts source last update + ZonedDateTime lastModifiedOnline = getHostsSourceLastUpdate(source); + // Some help with debug here + Timber.d("lastModifiedLocal: %s", dateToString(lastModifiedLocal)); + Timber.d("lastModifiedOnline: %s", dateToString(lastModifiedOnline)); + // Save last modified online + this.hostsSourceDao.updateOnlineModificationDate(source.getId(), lastModifiedOnline); + // Check if last modified online retrieved + if (lastModifiedOnline == null) { + // If not, consider update is available if install is older than a week + ZonedDateTime lastWeek = ZonedDateTime.now().minus(1, WEEKS); + if (lastModifiedLocal != null && lastModifiedLocal.isBefore(lastWeek)) { + updateAvailable = true; + } + } else { + // Check if source was never installed or installed before the last update + if (lastModifiedLocal == null || lastModifiedOnline.isAfter(lastModifiedLocal)) { + updateAvailable = true; + } + } + } + // Update statuses + Timber.d("Update check result: %s.", updateAvailable); + if (updateAvailable) { + setState(R.string.status_update_available); + } else { + setState(R.string.status_no_update_found); + } + this.updateAvailable.postValue(updateAvailable); + return updateAvailable; + } + + /** + * Format {@link ZonedDateTime} for printing. + * + * @param zonedDateTime The date to format. + * @return The formatted date string. + */ + private String dateToString(ZonedDateTime zonedDateTime) { + if (zonedDateTime == null) { + return "not defined"; + } else { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(MEDIUM); + return zonedDateTime + " (" + zonedDateTime.format(dateTimeFormatter) + ")"; + } + } + + /** + * Checks if device is offline. + * + * @return returns {@code true} if device is offline, {@code false} otherwise. + */ + private boolean isDeviceOffline() { + ConnectivityManager connectivityManager = (ConnectivityManager) this.context.getSystemService(CONNECTIVITY_SERVICE); + if (connectivityManager == null) { + return false; + } + NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo(); + return netInfo == null || !netInfo.isConnectedOrConnecting(); + } + + /** + * Get the hosts source last online update. + * + * @param source The hosts source to get last online update. + * @return The last online date, {@code null} if the date could not be retrieved. + */ + @Nullable + private ZonedDateTime getHostsSourceLastUpdate(HostsSource source) { + switch (source.getType()) { + case URL: + return getUrlLastUpdate(source); + case FILE: + Uri fileUri = Uri.parse(source.getUrl()); + return getFileLastUpdate(fileUri); + default: + return null; + } + } + + /** + * Get the url last online update. + * + * @param source The source to get last online update. + * @return The last online date, {@code null} if the date could not be retrieved. + */ + private ZonedDateTime getUrlLastUpdate(HostsSource source) { + String url = source.getUrl(); + Timber.v("Checking url last update for source: %s.", url); + // Check Git hosting + if (GitHostsSource.isHostedOnGit(url)) { + try { + return GitHostsSource.getSource(url).getLastUpdate(); + } catch (MalformedURLException e) { + Timber.w(e, "Failed to get Git last commit for url %s.", url); + return null; + } + } + // Default hosting + Request request = getRequestFor(source).head().build(); + try (Response response = getHttpClient().newCall(request).execute()) { + String lastModified = response.header(LAST_MODIFIED_HEADER); + if (lastModified == null) { + return response.code() == HTTP_NOT_MODIFIED ? + source.getOnlineModificationDate() : null; + } + return ZonedDateTime.parse(lastModified, RFC_1123_DATE_TIME); + } catch (IOException | DateTimeParseException e) { + Timber.e(e, "Exception while fetching last modified date of source %s.", url); + return null; + } + } + + /** + * Get the file last modified date. + * + * @param fileUri The file uri to get last modified date. + * @return The file last modified date, {@code null} if date could not be retrieved. + */ + private ZonedDateTime getFileLastUpdate(Uri fileUri) { + ContentResolver contentResolver = this.context.getContentResolver(); + try (Cursor cursor = contentResolver.query(fileUri, null, null, null, null)) { + if (cursor == null || !cursor.moveToFirst()) { + Timber.w("The content resolver could not find %s.", fileUri); + return null; + } + int columnIndex = cursor.getColumnIndex(COLUMN_LAST_MODIFIED); + if (columnIndex == -1) { + Timber.w("The content resolver does not support last modified column %s.", fileUri); + return null; + } + return ZonedDateTimeConverter.fromTimestamp(cursor.getLong(columnIndex)); + } catch (SecurityException e) { + Timber.i(e, "The SAF permission was removed."); + return null; + } + } + + /** + * Retrieve all hosts sources files to copy into a private local file. + * + * @throws HostErrorException If the hosts sources could not be downloaded. + */ + public void retrieveHostsSources() throws HostErrorException { + // Check connection status + if (isDeviceOffline()) { + throw new HostErrorException(NO_CONNECTION); + } + // Update state to downloading + setState(R.string.status_retrieve); + // Initialize copy counters + int numberOfCopies = 0; + int numberOfFailedCopies = 0; + // Compute current date in UTC timezone + ZonedDateTime now = ZonedDateTime.now(); + // Get each hosts source + for (HostsSource source : this.hostsSourceDao.getAll()) { + int sourceId = source.getId(); + // Clear disabled source + if (!source.isEnabled()) { + this.hostListItemDao.clearSourceHosts(sourceId); + this.hostsSourceDao.clearProperties(sourceId); + continue; + } + // Get hosts source last update + ZonedDateTime onlineModificationDate = getHostsSourceLastUpdate(source); + if (onlineModificationDate == null) { + onlineModificationDate = now; + } + // Check if update available + ZonedDateTime localModificationDate = source.getLocalModificationDate(); + if (localModificationDate != null && localModificationDate.isAfter(onlineModificationDate)) { + Timber.i("Skip source %s: no update.", source.getLabel()); + continue; + } + // Increment number of copy + numberOfCopies++; + try { + // Check hosts source type + switch (source.getType()) { + case URL: + downloadHostSource(source); + break; + case FILE: + readSourceFile(source); + break; + default: + Timber.w("Hosts source type is not supported."); + } + // Update local and online modification dates to now + localModificationDate = onlineModificationDate.isAfter(now) ? onlineModificationDate : now; + this.hostsSourceDao.updateModificationDates(sourceId, localModificationDate, onlineModificationDate); + // Update size + this.hostsSourceDao.updateSize(sourceId); + } catch (IOException e) { + Timber.w(e, "Failed to retrieve host source %s.", source.getUrl()); + // Increment number of failed copy + numberOfFailedCopies++; + } + } + // Check if all copies failed + if (numberOfCopies == numberOfFailedCopies && numberOfCopies != 0) { + throw new HostErrorException(DOWNLOAD_FAILED); + } + // Synchronize hosts entries + syncHostEntries(); + // Mark no update available + this.updateAvailable.postValue(false); + } + + /** + * Synchronize hosts entries from current source states. + */ + public void syncHostEntries() { + setState(R.string.status_sync_database); + this.hostEntryDao.sync(); + } + + /** + * Get the HTTP client to download hosts sources. + * + * @return The HTTP client to download hosts sources. + */ + @NonNull + private OkHttpClient getHttpClient() { + if (this.cachedHttpClient == null) { + this.cachedHttpClient = new OkHttpClient.Builder() + .cache(new Cache(this.context.getCacheDir(), CACHE_SIZE)) + .build(); + } + return this.cachedHttpClient; + } + + /** + * Get request builder for an hosts source. + * All cache data available are filled into the headers. + * + * @param source The hosts source to get request builder. + * @return The hosts source request builder. + */ + private Request.Builder getRequestFor(HostsSource source) { + Request.Builder request = new Request.Builder().url(source.getUrl()); + if (source.getEntityTag() != null) { + request = request.header(IF_NONE_MATCH_HEADER, source.getEntityTag()); + } + if (source.getOnlineModificationDate() != null) { + String lastModified = source.getOnlineModificationDate().format(RFC_1123_DATE_TIME); + request = request.header(IF_MODIFIED_SINCE_HEADER, lastModified); + } + return request; + } + + /** + * Download an hosts source file and append it to the database. + * + * @param source The hosts source to download. + * @throws IOException If the hosts source could not be downloaded. + */ + private void downloadHostSource(HostsSource source) throws IOException { + // Get hosts file URL + String hostsFileUrl = source.getUrl(); + Timber.v("Downloading hosts file: %s.", hostsFileUrl); + // Set state to downloading hosts source + setState(R.string.status_download_source, hostsFileUrl); + // Create request + Request request = getRequestFor(source).build(); + // Request hosts file and open byte stream + try (Response response = getHttpClient().newCall(request).execute(); + Reader reader = requireNonNull(response.body()).charStream(); + BufferedReader bufferedReader = new BufferedReader(reader)) { + // Skip source parsing if not modified + if (response.code() == HTTP_NOT_MODIFIED) { + Timber.d("Source %s was not updated since last fetch.", source.getUrl()); + return; + } + // Extract ETag if present + String entityTag = response.header(ENTITY_TAG_HEADER); + if (entityTag != null) { + if (entityTag.startsWith(WEAK_ENTITY_TAG_PREFIX)) { + entityTag = entityTag.substring(WEAK_ENTITY_TAG_PREFIX.length()); + } + this.hostsSourceDao.updateEntityTag(source.getId(), entityTag); + } + // Parse source + parseSourceInputStream(source, bufferedReader); + } catch (IOException e) { + throw new IOException("Exception while downloading hosts file from " + hostsFileUrl + ".", e); + } + } + + /** + * Read a hosts source file and append it to the database. + * + * @param hostsSource The hosts source to copy. + * @throws IOException If the hosts source could not be copied. + */ + private void readSourceFile(HostsSource hostsSource) throws IOException { + // Get hosts file URI + String hostsFileUrl = hostsSource.getUrl(); + Uri fileUri = Uri.parse(hostsFileUrl); + Timber.v("Reading hosts source file: %s.", hostsFileUrl); + // Set state to copying hosts source + setState(R.string.status_read_source, hostsFileUrl); + try (InputStream inputStream = this.context.getContentResolver().openInputStream(fileUri); + InputStreamReader reader = new InputStreamReader(inputStream); + BufferedReader bufferedReader = new BufferedReader(reader)) { + parseSourceInputStream(hostsSource, bufferedReader); + } catch (IOException e) { + throw new IOException("Error while reading hosts file from " + hostsFileUrl + ".", e); + } + } + + /** + * Parse a source from its input stream to store it into database. + * + * @param hostsSource The host source to parse. + * @param reader The host source reader. + */ + private void parseSourceInputStream(HostsSource hostsSource, BufferedReader reader) { + setState(R.string.status_parse_source, hostsSource.getLabel()); + long startTime = System.currentTimeMillis(); + new SourceLoader(hostsSource).parse(reader, this.hostListItemDao); + long endTime = System.currentTimeMillis(); + Timber.i("Parsed " + hostsSource.getUrl() + " in " + (endTime - startTime) / 1000 + "s"); + } + + /** + * Enable all hosts sources. + * + * @return {@code true} if at least one source was updated, {@code false} otherwise. + */ + public boolean enableAllSources() { + boolean updated = false; + for (HostsSource source : this.hostsSourceDao.getAll()) { + if (!source.isEnabled()) { + this.hostsSourceDao.toggleEnabled(source); + updated = true; + } + } + return updated; + } + + private void setState(@StringRes int stateResId, Object... details) { + String state = this.context.getString(stateResId, details); + Timber.d("Source model state: %s.", state); + this.state.postValue(state); + } +} diff --git a/app/src/main/java/org/adaway/model/source/SourceUpdateService.java b/app/src/main/java/org/adaway/model/source/SourceUpdateService.java new file mode 100644 index 0000000..047f395 --- /dev/null +++ b/app/src/main/java/org/adaway/model/source/SourceUpdateService.java @@ -0,0 +1,176 @@ +package org.adaway.model.source; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.work.Constraints; +import androidx.work.ExistingPeriodicWorkPolicy; +import androidx.work.NetworkType; +import androidx.work.PeriodicWorkRequest; +import androidx.work.WorkManager; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import org.adaway.AdAwayApplication; +import org.adaway.helper.NotificationHelper; +import org.adaway.helper.PreferenceHelper; +import org.adaway.model.adblocking.AdBlockModel; +import org.adaway.model.error.HostErrorException; + +import static androidx.work.ExistingPeriodicWorkPolicy.KEEP; +import static androidx.work.ExistingPeriodicWorkPolicy.UPDATE; +import static androidx.work.ListenableWorker.Result.failure; +import static androidx.work.ListenableWorker.Result.retry; +import static androidx.work.ListenableWorker.Result.success; +import static java.util.concurrent.TimeUnit.HOURS; + +import timber.log.Timber; + +/** + * This class is a service to check for hosts sources update.
    + * It could be enabled or disabled for periodic check.
    + * The implementation is based on WorkManager from Android X. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class SourceUpdateService { + /** + * The name of the periodic work. + */ + private static final String WORK_NAME = "HostsUpdateWork"; + + /** + * Private constructor. + */ + private SourceUpdateService() { + + } + + /** + * Enable update service. + * + * @param context The application context. + * @param unmeteredNetworkOnly true if the update should be done on unmetered network only, false otherwise. + */ + public static void enable(Context context, boolean unmeteredNetworkOnly) { + enqueueWork(context, UPDATE, unmeteredNetworkOnly); + } + + /** + * Disable update service. + * + * @param context The application context. + */ + public static void disable(Context context) { + // Cancel previous work + WorkManager.getInstance(context).cancelUniqueWork(WORK_NAME); + } + + /** + * Sync service on user preferences. + * + * @param context The application context. + */ + static void syncPreferences(Context context) { + if (PreferenceHelper.getUpdateCheckHostsDaily(context)) { + enqueueWork(context, KEEP, PreferenceHelper.getUpdateOnlyOnWifi(context)); + } else { + disable(context); + } + } + + private static void enqueueWork(Context context, ExistingPeriodicWorkPolicy workPolicy, boolean unmeteredNetworkOnly) { + // Create work request + PeriodicWorkRequest workRequest = getWorkRequest(unmeteredNetworkOnly); + // Enqueue work request + WorkManager workManager = WorkManager.getInstance(context); + workManager.enqueueUniquePeriodicWork(WORK_NAME, workPolicy, workRequest); + } + + /** + * Create source update work request. + * + * @param unmeteredNetworkOnly true if the update should be done on unmetered network only, false otherwise. + * @return The source update work request to queue. + */ + private static PeriodicWorkRequest getWorkRequest(boolean unmeteredNetworkOnly) { + // Create worker constraints + Constraints constraints = new Constraints.Builder() + .setRequiredNetworkType(unmeteredNetworkOnly ? NetworkType.UNMETERED : NetworkType.CONNECTED) + .setRequiresStorageNotLow(true) + .build(); + // Create work request + return new PeriodicWorkRequest.Builder(HostsSourcesUpdateWorker.class, 6, HOURS) + .setConstraints(constraints) + .setInitialDelay(3, HOURS) + .build(); + } + + /** + * This class is a {@link Worker} to fetch hosts sources updates and install them if needed. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ + public static class HostsSourcesUpdateWorker extends Worker { + /** + * Constructor. + * + * @param context The application context. + * @param workerParams The parameters to setup this worker. + */ + public HostsSourcesUpdateWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + } + + @NonNull + @Override + public Result doWork() { + Timber.i("Starting update worker"); + // Create model + AdAwayApplication application = (AdAwayApplication) getApplicationContext(); + SourceModel model = application.getSourceModel(); + // Check for update + boolean hasUpdate; + try { + hasUpdate = model.checkForUpdate(); + } catch (HostErrorException exception) { + // An error occurred, check will be retried + Timber.e(exception, "Failed to check for update. Will retry later."); + return retry(); + } + if (hasUpdate) { + // Do update + try { + doUpdate(application); + } catch (HostErrorException exception) { + // Installation failed. Worker failed. + Timber.e(exception, "Failed to apply hosts file during background update."); + return failure(); + } + } + // Return as success + return success(); + } + + /** + * Handle update according user preferences. + * + * @param application The application. + * @throws HostErrorException If the update could not be handled. + */ + private void doUpdate(AdAwayApplication application) throws HostErrorException { + // Check if automatic update are enabled + if (PreferenceHelper.getAutomaticUpdateDaily(application)) { + // Retrieve source updates + SourceModel sourceModel = application.getSourceModel(); + sourceModel.retrieveHostsSources(); + // Apply source updates + AdBlockModel adBlockModel = application.getAdBlockModel(); + adBlockModel.apply(); + } else { + // Display update notification + NotificationHelper.showUpdateHostsNotification(application); + } + } + } +} diff --git a/app/src/main/java/org/adaway/model/update/ApkDownloadReceiver.java b/app/src/main/java/org/adaway/model/update/ApkDownloadReceiver.java new file mode 100644 index 0000000..9927631 --- /dev/null +++ b/app/src/main/java/org/adaway/model/update/ApkDownloadReceiver.java @@ -0,0 +1,48 @@ +package org.adaway.model.update; + +import android.app.DownloadManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +import static android.content.Intent.ACTION_INSTALL_PACKAGE; + +import timber.log.Timber; + +/** + * This class is a {@link BroadcastReceiver} to install downloaded application updates. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class ApkDownloadReceiver extends BroadcastReceiver { + private final long downloadId; + + public ApkDownloadReceiver(long downloadId) { + this.downloadId = downloadId; + } + + @Override + public void onReceive(Context context, Intent intent) { + //Fetching the download id received with the broadcast + long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); + //Checking if the received broadcast is for our enqueued download by matching download id + if (this.downloadId == id) { + DownloadManager downloadManager = context.getSystemService(DownloadManager.class); + Uri apkUri = downloadManager.getUriForDownloadedFile(id); + if (apkUri == null) { + Timber.w("Failed to download id: %s.", id); + } else { + installApk(context, apkUri); + } + } + } + + private void installApk(Context context, Uri apkUri) { + Intent install = new Intent(ACTION_INSTALL_PACKAGE); + install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + install.setData(apkUri); + context.startActivity(install); + } +} diff --git a/app/src/main/java/org/adaway/model/update/ApkUpdateService.java b/app/src/main/java/org/adaway/model/update/ApkUpdateService.java new file mode 100644 index 0000000..1b377a7 --- /dev/null +++ b/app/src/main/java/org/adaway/model/update/ApkUpdateService.java @@ -0,0 +1,112 @@ +package org.adaway.model.update; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.work.ExistingPeriodicWorkPolicy; +import androidx.work.PeriodicWorkRequest; +import androidx.work.WorkManager; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import org.adaway.AdAwayApplication; +import org.adaway.helper.NotificationHelper; +import org.adaway.helper.PreferenceHelper; + +import static androidx.work.ExistingPeriodicWorkPolicy.KEEP; +import static androidx.work.ExistingPeriodicWorkPolicy.UPDATE; +import static androidx.work.ListenableWorker.Result.success; +import static java.util.concurrent.TimeUnit.DAYS; + +import timber.log.Timber; + +/** + * This class is a service to check for application update.
    + * It could be enabled or disabled for periodic check.
    + * The implementation is based on WorkManager from Android X. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class ApkUpdateService { + /** + * The name of the periodic work. + */ + private static final String WORK_NAME = "ApkUpdateWork"; + + /** + * Private constructor. + */ + private ApkUpdateService() { + + } + + /** + * Enable update service. + * + * @param context The application context. + */ + public static void enable(Context context) { + enqueueWork(context, UPDATE); + } + + /** + * Disable update service. + * + * @param context The application context. + */ + public static void disable(Context context) { + // Cancel previous work + WorkManager.getInstance(context).cancelUniqueWork(WORK_NAME); + } + + static void syncPreferences(Context context) { + if (PreferenceHelper.getUpdateCheckAppDaily(context)) { + enqueueWork(context, KEEP); + } else { + disable(context); + } + } + + private static void enqueueWork(Context context, ExistingPeriodicWorkPolicy workPolicy) { + // Create work request + PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(ApkUpdateWorker.class, 1, DAYS).build(); + // Enqueue work request + WorkManager workManager = WorkManager.getInstance(context); + workManager.enqueueUniquePeriodicWork(WORK_NAME, workPolicy, workRequest); + } + + /** + * This class is a {@link Worker} to check for application update and notify them if needed. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ + public static class ApkUpdateWorker extends Worker { + /** + * Constructor. + * + * @param context The application context. + * @param workerParams The parameters to setup this worker. + */ + public ApkUpdateWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + } + + @NonNull + @Override + public Result doWork() { + Timber.i("Starting update worker"); + // Create model + AdAwayApplication application = (AdAwayApplication) getApplicationContext(); + UpdateModel model = application.getUpdateModel(); + // Check for update + model.checkForUpdate(); + Manifest manifest = model.getManifest().getValue(); + if (manifest != null && manifest.updateAvailable) { + // Display update notification + NotificationHelper.showUpdateApplicationNotification(application); + } + // Return as success + return success(); + } + } +} diff --git a/app/src/main/java/org/adaway/model/update/Manifest.java b/app/src/main/java/org/adaway/model/update/Manifest.java new file mode 100644 index 0000000..40bf731 --- /dev/null +++ b/app/src/main/java/org/adaway/model/update/Manifest.java @@ -0,0 +1,24 @@ +package org.adaway.model.update; + +import org.json.JSONException; +import org.json.JSONObject; + +/** + * This class is represent an application manifest. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class Manifest { + public final String version; + public final int versionCode; + public final String changelog; + public final boolean updateAvailable; + + public Manifest(String manifest, long currentVersionCode) throws JSONException { + JSONObject manifestObject = new JSONObject(manifest); + this.version = manifestObject.getString("version"); + this.versionCode = manifestObject.getInt("versionCode"); + this.changelog = manifestObject.getString("changelog"); + this.updateAvailable = this.versionCode > currentVersionCode; + } +} diff --git a/app/src/main/java/org/adaway/model/update/UpdateModel.java b/app/src/main/java/org/adaway/model/update/UpdateModel.java new file mode 100644 index 0000000..a7e65d7 --- /dev/null +++ b/app/src/main/java/org/adaway/model/update/UpdateModel.java @@ -0,0 +1,203 @@ +package org.adaway.model.update; + +import static android.app.DownloadManager.ACTION_DOWNLOAD_COMPLETE; +import static android.os.Build.VERSION.SDK_INT; +import static org.adaway.model.update.UpdateStore.getApkStore; +import static java.util.Objects.requireNonNull; + +import android.app.DownloadManager; +import android.content.Context; +import android.content.IntentFilter; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.Uri; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import org.adaway.R; +import org.adaway.helper.PreferenceHelper; +import org.json.JSONException; + +import java.io.IOException; + +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import timber.log.Timber; + +/** + * This class is the model in charge of updating the application. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class UpdateModel { + private static final String MANIFEST_URL = "https://app.adaway.org/manifest.json"; + private static final String DOWNLOAD_URL = "https://app.adaway.org/adaway.apk?versionCode="; + private final Context context; + private final VersionInfo versionInfo; + private final OkHttpClient client; + private final MutableLiveData manifest; + private ApkDownloadReceiver receiver; + + /** + * Constructor. + * + * @param context The application context. + */ + public UpdateModel(Context context) { + this.context = context; + this.versionInfo = VersionInfo.get(context); + this.manifest = new MutableLiveData<>(); + this.client = buildHttpClient(); + ApkUpdateService.syncPreferences(context); + } + + /** + * Get the current version code. + * + * @return The current version code. + */ + public int getVersionCode() { + return this.versionInfo.code; + } + + /** + * Get the current version name. + * + * @return The current version name. + */ + public String getVersionName() { + return this.versionInfo.name; + } + + /** + * Get the last version manifest. + * + * @return The last version manifest. + */ + public LiveData getManifest() { + return this.manifest; + } + + /** + * Get the application update store. + * + * @return The application update store. + */ + public UpdateStore getStore() { + return getApkStore(this.context); + } + + /** + * Get the application update channel. + * + * @return The application update channel. + */ + public String getChannel() { + return PreferenceHelper.getIncludeBetaReleases(this.context) ? "beta" : "stable"; + } + + /** + * Check if there is an update available. + */ + public void checkForUpdate() { + Manifest manifest = downloadManifest(); + // Notify update + if (manifest != null) { + this.manifest.postValue(manifest); + } + } + + private OkHttpClient buildHttpClient() { + return new OkHttpClient.Builder().build(); + } + + private Manifest downloadManifest() { + if (!this.versionInfo.isValid()) { + return null; + } + HttpUrl httpUrl = requireNonNull(HttpUrl.parse(MANIFEST_URL), "Failed to parse manifest URL") + .newBuilder() + .addQueryParameter("versionCode", Integer.toString(this.versionInfo.code)) + .addQueryParameter("sdkCode", Integer.toString(SDK_INT)) + .addQueryParameter("channel", getChannel()) + .addQueryParameter("store", getStore().getName()) + .build(); + Request request = new Request.Builder() + .url(httpUrl) + .build(); + try (Response execute = this.client.newCall(request).execute(); + ResponseBody body = execute.body()) { + if (execute.isSuccessful() && body != null) { + return new Manifest(body.string(), this.versionInfo.code); + } else { + return null; + } + } catch (IOException | JSONException exception) { + Timber.e(exception, "Unable to download manifest."); + // Return failed + return null; + } + } + + /** + * Update the application to the latest version. + * + * @return The download identifier ({@code -1} if download was not started). + */ + public long update() { + // Check manifest + Manifest manifest = this.manifest.getValue(); + if (manifest == null) { + return -1; + } + // Check previous broadcast receiver + if (this.receiver != null) { + this.context.unregisterReceiver(this.receiver); + } + // Queue download + long downloadId = download(manifest); + // Register new broadcast receiver + this.receiver = new ApkDownloadReceiver(downloadId); + this.context.registerReceiver(this.receiver, new IntentFilter(ACTION_DOWNLOAD_COMPLETE)); + // Return download identifier + return downloadId; + } + + private long download(Manifest manifest) { + Timber.i("Downloading " + manifest.version + "."); + Uri uri = Uri.parse(DOWNLOAD_URL + manifest.versionCode); + DownloadManager.Request request = new DownloadManager.Request(uri) + .setTitle("AdAway " + manifest.version) + .setDescription(this.context.getString(R.string.update_notification_description)); + DownloadManager downloadManager = this.context.getSystemService(DownloadManager.class); + return downloadManager.enqueue(request); + } + + private static class VersionInfo { + private final int code; + private final String name; + + private VersionInfo(int code, String name) { + this.code = code; + this.name = name; + } + + public static VersionInfo get(Context context) { + try { + PackageInfo packageInfo = context.getPackageManager() + .getPackageInfo(context.getPackageName(), 0); + return new VersionInfo(packageInfo.versionCode, packageInfo.versionName); + } catch (PackageManager.NameNotFoundException e) { + return new VersionInfo(0, "development"); + } + } + + public boolean isValid() { + return this.code > 0; + } + } +} diff --git a/app/src/main/java/org/adaway/model/update/UpdateStore.java b/app/src/main/java/org/adaway/model/update/UpdateStore.java new file mode 100644 index 0000000..8ea7d39 --- /dev/null +++ b/app/src/main/java/org/adaway/model/update/UpdateStore.java @@ -0,0 +1,120 @@ +package org.adaway.model.update; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.Signature; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import static android.content.pm.PackageManager.GET_SIGNATURES; +import static android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES; +import static android.os.Build.VERSION.SDK_INT; +import static android.os.Build.VERSION_CODES.P; + +import timber.log.Timber; + +/** + * This enumerates represents the stores to get AdAway updates. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public enum UpdateStore { + /** + * The official store (usually GitHub releases) with AdAway signing key. + */ + ADAWAY("adaway", "D647FDAC42961502AC78F99919B8E1901747E8DA78FE13E1EABA688FECC4C99E"), + /** + * The F-Droid store with F-Droid signing key. + */ + F_DROID("fdroid", "42203F1AC857426D1496E971DB96FBE1F88C25C9E1F895A5C98D703891292277"), + /** + * An unknown store. + */ + UNKNOWN("unknown", ""); + /** + * The store name. + */ + public final String storeName; + /** + * The store singing certificate digest. + */ + public final String sign; + + UpdateStore(String name, String sign) { + this.storeName = name; + this.sign = sign; + } + + /** + * Get the store of the running application. + * + * @param context The application context. + * @return The application store, {@link #UNKNOWN} if store can't be defined. + */ + @SuppressLint("PackageManagerGetSignatures") + public static UpdateStore getApkStore(Context context) { + PackageManager packageManager = context.getPackageManager(); + String packageName = context.getPackageName(); + Signature[] signatures; + try { + if (SDK_INT >= P) { + signatures = packageManager.getPackageInfo( + packageName, + GET_SIGNING_CERTIFICATES + ).signingInfo.getSigningCertificateHistory(); + } else { + // Signatures are not used for security reason. Only to guess the flavor of the app. + signatures = packageManager.getPackageInfo( + packageName, + GET_SIGNATURES + ).signatures; + } + } catch (PackageManager.NameNotFoundException e) { + Timber.w(e, "Failed to get application package info."); + return UpdateStore.UNKNOWN; + } + return UpdateStore.getFromSigns(signatures); + } + + private static UpdateStore getFromSigns(Signature[] signatures) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + for (Signature signature : signatures) { + md.update(signature.toByteArray()); + String sign = bytesToHex(md.digest()); + for (UpdateStore store : UpdateStore.values()) { + if (store.sign.equals(sign)) { + return store; + } + } + } + } catch (NoSuchAlgorithmException e) { + Timber.w(e, "SHA-256 algorithm is no supported."); + } + return UpdateStore.UNKNOWN; + } + + private static String bytesToHex(byte[] bytes) { + final char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + char[] hexChars = new char[bytes.length * 2]; + int v; + for (int j = 0; j < bytes.length; j++) { + v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + + /** + * Get the store name. + * + * @return The store name. + */ + public String getName() { + return this.storeName; + } +} diff --git a/app/src/main/java/org/adaway/model/vpn/VpnModel.java b/app/src/main/java/org/adaway/model/vpn/VpnModel.java new file mode 100644 index 0000000..a9f220e --- /dev/null +++ b/app/src/main/java/org/adaway/model/vpn/VpnModel.java @@ -0,0 +1,124 @@ +package org.adaway.model.vpn; + +import static org.adaway.model.adblocking.AdBlockMethod.VPN; +import static org.adaway.model.error.HostError.ENABLE_VPN_FAIL; + +import android.content.Context; +import android.util.LruCache; + +import org.adaway.R; +import org.adaway.db.AppDatabase; +import org.adaway.db.dao.HostEntryDao; +import org.adaway.db.entity.HostEntry; +import org.adaway.model.adblocking.AdBlockMethod; +import org.adaway.model.adblocking.AdBlockModel; +import org.adaway.model.error.HostErrorException; +import org.adaway.vpn.VpnServiceControls; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; + +import timber.log.Timber; + +/** + * This class is the model to represent VPN service configuration. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class VpnModel extends AdBlockModel { + private final HostEntryDao hostEntryDao; + private final LruCache blockCache; + private final LinkedHashSet logs; + private boolean recordingLogs; + private int requestCount; + + /** + * Constructor. + * + * @param context The application context. + */ + public VpnModel(Context context) { + super(context); + AppDatabase database = AppDatabase.getInstance(context); + this.hostEntryDao = database.hostEntryDao(); + this.blockCache = new LruCache(4 * 1024) { + @Override + protected HostEntry create(String key) { + return VpnModel.this.hostEntryDao.getEntry(key); + } + }; + this.logs = new LinkedHashSet<>(); + this.recordingLogs = false; + this.requestCount = 0; + this.applied.postValue(VpnServiceControls.isRunning(context)); + } + + @Override + public AdBlockMethod getMethod() { + return VPN; + } + + @Override + public void apply() throws HostErrorException { + // Clear cache + this.blockCache.evictAll(); + // Start VPN + boolean started = VpnServiceControls.start(this.context); + this.applied.postValue(started); + if (!started) { + throw new HostErrorException(ENABLE_VPN_FAIL); + } + setState(R.string.status_vpn_configuration_updated); + } + + @Override + public void revert() { + VpnServiceControls.stop(this.context); + this.applied.postValue(false); + } + + @Override + public boolean isRecordingLogs() { + return this.recordingLogs; + } + + @Override + public void setRecordingLogs(boolean recording) { + this.recordingLogs = recording; + } + + @Override + public List getLogs() { + return new ArrayList<>(this.logs); + } + + @Override + public void clearLogs() { + this.logs.clear(); + } + + /** + * Checks host entry related to an host name. + * + * @param host A hostname to check. + * @return The related host entry. + */ + public HostEntry getEntry(String host) { + // Compute miss rate periodically + this.requestCount++; + if (this.requestCount >= 1000) { + int hits = this.blockCache.hitCount(); + int misses = this.blockCache.missCount(); + double missRate = 100D * (hits + misses) / misses; + Timber.d("Host cache miss rate: %s.", missRate); + this.requestCount = 0; + } + // Add host to logs + if (this.recordingLogs) { + this.logs.add(host); + } + // Check cache + return this.blockCache.get(host); + } +} diff --git a/app/src/main/java/org/adaway/tile/AdBlockingTileService.java b/app/src/main/java/org/adaway/tile/AdBlockingTileService.java new file mode 100644 index 0000000..a805f7a --- /dev/null +++ b/app/src/main/java/org/adaway/tile/AdBlockingTileService.java @@ -0,0 +1,81 @@ +package org.adaway.tile; + +import android.service.quicksettings.Tile; +import android.service.quicksettings.TileService; + +import androidx.lifecycle.LiveData; + +import org.adaway.AdAwayApplication; +import org.adaway.model.adblocking.AdBlockModel; +import org.adaway.model.error.HostErrorException; +import org.adaway.util.AppExecutors; + +import java.util.concurrent.atomic.AtomicBoolean; + +import static android.service.quicksettings.Tile.STATE_ACTIVE; +import static android.service.quicksettings.Tile.STATE_INACTIVE; + +import timber.log.Timber; + +/** + * This class is a {@link TileService} to toggle ad-blocking. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class AdBlockingTileService extends TileService { + private final AtomicBoolean toggling = new AtomicBoolean(false); + + @Override + public void onTileAdded() { + boolean adBlocked = getModel().isApplied().getValue() == Boolean.TRUE; + updateTile(adBlocked); + } + + @Override + public void onStartListening() { + LiveData applied = getModel().isApplied(); + applied.observeForever(this::updateTile); + } + + @Override + public void onStopListening() { + LiveData applied = getModel().isApplied(); + applied.removeObserver(this::updateTile); + } + + @Override + public void onClick() { + AppExecutors.getInstance() + .diskIO() + .execute(this::toggleAdBlocking); + } + + private void updateTile(boolean adBlocked) { + Tile tile = getQsTile(); + tile.setState(adBlocked ? STATE_ACTIVE : STATE_INACTIVE); + tile.updateTile(); + } + + private void toggleAdBlocking() { + if (this.toggling.get()) { + return; + } + AdBlockModel model = getModel(); + try { + this.toggling.set(true); + if (model.isApplied().getValue() == Boolean.TRUE) { + model.revert(); + } else { + model.apply(); + } + } catch (HostErrorException e) { + Timber.w(e, "Failed to toggle ad-blocking."); + } finally { + this.toggling.set(false); + } + } + + private AdBlockModel getModel() { + return ((AdAwayApplication) getApplication()).getAdBlockModel(); + } +} diff --git a/app/src/main/java/org/adaway/ui/Animations.java b/app/src/main/java/org/adaway/ui/Animations.java new file mode 100644 index 0000000..e8adbef --- /dev/null +++ b/app/src/main/java/org/adaway/ui/Animations.java @@ -0,0 +1,104 @@ +package org.adaway.ui; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.view.View; + +import static android.view.View.ALPHA; +import static android.view.View.GONE; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; + +/** + * This class is an utility class to animate views. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class Animations { + + private Animations() { + + } + + /** + * Animate view to be shown. + * + * @param view The view to animate. + */ + public static void showView(View view) { + ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, ALPHA, 1F); + objectAnimator.setAutoCancel(true); + objectAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + view.setVisibility(VISIBLE); + } + }); + objectAnimator.start(); + } + + /** + * Animate view to be hidden. + * + * @param view The view to animate. + */ + public static void hideView(View view) { + ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, ALPHA, 0F); + objectAnimator.setAutoCancel(true); + objectAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + view.setVisibility(INVISIBLE); + } + }); + objectAnimator.start(); + } + + /** + * Animate view to be removed. + * + * @param view The view to animate. + */ + public static void removeView(View view) { + ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, ALPHA, 0F); + objectAnimator.setAutoCancel(true); + objectAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + view.setVisibility(GONE); + } + }); + objectAnimator.start(); + } + + /** + * Immediately set view to shown state. + * + * @param view The view to set. + */ + public static void setShown(View view) { + view.setVisibility(VISIBLE); + view.setAlpha(1f); + } + + /** + * Immediately set view to hidden state. + * + * @param view The view to set. + */ + public static void setHidden(View view) { + view.setVisibility(INVISIBLE); + view.setAlpha(0f); + } + + /** + * Immediately set view to gone state. + * + * @param view The view to set. + */ + public static void setRemoved(View view) { + view.setVisibility(GONE); + view.setAlpha(0f); + } +} diff --git a/app/src/main/java/org/adaway/ui/adblocking/ApplyConfigurationSnackbar.java b/app/src/main/java/org/adaway/ui/adblocking/ApplyConfigurationSnackbar.java new file mode 100644 index 0000000..15be07c --- /dev/null +++ b/app/src/main/java/org/adaway/ui/adblocking/ApplyConfigurationSnackbar.java @@ -0,0 +1,191 @@ +package org.adaway.ui.adblocking; + +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.ProgressBar; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.Observer; + +import com.google.android.material.snackbar.Snackbar; + +import org.adaway.AdAwayApplication; +import org.adaway.R; +import org.adaway.model.adblocking.AdBlockModel; +import org.adaway.model.error.HostErrorException; +import org.adaway.model.source.SourceModel; +import org.adaway.util.AppExecutors; + +import java.util.Collection; + +import static com.google.android.material.snackbar.Snackbar.LENGTH_INDEFINITE; +import static com.google.android.material.snackbar.Snackbar.LENGTH_LONG; + +/** + * This class is a {@link Snackbar} to notify about adblock model new configuration to apply. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class ApplyConfigurationSnackbar { + /** + * The view to bind the snackbar to. + */ + private final View view; + /** + * The notify snackbar when hosts update available. + */ + private final Snackbar notifySnackbar; + /** + * The wait snackbar during hosts install. + */ + private final Snackbar waitSnackbar; + /** + * To synchronize sources before installing or not. + */ + private final boolean syncSources; + /** + * The current hosts update available status ({@code true} if update available, {@code false} otherwise). + */ + private boolean update; + /** + * Whether or not ignore the next update event ({@code true} to ignore, {@code false} otherwise). + */ + private boolean skipUpdate; + /** + * Whether or not ignore update events during the install ({@code true} to ignore, {@code false} otherwise). + */ + private boolean ignoreEventDuringInstall; + + /** + * Constructor. + * + * @param view The view to bind the snackbar to. + * @param syncSources To synchronize sources before installing or not. + * @param ignoreEventDuringInstall {@code true} to ignore events, {@code false} otherwise. + */ + public ApplyConfigurationSnackbar(@NonNull View view, boolean syncSources, boolean ignoreEventDuringInstall) { + this.view = view; + this.notifySnackbar = Snackbar.make(this.view, R.string.notification_configuration_changed, LENGTH_INDEFINITE) + .setAction(R.string.notification_configuration_changed_action, v -> apply()); + this.waitSnackbar = Snackbar.make(this.view, R.string.notification_configuration_installing, LENGTH_INDEFINITE); + appendViewToSnackbar(this.waitSnackbar, new ProgressBar(this.view.getContext())); + this.syncSources = syncSources; + this.ignoreEventDuringInstall = ignoreEventDuringInstall; + this.update = false; + this.skipUpdate = false; + } + + /** + * Create {@link Observer} which ignores first (initialization) event. + * + * @param The type of data to observe. + * @return The observer instance. + */ + public Observer createObserver() { + return new Observer() { + boolean firstUpdate = true; + + @Override + public void onChanged(@Nullable T t) { + // Check new data + if (t == null || (t instanceof Collection && ((Collection) t).isEmpty())) { + return; + } + // First update + if (this.firstUpdate) { + this.firstUpdate = false; + return; + } + ApplyConfigurationSnackbar.this.notifyUpdateAvailable(); + } + }; + } + + /** + * Notify update available. + */ + public void notifyUpdateAvailable() { + // Check if notify snackbar is already displayed + if (this.notifySnackbar.isShown()) { + return; + } + // Check if wait snackbar is displayed + if (this.waitSnackbar.isShown()) { + // Mark update available + this.update = true; + return; + } + // Check if update event should be skipped + if (this.skipUpdate) { + this.skipUpdate = false; + return; + } + // Show notify snackbar + this.notifySnackbar.show(); + // Mark update as notified + this.update = false; + } + + private void apply() { + showLoading(); + AppExecutors.getInstance().diskIO().execute(() -> { + AdAwayApplication application = (AdAwayApplication) this.view.getContext().getApplicationContext(); + SourceModel sourceModel = application.getSourceModel(); + AdBlockModel adBlockModel = application.getAdBlockModel(); + try { + if (this.syncSources) { + sourceModel.retrieveHostsSources(); + } else { + sourceModel.syncHostEntries(); + } + adBlockModel.apply(); + endLoading(true); + } catch (HostErrorException exception) { + endLoading(false); + } + }); + } + + private void showLoading() { + // Clear notify snackbar + this.notifySnackbar.dismiss(); + // Show wait snackbar + this.waitSnackbar.show(); + } + + private void endLoading(boolean successfulInstall) { + // Ensure the snackbar has time to display + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + // Clear snackbars + this.waitSnackbar.dismiss(); + // Check install failure + if (!successfulInstall) { + Snackbar failureSnackbar = Snackbar.make(this.view, R.string.notification_configuration_failed, LENGTH_LONG); + ImageView view = new ImageView(this.view.getContext()); + view.setImageResource(R.drawable.ic_error_outline_24dp); + appendViewToSnackbar(failureSnackbar, view); + failureSnackbar.show(); + } + // Check pending update notification + else if (this.update) { + // Ignore next update event if events should be ignored + if (this.ignoreEventDuringInstall) { + this.skipUpdate = true; + } else { + // Otherwise display update notification + notifyUpdateAvailable(); + } + } + } + + private void appendViewToSnackbar(Snackbar snackbar, View view) { + ViewGroup viewGroup = (ViewGroup) snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_text).getParent(); + viewGroup.addView(view); + } +} diff --git a/app/src/main/java/org/adaway/ui/adware/AdwareFragment.java b/app/src/main/java/org/adaway/ui/adware/AdwareFragment.java new file mode 100644 index 0000000..234a5a8 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/adware/AdwareFragment.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.ui.adware; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.ViewModelProvider; + +import org.adaway.R; + +import java.util.List; + +/** + * This class is a {@link Fragment} to scan and uninstall adware. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class AdwareFragment extends Fragment { + /** + * The adware install list view. + */ + private ListView mListView; + /** + * The status text. + */ + private TextView mStatusText; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + // Create fragment view + View view = inflater.inflate(R.layout.adware_fragment, container, false); + // Get list view + this.mListView = view.findViewById(R.id.adware_list); + // Bind list onclick listener + this.mListView.setOnItemClickListener((parent, view1, position, id) -> { + // Get clicked adware + AdwareInstall adwareInstall = (AdwareInstall) parent.getItemAtPosition(position); + // Uninstall adware + AdwareFragment.this.uninstallAdware(adwareInstall); + }); + // Get status text + this.mStatusText = view.findViewById(R.id.adware_status_text); + /* + * Get model and bind it to view. + */ + // Get the model scope + FragmentActivity activity = requireActivity(); + // Get the model + AdwareViewModel model = new ViewModelProvider(activity).get(AdwareViewModel.class); + // Bind model to views + model.getAdware().observe(getViewLifecycleOwner(), data -> { + if (data == null) { + this.displayStatusText(R.string.adware_scanning); + } else if (data.isEmpty()) { + this.displayStatusText(R.string.adware_empty); + } else { + this.displayAdware(data); + } + }); + // Return created view + return view; + } + + /** + * Display a status text. + * + * @param text The status text to display. + */ + private void displayStatusText(int text) { + // Set text + this.mStatusText.setText(text); + // Show the text + this.mStatusText.setVisibility(View.VISIBLE); + this.mListView.setVisibility(View.GONE); + } + + /** + * Display the installed adware. + * + * @param data The adware to show. + */ + private void displayAdware(List data) { + // Create adapter + String[] from = new String[]{ + AdwareInstall.APPLICATION_NAME_KEY, + AdwareInstall.PACKAGE_NAME_KEY + }; + int[] to = new int[]{ + R.id.checkbox_list_text, + R.id.checkbox_list_subtext + }; + SimpleAdapter adapter = new SimpleAdapter(this.getContext(), + data, + R.layout.list_two_entries, + from, + to + ); + // Update list + adapter.notifyDataSetChanged(); + // Show the list + this.mListView.setAdapter(adapter); + this.mStatusText.setVisibility(View.GONE); + this.mListView.setVisibility(View.VISIBLE); + } + + /** + * Uninstall adware. + * + * @param adwareInstall The adware to uninstall. + */ + private void uninstallAdware(AdwareInstall adwareInstall) { + Intent intent = new Intent(Intent.ACTION_DELETE); + intent.setData(Uri.parse("package:" + adwareInstall.get(AdwareInstall.PACKAGE_NAME_KEY))); + this.startActivity(intent); + } +} diff --git a/app/src/main/java/org/adaway/ui/adware/AdwareInstall.java b/app/src/main/java/org/adaway/ui/adware/AdwareInstall.java new file mode 100644 index 0000000..1b03ce9 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/adware/AdwareInstall.java @@ -0,0 +1,43 @@ +package org.adaway.ui.adware; + +import androidx.annotation.NonNull; + +import java.util.HashMap; + +/** + * This class is a POJO to represent an installed adware. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class AdwareInstall extends HashMap implements Comparable { + /** + * The adware application name. + */ + final static String APPLICATION_NAME_KEY = "app_name"; + /** + * The adware package name. + */ + final static String PACKAGE_NAME_KEY = "package_name"; + + /** + * Constructor. + * + * @param applicationName The adware application name. + * @param packageName The adware package name. + */ + AdwareInstall(String applicationName, String packageName) { + super(2); + this.put(AdwareInstall.APPLICATION_NAME_KEY, applicationName); + this.put(AdwareInstall.PACKAGE_NAME_KEY, packageName); + } + + @Override + public int compareTo(@NonNull AdwareInstall other) { + int nameComparison = this.get(AdwareInstall.APPLICATION_NAME_KEY).compareTo(other.get(AdwareInstall.APPLICATION_NAME_KEY)); + if (nameComparison == 0) { + return this.get(AdwareInstall.PACKAGE_NAME_KEY).compareTo(other.get(AdwareInstall.PACKAGE_NAME_KEY)); + } else { + return nameComparison; + } + } +} diff --git a/app/src/main/java/org/adaway/ui/adware/AdwareLiveData.java b/app/src/main/java/org/adaway/ui/adware/AdwareLiveData.java new file mode 100644 index 0000000..5d9c82f --- /dev/null +++ b/app/src/main/java/org/adaway/ui/adware/AdwareLiveData.java @@ -0,0 +1,154 @@ +package org.adaway.ui.adware; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; + +import androidx.annotation.WorkerThread; +import androidx.lifecycle.LiveData; + +import org.adaway.util.AppExecutors; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.stream.Collectors.toList; + +import timber.log.Timber; + +/** + * This class is {@link LiveData} to represents installed adware on device. + */ +class AdwareLiveData extends LiveData> { + /** + * The adware package prefixes. + */ + private static final String[] AD_PACKAGE_PREFIXES = { + "com.airpush.", + "com.adnotify.", + "com.appbucks.sdk.", + "com.appenda.", + "com.applovin.", + "com.iac.notification.", + "com.inmobi.", + "com.Leadbolt.", + "com.sellaring.", + "com.senddroid.", + "com.tapjoy.", + "cn.kuguo." + }; + + /** + * The application context. + */ + private final Context context; + + /** + * Constructor. + * + * @param context The application context. + */ + AdwareLiveData(Context context) { + this.context = context; + AppExecutors.getInstance().diskIO().execute(this::loadData); + } + + @WorkerThread + private void loadData() { + // Get the package manager + PackageManager pm = this.context.getPackageManager(); + // Get the adware packages + List adwarePackages = this.getAdwarePackages(pm); + // Create related adware installs + List adwareInstalls = adwarePackages.stream() + .map(this::createInstallFromPackageInfo) + .sorted() + .collect(toList()); + // Post loaded adware installs + this.postValue(adwareInstalls); + } + + /** + * Finds all installed packages that look like they include a known ad framework + * + * @param pm The package manager. + * @return The found adware package information. + */ + private List getAdwarePackages(PackageManager pm) { + List adPackages = new ArrayList<>(); + // It'd be simpler to just use pm.getInstalledPackages here, but apparently it's broken + List applicationInfoList = pm.getInstalledApplications(0); + for (ApplicationInfo applicationInfo : applicationInfoList) { + try { + // Retrieve package information + PackageInfo packageInfo = pm.getPackageInfo( + applicationInfo.packageName, + PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES + ); + if (this.isAdware(packageInfo)) { + adPackages.add(packageInfo); + } + } catch (Exception exception) { + Timber.e(exception, "An error occurred while scanning applications for adware"); + } + } + return adPackages; + } + + /** + * Check if application is an adware. + * + * @param info The application package information. + * @return true if the application is an adware, false otherwise. + */ + private boolean isAdware(PackageInfo info) { + // Get package name + String packageName = info.packageName; + Timber.v("Scanning package %s", packageName); + // Check package components + boolean matchActivity = info.activities != null && checkComponent(packageName, "activity", info.activities); + boolean matchReceiver = info.receivers != null && checkComponent(packageName, "receiver", info.receivers); + boolean matchService = info.services != null && checkComponent(packageName, "service", info.services); + return matchActivity || matchReceiver || matchService; + } + + + /** + * Check if an application component match the adware signature. + * + * @param packageName The application package name. + * @param type The component type. + * @param info The application components to check. + * @return true if a component matches adware signature, false otherwise. + */ + private boolean checkComponent(String packageName, String type, ComponentInfo[] info) { + for (ComponentInfo componentInfo : info) { + String componentName = componentInfo.name; + Timber.v("[%s] %s", type, componentName); + for (String adPackagePrefix : AD_PACKAGE_PREFIXES) { + if (componentName.startsWith(adPackagePrefix)) { + Timber.i("Detected ad framework prefix %s in package %s as %s %s", adPackagePrefix, packageName, type, componentName); + return true; + } + } + } + return false; + } + + /** + * Create {@link AdwareInstall} from {@link PackageInfo}. + * + * @param packageInfo The package info to convert. + * @return The related adware install. + */ + private AdwareInstall createInstallFromPackageInfo(PackageInfo packageInfo) { + // Get the package manager + PackageManager pm = this.context.getPackageManager(); + // Retrieve application name + String applicationName = pm.getApplicationLabel(packageInfo.applicationInfo).toString(); + // Add adware install + return new AdwareInstall(applicationName, packageInfo.packageName); + } +} diff --git a/app/src/main/java/org/adaway/ui/adware/AdwareViewModel.java b/app/src/main/java/org/adaway/ui/adware/AdwareViewModel.java new file mode 100644 index 0000000..c0dc5db --- /dev/null +++ b/app/src/main/java/org/adaway/ui/adware/AdwareViewModel.java @@ -0,0 +1,37 @@ +package org.adaway.ui.adware; + +import android.app.Application; + +import androidx.lifecycle.AndroidViewModel; +import androidx.annotation.NonNull; + +/** + * This class is a {@link androidx.lifecycle.ViewModel} for adware UI. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class AdwareViewModel extends AndroidViewModel { + /** + * The install adware. + */ + private final AdwareLiveData adware; + + /** + * Constructor. + * + * @param application The application context. + */ + public AdwareViewModel(@NonNull Application application) { + super(application); + this.adware = new AdwareLiveData(application); + } + + /** + * Get the installed adware. + * + * @return The installed adware. + */ + public AdwareLiveData getAdware() { + return this.adware; + } +} diff --git a/app/src/main/java/org/adaway/ui/dialog/AlertDialogValidator.java b/app/src/main/java/org/adaway/ui/dialog/AlertDialogValidator.java new file mode 100644 index 0000000..a0eebfe --- /dev/null +++ b/app/src/main/java/org/adaway/ui/dialog/AlertDialogValidator.java @@ -0,0 +1,55 @@ +package org.adaway.ui.dialog; + + +import androidx.appcompat.app.AlertDialog; +import androidx.arch.core.util.Function; + +import android.content.DialogInterface; +import android.text.Editable; +import android.text.TextWatcher; +import android.widget.Button; + +/** + * This class is a {@link TextWatcher} to validate an alert dialog field. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class AlertDialogValidator implements TextWatcher { + /** + * The button to change status. + */ + private final Button mButton; + /** + * The field validator. + */ + private final Function validator; + + /** + * Constructor. + * + * @param dialog The button to change status. + * @param validator The field validator. + * @param initialState The validation initial state. + */ + public AlertDialogValidator(AlertDialog dialog, Function validator, boolean initialState) { + this.mButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); + this.mButton.setEnabled(initialState); + this.validator = validator; + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + String url = s.toString(); + this.mButton.setEnabled(this.validator.apply(url)); + } +} diff --git a/app/src/main/java/org/adaway/ui/dialog/MissingAppDialog.java b/app/src/main/java/org/adaway/ui/dialog/MissingAppDialog.java new file mode 100644 index 0000000..6f034a5 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/dialog/MissingAppDialog.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.ui.dialog; + +import android.app.SearchManager; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +import androidx.annotation.StringRes; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +import org.adaway.R; + +import timber.log.Timber; + +/** + * This class is an utility class to help install missing applications. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class MissingAppDialog { + /** + * Show a dialog to install a text editor. + * + * @param context The application context. + */ + public static void showTextEditorMissingDialog(Context context) { + showMissingAppDialog( + context, + R.string.no_text_editor_title, + R.string.no_text_editor, + "market://details?id=jp.sblo.pandora.jota", + "Text Edit" + ); + } + + /** + * Show a dialog to install a file manager. + * + * @param context The application context. + */ + public static void showFileManagerMissingDialog(Context context) { + showMissingAppDialog( + context, + R.string.no_file_manager_title, + R.string.no_file_manager, + "market://details?id=org.openintents.filemanager", + "OI File Manager" + ); + } + + private static void showMissingAppDialog( + Context context, + @StringRes int title, + @StringRes int message, + String appGooglePlayUri, + String appFdroidQuery + ) { + new MaterialAlertDialogBuilder(context) + .setTitle(title) + .setMessage(message) + .setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(R.string.button_yes, (dialog, id) -> { + Intent intentGooglePlay = new Intent(Intent.ACTION_VIEW); + intentGooglePlay.setData(Uri.parse(appGooglePlayUri)); + + try { + context.startActivity(intentGooglePlay); + } catch (ActivityNotFoundException e) { + Timber.e(e, "No Google Play Store installed!, Trying FDroid..."); + + Intent intentFDroid = new Intent(Intent.ACTION_SEARCH); + intentFDroid.setComponent(new ComponentName("org.fdroid.fdroid", + "org.fdroid.fdroid.SearchResults")); + intentFDroid.putExtra(SearchManager.QUERY, appFdroidQuery); + + try { + context.startActivity(intentFDroid); + } catch (ActivityNotFoundException e2) { + Timber.e(e2, "No FDroid installed!"); + } + } + }) + .setNegativeButton(R.string.button_no, (dialog, id) -> dialog.dismiss()) + .create() + .show(); + } +} diff --git a/app/src/main/java/org/adaway/ui/help/HelpActivity.java b/app/src/main/java/org/adaway/ui/help/HelpActivity.java new file mode 100644 index 0000000..d9ea623 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/help/HelpActivity.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.ui.help; + +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.adapter.FragmentStateAdapter; +import androidx.viewpager2.widget.ViewPager2; + +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.tabs.TabLayoutMediator; + +import org.adaway.R; +import org.adaway.helper.ThemeHelper; + +public class HelpActivity extends AppCompatActivity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + setContentView(R.layout.help_activity); + + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + } + + ViewPager2 viewPager = findViewById(R.id.pager); + viewPager.setAdapter(new TabsAdapter(this)); + + TabLayout tabLayout = findViewById(R.id.tabLayout); + + new TabLayoutMediator( + tabLayout, + viewPager, + (tab, position) -> tab.setText(getTabName(position)) + ).attach(); + } + + private @StringRes + int getTabName(int position) { + switch (position) { + case 0: + return R.string.help_tab_faq; + case 1: + return R.string.help_tab_problems; + case 2: + return R.string.help_tab_s_on_s_off; + default: + throw new IllegalStateException("Position " + position + " is not supported."); + } + } + + private static class TabsAdapter extends FragmentStateAdapter { + private final Fragment faqFragment = HelpFragmentHtml.newInstance(R.raw.help_faq); + private final Fragment problemsFragment = HelpFragmentHtml.newInstance(R.raw.help_problems); + private final Fragment sonSofFragment = HelpFragmentHtml.newInstance(R.raw.help_s_on_s_off); + + TabsAdapter(@NonNull FragmentActivity fragmentActivity) { + super(fragmentActivity); + } + + @NonNull + @Override + public Fragment createFragment(int position) { + switch (position) { + case 0: + return this.faqFragment; + case 1: + return this.problemsFragment; + case 2: + return this.sonSofFragment; + default: + throw new IllegalStateException("Position " + position + " is not supported."); + } + } + + @Override + public int getItemCount() { + return 3; + } + } +} diff --git a/app/src/main/java/org/adaway/ui/help/HelpFragmentHtml.java b/app/src/main/java/org/adaway/ui/help/HelpFragmentHtml.java new file mode 100644 index 0000000..e8dd76e --- /dev/null +++ b/app/src/main/java/org/adaway/ui/help/HelpFragmentHtml.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.ui.help; + +import android.os.Bundle; +import android.text.Html; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.RawRes; +import androidx.fragment.app.Fragment; + +import org.adaway.R; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import static android.text.Html.FROM_HTML_MODE_LEGACY; + +import timber.log.Timber; + +public class HelpFragmentHtml extends Fragment { + private static final String TAG = "Help"; + private static final String ARG_HTML_FILE = "htmlFile"; + + /** + * Create a new instance of HelpFragmentHtml, providing "htmlFile" as an argument. + */ + static HelpFragmentHtml newInstance(@RawRes int htmlFile) { + HelpFragmentHtml instance = new HelpFragmentHtml(); + + // Supply html raw file input as an argument. + Bundle args = new Bundle(); + args.putInt(ARG_HTML_FILE, htmlFile); + instance.setArguments(args); + + return instance; + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Spanned spanned = new SpannableString(""); + if (getArguments() != null) { + int htmlFile = getArguments().getInt(ARG_HTML_FILE); + try { + spanned = Html.fromHtml(readHtmlRawFile(htmlFile), FROM_HTML_MODE_LEGACY); + } catch (IOException e) { + Timber.w("Failed to read help file."); + } + } + + View view = inflater.inflate(R.layout.help_fragment, container, false); + TextView helpTextView = view.findViewById(R.id.helpTextView); + helpTextView.setText(spanned); + helpTextView.setMovementMethod(LinkMovementMethod.getInstance()); + return view; + } + + private String readHtmlRawFile(@RawRes int resourceId) throws IOException { + try (InputStream inputStream = getResources().openRawResource(resourceId); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + StringBuilder content = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + content.append(line); + } + return content.toString(); + } + } +} diff --git a/app/src/main/java/org/adaway/ui/home/HomeActivity.java b/app/src/main/java/org/adaway/ui/home/HomeActivity.java new file mode 100644 index 0000000..229b3e5 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/home/HomeActivity.java @@ -0,0 +1,366 @@ +package org.adaway.ui.home; + +import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HALF_EXPANDED; +import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN; +import static org.adaway.model.adblocking.AdBlockMethod.UNDEFINED; +import static org.adaway.model.adblocking.AdBlockMethod.VPN; +import static org.adaway.ui.Animations.removeView; +import static org.adaway.ui.Animations.showView; +import static org.adaway.ui.lists.ListsActivity.ALLOWED_HOSTS_TAB; +import static org.adaway.ui.lists.ListsActivity.BLOCKED_HOSTS_TAB; +import static org.adaway.ui.lists.ListsActivity.REDIRECTED_HOSTS_TAB; +import static org.adaway.ui.lists.ListsActivity.TAB; + +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Typeface; +import android.net.Uri; +import android.net.VpnService; +import android.os.Bundle; +import android.view.MenuItem; +import android.view.View; +import android.widget.TextView; + +import androidx.activity.OnBackPressedCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; +import androidx.annotation.IdRes; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.Transformations; +import androidx.lifecycle.ViewModelProvider; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +import org.adaway.R; +import org.adaway.databinding.HomeActivityBinding; +import org.adaway.helper.NotificationHelper; +import org.adaway.helper.PreferenceHelper; +import org.adaway.helper.ThemeHelper; +import org.adaway.model.adblocking.AdBlockMethod; +import org.adaway.model.error.HostError; +import org.adaway.ui.help.HelpActivity; +import org.adaway.ui.hosts.HostsSourcesActivity; +import org.adaway.ui.lists.ListsActivity; +import org.adaway.ui.log.LogActivity; +import org.adaway.ui.prefs.PrefsActivity; +import org.adaway.ui.support.SupportActivity; +import org.adaway.ui.update.UpdateActivity; +import org.adaway.ui.welcome.WelcomeActivity; + +import kotlin.jvm.functions.Function1; +import timber.log.Timber; + +/** + * This class is the application main activity. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class HomeActivity extends AppCompatActivity { + /** + * The project link. + */ + private static final String PROJECT_LINK = "https://github.com/AdAway/AdAway"; + + private HomeActivityBinding binding; + private BottomSheetBehavior drawerBehavior; + private OnBackPressedCallback onBackPressedCallback; + private HomeViewModel homeViewModel; + private ActivityResultLauncher prepareVpnLauncher; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + NotificationHelper.clearUpdateNotifications(this); + Timber.i("Starting main activity"); + this.binding = HomeActivityBinding.inflate(getLayoutInflater()); + setContentView(this.binding.getRoot()); + + this.homeViewModel = new ViewModelProvider(this).get(HomeViewModel.class); + this.homeViewModel.isAdBlocked().observe(this, this::notifyAdBlocked); + this.homeViewModel.getError().observe(this, this::notifyError); + + applyActionBar(); + bindAppVersion(); + bindHostCounter(); + bindSourceCounter(); + bindPending(); + bindState(); + bindClickListeners(); + setUpBottomDrawer(); + bindFab(); + + this.binding.navigationView.setNavigationItemSelectedListener(item -> { + if (showFragment(item.getItemId())) { + this.drawerBehavior.setState(STATE_HIDDEN); + } + return false; // TODO Handle selection + }); + + this.prepareVpnLauncher = registerForActivityResult(new StartActivityForResult(), result -> { + + }); + + if (savedInstanceState == null) { + checkUpdateAtStartup(); + } + } + + @Override + protected void onResume() { + super.onResume(); + checkFirstStep(); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + return showFragment(item.getItemId()); + } + + private void checkFirstStep() { + AdBlockMethod adBlockMethod = PreferenceHelper.getAdBlockMethod(this); + Intent prepareIntent; + if (adBlockMethod == UNDEFINED) { + // Start welcome activity + startActivity(new Intent(this, WelcomeActivity.class)); + finish(); + } else if (adBlockMethod == VPN && (prepareIntent = VpnService.prepare(this)) != null) { + // Prepare VPN + this.prepareVpnLauncher.launch(prepareIntent); + } + } + + private void checkUpdateAtStartup() { + boolean checkAppUpdateAtStartup = PreferenceHelper.getUpdateCheckAppStartup(this); + if (checkAppUpdateAtStartup) { + this.homeViewModel.checkForAppUpdate(); + } + boolean checkUpdateAtStartup = PreferenceHelper.getUpdateCheck(this); + if (checkUpdateAtStartup) { + this.homeViewModel.update(); + } + } + + private void applyActionBar() { + setSupportActionBar(this.binding.bar); + } + + private void bindAppVersion() { + TextView versionTextView = this.binding.content.versionTextView; + versionTextView.setText(this.homeViewModel.getVersionName()); + versionTextView.setOnClickListener(this::showUpdate); + + this.homeViewModel.getAppManifest().observe( + this, + manifest -> { + if (manifest.updateAvailable) { + versionTextView.setTypeface(versionTextView.getTypeface(), Typeface.BOLD); + versionTextView.setText(R.string.update_available); + } + } + ); + } + + private void bindHostCounter() { + Function1 stringMapper = count -> Integer.toString(count); + + TextView blockedHostCountTextView = this.binding.content.blockedHostCounterTextView; + LiveData blockedHostCount = this.homeViewModel.getBlockedHostCount(); + Transformations.map(blockedHostCount, stringMapper).observe(this, blockedHostCountTextView::setText); + + TextView allowedHostCountTextView = this.binding.content.allowedHostCounterTextView; + LiveData allowedHostCount = this.homeViewModel.getAllowedHostCount(); + Transformations.map(allowedHostCount, stringMapper).observe(this, allowedHostCountTextView::setText); + + TextView redirectHostCountTextView = this.binding.content.redirectHostCounterTextView; + LiveData redirectHostCount = this.homeViewModel.getRedirectHostCount(); + Transformations.map(redirectHostCount, stringMapper).observe(this, redirectHostCountTextView::setText); + } + + private void bindSourceCounter() { + Resources resources = getResources(); + + TextView upToDateSourcesTextView = this.binding.content.upToDateSourcesTextView; + LiveData upToDateSourceCount = this.homeViewModel.getUpToDateSourceCount(); + upToDateSourceCount.observe(this, count -> + upToDateSourcesTextView.setText(resources.getQuantityString(R.plurals.up_to_date_source_label, count, count)) + ); + + TextView outdatedSourcesTextView = this.binding.content.outdatedSourcesTextView; + LiveData outdatedSourceCount = this.homeViewModel.getOutdatedSourceCount(); + outdatedSourceCount.observe(this, count -> + outdatedSourcesTextView.setText(resources.getQuantityString(R.plurals.outdated_source_label, count, count)) + ); + } + + private void bindPending() { + this.homeViewModel.getPending().observe(this, pending -> { + if (pending) { + showView(this.binding.content.sourcesProgressBar); + showView(this.binding.content.stateTextView); + } else { + removeView(this.binding.content.sourcesProgressBar); + } + }); + } + + private void bindState() { + this.homeViewModel.getState().observe(this, text -> { + this.binding.content.stateTextView.setText(text); + if (text.isEmpty()) { + removeView(this.binding.content.stateTextView); + } else { + showView(this.binding.content.stateTextView); + } + }); + } + + private void bindClickListeners() { + this.binding.content.blockedHostCardView.setOnClickListener(v -> startHostListActivity(BLOCKED_HOSTS_TAB)); + this.binding.content.allowedHostCardView.setOnClickListener(v -> startHostListActivity(ALLOWED_HOSTS_TAB)); + this.binding.content.redirectHostCardView.setOnClickListener(v -> startHostListActivity(REDIRECTED_HOSTS_TAB)); + this.binding.content.sourcesCardView.setOnClickListener(this::startHostsSourcesActivity); + this.binding.content.checkForUpdateImageView.setOnClickListener(v -> this.homeViewModel.update()); + this.binding.content.updateImageView.setOnClickListener(v -> this.homeViewModel.sync()); + this.binding.content.logCardView.setOnClickListener(this::startDnsLogActivity); + this.binding.content.helpCardView.setOnClickListener(this::startHelpActivity); + this.binding.content.supportCardView.setOnClickListener(this::showSupportActivity); + } + + private void setUpBottomDrawer() { + this.drawerBehavior = BottomSheetBehavior.from(this.binding.bottomDrawer); + this.drawerBehavior.setState(STATE_HIDDEN); + + this.onBackPressedCallback = new OnBackPressedCallback(false) { + @Override + public void handleOnBackPressed() { + // Hide drawer if expanded + HomeActivity.this.drawerBehavior.setState(STATE_HIDDEN); + HomeActivity.this.onBackPressedCallback.setEnabled(false); + } + }; + getOnBackPressedDispatcher().addCallback(this.onBackPressedCallback); + + this.binding.bar.setNavigationOnClickListener(v -> { + this.drawerBehavior.setState(STATE_HALF_EXPANDED); + this.onBackPressedCallback.setEnabled(true); + }); +// this.binding.bar.setNavigationIcon(R.drawable.ic_menu_24dp); +// this.binding.bar.replaceMenu(R.menu.next_actions); + } + + private void bindFab() { + this.binding.fab.setOnClickListener(v -> this.homeViewModel.toggleAdBlocking()); + } + + private boolean showFragment(@IdRes int actionId) { + if (actionId == R.id.drawer_preferences) { + startPrefsActivity(); + this.drawerBehavior.setState(STATE_HIDDEN); + return true; + } else if (actionId == R.id.drawer_github_project) { + showProjectPage(); + this.drawerBehavior.setState(STATE_HIDDEN); + return true; + } + return false; + } + + /** + * Start hosts lists activity. + * + * @param tab The tab to show. + */ + private void startHostListActivity(int tab) { + Intent intent = new Intent(this, ListsActivity.class); + intent.putExtra(TAB, tab); + startActivity(intent); + } + + /** + * Start hosts source activity. + * + * @param view The event source view. + */ + private void startHostsSourcesActivity(View view) { + startActivity(new Intent(this, HostsSourcesActivity.class)); + } + + /** + * Start help activity. + * + * @param view The source event view. + */ + private void startHelpActivity(View view) { + startActivity(new Intent(this, HelpActivity.class)); + } + + /** + * Show development project page. + */ + private void showProjectPage() { + // Show development page + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(PROJECT_LINK)); + startActivity(browserIntent); + } + + /** + * Show support activity. + * + * @param view The source event view. + */ + private void showSupportActivity(View view) { + startActivity(new Intent(this, SupportActivity.class)); + } + + /** + * Start preferences activity. + */ + private void startPrefsActivity() { + startActivity(new Intent(this, PrefsActivity.class)); + } + + /** + * Start DNS log activity. + * + * @param view The source event view. + */ + private void startDnsLogActivity(View view) { + startActivity(new Intent(this, LogActivity.class)); + } + + private void notifyAdBlocked(boolean adBlocked) { + int color = adBlocked ? getResources().getColor(R.color.primary, null) : Color.GRAY; + this.binding.content.headerFrameLayout.setBackgroundColor(color); + this.binding.fab.setImageResource(adBlocked ? R.drawable.ic_pause_24dp : R.drawable.logo); + } + + private void notifyError(HostError error) { + removeView(this.binding.content.stateTextView); + if (error == null) { + return; + } + + String message = getString(error.getDetailsKey()) + "\n\n" + getString(R.string.error_dialog_help); + new MaterialAlertDialogBuilder(this) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(error.getMessageKey()) + .setMessage(message) + .setPositiveButton(R.string.button_close, (dialog, id) -> dialog.dismiss()) + .setNegativeButton(R.string.button_help, (dialog, id) -> { + dialog.dismiss(); + startActivity(new Intent(this, HelpActivity.class)); + }) + .create() + .show(); + } + + private void showUpdate(View view) { + Intent intent = new Intent(this, UpdateActivity.class); + startActivity(intent); + } +} diff --git a/app/src/main/java/org/adaway/ui/home/HomeViewModel.java b/app/src/main/java/org/adaway/ui/home/HomeViewModel.java new file mode 100644 index 0000000..8fb8256 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/home/HomeViewModel.java @@ -0,0 +1,182 @@ +package org.adaway.ui.home; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MediatorLiveData; +import androidx.lifecycle.MutableLiveData; + +import org.adaway.AdAwayApplication; +import org.adaway.db.AppDatabase; +import org.adaway.db.dao.HostListItemDao; +import org.adaway.db.dao.HostsSourceDao; +import org.adaway.model.adblocking.AdBlockModel; +import org.adaway.model.error.HostError; +import org.adaway.model.error.HostErrorException; +import org.adaway.model.source.SourceModel; +import org.adaway.model.update.Manifest; +import org.adaway.model.update.UpdateModel; +import org.adaway.util.AppExecutors; + +import timber.log.Timber; + +/** + * This class is an {@link AndroidViewModel} for the {@link HomeActivity} cards. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class HomeViewModel extends AndroidViewModel { + private static final AppExecutors EXECUTORS = AppExecutors.getInstance(); + + private final SourceModel sourceModel; + private final AdBlockModel adBlockModel; + private final UpdateModel updateModel; + + private final HostsSourceDao hostsSourceDao; + private final HostListItemDao hostListItemDao; + + private final MutableLiveData pending; + private final MediatorLiveData state; + private final MutableLiveData error; + + public HomeViewModel(@NonNull Application application) { + super(application); + AdAwayApplication awayApplication = (AdAwayApplication) application; + this.sourceModel = awayApplication.getSourceModel(); + this.adBlockModel = awayApplication.getAdBlockModel(); + this.updateModel = awayApplication.getUpdateModel(); + + AppDatabase database = AppDatabase.getInstance(application); + this.hostsSourceDao = database.hostsSourceDao(); + this.hostListItemDao = database.hostsListItemDao(); + + this.pending = new MutableLiveData<>(false); + this.state = new MediatorLiveData<>(); + this.state.addSource(this.sourceModel.getState(), this.state::setValue); + this.state.addSource(this.adBlockModel.getState(), this.state::setValue); + this.error = new MutableLiveData<>(); + } + + private static boolean isTrue(LiveData liveData) { + Boolean value = liveData.getValue(); + return value != null && value; + } + + public LiveData isAdBlocked() { + return this.adBlockModel.isApplied(); + } + + public LiveData isUpdateAvailable() { + return this.sourceModel.isUpdateAvailable(); + } + + public String getVersionName() { + return this.updateModel.getVersionName(); + } + + public LiveData getAppManifest() { + return this.updateModel.getManifest(); + } + + public LiveData getBlockedHostCount() { + return this.hostListItemDao.getBlockedHostCount(); + } + + public LiveData getAllowedHostCount() { + return this.hostListItemDao.getAllowedHostCount(); + } + + public LiveData getRedirectHostCount() { + return this.hostListItemDao.getRedirectHostCount(); + } + + public LiveData getUpToDateSourceCount() { + return this.hostsSourceDao.countUpToDate(); + } + + public LiveData getOutdatedSourceCount() { + return this.hostsSourceDao.countOutdated(); + } + + public LiveData getPending() { + return this.pending; + } + + public LiveData getState() { + return this.state; + } + + public LiveData getError() { + return this.error; + } + + public void checkForAppUpdate() { + EXECUTORS.networkIO().execute(this.updateModel::checkForUpdate); + } + + public void toggleAdBlocking() { + if (isTrue(this.pending)) { + return; + } + EXECUTORS.diskIO().execute(() -> { + try { + this.pending.postValue(true); + if (isTrue(this.adBlockModel.isApplied())) { + this.adBlockModel.revert(); + } else { + this.adBlockModel.apply(); + } + } catch (HostErrorException exception) { + Timber.w(exception, "Failed to toggle ad blocking."); + this.error.postValue(exception.getError()); + } finally { + this.pending.postValue(false); + } + }); + } + + public void update() { + if (isTrue(this.pending)) { + return; + } + EXECUTORS.networkIO().execute(() -> { + try { + this.pending.postValue(true); + this.sourceModel.checkForUpdate(); + } catch (HostErrorException exception) { + Timber.w(exception, "Failed to update."); + this.error.postValue(exception.getError()); + } finally { + this.pending.postValue(false); + } + }); + } + + public void sync() { + if (isTrue(this.pending)) { + return; + } + EXECUTORS.networkIO().execute(() -> { + try { + this.pending.postValue(true); + this.sourceModel.retrieveHostsSources(); + this.adBlockModel.apply(); + } catch (HostErrorException exception) { + Timber.w(exception, "Failed to sync."); + this.error.postValue(exception.getError()); + } finally { + this.pending.postValue(false); + } + }); + } + + public void enableAllSources() { + EXECUTORS.diskIO().execute(() -> { + if (this.sourceModel.enableAllSources()) { + sync(); + } + }); + } +} diff --git a/app/src/main/java/org/adaway/ui/hosts/HostsSourcesActivity.java b/app/src/main/java/org/adaway/ui/hosts/HostsSourcesActivity.java new file mode 100644 index 0000000..585b3c6 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/hosts/HostsSourcesActivity.java @@ -0,0 +1,41 @@ +package org.adaway.ui.hosts; + +import android.os.Bundle; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; + +import org.adaway.R; +import org.adaway.helper.ThemeHelper; + +/** + * This activity display hosts list items. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class HostsSourcesActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + /* + * Create fragment + */ + HostsSourcesFragment fragment = new HostsSourcesFragment(); + /* + * Set view content. + */ + setContentView(R.layout.hosts_sources_activity); + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.hosts_sources_container, fragment) + .commit(); + /* + * Configure actionbar. + */ + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } + } +} diff --git a/app/src/main/java/org/adaway/ui/hosts/HostsSourcesAdapter.java b/app/src/main/java/org/adaway/ui/hosts/HostsSourcesAdapter.java new file mode 100644 index 0000000..13f9f73 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/hosts/HostsSourcesAdapter.java @@ -0,0 +1,208 @@ +package org.adaway.ui.hosts; + +import android.content.Context; +import android.content.res.Resources; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.ListAdapter; +import androidx.recyclerview.widget.RecyclerView; + +import org.adaway.R; +import org.adaway.db.entity.HostsSource; + +import java.time.Duration; +import java.time.ZonedDateTime; + +/** + * This class is a the {@link RecyclerView.Adapter} for the hosts sources view. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class HostsSourcesAdapter extends ListAdapter { + /** + * This callback is use to compare hosts sources. + */ + private static final DiffUtil.ItemCallback DIFF_CALLBACK = + new DiffUtil.ItemCallback() { + @Override + public boolean areItemsTheSame(@NonNull HostsSource oldSource, @NonNull HostsSource newSource) { + return oldSource.getUrl().equals(newSource.getUrl()); + } + + @Override + public boolean areContentsTheSame(@NonNull HostsSource oldSource, @NonNull HostsSource newSource) { + // NOTE: if you use equals, your object must properly override Object#equals() + // Incorrectly returning false here will result in too many animations. + return oldSource.equals(newSource); + } + }; + + /** + * This callback is use to call view actions. + */ + @NonNull + private final HostsSourcesViewCallback viewCallback; + private static final String[] QUANTITY_PREFIXES = new String[]{"k", "M", "G"}; + + /** + * Constructor. + * + * @param viewCallback The view callback. + */ + HostsSourcesAdapter(@NonNull HostsSourcesViewCallback viewCallback) { + super(DIFF_CALLBACK); + this.viewCallback = viewCallback; + } + + /** + * Get the approximate delay from a date to now. + * + * @param context The application context. + * @param from The date from which computes the delay. + * @return The approximate delay. + */ + private static String getApproximateDelay(Context context, ZonedDateTime from) { + // Get resource for plurals + Resources resources = context.getResources(); + // Get current date in UTC timezone + ZonedDateTime now = ZonedDateTime.now(); + // Get delay between from and now in minutes + long delay = Duration.between(from, now).toMinutes(); + // Check if delay is lower than an hour + if (delay < 60) { + return resources.getString(R.string.hosts_source_few_minutes); + } + // Get delay in hours + delay /= 60; + // Check if delay is lower than a day + if (delay < 24) { + int hours = (int) delay; + return resources.getQuantityString(R.plurals.hosts_source_hours, hours, hours); + } + // Get delay in days + delay /= 24; + // Check if delay is lower than a month + if (delay < 30) { + int days = (int) delay; + return resources.getQuantityString(R.plurals.hosts_source_days, days, days); + } + // Get delay in months + int months = (int) delay / 30; + return resources.getQuantityString(R.plurals.hosts_source_months, months, months); + } + + @NonNull + @Override + public HostsSourcesAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); + View view = layoutInflater.inflate(R.layout.hosts_sources_card, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + HostsSource source = this.getItem(position); + holder.enabledCheckBox.setChecked(source.isEnabled()); + holder.enabledCheckBox.setOnClickListener(view -> viewCallback.toggleEnabled(source)); + holder.labelTextView.setText(source.getLabel()); + holder.urlTextView.setText(source.getUrl()); + holder.updateTextView.setText(getUpdateText(source)); + holder.sizeTextView.setText(getHostCount(source)); + holder.itemView.setOnClickListener(view -> viewCallback.edit(source)); + } + + private String getUpdateText(HostsSource source) { + // Get context + Context context = this.viewCallback.getContext(); + // Check if source is enabled + if (!source.isEnabled()) { + return context.getString(R.string.hosts_source_disabled); + } + // Check modification dates + boolean lastOnlineModificationDefined = source.getOnlineModificationDate() != null; + boolean lastLocalModificationDefined = source.getLocalModificationDate() != null; + // Declare update text + String updateText; + // Check if last online modification date is known + if (lastOnlineModificationDefined) { + // Get last online modification delay + String approximateDelay = getApproximateDelay(context, source.getOnlineModificationDate()); + if (!lastLocalModificationDefined) { + updateText = context.getString(R.string.hosts_source_last_update, approximateDelay); + } else if (source.getOnlineModificationDate().isAfter(source.getLocalModificationDate())) { + updateText = context.getString(R.string.hosts_source_need_update, approximateDelay); + } else { + updateText = context.getString(R.string.hosts_source_up_to_date, approximateDelay); + } + } else { + if (lastLocalModificationDefined) { + String approximateDelay = getApproximateDelay(context, source.getLocalModificationDate()); + updateText = context.getString(R.string.hosts_source_installed, approximateDelay); + } else { + updateText = context.getString(R.string.hosts_source_unknown_status); + } + } + return updateText; + } + + private String getHostCount(HostsSource source) { + // Note: NumberFormat.getCompactNumberInstance is Java 12 only + // Check empty source + int size = source.getSize(); + if (size <= 0 || !source.isEnabled()) { + return ""; + } + // Compute size decimal length + int length = 1; + while (size > 10) { + size /= 10; + length++; + } + // Compute prefix to use + int prefixIndex = (length - 1) / 3 - 1; + // Return formatted count + Context context = this.viewCallback.getContext(); + size = source.getSize(); + if (prefixIndex < 0) { + return context.getString(R.string.hosts_count, Integer.toString(size)); + } else if (prefixIndex >= QUANTITY_PREFIXES.length) { + prefixIndex = QUANTITY_PREFIXES.length - 1; + size = 13; + } + size = Math.toIntExact(Math.round(size / Math.pow(10, (prefixIndex + 1) * 3D))); + return context.getString(R.string.hosts_count, size + QUANTITY_PREFIXES[prefixIndex]); + } + + /** + * This class is a the {@link RecyclerView.ViewHolder} for the hosts sources view. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ + static class ViewHolder extends RecyclerView.ViewHolder { + final CheckBox enabledCheckBox; + final TextView labelTextView; + final TextView urlTextView; + final TextView updateTextView; + final TextView sizeTextView; + + /** + * Constructor. + * + * @param itemView The hosts sources view. + */ + ViewHolder(View itemView) { + super(itemView); + this.enabledCheckBox = itemView.findViewById(R.id.sourceEnabledCheckBox); + this.labelTextView = itemView.findViewById(R.id.sourceLabelTextView); + this.urlTextView = itemView.findViewById(R.id.sourceUrlTextView); + this.updateTextView = itemView.findViewById(R.id.sourceUpdateTextView); + this.sizeTextView = itemView.findViewById(R.id.sourceSizeTextView); + } + } +} diff --git a/app/src/main/java/org/adaway/ui/hosts/HostsSourcesFragment.java b/app/src/main/java/org/adaway/ui/hosts/HostsSourcesFragment.java new file mode 100644 index 0000000..6c2a9b9 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/hosts/HostsSourcesFragment.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.ui.hosts; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import org.adaway.R; +import org.adaway.db.entity.HostsSource; +import org.adaway.ui.adblocking.ApplyConfigurationSnackbar; +import org.adaway.ui.source.SourceEditActivity; + +import static org.adaway.ui.source.SourceEditActivity.SOURCE_ID; + +/** + * This class is a {@link Fragment} to display and manage hosts sources. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class HostsSourcesFragment extends Fragment implements HostsSourcesViewCallback { + /** + * The view model (null if view is not created). + */ + private HostsSourcesViewModel mViewModel; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + // Get activity + Activity activity = requireActivity(); + // Initialize view model + this.mViewModel = new ViewModelProvider(this).get(HostsSourcesViewModel.class); + LifecycleOwner lifecycleOwner = getViewLifecycleOwner(); + // Create fragment view + View view = inflater.inflate(R.layout.hosts_sources_fragment, container, false); + /* + * Configure snackbar. + */ + // Get lists layout to attached snackbar to + CoordinatorLayout coordinatorLayout = view.findViewById(R.id.coordinator); + // Create apply snackbar + ApplyConfigurationSnackbar applySnackbar = new ApplyConfigurationSnackbar(coordinatorLayout, true, true); + // Bind snakbar to view models + this.mViewModel.getHostsSources().observe(lifecycleOwner, applySnackbar.createObserver()); + /* + * Configure recycler view. + */ + // Store recycler view + RecyclerView recyclerView = view.findViewById(R.id.hosts_sources_list); + recyclerView.setHasFixedSize(true); + // Defile recycler layout + LinearLayoutManager linearLayoutManager = new LinearLayoutManager(activity); + recyclerView.setLayoutManager(linearLayoutManager); + // Create recycler adapter + HostsSourcesAdapter adapter = new HostsSourcesAdapter(this); + recyclerView.setAdapter(adapter); + // Bind adapter to view model + this.mViewModel.getHostsSources().observe(lifecycleOwner, adapter::submitList); + /* + * Add floating action button. + */ + // Get floating action button + FloatingActionButton button = view.findViewById(R.id.hosts_sources_add); + // Set click listener to display menu add entry + button.setOnClickListener(actionButton -> startSourceEdition(null)); + // Return fragment view + return view; + } + + @Override + public void toggleEnabled(HostsSource source) { + this.mViewModel.toggleSourceEnabled(source); + } + + @Override + public void edit(HostsSource source) { + startSourceEdition(source); + } + + private void startSourceEdition(@Nullable HostsSource source) { + Intent intent = new Intent(requireContext(), SourceEditActivity.class); + if (source != null) { + intent.putExtra(SOURCE_ID, source.getId()); + } + startActivity(intent); + } +} diff --git a/app/src/main/java/org/adaway/ui/hosts/HostsSourcesViewCallback.java b/app/src/main/java/org/adaway/ui/hosts/HostsSourcesViewCallback.java new file mode 100644 index 0000000..b25aebc --- /dev/null +++ b/app/src/main/java/org/adaway/ui/hosts/HostsSourcesViewCallback.java @@ -0,0 +1,33 @@ +package org.adaway.ui.hosts; + +import android.content.Context; + +import org.adaway.db.entity.HostsSource; + +/** + * This class is represents the {@link HostsSourcesFragment} callback. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public interface HostsSourcesViewCallback { + /** + * Get the application context. + * + * @return The application context. + */ + Context getContext(); + + /** + * Toggle host source enable status. + * + * @param source The hosts source to toggle status. + */ + void toggleEnabled(HostsSource source); + + /** + * Start an action. + * + * @param source The hosts source to start the action. + */ + void edit(HostsSource source); +} diff --git a/app/src/main/java/org/adaway/ui/hosts/HostsSourcesViewModel.java b/app/src/main/java/org/adaway/ui/hosts/HostsSourcesViewModel.java new file mode 100644 index 0000000..7b1c4eb --- /dev/null +++ b/app/src/main/java/org/adaway/ui/hosts/HostsSourcesViewModel.java @@ -0,0 +1,38 @@ +package org.adaway.ui.hosts; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; + +import org.adaway.db.AppDatabase; +import org.adaway.db.dao.HostsSourceDao; +import org.adaway.db.entity.HostsSource; +import org.adaway.util.AppExecutors; + +import java.util.List; +import java.util.concurrent.Executor; + +/** + * This class is an {@link AndroidViewModel} for the {@link HostsSourcesFragment}. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class HostsSourcesViewModel extends AndroidViewModel { + private static final Executor EXECUTOR = AppExecutors.getInstance().diskIO(); + private final HostsSourceDao hostsSourceDao; + + public HostsSourcesViewModel(@NonNull Application application) { + super(application); + this.hostsSourceDao = AppDatabase.getInstance(application).hostsSourceDao(); + } + + public LiveData> getHostsSources() { + return this.hostsSourceDao.loadAll(); + } + + public void toggleSourceEnabled(HostsSource source) { + EXECUTOR.execute(() -> this.hostsSourceDao.toggleEnabled(source)); + } +} diff --git a/app/src/main/java/org/adaway/ui/lists/ListsActivity.java b/app/src/main/java/org/adaway/ui/lists/ListsActivity.java new file mode 100644 index 0000000..6d7116e --- /dev/null +++ b/app/src/main/java/org/adaway/ui/lists/ListsActivity.java @@ -0,0 +1,185 @@ +package org.adaway.ui.lists; + +import static android.content.Intent.ACTION_SEARCH; + +import android.app.SearchManager; +import android.content.Intent; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.widget.SearchView; + +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.lifecycle.ViewModelProvider; +import androidx.viewpager2.widget.ViewPager2; + +import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import org.adaway.R; +import org.adaway.helper.ThemeHelper; +import org.adaway.ui.adblocking.ApplyConfigurationSnackbar; + +/** + * This activity display hosts list items. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class ListsActivity extends AppCompatActivity { + /** + * The tab to display argument. + */ + public static final String TAB = "org.adaway.lists.tab"; + /** + * The blocked hosts tab index. + */ + public static final int BLOCKED_HOSTS_TAB = 0; + /** + * The allowed hosts tab index. + */ + public static final int ALLOWED_HOSTS_TAB = 1; + /** + * The redirected hosts tab index. + */ + public static final int REDIRECTED_HOSTS_TAB = 2; + /** + * The view model. + */ + private ListsViewModel listsViewModel; + /** + * The back press callback. + */ + private OnBackPressedCallback onBackPressedCallback; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + /* + * Set view content. + */ + setContentView(R.layout.lists_fragment); + /* + * Configure actionbar. + */ + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } + /* + * Configure back press callback. + */ + this.onBackPressedCallback = new OnBackPressedCallback(false) { + @Override + public void handleOnBackPressed() { + ListsActivity.this.listsViewModel.clearSearch(); + ListsActivity.this.onBackPressedCallback.setEnabled(false); + } + }; + getOnBackPressedDispatcher().addCallback(this.onBackPressedCallback); + /* + * Configure tabs. + */ + // Get view pager + ViewPager2 viewPager = findViewById(R.id.lists_view_pager); + // Create pager adapter + ListsFragmentPagerAdapter pagerAdapter = new ListsFragmentPagerAdapter(this); + // Set view pager adapter + viewPager.setAdapter(pagerAdapter); + // Get navigation view + BottomNavigationView navigationView = findViewById(R.id.navigation); + // Add view pager on page listener to set selected tab according the selected page + viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageSelected(int position) { + navigationView.getMenu().getItem(position).setChecked(true); + pagerAdapter.ensureActionModeCanceled(); + } + }); + // Add navigation view item selected listener to change view pager current item + navigationView.setOnItemSelectedListener(item -> { + if (item.getItemId() == R.id.lists_navigation_blocked) { + viewPager.setCurrentItem(0); + return true; + } else if (item.getItemId() == R.id.lists_navigation_allowed) { + viewPager.setCurrentItem(1); + return true; + } else if (item.getItemId() == R.id.lists_navigation_redirected) { + viewPager.setCurrentItem(2); + return true; + } + return false; + }); + // Display requested tab + Intent intent = getIntent(); + int tab = intent.getIntExtra(TAB, BLOCKED_HOSTS_TAB); + viewPager.setCurrentItem(tab); + /* + * Configure add action button. + */ + // Get the add action button + FloatingActionButton addActionButton = findViewById(R.id.lists_add); + // Set add action button listener + addActionButton.setOnClickListener(clickedView -> { + // Get current fragment position + int currentItemPosition = viewPager.getCurrentItem(); + // Add item to the current fragment + pagerAdapter.addItem(currentItemPosition); + }); + /* + * Configure snackbar. + */ + // Get lists layout to attached snackbar to + CoordinatorLayout coordinatorLayout = findViewById(R.id.coordinator); + // Create apply snackbar + ApplyConfigurationSnackbar applySnackbar = new ApplyConfigurationSnackbar(coordinatorLayout, false, false); + // Bind snackbar to view models + this.listsViewModel = new ViewModelProvider(this).get(ListsViewModel.class); + this.listsViewModel.getModelChanged().observe(this, applySnackbar.createObserver()); + // Get the intent, verify the action and get the query + handleQuery(intent); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + handleQuery(intent); + } + + private void handleQuery(Intent intent) { + if (ACTION_SEARCH.equals(intent.getAction())) { + String query = intent.getStringExtra(SearchManager.QUERY); + this.listsViewModel.search(query); + this.onBackPressedCallback.setEnabled(true); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.list_menu, menu); + // Get the SearchView and set the searchable configuration + SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE); + if (searchManager != null) { + SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView(); + searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); + searchView.setIconifiedByDefault(false); + } + return true; + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (item.getItemId() == R.id.menu_toggle_source) { + this.listsViewModel.toggleSources(); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/org/adaway/ui/lists/ListsFilter.java b/app/src/main/java/org/adaway/ui/lists/ListsFilter.java new file mode 100644 index 0000000..46cd7fc --- /dev/null +++ b/app/src/main/java/org/adaway/ui/lists/ListsFilter.java @@ -0,0 +1,33 @@ +package org.adaway.ui.lists; + +/** + * This class represents the filter to apply to host lists. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class ListsFilter { + public static final ListsFilter ALL = new ListsFilter(true, ""); + /** + * Whether included hosts from sources or not. + */ + public final boolean sourcesIncluded; + /** + * The query filter to apply to hosts name (wildcard based). + */ + public final String query; + /** + * The query filter to apply to hosts name (sql like format). + */ + public final String sqlQuery; + + public ListsFilter(boolean sourcesIncluded, String query) { + this.sourcesIncluded = sourcesIncluded; + this.query = query; + this.sqlQuery = convertToLikeQuery(query); + } + + private static String convertToLikeQuery(String query) { + return "%" + query.replace("*", "%") + .replace("?", "_") + "%"; + } +} diff --git a/app/src/main/java/org/adaway/ui/lists/ListsFragmentPagerAdapter.java b/app/src/main/java/org/adaway/ui/lists/ListsFragmentPagerAdapter.java new file mode 100644 index 0000000..1a95653 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/lists/ListsFragmentPagerAdapter.java @@ -0,0 +1,110 @@ +package org.adaway.ui.lists; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.adapter.FragmentStateAdapter; + +import org.adaway.ui.lists.type.AbstractListFragment; +import org.adaway.ui.lists.type.AllowedHostsFragment; +import org.adaway.ui.lists.type.BlockedHostsFragment; +import org.adaway.ui.lists.type.RedirectedHostsFragment; + +import static org.adaway.ui.lists.ListsActivity.BLOCKED_HOSTS_TAB; +import static org.adaway.ui.lists.ListsActivity.REDIRECTED_HOSTS_TAB; +import static org.adaway.ui.lists.ListsActivity.ALLOWED_HOSTS_TAB; + +/** + * This class is a {@link FragmentStateAdapter} to store lists tab fragments. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class ListsFragmentPagerAdapter extends FragmentStateAdapter { + /** + * The number of fragment. + */ + private static final int FRAGMENT_COUNT = 3; + /** + * The blacklist fragment (null until first retrieval). + */ + private final AbstractListFragment blacklistFragment; + /** + * The whitelist fragment (null until first retrieval). + */ + private final AbstractListFragment whitelistFragment; + /** + * The redirection list fragment (null until first retrieval). + */ + private final AbstractListFragment redirectionListFragment; + + /** + * Constructor. + * + */ + ListsFragmentPagerAdapter(FragmentActivity fragmentActivity) { + super(fragmentActivity); + this.blacklistFragment = new BlockedHostsFragment(); + this.whitelistFragment = new AllowedHostsFragment(); + this.redirectionListFragment = new RedirectedHostsFragment(); + } + + @NonNull + @Override + public Fragment createFragment(int position) { + switch (position) { + case BLOCKED_HOSTS_TAB: + return this.blacklistFragment; + case ALLOWED_HOSTS_TAB: + return this.whitelistFragment; + case REDIRECTED_HOSTS_TAB: + return this.redirectionListFragment; + default: + throw new IllegalStateException("Position " + position + " is not supported."); + } + } + + @Override + public int getItemCount() { + return FRAGMENT_COUNT; + } + + /** + * Ensure action mode is cancelled. + */ + void ensureActionModeCanceled() { + if (this.blacklistFragment != null) { + this.blacklistFragment.ensureActionModeCanceled(); + } + if (this.whitelistFragment != null) { + this.whitelistFragment.ensureActionModeCanceled(); + } + if (this.redirectionListFragment != null) { + this.redirectionListFragment.ensureActionModeCanceled(); + } + } + + /** + * Add an item into the requested fragment. + * + * @param position The fragment position. + */ + void addItem(int position) { + switch (position) { + case BLOCKED_HOSTS_TAB: + if (this.blacklistFragment != null) { + this.blacklistFragment.addItem(); + } + break; + case ALLOWED_HOSTS_TAB: + if (this.whitelistFragment != null) { + this.whitelistFragment.addItem(); + } + break; + case REDIRECTED_HOSTS_TAB: + if (this.redirectionListFragment != null) { + this.redirectionListFragment.addItem(); + } + break; + } + } +} diff --git a/app/src/main/java/org/adaway/ui/lists/ListsViewCallback.java b/app/src/main/java/org/adaway/ui/lists/ListsViewCallback.java new file mode 100644 index 0000000..879c1ed --- /dev/null +++ b/app/src/main/java/org/adaway/ui/lists/ListsViewCallback.java @@ -0,0 +1,36 @@ +package org.adaway.ui.lists; + +import android.view.View; + +import org.adaway.db.entity.HostListItem; +import org.adaway.ui.lists.type.AbstractListFragment; + +/** + * This class is represents the {@link AbstractListFragment} callback. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public interface ListsViewCallback { + /** + * Toggle item enable status. + * + * @param item The list to toggle status. + */ + void toggleItemEnabled(HostListItem item); + + /** + * Start an action. + * + * @param item The list to start the action. + * @param sourceView The list related view. + * @return true if the action was started, false otherwise. + */ + boolean startAction(HostListItem item, View sourceView); + + /** + * Copy an hosts into clipboard. + * + * @param item The list to copy hosts. + */ + boolean copyHostToClipboard(HostListItem item); +} diff --git a/app/src/main/java/org/adaway/ui/lists/ListsViewModel.java b/app/src/main/java/org/adaway/ui/lists/ListsViewModel.java new file mode 100644 index 0000000..1d843a8 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/lists/ListsViewModel.java @@ -0,0 +1,160 @@ +package org.adaway.ui.lists; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.paging.Pager; +import androidx.paging.PagingConfig; +import androidx.paging.PagingData; + +import org.adaway.db.AppDatabase; +import org.adaway.db.dao.HostListItemDao; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.ListType; +import org.adaway.ui.lists.type.AbstractListFragment; +import org.adaway.util.AppExecutors; + +import java.util.Optional; +import java.util.concurrent.Executor; + +import static androidx.lifecycle.Transformations.switchMap; +import static androidx.paging.PagingLiveData.getLiveData; +import static org.adaway.db.entity.HostsSource.USER_SOURCE_ID; +import static org.adaway.db.entity.ListType.ALLOWED; +import static org.adaway.db.entity.ListType.BLOCKED; +import static org.adaway.db.entity.ListType.REDIRECTED; +import static org.adaway.ui.lists.ListsFilter.ALL; + +/** + * This class is an {@link AndroidViewModel} for the {@link AbstractListFragment} implementations. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class ListsViewModel extends AndroidViewModel { + private static final Executor EXECUTOR = AppExecutors.getInstance().diskIO(); + private final HostListItemDao hostListItemDao; + private final MutableLiveData filter; + private final LiveData> blockedListItems; + private final LiveData> allowedListItems; + private final LiveData> redirectedListItems; + private final MutableLiveData modelChanged; + + public ListsViewModel(@NonNull Application application) { + super(application); + this.hostListItemDao = AppDatabase.getInstance(application).hostsListItemDao(); + this.filter = new MutableLiveData<>(ALL); + PagingConfig pagingConfig = new PagingConfig(50, 150, true); + this.blockedListItems = switchMap( + this.filter, + filter -> getLiveData(new Pager<>(pagingConfig, () -> + this.hostListItemDao.loadList(BLOCKED.getValue(), filter.sourcesIncluded, filter.sqlQuery) + )) + ); + this.allowedListItems = switchMap( + this.filter, + filter -> getLiveData(new Pager<>(pagingConfig, () -> + this.hostListItemDao.loadList(ALLOWED.getValue(), filter.sourcesIncluded, filter.sqlQuery) + )) + ); + this.redirectedListItems = switchMap( + this.filter, + filter -> getLiveData(new Pager<>(pagingConfig, () -> + this.hostListItemDao.loadList(REDIRECTED.getValue(), filter.sourcesIncluded, filter.sqlQuery) + )) + ); + this.modelChanged = new MutableLiveData<>(false); + } + + public LiveData> getBlockedListItems() { + return this.blockedListItems; + } + + public LiveData> getAllowedListItems() { + return this.allowedListItems; + } + + public LiveData> getRedirectedListItems() { + return this.redirectedListItems; + } + + public LiveData getModelChanged() { + return this.modelChanged; + } + + public void toggleItemEnabled(HostListItem item) { + item.setEnabled(!item.isEnabled()); + EXECUTOR.execute(() -> { + this.hostListItemDao.update(item); + this.modelChanged.postValue(true); + }); + } + + public void addListItem(@NonNull ListType type, @NonNull String host, String redirection) { + HostListItem item = new HostListItem(); + item.setType(type); + item.setHost(host); + item.setRedirection(redirection); + item.setEnabled(true); + item.setSourceId(USER_SOURCE_ID); + EXECUTOR.execute(() -> { + Optional id = this.hostListItemDao.getHostId(host); + if (id.isPresent()) { + item.setId(id.get()); + this.hostListItemDao.update(item); + } else { + this.hostListItemDao.insert(item); + } + this.modelChanged.postValue(true); + }); + } + + public void updateListItem(@NonNull HostListItem item, @NonNull String host, String redirection) { + item.setHost(host); + item.setRedirection(redirection); + EXECUTOR.execute(() -> { + this.hostListItemDao.update(item); + this.modelChanged.postValue(true); + }); + } + + public void removeListItem(HostListItem list) { + EXECUTOR.execute(() -> { + this.hostListItemDao.delete(list); + this.modelChanged.postValue(true); + }); + } + + public void search(String query) { + ListsFilter currentFilter = getFilter(); + ListsFilter newFilter = new ListsFilter(currentFilter.sourcesIncluded, query); + setFilter(newFilter); + } + + public boolean isSearching() { + return !getFilter().query.isEmpty(); + } + + public void clearSearch() { + ListsFilter currentFilter = getFilter(); + ListsFilter newFilter = new ListsFilter(currentFilter.sourcesIncluded, ""); + setFilter(newFilter); + } + + public void toggleSources() { + ListsFilter currentFilter = getFilter(); + ListsFilter newFilter = new ListsFilter(!currentFilter.sourcesIncluded, currentFilter.query); + setFilter(newFilter); + } + + private ListsFilter getFilter() { + ListsFilter filter = this.filter.getValue(); + return filter == null ? ALL : filter; + } + + private void setFilter(ListsFilter filter) { + this.filter.setValue(filter); + } +} diff --git a/app/src/main/java/org/adaway/ui/lists/type/AbstractListFragment.java b/app/src/main/java/org/adaway/ui/lists/type/AbstractListFragment.java new file mode 100644 index 0000000..5be0363 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/lists/type/AbstractListFragment.java @@ -0,0 +1,203 @@ +package org.adaway.ui.lists.type; + +import android.graphics.Color; +import android.os.Bundle; +import android.view.ActionMode; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.ViewModelProvider; +import androidx.paging.PagingData; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.adaway.R; +import org.adaway.db.entity.HostListItem; +import org.adaway.ui.lists.ListsViewCallback; +import org.adaway.ui.lists.ListsViewModel; +import org.adaway.util.Clipboard; + +/** + * This class is a {@link Fragment} to display and manage lists of {@link org.adaway.ui.lists.ListsActivity}. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public abstract class AbstractListFragment extends Fragment implements ListsViewCallback { + /** + * The view model (null if view is not created). + */ + protected ListsViewModel mViewModel; + /** + * The current activity (null if view is not created). + */ + protected FragmentActivity mActivity; + /** + * The current action mode when item is selection (null if no action started). + */ + private ActionMode mActionMode; + /** + * The action mode callback (null if view is not created). + */ + private ActionMode.Callback mActionCallback; + /** + * The hosts list related to the current action (null if view is not created). + */ + private HostListItem mActionItem; + /** + * The view related hosts source of the current action (null if view is not created). + */ + private View mActionSourceView; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + // Store activity + this.mActivity = requireActivity(); + // Create fragment view + View view = inflater.inflate(R.layout.hosts_lists_fragment, container, false); + /* + * Configure recycler view. + */ + // Store recycler view + RecyclerView recyclerView = view.findViewById(R.id.hosts_lists_list); + recyclerView.setHasFixedSize(true); + // Defile recycler layout + LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this.mActivity); + recyclerView.setLayoutManager(linearLayoutManager); + // Create recycler adapter + ListsAdapter adapter = new ListsAdapter(this, isTwoRowsItem()); + recyclerView.setAdapter(adapter); + /* + * Create action mode. + */ + // Create action mode callback to display edit/delete menu + this.mActionCallback = new ActionMode.Callback() { + @Override + public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { + // Get menu inflater + MenuInflater inflater = actionMode.getMenuInflater(); + // Set action mode title + actionMode.setTitle(R.string.checkbox_list_context_title); + // Inflate edit/delete menu + inflater.inflate(R.menu.checkbox_list_context, menu); + // Return action created + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { + // Nothing special to do + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode actionMode, MenuItem item) { + // Check action item + if (mActionItem == null) { + return false; + } + // Check item identifier + if (item.getItemId() == R.id.edit_action) { + // Edit action item + editItem(mActionItem); + // Finish action mode + mActionMode.finish(); + return true; + } else if (item.getItemId() == R.id.delete_action) { + // Delete action item + deleteItem(mActionItem); + // Finish action mode + mActionMode.finish(); + return true; + } else { + return false; + } + } + + @Override + public void onDestroyActionMode(ActionMode actionMode) { + // Clear view background color + if (mActionSourceView != null) { + mActionSourceView.setBackgroundColor(Color.TRANSPARENT); + } + // Clear current source and its view + mActionItem = null; + mActionSourceView = null; + // Clear action mode + mActionMode = null; + } + }; + /* + * Load data. + */ + // Get view model and bind it to the list view + this.mViewModel = new ViewModelProvider(this.mActivity).get(ListsViewModel.class); + getData().observe(getViewLifecycleOwner(), data -> adapter.submitData(getLifecycle(), data)); + // Return created view + return view; + } + + @Override + public boolean startAction(HostListItem item, View sourceView) { + // Check if there is already a current action + if (this.mActionMode != null) { + return false; + } + // Store current source and its view + this.mActionItem = item; + this.mActionSourceView = sourceView; + // Get current item background color + int currentItemBackgroundColor = getResources().getColor(R.color.selected_background, null); + // Apply background color to view + this.mActionSourceView.setBackgroundColor(currentItemBackgroundColor); + // Start action mode and store it + this.mActionMode = this.mActivity.startActionMode(this.mActionCallback); + // Return event consumed + return true; + } + + @Override + public boolean copyHostToClipboard(HostListItem item) { + Clipboard.copyHostToClipboard(this.mActivity, item.getHost()); + return true; + } + + /** + * Ensure action mode is cancelled. + */ + public void ensureActionModeCanceled() { + if (this.mActionMode != null) { + this.mActionMode.finish(); + } + } + + protected abstract LiveData> getData(); + + protected boolean isTwoRowsItem() { + return false; + } + + /** + * Display a UI to add an item to the list. + */ + public abstract void addItem(); + + protected abstract void editItem(HostListItem item); + + protected void deleteItem(HostListItem item) { + this.mViewModel.removeListItem(item); + } + + @Override + public void toggleItemEnabled(HostListItem item) { + this.mViewModel.toggleItemEnabled(item); + } +} diff --git a/app/src/main/java/org/adaway/ui/lists/type/AllowedHostsFragment.java b/app/src/main/java/org/adaway/ui/lists/type/AllowedHostsFragment.java new file mode 100644 index 0000000..c5f89cf --- /dev/null +++ b/app/src/main/java/org/adaway/ui/lists/type/AllowedHostsFragment.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.ui.lists.type; + + +import android.text.Editable; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; + +import androidx.appcompat.app.AlertDialog; +import androidx.lifecycle.LiveData; +import androidx.paging.PagingData; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +import org.adaway.R; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.ListType; +import org.adaway.ui.dialog.AlertDialogValidator; +import org.adaway.util.RegexUtils; + +/** + * This class is a {@link AbstractListFragment} to display and manage allowed hosts. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class AllowedHostsFragment extends AbstractListFragment { + @Override + protected LiveData> getData() { + return this.mViewModel.getAllowedListItems(); + } + + @Override + public void addItem() { + // Create dialog view + LayoutInflater factory = LayoutInflater.from(this.mActivity); + View view = factory.inflate(R.layout.lists_allowed_dialog, null); + EditText inputEditText = view.findViewById(R.id.list_dialog_hostname); + // Create dialog + AlertDialog alertDialog = new MaterialAlertDialogBuilder(this.mActivity) + .setCancelable(true) + .setTitle(R.string.list_add_dialog_white) + .setView(view) + // Setup buttons + .setPositiveButton( + R.string.button_add, + (dialog, which) -> { + // Close dialog + dialog.dismiss(); + // Check hostname validity + String hostname = inputEditText.getText().toString(); + if (RegexUtils.isValidWildcardHostname(hostname)) { + // Insert host to whitelist + this.mViewModel.addListItem(ListType.ALLOWED, hostname, null); + } + } + ) + .setNegativeButton( + R.string.button_cancel, + (dialog, which) -> dialog.dismiss() + ) + .create(); + // Show dialog + alertDialog.show(); + // Set button validation behavior + inputEditText.addTextChangedListener( + new AlertDialogValidator(alertDialog, RegexUtils::isValidWildcardHostname, false) + ); + } + + @Override + protected void editItem(HostListItem item) { + // Create dialog view + LayoutInflater factory = LayoutInflater.from(this.mActivity); + View view = factory.inflate(R.layout.lists_allowed_dialog, null); + // Set hostname + EditText inputEditText = view.findViewById(R.id.list_dialog_hostname); + inputEditText.setText(item.getHost()); + // Move cursor to end of EditText + Editable inputEditContent = inputEditText.getText(); + inputEditText.setSelection(inputEditContent.length()); + // Create dialog builder + AlertDialog alertDialog = new MaterialAlertDialogBuilder(this.mActivity) + .setCancelable(true) + .setTitle(R.string.list_edit_dialog_white) + .setView(view) + // Setup buttons + .setPositiveButton( + R.string.button_save, + (dialog, which) -> { + // Close dialog + dialog.dismiss(); + // Check hostname validity + String hostname = inputEditText.getText().toString(); + if (RegexUtils.isValidWildcardHostname(hostname)) { + // Update list item + this.mViewModel.updateListItem(item, hostname, null); + } + } + ) + .setNegativeButton( + R.string.button_cancel, + (dialog, which) -> dialog.dismiss() + ) + .create(); + // Show dialog + alertDialog.show(); + // Set button validation behavior + inputEditText.addTextChangedListener( + new AlertDialogValidator(alertDialog, RegexUtils::isValidWildcardHostname, true) + ); + } +} diff --git a/app/src/main/java/org/adaway/ui/lists/type/BlockedHostsFragment.java b/app/src/main/java/org/adaway/ui/lists/type/BlockedHostsFragment.java new file mode 100644 index 0000000..f37cdc5 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/lists/type/BlockedHostsFragment.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.ui.lists.type; + + +import android.text.Editable; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; + +import androidx.appcompat.app.AlertDialog; +import androidx.lifecycle.LiveData; +import androidx.paging.PagingData; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +import org.adaway.R; +import org.adaway.db.entity.HostListItem; +import org.adaway.ui.dialog.AlertDialogValidator; +import org.adaway.util.RegexUtils; + +import static org.adaway.db.entity.ListType.BLOCKED; + +/** + * This class is a {@link AbstractListFragment} to display and manage blocked hosts. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class BlockedHostsFragment extends AbstractListFragment { + @Override + protected LiveData> getData() { + return this.mViewModel.getBlockedListItems(); + } + + @Override + public void addItem() { + // Create dialog view + LayoutInflater factory = LayoutInflater.from(this.mActivity); + View view = factory.inflate(R.layout.lists_blocked_dialog, null); + EditText inputEditText = view.findViewById(R.id.list_dialog_hostname); + // Create dialog + AlertDialog alertDialog = new MaterialAlertDialogBuilder(this.mActivity) + .setCancelable(true) + .setTitle(R.string.list_add_dialog_black) + .setView(view) + // Setup buttons + .setPositiveButton( + R.string.button_add, + (dialog, which) -> { + // Close dialog + dialog.dismiss(); + // Check if hostname is valid + String hostname = inputEditText.getText().toString(); + if (RegexUtils.isValidHostname(hostname)) { + // Insert host to black list + this.mViewModel.addListItem(BLOCKED, hostname, null); + } + }) + .setNegativeButton( + R.string.button_cancel, + (dialog, which) -> dialog.dismiss() + ) + .create(); + // Show dialog + alertDialog.show(); + // Set button validation behavior + inputEditText.addTextChangedListener( + new AlertDialogValidator(alertDialog, RegexUtils::isValidHostname, false) + ); + } + + @Override + protected void editItem(HostListItem item) { + // Create dialog view + LayoutInflater factory = LayoutInflater.from(this.mActivity); + View view = factory.inflate(R.layout.lists_blocked_dialog, null); + // Set hostname + EditText inputEditText = view.findViewById(R.id.list_dialog_hostname); + inputEditText.setText(item.getHost()); + // Move cursor to end of EditText + Editable inputEditContent = inputEditText.getText(); + inputEditText.setSelection(inputEditContent.length()); + // Create dialog + AlertDialog alertDialog = new MaterialAlertDialogBuilder(this.mActivity) + .setCancelable(true) + .setTitle(R.string.list_edit_dialog_black) + .setView(view) + // Setup buttons + .setPositiveButton( + R.string.button_save, + (dialog, which) -> { + // Close dialog + dialog.dismiss(); + // Check hostname validity + String hostname = inputEditText.getText().toString(); + if (RegexUtils.isValidHostname(hostname)) { + // Update list item + this.mViewModel.updateListItem(item, hostname, null); + } + }) + .setNegativeButton( + R.string.button_cancel + , (dialog, which) -> dialog.dismiss() + ) + .create(); + // Show dialog + alertDialog.show(); + // Set button validation behavior + inputEditText.addTextChangedListener( + new AlertDialogValidator(alertDialog, RegexUtils::isValidHostname, true) + ); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/adaway/ui/lists/type/ListsAdapter.java b/app/src/main/java/org/adaway/ui/lists/type/ListsAdapter.java new file mode 100644 index 0000000..472b996 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/lists/type/ListsAdapter.java @@ -0,0 +1,131 @@ +package org.adaway.ui.lists.type; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.paging.PagingDataAdapter; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.RecyclerView; + +import org.adaway.R; +import org.adaway.db.entity.HostListItem; +import org.adaway.ui.lists.ListsViewCallback; + +import static org.adaway.db.entity.HostsSource.USER_SOURCE_ID; + +/** + * This class is a the {@link RecyclerView.Adapter} for the hosts list view. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class ListsAdapter extends PagingDataAdapter { + /** + * This callback is use to compare hosts sources. + */ + private static final DiffUtil.ItemCallback DIFF_CALLBACK = + new DiffUtil.ItemCallback() { + @Override + public boolean areItemsTheSame(@NonNull HostListItem oldItem, @NonNull HostListItem newItem) { + return (oldItem.getHost().equals(newItem.getHost())); + } + + @Override + public boolean areContentsTheSame(@NonNull HostListItem oldItem, @NonNull HostListItem newItem) { + // NOTE: if you use equals, your object must properly override Object#equals() + // Incorrectly returning false here will result in too many animations. + return oldItem.equals(newItem); + } + }; + + /** + * This callback is use to call view actions. + */ + @NonNull + private final ListsViewCallback viewCallback; + /** + * Whether the list item needs two rows or not. + */ + private final boolean twoRows; + + /** + * Constructor. + * + * @param viewCallback The view callback. + * @param twoRows Whether the list items need two rows or not. + */ + ListsAdapter(@NonNull ListsViewCallback viewCallback, boolean twoRows) { + super(DIFF_CALLBACK); + this.viewCallback = viewCallback; + this.twoRows = twoRows; + } + + @NonNull + @Override + public ListsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); + View view = layoutInflater.inflate( + this.twoRows ? R.layout.checkbox_list_two_entries : R.layout.checkbox_list_entry, + parent, + false + ); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + HostListItem item = getItem(position); + if (item == null) { // Data might be null if not loaded yet + holder.clear(); + return; + } + boolean editable = item.getSourceId() == USER_SOURCE_ID; + holder.enabledCheckBox.setEnabled(editable); + holder.enabledCheckBox.setChecked(item.isEnabled()); + holder.enabledCheckBox.setOnClickListener(editable ? view -> this.viewCallback.toggleItemEnabled(item) : null); + holder.hostTextView.setText(item.getHost()); + if (this.twoRows) { + holder.redirectionTextView.setText(item.getRedirection()); + } + holder.itemView.setOnLongClickListener(editable ? + view -> this.viewCallback.startAction(item, holder.itemView) : + view -> this.viewCallback.copyHostToClipboard(item)); + } + + /** + * This class is a the {@link RecyclerView.ViewHolder} for the hosts list view. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ + static class ViewHolder extends RecyclerView.ViewHolder { + final CheckBox enabledCheckBox; + final TextView hostTextView; + final TextView redirectionTextView; + + /** + * Constructor. + * + * @param itemView The hosts sources view. + */ + ViewHolder(View itemView) { + super(itemView); + this.enabledCheckBox = itemView.findViewById(R.id.checkbox_list_checkbox); + this.hostTextView = itemView.findViewById(R.id.checkbox_list_text); + this.redirectionTextView = itemView.findViewById(R.id.checkbox_list_subtext); + } + + void clear() { + this.enabledCheckBox.setChecked(true); + this.enabledCheckBox.setEnabled(false); + this.enabledCheckBox.setOnClickListener(null); + this.hostTextView.setText(""); + if (this.redirectionTextView != null) { + this.redirectionTextView.setText(""); + } + this.itemView.setOnLongClickListener(null); + } + } +} diff --git a/app/src/main/java/org/adaway/ui/lists/type/RedirectedHostsFragment.java b/app/src/main/java/org/adaway/ui/lists/type/RedirectedHostsFragment.java new file mode 100644 index 0000000..4261195 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/lists/type/RedirectedHostsFragment.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.ui.lists.type; + +import android.text.Editable; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; + +import androidx.appcompat.app.AlertDialog; +import androidx.lifecycle.LiveData; +import androidx.paging.PagingData; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +import org.adaway.R; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.ListType; +import org.adaway.ui.dialog.AlertDialogValidator; +import org.adaway.util.RegexUtils; + +/** + * This class is a {@link AbstractListFragment} to display and manage redirected hosts. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class RedirectedHostsFragment extends AbstractListFragment { + @Override + protected boolean isTwoRowsItem() { + return true; + } + + @Override + protected LiveData> getData() { + return this.mViewModel.getRedirectedListItems(); + } + + @Override + public void addItem() { + // Create dialog view + LayoutInflater factory = LayoutInflater.from(this.mActivity); + View view = factory.inflate(R.layout.lists_redirected_dialog, null); + EditText hostnameEditText = view.findViewById(R.id.list_dialog_hostname); + EditText ipEditText = view.findViewById(R.id.list_dialog_ip); + // Create dialog + AlertDialog alertDialog = new MaterialAlertDialogBuilder(this.mActivity) + .setCancelable(true) + .setTitle(R.string.list_add_dialog_redirect) + .setView(view) + // Setup buttons + .setPositiveButton( + R.string.button_add, + (dialog, which) -> { + // Close dialog + dialog.dismiss(); + // Check if hostname and IP are valid + String hostname = hostnameEditText.getText().toString(); + String ip = ipEditText.getText().toString(); + if (RegexUtils.isValidHostname(hostname) && RegexUtils.isValidIP(ip)) { + // Insert host to redirection list + this.mViewModel.addListItem(ListType.REDIRECTED, hostname, ip); + } + } + ) + .setNegativeButton( + R.string.button_cancel, + (dialog, which) -> dialog.dismiss() + ) + .create(); + // Show dialog + alertDialog.show(); + // Set button validation behavior + AlertDialogValidator validator = new AlertDialogValidator( + alertDialog, + input -> { + String hostname = hostnameEditText.getText().toString(); + String ip = ipEditText.getText().toString(); + return RegexUtils.isValidHostname(hostname) && RegexUtils.isValidIP(ip); + }, + false + ); + hostnameEditText.addTextChangedListener(validator); + ipEditText.addTextChangedListener(validator); + } + + @Override + protected void editItem(HostListItem item) { + // Create dialog view + LayoutInflater factory = LayoutInflater.from(this.mActivity); + View view = factory.inflate(R.layout.lists_redirected_dialog, null); + // Set hostname and IP + EditText hostnameEditText = view.findViewById(R.id.list_dialog_hostname); + EditText ipEditText = view.findViewById(R.id.list_dialog_ip); + hostnameEditText.setText(item.getHost()); + ipEditText.setText(item.getRedirection()); + // Move cursor to end of EditText + Editable hostnameEditContent = hostnameEditText.getText(); + hostnameEditText.setSelection(hostnameEditContent.length()); + // Create dialog + AlertDialog alertDialog = new MaterialAlertDialogBuilder(this.mActivity) + .setCancelable(true) + .setTitle(getString(R.string.list_edit_dialog_redirect)) + .setView(view) + // Set buttons + .setPositiveButton(R.string.button_save, + (dialog, which) -> { + // Close dialog + dialog.dismiss(); + // Check hostname and IP validity + String hostname = hostnameEditText.getText().toString(); + String ip = ipEditText.getText().toString(); + if (RegexUtils.isValidHostname(hostname) && RegexUtils.isValidIP(ip)) { + // Update list item + this.mViewModel.updateListItem(item, hostname, ip); + } + } + ) + .setNegativeButton( + R.string.button_cancel, + (dialog, which) -> dialog.dismiss() + ) + .create(); + // Show dialog + alertDialog.show(); + // Set button validation behavior + AlertDialogValidator validator = new AlertDialogValidator( + alertDialog, + input -> { + String hostname = hostnameEditText.getText().toString(); + String ip = ipEditText.getText().toString(); + return RegexUtils.isValidHostname(hostname) && RegexUtils.isValidIP(ip); + }, + true + ); + hostnameEditText.addTextChangedListener(validator); + ipEditText.addTextChangedListener(validator); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/adaway/ui/log/LogActivity.java b/app/src/main/java/org/adaway/ui/log/LogActivity.java new file mode 100644 index 0000000..37a1c23 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/log/LogActivity.java @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.ui.log; + +import static org.adaway.ui.Animations.hideView; +import static org.adaway.ui.Animations.showView; +import static java.lang.Boolean.TRUE; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +import org.adaway.R; +import org.adaway.databinding.LogActivityBinding; +import org.adaway.databinding.LogRedirectDialogBinding; +import org.adaway.db.entity.ListType; +import org.adaway.helper.ThemeHelper; +import org.adaway.ui.adblocking.ApplyConfigurationSnackbar; +import org.adaway.ui.dialog.AlertDialogValidator; +import org.adaway.util.Clipboard; +import org.adaway.util.RegexUtils; + +/** + * This class is an {@link android.app.Activity} to show DNS request log entries. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class LogActivity extends AppCompatActivity implements LogViewCallback { + private LogActivityBinding binding; + /** + * The view model (null if activity is not created). + */ + private LogViewModel mViewModel; + /** + * The snackbar notification (null if activity is not created). + */ + private ApplyConfigurationSnackbar mApplySnackbar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + /* + * Create activity. + */ + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + this.binding = LogActivityBinding.inflate(getLayoutInflater()); + setContentView(this.binding.getRoot()); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + } + // Get view model + this.mViewModel = new ViewModelProvider(this).get(LogViewModel.class); + /* + * Configure swipe layout. + */ + this.binding.swipeRefresh.setOnRefreshListener(this.mViewModel::updateLogs); + /* + * Configure empty view. + */ + if (this.mViewModel.areBlockedRequestsIgnored()) { + this.binding.emptyTextView.append(getString(R.string.log_blocked_requests_ignored)); + } + /* + * Configure recycler view. + */ + // Get recycler view + this.binding.logList.setHasFixedSize(true); + // Defile recycler layout + LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); + this.binding.logList.setLayoutManager(linearLayoutManager); + // Create recycler adapter + LogAdapter adapter = new LogAdapter(this); + this.binding.logList.setAdapter(adapter); + /* + * Configure fab. + */ + this.binding.toggleLogRecording.setOnClickListener(v -> this.mViewModel.toggleRecording()); + this.mViewModel.isRecording().observe(this, recoding -> + this.binding.toggleLogRecording.setImageResource(TRUE.equals(recoding) ? + R.drawable.ic_pause_24dp : + R.drawable.ic_record_24dp + ) + ); + /* + * Configure snackbar. + */ + // Create apply snackbar + this.mApplySnackbar = new ApplyConfigurationSnackbar(this.binding.swipeRefresh, false, false); + /* + * Load data. + */ + // Bind view model to the list view + this.mViewModel.getLogs().observe(this, logEntries -> { + if (logEntries.isEmpty()) { + showView(this.binding.emptyTextView); + } else { + hideView(this.binding.emptyTextView); + } + adapter.submitList(logEntries); + this.binding.swipeRefresh.setRefreshing(false); + }); + } + + @Override + protected void onResume() { + super.onResume(); + // Mark as loading data + this.binding.swipeRefresh.setRefreshing(true); + // Load initial data + this.mViewModel.updateLogs(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater menuInflater = getMenuInflater(); + menuInflater.inflate(R.menu.log_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.sort) { + this.mViewModel.toggleSort(); + return true; + } else if (item.getItemId() == R.id.delete) { + this.mViewModel.clearLogs(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void addListItem(@NonNull String hostName, @NonNull ListType type) { + // Check view model and snackbar notification + if (this.mViewModel == null || this.mApplySnackbar == null) { + return; + } + // Check type other than redirection + if (type != ListType.REDIRECTED) { + // Insert list item + this.mViewModel.addListItem(hostName, type, null); + // Display snackbar notification + this.mApplySnackbar.notifyUpdateAvailable(); + } else { + // Create dialog view + LayoutInflater inflater = LayoutInflater.from(this); + LogRedirectDialogBinding redirectBinding = LogRedirectDialogBinding.inflate(inflater); + // Create dialog + AlertDialog alertDialog = new MaterialAlertDialogBuilder(this) + .setCancelable(true) + .setTitle(R.string.log_redirect_dialog_title) + .setView(redirectBinding.getRoot()) + // Setup buttons + .setPositiveButton( + R.string.button_add, + (dialog, which) -> { + // Close dialog + dialog.dismiss(); + // Check IP is valid + String ip = redirectBinding.redirectIp.getText().toString(); + if (RegexUtils.isValidIP(ip)) { + // Insert list item + this.mViewModel.addListItem(hostName, type, ip); + // Display snackbar notification + this.mApplySnackbar.notifyUpdateAvailable(); + } + } + ) + .setNegativeButton( + R.string.button_cancel, + (dialog, which) -> dialog.dismiss() + ) + .create(); + // Show dialog + alertDialog.show(); + // Set button validation behavior + redirectBinding.redirectIp.addTextChangedListener( + new AlertDialogValidator(alertDialog, RegexUtils::isValidIP, false) + ); + } + } + + @Override + public void removeListItem(@NonNull String hostName) { + if (this.mViewModel != null && this.mApplySnackbar != null) { + this.mViewModel.removeListItem(hostName); + this.mApplySnackbar.notifyUpdateAvailable(); + } + } + + @Override + public void openHostInBrowser(@NonNull String hostName) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("http://" + hostName)); + startActivity(intent); + } + + @Override + public void copyHostToClipboard(@NonNull String hostName) { + Clipboard.copyHostToClipboard(this, hostName); + } +} diff --git a/app/src/main/java/org/adaway/ui/log/LogAdapter.java b/app/src/main/java/org/adaway/ui/log/LogAdapter.java new file mode 100644 index 0000000..38fcc7e --- /dev/null +++ b/app/src/main/java/org/adaway/ui/log/LogAdapter.java @@ -0,0 +1,107 @@ +package org.adaway.ui.log; + +import static android.graphics.PorterDuff.Mode.MULTIPLY; +import static org.adaway.db.entity.ListType.ALLOWED; +import static org.adaway.db.entity.ListType.BLOCKED; +import static org.adaway.db.entity.ListType.REDIRECTED; + +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.ListAdapter; +import androidx.recyclerview.widget.RecyclerView; + +import org.adaway.R; +import org.adaway.databinding.LogEntryBinding; +import org.adaway.db.entity.ListType; + +/** + * This class is a the {@link RecyclerView.Adapter} for the DNS request log view. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class LogAdapter extends ListAdapter { + /** + * This callback is use to compare hosts sources. + */ + private static final DiffUtil.ItemCallback DIFF_CALLBACK = + new DiffUtil.ItemCallback() { + @Override + public boolean areItemsTheSame(@NonNull LogEntry oldEntry, @NonNull LogEntry newEntry) { + return oldEntry.getHost().equals(newEntry.getHost()); + } + + @Override + public boolean areContentsTheSame(@NonNull LogEntry oldEntry, @NonNull LogEntry newEntry) { + return oldEntry.equals(newEntry); + } + }; + + /** + * The activity view callback. + */ + private final LogViewCallback callback; + + LogAdapter(LogViewCallback callback) { + super(DIFF_CALLBACK); + this.callback = callback; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); + LogEntryBinding binding = LogEntryBinding.inflate(layoutInflater, parent, false); + return new ViewHolder(binding); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + // Get log entry + LogEntry entry = getItem(position); + // Set host name + holder.binding.hostnameTextView.setText(entry.getHost()); + holder.binding.hostnameTextView.setOnClickListener(v -> this.callback.openHostInBrowser(entry.getHost())); + holder.binding.hostnameTextView.setOnLongClickListener(v -> { + this.callback.copyHostToClipboard(entry.getHost()); + return true; + }); + // Set type status + bindImageView(holder.binding.blockImageView, BLOCKED, entry); + bindImageView(holder.binding.allowImageView, ALLOWED, entry); + bindImageView(holder.binding.redirectionImageView, REDIRECTED, entry); + } + + private void bindImageView(ImageView imageView, ListType type, LogEntry entry) { + if (type == entry.getType()) { + int primaryColor = this.callback.getColor(R.color.primary); + imageView.setColorFilter(primaryColor, MULTIPLY); + imageView.setOnClickListener(v -> this.callback.removeListItem(entry.getHost())); + } else { + imageView.clearColorFilter(); + imageView.setOnClickListener(v -> this.callback.addListItem(entry.getHost(), type)); + } + } + + /** + * This class is a the {@link RecyclerView.ViewHolder} for the log entry view. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ + static class ViewHolder extends RecyclerView.ViewHolder { + final org.adaway.databinding.LogEntryBinding binding; + + /** + * Constructor. + * + * @param binding The log entry view binding. + */ + ViewHolder(LogEntryBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } +} diff --git a/app/src/main/java/org/adaway/ui/log/LogEntry.java b/app/src/main/java/org/adaway/ui/log/LogEntry.java new file mode 100644 index 0000000..a27e3d6 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/log/LogEntry.java @@ -0,0 +1,61 @@ +package org.adaway.ui.log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.adaway.db.entity.ListType; + +/** + * This class represents a DNS request log entry. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class LogEntry implements Comparable { + @NonNull + private final String host; + + @Nullable + private ListType type; + + LogEntry(@NonNull String host, @Nullable ListType type) { + this.host = host; + this.type = type; + } + + @NonNull + public String getHost() { + return this.host; + } + + @Nullable + public ListType getType() { + return this.type; + } + + public void setType(@Nullable ListType type) { + this.type = type; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LogEntry that = (LogEntry) o; + + if (!host.equals(that.host)) return false; + return type == that.type; + } + + @Override + public int hashCode() { + int result = host.hashCode(); + result = 31 * result + (type != null ? type.hashCode() : 0); + return result; + } + + @Override + public int compareTo(@NonNull LogEntry o) { + return this.host.compareTo(o.host); + } +} diff --git a/app/src/main/java/org/adaway/ui/log/LogEntrySort.java b/app/src/main/java/org/adaway/ui/log/LogEntrySort.java new file mode 100644 index 0000000..f1b7bf4 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/log/LogEntrySort.java @@ -0,0 +1,70 @@ +package org.adaway.ui.log; + +import org.adaway.R; + +import java.util.Comparator; + +/** + * This enumerate represents the kind of sort available for {@link LogEntry}. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +enum LogEntrySort { + ALPHABETICAL { + @Override + int getName() { + return R.string.log_sort_alphabetical; + } + + @Override + Comparator comparator() { + return LogEntry::compareTo; + } + }, + TOP_LEVEL_DOMAIN { + @Override + int getName() { + return R.string.log_sort_top_level_domain; + } + + @Override + Comparator comparator() { + return (entry1, entry2) -> { + String[] split1 = entry1.getHost().split("\\."); + String[] split2 = entry2.getHost().split("\\."); + + int index1 = split1.length - 1; + int index2 = split2.length - 1; + + while (index1 >= 0 && index2 >= 0) { + String part1 = split1[index1]; + String part2 = split2[index2]; + + int partCompare = part1.compareTo(part2); + if (partCompare != 0) { + return partCompare; + } + + index1--; + index2--; + } + + return index1 < 0 ? (index2 < 0 ? 0 : -1) : +1; + }; + } + }; + + /** + * Get the sort name. + * + * @return The sort name resource identifier. + */ + abstract int getName(); + + /** + * Get the sort comparator. + * + * @return The sort comparator. + */ + abstract Comparator comparator(); +} diff --git a/app/src/main/java/org/adaway/ui/log/LogViewCallback.java b/app/src/main/java/org/adaway/ui/log/LogViewCallback.java new file mode 100644 index 0000000..25def66 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/log/LogViewCallback.java @@ -0,0 +1,49 @@ +package org.adaway.ui.log; + +import androidx.annotation.NonNull; + +import org.adaway.db.entity.ListType; + +/** + * This class is represents the {@link LogActivity} callback. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public interface LogViewCallback { + /** + * Add a {@link org.adaway.db.entity.HostListItem}. + * + * @param hostName The item host name. + * @param type The item type. + */ + void addListItem(@NonNull String hostName, @NonNull ListType type); + + /** + * Remove a {@link org.adaway.db.entity.HostListItem} + * + * @param hostName The item host name. + */ + void removeListItem(@NonNull String hostName); + + /** + * Open an host into the user browser. + * + * @param hostName The host name to open. + */ + void openHostInBrowser(@NonNull String hostName); + + /** + * Copy an host into the clipboard. + * + * @param hostName The list to copy hosts. + */ + void copyHostToClipboard(@NonNull String hostName); + + /** + * Get color value from color identifier. + * + * @param colorId The color identifier. + * @return The related color value. + */ + int getColor(int colorId); +} diff --git a/app/src/main/java/org/adaway/ui/log/LogViewModel.java b/app/src/main/java/org/adaway/ui/log/LogViewModel.java new file mode 100644 index 0000000..286fa95 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/log/LogViewModel.java @@ -0,0 +1,151 @@ +package org.adaway.ui.log; + +import android.app.Application; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import org.adaway.AdAwayApplication; +import org.adaway.db.AppDatabase; +import org.adaway.db.dao.HostEntryDao; +import org.adaway.db.dao.HostListItemDao; +import org.adaway.db.entity.HostListItem; +import org.adaway.db.entity.ListType; +import org.adaway.model.adblocking.AdBlockMethod; +import org.adaway.model.adblocking.AdBlockModel; +import org.adaway.util.AppExecutors; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static org.adaway.db.entity.HostsSource.USER_SOURCE_ID; + +/** + * This class is an {@link AndroidViewModel} for the {@link LogActivity}. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class LogViewModel extends AndroidViewModel { + private final AdBlockModel adBlockModel; + private final HostListItemDao hostListItemDao; + private final HostEntryDao hostEntryDao; + private final MutableLiveData> logEntries; + private final MutableLiveData recording; + private LogEntrySort sort; + + public LogViewModel(@NonNull Application application) { + super(application); + this.adBlockModel = ((AdAwayApplication) application).getAdBlockModel(); + this.hostListItemDao = AppDatabase.getInstance(application).hostsListItemDao(); + this.hostEntryDao = AppDatabase.getInstance(application).hostEntryDao(); + this.logEntries = new MutableLiveData<>(); + this.recording = new MutableLiveData<>(this.adBlockModel.isRecordingLogs()); + this.sort = LogEntrySort.TOP_LEVEL_DOMAIN; + } + + public boolean areBlockedRequestsIgnored() { + return this.adBlockModel.getMethod() == AdBlockMethod.ROOT; + } + + public LiveData> getLogs() { + return this.logEntries; + } + + public void clearLogs() { + this.adBlockModel.clearLogs(); + this.logEntries.postValue(Collections.emptyList()); + } + + public void updateLogs() { + AppExecutors.getInstance().diskIO().execute( + () -> { + // Get tcpdump logs + List logItems = this.adBlockModel.getLogs() + .parallelStream() + .map(log -> { + ListType type = this.hostEntryDao.getTypeOfHost(log); + return new LogEntry(log, type); + }) + .sorted(this.sort.comparator()) + .collect(Collectors.toList()); + // Post result + this.logEntries.postValue(logItems); + } + ); + } + + public void toggleSort() { + this.sortDnsRequests(this.sort == LogEntrySort.ALPHABETICAL ? + LogEntrySort.TOP_LEVEL_DOMAIN : + LogEntrySort.ALPHABETICAL + ); + } + + public LiveData isRecording() { + return this.recording; + } + + public void toggleRecording() { + boolean recording = !this.adBlockModel.isRecordingLogs(); + this.adBlockModel.setRecordingLogs(recording); + this.recording.postValue(recording); + } + + public void addListItem(@NonNull String host, @NonNull ListType type, String redirection) { + // Create new host list item + HostListItem item = new HostListItem(); + item.setType(type); + item.setHost(host); + item.setRedirection(redirection); + item.setEnabled(true); + item.setSourceId(USER_SOURCE_ID); + // Insert host list item + AppExecutors.getInstance().diskIO().execute(() -> this.hostListItemDao.insert(item)); + // Update log entries + updateLogEntryType(host, type); + } + + public void removeListItem(@NonNull String host) { + // Delete host list item + AppExecutors.getInstance().diskIO().execute(() -> this.hostListItemDao.deleteUserFromHost(host)); + // Update log entries + updateLogEntryType(host, null); + } + + private void updateLogEntryType(@NonNull String host, ListType type) { + // Get current values + List entries = this.logEntries.getValue(); + if (entries == null) { + return; + } + // Update entry type + List updatedEntries = entries.stream() + .map(entry -> entry.getHost().equals(host) ? new LogEntry(host, type) : entry) + .collect(Collectors.toList()); + // Post new values + this.logEntries.postValue(updatedEntries); + } + + private void sortDnsRequests(LogEntrySort sort) { + // Save current sort + this.sort = sort; + // Apply sort to values + List entries = this.logEntries.getValue(); + if (entries != null) { + List sortedEntries = new ArrayList<>(entries); + sortedEntries.sort(this.sort.comparator()); + this.logEntries.postValue(sortedEntries); + } + // Notify user + Toast.makeText( + getApplication(), + this.sort.getName(), + Toast.LENGTH_SHORT + ).show(); + } +} diff --git a/app/src/main/java/org/adaway/ui/prefs/PrefsActivity.java b/app/src/main/java/org/adaway/ui/prefs/PrefsActivity.java new file mode 100644 index 0000000..769e071 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/prefs/PrefsActivity.java @@ -0,0 +1,96 @@ +package org.adaway.ui.prefs; + +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import org.adaway.R; +import org.adaway.helper.ThemeHelper; + +/** + * This activity is the preferences activity. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class PrefsActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { + static final String PREFERENCE_NOT_FOUND = "preference not found"; + + static void setAppBarTitle(PreferenceFragmentCompat fragment, @StringRes int title) { + FragmentActivity activity = fragment.getActivity(); + if (!(activity instanceof PrefsActivity)) { + return; + } + ActionBar supportActionBar = ((PrefsActivity) activity).getSupportActionBar(); + if (supportActionBar != null) { + supportActionBar.setTitle(title); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + /* + * Set view content. + */ + setContentView(R.layout.prefs_activity); + if (savedInstanceState == null) { + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.settings_container, new PrefsMainFragment()) + .commit(); + } + /* + * Configure actionbar. + */ + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } + } + + @Override + public boolean onSupportNavigateUp() { + if (getSupportFragmentManager().getBackStackEntryCount() > 0) { + getSupportFragmentManager().popBackStack(); + } else { + super.onSupportNavigateUp(); + } + return true; + } + + @Override + public boolean onPreferenceStartFragment(@NonNull PreferenceFragmentCompat caller, Preference pref) { + // Instantiate the new fragment + String fragmentClassName = pref.getFragment(); + if (fragmentClassName == null) { + return false; + } + Fragment fragment = getSupportFragmentManager().getFragmentFactory().instantiate( + getClassLoader(), + fragmentClassName + ); + Bundle args = pref.getExtras(); + fragment.setArguments(args); + // See https://developer.android.com/guide/topics/ui/settings/organize-your-settings#java + //noinspection deprecation + fragment.setTargetFragment(caller, 0); + // Replace the existing Fragment with the new Fragment + getSupportFragmentManager().beginTransaction() + .setCustomAnimations( + R.animator.fragment_open_enter, R.animator.fragment_open_exit, + R.animator.fragment_close_enter, R.animator.fragment_close_exit + ) + .replace(R.id.settings_container, fragment) + .addToBackStack(null) + .commit(); + return true; + } +} diff --git a/app/src/main/java/org/adaway/ui/prefs/PrefsBackupRestoreFragment.java b/app/src/main/java/org/adaway/ui/prefs/PrefsBackupRestoreFragment.java new file mode 100644 index 0000000..af53330 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/prefs/PrefsBackupRestoreFragment.java @@ -0,0 +1,115 @@ +package org.adaway.ui.prefs; + +import static android.content.Intent.CATEGORY_OPENABLE; +import static org.adaway.ui.prefs.PrefsActivity.PREFERENCE_NOT_FOUND; +import static org.adaway.util.Constants.PREFS_NAME; + +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts.CreateDocument; +import androidx.activity.result.contract.ActivityResultContracts.OpenDocument; +import androidx.annotation.NonNull; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import org.adaway.R; +import org.adaway.model.backup.BackupExporter; +import org.adaway.model.backup.BackupImporter; + +/** + * This fragment is the preferences fragment for backup and restore block rules. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class PrefsBackupRestoreFragment extends PreferenceFragmentCompat { + /** + * The backup mime type. + */ + private static final String JSON_MIME_TYPE = "application/json"; + /** + * The default backup file name. + */ + private static final String BACKUP_FILE_NAME = "adaway-backup.json"; + /** + * The launcher to start import backup activity. + */ + private ActivityResultLauncher importActivityLauncher; + /** + * The launcher to start export backup activity. + */ + private ActivityResultLauncher exportActivityLauncher; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + // Configure preferences + getPreferenceManager().setSharedPreferencesName(PREFS_NAME); + addPreferencesFromResource(R.xml.preferences_backup_restore); + // Register for activities + registerForImportActivity(); + registerForExportActivity(); + // Bind pref actions + bindBackupPref(); + bindRestorePref(); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + PrefsActivity.setAppBarTitle(this, R.string.pref_backup_restore_title); + } + + private void registerForImportActivity() { + this.importActivityLauncher = registerForActivityResult(new OpenDocument() { + @NonNull + @Override + public Intent createIntent(@NonNull Context context, @NonNull String[] input) { + return super.createIntent(context, input) + .addCategory(CATEGORY_OPENABLE); + } + }, backupUri -> { + if (backupUri != null) { + BackupImporter.importFromBackup(requireContext(), backupUri); + } + }); + } + + private void registerForExportActivity() { + this.exportActivityLauncher = registerForActivityResult( + new CreateDocument(JSON_MIME_TYPE), + backupUri -> { + if (backupUri != null) { + BackupExporter.exportToBackup(requireContext(), backupUri); + } + }); + } + + private void bindBackupPref() { + Preference backupPreference = findPreference(getString(R.string.pref_backup_key)); + assert backupPreference != null : PREFERENCE_NOT_FOUND; + backupPreference.setOnPreferenceClickListener(preference -> { + this.exportActivityLauncher.launch(BACKUP_FILE_NAME); + return true; + }); + } + + private void bindRestorePref() { + Preference backupPreference = findPreference(getString(R.string.pref_restore_key)); + assert backupPreference != null : PREFERENCE_NOT_FOUND; + backupPreference.setOnPreferenceClickListener(preference -> { + String[] mimeTypes; + if (Build.VERSION.SDK_INT < 28) { + mimeTypes = new String[]{"*/*"}; + } else if (Build.VERSION.SDK_INT < 29) { + mimeTypes = new String[]{JSON_MIME_TYPE, "application/octet-stream"}; + } else { + mimeTypes = new String[]{JSON_MIME_TYPE}; + } + this.importActivityLauncher.launch(mimeTypes); + return true; + }); + } +} diff --git a/app/src/main/java/org/adaway/ui/prefs/PrefsMainFragment.java b/app/src/main/java/org/adaway/ui/prefs/PrefsMainFragment.java new file mode 100644 index 0000000..7ad6997 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/prefs/PrefsMainFragment.java @@ -0,0 +1,81 @@ +package org.adaway.ui.prefs; + +import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import org.adaway.R; +import org.adaway.helper.PreferenceHelper; +import org.adaway.model.adblocking.AdBlockMethod; +import org.adaway.util.log.SentryLog; + +import static org.adaway.model.adblocking.AdBlockMethod.ROOT; +import static org.adaway.model.adblocking.AdBlockMethod.VPN; +import static org.adaway.ui.prefs.PrefsActivity.PREFERENCE_NOT_FOUND; +import static org.adaway.util.Constants.PREFS_NAME; + +/** + * This fragment is the preferences main fragment. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class PrefsMainFragment extends PreferenceFragmentCompat { + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + // Configure preferences + getPreferenceManager().setSharedPreferencesName(PREFS_NAME); + addPreferencesFromResource(R.xml.preferences_main); + // Bind pref actions + bindThemePrefAction(); + bindAdBlockMethod(); + bindTelemetryPrefAction(); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + PrefsActivity.setAppBarTitle(this, R.string.pref_main_title); + } + + @Override + public void onResume() { + super.onResume(); + PrefsActivity.setAppBarTitle(this, R.string.pref_main_title); + } + + private void bindThemePrefAction() { + Preference darkThemePref = findPreference(getString(R.string.pref_dark_theme_mode_key)); + assert darkThemePref != null : PREFERENCE_NOT_FOUND; + darkThemePref.setOnPreferenceChangeListener((preference, newValue) -> { + requireActivity().recreate(); + // Allow preference change + return true; + }); + } + + private void bindAdBlockMethod() { + Preference rootPreference = findPreference(getString(R.string.pref_root_ad_block_method_key)); + assert rootPreference != null : PREFERENCE_NOT_FOUND; + Preference vpnPreference = findPreference(getString(R.string.pref_vpn_ad_block_method_key)); + assert vpnPreference != null : PREFERENCE_NOT_FOUND; + AdBlockMethod adBlockMethod = PreferenceHelper.getAdBlockMethod(requireContext()); + rootPreference.setEnabled(adBlockMethod == ROOT); + vpnPreference.setEnabled(adBlockMethod == VPN); + } + + private void bindTelemetryPrefAction() { + Preference enableTelemetryPref = findPreference(getString(R.string.pref_enable_telemetry_key)); + assert enableTelemetryPref != null : PREFERENCE_NOT_FOUND; + enableTelemetryPref.setOnPreferenceChangeListener((preference, newValue) -> { + SentryLog.setEnabled(requireActivity().getApplication(), (boolean) newValue); + return true; + }); + if (SentryLog.isStub()) { + enableTelemetryPref.setEnabled(false); + enableTelemetryPref.setSummary(R.string.pref_enable_telemetry_disabled_summary); + } + } +} diff --git a/app/src/main/java/org/adaway/ui/prefs/PrefsRootFragment.java b/app/src/main/java/org/adaway/ui/prefs/PrefsRootFragment.java new file mode 100644 index 0000000..923d047 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/prefs/PrefsRootFragment.java @@ -0,0 +1,284 @@ +package org.adaway.ui.prefs; + +import static android.os.Build.VERSION.SDK_INT; +import static android.provider.Settings.ACTION_SECURITY_SETTINGS; +import static android.widget.Toast.LENGTH_SHORT; +import static org.adaway.model.root.MountType.READ_ONLY; +import static org.adaway.model.root.MountType.READ_WRITE; +import static org.adaway.model.root.ShellUtils.isWritable; +import static org.adaway.model.root.ShellUtils.remountPartition; +import static org.adaway.ui.prefs.PrefsActivity.PREFERENCE_NOT_FOUND; +import static org.adaway.util.Constants.ANDROID_SYSTEM_ETC_HOSTS; +import static org.adaway.util.Constants.PREFS_NAME; +import static org.adaway.util.WebServerUtils.TEST_URL; +import static org.adaway.util.WebServerUtils.copyCertificate; +import static org.adaway.util.WebServerUtils.getWebServerState; +import static org.adaway.util.WebServerUtils.installCertificate; +import static org.adaway.util.WebServerUtils.isWebServerRunning; +import static org.adaway.util.WebServerUtils.startWebServer; +import static org.adaway.util.WebServerUtils.stopWebServer; + +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import android.widget.Toast; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; +import androidx.annotation.NonNull; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.SwitchPreferenceCompat; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.common.net.InetAddresses; + +import org.adaway.R; +import org.adaway.helper.PreferenceHelper; +import org.adaway.ui.dialog.MissingAppDialog; +import org.adaway.util.AppExecutors; + +import java.io.File; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; + +import timber.log.Timber; + +/** + * This fragment is the preferences fragment for root ad blocker. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class PrefsRootFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { + /** + * The webserver certificate mime type. + */ + private static final String CERTIFICATE_MIME_TYPE = "application/x-x509-ca-cert"; + /** + * The launcher to start open hosts file activity. + */ + private ActivityResultLauncher openHostsFileLauncher; + /** + * The launcher to prepare web service certificate activity. + */ + private ActivityResultLauncher prepareCertificateLauncher; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + // Configure preferences + getPreferenceManager().setSharedPreferencesName(PREFS_NAME); + addPreferencesFromResource(R.xml.preferences_root); + // Register for activities + registerForOpenHostActivity(); + registerForPrepareCertificateActivity(); + // Bind pref actions + bindOpenHostsFile(); + bindRedirection(); + bindWebServerPrefAction(); + bindWebServerTest(); + bindWebServerCertificate(); + // Update current state + updateWebServerState(); + // Register as listener + getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + PrefsActivity.setAppBarTitle(this, R.string.pref_root_title); + } + + @Override + public void onResume() { + super.onResume(); + // Update current state + updateWebServerState(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + // Unregister as listener + getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + Context context = requireContext(); + // Restart web server on icon change + if (context.getString(R.string.pref_webserver_icon_key).equals(key) && isWebServerRunning()) { + stopWebServer(); + startWebServer(context); + updateWebServerState(); + } + } + + private void registerForOpenHostActivity() { + this.openHostsFileLauncher = registerForActivityResult(new StartActivityForResult(), result -> { + try { + File hostFile = new File(ANDROID_SYSTEM_ETC_HOSTS).getCanonicalFile(); + remountPartition(hostFile, READ_ONLY); + } catch (IOException e) { + Timber.e(e, "Failed to get hosts canonical file."); + } + }); + } + + private void registerForPrepareCertificateActivity() { + this.prepareCertificateLauncher = registerForActivityResult( + new ActivityResultContracts.CreateDocument(CERTIFICATE_MIME_TYPE), + this::prepareWebServerCertificate + ); + } + + private void bindOpenHostsFile() { + Preference openHostsFilePreference = findPreference(getString(R.string.pref_open_hosts_key)); + assert openHostsFilePreference != null : PREFERENCE_NOT_FOUND; + openHostsFilePreference.setOnPreferenceClickListener(this::openHostsFile); + } + + private boolean openHostsFile(Preference preference) { + try { + File hostFile = new File(ANDROID_SYSTEM_ETC_HOSTS).getCanonicalFile(); + boolean remount = !isWritable(hostFile) && remountPartition(hostFile, READ_WRITE); + Intent intent = new Intent() + .setAction(Intent.ACTION_VIEW) + .setDataAndType(Uri.parse("file://" + hostFile.getAbsolutePath()), "text/plain"); + if (remount) { + this.openHostsFileLauncher.launch(intent); + } else { + startActivity(intent); + } + return true; + } catch (IOException e) { + Timber.e(e, "Failed to get hosts canonical file."); + } catch (ActivityNotFoundException e) { + MissingAppDialog.showTextEditorMissingDialog(getContext()); + return false; + } + return false; + } + + private void bindRedirection() { + Context context = requireContext(); + boolean ipv6Enabled = PreferenceHelper.getEnableIpv6(context); + Preference ipv4RedirectionPreference = findPreference(getString(R.string.pref_redirection_ipv4_key)); + assert ipv4RedirectionPreference != null : PREFERENCE_NOT_FOUND; + ipv4RedirectionPreference.setOnPreferenceChangeListener( + (preference, newValue) -> validateRedirection(Inet4Address.class, (String) newValue) + ); + Preference ipv6RedirectionPreference = findPreference(getString(R.string.pref_redirection_ipv6_key)); + assert ipv6RedirectionPreference != null : PREFERENCE_NOT_FOUND; + ipv6RedirectionPreference.setEnabled(ipv6Enabled); + ipv6RedirectionPreference.setOnPreferenceChangeListener( + (preference, newValue) -> validateRedirection(Inet6Address.class, (String) newValue) + ); + } + + private boolean validateRedirection(Class addressType, String redirection) { + boolean valid; + try { + InetAddress inetAddress = InetAddresses.forString(redirection); + valid = addressType.isAssignableFrom(inetAddress.getClass()); + } catch (IllegalArgumentException exception) { + valid = false; + } + if (!valid) { + Toast.makeText(requireContext(), R.string.pref_redirection_invalid, LENGTH_SHORT).show(); + } + return valid; + } + + private void bindWebServerPrefAction() { + Context context = requireContext(); + // Start web server when preference is enabled + SwitchPreferenceCompat webServerEnabledPref = findPreference(getString(R.string.pref_webserver_enabled_key)); + assert webServerEnabledPref != null : PREFERENCE_NOT_FOUND; + webServerEnabledPref.setOnPreferenceChangeListener((preference, newValue) -> { + if (newValue.equals(true)) { + // Start web server + startWebServer(context); + updateWebServerState(); + return isWebServerRunning(); + } else { + // Stop web server + stopWebServer(); + updateWebServerState(); + return !isWebServerRunning(); + } + }); + } + + private void bindWebServerTest() { + Preference webServerTest = findPreference(getString(R.string.pref_webserver_test_key)); + assert webServerTest != null : PREFERENCE_NOT_FOUND; + webServerTest.setOnPreferenceClickListener(preference -> { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(TEST_URL)); + startActivity(intent); + return true; + }); + } + + private void bindWebServerCertificate() { + Preference webServerTest = findPreference(getString(R.string.pref_webserver_certificate_key)); + assert webServerTest != null : PREFERENCE_NOT_FOUND; + webServerTest.setOnPreferenceClickListener(preference -> { + if (SDK_INT < VERSION_CODES.R) { + installCertificate(requireContext()); + } else { + this.prepareCertificateLauncher.launch("adaway-webserver-certificate.crt"); + } + return true; + }); + } + + private void prepareWebServerCertificate(Uri uri) { + // Check user selected document + if (uri == null) { + return; + } + Timber.d("Certificate URI: %s", uri); + copyCertificate(requireActivity(), uri); + new MaterialAlertDialogBuilder(requireContext()) + .setCancelable(true) + .setTitle(R.string.pref_webserver_certificate_dialog_title) + .setMessage(R.string.pref_webserver_certificate_dialog_content) + .setPositiveButton( + R.string.pref_webserver_certificate_dialog_action, + (dialog, which) -> { + dialog.dismiss(); + Intent intent = new Intent(ACTION_SECURITY_SETTINGS); + startActivity(intent); + }) + .create() + .show(); + } + + private void updateWebServerState() { + Preference webServerTest = findPreference(getString(R.string.pref_webserver_test_key)); + assert webServerTest != null : PREFERENCE_NOT_FOUND; + webServerTest.setSummary(R.string.pref_webserver_state_checking); + AppExecutors executors = AppExecutors.getInstance(); + executors.networkIO().execute(() -> { + // Wait for server to start + try { + Thread.sleep(500); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + int summaryResId = getWebServerState(); + executors.mainThread().execute( + () -> webServerTest.setSummary(summaryResId) + ); + } + ); + } +} diff --git a/app/src/main/java/org/adaway/ui/prefs/PrefsUpdateFragment.java b/app/src/main/java/org/adaway/ui/prefs/PrefsUpdateFragment.java new file mode 100644 index 0000000..19f670c --- /dev/null +++ b/app/src/main/java/org/adaway/ui/prefs/PrefsUpdateFragment.java @@ -0,0 +1,127 @@ +package org.adaway.ui.prefs; + +import static android.Manifest.permission.POST_NOTIFICATIONS; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Build.VERSION.SDK_INT; +import static android.os.Build.VERSION_CODES.TIRAMISU; +import static android.provider.Settings.ACTION_APP_NOTIFICATION_SETTINGS; +import static android.provider.Settings.EXTRA_APP_PACKAGE; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.SwitchPreferenceCompat; + +import org.adaway.AdAwayApplication; +import org.adaway.R; +import org.adaway.helper.PreferenceHelper; +import org.adaway.model.source.SourceUpdateService; +import org.adaway.model.update.ApkUpdateService; +import org.adaway.model.update.UpdateStore; + +import static org.adaway.model.update.UpdateStore.ADAWAY; +import static org.adaway.ui.prefs.PrefsActivity.PREFERENCE_NOT_FOUND; +import static org.adaway.util.Constants.PREFS_NAME; + +/** + * This fragment is the preferences fragment for update settings. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class PrefsUpdateFragment extends PreferenceFragmentCompat { + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + // Configure preferences + getPreferenceManager().setSharedPreferencesName(PREFS_NAME); + addPreferencesFromResource(R.xml.preferences_update); + // Bind pref actions + bindNotificationPreferencesAction(); + bindAppUpdatePrefAction(); + bindAppChannelPrefAction(); + bindHostsUpdatePrefAction(); + // Update current state + updateNotificationPreferencesState(); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + PrefsActivity.setAppBarTitle(this, R.string.pref_update_title); + } + + @Override + public void onResume() { + super.onResume(); + updateNotificationPreferencesState(); + } + + private void bindNotificationPreferencesAction() { + Context context = requireContext(); + Preference openNotificationPref = findPreference(getString(R.string.pref_update_open_notification_preferences_key)); + assert openNotificationPref != null : PREFERENCE_NOT_FOUND; + openNotificationPref.setOnPreferenceClickListener(preference -> { + Intent settingsIntent = new Intent(ACTION_APP_NOTIFICATION_SETTINGS) + .addFlags(FLAG_ACTIVITY_NEW_TASK) + .putExtra(EXTRA_APP_PACKAGE, context.getPackageName()); + context.startActivity(settingsIntent); + return true; + }); + } + + private void bindAppUpdatePrefAction() { + Context context = requireContext(); + SwitchPreferenceCompat checkAppDailyPref = findPreference(getString(R.string.pref_update_check_app_daily_key)); + assert checkAppDailyPref != null : PREFERENCE_NOT_FOUND; + checkAppDailyPref.setOnPreferenceChangeListener((preference, newValue) -> { + if (Boolean.TRUE.equals(newValue)) { + ApkUpdateService.enable(context); + } else { + ApkUpdateService.disable(context); + } + return true; + }); + } + + private void bindAppChannelPrefAction() { + Context context = requireContext(); + AdAwayApplication application = (AdAwayApplication) context.getApplicationContext(); + UpdateStore store = application.getUpdateModel().getStore(); + Preference includeBetaReleasesPref = findPreference(getString(R.string.pref_update_include_beta_releases_key)); + assert includeBetaReleasesPref != null : PREFERENCE_NOT_FOUND; + includeBetaReleasesPref.setEnabled(store == ADAWAY); + } + + private void bindHostsUpdatePrefAction() { + Context context = requireContext(); + Preference checkHostsDailyPref = findPreference(getString(R.string.pref_update_check_hosts_daily_key)); + assert checkHostsDailyPref != null : PREFERENCE_NOT_FOUND; + checkHostsDailyPref.setOnPreferenceChangeListener((preference, newValue) -> { + if (Boolean.TRUE.equals(newValue)) { + boolean unmeteredNetworkOnly = PreferenceHelper.getUpdateOnlyOnWifi(context); + SourceUpdateService.enable(context, unmeteredNetworkOnly); + } else { + SourceUpdateService.disable(context); + } + return true; + }); + Preference updateOnlyOnWifiPref = findPreference(this.getString(R.string.pref_update_only_on_wifi_key)); + assert updateOnlyOnWifiPref != null : PREFERENCE_NOT_FOUND; + updateOnlyOnWifiPref.setOnPreferenceChangeListener((preference, newValue) -> { + SourceUpdateService.enable(context, Boolean.TRUE.equals(newValue)); + return true; + }); + } + + private void updateNotificationPreferencesState() { + Context context = requireContext(); + Preference openNotificationPref = findPreference(getString(R.string.pref_update_open_notification_preferences_key)); + assert openNotificationPref != null : PREFERENCE_NOT_FOUND; + boolean notificationsDisabled = SDK_INT >= TIRAMISU && context.checkSelfPermission(POST_NOTIFICATIONS) != PERMISSION_GRANTED; + openNotificationPref.setVisible(notificationsDisabled); + } +} diff --git a/app/src/main/java/org/adaway/ui/prefs/PrefsVpnFragment.java b/app/src/main/java/org/adaway/ui/prefs/PrefsVpnFragment.java new file mode 100644 index 0000000..6e2ad8a --- /dev/null +++ b/app/src/main/java/org/adaway/ui/prefs/PrefsVpnFragment.java @@ -0,0 +1,81 @@ +package org.adaway.ui.prefs; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; +import androidx.annotation.NonNull; +import androidx.preference.ListPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import org.adaway.R; +import org.adaway.ui.prefs.exclusion.PrefsVpnExcludedAppsActivity; +import org.adaway.vpn.VpnServiceControls; + +import static org.adaway.ui.prefs.PrefsActivity.PREFERENCE_NOT_FOUND; +import static org.adaway.util.Constants.PREFS_NAME; + +/** + * This fragment is the preferences fragment for VPN ad blocker. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class PrefsVpnFragment extends PreferenceFragmentCompat { + private ActivityResultLauncher startActivityLauncher; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + // Configure preferences + getPreferenceManager().setSharedPreferencesName(PREFS_NAME); + addPreferencesFromResource(R.xml.preferences_vpn); + // Register for activity + registerForStartActivity(); + // Bind pref actions + bindExcludedSystemApps(); + bindExcludedUserApps(); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + PrefsActivity.setAppBarTitle(this, R.string.pref_vpn_title); + } + + private void registerForStartActivity() { + this.startActivityLauncher = registerForActivityResult( + new StartActivityForResult(), + result -> restartVpn() + ); + } + + private void bindExcludedSystemApps() { + ListPreference excludeUserAppsPreferences = findPreference(getString(R.string.pref_vpn_excluded_system_apps_key)); + assert excludeUserAppsPreferences != null : PREFERENCE_NOT_FOUND; + excludeUserAppsPreferences.setOnPreferenceChangeListener((preference, newValue) -> { + restartVpn(); + return true; + }); + } + + private void bindExcludedUserApps() { + Context context = requireContext(); + Preference excludeUserAppsPreferences = findPreference(getString(R.string.pref_vpn_excluded_user_apps_key)); + assert excludeUserAppsPreferences != null : PREFERENCE_NOT_FOUND; + excludeUserAppsPreferences.setOnPreferenceClickListener(preference -> { + Intent intent = new Intent(context, PrefsVpnExcludedAppsActivity.class); + this.startActivityLauncher.launch(intent); + return true; + }); + } + + private void restartVpn() { + Context context = requireContext(); + if (VpnServiceControls.isRunning(context)) { + VpnServiceControls.stop(context); + VpnServiceControls.start(context); + } + } +} diff --git a/app/src/main/java/org/adaway/ui/prefs/exclusion/ExcludedAppController.java b/app/src/main/java/org/adaway/ui/prefs/exclusion/ExcludedAppController.java new file mode 100644 index 0000000..fa759b1 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/prefs/exclusion/ExcludedAppController.java @@ -0,0 +1,26 @@ +package org.adaway.ui.prefs.exclusion; + +/** + * This fragment is the preferences fragment for VPN ad blocker. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public interface ExcludedAppController { + /** + * Get installed user applications. + * @return The installed user applications. + */ + UserApp[] getUserApplications(); + + /** + * Exclude applications from VPN. + * @param applications The applications to exclude. + */ + void excludeApplications(UserApp... applications); + + /** + * Include applications into VPN. + * @param applications The application to include. + */ + void includeApplications(UserApp... applications); +} diff --git a/app/src/main/java/org/adaway/ui/prefs/exclusion/PrefsVpnExcludedAppsActivity.java b/app/src/main/java/org/adaway/ui/prefs/exclusion/PrefsVpnExcludedAppsActivity.java new file mode 100644 index 0000000..f56adb4 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/prefs/exclusion/PrefsVpnExcludedAppsActivity.java @@ -0,0 +1,131 @@ +package org.adaway.ui.prefs.exclusion; + +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; + +import org.adaway.R; +import org.adaway.databinding.VpnExcludedAppActivityBinding; +import org.adaway.helper.PreferenceHelper; +import org.adaway.helper.ThemeHelper; + +import java.util.Arrays; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * This activity is the activity to select excluded applications from VPN. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class PrefsVpnExcludedAppsActivity extends AppCompatActivity implements ExcludedAppController { + private UserApp[] userApplications; + private UserAppRecycleViewAdapter adapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + /* + * Create activity. + */ + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + VpnExcludedAppActivityBinding binding = VpnExcludedAppActivityBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + } + /* + * Configure recycler view. + */ + // Get recycler view + binding.vpnExcludedAppList.setHasFixedSize(true); + // Defile recycler layout + LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); + binding.vpnExcludedAppList.setLayoutManager(linearLayoutManager); + // Create recycler adapter + this.userApplications = getUserApplications(); + this.adapter = new UserAppRecycleViewAdapter(this); + binding.vpnExcludedAppList.setAdapter(this.adapter); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater menuInflater = getMenuInflater(); + menuInflater.inflate(R.menu.vpn_excluded_app_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } else if (item.getItemId() == R.id.select_all) { + excludeApplications(this.userApplications); + this.adapter.notifyItemRangeChanged(0, this.adapter.getItemCount()); + return true; + } else if (item.getItemId() == R.id.deselect_all) { + includeApplications(this.userApplications); + this.adapter.notifyItemRangeChanged(0, this.adapter.getItemCount()); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public UserApp[] getUserApplications() { + if (this.userApplications == null) { + PackageManager packageManager = getPackageManager(); + ApplicationInfo self = getApplicationInfo(); + Set excludedApps = PreferenceHelper.getVpnExcludedApps(this); + + this.userApplications = packageManager.getInstalledApplications(0).stream() + .filter(applicationInfo -> (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) + .filter(applicationInfo -> !Objects.equals(applicationInfo.name, self.name)) + .map(applicationInfo -> new UserApp( + packageManager.getApplicationLabel(applicationInfo), + applicationInfo.packageName, + packageManager.getApplicationIcon(applicationInfo), + excludedApps.contains(applicationInfo.packageName) + )) + .sorted() + .toArray(UserApp[]::new); + } + return this.userApplications; + } + + @Override + public void excludeApplications(UserApp... applications) { + for (UserApp application : applications) { + application.excluded = true; + } + updatePreferences(); + } + + @Override + public void includeApplications(UserApp... applications) { + for (UserApp application : applications) { + application.excluded = false; + } + updatePreferences(); + } + + private void updatePreferences() { + Set excludedApplicationPackageNames = Arrays.stream(this.userApplications) + .filter(userApp -> userApp.excluded) + .map(userApp -> userApp.packageName.toString()) + .collect(Collectors.toSet()); + PreferenceHelper.setVpnExcludedApps(this, excludedApplicationPackageNames); + } +} diff --git a/app/src/main/java/org/adaway/ui/prefs/exclusion/UserApp.java b/app/src/main/java/org/adaway/ui/prefs/exclusion/UserApp.java new file mode 100644 index 0000000..d943115 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/prefs/exclusion/UserApp.java @@ -0,0 +1,27 @@ +package org.adaway.ui.prefs.exclusion; + +import android.graphics.drawable.Drawable; + +/** + * This class represents an installed user application to exclude / include into the VPN. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class UserApp implements Comparable { + final String name; + final CharSequence packageName; + final Drawable icon; + boolean excluded; + + UserApp(CharSequence name, CharSequence packageName, Drawable icon, boolean excluded) { + this.name = name.toString(); + this.packageName = packageName; + this.icon = icon; + this.excluded = excluded; + } + + @Override + public int compareTo(UserApp o) { + return this.name.compareTo(o.name); + } +} diff --git a/app/src/main/java/org/adaway/ui/prefs/exclusion/UserAppRecycleViewAdapter.java b/app/src/main/java/org/adaway/ui/prefs/exclusion/UserAppRecycleViewAdapter.java new file mode 100644 index 0000000..99d86a9 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/prefs/exclusion/UserAppRecycleViewAdapter.java @@ -0,0 +1,83 @@ +package org.adaway.ui.prefs.exclusion; + +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import org.adaway.databinding.VpnExcludedAppEntryBinding; + +/** + * This class is the {@link RecyclerView.Adapter} for the {@link PrefsVpnExcludedAppsActivity}. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class UserAppRecycleViewAdapter extends RecyclerView.Adapter { + private final ExcludedAppController controller; + + /** + * Constructor. + * + * @param controller The user applications. + */ + UserAppRecycleViewAdapter(ExcludedAppController controller) { + this.controller = controller; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); + VpnExcludedAppEntryBinding binding = VpnExcludedAppEntryBinding.inflate(layoutInflater, parent, false); + return new ViewHolder(binding); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + UserApp[] applications = this.controller.getUserApplications(); + if (position < 0 || position >= applications.length) { + return; + } + UserApp application = applications[position]; + holder.binding.rowLayout.setOnClickListener( + v -> holder.binding.excludedSwitch.setChecked(!holder.binding.excludedSwitch.isChecked()) + ); + holder.binding.iconImageView.setImageDrawable(application.icon); + holder.binding.nameTextView.setText(application.name); + holder.binding.packageTextView.setText(application.packageName); + holder.binding.excludedSwitch.setOnCheckedChangeListener(null); + holder.binding.excludedSwitch.setChecked(application.excluded); + holder.binding.excludedSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + this.controller.excludeApplications(application); + } else { + this.controller.includeApplications(application); + } + }); + } + + @Override + public int getItemCount() { + return this.controller.getUserApplications().length; + } + + /** + * This class is a the {@link RecyclerView.ViewHolder} for the app list view. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ + static class ViewHolder extends RecyclerView.ViewHolder { + final VpnExcludedAppEntryBinding binding; + + /** + * Constructor. + * + * @param binding The hosts sources view binding. + */ + ViewHolder(VpnExcludedAppEntryBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } +} diff --git a/app/src/main/java/org/adaway/ui/source/SourceEditActivity.java b/app/src/main/java/org/adaway/ui/source/SourceEditActivity.java new file mode 100644 index 0000000..d5ec4d9 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/source/SourceEditActivity.java @@ -0,0 +1,257 @@ +package org.adaway.ui.source; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; + +import org.adaway.R; +import org.adaway.databinding.SourceEditActivityBinding; +import org.adaway.db.AppDatabase; +import org.adaway.db.dao.HostsSourceDao; +import org.adaway.db.entity.HostsSource; +import org.adaway.helper.ThemeHelper; +import org.adaway.util.AppExecutors; + +import java.util.Optional; +import java.util.concurrent.Executor; + +import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static java.util.Objects.requireNonNull; +import static org.adaway.ui.Animations.hideView; +import static org.adaway.ui.Animations.setHidden; +import static org.adaway.ui.Animations.setShown; +import static org.adaway.ui.Animations.showView; + +/** + * This activity create, edit and delete a hosts source. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class SourceEditActivity extends AppCompatActivity { + /** + * The source identifier extra. + */ + public static final String SOURCE_ID = "sourceId"; + /** + * The any type mime type. + */ + private static final String ANY_MIME_TYPE = "*/*"; + private static final Executor DISK_IO_EXECUTOR = AppExecutors.getInstance().diskIO(); + private static final Executor MAIN_THREAD_EXECUTOR = AppExecutors.getInstance().mainThread(); + + private SourceEditActivityBinding binding; + private HostsSourceDao hostsSourceDao; + private ActivityResultLauncher startActivityLauncher; + private boolean editing; + private HostsSource edited; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + /* + * Set view content. + */ + this.binding = SourceEditActivityBinding.inflate(getLayoutInflater()); + setContentView(this.binding.getRoot()); + /* + * Configure actionbar. + */ + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } + /* + * Get database access. + */ + AppDatabase database = AppDatabase.getInstance(this); + this.hostsSourceDao = database.hostsSourceDao(); + // Register for activity + registerForStartActivity(); + // Set up values + checkInitialValueFromIntent(); + } + + private void registerForStartActivity() { + this.startActivityLauncher = registerForActivityResult(new StartActivityForResult(), result -> { + Uri uri; + Intent data = result.getData(); + if (result.getResultCode() == RESULT_OK + && data != null + && (uri = data.getData()) != null) { + // Persist read permission + getContentResolver().takePersistableUriPermission(uri, FLAG_GRANT_READ_URI_PERMISSION); + // Update file location + this.binding.fileLocationTextView.setText(uri.toString()); + this.binding.fileLocationTextView.setError(null); + } + }); + } + + private void checkInitialValueFromIntent() { + Intent intent = getIntent(); + int sourceId = intent.getIntExtra(SOURCE_ID, -1); + this.editing = sourceId != -1; + if (this.editing) { + DISK_IO_EXECUTOR.execute(() -> { + Optional hostsSource = this.hostsSourceDao.getById(sourceId); + hostsSource.ifPresent(source -> { + this.edited = source; + MAIN_THREAD_EXECUTOR.execute(() -> { + applyInitialValues(source); + bindLocation(); + bindFormats(); + }); + }); + }); + } else { + setTitle(R.string.source_edit_add_title); + bindLocation(); + bindFormats(); + } + } + + private void applyInitialValues(HostsSource source) { + this.binding.labelEditText.setText(source.getLabel()); + this.binding.blockFormatButton.setChecked(!source.isAllowEnabled()); + this.binding.allowFormatButton.setChecked(source.isAllowEnabled()); + switch (source.getType()) { + case URL: + this.binding.typeButtonGroup.check(R.id.url_button); + this.binding.locationEditText.setText(source.getUrl()); + break; + case FILE: + this.binding.typeButtonGroup.check(R.id.file_button); + this.binding.fileLocationTextView.setText(source.getUrl()); + this.binding.fileLocationTextView.setVisibility(VISIBLE); + this.binding.urlTextInputLayout.setVisibility(INVISIBLE); + break; + } + this.binding.redirectedHostsCheckbox.setChecked(source.isRedirectEnabled()); + if (source.isAllowEnabled()) { + setHidden(this.binding.redirectedHostsCheckbox); + setHidden(this.binding.redirectedHostsWarningTextView); + } else { + setShown(this.binding.redirectedHostsCheckbox); + setShown(this.binding.redirectedHostsWarningTextView); + } + } + + private void bindLocation() { + this.binding.typeButtonGroup.addOnButtonCheckedListener((group, checkedId, isChecked) -> { + // Keep always one button checked + if (group.getCheckedButtonId() == View.NO_ID) { + group.check(checkedId); + return; + } + if (isChecked) { + boolean isFile = checkedId == R.id.file_button; + this.binding.locationEditText.setText(isFile ? "" : "https://"); + this.binding.locationEditText.setEnabled(!isFile); + if (isFile) { + openDocument(); + } + this.binding.urlTextInputLayout.setVisibility(isFile ? INVISIBLE : VISIBLE); + this.binding.fileLocationTextView.setVisibility(isFile ? VISIBLE : INVISIBLE); + } + }); + this.binding.fileLocationTextView.setOnClickListener(view -> openDocument()); + } + + private void bindFormats() { + this.binding.blockFormatButton.addOnCheckedChangeListener((button, isChecked) -> { + if (isChecked) { + showView(this.binding.redirectedHostsCheckbox); + showView(this.binding.redirectedHostsWarningTextView); + } else { + hideView(this.binding.redirectedHostsCheckbox); + hideView(this.binding.redirectedHostsWarningTextView); + } + }); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.source_edit_menu, menu); + menu.findItem(R.id.delete_action).setVisible(this.editing); + return true; + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + // Check item identifier + if (item.getItemId() == R.id.delete_action) { + DISK_IO_EXECUTOR.execute(() -> this.hostsSourceDao.delete(this.edited)); + finish(); + return true; + } else if (item.getItemId() == R.id.apply_action) { + HostsSource source = validate(); + if (source == null) { + return false; + } + DISK_IO_EXECUTOR.execute(() -> { + if (this.editing) { + this.hostsSourceDao.delete(this.edited); + } + this.hostsSourceDao.insert(source); + finish(); + }); + return true; + } + return false; + } + + private HostsSource validate() { + String label = requireNonNull(this.binding.labelEditText.getText()).toString(); + if (label.isEmpty()) { + this.binding.labelEditText.setError(getString(R.string.source_edit_label_required)); + return null; + } + String url; + if (this.binding.typeButtonGroup.getCheckedButtonId() == R.id.url_button) { + url = requireNonNull(this.binding.locationEditText.getText()).toString(); + if (url.isEmpty()) { + this.binding.locationEditText.setError(getString(R.string.source_edit_url_location_required)); + return null; + } + if (!HostsSource.isValidUrl(url)) { + this.binding.locationEditText.setError(getString(R.string.source_edit_location_invalid)); + return null; + } + } else { + url = this.binding.fileLocationTextView.getText().toString(); + if (!HostsSource.isValidUrl(url)) { + this.binding.fileLocationTextView.setError(getString(R.string.source_edit_location_invalid)); + return null; + } + } + HostsSource source = new HostsSource(); + source.setLabel(label); + source.setUrl(url); + boolean allowFormat = this.binding.allowFormatButton.isChecked(); + source.setAllowEnabled(allowFormat); + source.setRedirectEnabled(!allowFormat && this.binding.redirectedHostsCheckbox.isChecked()); + return source; + } + + private void openDocument() { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType(ANY_MIME_TYPE); + this.startActivityLauncher.launch(intent); + } +} diff --git a/app/src/main/java/org/adaway/ui/support/SupportActivity.java b/app/src/main/java/org/adaway/ui/support/SupportActivity.java new file mode 100644 index 0000000..0ab3394 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/support/SupportActivity.java @@ -0,0 +1,87 @@ +package org.adaway.ui.support; + +import static android.content.Intent.ACTION_VIEW; +import static android.net.Uri.parse; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import org.adaway.R; + +/** + * This class is an activity for users to show their supports to the project. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class SupportActivity extends AppCompatActivity { + /** + * The support link. + */ + public static final Uri SUPPORT_LINK = parse("https://paypal.me/BruceBUJON"); + /** + * The sponsorship link. + */ + public static final Uri SPONSORSHIP_LINK = parse("https://github.com/sponsors/PerfectSlayer"); + + public static void animateHeart(ImageView heartImageView) { + PropertyValuesHolder growScaleX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1F, 1.2F); + PropertyValuesHolder growScaleY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1F, 1.2F); + Animator growAnimator = ObjectAnimator.ofPropertyValuesHolder(heartImageView, growScaleX, growScaleY); + growAnimator.setDuration(200); + growAnimator.setStartDelay(2000); + + PropertyValuesHolder shrinkScaleX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1.2F, 1F); + PropertyValuesHolder shrinkScaleY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.2F, 1F); + Animator shrinkAnimator = ObjectAnimator.ofPropertyValuesHolder(heartImageView, shrinkScaleX, shrinkScaleY); + growAnimator.setDuration(400); + + AnimatorSet animationSet = new AnimatorSet(); + animationSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + animationSet.start(); + } + }); + animationSet.playSequentially(growAnimator, shrinkAnimator); + animationSet.start(); + } + + public static void bindLink(Context context, View view, Uri uri) { + view.setOnClickListener(v -> { + Intent browserIntent = new Intent(ACTION_VIEW, uri); + context.startActivity(browserIntent); + }); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.support_activity); + + ImageView heartImageView = findViewById(R.id.headerImageView); + animateHeart(heartImageView); + bindPaypal(); + bindSponsorShip(); + } + + private void bindPaypal() { + bindLink(this, findViewById(R.id.headerImageView), SUPPORT_LINK); + bindLink(this, findViewById(R.id.paypalCardView), SUPPORT_LINK); + } + + private void bindSponsorShip() { + bindLink(this, findViewById(R.id.sponsorshipCardView), SPONSORSHIP_LINK); + } +} diff --git a/app/src/main/java/org/adaway/ui/update/CompleteDownloadStatus.java b/app/src/main/java/org/adaway/ui/update/CompleteDownloadStatus.java new file mode 100644 index 0000000..4bc03d8 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/update/CompleteDownloadStatus.java @@ -0,0 +1,22 @@ +package org.adaway.ui.update; + +import android.content.Context; + +import org.adaway.R; + +/** + * This class represents the application complete update download status. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class CompleteDownloadStatus implements DownloadStatus { + @Override + public int getProgress() { + return 100; + } + + @Override + public String format(Context context) { + return context.getString(R.string.update_complete_label); + } +} diff --git a/app/src/main/java/org/adaway/ui/update/DownloadStatus.java b/app/src/main/java/org/adaway/ui/update/DownloadStatus.java new file mode 100644 index 0000000..b99fdc0 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/update/DownloadStatus.java @@ -0,0 +1,23 @@ +package org.adaway.ui.update; + +import android.content.Context; + +/** + * This class represents the application update download status. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public interface DownloadStatus { + /** + * Get the download progress percent. + */ + int getProgress(); + + /** + * Format status to string. + * + * @param context The application context. + * @return The formatted status. + */ + String format(Context context); +} diff --git a/app/src/main/java/org/adaway/ui/update/PendingDownloadStatus.java b/app/src/main/java/org/adaway/ui/update/PendingDownloadStatus.java new file mode 100644 index 0000000..a9caf31 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/update/PendingDownloadStatus.java @@ -0,0 +1,52 @@ +package org.adaway.ui.update; + +import android.content.Context; +import android.text.format.Formatter; + +import org.adaway.R; + +/** + * This class represents the application pending update download status. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class PendingDownloadStatus implements DownloadStatus { + /** + * The downloaded bytes. + */ + final long downloaded; + /** + * The total bytes to download. + */ + final long total; + /** + * The download progress percent. + */ + final int progress; + + /** + * Constructor. + * + * @param downloaded The downloaded bytes. + * @param total The total bytes to download. + */ + PendingDownloadStatus(long downloaded, long total) { + this.downloaded = downloaded; + this.total = total; + this.progress = (int) (downloaded * 100L / total); + } + + @Override + public int getProgress() { + return this.progress; + } + + @Override + public String format(Context context) { + return context.getString( + R.string.update_progress_label, + Formatter.formatFileSize(context, this.downloaded), + Formatter.formatFileSize(context, this.total) + ); + } +} diff --git a/app/src/main/java/org/adaway/ui/update/UpdateActivity.java b/app/src/main/java/org/adaway/ui/update/UpdateActivity.java new file mode 100644 index 0000000..05407ce --- /dev/null +++ b/app/src/main/java/org/adaway/ui/update/UpdateActivity.java @@ -0,0 +1,86 @@ +package org.adaway.ui.update; + +import static android.view.View.GONE; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static org.adaway.ui.support.SupportActivity.SPONSORSHIP_LINK; +import static org.adaway.ui.support.SupportActivity.SUPPORT_LINK; +import static org.adaway.ui.support.SupportActivity.bindLink; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.lifecycle.ViewModelProvider; + +import org.adaway.R; +import org.adaway.databinding.UpdateActityBinding; +import org.adaway.helper.ThemeHelper; +import org.adaway.model.update.Manifest; + +/** + * This class is the application main activity. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class UpdateActivity extends AppCompatActivity { + private UpdateActityBinding binding; + private UpdateViewModel updateViewModel; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeHelper.applyTheme(this); + this.binding = UpdateActityBinding.inflate(getLayoutInflater()); + setContentView(this.binding.getRoot()); + + this.updateViewModel = new ViewModelProvider(this).get(UpdateViewModel.class); + bindListeners(); + bindManifest(); + bindProgress(); + } + + private void bindListeners() { + this.binding.updateButton.setOnClickListener(this::startUpdate); + bindLink(this, this.binding.updateDonateButton, SUPPORT_LINK); + bindLink(this, this.binding.updateSponsorButton, SPONSORSHIP_LINK); + } + + private void bindManifest() { + this.updateViewModel.getAppManifest().observe(this, manifest -> { + if (manifest.updateAvailable) { + showUpdate(manifest); + } else { + markUpToDate(manifest); + } + }); + } + + private void bindProgress() { + this.updateViewModel.getDownloadProgress().observe(this, progress -> { + this.binding.updateButton.setVisibility(INVISIBLE); + this.binding.downloadProgressBar.setVisibility(VISIBLE); + this.binding.downloadProgressBar.setProgress(progress.getProgress(), true); + this.binding.progressTextView.setText(progress.format(this)); + }); + } + + private void markUpToDate(Manifest manifest) { + this.binding.headerTextView.setText(R.string.update_up_to_date_header); + this.binding.updateButton.setVisibility(GONE); + this.binding.changelogTextView.setText(manifest.changelog); + } + + private void showUpdate(Manifest manifest) { + this.binding.headerTextView.setText(R.string.update_update_available_header); + this.binding.updateButton.setVisibility(VISIBLE); + this.binding.changelogTextView.setText(manifest.changelog); + } + + private void startUpdate(View view) { + this.binding.updateButton.setVisibility(INVISIBLE); + this.binding.downloadProgressBar.setVisibility(VISIBLE); + this.updateViewModel.update(); + } +} diff --git a/app/src/main/java/org/adaway/ui/update/UpdateViewModel.java b/app/src/main/java/org/adaway/ui/update/UpdateViewModel.java new file mode 100644 index 0000000..c558d62 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/update/UpdateViewModel.java @@ -0,0 +1,105 @@ +package org.adaway.ui.update; + +import static android.app.DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR; +import static android.app.DownloadManager.COLUMN_STATUS; +import static android.app.DownloadManager.COLUMN_TOTAL_SIZE_BYTES; +import static android.app.DownloadManager.STATUS_FAILED; +import static android.app.DownloadManager.STATUS_RUNNING; +import static android.app.DownloadManager.STATUS_SUCCESSFUL; + +import android.app.Application; +import android.app.DownloadManager; +import android.database.Cursor; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import org.adaway.AdAwayApplication; +import org.adaway.model.update.Manifest; +import org.adaway.model.update.UpdateModel; +import org.adaway.ui.adware.AdwareViewModel; +import org.adaway.util.AppExecutors; + +import java.util.concurrent.Executor; + +import timber.log.Timber; + +/** + * This class is an {@link AndroidViewModel} for the {@link UpdateActivity} cards. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class UpdateViewModel extends AdwareViewModel { + private static final Executor NETWORK_IO = AppExecutors.getInstance().networkIO(); + private final UpdateModel updateModel; + private final MutableLiveData downloadProgress; + + public UpdateViewModel(@NonNull Application application) { + super(application); + this.updateModel = ((AdAwayApplication) application).getUpdateModel(); + this.downloadProgress = new MutableLiveData<>(); + } + + public LiveData getAppManifest() { + return this.updateModel.getManifest(); + } + + public void update() { + long downloadId = this.updateModel.update(); + NETWORK_IO.execute(() -> trackProgress(downloadId)); + } + + public MutableLiveData getDownloadProgress() { + return this.downloadProgress; + } + + private void trackProgress(long downloadId) { + DownloadManager downloadManager = getApplication().getSystemService(DownloadManager.class); + DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId); + boolean finishDownload = false; + while (!finishDownload) { + // Add wait before querying download manager + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Timber.d(e, "Failed to wait before querying download manager."); + Thread.currentThread().interrupt(); + this.downloadProgress.postValue(null); + return; + } + // Query download manager + try (Cursor cursor = downloadManager.query(query)) { + if (!cursor.moveToFirst()) { + Timber.d("Download item was not found"); + continue; + } + // Check download status + int statusColumnIndex = cursor.getColumnIndex(COLUMN_STATUS); + int status = cursor.getInt(statusColumnIndex); + switch (status) { + case STATUS_FAILED: + finishDownload = true; + this.downloadProgress.postValue(null); + break; + case STATUS_RUNNING: + int totalSizeColumnIndex = cursor.getColumnIndex(COLUMN_TOTAL_SIZE_BYTES); + long total = cursor.getLong(totalSizeColumnIndex); + if (total > 0) { + int bytesDownloadedColumnIndex = cursor.getColumnIndex(COLUMN_BYTES_DOWNLOADED_SO_FAR); + long downloaded = cursor.getLong(bytesDownloadedColumnIndex); + this.downloadProgress.postValue(new PendingDownloadStatus(downloaded, total)); + } + break; + case STATUS_SUCCESSFUL: + this.downloadProgress.postValue(new CompleteDownloadStatus()); + finishDownload = true; + break; + default: + break; + } + } + } + } +} diff --git a/app/src/main/java/org/adaway/ui/welcome/WelcomeActivity.java b/app/src/main/java/org/adaway/ui/welcome/WelcomeActivity.java new file mode 100644 index 0000000..213244a --- /dev/null +++ b/app/src/main/java/org/adaway/ui/welcome/WelcomeActivity.java @@ -0,0 +1,155 @@ +package org.adaway.ui.welcome; + +import android.content.Intent; +import android.os.Bundle; +import android.widget.ImageView; + +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.viewpager2.widget.ViewPager2; + +import org.adaway.R; +import org.adaway.databinding.WelcomeActivityBinding; +import org.adaway.ui.home.HomeActivity; + +import static org.adaway.ui.Animations.hideView; +import static org.adaway.ui.Animations.showView; + +/** + * This class is a welcome activity to run first time setup on the user device. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class WelcomeActivity extends AppCompatActivity implements WelcomeNavigable { + private WelcomeActivityBinding binding; + private WelcomePagerAdapter pagerAdapter; + private ImageView[] dotImageViews; + private OnBackPressedCallback onBackPressedCallback; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.binding = WelcomeActivityBinding.inflate(getLayoutInflater()); + setContentView(this.binding.getRoot()); + buildPager(); + bindBackButton(); + bindNextButton(); + bindDots(); + bindBackPress(); + } + + private void buildPager() { + this.pagerAdapter = new WelcomePagerAdapter(this); + this.binding.viewPager.setAdapter(this.pagerAdapter); + this.binding.viewPager.setUserInputEnabled(false); + } + + private void bindNextButton() { + this.binding.nextButton.setOnClickListener(view -> goNext()); + } + + private void bindBackButton() { + this.binding.backButton.setOnClickListener(view -> goBack()); + } + + private void bindDots() { + this.dotImageViews = new ImageView[]{ + this.binding.dot1ImageView, + this.binding.dot2ImageView, + this.binding.dot3ImageView + }; + highlightDot(this.binding.viewPager.getCurrentItem()); + this.binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageSelected(int position) { + highlightDot(position); + } + }); + } + + private void highlightDot(int position) { + for (int index = 0; index < this.dotImageViews.length; index++) { + if (index == position) { + this.dotImageViews[index].setImageResource(R.drawable.dot); + this.dotImageViews[index].animate().alpha(0.7F).scaleX(1.2F).scaleY(1.2F); + } else { + this.dotImageViews[index].setImageResource(R.drawable.dot_outline); + this.dotImageViews[index].animate().alpha(0.5F).scaleX(1F).scaleY(1F); + } + } + } + + private void bindBackPress() { + this.onBackPressedCallback = new OnBackPressedCallback(false) { + @Override + public void handleOnBackPressed() { + goBack(); + } + }; + getOnBackPressedDispatcher().addCallback(this.onBackPressedCallback); + this.binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageSelected(int position) { + WelcomeActivity.this.onBackPressedCallback.setEnabled(position > 0); + } + }); + } + + @Override + public void allowNext() { + if (this.binding.viewPager.getCurrentItem() == this.pagerAdapter.getItemCount() - 1) { + this.binding.nextButton.setText(R.string.welcome_finish_button); + } else { + this.binding.nextButton.setText(R.string.welcome_next_button); + } + showView(this.binding.nextButton); + } + + @Override + public void blockNext() { + hideView(this.binding.nextButton); + } + + private void allowBack() { + showView(this.binding.backButton); + } + + private void blockBack() { + hideView(this.binding.backButton); + } + + private void goNext() { + int currentItem = this.binding.viewPager.getCurrentItem(); + int count = this.pagerAdapter.getItemCount(); + if (currentItem >= count - 1) { + startHomeActivity(); + return; + } + currentItem++; + this.binding.viewPager.setCurrentItem(currentItem); + allowBack(); + if (this.pagerAdapter.createFragment(currentItem).canGoNext()) { + allowNext(); + } else { + blockNext(); + } + } + + private void goBack() { + int currentItem = this.binding.viewPager.getCurrentItem(); + if (currentItem == 0) { + return; + } + this.binding.viewPager.setCurrentItem(currentItem - 1); + if (currentItem <= 1) { + blockBack(); + } + allowNext(); + } + + private void startHomeActivity() { + startActivity(new Intent(this, HomeActivity.class)); + finish(); + } +} diff --git a/app/src/main/java/org/adaway/ui/welcome/WelcomeFragment.java b/app/src/main/java/org/adaway/ui/welcome/WelcomeFragment.java new file mode 100644 index 0000000..668d564 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/welcome/WelcomeFragment.java @@ -0,0 +1,30 @@ +package org.adaway.ui.welcome; + +import androidx.fragment.app.Fragment; + +/** + * This class is the base fragment to all setup fragments. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public abstract class WelcomeFragment extends Fragment { + private boolean goNext = false; + + protected void allowNext() { + this.goNext = true; + getNavigable().allowNext(); + } + + protected void blockNext() { + this.goNext = false; + getNavigable().blockNext(); + } + + protected boolean canGoNext() { + return this.goNext; + } + + private WelcomeNavigable getNavigable() { + return (WelcomeNavigable) getActivity(); + } +} diff --git a/app/src/main/java/org/adaway/ui/welcome/WelcomeMethodFragment.java b/app/src/main/java/org/adaway/ui/welcome/WelcomeMethodFragment.java new file mode 100644 index 0000000..68d1086 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/welcome/WelcomeMethodFragment.java @@ -0,0 +1,126 @@ +package org.adaway.ui.welcome; + +import static android.app.Activity.RESULT_OK; +import static org.adaway.model.adblocking.AdBlockMethod.ROOT; +import static org.adaway.model.adblocking.AdBlockMethod.UNDEFINED; +import static org.adaway.model.adblocking.AdBlockMethod.VPN; +import static java.lang.Boolean.TRUE; + +import android.content.Context; +import android.content.Intent; +import android.net.VpnService; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.topjohnwu.superuser.Shell; + +import org.adaway.R; +import org.adaway.databinding.WelcomeMethodLayoutBinding; +import org.adaway.helper.PreferenceHelper; +import org.adaway.util.log.SentryLog; + +/** + * This class is a fragment to setup the ad blocking method. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class WelcomeMethodFragment extends WelcomeFragment { + private WelcomeMethodLayoutBinding binding; + private ActivityResultLauncher prepareVpnLauncher; + @ColorInt + private int cardColor; + @ColorInt + private int cardEnabledColor; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + this.binding = WelcomeMethodLayoutBinding.inflate(inflater, container, false); + this.prepareVpnLauncher = registerForActivityResult(new StartActivityForResult(), result -> { + if (result.getResultCode() == RESULT_OK) { + notifyVpnEnabled(); + } else { + notifyVpnDisabled(); + } + }); + + this.binding.rootCardView.setOnClickListener(this::checkRoot); + this.binding.vpnCardView.setOnClickListener(this::enableVpnService); + + this.cardColor = getResources().getColor(R.color.cardBackground, null); + this.cardEnabledColor = getResources().getColor(R.color.cardEnabledBackground, null); + return this.binding.getRoot(); + } + + private void checkRoot(@Nullable View view) { + notifyVpnDisabled(); + Shell.getShell(); + if (TRUE.equals(Shell.isAppGrantedRoot())) { + notifyRootEnabled(); + } else { + notifyRootDisabled(true); + } + } + + private void enableVpnService(@Nullable View view) { + notifyRootDisabled(false); + Context context = getContext(); + if (context == null) { + return; + } + // Check user authorization + Intent prepareIntent = VpnService.prepare(context); + if (prepareIntent == null) { + notifyVpnEnabled(); + } else { + this.prepareVpnLauncher.launch(prepareIntent); + } + } + + private void notifyRootEnabled() { + SentryLog.recordBreadcrumb("Enable root ad-blocking method"); + PreferenceHelper.setAbBlockMethod(requireContext(), ROOT); + this.binding.rootCardView.setCardBackgroundColor(this.cardEnabledColor); + this.binding.vpnCardView.setCardBackgroundColor(this.cardColor); + allowNext(); + } + + private void notifyRootDisabled(boolean showDialog) { + PreferenceHelper.setAbBlockMethod(requireContext(), UNDEFINED); + this.binding.rootCardView.setCardBackgroundColor(this.cardColor); + this.binding.vpnCardView.setCardBackgroundColor(this.cardColor); + if (showDialog) { + blockNext(); + new MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.welcome_root_missing_title) + .setMessage(R.string.welcome_root_missile_description) + .setPositiveButton(R.string.button_close, null) + .create() + .show(); + } + } + + private void notifyVpnEnabled() { + SentryLog.recordBreadcrumb("Enable vpn ad-blocking method"); + PreferenceHelper.setAbBlockMethod(requireContext(), VPN); + this.binding.rootCardView.setCardBackgroundColor(this.cardColor); + this.binding.vpnCardView.setCardBackgroundColor(this.cardEnabledColor); + allowNext(); + } + + private void notifyVpnDisabled() { + PreferenceHelper.setAbBlockMethod(requireContext(), UNDEFINED); + this.binding.rootCardView.setCardBackgroundColor(this.cardColor); + this.binding.vpnCardView.setCardBackgroundColor(this.cardColor); + blockNext(); + } +} diff --git a/app/src/main/java/org/adaway/ui/welcome/WelcomeNavigable.java b/app/src/main/java/org/adaway/ui/welcome/WelcomeNavigable.java new file mode 100644 index 0000000..380dea2 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/welcome/WelcomeNavigable.java @@ -0,0 +1,11 @@ +package org.adaway.ui.welcome; + +/** + * This interface represents step to navigate to during the setup. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public interface WelcomeNavigable { + void allowNext(); + void blockNext(); +} diff --git a/app/src/main/java/org/adaway/ui/welcome/WelcomePagerAdapter.java b/app/src/main/java/org/adaway/ui/welcome/WelcomePagerAdapter.java new file mode 100644 index 0000000..6255c8c --- /dev/null +++ b/app/src/main/java/org/adaway/ui/welcome/WelcomePagerAdapter.java @@ -0,0 +1,43 @@ +package org.adaway.ui.welcome; + +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.adapter.FragmentStateAdapter; + +/** + * This class is a pager adapter to create setup step fragments. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class WelcomePagerAdapter extends FragmentStateAdapter { + private final WelcomeMethodFragment welcomeMethodFragment; + private final WelcomeSyncFragment welcomeSyncFragment; + private final WelcomeSupportFragment welcomeSupportFragment; + + WelcomePagerAdapter(@NonNull FragmentActivity fragmentManager) { + super(fragmentManager); + this.welcomeMethodFragment = new WelcomeMethodFragment(); + this.welcomeSyncFragment = new WelcomeSyncFragment(); + this.welcomeSupportFragment = new WelcomeSupportFragment(); + } + + @NonNull + @Override + public WelcomeFragment createFragment(int position) { + switch (position) { + case 0: + return this.welcomeMethodFragment; + case 1: + return this.welcomeSyncFragment; + case 2: + return this.welcomeSupportFragment; + default: + throw new IllegalStateException("Position " + position + " is not supported."); + } + } + + @Override + public int getItemCount() { + return 3; + } +} diff --git a/app/src/main/java/org/adaway/ui/welcome/WelcomeSupportFragment.java b/app/src/main/java/org/adaway/ui/welcome/WelcomeSupportFragment.java new file mode 100644 index 0000000..0ec00d4 --- /dev/null +++ b/app/src/main/java/org/adaway/ui/welcome/WelcomeSupportFragment.java @@ -0,0 +1,76 @@ +package org.adaway.ui.welcome; + +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static org.adaway.ui.support.SupportActivity.SPONSORSHIP_LINK; +import static org.adaway.ui.support.SupportActivity.SUPPORT_LINK; +import static org.adaway.ui.support.SupportActivity.animateHeart; +import static org.adaway.ui.support.SupportActivity.bindLink; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.adaway.databinding.WelcomeSupportLayoutBinding; +import org.adaway.helper.PreferenceHelper; +import org.adaway.util.log.SentryLog; + +/** + * This class is a fragment to inform user how to support the application development. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class WelcomeSupportFragment extends WelcomeFragment { + private WelcomeSupportLayoutBinding binding; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + this.binding = WelcomeSupportLayoutBinding.inflate(inflater, container, false); + + animateHeart(this.binding.headerImageView); + bindSupport(); + customizeSecondOption(); + + return this.binding.getRoot(); + } + + @Override + protected boolean canGoNext() { + return true; + } + + private void customizeSecondOption() { + if (SentryLog.isStub()) { + showAndBindSponsorship(); + } else { + bindTelemetry(); + } + } + + private void bindSupport() { + Context context = requireContext(); + bindLink(context, this.binding.headerImageView, SUPPORT_LINK); + bindLink(context, this.binding.headerTextView, SUPPORT_LINK); + bindLink(context, this.binding.paypalCardView, SUPPORT_LINK); + } + + private void bindTelemetry() { + this.binding.telemetryCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> { + PreferenceHelper.setTelemetryEnabled(requireContext(), isChecked); + SentryLog.setEnabled(requireActivity().getApplication(), isChecked); + }); + } + + private void showAndBindSponsorship() { + this.binding.telemetryTextView.setVisibility(INVISIBLE); + this.binding.telemetryCheckBox.setVisibility(INVISIBLE); + this.binding.sponsorshipCardView.setVisibility(VISIBLE); + bindLink(requireContext(), this.binding.sponsorshipCardView, SPONSORSHIP_LINK); + } +} diff --git a/app/src/main/java/org/adaway/ui/welcome/WelcomeSyncFragment.java b/app/src/main/java/org/adaway/ui/welcome/WelcomeSyncFragment.java new file mode 100644 index 0000000..843053c --- /dev/null +++ b/app/src/main/java/org/adaway/ui/welcome/WelcomeSyncFragment.java @@ -0,0 +1,117 @@ +package org.adaway.ui.welcome; + +import static android.Manifest.permission.POST_NOTIFICATIONS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Build.VERSION.SDK_INT; +import static android.os.Build.VERSION_CODES.TIRAMISU; +import static android.view.View.VISIBLE; +import static org.adaway.ui.Animations.hideView; +import static org.adaway.ui.Animations.showView; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.ViewModelProvider; + +import org.adaway.R; +import org.adaway.databinding.WelcomeSyncLayoutBinding; +import org.adaway.model.error.HostError; +import org.adaway.ui.home.HomeViewModel; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * This class is a fragment to first sync the main hosts source. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class WelcomeSyncFragment extends WelcomeFragment { + private WelcomeSyncLayoutBinding binding; + private HomeViewModel homeViewModel; + private ActivityResultLauncher activityResultLauncher; + private boolean requestPostNotificationsPermission; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + this.binding = WelcomeSyncLayoutBinding.inflate(inflater, container, false); + this.activityResultLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {}); + bindRetry(); + bindNotifications(); + + this.homeViewModel = new ViewModelProvider(this).get(HomeViewModel.class); + LifecycleOwner lifecycleOwner = getViewLifecycleOwner(); + this.homeViewModel.isAdBlocked().observe(lifecycleOwner, adBlocked -> { + if (adBlocked) { + notifySynced(); + } + }); + this.homeViewModel.getError().observe(lifecycleOwner, this::notifyError); + this.homeViewModel.sync(); + + return this.binding.getRoot(); + } + + private void bindRetry() { + this.binding.retryImageView.setOnClickListener(this::retry); + this.binding.errorTextView.setOnClickListener(this::retry); + } + + private void bindNotifications() { + if (SDK_INT < TIRAMISU || requireActivity().checkSelfPermission(POST_NOTIFICATIONS) == PERMISSION_GRANTED) { + this.requestPostNotificationsPermission = false; + } else { + this.binding.notificationsTextView.setVisibility(VISIBLE); + this.requestPostNotificationsPermission = true; + new Timer(true).schedule(new TimerTask() { + @Override + public void run() { + requestPostNotificationsPermission(); + } + }, 10_000); + } + } + + private void notifySynced() { + this.homeViewModel.enableAllSources(); + this.binding.headerTextView.setText(R.string.welcome_synced_header); + hideView(this.binding.progressBar); + showView(this.binding.syncedImageView); + allowNext(); + requestPostNotificationsPermission(); + } + + private void notifyError(HostError error) { + String errorMessage = getResources().getText(error.getMessageKey()).toString(); + String syncError = getResources().getText(R.string.welcome_sync_error).toString(); + String retryMessage = String.format(syncError, errorMessage); + this.binding.errorTextView.setText(retryMessage); + hideView(this.binding.progressBar); + showView(this.binding.errorImageView); + showView(this.binding.retryImageView); + showView(this.binding.errorTextView); + } + + private void retry(@SuppressWarnings("unused") View view) { + hideView(this.binding.errorImageView); + hideView(this.binding.retryImageView); + hideView(this.binding.errorTextView); + showView(this.binding.progressBar); + this.homeViewModel.sync(); + } + + private void requestPostNotificationsPermission() { + if (SDK_INT >= TIRAMISU && this.requestPostNotificationsPermission) { + this.requestPostNotificationsPermission = false; + this.activityResultLauncher.launch(POST_NOTIFICATIONS); + } + } +} diff --git a/app/src/main/java/org/adaway/util/AppExecutors.java b/app/src/main/java/org/adaway/util/AppExecutors.java new file mode 100644 index 0000000..684a455 --- /dev/null +++ b/app/src/main/java/org/adaway/util/AppExecutors.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.adaway.util; + +import android.os.Handler; +import android.os.Looper; + +import androidx.annotation.NonNull; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +/** + * Global executor pools for the whole application. + *

    + * Grouping tasks like this avoids the effects of task starvation (e.g. disk reads don't wait behind + * webservice requests). + * Source: https://github.com/googlecodelabs/android-build-an-app-architecture-components/blob/7364e9013419952b00aa582553aa1466c1a1dede/app/src/main/java/com/example/android/sunshine/AppExecutors.java + */ +public class AppExecutors { + + // For Singleton instantiation + private static final Object LOCK = new Object(); + private static AppExecutors sInstance; + private final Executor diskIO; + private final Executor mainThread; + private final Executor networkIO; + + private AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) { + this.diskIO = diskIO; + this.networkIO = networkIO; + this.mainThread = mainThread; + } + + public static AppExecutors getInstance() { + if (sInstance == null) { + synchronized (LOCK) { + sInstance = new AppExecutors( + Executors.newSingleThreadExecutor(), + Executors.newFixedThreadPool(3), + new MainThreadExecutor() + ); + } + } + return sInstance; + } + + public Executor diskIO() { + return diskIO; + } + + public Executor networkIO() { + return networkIO; + } + + public Executor mainThread() { + return mainThread; + } + + private static class MainThreadExecutor implements Executor { + private Handler mainThreadHandler = new Handler(Looper.getMainLooper()); + + @Override + public void execute(@NonNull Runnable command) { + mainThreadHandler.post(command); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/adaway/util/Clipboard.java b/app/src/main/java/org/adaway/util/Clipboard.java new file mode 100644 index 0000000..fbbdded --- /dev/null +++ b/app/src/main/java/org/adaway/util/Clipboard.java @@ -0,0 +1,38 @@ +package org.adaway.util; + +import static android.widget.Toast.LENGTH_SHORT; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.widget.Toast; + +import org.adaway.R; + +/** + * This class manages the clipboard interactions. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class Clipboard { + private Clipboard() { + + } + + /** + * Copy a host into the clipboard for the user. + * + * @param context The application context. + * @param host The host to copy to the clipboard + */ + public static void copyHostToClipboard(Context context, String host) { + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = ClipData.newPlainText("Host", host); + clipboard.setPrimaryClip(clipData); + Toast.makeText( + context, + context.getString(R.string.clipboard_host_copied), + LENGTH_SHORT + ).show(); + } +} diff --git a/app/src/main/java/org/adaway/util/Constants.java b/app/src/main/java/org/adaway/util/Constants.java new file mode 100644 index 0000000..31d1305 --- /dev/null +++ b/app/src/main/java/org/adaway/util/Constants.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.util; + +public class Constants { + public static final String PREFS_NAME = "preferences"; + + public static final String LOCALHOST_IPV4 = "127.0.0.1"; + public static final String LOCALHOST_IPV6 = "::1"; + public static final String BOGUS_IPV4 = "0.0.0.0"; + public static final String LOCALHOST_HOSTNAME = "localhost"; + + public static final String HOSTS_FILENAME = "hosts"; + public static final String DEFAULT_HOSTS_FILENAME = "default_hosts"; + public static final String LINE_SEPARATOR = System.getProperty("line.separator", "\n"); + + public static final String COMMAND_CHOWN = "chown 0:0"; + public static final String COMMAND_CHMOD_644 = "chmod 644"; + + public static final String ANDROID_SYSTEM_ETC_HOSTS = "/system/etc/" + HOSTS_FILENAME; +} diff --git a/app/src/main/java/org/adaway/util/RegexUtils.java b/app/src/main/java/org/adaway/util/RegexUtils.java new file mode 100644 index 0000000..495aa2a --- /dev/null +++ b/app/src/main/java/org/adaway/util/RegexUtils.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.util; + +import com.google.common.net.InetAddresses; +import com.google.common.net.InternetDomainName; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import timber.log.Timber; + +public class RegexUtils { + private static final Pattern WILDCARD_PATTERN = Pattern.compile("[*?]"); + + /** + * Check whether a hostname is valid. + * + * @param hostname The hostname to validate. + * @return return {@code true} if hostname is valid, {@code false} otherwise. + */ + public static boolean isValidHostname(String hostname) { + return InternetDomainName.isValid(hostname); + } + + /** + * Check whether a wildcard hostname is valid. + * Wildcard hostname is an hostname with one of the following wildcard: + *

      + *
    • {@code *} for any character sequence,
    • + *
    • {@code ?} for any character
    • + *
    + *

    + * Wildcard validation is quite tricky, because wildcards can be placed anywhere and can match with + * anything. To make sure we don't dismiss certain valid wildcard host names, we trim wildcards + * or replace them with an alphanumeric character for further validation.
    + * We only reject whitelist host names which cannot match against valid host names under any circumstances. + * + * @param hostname The wildcard hostname to validate. + * @return return {@code true} if wildcard hostname is valid, {@code false} otherwise. + */ + public static boolean isValidWildcardHostname(String hostname) { + // Clear wildcards from host name then validate it + Matcher matcher = WILDCARD_PATTERN.matcher(hostname); + String clearedHostname = matcher.replaceAll(""); + // Replace wildcards from host name by an alphanumeric character + String replacedHostname = matcher.replaceAll("a"); + // Check if any hostname is valid + return isValidHostname(clearedHostname) || isValidHostname(replacedHostname); + } + + /** + * Check if an IP address is valid. + * + * @param ip The IP to validate. + * @return {@code true} if the IP is valid, {@code false} otherwise. + */ + public static boolean isValidIP(String ip) { + try { + InetAddresses.forString(ip); + return true; + } catch (IllegalArgumentException exception) { + Timber.d(exception, "Invalid IP address: %s.", ip); + return false; + } + } + + /* + * Transforms String with * and ? characters to regex String, convert "example*.*" to regex + * "^example.*\\..*$", from http://www.rgagnon.com/javadetails/java-0515.html + */ + public static String wildcardToRegex(String wildcard) { + StringBuilder regex = new StringBuilder(wildcard.length()); + regex.append('^'); + for (int i = 0, is = wildcard.length(); i < is; i++) { + char c = wildcard.charAt(i); + switch (c) { + case '*': + regex.append(".*"); + break; + case '?': + regex.append("."); + break; + // escape special regex-characters + case '(': + case ')': + case '[': + case ']': + case '$': + case '^': + case '.': + case '{': + case '}': + case '|': + case '\\': + regex.append("\\"); + regex.append(c); + break; + default: + regex.append(c); + break; + } + } + regex.append('$'); + return regex.toString(); + } +} diff --git a/app/src/main/java/org/adaway/util/WebServerUtils.java b/app/src/main/java/org/adaway/util/WebServerUtils.java new file mode 100644 index 0000000..54a6ab0 --- /dev/null +++ b/app/src/main/java/org/adaway/util/WebServerUtils.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2011-2012 Dominik Schürmann + * + * This file is part of AdAway. + * + * AdAway is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AdAway is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AdAway. If not, see . + * + */ + +package org.adaway.util; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.res.AssetManager; +import android.net.Uri; +import android.security.KeyChain; +import android.view.ContextThemeWrapper; + +import androidx.annotation.StringRes; + +import org.adaway.R; +import org.adaway.helper.PreferenceHelper; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ConnectException; +import java.nio.file.Files; +import java.nio.file.Path; + +import javax.net.ssl.SSLHandshakeException; +import javax.security.cert.CertificateException; +import javax.security.cert.X509Certificate; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import timber.log.Timber; + +import static org.adaway.model.root.ShellUtils.isBundledExecutableRunning; +import static org.adaway.model.root.ShellUtils.killBundledExecutable; +import static org.adaway.model.root.ShellUtils.runBundledExecutable; + +/** + * This class is an utility class to control web server execution. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class WebServerUtils { + public static final String TEST_URL = "https://localhost/internal-test"; + private static final String WEB_SERVER_EXECUTABLE = "webserver"; + private static final String LOCALHOST_CERTIFICATE = "localhost-2410.crt"; + private static final String LOCALHOST_CERTIFICATE_KEY = "localhost-2410.key"; + + /** + * Start the web server in new thread with RootTools + * + * @param context The application context. + */ + public static void startWebServer(Context context) { + Timber.d("Starting web server…"); + + Path resourcePath = context.getFilesDir().toPath().resolve(WEB_SERVER_EXECUTABLE); + inflateResources(context, resourcePath); + + String parameters = "--resources " + resourcePath.toAbsolutePath() + + (PreferenceHelper.getWebServerIcon(context) ? " --icon" : "") + + " > /dev/null 2>&1"; + runBundledExecutable(context, WEB_SERVER_EXECUTABLE, parameters); + } + + /** + * Stop the web server. + */ + public static void stopWebServer() { + killBundledExecutable(WEB_SERVER_EXECUTABLE); + } + + /** + * Checks if web server is running + * + * @return true if webs server is running, false otherwise. + */ + public static boolean isWebServerRunning() { + return isBundledExecutableRunning(WEB_SERVER_EXECUTABLE); + } + + /** + * Get the web server state description. + * + * @return The web server state description. + */ + @StringRes + public static int getWebServerState() { + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder() + .url(TEST_URL) + .build(); + try (Response response = client.newCall(request).execute()) { + return response.isSuccessful() ? + R.string.pref_webserver_state_running_and_installed : + R.string.pref_webserver_state_not_running; + } catch (SSLHandshakeException e) { + return R.string.pref_webserver_state_running_not_installed; + } catch (ConnectException e) { + return R.string.pref_webserver_state_not_running; + } catch (IOException e) { + Timber.w(e, "Failed to test web server."); + return R.string.pref_webserver_state_not_running; + } + } + + /** + * Prompt user to install web server certificate. + * + * @param context The application context. + */ + public static void installCertificate(Context context) { + AssetManager assetManager = context.getAssets(); + try (InputStream inputStream = assetManager.open(LOCALHOST_CERTIFICATE); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int read; + while ((read = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, read); + } + byte[] bytes = outputStream.toByteArray(); + X509Certificate x509 = X509Certificate.getInstance(bytes); + Intent intent = KeyChain.createInstallIntent(); + intent.putExtra(KeyChain.EXTRA_CERTIFICATE, x509.getEncoded()); + intent.putExtra(KeyChain.EXTRA_NAME, "AdAway"); + context.startActivity(intent); + } catch (IOException e) { + Timber.w(e, "Failed to read certificate."); + } catch (CertificateException e) { + Timber.w(e, "Failed to parse certificate."); + } + } + + public static void copyCertificate(ContextThemeWrapper wrapper, Uri uri) { + ContentResolver contentResolver = wrapper.getContentResolver(); + AssetManager assetManager = wrapper.getAssets(); + try (InputStream inputStream = assetManager.open(LOCALHOST_CERTIFICATE); + OutputStream outputStream = contentResolver.openOutputStream(uri)) { + if (outputStream == null) { + throw new IOException("Failed to open "+uri); + } + byte[] buffer = new byte[1024]; + int read; + while ((read = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, read); + } + } catch (IOException e) { + Timber.w(e, "Failed to copy certificate."); + } + } + + private static void inflateResources(Context context, Path target) { + AssetManager assetManager = context.getAssets(); + try { + inflateResource(assetManager, LOCALHOST_CERTIFICATE, target); + inflateResource(assetManager, LOCALHOST_CERTIFICATE_KEY, target); + inflateResource(assetManager, "icon.svg", target); + inflateResource(assetManager, "test.html", target); + } catch (IOException e) { + Timber.w(e, "Failed to inflate web server resources."); + } + } + + private static void inflateResource(AssetManager assetManager, String resource, Path target) throws IOException { + if (!Files.isDirectory(target)) { + Files.createDirectories(target); + } + Path targetFile = target.resolve(resource); + if (!Files.isRegularFile(targetFile)) { + Files.copy(assetManager.open(resource), targetFile); + } + } +} diff --git a/app/src/main/java/org/adaway/util/log/ApplicationLog.java b/app/src/main/java/org/adaway/util/log/ApplicationLog.java new file mode 100644 index 0000000..6d0ed8e --- /dev/null +++ b/app/src/main/java/org/adaway/util/log/ApplicationLog.java @@ -0,0 +1,44 @@ +package org.adaway.util.log; + +import android.app.Application; +import android.content.Context; +import android.content.pm.ApplicationInfo; + +import com.topjohnwu.superuser.Shell; + +import org.adaway.helper.PreferenceHelper; + +import timber.log.Timber; + +/** + * This class is an utility class that configures the application log. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class ApplicationLog { + /** + * Private constructor. + */ + private ApplicationLog() { + + } + + /** + * Initialize application logging. + * + * @param application The application instance. + */ + public static void init(Application application) { + if (isApplicationDebuggable(application) || PreferenceHelper.getDebugEnabled(application)) { + Shell.enableVerboseLogging = true; + Timber.plant(new Timber.DebugTree()); + } else { + Shell.enableVerboseLogging = false; + SentryLog.init(application); + } + } + + private static boolean isApplicationDebuggable(Context context) { + return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + } +} diff --git a/app/src/main/java/org/adaway/util/log/SentryLog.java b/app/src/main/java/org/adaway/util/log/SentryLog.java new file mode 100644 index 0000000..1af31be --- /dev/null +++ b/app/src/main/java/org/adaway/util/log/SentryLog.java @@ -0,0 +1,81 @@ +package org.adaway.util.log; + +import static io.sentry.SentryLevel.ERROR; +import static io.sentry.SentryLevel.INFO; + +import android.app.Application; + +import org.adaway.helper.PreferenceHelper; + +import io.sentry.Breadcrumb; +import io.sentry.Sentry; +import io.sentry.android.core.SentryAndroid; +import io.sentry.android.fragment.FragmentLifecycleIntegration; +import io.sentry.android.timber.SentryTimberIntegration; + +/** + * This class is a helper to initialize and configuration Sentry. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class SentryLog { + /** + * Private constructor. + */ + private SentryLog() { + + } + + /** + * Initialize Sentry logging client according user preferences. + * + * @param application The application instance. + */ + public static void init(Application application) { + setEnabled(application, PreferenceHelper.getTelemetryEnabled(application)); + } + + /** + * Initialize Sentry logging client. + * + * @param application The application instance. + * @param enabled Whether the application is allowed to send events to Sentry or not. + */ + public static void setEnabled(Application application, boolean enabled) { + if (enabled) { + // Initialize sentry client manually and bind it to logging + SentryAndroid.init(application, options -> { + options.addIntegration(new SentryTimberIntegration(ERROR, INFO)); + options.addIntegration(new FragmentLifecycleIntegration(application, true, false)); + }); + } + } + + /** + * Record a breadcrumb. + * + * @param message The breadcrumb message. + */ + public static void recordBreadcrumb(String message) { + Sentry.configureScope(scope -> { + Breadcrumb breadcrumb = new Breadcrumb(); + breadcrumb.setMessage(message); + breadcrumb.setLevel(INFO); + scope.addBreadcrumb(breadcrumb); + }); + } + + /** + * Check if {@link Sentry} implementation is a stub or not. + * + * @return {@code true} if the runtime implementation is a stub, {@code false} otherwise. + */ + public static boolean isStub() { + try { + Sentry.class.getDeclaredField("STUB"); + return true; + } catch (NoSuchFieldException exception) { + return false; + } + } +} diff --git a/app/src/main/java/org/adaway/vpn/VpnService.java b/app/src/main/java/org/adaway/vpn/VpnService.java new file mode 100644 index 0000000..8f1ac03 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/VpnService.java @@ -0,0 +1,371 @@ +/* + * Derived from dns66: + * Copyright (C) 2016-2019 Julian Andres Klode + * + * Derived from AdBuster: + * Copyright (C) 2016 Daniel Brodie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * Contributions shall also be provided under any later versions of the + * GPL. + */ +package org.adaway.vpn; + +import static android.Manifest.permission.POST_NOTIFICATIONS; +import static android.app.NotificationManager.IMPORTANCE_LOW; +import static android.app.PendingIntent.FLAG_IMMUTABLE; +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static org.adaway.broadcast.Command.START; +import static org.adaway.broadcast.Command.STOP; +import static org.adaway.broadcast.CommandReceiver.SEND_COMMAND_ACTION; +import static org.adaway.helper.NotificationHelper.VPN_RESUME_SERVICE_NOTIFICATION_ID; +import static org.adaway.helper.NotificationHelper.VPN_RUNNING_SERVICE_NOTIFICATION_ID; +import static org.adaway.helper.NotificationHelper.VPN_SERVICE_NOTIFICATION_CHANNEL; +import static org.adaway.vpn.VpnService.NetworkType.CELLULAR; +import static org.adaway.vpn.VpnService.NetworkType.WIFI; +import static org.adaway.vpn.VpnStatus.RECONNECTING; +import static org.adaway.vpn.VpnStatus.RUNNING; +import static org.adaway.vpn.VpnStatus.STARTING; +import static org.adaway.vpn.VpnStatus.STOPPED; +import static org.adaway.vpn.VpnStatus.WAITING_FOR_NETWORK; +import static java.util.Objects.requireNonNull; + +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import org.adaway.R; +import org.adaway.broadcast.Command; +import org.adaway.broadcast.CommandReceiver; +import org.adaway.helper.PreferenceHelper; +import org.adaway.ui.home.HomeActivity; +import org.adaway.vpn.worker.VpnWorker; + +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.Set; + +import timber.log.Timber; + +/** + * This class is the VPN platform service implementation. + *

    + * it is in charge of: + *

      + *
    • Accepting service commands,
    • + *
    • Starting / stopping the {@link VpnWorker} thread,
    • + *
    • Publishing notifications and intent about the VPN state,
    • + *
    • Reacting to network connectivity changes.
    • + *
    + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class VpnService extends android.net.VpnService implements Handler.Callback { + public static final String VPN_UPDATE_STATUS_INTENT = "org.jak_linux.dns66.VPN_UPDATE_STATUS"; + public static final String VPN_UPDATE_STATUS_EXTRA = "VPN_STATUS"; + /* + * Notification intent related. + */ + private static final int REQUEST_CODE_START = 43; + private static final int REQUEST_CODE_PAUSE = 42; + /* + * Handler related. + */ + private static final int VPN_STATUS_UPDATE_MESSAGE_TYPE = 0; + + private final MyHandler handler; + private final NetworkTypeCallback wifiNetworkCallback; + private final NetworkTypeCallback cellularNetworkCallback; + private final Set availableNetworkTypes; + private final VpnWorker vpnWorker; + + /** + * Constructor. + */ + public VpnService() { + this.handler = new MyHandler(this); + this.wifiNetworkCallback = new NetworkTypeCallback(WIFI); + this.cellularNetworkCallback = new NetworkTypeCallback(CELLULAR); + this.availableNetworkTypes = new HashSet<>(); + this.vpnWorker = new VpnWorker(this); + } + + /* + * VPN Service. + */ + + @Override + public void onCreate() { + Timber.d("Creating VPN service…"); + registerNetworkCallback(); + } + + @Override + public int onStartCommand(@Nullable Intent intent, int flags, int startId) { + Timber.d("onStartCommand %s", intent == null ? "null intent" : intent); + // Check null intent that happens when system restart the service + // https://developer.android.com/reference/android/app/Service#START_STICKY + Command command = intent == null ? + START : + Command.readFromIntent(intent); + switch (command) { + case START: + startVpn(); + return START_STICKY; + case STOP: + stopVpn(); + return START_NOT_STICKY; + default: + Timber.w("Unknown command: %s", command); + return START_NOT_STICKY; + } + } + + @Override + public void onDestroy() { + Timber.d("Destroying VPN service…"); + unregisterNetworkCallback(); + Timber.d("Destroyed VPN service."); + } + + /* + * Handler callback. + */ + + @Override + public boolean handleMessage(@NonNull Message message) { + if (message.what == VPN_STATUS_UPDATE_MESSAGE_TYPE) { + updateVpnStatus(VpnStatus.fromCode(message.arg1)); + } + return true; + } + + /** + * Notify a of the new VPN status. + * + * @param status The new VPN status. + */ + public void notifyVpnStatus(VpnStatus status) { + Message statusMessage = this.handler.obtainMessage(VPN_STATUS_UPDATE_MESSAGE_TYPE, status.toCode(), 0); + this.handler.sendMessage(statusMessage); + } + + private void startVpn() { + Timber.d("Starting VPN service…"); + PreferenceHelper.setVpnServiceStatus(this, RUNNING); + updateVpnStatus(STARTING); + this.vpnWorker.start(); + Timber.i("VPN service started."); + } + + private void stopVpn() { + Timber.d("Stopping VPN service…"); + PreferenceHelper.setVpnServiceStatus(this, STOPPED); + this.vpnWorker.stop(); + stopForeground(true); + stopSelf(); + updateVpnStatus(STOPPED); + Timber.i("VPN service stopped."); + } + + private void waitForNetVpn() { + this.vpnWorker.stop(); + updateVpnStatus(WAITING_FOR_NETWORK); + } + + private void reconnect() { + updateVpnStatus(RECONNECTING); + this.vpnWorker.start(); + } + + private void updateVpnStatus(VpnStatus status) { + Notification notification = getNotification(status); + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); + switch (status) { + case STARTING: + case RUNNING: + notificationManager.cancel(VPN_RESUME_SERVICE_NOTIFICATION_ID); + startForeground(VPN_RUNNING_SERVICE_NOTIFICATION_ID, notification); + break; + default: + if (checkSelfPermission(POST_NOTIFICATIONS) == PERMISSION_GRANTED) { + notificationManager.notify(VPN_RESUME_SERVICE_NOTIFICATION_ID, notification); + } + } + + // TODO BUG - Nobody is listening to this intent + // TODO BUG - VpnModel can lister to it to update the MainActivity according its current state + Intent intent = new Intent(VPN_UPDATE_STATUS_INTENT); + intent.putExtra(VPN_UPDATE_STATUS_EXTRA, status); + LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + } + + private Notification getNotification(VpnStatus status) { + String title = getString(R.string.vpn_notification_title, getString(status.getTextResource())); + + Intent intent = new Intent(getApplicationContext(), HomeActivity.class); + intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); + PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, FLAG_IMMUTABLE); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, VPN_SERVICE_NOTIFICATION_CHANNEL) + .setPriority(IMPORTANCE_LOW) + .setContentIntent(contentIntent) + .setSmallIcon(R.drawable.logo) + .setColorized(true) + .setColor(getColor(R.color.notification)) + .setContentTitle(title); + switch (status) { + case RUNNING: + Intent stopIntent = new Intent(this, CommandReceiver.class) + .setAction(SEND_COMMAND_ACTION); + STOP.appendToIntent(stopIntent); + PendingIntent stopActionIntent = PendingIntent.getBroadcast(this, REQUEST_CODE_PAUSE, stopIntent, FLAG_IMMUTABLE); + builder.addAction( + R.drawable.ic_pause_24dp, + getString(R.string.vpn_notification_action_pause), + stopActionIntent + ).setOngoing(true); + break; + case STOPPED: + Intent startIntent = new Intent(this, CommandReceiver.class) + .setAction(SEND_COMMAND_ACTION); + START.appendToIntent(startIntent); + PendingIntent startActionIntent = PendingIntent.getBroadcast(this, REQUEST_CODE_START, startIntent, FLAG_IMMUTABLE); + builder.addAction( + 0, + getString(R.string.vpn_notification_action_resume), + startActionIntent + ); + break; + } + return builder.build(); + } + + private void registerNetworkCallback() { + ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); + NetworkRequest wifiNetworkRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .build(); + NetworkRequest cellularNetworkRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .build(); + initializeNetworkTypes(connectivityManager); + connectivityManager.registerNetworkCallback(wifiNetworkRequest, this.wifiNetworkCallback, this.handler); + connectivityManager.registerNetworkCallback(cellularNetworkRequest, this.cellularNetworkCallback, this.handler); + + } + + private void unregisterNetworkCallback() { + ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); + connectivityManager.unregisterNetworkCallback(this.wifiNetworkCallback); + connectivityManager.unregisterNetworkCallback(this.cellularNetworkCallback); + } + + private void initializeNetworkTypes(ConnectivityManager connectivityManager) { + this.availableNetworkTypes.clear(); + Network activeNetwork = connectivityManager.getActiveNetwork(); + if (activeNetwork != null) { + NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork); + if (networkCapabilities != null) { + if (networkCapabilities.hasTransport(TRANSPORT_WIFI)) { + this.availableNetworkTypes.add(WIFI); + } + if (networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { + this.availableNetworkTypes.add(CELLULAR); + } + } + } + Timber.d("Initial network types: %s ", this.availableNetworkTypes); + } + + private void addNetworkType(NetworkType type) { + boolean noNetwork = this.availableNetworkTypes.isEmpty(); + this.availableNetworkTypes.add(type); + if (noNetwork) { + Timber.d("Reconnecting VPN on network %s.", type); + reconnect(); + } + } + + private void removeNetworkType(NetworkType type) { + this.availableNetworkTypes.remove(type); + if (this.availableNetworkTypes.isEmpty()) { + Timber.d("Waiting for network…"); + waitForNetVpn(); + } else { + reconnect(); + } + } + + /** + * This class receives network change events to monitor network type available. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + * @see
    Android Developer Documentation + */ + private class NetworkTypeCallback extends NetworkCallback { + private final NetworkType monitoredType; + + NetworkTypeCallback(NetworkType monitoredType) { + this.monitoredType = monitoredType; + } + + @Override + public void onAvailable(@NonNull Network network) { + Timber.d("On available %s", this.monitoredType); + addNetworkType(this.monitoredType); + } + + @Override + public void onLost(@NonNull Network network) { + Timber.d("On lost %s", this.monitoredType); + removeNetworkType(this.monitoredType); + } + } + + enum NetworkType { + CELLULAR, + WIFI, + } + + /* The handler may only keep a weak reference around, otherwise it leaks */ + private static class MyHandler extends Handler { + + private final WeakReference callback; + + MyHandler(Callback callback) { + super(requireNonNull(Looper.myLooper())); + this.callback = new WeakReference<>(callback); + } + + @Override + public void handleMessage(@NonNull Message msg) { + Callback callback = this.callback.get(); + if (callback != null) { + callback.handleMessage(msg); + } + super.handleMessage(msg); + } + } +} diff --git a/app/src/main/java/org/adaway/vpn/VpnServiceControls.java b/app/src/main/java/org/adaway/vpn/VpnServiceControls.java new file mode 100644 index 0000000..81e3ce9 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/VpnServiceControls.java @@ -0,0 +1,100 @@ +package org.adaway.vpn; + +import static android.content.Context.CONNECTIVITY_SERVICE; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static org.adaway.broadcast.Command.START; +import static org.adaway.broadcast.Command.STOP; +import static org.adaway.vpn.VpnStatus.STOPPED; + +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; + +import org.adaway.helper.PreferenceHelper; + +import java.util.Arrays; +import java.util.Objects; + +/** + * This utility class allows controlling (start and stop) the AdAway VPN service. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public final class VpnServiceControls { + /** + * Private constructor. + */ + private VpnServiceControls() { + + } + + /** + * Check if the VPN service is currently running. + * + * @param context The application context. + * @return {@code true} if the VPN service is currently running, {@code false} otherwise. + */ + public static boolean isRunning(Context context) { + boolean networkVpnCapability = checkAnyNetworkVpnCapability(context); + VpnStatus status = PreferenceHelper.getVpnServiceStatus(context); + if (status.isStarted() && !networkVpnCapability) { + status = STOPPED; + PreferenceHelper.setVpnServiceStatus(context, status); + } + return status.isStarted(); + } + + /** + * Check if the VPN service is started. + * + * @param context The application context. + * @return {@code true} if the VPN service is started, {@code false} otherwise. + */ + public static boolean isStarted(Context context) { + return PreferenceHelper.getVpnServiceStatus(context).isStarted(); + } + + /** + * Start the VPN service. + * + * @param context The application context. + * @return {@code true} if the service is started, {@code false} otherwise. + */ + public static boolean start(Context context) { + // Check if VPN is already running + if (isRunning(context)) { + return true; + } + // Start the VPN service + Intent intent = new Intent(context, VpnService.class); + START.appendToIntent(intent); + boolean started = context.startForegroundService(intent) != null; + if (started) { + // Start the heartbeat + VpnServiceHeartbeat.start(context); + } + return started; + } + + /** + * Stop the VPN service. + * + * @param context The application context. + */ + public static void stop(Context context) { + // Stop the heartbeat + VpnServiceHeartbeat.stop(context); + // Stop the service + Intent intent = new Intent(context, VpnService.class); + STOP.appendToIntent(intent); + context.startService(intent); + } + + private static boolean checkAnyNetworkVpnCapability(Context context) { + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE); + return Arrays.stream(connectivityManager.getAllNetworks()) + .map(connectivityManager::getNetworkCapabilities) + .filter(Objects::nonNull) + .anyMatch(networkCapabilities -> networkCapabilities.hasTransport(TRANSPORT_VPN)); + } +} diff --git a/app/src/main/java/org/adaway/vpn/VpnServiceHeartbeat.java b/app/src/main/java/org/adaway/vpn/VpnServiceHeartbeat.java new file mode 100644 index 0000000..1f0b478 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/VpnServiceHeartbeat.java @@ -0,0 +1,92 @@ +package org.adaway.vpn; + +import static android.content.Context.ACTIVITY_SERVICE; +import static androidx.work.ExistingPeriodicWorkPolicy.KEEP; +import static androidx.work.ListenableWorker.Result.success; +import static java.lang.Integer.MAX_VALUE; +import static java.util.concurrent.TimeUnit.MINUTES; + +import android.app.ActivityManager; +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.work.Constraints; +import androidx.work.NetworkType; +import androidx.work.PeriodicWorkRequest; +import androidx.work.WorkManager; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import timber.log.Timber; + +/** + * This class is a worker to monitor the {@link VpnService} is still running. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class VpnServiceHeartbeat extends Worker { + /** + * The VPN service heartbeat unique worker name. + */ + private static final String WORK_NAME = "vpnHeartbeat"; + + /** + * Constructor. + * + * @param context The application context. + * @param workerParams The worker parameters. + */ + public VpnServiceHeartbeat(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + } + + @NonNull + @Override + public Result doWork() { + Context context = getApplicationContext(); + if (VpnServiceControls.isStarted(context) && !isVpnServiceRunning()) { + Timber.i("VPN service is not running. Starting VPN service…"); + VpnServiceControls.start(context); + Timber.i("VPN service started."); + } + return success(); + } + + // TODO Use VpnServiceControls.isVpnServiceRunning instead? + private boolean isVpnServiceRunning() { + String serviceName = VpnService.class.getName(); + ActivityManager manager = (ActivityManager) getApplicationContext().getSystemService(ACTIVITY_SERVICE); + // Deprecated as it only return application service. It is fine for this use case. + for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(MAX_VALUE)) { + if (serviceName.equals(service.service.getClassName())) { + return true; + } + } + return false; + } + + /** + * Start the VPN service monitor. + * + * @param context The application context. + */ + public static void start(Context context) { + PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(VpnServiceHeartbeat.class, 15, MINUTES) + .addTag("VPN-heartbeat") + .setConstraints(new Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + ) + .build(); + WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_NAME, KEEP, workRequest); + } + + /** + * Stop the VPN service monitor. + * + * @param context The application context. + */ + public static void stop(Context context) { + WorkManager.getInstance(context).cancelUniqueWork(WORK_NAME); + } +} diff --git a/app/src/main/java/org/adaway/vpn/VpnStatus.java b/app/src/main/java/org/adaway/vpn/VpnStatus.java new file mode 100644 index 0000000..4105913 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/VpnStatus.java @@ -0,0 +1,47 @@ +package org.adaway.vpn; + +import androidx.annotation.StringRes; + +import org.adaway.R; + +import java.util.Arrays; + +public enum VpnStatus { + STARTING(10, R.string.vpn_notification_starting), + RUNNING(11, R.string.vpn_notification_running), + STOPPING(20, R.string.vpn_notification_stopping), + WAITING_FOR_NETWORK(21, R.string.vpn_notification_waiting_for_net), + RECONNECTING(22, R.string.vpn_notification_reconnecting), + RECONNECTING_NETWORK_ERROR(23, R.string.vpn_notification_reconnecting_error), + STOPPED(0, R.string.vpn_notification_stopped); + + private final int code; + + @StringRes + private final int textResource; + + VpnStatus(int code, @StringRes int textResource) { + this.code = code; + this.textResource = textResource; + } + + public static VpnStatus fromCode(int code) { + return Arrays.stream(VpnStatus.values()) + .filter(vpnStatus -> vpnStatus.code == code) + .findAny() + .orElse(STOPPED); + } + + @StringRes + public int getTextResource() { + return this.textResource; + } + + public int toCode() { + return this.code; + } + + public boolean isStarted() { + return this != STOPPED; + } +} diff --git a/app/src/main/java/org/adaway/vpn/dns/DnsPacketProxy.java b/app/src/main/java/org/adaway/vpn/dns/DnsPacketProxy.java new file mode 100644 index 0000000..e0703a1 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/dns/DnsPacketProxy.java @@ -0,0 +1,278 @@ +/* + * Derived from dns66: + * Copyright (C) 2016-2019 Julian Andres Klode + * + * Derived from AdBuster: + * Copyright (C) 2016 Daniel Brodie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * Contributions shall also be provided under any later versions of the + * GPL. + */ +package org.adaway.vpn.dns; + +import android.content.Context; + +import org.adaway.AdAwayApplication; +import org.adaway.db.entity.HostEntry; +import org.adaway.db.entity.ListType; +import org.adaway.model.vpn.VpnModel; +import org.pcap4j.packet.IpPacket; +import org.pcap4j.packet.IpSelector; +import org.pcap4j.packet.IpV4Packet; +import org.pcap4j.packet.IpV6Packet; +import org.pcap4j.packet.Packet; +import org.pcap4j.packet.UdpPacket; +import org.pcap4j.packet.UnknownPacket; +import org.pcap4j.packet.namednumber.IpNumber; +import org.xbill.DNS.AAAARecord; +import org.xbill.DNS.ARecord; +import org.xbill.DNS.DClass; +import org.xbill.DNS.Flags; +import org.xbill.DNS.Message; +import org.xbill.DNS.Name; +import org.xbill.DNS.Rcode; +import org.xbill.DNS.Record; +import org.xbill.DNS.SOARecord; +import org.xbill.DNS.Section; +import org.xbill.DNS.TextParseException; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Locale; +import java.util.Optional; +import java.util.function.Consumer; + +import timber.log.Timber; + +/** + * Creates and parses packets, and sends packets to a remote socket or the device using VpnWorker. + */ +public class DnsPacketProxy { + // Choose a value that is smaller than the time needed to unblock a host. + private static final int NEGATIVE_CACHE_TTL_SECONDS = 5; + private static final SOARecord NEGATIVE_CACHE_SOA_RECORD; + + static { + try { + // Let's use a guaranteed invalid hostname here, clients are not supposed to use + // our fake values, the whole thing just exists for negative caching. + Name name = new Name("adaway.vpn.invalid."); + NEGATIVE_CACHE_SOA_RECORD = new SOARecord(name, DClass.IN, NEGATIVE_CACHE_TTL_SECONDS, + name, name, 0, 0, 0, 0, NEGATIVE_CACHE_TTL_SECONDS); + } catch (TextParseException e) { + throw new RuntimeException(e); + } + } + + private final EventLoop eventLoop; + private final DnsServerMapper dnsServerMapper; + private VpnModel vpnModel; + + public DnsPacketProxy(EventLoop eventLoop, DnsServerMapper dnsServerMapper) { + this.eventLoop = eventLoop; + this.dnsServerMapper = dnsServerMapper; + } + + /** + * Initializes the rules database and the list of upstream servers. + * + * @param context The context we are operating in (for the database). + */ + public void initialize(Context context) { + this.vpnModel = (VpnModel) ((AdAwayApplication) context.getApplicationContext()).getAdBlockModel(); + } + + /** + * Handles a responsePayload from an upstream DNS server + * + * @param requestPacket The original request packet + * @param responsePayload The payload of the response + */ + public void handleDnsResponse(IpPacket requestPacket, byte[] responsePayload) { + UdpPacket udpOutPacket = (UdpPacket) requestPacket.getPayload(); + UdpPacket.Builder payLoadBuilder = new UdpPacket.Builder(udpOutPacket) + .srcPort(udpOutPacket.getHeader().getDstPort()) + .dstPort(udpOutPacket.getHeader().getSrcPort()) + .srcAddr(requestPacket.getHeader().getDstAddr()) + .dstAddr(requestPacket.getHeader().getSrcAddr()) + .correctChecksumAtBuild(true) + .correctLengthAtBuild(true) + .payloadBuilder( + new UnknownPacket.Builder().rawData(responsePayload) + ); + + IpPacket ipOutPacket; + if (requestPacket instanceof IpV4Packet) { + ipOutPacket = new IpV4Packet.Builder((IpV4Packet) requestPacket) + .srcAddr((Inet4Address) requestPacket.getHeader().getDstAddr()) + .dstAddr((Inet4Address) requestPacket.getHeader().getSrcAddr()) + .correctChecksumAtBuild(true) + .correctLengthAtBuild(true) + .payloadBuilder(payLoadBuilder) + .build(); + + } else { + ipOutPacket = new IpV6Packet.Builder((IpV6Packet) requestPacket) + .srcAddr((Inet6Address) requestPacket.getHeader().getDstAddr()) + .dstAddr((Inet6Address) requestPacket.getHeader().getSrcAddr()) + .correctLengthAtBuild(true) + .payloadBuilder(payLoadBuilder) + .build(); + } + + this.eventLoop.queueDeviceWrite(ipOutPacket); + } + + /** + * Handles a DNS request, by either blocking it or forwarding it to the remote location. + * + * @param packetData The packet data to read + * @throws IOException If some network error occurred + */ + public void handleDnsRequest(byte[] packetData) throws IOException { + IpPacket ipPacket; + try { + ipPacket = (IpPacket) IpSelector.newPacket(packetData, 0, packetData.length); + } catch (Exception e) { + Timber.i(e, "handleDnsRequest: Discarding invalid IP packet"); + return; + } + + // Check UDP protocol + if (ipPacket.getHeader().getProtocol() != IpNumber.UDP) { + return; + } + + UdpPacket updPacket; + Packet udpPayload; + + try { + updPacket = (UdpPacket) ipPacket.getPayload(); + udpPayload = updPacket.getPayload(); + } catch (Exception e) { + Timber.i(e, "handleDnsRequest: Discarding unknown packet type %s", ipPacket.getHeader()); + return; + } + + InetAddress packetAddress = ipPacket.getHeader().getDstAddr(); + int packetPort = updPacket.getHeader().getDstPort().valueAsInt(); + Optional dnsAddressOptional = this.dnsServerMapper.getDnsServerFromFakeAddress(packetAddress); + if (!dnsAddressOptional.isPresent()) { + Timber.w("Cannot find mapped DNS for %s.", packetAddress.getHostAddress()); + return; + } + InetAddress dnsAddress = dnsAddressOptional.get(); + + if (udpPayload == null) { + Timber.i("handleDnsRequest: Sending UDP packet without payload: %s", updPacket); + + // Let's be nice to Firefox. Firefox uses an empty UDP packet to + // the gateway to reduce the RTT. For further details, please see + // https://bugzilla.mozilla.org/show_bug.cgi?id=888268 + DatagramPacket outPacket = new DatagramPacket(new byte[0], 0, dnsAddress, packetPort); + eventLoop.forwardPacket(outPacket); + return; + } + + byte[] dnsRawData = udpPayload.getRawData(); + Message dnsMsg; + try { + dnsMsg = new Message(dnsRawData); + } catch (IOException e) { + Timber.i(e, "handleDnsRequest: Discarding non-DNS or invalid packet"); + return; + } + if (dnsMsg.getQuestion() == null) { + Timber.i("handleDnsRequest: Discarding DNS packet with no query %s", dnsMsg); + return; + } + Name name = dnsMsg.getQuestion().getName(); + String dnsQueryName = name.toString(true); + HostEntry entry = getHostEntry(dnsQueryName); + switch (entry.getType()) { + case BLOCKED: + Timber.i("handleDnsRequest: DNS Name %s blocked!", dnsQueryName); + dnsMsg.getHeader().setFlag(Flags.QR); + dnsMsg.getHeader().setRcode(Rcode.NOERROR); + dnsMsg.addRecord(NEGATIVE_CACHE_SOA_RECORD, Section.AUTHORITY); + handleDnsResponse(ipPacket, dnsMsg.toWire()); + break; + case ALLOWED: + Timber.i("handleDnsRequest: DNS Name %s allowed, sending to %s.", dnsQueryName, dnsAddress); + DatagramPacket outPacket = new DatagramPacket(dnsRawData, 0, dnsRawData.length, dnsAddress, packetPort); + this.eventLoop.forwardPacket(outPacket, data -> handleDnsResponse(ipPacket, data)); + break; + case REDIRECTED: + Timber.i("handleDnsRequest: DNS Name %s redirected to %s.", dnsQueryName, entry.getRedirection()); + dnsMsg.getHeader().setFlag(Flags.QR); + dnsMsg.getHeader().setFlag(Flags.AA); + dnsMsg.getHeader().unsetFlag(Flags.RD); + dnsMsg.getHeader().setRcode(Rcode.NOERROR); + try { + InetAddress address = InetAddress.getByName(entry.getRedirection()); + Record record; + if (address instanceof Inet6Address) { + record = new AAAARecord(name, DClass.IN, NEGATIVE_CACHE_TTL_SECONDS, address); + } else { + record = new ARecord(name, DClass.IN, NEGATIVE_CACHE_TTL_SECONDS, address); + } + dnsMsg.addRecord(record, Section.ANSWER); + } catch (UnknownHostException e) { + Timber.w(e, "Failed to get inet address for host %s.", dnsQueryName); + } + handleDnsResponse(ipPacket, dnsMsg.toWire()); + break; + } + } + + private HostEntry getHostEntry(String dnsQueryName) { + String hostname = dnsQueryName.toLowerCase(Locale.ENGLISH); + HostEntry entry = null; + if (this.vpnModel != null) { + entry = this.vpnModel.getEntry(hostname); + } + if (entry == null) { + entry = new HostEntry(); + entry.setHost(hostname); + entry.setType(ListType.ALLOWED); + } + return entry; + } + + /** + * Interface abstracting away VpnWorker. + */ + public interface EventLoop { + /** + * Forward a packet to the VPN underlying network. + * + * @param packet The packet to forward. + * @throws IOException If the packet could not be forwarded. + */ + void forwardPacket(DatagramPacket packet) throws IOException; + + /** + * Forward a packet to the VPN underlying network. + * + * @param packet The packet to forward. + * @param callback The callback to call with the packet response data. + * @throws IOException If the packet could not be forwarded. + */ + void forwardPacket(DatagramPacket packet, Consumer callback) throws IOException; + + /** + * Write an IP packet to the local TUN device + * + * @param packet The packet to write (a response to a DNS request) + */ + void queueDeviceWrite(IpPacket packet); + } +} diff --git a/app/src/main/java/org/adaway/vpn/dns/DnsQuery.java b/app/src/main/java/org/adaway/vpn/dns/DnsQuery.java new file mode 100644 index 0000000..d96fa91 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/dns/DnsQuery.java @@ -0,0 +1,100 @@ +package org.adaway.vpn.dns; + +import static android.system.OsConstants.POLLIN; + +import android.os.ParcelFileDescriptor; +import android.system.StructPollfd; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.util.function.Consumer; + +import timber.log.Timber; + +/** + * This class represents a DNS query. + * + * @author Bruce BUJON + */ +class DnsQuery implements AutoCloseable { + /** + * The socket used to query DNS server. + */ + private final DatagramSocket socket; + /** + * The callback to call with the query response data. + */ + private final Consumer callback; + /** + * The pollfd related to the query to poll the OS with. + */ + private final StructPollfd pollfd; + /** + * The query creation time, UNIX timestamp in seconds). + */ + private final long time; + + /** + * Constructor. + * + * @param socket The socket used to query DNS server. + * @param callback The callback to call with the query response data. + */ + DnsQuery(DatagramSocket socket, Consumer callback) { + this.socket = socket; + this.callback = callback; + this.time = System.currentTimeMillis() / 1000; + this.pollfd = new StructPollfd(); + this.pollfd.fd = ParcelFileDescriptor.fromDatagramSocket(this.socket).getFileDescriptor(); + this.pollfd.events = (short) POLLIN; + } + + /** + * Check whether a query is older than a timestamp. + * + * @param timestamp The UNIX timestamp (in seconds) to compare query time with. + * @return true if the query is older than the given timestamp, false otherwise. + */ + boolean isOlderThan(long timestamp) { + return this.time < timestamp; + } + + /** + * Get the pollfd related to the query to poll the OS with. + * @return The pollfd related to the query to poll the OS with. + */ + StructPollfd getPollfd() { + return this.pollfd; + } + + /** + * Check whether the query is answered, meaning its socket has received data to read. + * + * @return {@code true} if there is data to read from {@link #socket}, {@code false} otherwise. + */ + boolean isAnswered() { + return (this.pollfd.revents & POLLIN) != 0; + } + + /** + * Read DNS query response and notify callback. + */ + void handleResponse() { + try { + byte[] responseData = new byte[1024]; + DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length); + this.socket.receive(responsePacket); + this.callback.accept(responseData); + } catch (IOException e) { + Timber.w(e, "Could not handle DNS response."); + } finally { + close(); + } + } + + @Override + public void close() { + this.socket.close(); + } +} diff --git a/app/src/main/java/org/adaway/vpn/dns/DnsQueryQueue.java b/app/src/main/java/org/adaway/vpn/dns/DnsQueryQueue.java new file mode 100644 index 0000000..460f975 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/dns/DnsQueryQueue.java @@ -0,0 +1,106 @@ +package org.adaway.vpn.dns; + +import android.system.StructPollfd; + +import java.net.DatagramSocket; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Queue; +import java.util.function.Consumer; + +import timber.log.Timber; + +/** + * This class represents the running DNS queries queue.
    + * This queue is time and space bound. + * + * @author Bruce BUJON + */ +public class DnsQueryQueue { + /** + * The maximum number of responses to wait for. + */ + private static final int DNS_MAXIMUM_WAITING = 1024; + /** + * The maximum time to wait for the response (in seconds). + */ + private static final long DNS_TIMEOUT_SEC = 10; + /** + * The packet queue (older packets first, in the queue head). + */ + private final Queue queries; + + /** + * Constructor. + */ + public DnsQueryQueue() { + this.queries = new LinkedList<>(); + } + + /** + * Add DNS query to the queue. + * + * @param socket The socket used to query DNS server. + * @param callback The callback to call with the query response data. + */ + public void addQuery(DatagramSocket socket, Consumer callback) { + // Apply time constraint by removing timed out queries + clearTimedOutQueries(); + // Apply space constraint by removing older packet if queue is full + ensureFreeSpace(); + // Add query to the queue + DnsQuery query = new DnsQuery(socket, callback); + this.queries.add(query); + } + + private void ensureFreeSpace() { + if (this.queries.size() > DNS_MAXIMUM_WAITING) { + DnsQuery oldestQuery = this.queries.remove(); + Timber.d("Dropping query due to space constraints: %s.", oldestQuery); + oldestQuery.close(); + } + } + + private void clearTimedOutQueries() { + long now = System.currentTimeMillis() / 1000; + while (!this.queries.isEmpty() && this.queries.element().isOlderThan(now - DNS_TIMEOUT_SEC)) { + DnsQuery timedOutQuery = this.queries.remove(); + Timber.d("Query %s timed out.", timedOutQuery); + timedOutQuery.close(); + } + } + + /** + * Get the number of pending DNS queries. + * + * @return The number of pending DNS queries. + */ + public int size() { + return this.queries.size(); + } + + /** + * Get the query pollfds. + * + * @return The query pollfds. + */ + public StructPollfd[] getQueryFds() { + return this.queries.stream() + .map(DnsQuery::getPollfd) + .toArray(StructPollfd[]::new); + } + + /** + * Handle any responded query. + */ + public void handleResponses() { + Iterator iterator = this.queries.iterator(); + while (iterator.hasNext()) { + DnsQuery query = iterator.next(); + if (query.isAnswered()) { + iterator.remove(); + query.handleResponse(); + } + } + } +} diff --git a/app/src/main/java/org/adaway/vpn/dns/DnsServerMapper.java b/app/src/main/java/org/adaway/vpn/dns/DnsServerMapper.java new file mode 100644 index 0000000..5ae337b --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/dns/DnsServerMapper.java @@ -0,0 +1,307 @@ +package org.adaway.vpn.dns; + +import static android.content.Context.CONNECTIVITY_SERVICE; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static java.util.Collections.emptyList; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.VpnService; + +import org.adaway.helper.PreferenceHelper; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import timber.log.Timber; + +/** + * This class is in charge of mapping DNS server addresses between network DNS and fake DNS. + *

    + * Fake DNS addresses are registered as VPN interface DNS to capture DNS traffic. + * Each original DNS server is directly mapped to one fake address. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class DnsServerMapper { + /** + * The TEST NET addresses blocks, defined in RFC5735. + */ + private static final String[] TEST_NET_ADDRESS_BLOCKS = { + "192.0.2.0/24", // TEST-NET-1 + "198.51.100.0/24", // TEST-NET-2 + "203.0.113.0/24" // TEST-NET-3 + }; + /** + * This IPv6 address prefix for documentation, defined in RFC3849. + */ + private static final String IPV6_ADDRESS_PREFIX_RESERVED_FOR_DOCUMENTATION = "2001:db8::/32"; + /** + * VPN network IPv6 interface prefix length. + */ + private static final int IPV6_PREFIX_LENGTH = 120; + /** + * The original DNS servers. + */ + private final List dnsServers; + + /** + * Constructor. + */ + public DnsServerMapper() { + this.dnsServers = new ArrayList<>(); + } + + /** + * Configure the VPN. + *

    + * Add interface address per IP family and fake DNS server per system DNS server. + * + * @param context The application context. + * @param builder The builder of the VPN to configure. + */ + public void configureVpn(Context context, VpnService.Builder builder) { + // Get DNS servers + List dnsServers = getNetworkDnsServers(context); + // Configure tunnel network address + Subnet ipv4Subnet = addIpv4Address(builder); + Subnet ipv6Subnet = hasIpV6DnsServers(context, dnsServers) ? addIpv6Address(builder) : null; + // Configure DNS mapping + this.dnsServers.clear(); + for (InetAddress dnsServer : dnsServers) { + Subnet subnetForDnsServer = dnsServer instanceof Inet4Address ? ipv4Subnet : ipv6Subnet; + if (subnetForDnsServer == null) { + continue; + } + this.dnsServers.add(dnsServer); + int serverIndex = this.dnsServers.size(); + InetAddress dnsAddressAlias = subnetForDnsServer.getAddress(serverIndex); + Timber.i("Mapping DNS server %s as %s.", dnsServer, dnsAddressAlias); + builder.addDnsServer(dnsAddressAlias); + if (dnsServer instanceof Inet4Address) { + builder.addRoute(dnsAddressAlias, 32); + } + } + } + + public InetAddress getDefaultDnsServerAddress() { + if (this.dnsServers.isEmpty()) { + try { + return InetAddress.getByName("1.1.1.1"); + } catch (UnknownHostException e) { + throw new IllegalStateException("Failed to parse hardcoded DNS IP address.", e); + } + } + // Return last DNS server added + return this.dnsServers.get(this.dnsServers.size() - 1); + } + + /** + * Get the original DNS server address from fake DNS server address. + * + * @param fakeDnsAddress The fake DNS address to get the original DNS server address. + * @return The original DNS server address, wrapped into an {@link Optional} or {@link Optional#empty()} if it does not exists. + */ + Optional getDnsServerFromFakeAddress(InetAddress fakeDnsAddress) { + byte[] address = fakeDnsAddress.getAddress(); + int index = address[address.length - 1] - 2; + if (index < 0 || index >= this.dnsServers.size()) { + return Optional.empty(); + } + InetAddress dnsAddress = this.dnsServers.get(index); + Timber.d("handleDnsRequest: Incoming packet to %s AKA %d AKA %s", fakeDnsAddress.getHostAddress(), index, dnsAddress.getHostAddress()); + return Optional.of(dnsAddress); + } + + /** + * Get the DNS server addresses from the device networks. + * + * @param context The application context. + * @return The DNS server addresses, an empty collection if no network. + */ + private List getNetworkDnsServers(Context context) { + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE); + dumpNetworkInfo(connectivityManager); + Network activeNetwork = connectivityManager.getActiveNetwork(); + if (activeNetwork == null) { + return getAnyNonVpnNetworkDns(connectivityManager); + } else if (isNotVpnNetwork(connectivityManager, activeNetwork)) { + Timber.d("Get DNS servers from active network %s", activeNetwork); + return getNetworkDnsServers(connectivityManager, activeNetwork); + } else { + return getDnsFromNonVpnNetworkWithMatchingTransportType(connectivityManager, activeNetwork); + } + } + + /** + * Dump all network properties to logs. + * + * @param connectivityManager The connectivity manager. + */ + private void dumpNetworkInfo(ConnectivityManager connectivityManager) { + Network activeNetwork = connectivityManager.getActiveNetwork(); + Timber.d("Dumping network and dns configuration:"); + for (Network network : connectivityManager.getAllNetworks()) { + NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(network); + boolean cellular = networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_CELLULAR); + boolean wifi = networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_WIFI); + boolean vpn = networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_VPN); + LinkProperties linkProperties = connectivityManager.getLinkProperties(network); + String dnsList = linkProperties == null ? "none" : linkProperties.getDnsServers() + .stream() + .map(InetAddress::toString) + .collect(Collectors.joining(", ")); + Timber.d( + "Network %s %s: %s%s%s with dns %s", + network, + network.equals(activeNetwork) ? "[default]" : "[other]", + cellular ? "cellular" : "", + wifi ? "WiFi" : "", + vpn ? " VPN" : "", + dnsList); + } + } + + /** + * Get the DNS server addresses of any network without VPN capability. + * + * @param connectivityManager The connectivity manager. + * @return The DNS server addresses, an empty collection if no applicable DNS server found. + */ + private List getAnyNonVpnNetworkDns(ConnectivityManager connectivityManager) { + for (Network network : connectivityManager.getAllNetworks()) { + if (isNotVpnNetwork(connectivityManager, network)) { + List dnsServers = getNetworkDnsServers(connectivityManager, network); + if (!dnsServers.isEmpty()) { + Timber.d("Get DNS servers from non VPN network %s", network); + return dnsServers; + } + } + } + return emptyList(); + } + + /** + * Get the DNS server addresses of a network with the same transport type as the active network except VPN. + * + * @param connectivityManager The connectivity manager. + * @param activeNetwork The active network to filter similar transport type. + * @return The DNS server addresses, an empty collection if no applicable DNS server found. + */ + private List getDnsFromNonVpnNetworkWithMatchingTransportType( + ConnectivityManager connectivityManager, + Network activeNetwork + ) { + // Get active network transport + NetworkCapabilities activeNetworkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork); + if (activeNetworkCapabilities == null) { + return emptyList(); + } + int activeNetworkTransport = -1; + if (activeNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { + activeNetworkTransport = TRANSPORT_CELLULAR; + } else if (activeNetworkCapabilities.hasTransport(TRANSPORT_WIFI)) { + activeNetworkTransport = TRANSPORT_WIFI; + } + // Check all network to find one without VPN and matching transport + for (Network network : connectivityManager.getAllNetworks()) { + NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(network); + if (networkCapabilities == null) { + continue; + } + if (networkCapabilities.hasTransport(activeNetworkTransport) && !networkCapabilities.hasTransport(TRANSPORT_VPN)) { + List dns = getNetworkDnsServers(connectivityManager, network); + if (!dns.isEmpty()) { + Timber.d("Get DNS servers from non VPN matching type network %s", network); + return dns; + } + } + } + return emptyList(); + } + + /** + * Get the DNS server addresses of a network. + * + * @param connectivityManager The connectivity manager. + * @param network The network to get DNS server addresses. + * @return The DNS server addresses, an empty collection if no network. + */ + private List getNetworkDnsServers(ConnectivityManager connectivityManager, Network network) { + LinkProperties linkProperties = connectivityManager.getLinkProperties(network); + if (linkProperties == null) { + return emptyList(); + } + return linkProperties.getDnsServers(); + } + + /** + * Check a network does not have VPN transport. + * + * @param connectivityManager The connectivity manager. + * @param network The network to check. + * @return true if a network is not a VPN, false otherwise. + */ + private boolean isNotVpnNetwork(ConnectivityManager connectivityManager, Network network) { + if (network == null) { + return false; + } + NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(network); + return networkCapabilities != null && !networkCapabilities.hasTransport(TRANSPORT_VPN); + } + + /** + * Add IPv4 network address to the VPN. + * + * @param builder The build of the VPN to configure. + * @return The IPv4 address of the VPN network. + */ + private Subnet addIpv4Address(VpnService.Builder builder) { + for (String addressBlock : TEST_NET_ADDRESS_BLOCKS) { + try { + Subnet subnet = Subnet.parse(addressBlock); + InetAddress address = subnet.getAddress(0); + builder.addAddress(address, subnet.prefixLength); + Timber.d("Set %s as IPv4 network address to tunnel interface.", address); + return subnet; + } catch (IllegalArgumentException e) { + Timber.w(e, "Failed to add %s network address to tunnel interface.", addressBlock); + } + } + throw new IllegalStateException("Failed to add any IPv4 address for TEST-NET to tunnel interface."); + } + + /** + * Add IPv6 network address to the VPN. + * + * @param builder The build of the VPN to configure. + * @return The IPv4 address of the VPN network. + */ + private Subnet addIpv6Address(VpnService.Builder builder) { + Subnet subnet = Subnet.parse(IPV6_ADDRESS_PREFIX_RESERVED_FOR_DOCUMENTATION); + builder.addAddress(subnet.address, IPV6_PREFIX_LENGTH); + Timber.d("Set %s as IPv6 network address to tunnel interface.", subnet.address); + return subnet; + } + + + private boolean hasIpV6DnsServers(Context context, Collection dnsServers) { + boolean hasIpv6Server = dnsServers.stream() + .anyMatch(server -> server instanceof Inet6Address); + boolean hasOnlyOnServer = dnsServers.size() == 1; + boolean isIpv6Enabled = PreferenceHelper.getEnableIpv6(context); + return (isIpv6Enabled || hasOnlyOnServer) && hasIpv6Server; + } +} diff --git a/app/src/main/java/org/adaway/vpn/dns/DohPacketProxy.java b/app/src/main/java/org/adaway/vpn/dns/DohPacketProxy.java new file mode 100644 index 0000000..43a4a88 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/dns/DohPacketProxy.java @@ -0,0 +1,299 @@ + +package org.adaway.vpn.dns; + +import android.content.Context; + +import org.adaway.AdAwayApplication; +import org.adaway.db.entity.HostEntry; +import org.adaway.db.entity.ListType; +import org.adaway.model.vpn.VpnModel; +import org.adaway.util.AppExecutors; +import org.adaway.vpn.dns.DnsPacketProxy.EventLoop; +import org.pcap4j.packet.IpPacket; +import org.pcap4j.packet.IpSelector; +import org.pcap4j.packet.IpV4Packet; +import org.pcap4j.packet.IpV6Packet; +import org.pcap4j.packet.Packet; +import org.pcap4j.packet.UdpPacket; +import org.pcap4j.packet.UnknownPacket; +import org.pcap4j.packet.namednumber.IpNumber; +import org.xbill.DNS.AAAARecord; +import org.xbill.DNS.ARecord; +import org.xbill.DNS.DClass; +import org.xbill.DNS.Flags; +import org.xbill.DNS.Message; +import org.xbill.DNS.Name; +import org.xbill.DNS.Rcode; +import org.xbill.DNS.Record; +import org.xbill.DNS.SOARecord; +import org.xbill.DNS.Section; +import org.xbill.DNS.TextParseException; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.concurrent.Executor; + +import okhttp3.Cache; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.dnsoverhttps.DnsOverHttps; +import timber.log.Timber; + +/** + * Creates and parses packets, and sends packets to a remote socket or the device using VpnWorker. + */ +public class DohPacketProxy { + // Choose a value that is smaller than the time needed to unblock a host. + private static final int NEGATIVE_CACHE_TTL_SECONDS = 5; + private static final SOARecord NEGATIVE_CACHE_SOA_RECORD; + + private static final Executor EXECUTOR = AppExecutors.getInstance().networkIO(); + + static { + try { + // Let's use a guaranteed invalid hostname here, clients are not supposed to use + // our fake values, the whole thing just exists for negative caching. + Name name = new Name("adaway.vpn.invalid."); + NEGATIVE_CACHE_SOA_RECORD = new SOARecord(name, DClass.IN, NEGATIVE_CACHE_TTL_SECONDS, + name, name, 0, 0, 0, 0, NEGATIVE_CACHE_TTL_SECONDS); + } catch (TextParseException e) { + throw new RuntimeException(e); + } + } + + private final EventLoop eventLoop; + private final DnsServerMapper dnsServerMapper; + private VpnModel vpnModel; + private DnsOverHttps dnsOverHttps; + + public DohPacketProxy(EventLoop eventLoop, DnsServerMapper dnsServerMapper) { + this.eventLoop = eventLoop; + this.dnsServerMapper = dnsServerMapper; + } + + private static InetAddress getByIp(String host) { + try { + return InetAddress.getByName(host); + } catch (UnknownHostException e) { + // unlikely + throw new RuntimeException(e); + } + } + + /** + * Initializes the rules database and the list of upstream servers. + * + * @param context The context we are operating in (for the database). + */ + public void initialize(Context context) { + this.vpnModel = (VpnModel) ((AdAwayApplication) context.getApplicationContext()).getAdBlockModel(); + this.dnsOverHttps = createDnsOverHttps(context); + } + + private DnsOverHttps createDnsOverHttps(Context context) { + Cache dnsClientCache = new Cache(context.getCacheDir(), 10 * 1024 * 1024L); + OkHttpClient dnsClient = new OkHttpClient.Builder().cache(dnsClientCache).build(); + return new DnsOverHttps.Builder() + .client(dnsClient) + .url(HttpUrl.get("https://cloudflare-dns.com/dns-query")) + .bootstrapDnsHosts(getByIp("1.1.1.1"), getByIp("1.0.0.1")) + .includeIPv6(false) + .post(true) + .build(); + } + + /** + * Handles a responsePayload from an upstream DNS server + * + * @param requestPacket The original request packet + * @param responsePayload The payload of the response + */ + public void handleDnsResponse(IpPacket requestPacket, byte[] responsePayload) { + UdpPacket udpOutPacket = (UdpPacket) requestPacket.getPayload(); + UdpPacket.Builder payLoadBuilder = new UdpPacket.Builder(udpOutPacket) + .srcPort(udpOutPacket.getHeader().getDstPort()) + .dstPort(udpOutPacket.getHeader().getSrcPort()) + .srcAddr(requestPacket.getHeader().getDstAddr()) + .dstAddr(requestPacket.getHeader().getSrcAddr()) + .correctChecksumAtBuild(true) + .correctLengthAtBuild(true) + .payloadBuilder( + new UnknownPacket.Builder().rawData(responsePayload) + ); + + IpPacket ipOutPacket; + if (requestPacket instanceof IpV4Packet) { + ipOutPacket = new IpV4Packet.Builder((IpV4Packet) requestPacket) + .srcAddr((Inet4Address) requestPacket.getHeader().getDstAddr()) + .dstAddr((Inet4Address) requestPacket.getHeader().getSrcAddr()) + .correctChecksumAtBuild(true) + .correctLengthAtBuild(true) + .payloadBuilder(payLoadBuilder) + .build(); + + } else { + ipOutPacket = new IpV6Packet.Builder((IpV6Packet) requestPacket) + .srcAddr((Inet6Address) requestPacket.getHeader().getDstAddr()) + .dstAddr((Inet6Address) requestPacket.getHeader().getSrcAddr()) + .correctLengthAtBuild(true) + .payloadBuilder(payLoadBuilder) + .build(); + } + + this.eventLoop.queueDeviceWrite(ipOutPacket); + } + + /** + * Handles a DNS request, by either blocking it or forwarding it to the remote location. + * + * @param packetData The packet data to read + * @throws IOException If some network error occurred + */ + public void handleDnsRequest(byte[] packetData) throws IOException { + IpPacket ipPacket; + try { + ipPacket = (IpPacket) IpSelector.newPacket(packetData, 0, packetData.length); + } catch (Exception e) { + Timber.i(e, "handleDnsRequest: Discarding invalid IP packet"); + return; + } + + // Check UDP protocol + if (ipPacket.getHeader().getProtocol() != IpNumber.UDP) { + return; + } + + UdpPacket updPacket; + Packet udpPayload; + + try { + updPacket = (UdpPacket) ipPacket.getPayload(); + udpPayload = updPacket.getPayload(); + } catch (Exception e) { + Timber.i(e, "handleDnsRequest: Discarding unknown packet type %s", ipPacket.getHeader()); + return; + } + + InetAddress packetAddress = ipPacket.getHeader().getDstAddr(); + int packetPort = updPacket.getHeader().getDstPort().valueAsInt(); + Optional dnsAddressOptional = this.dnsServerMapper.getDnsServerFromFakeAddress(packetAddress); + if (!dnsAddressOptional.isPresent()) { + Timber.w("Cannot find mapped DNS for %s.", packetAddress.getHostAddress()); + return; + } + InetAddress dnsAddress = dnsAddressOptional.get(); + + if (udpPayload == null) { + Timber.i("handleDnsRequest: Sending UDP packet without payload: %s", updPacket); + + // Let's be nice to Firefox. Firefox uses an empty UDP packet to + // the gateway to reduce the RTT. For further details, please see + // https://bugzilla.mozilla.org/show_bug.cgi?id=888268 + DatagramPacket outPacket = new DatagramPacket(new byte[0], 0, 0 /* length */, dnsAddress, packetPort); + eventLoop.forwardPacket(outPacket); + return; + } + + byte[] dnsRawData = udpPayload.getRawData(); + Message dnsMsg; + try { + dnsMsg = new Message(dnsRawData); + } catch (IOException e) { + Timber.i(e, "handleDnsRequest: Discarding non-DNS or invalid packet"); + return; + } + if (dnsMsg.getQuestion() == null) { + Timber.i("handleDnsRequest: Discarding DNS packet with no query %s", dnsMsg); + return; + } + Name name = dnsMsg.getQuestion().getName(); + String dnsQueryName = name.toString(true); + HostEntry entry = getHostEntry(dnsQueryName); + switch (entry.getType()) { + case BLOCKED: + Timber.i("handleDnsRequest: DNS Name %s blocked!", dnsQueryName); + dnsMsg.getHeader().setFlag(Flags.QR); + dnsMsg.getHeader().setRcode(Rcode.NOERROR); + dnsMsg.addRecord(NEGATIVE_CACHE_SOA_RECORD, Section.AUTHORITY); + handleDnsResponse(ipPacket, dnsMsg.toWire()); + break; + case ALLOWED: + Timber.i("handleDnsRequest: DNS Name %s allowed, sending to %s.", dnsQueryName, dnsAddress); + EXECUTOR.execute(() -> queryDohServer(ipPacket, dnsMsg, name)); + break; + case REDIRECTED: + Timber.i("handleDnsRequest: DNS Name %s redirected to %s.", dnsQueryName, entry.getRedirection()); + dnsMsg.getHeader().setFlag(Flags.QR); + dnsMsg.getHeader().setFlag(Flags.AA); + dnsMsg.getHeader().unsetFlag(Flags.RD); + dnsMsg.getHeader().setRcode(Rcode.NOERROR); + try { + InetAddress address = InetAddress.getByName(entry.getRedirection()); + Record dnsRecord; + if (address instanceof Inet6Address) { + dnsRecord = new AAAARecord(name, DClass.IN, NEGATIVE_CACHE_TTL_SECONDS, address); + } else { + dnsRecord = new ARecord(name, DClass.IN, NEGATIVE_CACHE_TTL_SECONDS, address); + } + dnsMsg.addRecord(dnsRecord, Section.ANSWER); + } catch (UnknownHostException e) { + Timber.w(e, "Failed to get inet address for host %s.", dnsQueryName); + } + handleDnsResponse(ipPacket, dnsMsg.toWire()); + break; + } + } + + private void queryDohServer(IpPacket ipPacket, Message dnsMsg, Name name) { + String dnsQueryName = name.toString(true); + InetAddress address = null; + try { + List addresses = this.dnsOverHttps.lookup(dnsQueryName); + if (!addresses.isEmpty()) { + address = addresses.get(0); + } + } catch (UnknownHostException e) { + Timber.i(e, "Failed to query DNS Name %s.", dnsQueryName); + } + + if (address == null) { + Timber.i("No address was found for DNS Name %s.", dnsQueryName); + return; + } + + Timber.i("handleDnsRequest: DNS Name %s redirected to %s.", dnsQueryName, address); + dnsMsg.getHeader().setFlag(Flags.QR); + dnsMsg.getHeader().setFlag(Flags.AA); + dnsMsg.getHeader().unsetFlag(Flags.RD); + dnsMsg.getHeader().setRcode(Rcode.NOERROR); + Record dnsRecord; + if (address instanceof Inet6Address) { + dnsRecord = new AAAARecord(name, DClass.IN, NEGATIVE_CACHE_TTL_SECONDS, address); + } else { + dnsRecord = new ARecord(name, DClass.IN, NEGATIVE_CACHE_TTL_SECONDS, address); + } + dnsMsg.addRecord(dnsRecord, Section.ANSWER); + handleDnsResponse(ipPacket, dnsMsg.toWire()); + } + + private HostEntry getHostEntry(String dnsQueryName) { + String hostname = dnsQueryName.toLowerCase(Locale.ENGLISH); + HostEntry entry = null; + if (this.vpnModel != null) { + entry = this.vpnModel.getEntry(hostname); + } + if (entry == null) { + entry = new HostEntry(); + entry.setHost(hostname); + entry.setType(ListType.ALLOWED); + } + return entry; + } +} diff --git a/app/src/main/java/org/adaway/vpn/dns/Subnet.java b/app/src/main/java/org/adaway/vpn/dns/Subnet.java new file mode 100644 index 0000000..2985dfc --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/dns/Subnet.java @@ -0,0 +1,67 @@ +package org.adaway.vpn.dns; + +import static java.lang.Integer.parseInt; +import static java.util.Objects.requireNonNull; + +import androidx.annotation.NonNull; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * This class represents a sub network. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class Subnet { + /** + * The subnet address. + */ + final InetAddress address; + /** + * The subnet prefix length. + */ + final int prefixLength; + + /** + * Parse a subnet string representation. + * + * @param subnet The subnet string representation. + * @return The parsed subnet. + */ + static Subnet parse(String subnet) { + String[] parts = subnet.split("/"); + try { + return new Subnet(InetAddress.getByName(parts[0]), parseInt(parts[1])); + } catch (UnknownHostException e) { + throw new IllegalStateException("Failed to parse hardcoded documentation subnet.", e); + } + } + + private Subnet(InetAddress address, int prefixLength) { + this.address = requireNonNull(address, "Subnet address cannot be null."); + this.prefixLength = prefixLength; + } + + /** + * Get an address of the subnet. + * + * @param index The host index. + * @return An address of the subnet. + */ + InetAddress getAddress(int index) { + byte[] address = this.address.getAddress(); + address[address.length - 1] = (byte) (index + 1); + try { + return InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + throw new IllegalStateException("Failed to create address " + index + " in subnet " + this); + } + } + + @NonNull + @Override + public String toString() { + return this.address + "/" + this.prefixLength; + } +} diff --git a/app/src/main/java/org/adaway/vpn/worker/VpnBuilder.java b/app/src/main/java/org/adaway/vpn/worker/VpnBuilder.java new file mode 100644 index 0000000..8813900 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/worker/VpnBuilder.java @@ -0,0 +1,137 @@ +package org.adaway.vpn.worker; + +import static android.app.PendingIntent.FLAG_CANCEL_CURRENT; +import static android.app.PendingIntent.FLAG_IMMUTABLE; +import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; +import static android.os.Build.VERSION.SDK_INT; +import static android.os.Build.VERSION_CODES.Q; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static java.util.Collections.emptySet; + +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.net.VpnService; +import android.os.ParcelFileDescriptor; + +import org.adaway.helper.PreferenceHelper; +import org.adaway.ui.home.HomeActivity; +import org.adaway.vpn.dns.DnsServerMapper; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import timber.log.Timber; + +/** + * This utility class is in charge of establishing a new VPN interface. + * + * @author Bruce BUJON + */ +public final class VpnBuilder { + /** + * Private constructor. + */ + private VpnBuilder() { + + } + + /** + * Establish the VPN interface. + * + * @param service The VPN service to create interface. + * @param dnsServerMapper The DNS server mapper used to configure VPN address and routes. + * @return The VPN interface. + */ + public static ParcelFileDescriptor establish(VpnService service, DnsServerMapper dnsServerMapper) { + Timber.d("Establishing VPN…"); + VpnService.Builder builder = service.new Builder(); + // Configure VPN address and DNS servers + dnsServerMapper.configureVpn(service, builder); + // Exclude applications from VPN according user preferences (all applications goes through VPN by default) + excludeApplicationsFromVpn(service, builder); + // Allow applications to bypass the VPN by programmatically binding to a network for compatibility + builder.allowBypass(); + // Set file descriptor in blocking mode as worker has a dedicated thread + builder.setBlocking(true); + // Set the VPN to unmetered + if (SDK_INT >= Q) { + builder.setMetered(false); + } + // Explicitly allow both families to prevent a family being blocked if no DNS server is found with it + builder.allowFamily(AF_INET); + builder.allowFamily(AF_INET6); + // Create a new interface. + ParcelFileDescriptor pfd = builder + .setSession("AdAway") + .setConfigureIntent(PendingIntent.getActivity( + service, + 1, + new Intent(service, HomeActivity.class), + FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE + )) + .establish(); + Timber.i("VPN established."); + return pfd; + } + + private static void excludeApplicationsFromVpn(Context context, VpnService.Builder builder) { + PackageManager packageManager = context.getPackageManager(); + + ApplicationInfo self = context.getApplicationInfo(); + Set excludedApps = PreferenceHelper.getVpnExcludedApps(context); + String vpnExcludedSystemApps = PreferenceHelper.getVpnExcludedSystemApps(context); + Set webBrowserPackageName = vpnExcludedSystemApps.equals("allExceptBrowsers") ? + getWebBrowserPackageName(packageManager) : + emptySet(); + + List installedApplications = packageManager.getInstalledApplications(0); + for (ApplicationInfo applicationInfo : installedApplications) { + boolean excluded = false; + // Skip itself + if (applicationInfo.packageName.equals(self.packageName)) { + continue; + } + // Check system app + if ((applicationInfo.flags & FLAG_SYSTEM) != 0) { + excluded = vpnExcludedSystemApps.equals("all") || + (vpnExcludedSystemApps.equals("allExceptBrowsers") && !webBrowserPackageName.contains(applicationInfo.packageName)); + } + // Check user excluded applications + else if (excludedApps.contains(applicationInfo.packageName)) { + excluded = true; + } + if (excluded) { + try { + builder.addDisallowedApplication(applicationInfo.packageName); + } catch (PackageManager.NameNotFoundException e) { + Timber.w(e, "Failed to exclude application %s from VPN.", applicationInfo.packageName); + } + } + } + } + + private static Set getWebBrowserPackageName(PackageManager packageManager) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("https://isabrowser.adaway.org/")); + List resolveInfoList = packageManager.queryIntentActivities(intent, 0); + Set packageNames = new HashSet<>(); + for (ResolveInfo resolveInfo : resolveInfoList) { + packageNames.add(resolveInfo.activityInfo.packageName); + } + + packageNames.add("com.google.android.webview"); + packageNames.add("com.android.htmlviewer"); + packageNames.add("com.google.android.backuptransport"); + packageNames.add("com.google.android.gms"); + packageNames.add("com.google.android.gsf"); + + return packageNames; + } +} diff --git a/app/src/main/java/org/adaway/vpn/worker/VpnConnectionMonitor.java b/app/src/main/java/org/adaway/vpn/worker/VpnConnectionMonitor.java new file mode 100644 index 0000000..c00065f --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/worker/VpnConnectionMonitor.java @@ -0,0 +1,139 @@ +package org.adaway.vpn.worker; + +import static java.lang.Integer.parseInt; +import static java.util.Objects.requireNonNull; + +import android.content.Context; + +import org.adaway.vpn.VpnServiceControls; + +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import timber.log.Timber; + +/** + * This class monitors the VPN network interface is still up while the VPN is running. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +public class VpnConnectionMonitor { + private static final int CONNECTION_CHECK_DELAY_MS = 10_000; + private static final Pattern TUNNEL_PATTERN = Pattern.compile("tun([0-9]+)"); + /** + * The application context. + */ + private final Context context; + /** + * Whether the monitor is running (true if running, false if stopped). + */ + private final AtomicBoolean running; + /** + * The network interface to monitor (null if not initialized). + */ + private NetworkInterface networkInterface; + + /** + * Constructor. + * + * @param context The application context. + */ + VpnConnectionMonitor(Context context) { + this.context = context; + this.running = new AtomicBoolean(true); + this.networkInterface = null; + } + + private static NetworkInterface findVpnNetworkInterface() { + try { + NetworkInterface vpnNetworkInterface = null; + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + while (networkInterfaces.hasMoreElements()) { + NetworkInterface networkInterface = networkInterfaces.nextElement(); + vpnNetworkInterface = pickLastVpnNetworkInterface(vpnNetworkInterface, networkInterface); + } + if (vpnNetworkInterface == null) { + throw new IllegalStateException("Failed to find a network interface."); + } + return vpnNetworkInterface; + } catch (SocketException e) { + throw new IllegalStateException("Failed to find VPN network interface.", e); + } + } + + private static NetworkInterface pickLastVpnNetworkInterface(NetworkInterface current, NetworkInterface other) { + // Ensure other is a tunnel interface, otherwise picks current + Matcher otherMatcher = TUNNEL_PATTERN.matcher(other.getName()); + if (!otherMatcher.matches()) { + return current; + } + // If other is a tunnel interface and no current interface, picks other. + if (current == null) { + return other; + } + // Ensure current is still a tunnel interface (it happens to change), otherwise picks other + Matcher currentMatcher = TUNNEL_PATTERN.matcher(current.getName()); + if (!currentMatcher.matches()) { + Timber.e("Current interface %s is no more a tunnel interface.", current.getName()); + return other; + } + // Compare current and ot then pick the last one + int currentTunnelNumber = parseInt(requireNonNull(currentMatcher.group(1))); + int otherTunnelNumber = parseInt(requireNonNull(otherMatcher.group(1))); + return otherTunnelNumber > currentTunnelNumber ? other : current; + } + + /** + * Initialize the monitor once the VPN connection is up. + */ + void initialize() { + Timber.d("Initializing connection monitor…"); + this.networkInterface = findVpnNetworkInterface(); + Timber.d("Connection monitor initialized to watch interface %s.", this.networkInterface.getName()); + } + + /** + * Monitor the VPN network interface is still up while the VPN is running. + */ + void monitor() { + try { + while (this.running.get()) { + if (this.networkInterface != null && !this.networkInterface.isUp()) { + stop(); + Timber.i("VPN network interface %s is down. Starting VPN service…", + this.networkInterface == null ? "unset" : this.networkInterface.getName()); + VpnServiceControls.start(this.context); + } + try { + Thread.sleep(CONNECTION_CHECK_DELAY_MS); + } catch (InterruptedException e) { + Timber.d("Stop monitoring."); + Thread.currentThread().interrupt(); + break; + } + } + } catch (SocketException e) { + Timber.w(e, "Failed to test VPN network interface %s. Starting VPN service…", this.networkInterface.getName()); + reset(); + VpnServiceControls.start(this.context); + } + } + + /** + * Reset the connection monitor if the VPN connection changed. + */ + void reset() { + this.networkInterface = null; + } + + /** + * Stop the monitor. + */ + void stop() { + this.running.set(false); + } +} diff --git a/app/src/main/java/org/adaway/vpn/worker/VpnConnectionThrottler.java b/app/src/main/java/org/adaway/vpn/worker/VpnConnectionThrottler.java new file mode 100644 index 0000000..8a66270 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/worker/VpnConnectionThrottler.java @@ -0,0 +1,74 @@ +package org.adaway.vpn.worker; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +import timber.log.Timber; + +/** + * This class limits how often the VPN connection is established. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +class VpnConnectionThrottler { + private static final long INITIAL_TIMEOUT_MS = 1_000; + private static final long MAXIMUM_TIMEOUT_MS = 128_000; + /** + * The current timeout before any new connection establishment (in ms). + */ + private long timeout; + /** + * The last time the throttler was called (timestamp in ms, 0 if not initialized). + */ + private long time; + + /** + * Constructor. + */ + VpnConnectionThrottler() { + this.time = 0; + this.timeout = INITIAL_TIMEOUT_MS; + } + + /** + * Limit the VPN connection to be established to often. + * + * @throws InterruptedException If the throttler cannot wait to delay the VPN connection. + */ + void throttle() throws InterruptedException { + long now = System.currentTimeMillis(); + // Check first call + if (this.time == 0) { + this.time = now; + return; + } + // Compute time between two throttle calls + long elapsedTimeBetweenCall = now - this.time; + // If the call happens before the time out + if (elapsedTimeBetweenCall < this.timeout) { + this.time = now; + // Increase timeout and wait the remaining time to limit connexion + increaseTimeout(); + long remainingTime = this.timeout - elapsedTimeBetweenCall; + Timber.d("Limiting the connexion by wait for %ds.", remainingTime / 1000); + Thread.sleep(remainingTime); + } + // If the call happens after the timeout + else { + this.time = now; + // Decrease the time out (up to restoring it) and do no limit connexion + decreaseTimeout(elapsedTimeBetweenCall > MAXIMUM_TIMEOUT_MS); + Timber.d("Allowing the connexion right now."); + } + } + + private void increaseTimeout() { + this.timeout = min(this.timeout * 2, MAXIMUM_TIMEOUT_MS); + Timber.d("Increasing timeout to %ds", this.timeout / 1000); + } + + private void decreaseTimeout(boolean reset) { + this.timeout = reset ? INITIAL_TIMEOUT_MS : max(this.timeout / 4, INITIAL_TIMEOUT_MS); + Timber.d("Decreasing timeout to %ds.", this.timeout / 1000); + } +} diff --git a/app/src/main/java/org/adaway/vpn/worker/VpnNetworkException.java b/app/src/main/java/org/adaway/vpn/worker/VpnNetworkException.java new file mode 100644 index 0000000..bd7c45b --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/worker/VpnNetworkException.java @@ -0,0 +1,12 @@ +package org.adaway.vpn.worker; + +public class VpnNetworkException extends Exception { + public VpnNetworkException(String s) { + super(s); + } + + public VpnNetworkException(String s, Throwable t) { + super(s, t); + } + +} diff --git a/app/src/main/java/org/adaway/vpn/worker/VpnWatchdog.java b/app/src/main/java/org/adaway/vpn/worker/VpnWatchdog.java new file mode 100644 index 0000000..3d61258 --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/worker/VpnWatchdog.java @@ -0,0 +1,182 @@ +/* + * Derived from dns66: + * Copyright (C) 2016-2019 Julian Andres Klode + * + * Parsing code derived from AdBuster: + * Copyright (C) 2016 Daniel Brodie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * Contributions shall also be provided under any later versions of the + * GPL. + */ +package org.adaway.vpn.worker; + +import androidx.annotation.NonNull; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; + +import timber.log.Timber; + +/** + * Ensures that the connection is alive and sets various timeouts and delays in response. + *

    + * The implementation is a bit weird: Success and Failure cases are both handled in the timeout + * case. When a packet is received, we simply store the time. + *

    + * If poll() times out and we have not seen a packet after we last sent a ping, then we force + * a reconnect and increase the reconnect delay. + *

    + * If poll() times out and we have seen a packet after we last sent a ping, we increase the + * poll() time out, causing the next check to run later, and send a ping packet. + */ + +class VpnWatchdog { + // Polling is quadrupled on every success, and values range from 4s to 1h8m. + private static final int POLL_TIMEOUT_START = 1000; + private static final int POLL_TIMEOUT_END = 4096000; + private static final int POLL_TIMEOUT_WAITING = 7000; + private static final int POLL_TIMEOUT_GROW = 4; + + // Reconnect penalty ranges from 0s to 5s, in increments of 200 ms. + private static final int INIT_PENALTY_START = 0; + private static final int INIT_PENALTY_END = 5000; + private static final int INIT_PENALTY_INC = 200; + + private int initPenalty = INIT_PENALTY_START; + private int pollTimeout = POLL_TIMEOUT_START; + + // Information about when packets where received. + private long lastPacketSent; + private long lastPacketReceived; + + private boolean enabled; + private DatagramPacket checkAlivePacket; + + VpnWatchdog() { + // Set default timestamps + this.lastPacketSent = 0; + this.lastPacketReceived = 0; + // Set disable by default + this.enabled = false; + } + + + /** + * Returns the current poll time out. + */ + int getPollTimeout() { + if (!this.enabled) { + return -1; + } + if (this.lastPacketReceived < this.lastPacketSent) { + return POLL_TIMEOUT_WAITING; + } + return this.pollTimeout; + } + + /** + * Sets the target address ping packets should be sent to. + */ + void setTarget(InetAddress target) { + this.checkAlivePacket = new DatagramPacket(new byte[0], 0, 0 /* length */, target, 53); + } + + /** + * An initialization method. Sleeps the penalty and sends initial packet. + * + * @param enabled If the watchdog should be enabled. + */ + void initialize(boolean enabled) { + Timber.d("initialize: Initializing watchdog"); + + this.pollTimeout = POLL_TIMEOUT_START; + this.lastPacketSent = 0; + this.enabled = enabled; + + if (!this.enabled) { + Timber.d("initialize: Disabled."); + return; + } + + if (this.initPenalty > 0) { + Timber.d("init penalty: Sleeping for %dms…", this.initPenalty); + try { + Thread.sleep(this.initPenalty); + } catch (InterruptedException exception) { + Timber.d("Failed to wait the initial penalty."); + Thread.currentThread().interrupt(); + } + } + } + + /** + * Handles a timeout of poll() + * + * @throws VpnNetworkException When the watchdog timed out + */ + void handleTimeout() throws VpnNetworkException { + if (!this.enabled) { + return; + } + Timber.d("handleTimeout: Milliseconds elapsed between last receive and sent: %dms", (this.lastPacketReceived - this.lastPacketSent)); + // Receive really timed out + if (this.lastPacketReceived < this.lastPacketSent && this.lastPacketSent != 0) { + this.initPenalty += INIT_PENALTY_INC; + if (this.initPenalty > INIT_PENALTY_END) { + this.initPenalty = INIT_PENALTY_END; + } + throw new VpnNetworkException("Watchdog timed out"); + } + // We received a packet after sending it, so we can be more confident and grow our wait time + this.pollTimeout *= POLL_TIMEOUT_GROW; + if (this.pollTimeout > POLL_TIMEOUT_END) { + this.pollTimeout = POLL_TIMEOUT_END; + } + + sendPacket(); + } + + /** + * Handles an incoming packet on a device. + * + * @param packetData The data of the packet + */ + void handlePacket(byte[] packetData) { + if (!this.enabled) { + return; + } + Timber.d("handlePacket: Received packet of length %s", packetData.length); + this.lastPacketReceived = System.currentTimeMillis(); + } + + /** + * Sends an empty check-alive packet to the configured target address. + * + * @throws VpnNetworkException If sending failed and we should restart + */ + void sendPacket() throws VpnNetworkException { + if (!this.enabled || this.checkAlivePacket == null) { + return; + } + Timber.d("sendPacket: Sending packet, poll timeout is %d.", this.pollTimeout); + + try (DatagramSocket socket = newDatagramSocket()) { + socket.send(this.checkAlivePacket); + this.lastPacketSent = System.currentTimeMillis(); + } catch (IOException e) { + throw new VpnNetworkException("Failed to send check-alive packet.", e); + } + } + + @NonNull + DatagramSocket newDatagramSocket() throws SocketException { + return new DatagramSocket(); + } +} diff --git a/app/src/main/java/org/adaway/vpn/worker/VpnWorker.java b/app/src/main/java/org/adaway/vpn/worker/VpnWorker.java new file mode 100644 index 0000000..8c1c8fd --- /dev/null +++ b/app/src/main/java/org/adaway/vpn/worker/VpnWorker.java @@ -0,0 +1,341 @@ +/* + * Derived from dns66: + * Copyright (C) 2016-2019 Julian Andres Klode + * + * Derived from AdBuster: + * Copyright (C) 2016 Daniel Brodie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * Contributions shall also be provided under any later versions of the + * GPL. + */ +package org.adaway.vpn.worker; + +import static android.system.OsConstants.ENETUNREACH; +import static android.system.OsConstants.EPERM; +import static android.system.OsConstants.POLLIN; +import static android.system.OsConstants.POLLOUT; +import static org.adaway.vpn.VpnStatus.RECONNECTING_NETWORK_ERROR; +import static org.adaway.vpn.VpnStatus.RUNNING; +import static org.adaway.vpn.VpnStatus.STARTING; +import static org.adaway.vpn.VpnStatus.STOPPED; +import static org.adaway.vpn.VpnStatus.STOPPING; +import static org.adaway.vpn.worker.VpnBuilder.establish; + +import android.os.ParcelFileDescriptor; +import android.system.ErrnoException; +import android.system.Os; +import android.system.StructPollfd; + +import org.adaway.helper.PreferenceHelper; +import org.adaway.vpn.VpnService; +import org.adaway.vpn.dns.DnsPacketProxy; +import org.adaway.vpn.dns.DnsQueryQueue; +import org.adaway.vpn.dns.DnsServerMapper; +import org.pcap4j.packet.IpPacket; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import timber.log.Timber; + +// TODO Write document +// TODO It is thread safe +// TODO Rework status notification +// TODO Improve exception handling in work() +public class VpnWorker implements DnsPacketProxy.EventLoop { + /** + * Maximum packet size is constrained by the MTU, which is given as a signed short. + */ + private static final int MAX_PACKET_SIZE = Short.MAX_VALUE; + + /** + * The VPN service, also used as {@link android.content.Context}. + */ + private final VpnService vpnService; + /** + * The queue of packets to send to the device. + */ + private final Queue deviceWrites; + /** + * The queue of DNS queries. + */ + private final DnsQueryQueue dnsQueryQueue; + // The mapping between fake and real dns addresses + private final DnsServerMapper dnsServerMapper; + // The object where we actually handle packets. + private final DnsPacketProxy dnsPacketProxy; + + // TODO Comment + private final VpnConnectionThrottler connectionThrottler; + private final VpnConnectionMonitor connectionMonitor; + + // Watch dog that checks our connection is alive. + private final VpnWatchdog vpnWatchDog; + + /** + * The VPN worker executor (null if not started). + */ + private final AtomicReference executor; + /** + * The VPN network interface, (null if not established). + */ + private final AtomicReference vpnNetworkInterface; + + /** + * Constructor. + * + * @param vpnService The VPN service, also used as {@link android.content.Context}. + */ + public VpnWorker(VpnService vpnService) { + this.vpnService = vpnService; + this.deviceWrites = new LinkedList<>(); + this.dnsQueryQueue = new DnsQueryQueue(); + this.dnsServerMapper = new DnsServerMapper(); + this.dnsPacketProxy = new DnsPacketProxy(this, this.dnsServerMapper); + this.connectionThrottler = new VpnConnectionThrottler(); + this.connectionMonitor = new VpnConnectionMonitor(this.vpnService); + this.vpnWatchDog = new VpnWatchdog(); + this.executor = new AtomicReference<>(null); + this.vpnNetworkInterface = new AtomicReference<>(null); + } + + /** + * Start the VPN worker. + * Kill the current worker and restart it if already running. + */ + public void start() { + Timber.d("Starting VPN thread…"); + ExecutorService executor = Executors.newFixedThreadPool(2); + executor.submit(this::work); + executor.submit(this.connectionMonitor::monitor); + setExecutor(executor); + Timber.i("VPN thread started."); + } + + /** + * Stop the VPN worker. + */ + public void stop() { + Timber.d("Stopping VPN thread."); + this.connectionMonitor.reset(); + forceCloseTunnel(); + setExecutor(null); + Timber.i("VPN thread stopped."); + } + + /** + * Keep track of the worker executor.
    + * Shut the previous one down in exists. + * + * @param executor The new worker executor, null if no executor any more. + */ + private void setExecutor(ExecutorService executor) { + ExecutorService oldExecutor = this.executor.getAndSet(executor); + if (oldExecutor != null) { + Timber.d("Shutting down VPN executor…"); + oldExecutor.shutdownNow(); + Timber.d("VPN executor shut down."); + } + } + + /** + * Force close the tunnel connection. + */ + private void forceCloseTunnel() { + ParcelFileDescriptor networkInterface = this.vpnNetworkInterface.get(); + if (networkInterface != null) { + try { + networkInterface.close(); + } catch (IOException e) { + Timber.tag("Failed to close VPN network interface.").w(e); + } + } + } + + private void work() { + Timber.d("Starting work…"); + // Initialize context + this.dnsPacketProxy.initialize(this.vpnService); + // Initialize the watchdog + this.vpnWatchDog.initialize(PreferenceHelper.getVpnWatchdogEnabled(this.vpnService)); + // Try connecting the vpn continuously + while (true) { + try { + this.connectionThrottler.throttle(); + this.vpnService.notifyVpnStatus(STARTING); + runVpn(); + Timber.i("Told to stop"); + this.vpnService.notifyVpnStatus(STOPPING); + break; + } catch (InterruptedException e) { + Timber.d(e, "Failed to wait for connexion throttling."); + Thread.currentThread().interrupt(); + break; + } catch (VpnNetworkException | IOException e) { + Timber.w(e, "Network exception in vpn thread, reconnecting…"); + // If an exception was thrown, notify status and try again + this.vpnService.notifyVpnStatus(RECONNECTING_NETWORK_ERROR); + } + } + this.vpnService.notifyVpnStatus(STOPPED); + Timber.d("Exiting work."); + } + + private void runVpn() throws IOException, VpnNetworkException { + // Allocate the buffer for a single packet. + byte[] packet = new byte[MAX_PACKET_SIZE]; + + // Authenticate and configure the virtual network interface. + try (ParcelFileDescriptor pfd = establish(this.vpnService, this.dnsServerMapper); + // Read and write views of the tunnel device + FileInputStream inputStream = new FileInputStream(pfd.getFileDescriptor()); + FileOutputStream outputStream = new FileOutputStream(pfd.getFileDescriptor())) { + // Store reference to network interface to close it externally on demand + this.vpnNetworkInterface.set(pfd); + // Initialize connection monitor + this.connectionMonitor.initialize(); + + // Update address to ping with default DNS server + this.vpnWatchDog.setTarget(this.dnsServerMapper.getDefaultDnsServerAddress()); + + // Now we are connected. Set the flag and show the message. + this.vpnService.notifyVpnStatus(RUNNING); + + // We keep forwarding packets till something goes wrong. + boolean deviceOpened = true; + while (deviceOpened) { + deviceOpened = doOne(inputStream, outputStream, packet); + } + } + } + + private boolean doOne(FileInputStream inputStream, FileOutputStream fileOutputStream, byte[] packet) + throws IOException, VpnNetworkException { + // Create poll FD on tunnel + StructPollfd deviceFd = new StructPollfd(); + deviceFd.fd = inputStream.getFD(); + deviceFd.events = (short) POLLIN; + if (!this.deviceWrites.isEmpty()) { + deviceFd.events |= (short) POLLOUT; + } + // Create poll FD on each DNS query socket + StructPollfd[] queryFds = this.dnsQueryQueue.getQueryFds(); + StructPollfd[] polls = new StructPollfd[1 + queryFds.length]; + polls[0] = deviceFd; + System.arraycopy(queryFds, 0, polls, 1, queryFds.length); + boolean deviceReadyToWrite; + boolean deviceReadyToRead; + try { + Timber.d("doOne: Polling %d file descriptors.", polls.length); + int numberOfEvents = Os.poll(polls, this.vpnWatchDog.getPollTimeout()); + // TODO BUG - There is a bug where the watchdog keeps doing timeout if there is no network activity + // TODO BUG - 0 Might be a valid value if no current DNS query and everything was already sent back to device + if (numberOfEvents == 0) { + this.vpnWatchDog.handleTimeout(); + return true; + } + deviceReadyToWrite = (deviceFd.revents & POLLOUT) != 0; + deviceReadyToRead = (deviceFd.revents & POLLIN) != 0; + } catch (ErrnoException e) { + throw new IOException("Failed to wait for event on file descriptors. Error number: " + e.errno, e); + } + + // Need to do this before reading from the device, otherwise a new insertion there could + // invalidate one of the sockets we want to read from either due to size or time out + // constraints + this.dnsQueryQueue.handleResponses(); + if (deviceReadyToWrite) { + writeToDevice(fileOutputStream); + } + if (deviceReadyToRead) { + return readPacketFromDevice(inputStream, packet) != -1; + } + return true; + } + + private void writeToDevice(FileOutputStream fileOutputStream) throws IOException { + Timber.d("Write to device %d packets.", this.deviceWrites.size()); + try { + while (!this.deviceWrites.isEmpty()) { + byte[] ipPacketData = this.deviceWrites.poll(); + fileOutputStream.write(ipPacketData); + } + } catch (IOException e) { + throw new IOException("Failed to write to tunnel output stream.", e); + } + } + + private int readPacketFromDevice(FileInputStream inputStream, byte[] packet) throws IOException { + Timber.d("Read a packet from device."); + // Read the outgoing packet from the input stream. + int length = inputStream.read(packet); + if (length < 0) { + // TODO Stream closed. Is there anything else to do? + Timber.d("Tunnel input stream closed."); + } else if (length == 0) { + Timber.d("Read empty packet from tunnel."); + } else { + byte[] readPacket = Arrays.copyOf(packet, length); + vpnWatchDog.handlePacket(readPacket); + dnsPacketProxy.handleDnsRequest(readPacket); + } + return length; + } + + @Override + public void forwardPacket(DatagramPacket packet) throws IOException { + try (DatagramSocket dnsSocket = new DatagramSocket()) { + this.vpnService.protect(dnsSocket); + dnsSocket.send(packet); + } catch (IOException e) { + throw new IOException("Failed to forward packet.", e); + } + } + + @Override + public void forwardPacket(DatagramPacket outPacket, Consumer callback) throws IOException { + DatagramSocket dnsSocket = null; + try { + dnsSocket = new DatagramSocket(); + // Packets to be sent to the real DNS server will need to be protected from the VPN + this.vpnService.protect(dnsSocket); + dnsSocket.send(outPacket); + // Enqueue DNS query + this.dnsQueryQueue.addQuery(dnsSocket, callback); + } catch (IOException e) { + if (dnsSocket != null) { + dnsSocket.close(); + } + if (e.getCause() instanceof ErrnoException) { + ErrnoException errnoExc = (ErrnoException) e.getCause(); + if ((errnoExc.errno == ENETUNREACH) || (errnoExc.errno == EPERM)) { + throw new IOException("Cannot send message:", e); + } + } + Timber.w(e, "handleDnsRequest: Could not send packet to upstream"); + } + } + + @Override + public void queueDeviceWrite(IpPacket ipOutPacket) { + byte[] rawData = ipOutPacket.getRawData(); + // TODO Check why data could be null + if (rawData != null) { + this.deviceWrites.add(rawData); + } + } +} diff --git a/app/src/main/res/animator/fragment_close_enter.xml b/app/src/main/res/animator/fragment_close_enter.xml new file mode 100644 index 0000000..d18fdd5 --- /dev/null +++ b/app/src/main/res/animator/fragment_close_enter.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/animator/fragment_close_exit.xml b/app/src/main/res/animator/fragment_close_exit.xml new file mode 100644 index 0000000..11d0780 --- /dev/null +++ b/app/src/main/res/animator/fragment_close_exit.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/animator/fragment_open_enter.xml b/app/src/main/res/animator/fragment_open_enter.xml new file mode 100644 index 0000000..48ff32d --- /dev/null +++ b/app/src/main/res/animator/fragment_open_enter.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/animator/fragment_open_exit.xml b/app/src/main/res/animator/fragment_open_exit.xml new file mode 100644 index 0000000..c2052a2 --- /dev/null +++ b/app/src/main/res/animator/fragment_open_exit.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/baseline_block_24.xml b/app/src/main/res/drawable/baseline_block_24.xml new file mode 100644 index 0000000..8c44535 --- /dev/null +++ b/app/src/main/res/drawable/baseline_block_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_check_24.xml b/app/src/main/res/drawable/baseline_check_24.xml new file mode 100644 index 0000000..5291b7f --- /dev/null +++ b/app/src/main/res/drawable/baseline_check_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_clear_all_24.xml b/app/src/main/res/drawable/baseline_clear_all_24.xml new file mode 100644 index 0000000..a7e1cb5 --- /dev/null +++ b/app/src/main/res/drawable/baseline_clear_all_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_compare_arrows_24.xml b/app/src/main/res/drawable/baseline_compare_arrows_24.xml new file mode 100644 index 0000000..e03ad53 --- /dev/null +++ b/app/src/main/res/drawable/baseline_compare_arrows_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_edit_24.xml b/app/src/main/res/drawable/baseline_edit_24.xml new file mode 100644 index 0000000..56dbeee --- /dev/null +++ b/app/src/main/res/drawable/baseline_edit_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_favorite_24.xml b/app/src/main/res/drawable/baseline_favorite_24.xml new file mode 100644 index 0000000..26161c5 --- /dev/null +++ b/app/src/main/res/drawable/baseline_favorite_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_search_24.xml b/app/src/main/res/drawable/baseline_search_24.xml new file mode 100644 index 0000000..083d636 --- /dev/null +++ b/app/src/main/res/drawable/baseline_search_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_sort_by_alpha_24.xml b/app/src/main/res/drawable/baseline_sort_by_alpha_24.xml new file mode 100644 index 0000000..c4a3737 --- /dev/null +++ b/app/src/main/res/drawable/baseline_sort_by_alpha_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/dot.xml b/app/src/main/res/drawable/dot.xml new file mode 100644 index 0000000..29cc01f --- /dev/null +++ b/app/src/main/res/drawable/dot.xml @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_outline.xml b/app/src/main/res/drawable/dot_outline.xml new file mode 100644 index 0000000..b5f9913 --- /dev/null +++ b/app/src/main/res/drawable/dot_outline.xml @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black_24px.xml b/app/src/main/res/drawable/ic_add_black_24px.xml new file mode 100644 index 0000000..1f463d3 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black_24px.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_circle_outline_24dp.xml b/app/src/main/res/drawable/ic_add_circle_outline_24dp.xml new file mode 100644 index 0000000..24b996a --- /dev/null +++ b/app/src/main/res/drawable/ic_add_circle_outline_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_medium_24dp.xml b/app/src/main/res/drawable/ic_brightness_medium_24dp.xml new file mode 100644 index 0000000..0170cf6 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_medium_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_bug_report_24dp.xml b/app/src/main/res/drawable/ic_bug_report_24dp.xml new file mode 100644 index 0000000..2629b47 --- /dev/null +++ b/app/src/main/res/drawable/ic_bug_report_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_cloud_off_24dp.xml b/app/src/main/res/drawable/ic_cloud_off_24dp.xml new file mode 100644 index 0000000..1bda2dc --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_off_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_collections_bookmark_24dp.xml b/app/src/main/res/drawable/ic_collections_bookmark_24dp.xml new file mode 100644 index 0000000..1f1e886 --- /dev/null +++ b/app/src/main/res/drawable/ic_collections_bookmark_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_error_outline_24dp.xml b/app/src/main/res/drawable/ic_error_outline_24dp.xml new file mode 100644 index 0000000..6a15172 --- /dev/null +++ b/app/src/main/res/drawable/ic_error_outline_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_get_app_24dp.xml b/app/src/main/res/drawable/ic_get_app_24dp.xml new file mode 100644 index 0000000..56b2e31 --- /dev/null +++ b/app/src/main/res/drawable/ic_get_app_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_github_24dp.xml b/app/src/main/res/drawable/ic_github_24dp.xml new file mode 100644 index 0000000..220ebea --- /dev/null +++ b/app/src/main/res/drawable/ic_github_24dp.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_github_32dp.xml b/app/src/main/res/drawable/ic_github_32dp.xml new file mode 100644 index 0000000..005bbbe --- /dev/null +++ b/app/src/main/res/drawable/ic_github_32dp.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_help_24dp.xml b/app/src/main/res/drawable/ic_help_24dp.xml new file mode 100644 index 0000000..d775ec8 --- /dev/null +++ b/app/src/main/res/drawable/ic_help_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_ipv6_24dp.xml b/app/src/main/res/drawable/ic_ipv6_24dp.xml new file mode 100644 index 0000000..0ff24ba --- /dev/null +++ b/app/src/main/res/drawable/ic_ipv6_24dp.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_language_24dp.xml b/app/src/main/res/drawable/ic_language_24dp.xml new file mode 100644 index 0000000..e7cad55 --- /dev/null +++ b/app/src/main/res/drawable/ic_language_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_language_red.xml b/app/src/main/res/drawable/ic_language_red.xml new file mode 100644 index 0000000..bf7144d --- /dev/null +++ b/app/src/main/res/drawable/ic_language_red.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_list_red.xml b/app/src/main/res/drawable/ic_list_red.xml new file mode 100644 index 0000000..b4343bb --- /dev/null +++ b/app/src/main/res/drawable/ic_list_red.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_menu_24dp.xml b/app/src/main/res/drawable/ic_menu_24dp.xml new file mode 100644 index 0000000..a1acf66 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_outline_rule_24.xml b/app/src/main/res/drawable/ic_outline_rule_24.xml new file mode 100644 index 0000000..67e0652 --- /dev/null +++ b/app/src/main/res/drawable/ic_outline_rule_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_pause_24dp.xml b/app/src/main/res/drawable/ic_pause_24dp.xml new file mode 100644 index 0000000..58ea7a9 --- /dev/null +++ b/app/src/main/res/drawable/ic_pause_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_playlist_add_24dp.xml b/app/src/main/res/drawable/ic_playlist_add_24dp.xml new file mode 100644 index 0000000..d20768c --- /dev/null +++ b/app/src/main/res/drawable/ic_playlist_add_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_record_24dp.xml b/app/src/main/res/drawable/ic_record_24dp.xml new file mode 100644 index 0000000..564e488 --- /dev/null +++ b/app/src/main/res/drawable/ic_record_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_remove_circle_outline_24dp.xml b/app/src/main/res/drawable/ic_remove_circle_outline_24dp.xml new file mode 100644 index 0000000..1d11f46 --- /dev/null +++ b/app/src/main/res/drawable/ic_remove_circle_outline_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_save_24dp.xml b/app/src/main/res/drawable/ic_save_24dp.xml new file mode 100644 index 0000000..ad282ce --- /dev/null +++ b/app/src/main/res/drawable/ic_save_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_sd_storage_24dp.xml b/app/src/main/res/drawable/ic_sd_storage_24dp.xml new file mode 100644 index 0000000..cc7dd4d --- /dev/null +++ b/app/src/main/res/drawable/ic_sd_storage_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_24dp.xml b/app/src/main/res/drawable/ic_settings_24dp.xml new file mode 100644 index 0000000..c4149ea --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_backup_restore_24dp.xml b/app/src/main/res/drawable/ic_settings_backup_restore_24dp.xml new file mode 100644 index 0000000..5accc94 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_backup_restore_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_red.xml b/app/src/main/res/drawable/ic_settings_red.xml new file mode 100644 index 0000000..c10d4d9 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_red.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_superuser_24dp.xml b/app/src/main/res/drawable/ic_superuser_24dp.xml new file mode 100644 index 0000000..2fcee0f --- /dev/null +++ b/app/src/main/res/drawable/ic_superuser_24dp.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_sync_24dp.xml b/app/src/main/res/drawable/ic_sync_24dp.xml new file mode 100644 index 0000000..bcf3d16 --- /dev/null +++ b/app/src/main/res/drawable/ic_sync_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_vpn_key_24dp.xml b/app/src/main/res/drawable/ic_vpn_key_24dp.xml new file mode 100644 index 0000000..ca2576b --- /dev/null +++ b/app/src/main/res/drawable/ic_vpn_key_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/icon_monochrome.xml b/app/src/main/res/drawable/icon_monochrome.xml new file mode 100644 index 0000000..77b8b4c --- /dev/null +++ b/app/src/main/res/drawable/icon_monochrome.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/logo.xml b/app/src/main/res/drawable/logo.xml new file mode 100644 index 0000000..6ff6608 --- /dev/null +++ b/app/src/main/res/drawable/logo.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/notifications_off_24.xml b/app/src/main/res/drawable/notifications_off_24.xml new file mode 100644 index 0000000..f83e9cd --- /dev/null +++ b/app/src/main/res/drawable/notifications_off_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/outline_cloud_upload_24.xml b/app/src/main/res/drawable/outline_cloud_upload_24.xml new file mode 100644 index 0000000..9e42b29 --- /dev/null +++ b/app/src/main/res/drawable/outline_cloud_upload_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/outline_create_24.xml b/app/src/main/res/drawable/outline_create_24.xml new file mode 100644 index 0000000..8520bc4 --- /dev/null +++ b/app/src/main/res/drawable/outline_create_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/outline_delete_24.xml b/app/src/main/res/drawable/outline_delete_24.xml new file mode 100644 index 0000000..d0e092f --- /dev/null +++ b/app/src/main/res/drawable/outline_delete_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/paypal.xml b/app/src/main/res/drawable/paypal.xml new file mode 100644 index 0000000..1e92e4c --- /dev/null +++ b/app/src/main/res/drawable/paypal.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/app/src/main/res/drawable/shadow.xml b/app/src/main/res/drawable/shadow.xml new file mode 100644 index 0000000..52f776e --- /dev/null +++ b/app/src/main/res/drawable/shadow.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/adware_fragment.xml b/app/src/main/res/layout/adware_fragment.xml new file mode 100644 index 0000000..824fca9 --- /dev/null +++ b/app/src/main/res/layout/adware_fragment.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/checkbox_list_entry.xml b/app/src/main/res/layout/checkbox_list_entry.xml new file mode 100644 index 0000000..61057ac --- /dev/null +++ b/app/src/main/res/layout/checkbox_list_entry.xml @@ -0,0 +1,40 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/checkbox_list_two_entries.xml b/app/src/main/res/layout/checkbox_list_two_entries.xml new file mode 100644 index 0000000..0688cae --- /dev/null +++ b/app/src/main/res/layout/checkbox_list_two_entries.xml @@ -0,0 +1,55 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/drawer_list_item.xml b/app/src/main/res/layout/drawer_list_item.xml new file mode 100644 index 0000000..ae2e3a6 --- /dev/null +++ b/app/src/main/res/layout/drawer_list_item.xml @@ -0,0 +1,11 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/help_activity.xml b/app/src/main/res/layout/help_activity.xml new file mode 100644 index 0000000..3641b38 --- /dev/null +++ b/app/src/main/res/layout/help_activity.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/app/src/main/res/layout/help_fragment.xml b/app/src/main/res/layout/help_fragment.xml new file mode 100644 index 0000000..2ac2dfa --- /dev/null +++ b/app/src/main/res/layout/help_fragment.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/app/src/main/res/layout/home_activity.xml b/app/src/main/res/layout/home_activity.xml new file mode 100644 index 0000000..0f9ab02 --- /dev/null +++ b/app/src/main/res/layout/home_activity.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/home_content.xml b/app/src/main/res/layout/home_content.xml new file mode 100644 index 0000000..765d019 --- /dev/null +++ b/app/src/main/res/layout/home_content.xml @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/hosts_content_fragment.xml b/app/src/main/res/layout/hosts_content_fragment.xml new file mode 100644 index 0000000..dbc6e1a --- /dev/null +++ b/app/src/main/res/layout/hosts_content_fragment.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/hosts_lists_fragment.xml b/app/src/main/res/layout/hosts_lists_fragment.xml new file mode 100644 index 0000000..3e73e34 --- /dev/null +++ b/app/src/main/res/layout/hosts_lists_fragment.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/layout/hosts_sources_activity.xml b/app/src/main/res/layout/hosts_sources_activity.xml new file mode 100644 index 0000000..951a62a --- /dev/null +++ b/app/src/main/res/layout/hosts_sources_activity.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/hosts_sources_card.xml b/app/src/main/res/layout/hosts_sources_card.xml new file mode 100644 index 0000000..18ed93e --- /dev/null +++ b/app/src/main/res/layout/hosts_sources_card.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/hosts_sources_dialog.xml b/app/src/main/res/layout/hosts_sources_dialog.xml new file mode 100644 index 0000000..fc030dc --- /dev/null +++ b/app/src/main/res/layout/hosts_sources_dialog.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/app/src/main/res/layout/hosts_sources_fragment.xml b/app/src/main/res/layout/hosts_sources_fragment.xml new file mode 100644 index 0000000..99f57da --- /dev/null +++ b/app/src/main/res/layout/hosts_sources_fragment.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/app/src/main/res/layout/list_two_entries.xml b/app/src/main/res/layout/list_two_entries.xml new file mode 100644 index 0000000..71d887c --- /dev/null +++ b/app/src/main/res/layout/list_two_entries.xml @@ -0,0 +1,42 @@ + + + + + + + diff --git a/app/src/main/res/layout/lists_activity.xml b/app/src/main/res/layout/lists_activity.xml new file mode 100644 index 0000000..e0fdeb5 --- /dev/null +++ b/app/src/main/res/layout/lists_activity.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/lists_allowed_dialog.xml b/app/src/main/res/layout/lists_allowed_dialog.xml new file mode 100644 index 0000000..e88656b --- /dev/null +++ b/app/src/main/res/layout/lists_allowed_dialog.xml @@ -0,0 +1,29 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/lists_blocked_dialog.xml b/app/src/main/res/layout/lists_blocked_dialog.xml new file mode 100644 index 0000000..83d8342 --- /dev/null +++ b/app/src/main/res/layout/lists_blocked_dialog.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/layout/lists_fragment.xml b/app/src/main/res/layout/lists_fragment.xml new file mode 100644 index 0000000..a381cfd --- /dev/null +++ b/app/src/main/res/layout/lists_fragment.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/lists_redirected_dialog.xml b/app/src/main/res/layout/lists_redirected_dialog.xml new file mode 100644 index 0000000..a8f439b --- /dev/null +++ b/app/src/main/res/layout/lists_redirected_dialog.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/log_activity.xml b/app/src/main/res/layout/log_activity.xml new file mode 100644 index 0000000..07d2521 --- /dev/null +++ b/app/src/main/res/layout/log_activity.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/log_entry.xml b/app/src/main/res/layout/log_entry.xml new file mode 100644 index 0000000..8c42f9e --- /dev/null +++ b/app/src/main/res/layout/log_entry.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/log_redirect_dialog.xml b/app/src/main/res/layout/log_redirect_dialog.xml new file mode 100644 index 0000000..1ad886d --- /dev/null +++ b/app/src/main/res/layout/log_redirect_dialog.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/layout/pref_edittext_dialog.xml b/app/src/main/res/layout/pref_edittext_dialog.xml new file mode 100644 index 0000000..36e7127 --- /dev/null +++ b/app/src/main/res/layout/pref_edittext_dialog.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/layout/prefs_activity.xml b/app/src/main/res/layout/prefs_activity.xml new file mode 100644 index 0000000..816e04c --- /dev/null +++ b/app/src/main/res/layout/prefs_activity.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/reboot_dialog.xml b/app/src/main/res/layout/reboot_dialog.xml new file mode 100644 index 0000000..08c50fc --- /dev/null +++ b/app/src/main/res/layout/reboot_dialog.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/source_edit_activity.xml b/app/src/main/res/layout/source_edit_activity.xml new file mode 100644 index 0000000..f0b752e --- /dev/null +++ b/app/src/main/res/layout/source_edit_activity.xml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/support_activity.xml b/app/src/main/res/layout/support_activity.xml new file mode 100644 index 0000000..488100b --- /dev/null +++ b/app/src/main/res/layout/support_activity.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/update_actity.xml b/app/src/main/res/layout/update_actity.xml new file mode 100644 index 0000000..2a68e0a --- /dev/null +++ b/app/src/main/res/layout/update_actity.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/vpn_excluded_app_activity.xml b/app/src/main/res/layout/vpn_excluded_app_activity.xml new file mode 100644 index 0000000..3946249 --- /dev/null +++ b/app/src/main/res/layout/vpn_excluded_app_activity.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/vpn_excluded_app_entry.xml b/app/src/main/res/layout/vpn_excluded_app_entry.xml new file mode 100644 index 0000000..400738d --- /dev/null +++ b/app/src/main/res/layout/vpn_excluded_app_entry.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/welcome_activity.xml b/app/src/main/res/layout/welcome_activity.xml new file mode 100644 index 0000000..dd5d767 --- /dev/null +++ b/app/src/main/res/layout/welcome_activity.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/welcome_method_layout.xml b/app/src/main/res/layout/welcome_method_layout.xml new file mode 100644 index 0000000..b090a7e --- /dev/null +++ b/app/src/main/res/layout/welcome_method_layout.xml @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/welcome_support_layout.xml b/app/src/main/res/layout/welcome_support_layout.xml new file mode 100644 index 0000000..6db15ad --- /dev/null +++ b/app/src/main/res/layout/welcome_support_layout.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/welcome_sync_layout.xml b/app/src/main/res/layout/welcome_sync_layout.xml new file mode 100644 index 0000000..84c79b3 --- /dev/null +++ b/app/src/main/res/layout/welcome_sync_layout.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/checkbox_list_context.xml b/app/src/main/res/menu/checkbox_list_context.xml new file mode 100644 index 0000000..580e20e --- /dev/null +++ b/app/src/main/res/menu/checkbox_list_context.xml @@ -0,0 +1,11 @@ + +

    + + + \ No newline at end of file diff --git a/app/src/main/res/menu/home_drawer.xml b/app/src/main/res/menu/home_drawer.xml new file mode 100644 index 0000000..5e9d8f6 --- /dev/null +++ b/app/src/main/res/menu/home_drawer.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/app/src/main/res/menu/list_menu.xml b/app/src/main/res/menu/list_menu.xml new file mode 100644 index 0000000..40c7c1e --- /dev/null +++ b/app/src/main/res/menu/list_menu.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/lists_navigation.xml b/app/src/main/res/menu/lists_navigation.xml new file mode 100644 index 0000000..f402836 --- /dev/null +++ b/app/src/main/res/menu/lists_navigation.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/log_menu.xml b/app/src/main/res/menu/log_menu.xml new file mode 100644 index 0000000..096b115 --- /dev/null +++ b/app/src/main/res/menu/log_menu.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/next_actions.xml b/app/src/main/res/menu/next_actions.xml new file mode 100644 index 0000000..3a1a886 --- /dev/null +++ b/app/src/main/res/menu/next_actions.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/source_edit_menu.xml b/app/src/main/res/menu/source_edit_menu.xml new file mode 100644 index 0000000..3e1b412 --- /dev/null +++ b/app/src/main/res/menu/source_edit_menu.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/vpn_excluded_app_menu.xml b/app/src/main/res/menu/vpn_excluded_app_menu.xml new file mode 100644 index 0000000..5d28906 --- /dev/null +++ b/app/src/main/res/menu/vpn_excluded_app_menu.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/icon.xml b/app/src/main/res/mipmap-anydpi/icon.xml new file mode 100644 index 0000000..19ec2c6 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/icon.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/src/main/res/mipmap-anydpi/icon_round.xml b/app/src/main/res/mipmap-anydpi/icon_round.xml new file mode 100644 index 0000000..e32fcf9 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/icon_round.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/src/main/res/mipmap-anydpi/shortcut_dns_requests.xml b/app/src/main/res/mipmap-anydpi/shortcut_dns_requests.xml new file mode 100644 index 0000000..aa70404 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/shortcut_dns_requests.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/shortcut_preferences.xml b/app/src/main/res/mipmap-anydpi/shortcut_preferences.xml new file mode 100644 index 0000000..b743ea5 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/shortcut_preferences.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/shortcut_your_lists.xml b/app/src/main/res/mipmap-anydpi/shortcut_your_lists.xml new file mode 100644 index 0000000..2128639 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/shortcut_your_lists.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/icon.png b/app/src/main/res/mipmap-hdpi/icon.png new file mode 100755 index 0000000000000000000000000000000000000000..a000baf5f472413887e518caa31a378db99767f2 GIT binary patch literal 1923 zcmV-}2YmR6P)jNI0mU#M=LCiU@yw86K<)r^F)}jPs8XE(FiWNoF0=aiJ)d1y*Ch6M zqR*iJ;T!@mUuf7G(c{LBM~G~0G*GG4ewSczLqiP z@I`N#)nduXZfv~EC&+i*Wk7C7$b3H8uZxnnT>|7WVdV&!2sueGAdiP5Qce;C=v;KP z+Nx9@mVGIw4X%N5Hrpke#WHtRQ&S6T7tDY-IDUQypitzp4(4Y03$~t~TvkX-fV?KG zM9fLlfV>`#z??({=!tKa(PI>oxP^7iAT;vNKu1rG5-w>BR!%k$9P(t@_%OVL(#1&@CH4c&h~ zl-EgDM{@va5TKuRx}R8{$^*xY!MGzw;TxpxHL>T>qsOpHFT-%-CX6-Juvsjwx*&&s zSyp|0THk?&0%T*gBc_|5A4%JHAZ&UDCvP>GpfA~rrb7n>&05I-5#xM=gAq1u8Z!jU*h{`gw#>NU`=Ts27S?$#}MaO@bL`k?EQ0_r=ON~c3;S~?a(MuATndDW;16D$qT^~ zCnBz(0P0kBKz5HBb{9imQZmTFu#8M3ZQTYRm8$pJnbW6{o}P{vt(Nozsq)ti2=-qpujEHa<%)kyv@+GSrff5iO@3enQXD2H2UPDKDIkO#- z0wUI^Q&YLsEF>+>;j+(cHKRiP7dz4T)d5DW$KsL$vRmaJqlJG|By1Kd6n=h4+P)ns zZLA=pS(L~ut5}o^i^0I6)+;L;Ap3}1&X_w7@f$V@UiMi$Z7BW{`u+P@RQk!v3P=?f z4_$sfG?_C58_cRma!*@nDXW@$W>9$cY$R^^M7CUH>*+!H%uJY@o4o@Nv2x_g%Me#k zDA-^YMU%b(s){mu%2g<}K%yb0*+6KxFSaY1QgHJcEcJ{gH0eGK1_5Ne0-ytM}ZUc5jpKa`-`W{?o8lMfz7$fQYBs$^@U^3`R% z+bvW|LkM{dAeB~&l;bDi7Z%3rtEIgim8(_=dU_w&xmN&EPndvF9~2=dIhhv@sh;aT zEW*Pd&+y992zWFg|LAD$j4fi$3-AdHURhcJj|4;#aa7I%L@!xN zz1e2GcMrAiZ-U|abz0x4{!ITQ;5(hQ}{&tT{m36hU&rsm!8;NEfkrKo|(J@xZI*$u@X_a3z>_-_N!M>wJskd z_ej+EkDggyUSKhl>@Jd{8ci1aM?mCBz4Dc1FzNLyL(f2fP8T=47(R00ok4Oy>PsYH(|d?o zxTyDEh8s6%;-X2!|OE zQIP9n7V;RP)M#Kec7eR}C_;Uhaf^&iI#&Lgq!@o+hI3EWH_Sa zAdi700USvH^$EA(pU0uf30^KF$|~mN44j%j42b9M4g=x=^dAR2j&?&O=X?MF002ov JPDHLkV1jTwh;0A> literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/icon_foreground.png b/app/src/main/res/mipmap-hdpi/icon_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..9b6b67cc5606816ad1914a5df19db3bf2cf42f34 GIT binary patch literal 1653 zcmb7E`#%#3A0~H_4#lKXVofra-0w$hv#B%Jl+EHWtq99#hJ#AeY%H8<8tstlsfdWV zY;hPTw_Mk-Y52*`bp4^81D0j$V=K!my5ffttN z&BWk)HJ?sG`6A8xc*pwm{;dq_UWTqtlsSNymlFEH22Ki?X9&7(*`CTEXBAryjs>2J z5&J7uMH_f$(aG^(4!dc*EZ*nCtlyLJ` z6BK4#^{8ahm>2n?mv{So*eAk;V_UR?!x*IbfSb8kyC=I|tIpBXQalY~b7Dr9GWbh0 zZ3~^0>W!f8m(EnpHP@!A06U(2x?L!TAqz_wB&`$oZ+s@n)Kr3hy%7-BXAseaxH=h< z&{+VN0gp}#nE0%Iwfb(h$Z(?!TBFLIH}jl~V{*$xx;JB<#M=x$#KnZPKeICxU1Yui z_VX@9|In1jbVMHB;_pT$s0^?-z{hSbTWKS1Ho7PDZ2xx~J+U|0{iPwy_HQbDfjljg zSd@5Ql)hW@s&hwGJxy|0T6B~~D0#G#tft)21~ge zOpojPZ45kb<`iI~57*xxl4&h^3Z;&#y!FbP-Flg&iRf@HxkMFch>bG0-As)q;JVJR z9?f%hHTzXp7gdFcS9XH~-y5|7?1=WpsFmQP-&`Ozy;|i9g?6%fF*Y&IOczLhcmzdO zZ~cz#iqc5vhlK|EEqkXtQ}EEfchIGDJA z(B;482@WitxjdZEY7KE9-s*3ltn#Z?J{~j{+-uoZxFEyR?R~PAL0kT= z@Z8Dj*7W@N)vg~aop8wAusRf7q2xpwy)ea|Gpmof^OjiSG3ZOS)#xCush+TnTQ;fzIbjF*ei+jAb8l{Vzk=8GawjNaEXk9i`lyM8=Nem8_`#iGLzZR94>+ z#z(-9%hm{sZ&-)+*+tFxpRB0!-H zpHq8Eb{R9*$ZGMi>9G8dmVKzx@SND_BvsGF$Ri`R{0gp&=hT76>q3pb#>z;V_gTiF z94V4M6&<$u^MP;qy9umCON!*z`Lv2*jYB80r!#+HeU7_1V$TPGK;VHhio};!GWmbj zZhFJkAf()J*eqB`euho{f_aO0Yc0})MTX9BitEcWTY_shsDh#8s;A^Zb*F5DwpXQ3 zKm1(4^6V?#lm#i_5K?=hBA0{Mx7Q6Qq$d;F51YAMt_(1ng!A)Slz)Ge|D^{_k_B+^ zC+jJ%7eH4EEtcfiPtyfw(gG4JF8j7E>>UqRudIy9spmQl)@E`g^l{gw4ft&J2o_u5 zvdciZf;>P4f`wg=nccJDio#9WsK{Zz(>{IqvX?`50nl>T9r@+HP8|?o%R)*2FYBBd ZB2ja=M=wK3SE_u!M?jH~D%aq<{{kT5184vM literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/icon_round.png b/app/src/main/res/mipmap-hdpi/icon_round.png new file mode 100755 index 0000000000000000000000000000000000000000..5108683c86f19eba80287668c09a86fd773b448d GIT binary patch literal 3503 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/icon.png b/app/src/main/res/mipmap-mdpi/icon.png new file mode 100755 index 0000000000000000000000000000000000000000..6ad4b84dae36910939284a79ebedb494c1c4dafb GIT binary patch literal 1155 zcmV-}1bq96P)k*C9~Nrwzn}@typ{FU4Y{R z2=CAk#=E*OaqSm)2b>5@PtU>4+?{}TWCZa0slYMG$wJ3WyIj;*08>_;*Ubh73j}Bx zQl2PAMnePQESa=W_&pws{n!P*sZo#(RSe}7SabYsXtY`kHh+lW))s1BE6>kyOBN8a za~zT%ErhC9%KcjL0Mka6H364vKYd(F%9=zVE7$deSE$%OT1+pr=%9X_8AcKcNn7ncZ@3SFB!**pw8>LctaKZ4H7Tttb|l*8s;M`<;_8R#wv575$yOGLDKe zrddlhfmppBIn5to<;IPQ;7R4bzxoot9eJH8k7@#BHp)JB9LA@gVQN?`h-LPft*@Q{ znNf8*JZ%42cq%E*rbdjMIn9(pRRPlCx{q71>ailG#=`~u@zzm{e*PI#4%G#c3Ja0j z`YAO3Z84ZAf`aOt|a??gP+M V3{U=eu=4-_002ovPDHLkV1nL79O3`~ literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/icon_foreground.png b/app/src/main/res/mipmap-mdpi/icon_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a13a49738e8859115c414f92949dfb4ead3861 GIT binary patch literal 1114 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 JPDHLkV1hX`H0=NY literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/icon.png b/app/src/main/res/mipmap-xhdpi/icon.png new file mode 100755 index 0000000000000000000000000000000000000000..6e58ea76a644d296f076425837c37a0eb3b80b79 GIT binary patch literal 2274 zcmV<82p#u{P)m|B^MWj0N|s!{Rn zWMxj)lwyrGrOxCV60eWTofMUaT@){fw^_%I0p5GhIs5GMxR3qQyVu%#t?&Ex-e*5B z2!Uc~27(N2J|U6r5-06xHc-ITx`03Tw$E=u4EfDbZXb0u&C zz=xTysS>yV;0MgtObMz1@FV7Hq6Ad{_#yMTD}fmRKW08xB`^UHVE%m@+swPDiU9~P z-|eXa(=Mta00PXHJVH{e1la%tm@k=pv4SEc$O0h1eA&rYe8wyZK!Ev*ldnh#9sy9p z{IsG?XrGaR8zm*US#laR`}d>v*iqcBu4azN3k@ab1h)XFWqxA*93axc;fl2M)k~ zR8ef0!@Q*Ch3Lxvz_$x;M`hI(|>Xt$&G_%YO-wZKts^*Bs5 z*4j~DaRs-m7vXGZP}{|O_Cc*%BRnk~ts>f^_Si8r*4A?KO^!y`Y%X)HDFD=PMBlzh znll&e($csFM9ywmt*9w3M%9l$;KqsL%>E<#^+WRFB?wKptJXUX2QI$%F0OsOli6oW zL&E@|j)X)hz#8pEJW<6(f8^) z91bj)Uw{cY6Vba*AK~9g34gC$gTGg;l=SJTg6RMdI~$ul63I(GP!(J=W2X}p8;f9F z>e*+v_ZFkW=%<^R+U<7aPRzl~S+kIt^+dDZE-YGzt2?$c_tQ`SXby-RFc6ONax~t! zfsm*uge4^*JUty9o*jeWurTJpTpBu^uof;Ah7MONrMMTyqwBo4WVcCvXed%s3xj~+$oOOq9^tX%mwTmjUnwkfGdUi?1VrKiiyfnoLNgRpeU z6x3H-=F$gK06>wn3J({SqV3XpA@sonIBz!s&N~S07>9`d{ka6o!wIkDr`Q+M0N^e; z1k5Af>{2{T@JMz`AG9^{XXYSb3CgRO8UR;oa$bS6_^I6e9nQTmm&MerjcEah&CW)r zY17fBYgeuTt8sSW?fJsC2G3$j03rtrK#x^xfFQ|(Ii9(Y^i`5GLD-$;SxgB44L#jI z`IPHcgxaJvR8`{SGf#6rxicjIlq~u#NG<%(G%KJwiv=g2`G0>%Eudbp3Zhf9jGy=N zidB^#zXX6XmhsbGQ!GLK76AG}Zn`zBipDC8Z=U%Jr^b#^;lZ`3Y3Bg3yWF>>8BEStTi`lF#$ZSE?^w4?uYDKEjKem|?@EV)gj@l`WfLT~?@T z^1b>yfF@YF+TQXWr&1J%?c#MsrM5ikvnW8-6D1y8b5KU7n>&v^>hSUEkvTyf=BcV)4QDNRL`l^Gubcr=m^N;KAtr>1S$O z+_R-G+|rk)fF1=JP}rZTik&q=35m1kAmPR4Ph44(N0)02dJ-$^PZr3!kfXN}Xj`G< z*yj*EWT^0lfVI#gz7yFaSk2YgNitt_E(?Gr!;$WPc0PLOP&_oRfazMh?c?Rb`v9Gb zEaoc)z{oive&Qq~y{_!8CM`Qp=S;xO(h@!MFPr&H02rx+)D@o~`iUn2r&Acy8)~W% zGt~Y60bxIMNSJ(eEQ*-V41iHepuPSF`u4>gNB!MeLGC2(iHrU3Yu5;S4H<^cGJ5;SAJE&zDB5;SGL zZUA_x5;SMNt^jzM5_Dm{?f`g+5_Ds}Apn?M3A!@hFaS)d1l^f$C;%MxV|>Pi>_d5< wiP&U;1OPA?kN^My01VE6!OaI0U@!px0#T3pjz5mSSpWb407*qoM6N<$g1omkBme*a literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/icon_foreground.png b/app/src/main/res/mipmap-xhdpi/icon_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..2ee0499ec36ddc2bbb407411db79b4c3fadab8b0 GIT binary patch literal 2181 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/icon_foreground.png b/app/src/main/res/mipmap-xxhdpi/icon_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..5ba37a0935778b81c24dace92dac59f9c071eec9 GIT binary patch literal 3400 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 BTfG1P literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/icon_round.png b/app/src/main/res/mipmap-xxhdpi/icon_round.png new file mode 100755 index 0000000000000000000000000000000000000000..5d7caf4cfbd83643409af387948c3532c23ab67c GIT binary patch literal 7721 zcmV+^9@gQBP)^d*A!sXEGTN z<6%6Ehw(5T#v@Q4#AK>6!ek0US!yy>El!lr;dhLYtArpy5NtA;f>H2wd4Pc5bv>Q| zt_lViMX@D)HicngHq@xWr8ykc)(S%XHKN#bjUY6a1YYC+@ICwtezqi#D8MoR6=0xI zT#dW;(|Mj<<8-#la60>djK~nh&*6Ck$U%?`AU}cJ0J#Zr8-!4~P5*a;e&z!G&IWpn z5qL~IHvUFYfGV%WGaed(2Jd{d8tJ0=e0qHROi*wZ$Tbxx3M9Q8;^uhx8#}>j&A{Kr zbHH;kz@)Q>;-1w1L)VfKAKw*ZA}DbmwHWSzavPL;6D3U)Z%G3GLxK116er5(l0Aiox}G;Z989wkk2pM_l=UdsZ!HUmgr1de(DA)M|E1HZ12i&D9X zK$HRwRrs3LtxZUHsHkx;9v<)UhT*fr}esq86ya@**Y5TH3H-C|vmRg3#RHI^~Mg zlx-$j!Smy#4lV^a(KOkBuiutnx&7CP> z2q!+Fh5ot^@s>4b`&@@c37hv0o;Ndj>k45xPz`s#57Vo4(8dkA6S|;XPR*2q`8C z9$ij*Q1e(NT@**D@;rtTb&|D)@SZFbgz+XlmdYwDf3?&3q^gF;ND}HO*@!w>4j`J# zalLgFnJH+diNfoZwE!$o3e=Vg!cP+zrmikXwF~drVoZ$c-<7QfE3`-ucA6-7{K|)D zZlMa0v=0s56ELLu<_ZAOe4Za`a#_IO7t*}a>1=KAp1|Wn;L6BUp6_UqyO;#~%XJ08 z3GFgmS75rbuN;nS&|!$?uB^ayiQ-$ObzK?NtCKagYDtn&t(u`sKe{rE%4T!iP)%JK z&16KN260i)#YFwxf&x-}&AH!I- z4s~TgT5+EsIDvU(ab4N(4I|gC{Xo9I{*Sxz<4@$m&Mb0x`~(F2 z0V_1m;aFs%?f*0(&MV|DU$@IboVPvoG|4}Ap)i0{K*IMf?%qR=&-;vQ>)Dg6Z`zck zCnOlk_93BO;&9v^rv;&=CJwF7in0>twe{+eob)yB0pucAbMwjhOpMY}MLubKWD=ca}g{KbB!0^O+SYus))=niA(SPgkt1TbCT0J%?NaV0a87wPni7 zCl`0^k%;)dL4(Pr&Yj7I<}JwD1`Ws>ICgq`eCb8+iuU0-qApj-^JMFNVucjzvy|ss zc`IqSu3G=t;38<8n_pD&$Gu`GF?l4MPtI%M}>UniFj9+tR{ zzk%c~GQ7Ain;e-ogJj-!pYJUbfFiR)2XbNCc5?0eAB#Mv^P4u4%=YcQc0P(u7x4Vg z16j5<>b#dXKtwZ?K`TV@Z@w(m*x0(YH0J@yK6r>M{(31nefGTD_b=?&Nwz%pm^X4lw{Vhmirqd7bzf#T zrns-yST;J1uJ7`D*D$!_*EMQPwmkYMIsU~0zk>)}?B0QIlQjVF@?6)pC!Zvj_GTCP zJ2`N}JpRNJBqk575f{fa?X)>uV3!>3b{0Sd5lJ6ta zrjxbx>w9%-<4d0Z*IRLMNr;6~B^8zEYmp%QF+`7Ld66j!H;7^ygbk$pPL>t?-C0n|6Bm3SRB28!P|KLNCJ!GgX?+ug4cd1Hb zD*(63dbzK!s}v>OBat3vwf3d?pioZ%6uMLp-le^Vb>9da&G;Ei$W;;mAxA9FbcLq? z!sr{zJ3e9A(TE9;07O3&_MIS1*P1|=89+5^NCo$m0zeSOp%vC>Y^5s2@eH#7G2sz_ zI?5a<0=}3M2mrz=!4nG?RhZDfB)NR(2+8c&QLELfQY1FnZpUK#$c~>J(zX?QfB3UeKt0>g~tFIZm~3mFW%52fC_497B8uE0K!y-v~*iz0Da|f{P+2o zm^O%wVgW=`)nP+fHVF>!KfMA7Wqp$-Qbbaz0F<>`DtplyKscT8g2mDfvC*rzT#y2w zcUiWX-T{QN>467zRoYrn0knYUfAa`H)I5c~W3e=W1N=wt075x3b(#SnUvnUb<3?}U zg@v^!ZbDT7&;YA7F-;Wzsk<=V-Fm8*`&OEeUTXlQilQ8a@%+Dfn$0ae2GEOUa~=5d z4}kz6tR2Fx8U}!T7sk)$`RiSyqMDWnAf*zqOGHHcYJU`yl_er;-n`OOFygcgF8S6P zKyx@Q|DLe0dWa2A!g$u_%a9Wp`C^e?6h^sho**7kU))GKi zRKLjKAb*XG?T?u72tbd>QCQ3yR%_dI9Z#qhCp-E)CoOv^&q|Fe7cNPi(M~U4Aw@q} zhkS7KXma|y735O(e$7itq(b_-^)$~yf9`Pn_bIcvE3HTjFA+dA&W~yk9$pOy)cN!P za%1Yy9-CES*RRvdz9X0RACww4;BpvOQGjykz#;hTa&ma$r&4R*t&cw;bxXyj=-5dX zxd$#W!tNJXhkazqR88IGp>g9iZHTVue7fD9TSLwPMbRW;iK|nqa`0hz=9US<`t$%I z((af1)FA7dH3L9APO@Hl`FA4i4%DhOS)bIbR0I_l_2sNi)2xXVHfGRxJ18jv8^^M^ zwAmrZ?#rVN9YJ7)qT!kO!r}NdBftUVOF24omL>o?HfJta!Ma)#XsPAzFq`c&!~(^H zM_V8SwUE(fO}5*gH}*m;I`@Q%^?CO*us$2xwAI@BNCbKz5a?Iq;@&_kP)v9PpenUx zA|3lwWMnh&h1UaNPE7NHHgI`J)P3Fw_Ja|A+08IRUXAhdgE2835DV2kAkYN>Lb8NQ zd*HPQW^7A95@{b7_wOJ6flt!~I5mT7{Sb+uz zvY{JWBnVj*-USkfN{AEQ{SZYEj*Xnaa3_ zDw?biYQjV~=#W&6dPe)J90VH|oL#$K(+%vh`u5edNUWsZ(3m_NV6h~l&g;tn3Ne*q z&#+t-XbDCBbVrhmyBdwz5 zzK}c*wpzbIUDpBtmB)P*ipFSGTIgjqKfGKN{}<@@{Wob_Z>?8x zpnJqU>bO|ot-mEQ?Uc#1vrk-HkL3=>%|Ht2k)+~oK&O^1 z_e=MCoHIK*eWqR_Ew?-K%(B~WJuYXSouU`WvnzlQiII%FxUBYcyL~xkD+9p_NgeOO z>iBK>^N&A~WAo&)fm=OkU5Z*->w|lvzGJaq`STb^LIU#%4!+>Tlw#v7q~u^~Molp?j(V2foaviA&~ z0SNiVsc)D0bsg8~6)9wWQj%`159;hQo+tfcV@IJbeQkXTaUq=IhZrv&p6gHN`K^*G z6NH<(;XVx-NNc(LW_=)J_ti#lUU6NbcoT2@4;f|;=&%9RWt=a#PmvKBYclbeGw2c- z`Pf2-<3DLSo8rKIO81ZWkepq+j$FBLQBwe&S)HnBAD^;JSxn*i8yzAdkT}=$RpeEi z6~Y{W84y$*p6d-~+0mE=*WE;GLIPRWxG~xO$KK@F+Ow2e+Bcak;DXoL~g2fP1>*N>5(_==l8k znzdjlEqIWtCfn`#@xj6Oq0T^ef)>QNBtjjlxUv_l)|VDI9Jlqxhg{v7lppdzu^1jR ztKTcShG zZ58T<>d5X-*Hx4&i=jRhmx44-W|&PhGSlsZD<&Mb^>~u(eC~O&`Jpa_R)J!%S?;kD zrE9^GJVt5(qbKm7HyFw=+d(JT=ebUVJQWq=PuJzn3I)*=cpT9AYUpD@k|wZhHYThv zag`Q;g=bqH?IzVNdkUbv7{2Q$S%^3A`z(7Hbb(tn)uXzJQ%zS?G3n%?=0jFsW;HQO zEk;DNnPj)04rCBv4ut#A@5tzU8KWgxdvfD2GfrI$&j5!BE`<>k&MK zsuw9iW0lAZK{UZ`Kc#n0R2=Ev3S8;jhRh;MVK465?bqzH!g;=iG5&~Ub0~O}h>N8< z3DGlnT&Fsu!gzEtVo}xg+(Ii#_xX`9= zSgjLqCBO<%3`}06lew)aFov(h#ZAF6#j&Mh%mq4l+<^%FFpD$5@S-8SZqhR*rr&s$ zy|mB^Bm+m46~UJ55FJBkP8iMgkws_HYyM~kEfO>gyte}A}=05 zl!)^)$cy@0tz)O~{IB20*62=}VU2!AlyPh(aNMtb}Zvl|x+>uiG80erWa8(E#SkvbmVe zUM`buWl7O(y@H8anmg3mNHxlsM8zoxyq33YwuP;uqo1O{X^PiO-BmR@7O{raDIGV8 zqR|DK>}v3j1{irL7ReGE+^(<1^6?0k-80p0m#orC*(xbuQrw(h0ObOhTMB3}xPV+gEtD+XCI=xmaz4kCwcy55l3qX=A66HvZLuA(`xi_4Ne!y&g?p2Fr`ui-q z<5P~ihB>806i}%YP*fB}-%`MpN=14NU{H(e`)R80W>BzXP%t52knqok-~QBYzXs>B z9na~(n3xyf99zWK?xn%e(erE{7q~S5(Sjl)yJa%w!a2xtt&FF6{mPP?hEqbmF zdhW6GT0#xrXbYsOG$K)~QmhJ0I5$)S6O-^pBa2K<72f0us^-)}v_$1I;o+TXg@rv_ zCo-~I!^p_)DEJ!xhwo8m`ZxkxQkKAlc!KqZk%0}76M6d<+ecWTgM z#M5K)^f#>ZH)H5I7@!GIFjb{W3!&sRg634BDSuLcWuvZzrG%EFU{DK3-(%@#Z7QIc z=`o||Z-mj`40dr(2515tP-;*qzzU@b52wnHpjN}3DDQ{U?}Vy=q6Uirm`VaFS8xTn j08K6KKI3|vO859b-dg)vh4Id>00000NkvXXu0mjfOrN$` literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/icon.png b/app/src/main/res/mipmap-xxxhdpi/icon.png new file mode 100755 index 0000000000000000000000000000000000000000..74dbf9e4a5e7bd687af30f9ae4cb1456e315d22a GIT binary patch literal 4715 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 PoceEOY;_lJhe~oiXe&GN2g;KyV%7pcCm|H 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 + + +Vrae + +

    Inkomste deur advertensies

    +

    Daar bestaan 'n miskonsepsie dat indien die gebruiker nie op die advertensie klik nie, die blokkering, nie die webwerf of die program finansieel sal benadeel nie. Dit is egter nie waar nie, program ontwikkelaars verdien ook geld as die advertensie vertoon word. Dit is jou keuse of jy die advertensie wil blokkeer al dan nie. Persoonlik gebruik ek nie programme wat advertensie vertoon nie aangesien ek dit frustrerend vind, dus sal ek nie die programme sonder 'n advertensie blokkeerder installeer nie.

    + +

    Hoe werk AdAway?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Hoekom moet Android weer begin om veranderinge te implementeer?

    +

    Java en Android onderhou hulle eie interne DNS geheue. Die bedryfstelsel sal dadelik nuwe gasheer lêers vertoon (verifieer dit met ping op die "command line") jy sal egter Android weer moet begin om die DNS geheue en Java te herbou.

    + +

    Hoe om die webbediener in AdAway te gebruik?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    Hoe kan ek spesifieke gasheername blokkeer/toelaat?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Waar kan ek meer gasheer bronne vind?

    +

    Sien Lys van addisionele gasheer bronne vir AdAway.

    + +

    Help vertaal/rapporteer foute

    +

    Gaan asseblief na https://adaway.org.

    + + diff --git a/app/src/main/res/raw-af/help_problems.html b/app/src/main/res/raw-af/help_problems.html new file mode 100644 index 0000000..e1e9d90 --- /dev/null +++ b/app/src/main/res/raw-af/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Nie genoeg spasie op die partisie nie

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    Dit blokkeer nie advertensie in Programme XYZ nie!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Gestoorde advertensies

    +

    Somtyds stoor programme advertensies nadat dit afgelaai is. Dit veroorsaak dan die oorblywende advertensies in sommige programme. Jy kan probeer om die geheue van hierdie programme uit te vee in Android se Program lys en so die probleem op te los.

    + +

    Program XYZ werk nie meer nie!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Die terug knoppie in die webleser werk nie meer nie

    +

    Kan kan AdAway se lokale webbediener aktiveer in voorkeure as 'n omseiling.

    + +

    Die terug knoppie in die webleser werk nie meer nie

    +

    Kan kan AdAway se lokale webbediener aktiveer in voorkeure as 'n omseiling.

    + + + diff --git a/app/src/main/res/raw-af/help_s_on_s_off.html b/app/src/main/res/raw-af/help_s_on_s_off.html new file mode 100644 index 0000000..8ba6ca2 --- /dev/null +++ b/app/src/main/res/raw-af/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Toestelle

    +

    AdAway sal nie werk in jou toestel die sogenaamde S-ON stelsel gebruik nie. Hierdie 'eienskap' bestaan gewoonlik op HTC Toestelle en verhoed AdAaway om na die gasheer lêers te skryf.

    + +

    S-ON/S-OFF?

    +

    S=OFF beteken dat die NAND deel van die toestel ontsluit is en geredigeer kan word. Die verstek instelling vit HTC is S-ON, wat beteken dat sekere dele ontoeganklik is en nie geredigeer kan word nie. Verder meer , die egtheid van die kern sagteware word verseker deur die S-ON vlag.

    + +

    Het ek S-ON of S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Omseil

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway behoort nou te werk.
    16. +
    + + diff --git a/app/src/main/res/raw-ar/help_faq.html b/app/src/main/res/raw-ar/help_faq.html new file mode 100644 index 0000000..9fd51cd --- /dev/null +++ b/app/src/main/res/raw-ar/help_faq.html @@ -0,0 +1,32 @@ + + + +الأسئلة الشائعة + +

    الدخل من خلال الإعلانات

    +

    يوجد سوء Ùهم ÙÙŠ كثير من الأحيان وهو أنه إذا لم ينقر المستخدم على الاعلانات، ÙØ¨Ø§Ù„تالي لن يضرّ الحجب بصاحب الموقع أو صاحب التطبيق من الناحية المادية. هذا Ù…Ùهومٌ خاطئ، إذ يكسب المطورّون المال أيضاً عن طريق عرض الإعلانات. الأمر يعود إليك إذا كنت ترغب بحجب الإعلانات أم لا. أنا شخصياً لا أستخدم التطبيقات التي تعرض الإعلانات لأنني أجدها مزعجة جداً ØŒ ممّا يعني أنّي لا أقوم بتثبيتها بدون توÙّر حاجب للإعلانات.

    + +

    كي٠يعمل AdAway ?

    +

    يستخدم AdAway مل٠المضيÙين لحظر أسماء المضيÙين التي تخدم الإعلانات. مل٠المضيÙين هو مل٠موجود ÙÙŠ /system/etc/hosts يعيّن أسماء المضيÙين إلى عناوين IP. إنها طريقة تقليدية لتعري٠اسم المضي٠لأزواج عناوين IP دون الاعتماد على نظام اسم المجال (DNS). يتم إعادة توجيه جميع أسماء المضيÙين غير المرغوب Ùيها إلى 127.0.0.1 مما يعني أنها ستشير إلى جهازك الخاص.
    +إذا لم يكن مل٠المضيÙين قابلاً للكتابة ØŒ ÙØ¥Ù† الحل الاحتياطي هو استخدام خدمة VPN المدمجة. سيقوم بتصÙية الاتصالات لأسماء المضي٠غير المرغوب Ùيها والسماح للآخرين بالمرور.

    + +

    لماذا يجب على المستخدم إعادة تشغيل الجهاز لكي تأخذ التحديثات مجراها؟

    +

    Ø§Ù„Ø¬Ø§ÙØ§ على الأندرويد ÙŠØ­ØªÙØ¸ بالمخزون المؤقت للـ DNS الداخلي الخاص به. نظام التشغيل سيعكس Ù…Ù„ÙØ§Øª المضي٠الجديدة مباشرةً (التحقق من ذلك مع بينج ÙÙŠ سطر الأوامر) لكنك ستحتاج إلى إعادة تشغيل الجهاز لإعادة بناء المخزون المؤقت للـ DNS من Ø§Ù„Ø¬Ø§ÙØ§.

    + +

    كيÙية استخدام خادم الويب ÙÙŠ AdAway?

    +

    AdAway يمكنه أن يعمل أيضاً دون استخدام خادم الويب! +

    يمكنك تشغيل خادم الويب المحلي من إعدادات AdAway للإجابة على طلبات محلية لعنوان الـ IP 127.0.0.1. وهذا يعني أنّ الطلبات من التطبيقات إلى خوادم الإعلانات التي ÙŠÙØ¹Ø§Ø¯Ù توجيهها إلى 127.0.0.1 سو٠يتمّ الردّ عليها من Ù‚ÙØ¨ÙŽÙ„٠خادم الويب الخاص بـ AdAway. +
    ØªØ±ÙØ¶ بعض التطبيقات العمل عندما لا تكون خوادم الإعلانات قابلة للوصول. بهذه الطريقة ستصبح قابلة للوصول مرة أخرى ØŒ وسيكون الردّ بهيئة ØµÙØ­Ø© ÙØ§Ø±ØºØ© بدون أيّ صور إعلانية.

    + +

    كي٠يمكنني منع / السماح لأسماء المواقع محددة؟

    +

    أض٠أسماء المضي٠التي تريد حظرها إلى القائمة المحظورة من الشاشة الرئيسية. Ø¨Ø§Ù„Ø¥Ø¶Ø§ÙØ© إلى ذلك ØŒ يمكن Ø¥Ø¶Ø§ÙØ© أسماء المضي٠التي تريد استبعادها من الحظر إلى الأسماء المسموح بها وأسماء المضي٠التي تريد إعادة توجيهها إلى عنوان IP محدد ينتمي إلى تم توجيهها.

    + +

    أين يمكنني العثور على المزيد من مصادر Ù…Ù„ÙØ§Øª Ø§Ù„Ù…Ø¶ÙŠÙØŸ

    +

    اطلع على لإيجاد قائمة المصادر الإضاÙية Ù„Ù…Ù„ÙØ§Øª المضي٠لـAdAway .

    + +

    ساعد ÙÙŠ الترجمة أو ارسل ملاحظتك حول مشكلة.

    +

    يرجى الانتقال إلى https://adaway.org .

    + + diff --git a/app/src/main/res/raw-ar/help_problems.html b/app/src/main/res/raw-ar/help_problems.html new file mode 100644 index 0000000..8a79123 --- /dev/null +++ b/app/src/main/res/raw-ar/help_problems.html @@ -0,0 +1,36 @@ + + + +مشاكل شائعة + +

    ÙØ´Ù„ نسخ Ù…Ù„ÙØ§Øª المضي٠على أندرويد 9 أو أحدث!

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    المساحة غير كاÙية على القرص

    +

    حاول تغيير مسار مل٠المضي٠من الإعدادات الى /data/data/hosts (أو /data/hosts) وقم بإعادة تحديث AdAway مجدداً .

    + +

    لا يعمل على انظمة الاندرويد من اصدار 4.4+

    +

    حاول تغيير مسار مل٠المضي٠من الإعدادات من /data/data/hosts إلى /data/hosts أو /system/etc/hosts وقم بإعادة تحديث AdAway مجدداً .

    + +

    إنه لا يحجب الإعلانات ÙÙŠ التطبيق س ص ع!

    +

    قد تكون بعض أسماء المضي٠مÙقودة ÙÙŠ Ù…Ù„ÙØ§Øª Ø§Ù„Ù…Ø¶ÙŠÙØ§Øª المقدمة منHosts Sources أو يحتوي التطبيق على صور لتقديم إعلانات دون الوصول إلى الإنترنت.

    +يمكنك تسجيل طلبات الDNS من (Menu->Log DNS Requests) عن طريق AdAway وذلك Ù„Ù…Ø¹Ø±ÙØ© أسماء المضي٠الإضاÙية التي يجب حظرها. +

    أض٠أسماء Ø§Ù„Ù…Ø¶ÙŠÙØ§Øª المريبة إلى القائمة السوداء Blacklist الخاصة بك من خلال الضغط على الإدخالات ÙÙŠ السجل Log وبلّغ عن أسماء Ø§Ù„Ù…Ø¶ÙŠÙØ§Øª هذه عند التحقق منها ÙÙŠ Forum المنتدى Hosts Inbox لـ hosts-file.net.

    + +

    إعلانات مخبوءة

    +

    أحيانا بعض التطبيقات ØªØ­ÙØ¸ الإعلانات بعد التحميل. Ùˆ ذلك يؤدي إلى بقائها ÙÙŠ بعض التطبيقات. تستطيع حذ٠هذه الإعلانات المخبأة لتلك التطبيقات ÙÙŠ قائمة تطبيقات آندرويد لتطويق هذه المشكلة.

    + +

    التطبيق XYZ لم يعد يعمل بعد الآن.

    +

    بعض التطبيقات تحتاج إلى تواصل مع إسم الموقع الذي تم حظره من Ù‚ÙØ¨ÙŽÙ„ AdAway وإلا ÙØ¥Ù†Ù‡Ø§ Ø³ØªØ±ÙØ¶ العمل عندما يكون التواصل متعذّراً مع أسماء مواقع٠من Ø§Ù„Ù…ÙØªØ±Ø¶ أن تÙقدّم الإعلانات . يرجى زيارة https://github.com/AdAway/AdAway/wiki/ProblematicApps للحصول على قائمة البرامج Ø§Ù„Ù…Ø¹Ø±ÙˆÙØ© بهذه المشكلة بالتحديد . وإلا Ùيرجى محاولة Ù…Ø¹Ø±ÙØ© أسماء المضي٠المطلوبة ÙˆØ¥Ø¶Ø§ÙØªÙ‡Ø§ إلى القائمة البيضاء تحت قوائمك والإبلاغ عنها ÙÙŠ تعقّب العÙلل لـ AdAway.

    + +

    زر الرجوع للخل٠ÙÙŠ Ø§Ù„Ù…ØªØµÙØ­ لا يعمل.

    +

    تستطيع ØªÙØ¹ÙŠÙ„ خادم AdAway المحلي من الإعدادات كحل بديل.

    + +

    زر الرجوع للخل٠ÙÙŠ Ø§Ù„Ù…ØªØµÙØ­ لا يعمل.

    +

    تستطيع ØªÙØ¹ÙŠÙ„ خادم AdAway المحلي من الإعدادات كحل بديل.

    + + + diff --git a/app/src/main/res/raw-ar/help_s_on_s_off.html b/app/src/main/res/raw-ar/help_s_on_s_off.html new file mode 100644 index 0000000..afac4be --- /dev/null +++ b/app/src/main/res/raw-ar/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +مساعدة عن خاصية S-ON + +

    أجهزة HTC

    +

    adaway لن يعمل ÙÙŠ الاجهزة التي تستخدم خاصية S-on هذه الميزة موجودة ÙÙŠ اغلب اجهزة HTC وهي تمنع adaway من العمل

    + +

    تشغيل S - ايقا٠S

    +

    عدم وجود S يعني ان القرص غير مقÙول Ùˆ يمكن الكتابة عليه. الاعدادت Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠØ© لاجهزة HTC تجعل S تعمل وهذا يعني ان adaway لن يعمل

    + +

    هل لديَّ خاصية S-ON أم S-OFF ؟

    +

    قم بالإقلاع إلى قائمة الإقلاع على جهازك عن طريق الضغط باستمرار على زر Ø®ÙØ¶ مستوى الصوت أثناء الضغط على الطاقة وسيظهر النص الموجود ÙÙŠ الأعلى حالة العلم إما على S-OFF أو S-ON. الرووت الكامل يعني عمومًا S-OFF. +

    يمكن العثور على مزيد من المعلومات على www.addictivetips.com. قد تهمك طرق S-OFF الإضاÙية نظرًا لأن Unrevokable (ÙÙŠ الرابط) ØŒ وهي: Revolutionary Ùˆ Revone Ùˆ Firewater Ùˆ RumRunner Ùˆ Moonshine Ùˆ SunShine ...

    + +

    العمل

    +

    الشرط الأساسي: يجب عليك تثبيت Android SDK ÙØ¹Ø§Ù„ مع shell ADB على جهاز الكمبيوتر الخاص بك.

    +
      +
    1. يرجى الذهاب إالى قائمة الإقلاع على جهازك بواسطة الضغط على زرّ Ø®ÙØ¶ الصوت وزرّ التشغيل ÙÙŠ آن٠واحد .
    2. +
    3. يرجى الضغط على زرّ Ø®ÙØ¶ الصوت لتحديد الخيار recovery ومن ثمَّ زرّ التشغيل للإقلاع .
    4. +
    5. يرجى الذهاب إلى "قائمة الأقسام" ÙÙŠ ClockworkMod Recovery
    6. +
    7. يرجى اختيار mount /system، mount /sdcard و mount /data.
    8. +
    9. يرجى وصل كابل الـ USB ÙˆÙØªØ­ واجهة سطر الأوامر على حاسوبك .
    10. +
    11. يرجى الدخول إلى الـ adb shell وطباعة ln -s /data/hosts /system/etc/hosts (سيقوم هذا بإنشاء رابط رمزي symbolic link, ممّا يتيح لـ AdAway تحرير مل٠المضي٠المخزّن داخل /data ÙˆÙÙŠ Ù†ÙØ³ الوقت يستطيع نظام التشغيل استخدام المل٠وكأنه مخزّن داخل /system) .
    12. +
    13. يرجى إعادة تشغيل جهازك وتحديد مسار مل٠المضي٠إلى /data/hosts ÙÙŠ إعدادات AdAway .
    14. +
    15. AdAway يجب ان يعمل الآن .
    16. +
    + + diff --git a/app/src/main/res/raw-ast/help_faq.html b/app/src/main/res/raw-ast/help_faq.html new file mode 100644 index 0000000..e7359e7 --- /dev/null +++ b/app/src/main/res/raw-ast/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    ¿Cómo funciona AdAway?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    ¿Por qué tengo de reaniciar Android pa que los cambeos faigan efeutu?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ast/help_problems.html b/app/src/main/res/raw-ast/help_problems.html new file mode 100644 index 0000000..a044a14 --- /dev/null +++ b/app/src/main/res/raw-ast/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Nun hai espaciu abondo na patición

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Nun furrula n'Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    ¡Nun bloquia los anuncios na aplicación XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Anuncios na caché

    +

    Dalcuando delles aplicaciones atroxen na caché los anuncios dempués de baxalos. Esto conduz a que queden anuncios de delles aplicaciones. Pues intentar desaniciar la caché pa eses aplicaciones na llista d'aplicaciones d'Android pa burllase d'esti problema.

    + +

    ¡L'aplicación XYZ yá nun furrula más!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    El botón Atrás nun ta furrulando nos restoladores web

    +

    Pues habilitar el sirvidor llocal d'AdAway nes preferencies como una igua alternativa.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-ast/help_s_on_s_off.html b/app/src/main/res/raw-ast/help_s_on_s_off.html new file mode 100644 index 0000000..f50b251 --- /dev/null +++ b/app/src/main/res/raw-ast/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Ayuda rellacionada con S-ON + +

    Preseos de HTC

    +

    AdAway nun funciona cuando tas usando un preséu col llamáu S-ON. Esta «carauterística» esiste en munchos preseos de HTC y evita qu'AdAway escriba nel ficheru hosts.

    + +

    ¿S-ON / S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    ¿Tengo S-ON o S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. Agora AdAway debería funcionar.
    16. +
    + + diff --git a/app/src/main/res/raw-az/help_faq.html b/app/src/main/res/raw-az/help_faq.html new file mode 100644 index 0000000..e3be6c5 --- /dev/null +++ b/app/src/main/res/raw-az/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Reklam ilə gəlir.

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    AdAway necə işləyir?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Nə üçün effekti görmək üçün Android cihazımı yenidən başlatmalıyam?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    AdAway-də vebserveri necə işlədə bilərəm?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    Xüsusu host adlarını necə bloklaya və ya blokdan çıxara bilərəm?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Mən başqa host resurslarını hardan əldə edə bilərəm?

    +

    Baxış AdAway üçün əlavə host mənbələrinin siyahısı.

    + +

    Tərcüməyə kömək et/Xəta bildir

    +

    Xahiş olunur buranı ziyarət edin https://adaway.org.

    + + diff --git a/app/src/main/res/raw-az/help_problems.html b/app/src/main/res/raw-az/help_problems.html new file mode 100644 index 0000000..667d7d4 --- /dev/null +++ b/app/src/main/res/raw-az/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Yaddaşda kifayət qədər yer yoxdur

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-az/help_s_on_s_off.html b/app/src/main/res/raw-az/help_s_on_s_off.html new file mode 100644 index 0000000..5a78898 --- /dev/null +++ b/app/src/main/res/raw-az/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Cihazlar

    +

    ÆgÉ™r cihazda S-ON varsa, AdAway iÅŸlÉ™mÉ™yÉ™cÉ™k. Bu "funksiya" bir çox HTC cihazda mövcuddur vÉ™ AdAwayın hosts fayllarını yazmasına mane olur

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-be/help_faq.html b/app/src/main/res/raw-be/help_faq.html new file mode 100644 index 0000000..4eab7b9 --- /dev/null +++ b/app/src/main/res/raw-be/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Даходы ад Ñ€Ñкламы

    +

    ІÑнуе чаÑты зман, што калі карыÑтальнік не націÑкае на Ñ€Ñкламу, то, заблакаваўшы Ñе, не нанÑÑе шкоды Ñайту або праграме Ñž фінанÑавым плане. ГÑта нÑправільна: раÑпрацоўшчыкі зараблÑюць грошы проÑта за паказ Ñ€Ñкламы. Блакаваць Ñ€Ñкламу ці не, залежыць толькі ад ваÑ. ÐÑабіÑта Ñ Ð½Ðµ Ñтаў бы выкарыÑтоўваць праграму з Ñ€Ñкламай, бо Ñна вельмі раздражнÑе, так што без блакавальнікі Ñ€Ñкламы Ñ Ð± не Ñтаў ÑžÑталёўваць Ñ‚Ð°ÐºÑ–Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹.

    + +

    Як працуе AdAway?

    +

    AdAway выкарыÑтоўваефайл hosts, каб блакаваць імёны hosts, ÑÐºÑ–Ñ Ð¿Ñ€Ð°Ð´Ð°ÑтаўлÑюць Ñ€Ñкламу. hosts - гÑта файл, Ñкі знаходзіцца Ñž /system/etc/hosts, Ñкі адлюÑтроўвае імёны hosts у ÑкаÑці IP-адраÑоў. ГÑта звычайны ÑпоÑаб вызначÑÐ½Ð½Ñ Ñ–Ð¼Ñ hosts Ð´Ð»Ñ Ð¿Ð°Ñ€ IP-адраÑоў, не абапіраючыÑÑ Ð½Ð° ÑÑ–ÑÑ‚Ñму даменных імёнаў (DNS). УÑе Ð½ÐµÐ¿Ð°Ð¶Ð°Ð´Ð°Ð½Ñ‹Ñ Ñ–Ð¼Ñ‘Ð½Ñ‹ hosts будуць перанакіраваны на 127.0.0.1, гÑта азначае, што Ñны будуць Ð°Ð´Ð¿Ñ€Ð°ÑžÐ»ÐµÐ½Ñ‹Ñ Ð½Ð° вашу прыладу.
    +Калі файл hosts немагчыма адрÑдагаваць, іншым рашÑннем з'ÑўлÑецца выкарыÑтанне ўбудаванай Ñлужбы VPN. Ðн будзе фільтраваць злучÑнні з непажаданымі імёнамі hosts Ñ– прапуÑкаць іншыÑ.

    + +

    Чаму трÑба перазагружаць прыладу, каб змены ÑžÑтупілі Ñž Ñілу?

    +

    Java у Android мае Ñвой унутраны кÑш DNS. ÐÐ¿ÐµÑ€Ð°Ñ†Ñ‹Ð¹Ð½Ð°Ñ ÑÑ–ÑÑ‚Ñма будзе выкарыÑтоўваць абноўлены файл hosts адразу ж (можаце Ñž гÑтым пераканацца з дапамогай каманды PING Ñž камандным радку), але вы павінны перазагрузіць прылада, каб пераÑтварыць кÑш DNS Ñž Java.

    + +

    Як выкарыÑтоўваць вÑб-Ñервер у AdAway?

    +

    AdAway такÑама будзе працаваць Ñ– без выкарыÑÑ‚Ð°Ð½Ð½Ñ Ð’Ñб-Ñервера! +

    Ð’Ñ‹ можаце ўключыць лакальны Ð’Ñб-Ñервер у наладах AdAway Ð´Ð»Ñ Ð°Ð´ÐºÐ°Ð·Ð°Ñž на запыты да лакальнага IP-адраÑе127.0.0.1. Тады на ÑžÑе запыты host з Ñ€Ñкламай, ÑÐºÑ–Ñ Ð¿ÐµÑ€Ð°Ð½Ð°ÐºÑ–Ñ€Ð¾ÑžÐ²Ð°ÑŽÑ†Ñ†Ð° на ваш лакальны IP-Ð°Ð´Ñ€Ð°Ñ 127.0.0.1 будзе адказваць Ð’Ñб-Ñервер AdAway. +
    ПÑÑžÐ½Ñ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ адмаўлÑюцца працаваць, калі не маюць доÑтупу да host з Ñ€Ñкламай. ГÑты метад дазволіць запуÑкаць Ñ‚Ð°ÐºÑ–Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹, але замеÑÑ‚ Ñ€Ñкламы будзе падÑтаўлÑцца пуÑтое меÑца Ñ– адÑутнічаць выÑва Ñ€Ñкламы..

    + +

    Як Ñ Ð¼Ð°Ð³Ñƒ заблакаваць/разблакаваць канкрÑÑ‚Ð½Ñ‹Ñ Ñ–Ð¼Ñ‘Ð½Ñ‹ host?

    +

    Ðазву hosts, ÑÐºÑ–Ñ Ð²Ñ‹ хочаце заблакаваць, патрÑбна дадаць у Чорны ÑпіÑ, Ñкі знаходзіцца на галоўным Ñкране. ТакÑама, назву hosts, Ñкі не хочаце блакавць, патрÑбна дадаць у Белы ÑпіÑ, а назву hosts, Ñкі патрÑбна перанакіраваць на пÑўны IP-адраÑ, трÑба ўнеÑці Ñž Ð¡Ð¿Ñ–Ñ Ð¿ÐµÑ€Ð°Ð½Ð°ÐºÑ–Ñ€Ð°Ð²Ð°Ð½Ð½ÑÑž.

    + +

    Дзе Ñ Ð¼Ð°Ð³Ñƒ знайÑці больш крыніц ÑпіÑаў host?

    +

    ГлÑдзіце ÑÐ¿Ñ–Ñ Ð´Ð°Ð´Ð°Ñ‚ÐºÐ¾Ð²Ñ‹Ñ… крыніц host AdAway.

    + +

    Дапамагчы з перакладам/паведаміць пра памылку

    +

    Калі лаÑка, перайдзіце на https://adaway.org.

    + + diff --git a/app/src/main/res/raw-be/help_problems.html b/app/src/main/res/raw-be/help_problems.html new file mode 100644 index 0000000..86aa7d2 --- /dev/null +++ b/app/src/main/res/raw-be/help_problems.html @@ -0,0 +1,37 @@ + + + +ЧаÑÑ‚Ñ‹Ñ Ð¿Ñ€Ð°Ð±Ð»ÐµÐ¼Ñ‹ + +

    КапіÑванне файла hosts не ўдалоÑÑ Ð½Ð° Android 9+

    +

    ÐÐ¿Ð¾ÑˆÐ½Ñ–Ñ Ð²ÐµÑ€ÑÑ–Ñ– Android выкарыÑтоўваюць раздзел /system даÑтупны толькі Ð´Ð»Ñ Ñ‡Ñ‹Ñ‚Ð°Ð½Ð½Ñ.
    +Калі вы выкарыÑтоўваеце Magisk, Ð´Ð»Ñ Ð°Ñ‚Ñ€Ñ‹Ð¼Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¾Ñž root, пераканайцеÑÑ, што вы ўключылі беÑÑÑ–ÑÑ‚Ñмны модуль hosts, затым перазагрузіце.

    + +

    Ðе хапае меÑца Ñž дыÑкавым раздзеле

    +

    ПаÑпрабуйце змÑніць шлÑÑ… да файлу host у наладах на /data/data/hosts (ці /data/hosts) Ñ– прымÑніце зноў AdAway.

    + +

    Ðе працуе на Android 4.4+

    +

    ПераканайцеÑÑ, што вы адключылі лёгкі Ñ€Ñжым (раней вÑдомы Ñк захаванне дадзеных) у наладах Chrome. ГÑÑ‚Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ‹Ñ Ð´Ð°Ð·Ð²Ð°Ð»Ñе Chrome выкарыÑтоўваць прыватнае рашÑнне DNS Ñ– абыходзіць AdAway.

    + +

    Ðе блакуецца Ñ€Ñклама Ñž пÑўнай праграме!

    +

    ÐÐµÐºÐ°Ñ‚Ð¾Ñ€Ñ‹Ñ Ñ–Ð¼Ñ‘Ð½Ñ‹ hosts могуць адÑутнічаць Ñž адпаведных файлах hosts з Крыніц host або праграма мае камплект выÑÑž Ð´Ð»Ñ Ð¿Ñ€Ð°Ð´Ð°ÑÑ‚Ð°ÑžÐ»ÐµÐ½Ð½Ñ Ñ€Ñкламы без доÑтупу Ñž інтÑрнÑÑ‚. +

    +Ð’Ñ‹ можаце зайÑці Ñž журнал запытаў DNS (Меню-Опции-Журнал запытаў DNS) AdAway, каб выÑветліць, ÑÐºÑ–Ñ Ð´Ð°Ð´Ð°Ñ‚ÐºÐ¾Ð²Ñ‹Ñ Ñ–Ð¼Ñ‘Ð½Ñ‹ host павінны быць заблaкаваны. +

    Дадайце Ð¿Ð°Ð´Ð°Ð·Ñ€Ð¾Ð½Ñ‹Ñ Ñ–Ð¼Ñ‘Ð½Ñ‹ host у ваш Чорны ÑÐ¿Ñ–Ñ Ð´Ð¾ÑžÐ³Ñ–Ð¼ націÑкам на Ð·Ð°Ð¿Ñ–Ñ Ñƒ журнале, Ñ– паÑÐ»Ñ Ð¿Ñ€Ð°Ð²ÐµÑ€ÐºÑ– паведаміце аб гÑтых імёнах host на форуме Hosts Inbox на hosts-file.net.

    + +

    ЗакÑÑˆÐ°Ð²Ð°Ð½Ð°Ñ Ñ€Ñклама

    +

    ПÑÑžÐ½Ñ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ кÑшуюць Ñ€Ñкламу паÑÐ»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÑ–. З-за гÑтага Ñ€Ñклама можа заÑтавацца Ñž гÑтых праграмах. Ð’Ñ‹ можаце паÑпрабаваць выдаліць кÑш Ð´Ð»Ñ Ð³Ñтых праграм у ÑпіÑе праграм Android Ð´Ð»Ñ Ð»Ñ–ÐºÐ²Ñ–Ð´Ð°Ñ†Ñ‹Ñ– гÑтай праблемы

    + +

    ПÑÑžÐ½Ð°Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ð° пераÑтала працаваць!

    +

    Ðекаторым праграмам неабходна звÑзвацца з адраÑамі, заблакаванымі AdAway, ці праграма не працуе, калі імёны host ÑÐºÑ–Ñ Ð°Ð´Ð»ÑŽÑтроўваюць Ñ€Ñкламу недаÑтупныÑ. Ðаведайце https://github.com/AdAway/AdAway/wiki/ProblematicApps, каб азнаёміцца ​​Ñа ÑпіÑам праграм, ÑÐºÑ–Ñ Ð¼Ð°ÑŽÑ†ÑŒ Ð¿Ð°Ð´Ð¾Ð±Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ð±Ð»ÐµÐ¼Ñ‹. Ðльбо выÑвÑтліце ÑÐºÑ–Ñ Ñ–Ð¼Ñ‘Ð½Ñ‹ host Ð½ÐµÐ°Ð±Ñ…Ð¾Ð´Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ð°Ð¼ Ñ– дадайце Ñ–Ñ… у Белы ÑÐ¿Ñ–Ñ Ñƒ катÑгорыі Вашы ÑпіÑÑ‹ Ñ– паведаміце аб гÑтым багтрÑкеры AdAway.

    + +

    Ðе працуе на Android 4.4+

    +

    ПаÑпрабуйце змÑніць шлÑÑ… да файлу host у наладах з /data/data/hosts на /data/hosts ці /system/etc/hosts Ñ– зноў прымÑніце AdAway.

    + +

    Ðе працуе кнопка «ÐÐЗÐД» Ñž вÑб-браўзерах

    +

    Ð’Ñ‹ можаце ўключыць лакальны вÑб-Ñервер AdAway у наладах Ñž ÑкаÑці абыходнага шлÑху.

    + + + diff --git a/app/src/main/res/raw-be/help_s_on_s_off.html b/app/src/main/res/raw-be/help_s_on_s_off.html new file mode 100644 index 0000000..5e42b57 --- /dev/null +++ b/app/src/main/res/raw-be/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Даведка па S-ON + +

    Прылады HTC

    +

    AdAway не працуе на прыладах, ÑÐºÑ–Ñ Ð¿Ñ€Ð°Ñ†ÑƒÑŽÑ†ÑŒ у Ñ€Ñжыме S-ON. ГÑÑ‚Ð°Ñ Ð°ÑабліваÑць маецца Ñž многіх прыладах HTC Ñ– не дазвалÑе AdAway змÑнÑць файл hosts.

    + +

    S-ON/S-OFF?

    +

    S-OFF азначае, што чаÑтка памÑці, званай NAND, Ð°Ð´Ð¼Ñ‹ÐºÐ½ÑƒÑ‚Ð°Ñ Ñ– дазвалÑе выраблÑць запіÑ. Па-змаўчанню прылады HTC працуюць у Ñ€Ñжыме S-ON, а гÑта азначае, што вы не можаце атрымаць доÑтупу да пÑўных аблаÑцей памÑці. ÐÐºÑ€Ð°Ð¼Ñ Ñ‚Ð°Ð³Ð¾ ÑцÑг S-ON правÑрае лічбавы Ð¿Ð¾Ð´Ð¿Ñ–Ñ ÑƒÑÑ–Ñ… прашывак.

    + +

    ÐœÐ°Ñ Ð¿Ñ€Ñ‹Ð»Ð°Ð´Ð° працуе Ñž Ñ€Ñжыме S-ON або S-OFF?

    +

    ЗагрузіцеÑÑ Ñž меню загрузніка на вашай прыладзе, утрымліваючы кнопку памÑншÑÐ½Ð½Ñ Ð³ÑƒÑ‡Ð½Ð°Ñці Ñ– адначаÑова заціÑкаючы кнопку ўключÑннÑ, паÑÐ»Ñ Ñ‡Ð°Ð³Ð¾ вы ўбачыце уверÑе Ñ‚ÑкÑÑ‚, Ñкі пакажа Ñтатут ÑцÑга - S-OFF або S-ON. Звычайна поўны рут-доÑтуп азначае S-OFF. +

    Больш інфармацыі можна знайÑці на www.addictivetips.com. Ðазвы дадатковых метадаў S-OFF, ÑÐºÑ–Ñ Ð¼Ð¾Ð³ÑƒÑ†ÑŒ Ð²Ð°Ñ Ð·Ð°Ñ†Ñ–ÐºÐ°Ð²Ñ–Ñ†ÑŒ, пачынаючы з Unrevokable (па ÑпаÑылцы): Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    РашÑнні

    +

    Патрабаванне: Ð’Ñ‹ павінны ÑžÑталÑваць працоўны Android SDK з абалонкай ADB на ваш ПК.

    +
      +
    1. ЗагрузіцеÑÑ Ñž меню загрузкі прылады, утрымліваючы кнопку памÑншÑÐ½Ð½Ñ Ð³ÑƒÑ‡Ð½Ð°Ñці пры заціÑнутай кнопкі выключÑннÑ.
    2. +
    3. ВыкарыÑтоўвайце кнопку памÑншÑÐ½Ð½Ñ Ð³ÑƒÑ‡Ð½Ð°Ñці каб выбраць Ñ€Ñжым аднаўленнÑ, затым кнопку уключÑннÑ, каб загрузіць Ñго.
    4. +
    5. У Clockwork Recovery перайÑці Ñž "partitions menu".
    6. +
    7. Выберыце mount /system, mount /sdcard і mount /data.
    8. +
    9. Падключыце ваш Ñ‚Ñлефон да ПК праз кабель USB Ñ– адкрыйце акно каманднага радка на ПК.
    10. +
    11. ЗапуÑціце абалонку ADB Ñ– ўвÑдзіце ln -s /data/hosts /system/etc/hosts (гÑта Ñтворыць знакавую ÑпаÑылку, ÑÐºÐ°Ñ Ð´Ð°Ð·Ð²Ð¾Ð»Ñ–Ñ†ÑŒ AdAway Ñ€Ñдагаваць файл hosts, размешчаны па шлÑху /data, адначаÑова дазвалÑючы ÐС выкарыÑтаць гÑты файл так, Ñк калі б ён размÑшчаўÑÑ Ð¿Ð° шлÑху /system).
    12. +
    13. Перазагрузіце вашую прыладу Ñ– уÑталюйце ШлÑÑ… да файла hosts на /data/hosts у наладах AdAway.
    14. +
    15. ЦÑпер AdAway павінен працаваць.
    16. +
    + + diff --git a/app/src/main/res/raw-bg/help_faq.html b/app/src/main/res/raw-bg/help_faq.html new file mode 100644 index 0000000..8a8b8b2 --- /dev/null +++ b/app/src/main/res/raw-bg/help_faq.html @@ -0,0 +1,32 @@ + + + +ЧЗВ + +

    Приход от реклами

    +

    Има чеÑто Ñрещана заблуда, че ако потребителÑÑ‚ никога не натиÑка реклами, тогава блокирането им нÑма да навреди финанÑово на Ñайта или приложението. Това не е така, дивелъпърите печелÑÑ‚ пари Ñамо като показват реклами. ЗавиÑи от Ð’Ð°Ñ Ð´Ð°Ð»Ð¸ ще блокирате реклами или не. Лично аз не бих ползвал приложениÑ, които показват реклами, защото ги намирам за много дразнещи и затова не бих ги инÑталирал без блокиране на рекламите.

    + +

    Как работи AdAway?

    +

    AdAway използва хоÑÑ‚ файл, за да блокира имена на хоÑтове, които облужват реклами. ХоÑÑ‚ файлът може да бъде открит в /system/etc/hosts. Той Ñвързва имена на хоÑтове към IP адреÑи. Това е традиционен начин за дефиниране на двойка име на хоÑÑ‚ към IP Ð°Ð´Ñ€ÐµÑ Ð±ÐµÐ· да Ñе разчита на СиÑтемата за имена на домейните (DNS). Ð’Ñички нежелани имена на хоÑтове Ñе пренаÑочват към 127.0.0.1, което означава, че те ще Ñочат ÑобÑтвеното Ви уÑтройÑтво.
    +Ðко хоÑÑ‚ файлът не може да бъде редактиран, резервно решение е да Ñе използва VPN уÑлуга. Ð¢Ñ Ñ‰Ðµ филтрира връзките към нежелани имена на хоÑтове и ще позволÑва на други да преминават.

    + +

    Защо трÑбва да реÑтартирам Android, за да имат ефект промените?

    +

    Java на Android поддържа Ñвой ÑобÑтвен вътрешен DNS кеш. Операционната ÑиÑтема ще отрази Ð½Ð¾Ð²Ð¸Ñ hosts файл моментално (потвърдете това Ñ ping или команден ред), но ще трÑбва да реÑтартирате Android, за да преÑтроите DNS кеша на Java.

    + +

    Как да използвам уебÑървъра в AdAway?

    +

    AdAway Ñъщо така ще работи без използването на уеб Ñървъра! +

    Можете да включите локален уеб Ñървър в предпочитаниÑта на AdAway, за да отговарÑте на заÑвките до Ð»Ð¾ÐºÐ°Ð»Ð½Ð¸Ñ IP Ð°Ð´Ñ€ÐµÑ 127.0.0.1. Това означава, че заÑвки от Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÐºÑŠÐ¼ рекламни Ñървъри, които Ñа пренаÑочени към 127.0.0.1, ще бъдат отговарÑни от уеб Ñървъра на AdAway. +
    ÐÑкои Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¾Ñ‚ÐºÐ°Ð·Ð²Ð°Ñ‚ да работÑÑ‚, когато рекламните Ñървъри не Ñа доÑтъпни. Чрез този метод те ще бъдат доÑтъпни отново, отговарÑйки Ñ Ð¿Ñ€Ð°Ð·Ð½Ð° Ñтраница и без рекламни изображениÑ.

    + +

    Как мога да блокирам/разблокирам определени имена на хоÑтове?

    +

    Добавете имената на хоÑтовете, които иÑкате да блокирате в ÑпиÑъка Блокирани, намиращ Ñе Ð½Ð°Ð½Ð°Ñ‡Ð°Ð»Ð½Ð¸Ñ ÐµÐºÑ€Ð°Ð½. Ð’ допълнение, имена на хоÑтове, които иÑкате да изключите от блокиране, може да бъдат добавени в Позволени и имена на хоÑтове, които иÑкате да пренаÑочите към Ñпецифичен IP адреÑ, могат да бъдат открити в ПренаÑочени.

    + +

    Където мога да Ð½Ð°Ð¼ÐµÑ€Ñ Ð¾Ñ‰Ðµ източници на hosts?

    +

    Погледнете СпиÑък Ñ Ð´Ð¾Ð¿ÑŠÐ»Ð½Ð¸Ñ‚ÐµÐ»Ð½Ð¸ източници за AdAway.

    + +

    Помогнете Ñ Ð¿Ñ€ÐµÐ²ÐµÐ¶Ð´Ð°Ð½ÐµÑ‚Ð¾/докладването на грешки

    +

    МолÑ, отидете на https://adaway.org.

    + + diff --git a/app/src/main/res/raw-bg/help_problems.html b/app/src/main/res/raw-bg/help_problems.html new file mode 100644 index 0000000..16030ba --- /dev/null +++ b/app/src/main/res/raw-bg/help_problems.html @@ -0,0 +1,36 @@ + + + +ЧеÑто Ñрещани проблеми + +

    Копиране на хоÑÑ‚ файла Ñе провали на Android 9+

    +

    ПоÑледните верÑии на Android използват Ñамо за четене /system дÑл.
    +Ðко използвате Magisk като руут решение, уверете Ñе, че Ñте включили безÑиÑтемен хоÑÑ‚ модул, Ñлед това реÑтартирайте.

    + +

    ÐÑма доÑтатъчно мÑÑто на дÑла

    +

    Пробвайте да промените Ñ†ÐµÐ»ÐµÐ²Ð¸Ñ Ñ…Ð¾ÑÑ‚ файл в наÑтройките към /data/data/hosts (или /data/hosts) и приложете AdAway отново.

    + +

    Chrome вÑе още показва реклами

    +

    Уверете Ñе, че Ñте изключили Ð¾Ð»ÐµÐºÐ¾Ñ‚ÐµÐ½Ð¸Ñ Ñ€ÐµÐ¶Ð¸Ð¼ (извеÑтен преди като пеÑтене на данни) от наÑтройките на Chrome. Тази Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñва на Chrome да използва чаÑтни DNS Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð¸ да заобиколи AdAway.

    + +

    Ðе Ñпира рекламите в приложението XYZ!

    +

    ÐÑкои имена на хоÑтове може би липÑват в предоÑтавените хоÑÑ‚ файлове от Източници за хоÑтове или приложението е Ñнабдило изображениÑта, за да предоÑтави реклами, без да има доÑтъп до интернет.

    +Може да запиÑвате DNS заÑвките (Меню-&gtЗапиÑване на DNS заÑвки) от AdAway, за да откриете кои допълнителни имена на хоÑтове трÑбва да бъдат блокирани. +

    Добавете подозрителните имена на хоÑтове в ÑобÑтвен Черен ÑпиÑък, като продължително натиÑнете на запиÑите в дневника и докладвате тези имена на хоÑтове, когато Ñте ги потвърдили в Ð½Ð°ÑˆÐ¸Ñ Ð¡ÑŠÐ³Ð»ÐµÐ´Ð²Ð°Ñ‡ за проблеми в GitHub.

    + +

    Кеширани реклами

    +

    ПонÑкога приложениÑта кешират реклами Ñлед изтеглÑне. Това води до оÑтатъчни реклами в нÑкои приложениÑ. Може да Ñе опитате да изтриете кеша на тези Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² СпиÑъка Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² Ðндроид, за да заобиколите този проблем.

    + +

    Приложение XYZ вече не работи!

    +

    ÐÑкои Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð¼Ð°Ñ‚ нужда да комуникират Ñ Ð¸Ð¼Ðµ на хоÑÑ‚, което е блокирано от AdAway или отказват да работÑÑ‚, когато имената на хоÑтовете, които предоÑтавÑÑ‚ реклами не Ñа доÑтъпни. Вижте https://github.com/AdAway/AdAway/wiki/ProblematicApps. Това е ÑпиÑък Ñ Ð¿Ð¾Ð·Ð½Ð°Ñ‚Ð¸ приложениÑ, които имат проблеми. Ð’ противен Ñлучай, намерете кои имена на хоÑтове Ñа нужни и ги добавете във Ð’Ð°ÑˆÐ¸Ñ Ð‘Ñл ÑпиÑък, намиращ Ñе в Ваши ÑпиÑъци и ги докладвайте на преÑледвача на проблеми на AdAway.

    + +

    Ðе работи на Android 4.4+

    +

    Пробвайте да промените Ñ†ÐµÐ»ÐµÐ²Ð¸Ñ Ñ…Ð¾ÑÑ‚ файл в наÑтройките от /data/data/hosts към /data/hosts или /system/etc/hosts и приложете AdAway отново.

    + +

    Бутонът "назад" в мрежовите четци вече не работи!

    +

    Като заобиколен метод можете да включите меÑÑ‚Ð½Ð¸Ñ Ñървър на AdAwaу от наÑтройките.

    + + + diff --git a/app/src/main/res/raw-bg/help_s_on_s_off.html b/app/src/main/res/raw-bg/help_s_on_s_off.html new file mode 100644 index 0000000..65c567e --- /dev/null +++ b/app/src/main/res/raw-bg/help_s_on_s_off.html @@ -0,0 +1,32 @@ + + + +Помощ, Ñвързана ÑÑŠÑ S-ON + +

    HTC УÑтройÑтва

    +

    AdAway не работи, когато използвате уÑтройÑтво Ñ Ñ‚Ð°ÐºÐ° Ð½Ð°Ñ€ÐµÑ‡ÐµÐ½Ð¸Ñ S-ON. Тази "функциÑ" ÑъщеÑтвува на множеÑтво HTC уÑтройÑтва и предотвратÑтва AdAway да пише по hosts файла.

    + +

    S-ON/S-OFF?

    +

    S-OFF означава, че NAND партишъна на уÑтройÑтвото е отключен и може да Ñе запиÑва на него. ОпциÑта по подразбиране на HTC уÑтройÑтвата е S-ON, което означава, че не можете да получите доÑтъп до голÑма чаÑÑ‚ от ÑиÑтемата и не можете да гарантирате поÑтоÑнен root режим. ОÑвен това, проверката на firmware отново е оÑигурена от S-ON.

    + +

    Имам ли S-ON или S-OFF?

    +

    Влезте в Boot менюто на Вашето уÑтройÑтво, задържайки копчето за намалÑване на звука и копчето за Ñтартиране. ТекÑтът отгоре ще покаже ÑтатуÑа, които може да бъде S-OFF or S-ON. Пълен руут доÑтъп обикновено означава S-OFF. +

    Допълнителна Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¼Ð¾Ð¶Ðµ да бъде намерена на www.addictivetips.com. Допълнителни методи за S-OFF Ñлед Unrevokable (във връзката) може да ви заинтереÑуват. Казват Ñе: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Временно решение

    +

    Ðеобходимо уÑловие: ТрÑбва да инÑталирате работещ Android SDK Ñ ADB обвивка на компютъра Ви.

    +
      +
    1. h +Влезте в Boot менюто на Вашето уÑтройÑтво, задържайки копчето за намалÑване на звука и копчето за Ñтартиране.
    2. +
    3. ÐатиÑнете бутона за намалÑване на звука, за да изберете режим възÑтановÑване и натиÑнете бутона за включване, за да го заредите.
    4. +
    5. Ð’ режимът за възÑтановÑване "clockwork" отидете в "менюто на дÑловете".
    6. +
    7. Изберете mount /system, mount /sdcard и mount /data.
    8. +
    9. Включете USB кабела и отворете ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¸Ñ Ñ€ÐµÐ´ на компютъра Ви.
    10. +
    11. Влезте в adb shell и напишете ln -s /data/hosts /system/etc/hosts (Това Ñъздава Ñимволна връзка, коÑто позволÑва на AdAway да редактира host файла, запиÑан в /data, докато позволÑва на операционната ÑиÑтема да използва файла, запиÑан в /system.)
    12. +
    13. РеÑтартирайте уÑтройÑтвото и в наÑтройките на AdAway поÑтавете Ð¦ÐµÐ»ÐµÐ²Ð¸Ñ Ñ…Ð¾ÑÑ‚ файл в /data/hosts.
    14. +
    15. AdAway Ñега трÑбва да работи.
    16. +
    + + diff --git a/app/src/main/res/raw-bn/help_faq.html b/app/src/main/res/raw-bn/help_faq.html new file mode 100644 index 0000000..5d0b567 --- /dev/null +++ b/app/src/main/res/raw-bn/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    বিজà§à¦žà¦¾à¦ªà¦¨ দà§à¦¬à¦¾à¦°à¦¾ আয়

    +

    à¦à¦•টি অননà§à¦®à§‹à¦¦à¦¿à¦¤ ভà§à¦² ধারণা রয়েছে যে যদি কোনো বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•ারী বিজà§à¦žà¦¾à¦ªà¦¨à¦—à§à¦²à¦¿à¦¤à§‡ কà§à¦²à¦¿à¦• করেন না, তাহলে তাদের বà§à¦²à¦• করা কোন সাইট বা অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•েশানকে আরà§à¦¥à¦¿à¦•ভাবে কà§à¦·à¦¤à¦¿à¦—à§à¦°à¦¸à§à¦¤ করবে না à¦à¦Ÿà¦¾ ভà§à¦², ডেভেলপাররা শà§à¦§à§ বিজà§à¦žà¦¾à¦ªà¦¨ পà§à¦°à¦¦à¦°à§à¦¶à¦¨ করে অরà§à¦¥ উপারà§à¦œà¦¨ করে à¦à¦Ÿà¦¾ আপনার উপর নিরà§à¦­à¦° করে কিনা আপনি বিজà§à¦žà¦¾à¦ªà¦¨ বà§à¦²à¦• বা না। বà§à¦¯à¦•à§à¦¤à¦¿à¦—তভাবে আমি à¦à¦®à¦¨ বিজà§à¦žà¦¾à¦ªà¦¨à¦—à§à¦²à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করব না যা বিজà§à¦žà¦¾à¦ªà¦¨ পà§à¦°à¦¦à¦°à§à¦¶à¦¨ করে কারণ আমি তাদের খà§à¦¬ বিরকà§à¦¤à¦¿à¦•র, তাই বিজà§à¦žà¦¾à¦ªà¦¨ বà§à¦²à¦• ছাড়াই আমি à¦à¦‡ অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•েশানগà§à¦²à¦¿ ইনসà§à¦Ÿà¦² করব না

    + +

    AdAway কিভাবে কাজ করে ?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    অà§à¦¯à¦¾à¦¡à¦…à§à¦¯à¦¾à¦“য়েতে ওয়েব সারà§à¦­à¦¾à¦° কিভাবে বà§à¦¯à¦¬à¦¹à¦¾à¦° করবেন?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    অনà§à¦¬à¦¾à¦¦ বা পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ বাগ ধরতে সাহাযà§à¦¯ করà§à¦¨

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-bn/help_problems.html b/app/src/main/res/raw-bn/help_problems.html new file mode 100644 index 0000000..6476dd3 --- /dev/null +++ b/app/src/main/res/raw-bn/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    পারà§à¦Ÿà¦¿à¦¶à¦¨ পরà§à¦¯à¦¾à¦ªà§à¦¤ নয়

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Android 4.4+ ঠকাজ করে না

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    কà§à¦¯à¦¾à¦¶ বিজà§à¦žà¦¾à¦ªà¦¨à¦—à§à¦²à¦¿

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-bn/help_s_on_s_off.html b/app/src/main/res/raw-bn/help_s_on_s_off.html new file mode 100644 index 0000000..e0590ab --- /dev/null +++ b/app/src/main/res/raw-bn/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    à¦à¦‡à¦šà¦Ÿà¦¿à¦¸à¦¿ ডিভাইস

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-ca/help_faq.html b/app/src/main/res/raw-ca/help_faq.html new file mode 100644 index 0000000..9891d3e --- /dev/null +++ b/app/src/main/res/raw-ca/help_faq.html @@ -0,0 +1,32 @@ + + + +PMF (FAQ) + +

    Ingressos per publicitat

    +

    Sovint es diu que, si un usuari no clica els anuncis, els desenvolupadors no reben ingressos. Això és fals, ja que també es reben ingressos mostrant els anuncis. No obstant això, mostrar o amagar els anuncis es decisió vostra.

    + +

    Com funciona AdAway?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Per què haig de reiniciar Android perquè els canvis facin efecte?

    +

    El Java d'Android manté la seva llista d'entrades DNS internament. El sistema utilitzarà el nou arxiu hosts immediatament (ho podeu comprovar amb "ping") però, no obstant, haureu de reiniciar Android per reinicialitzar la llista d'entrades de DNS internes.

    + +

    Com s'utilitza el servidor web d'AdAway?

    +

    L'AdAway també funcionarà sense l'ús d'un servidor Web! +

    Podeu habilitar el servidor Web local a les opcions de l'AdAway per respondre les peticions cap a l'adreça local 127.0.0.1. Això significa que totes les peticions de servidors de publicitat redirigits cap a 127.0.0.1 obtindran resposta per part del servidor Web de l'AdAway. +
    Algunes aplicacions poden no funcionar correctament si no troben el servidor de publicitat. Amb aquest mètode s'evita el problema atès que s'envia una pàgina en blanc sense imatges publicitàries.

    + +

    Com puc bloquejar noms de màquina específics?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    On puc trobar més fonts d'amfitrions?

    +

    Vegeu la llista de fonts addicionals d'amfitrions per a l'AdAway.

    + +

    Ajudeu traduint/comunicant errors

    +

    Aneu a https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ca/help_problems.html b/app/src/main/res/raw-ca/help_problems.html new file mode 100644 index 0000000..515e81f --- /dev/null +++ b/app/src/main/res/raw-ca/help_problems.html @@ -0,0 +1,36 @@ + + + +Problemes comuns + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    No hi ha prou espai a la partició

    +

    Intenteu canviar el fitxer d'amfitrions de destinació a les preferències a /data/data/hosts (o /data/hosts) i torneu a aplicar l'AdAway.

    + +

    No funciona a Android 4.4+

    +

    Intenteu canviar el fitxer d'amfitrions de destinació a les preferències de /data/data/hosts a /data/hosts o /system/etc/hosts i torneu a aplicar l'AdAway.

    + +

    No bloqueja els anuncis de l'aplicació X!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Anuncis en memòria cau

    +

    Algunes aplicacions carreguen anuncis en memòria. Això fa que quedin alguns anuncis en algunes aplicacions. Podeu provar eliminant les dades en memòria d'aquestes aplicacions en el gestor de programari d'Android per solucionar aquest problema.

    + +

    L'aplicació X no funciona més.

    +

    Algunes aplicacions necessiten connexió amb un amfitrió que l'AdAway ha blocat o bé no funcionen correctament si el servidor de publicitat no està disponible. Veieu https://github.com/AdAway/AdAway/wiki/ProblematicApps per obtenir un llistat d'aplicacions amb aquest comportament. D'altra banda, podeu esbrinar quins noms de domini necessiten les aplicacions i els podeu afegir a la llista blanca a llistes i reportar (en anglès) el problema mitjançant el bug tracker of AdAway.

    + +

    El botó enrera en els navegadors web no funciona

    +

    Podeu habilitar el servidor local d'AdAway a les preferències com a solució temporal.

    + +

    El botó enrera en els navegadors web no funciona

    +

    Podeu habilitar el servidor local d'AdAway a les preferències com a solució temporal.

    + + + diff --git a/app/src/main/res/raw-ca/help_s_on_s_off.html b/app/src/main/res/raw-ca/help_s_on_s_off.html new file mode 100644 index 0000000..3facd52 --- /dev/null +++ b/app/src/main/res/raw-ca/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Ajuda sobre l'S-ON + +

    Dispositius HTC

    +

    AdAway no funciona si utilitzeu un dispositiu amb la funció S-ON. Aquesta funció, que evita que AdAway escrigui fitxers hosts, existeix en diversos dispositius HTC.

    + +

    S-ON/S-OFF?

    +

    S-OFF significa que la porció de la memòria NAND del vostre dispositu està desbloquejada i llesta per l'escriptura. L'ajustament per defecte d'HTC és S-ON que significa que no es pot accedir a algunes àrees del sistema i no es pot garantitzar un root permanent. A més a més, es comproven les signatures dels fitxers de firmware.

    + +

    Tinc S-ON o S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Solució

    +

    Pre-requisit: Heu d'instal·lar un SDK d'Android amb una shell ADB en el vostre ordinador personal.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway hauria de funcinar ara.
    16. +
    + + diff --git a/app/src/main/res/raw-cs/help_faq.html b/app/src/main/res/raw-cs/help_faq.html new file mode 100644 index 0000000..b1e49bc --- /dev/null +++ b/app/src/main/res/raw-cs/help_faq.html @@ -0,0 +1,32 @@ + + + +Časté otázky + +

    Vydělávání na reklamách

    +

    Uživatelé se Äasto mylnÄ› domnívají, že pokud nikdy neklikají na reklamy, blokování nijak finanÄnÄ› nepoÅ¡kodí aplikace nebo navÅ¡tívené stránky. Toto není pravda, vývojáři vydÄ›lávají peníze i pouhým zobrazením reklam. Je pouze na vás, jestli budete reklamy blokovat, nebo ne. OsobnÄ› bych nepoužíval aplikace zobrazující reklamy, protože reklama je podle mÄ› velmi otravná, takže bez blokovaÄe reklam bych si tyto aplikace ani nenainstaloval.

    + +

    Jak AdAway funguje?

    +

    AdAway používá soubor hostitelů pro blokování doménových jmen serverů, které slouží k poskytování reklam. Soubor hostitelů je soubor, který naleznete v /system/etc/hosts a který pÅ™iÅ™azuje jména hostitelů IP adresám. Toto je tradiÄní způsob, jak pÅ™iÅ™adit jméno hostitele IP adrese bez spoléhání se na Domain Name System (DNS). VÅ¡echna nechtÄ›ná jména hostitelů jsou pÅ™esmÄ›rována na 127.0.0.1, tzn. na vlastní zařízení.
    +Pokud soubor hostitelů nelze editovat, záložním řešením je použití vestavěné služby VPN. Ta vyfiltruje spojení se servery s nechtěnými doménovými jmény a ostatní spojení zachová.

    + +

    ProÄ je pro uplatnÄ›ní zmÄ›n potÅ™eba restartovat zařízení?

    +

    Java v Androidu si spravuje vlastní interní vyrovnávací paměť DNS. ZmÄ›ny v souboru hostitelů budou v operaÄním systému provedeny ihned (toto můžete zkontrolovat příkazem ping v terminálu), pro znovuvytvoÅ™ení vyrovnávací pamÄ›ti DNS Javy ale musíte zařízení restartovat.

    + +

    Jak používat webový server v AdAway?

    +

    AdAway funguje i bez použití webového serveru! +

    V nastavení AdAway můžete povolit lokální webový server, běžící na lokální IP adrese 127.0.0.1. V tomto případě budou dotazy aplikací na reklamní servery přesměrovány na 127.0.0.1 a zodpovězeny webovým serverem AdAway. +
    Některé aplikace se odmítnou spustit, pokud jsou reklamní servery nedostupné. Při použití této metody budou znovu dostupné, ale budou odpovídat prázdnou stránkou bez reklamních obrázků.

    + +

    Jak můžu zablokovat/odblokovat urÄitá jména hostitelů?

    +

    Jména hostitelů, která chcete zablokovat, pÅ™idejte z domovské obrazovky do seznamu Zablokované. Dále jména hostitelů, která chcete z blokování vyjmout, můžete pÅ™idat do Povolené a jména hostitelů, která chcete pÅ™esmÄ›rovat na urÄitou IP adresu, patří do PÅ™esmÄ›rováné.

    + +

    Kde mohu najít více zdrojů hostitelů?

    +

    Podívejte se na seznam dalších zdrojů hostitelů pro AdAway.

    + +

    Pomozte s překladem / hlášením chyb

    +

    Přejděte prosím na https://adaway.org.

    + + diff --git a/app/src/main/res/raw-cs/help_problems.html b/app/src/main/res/raw-cs/help_problems.html new file mode 100644 index 0000000..e991f82 --- /dev/null +++ b/app/src/main/res/raw-cs/help_problems.html @@ -0,0 +1,36 @@ + + + +Obvyklé problémy + +

    Kopírování souboru hostitelů na Androidu 9+ selhalo

    +

    Poslední verze Androidu používají oddíl /system v módu jen pro Ätení.
    +Pokud používáte pro ROOT přístup Magisk, ujistěte se, že je modul nesystémoví hostitelé povolen a poté restartujte zařízení.

    + +

    Nedostatek místa na oddílu

    +

    Zkuste v nastavení změnit cílový soubor hostitelů na /data/data/hosts (nebo /data/hosts) a použít AdAway znovu.

    + +

    Chrome stále zobrazuje reklamy

    +

    UjistÄ›te se, že máte vypnutý zjednoduÅ¡ený režim (dříve nazývaný jako spoÅ™iÄ dat) v nastavení Chromu. Tato funkce Chromu umožňuje používat soukromé Å™eÅ¡ení DNS a obejít tak AdAway.

    + +

    Reklamy v aplikaci XYZ nejsou blokovány!

    +

    Některá jména hostitelů mohou v poskytnutých souborech hostitelů ze Zdrojů hostitelů chybět nebo má aplikace reklamy zabudovány přímo v sobě a tudíž nepotřebuje k jejich zobrazování připojení k internetu.

    +Pomocí AdAway můžete zaznamenávat DNS požadavky (Menu->Záznam DNS požadavků) a zjistit tak, která další jména hostitelů mají být zablokována. +

    PÅ™idejte podezÅ™elá jména hostitelů na svou vlastní Äernou listinu dlouhým podržením vybraného jména hostitele v záznamu a pokud jste ověřili jejich funkÄnost, nahlaÅ¡te je na naÅ¡em GitHub Issue Trackeru.

    + +

    Reklamy v doÄasné pamÄ›ti

    +

    ObÄas si aplikace ukládají stažené reklamy do doÄasné pamÄ›ti. To vede k tomu, že v nÄ›kterých aplikacích reklamy můžou zůstat. Pro obejití tohoto problému můžete zkusit vymazat doÄasnou paměť u tÄ›chto aplikací v Seznamu aplikací systému Android.

    + +

    Aplikace XYZ již nefunguje!

    +

    Některé aplikace potřebují komunikovat s hostitelem, který je blokován pomocí AdAway, nebo dokonce odmítají pracovat, pokud pro ně takový hostitel není dostupný. Podívejte se na https://github.com/dschuermann/ad-away/wiki/ProblematicApps, kde naleznete seznam známých aplikací, které se potýkají s tímto problémem. Anebo si zjistěte, která jména hostitelů je potřeba přestat blokovat a pak je přidejte na svou Bílou listinu ve Vašich seznamech a nahlaste je na AdAway bug tracker.

    + +

    Nefunguje na Androidu 4.4+

    +

    Zkuste v nastavení změnit cílový soubor hostitelů z /data/data/hosts na /data/hosts nebo /system/etc/hosts a použít AdAway znovu.

    + +

    TlaÄítko zpÄ›t ve webovém prohlížeÄi nefunguje

    +

    Pro obejití problému můžete v nastavení povolit lokální webový server AdAway.

    + + + diff --git a/app/src/main/res/raw-cs/help_s_on_s_off.html b/app/src/main/res/raw-cs/help_s_on_s_off.html new file mode 100644 index 0000000..f503328 --- /dev/null +++ b/app/src/main/res/raw-cs/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Nápověda vztahující se k S-ON + +

    HTC zařízení

    +

    AdAway nefunguje, pokud používáte zařízení s takzvaným S-ON. Toto "vylepšení" se vyskytuje na mnoha HTC zařízeních a znemožňuje AdAway upravování souboru hostitelů.

    + +

    S-ON/S-OFF?

    +

    S-OFF znamená, že NAND paměť vaÅ¡eho zařízení je odemÄená a lze do ní zapisovat. Výchozí nastavení u HTC zařízení je S-ON, tzn. že nemůžete zapisovat do urÄitých Äástí pamÄ›ti a získat úplný ROOT zařízení. Dále S-ON příznak zajišťuje kontrolu podpisu obrazů firmware.

    + +

    Mám S-ON, nebo S-OFF?

    +

    ZapnÄ›te zařízení do tzv. Boot Menu souÄasným držením tlaÄítek ZtiÅ¡ení hlasitosti a Zapnutí/Vypnutí. NahoÅ™e obrazovky poté uvidíte stav S-OFF nebo S-ON. Úplný ROOT přístup obvykle znamená S-OFF. +

    Pro více informací navštivte stránku www.addictivetips.com. Mohly by vás zajímat i jiné metody získání S-OFF než Unrevokable (viz odkaz), a to např. Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine...

    + +

    Obejití problému

    +

    PÅ™edpoklad: Na vaÅ¡em poÄítaÄi musíte nainstalovat funkÄní Android SDK s ADB shellem.

    +
      +
    1. ZapnÄ›te zařízení do tzv. Boot Menu souÄasným držením tlaÄítek ZtiÅ¡ení hlasitosti a Zapnutí/Vypnutí.
    2. +
    3. Použijte tlaÄítko ZtiÅ¡ení hlasitosti pro zvolení recovery a poté stisknÄ›te tlaÄítko Zapnutí/Vypnutí pro pÅ™esun do tohoto režimu.
    4. +
    5. V clockwork recovery přejděte do "partitions menu".
    6. +
    7. Zvolte mount /system, mount /sdcard a mount /data.
    8. +
    9. PÅ™ipojte USB kabel a na poÄítaÄi otevÅ™ete příkazovou řádku.
    10. +
    11. Spusťte adb shell a napište příkaz ln -s /data/hosts /system/etc/hosts (Toto vytvoří symbolický odkaz, který AdAway umožní upravovat soubor hostitelů uložený v /data, zatímco OS bude soubor používat jako by byl uložen v /system.)
    12. +
    13. Restartujte vaše zařízení a v nastavení AdAway nastavte Cílový soubor hostitelů na /data/hosts.
    14. +
    15. AdAway by nyní měl fungovat.
    16. +
    + + diff --git a/app/src/main/res/raw-da/help_faq.html b/app/src/main/res/raw-da/help_faq.html new file mode 100644 index 0000000..fd2b07f --- /dev/null +++ b/app/src/main/res/raw-da/help_faq.html @@ -0,0 +1,32 @@ + + + +OSS + +

    Indkomst af reklamer

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    Hvordan virker AdAway?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Hvorfor skal jeg genstarte Android for at ændringerne træder i kraft?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    Hvordan bruger jeg webserveren i AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    Hvordan kan jeg blokere/afblokere specifikke hostnavne?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Hvor kan jeg finde flere hosts kilder?

    +

    See List of additional hosts sources for AdAway.

    + +

    Hjælp med at oversætte/rapportere fejl

    +

    GÃ¥ venligst til https://adaway.org.

    + + diff --git a/app/src/main/res/raw-da/help_problems.html b/app/src/main/res/raw-da/help_problems.html new file mode 100644 index 0000000..54f881b --- /dev/null +++ b/app/src/main/res/raw-da/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Ikke nok plads på partitionen

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Virker ikke på Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    Den blokkerer ikke annoncer fra programmet XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cachede Annoncer

    +

    Nogle gange har applikationer gemt reklamer efter download. Dette fører til rest reklamer i nogle programmer. Du kan prøve at slette cachen for disse applikationer i Android Application liste at omgå dette problem.

    + +

    Programmet XYZ virker ikke mere!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Tilbage-knappen i webbrowsere virker ikke

    +

    Du kan aktivere AdAways lokale webserver i Indstillinger som en workaround.

    + +

    Tilbage-knappen i webbrowsere virker ikke

    +

    Du kan aktivere AdAways lokale webserver i Indstillinger som en workaround.

    + + + diff --git a/app/src/main/res/raw-da/help_s_on_s_off.html b/app/src/main/res/raw-da/help_s_on_s_off.html new file mode 100644 index 0000000..4d9bc3a --- /dev/null +++ b/app/src/main/res/raw-da/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC-enheder

    +

    AdAway virker ikke når du bruger en enheder med S-ON. Denne 'feature' findes på mange HTC-enheder og gør at AdAway ikke kan skrive til hosts-filen.

    + +

    S-ON/S-OFF?

    +

    S-OFF betyder at NAND-delen af din enhed er ulåst og kan skrives til. Standard-indstillingen for HTC-enheder er S-ON, hvilket betyder at du hverken kan tilgå bestemte områder af filsystemet eller sikre dig en permanent root-adgang. Ydermere, signatur-tjek for dine firmware-images er også påvirket af S-ON.

    + +

    Har jeg S-ON eller S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Mulig omvej

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway skulle virke nu.
    16. +
    + + diff --git a/app/src/main/res/raw-de/help_faq.html b/app/src/main/res/raw-de/help_faq.html new file mode 100644 index 0000000..c1767c6 --- /dev/null +++ b/app/src/main/res/raw-de/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Einnahmen durch Werbung

    +

    Die oft geäußerte Auffassung, dass ein Nutzer, der nie auf Werbung klickt, einer Webseite oder Anwendung finanziell nicht schadet, wenn Werbung blockiert wird, ist falsch. Denn Entwickler erhalten auch durch das bloße Einblenden von Werbung Geld. Es bleibt Ihre Entscheidung, ob Sie Werbung blockieren oder nicht. Ich persönlich würde keine Anwendungen verwenden, die Werbung anzeigen, da ich sie sehr störend finde, d. h. ohne einen Werbeblocker würde ich diese Anwendungen nicht installieren.

    + +

    Wie funktioniert AdAway?

    +

    AdAway benutzt die Hosts-Datei, um Hostnamen zu blockieren, die Werbung ausliefern. Die Hosts-Datei befindet sich unter /system/etc/hosts und weist Hostnamen eine IP-Adresse zu. Traditionell werden über diese Datei Paare aus IP-Adresse und Hostname definiert, ohne auf das Domain Name System (DNS) zurückzugreifen. Alle unerwünschten Hostnamen werden zu 127.0.0.1 umgeleitet, also auf Ihr eigenes Gerät.
    +Wenn die Hosts-Datei nicht beschreibbar ist, besteht eine Ausweichlösung darin, den eingebauten VPN-Dienst zu verwenden. Dieser filtert Verbindungen zu unerwünschten Hostnamen und lässt andere durch.

    + +

    Warum muss ich Android neustarten, damit die Änderungen wirksam werden?

    +

    Java auf Android hat einen eigenen internen DNS-Zwischenspeicher. Zwar übernimmt das Betriebssystem die neue Hosts-Datei sofort (dieses kann man mit einem Ping über die Kommandozeile überprüfen). Jedoch ist es nötig, Android neu zu starten, um auch Javas DNS-Zwischenspeicher zu erneuern.

    + +

    Wie verwendet man den Webserver in AdAway?

    +

    AdAway funktioniert auch ohne den Webserver! +

    Sie können in den Einstellungen von AdAway einen lokalen Webserver aktivieren, um Anfragen an die lokale IP-Adresse 127.0.0.1 zu beantworten. Dadurch werden Anfragen von Anwendungen an Werbeserver, die an 127.0.0.1 umgeleitet werden, nun vom AdAway-Webserver beantwortet. +
    Einige Anwendungen funktionieren nicht, wenn die von ihnen angesprochenen Werbeserver nicht erreichbar sind. Mit dieser Methode erscheinen sie erreichbar, indem sie eine leere Seite anstelle von Werbebildern zurückgeben.

    + +

    Wie kann ich bestimmte Hostnamen sperren/entsperren?

    +

    Host der blockiert werden soll zu Blockieren-Liste vom Desktop und Host der ausgeschlossen werden vom Blockieren zu Erlaubt-Liste, sowie Umleiten-Liste von Hosts zu speziellen IP-Adressen.

    + +

    Wo finde ich weitere Hosts-Quellen?

    +

    Siehe Liste zusätzlicher Hosts-Quellen für AdAway.

    + +

    Übersetzen helfen - Fehler melden

    +

    Bitte gehen Sie auf https://adaway.org.

    + + diff --git a/app/src/main/res/raw-de/help_problems.html b/app/src/main/res/raw-de/help_problems.html new file mode 100644 index 0000000..9137c42 --- /dev/null +++ b/app/src/main/res/raw-de/help_problems.html @@ -0,0 +1,36 @@ + + + +Häufige Probleme + +

    Kopie der hosts-Datei in Android 9+ schlägt fehl

    +

    Die neuesten Versionen von Android verwenden eine schreibgeschützte /system Partition.
    +Wenn sie Magisk als Root Lösung verwenden, stellen sie sicher das der Punkt "Systemlose Host-Datei" aktiviert ist und starten dann neu.

    + +

    Auf der Partition ist nicht genügend Speicherplatz vorhanden

    +

    Versuchen Sie, das Zielverzeichnis der Hosts-Datei in den Einstellungen auf /data/data/hosts (oder /data/hosts) zu ändern, und wenden Sie AdAway erneut an.

    + +

    Funktioniert nicht auf Android 4.4+

    +

    Versuchen Sie, das Zielverzeichnis der Hosts-Datei in den Einstellungen von /data/data/hosts auf /data/hosts oder /system/etc/hosts umzustellen, und wenden Sie danach AdAway erneut an.

    + +

    Die Werbung in Anwendung XYZ wird nicht blockiert!

    +

    In den bereitgestellten Hosts-Dateien der Hosts-Quellen fehlen möglicherweise einige Hostnamen oder die Anwendung hat die Anzeigen gebündelt, um Werbung bereitzustellen, ohne auf das Internet zuzugreifen.

    +Sie können die DNS-Anforderungen (Menü->DNS-Anfragen protokollieren) von AdAway protokollieren lassen, um herauszufinden, welche zusätzlichen Hostnamen gesperrt werden müssen. +

    Fügen Sie die verdächtigen Hostnamen zu Ihrer eigenen Negativliste hinzu, indem Sie länger auf die Einträge im Protokoll drücken und melden Sie diese Hostnamen im Forum Hosts Inbox von hosts-file.net, wenn Sie sie überprüft haben.

    + +

    Zwischengespeicherte Werbung

    +

    Manche Anwendungen speichern Werbung nach dem Herunterladen temporär. Dies führt dazu, dass Werbung in manchen Anwendungen erhalten bleibt. Um dieses Problem zu umgehen, können Sie versuchen, den Zwischenspeicher dieser Anwendungen, in der Anwendungsliste von Android, zu löschen.

    + +

    Anwendung XYZ funktioniert nicht mehr richtig!

    +

    Manche Anwendungen funktionieren nicht, wenn Host-Namen, die Werbung bereitstellen sollen, nicht erreichbar sind, da sie von AdAway blockiert werden. Besuchen Sie https://github.com/AdAway/AdAway/wiki/ProblematicApps, um eine Liste von bekannten Anwendungen einzusehen, die solche Probleme haben. Sie können auch versuchen herauszufinden, welche Hostnamen benötigt werden, und diese Ihrer Positivliste unter Meine Listen hinzufügen. Melden Sie diese bitte zusätzlich im Ticketsystem von AdAway.

    + +

    Der Zurückknopf im Browser funktioniert nicht

    +

    Versuchen Sie, in den Einstellungen das Ziel der Hosts-Datei von /data/data/hosts in /data/hosts oder /system/etc/hosts zu ändern, und wenden Sie AdAway erneut an.

    + +

    Der Zurückknopf im Browser funktioniert nicht

    +

    Als Problemumgehung können Sie den lokalen Webserver von AdAway in den Einstellungen aktivieren.

    + + + diff --git a/app/src/main/res/raw-de/help_s_on_s_off.html b/app/src/main/res/raw-de/help_s_on_s_off.html new file mode 100644 index 0000000..4220062 --- /dev/null +++ b/app/src/main/res/raw-de/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON-spezifische Hilfe + +

    HTC-Geräte

    +

    AdAway funktioniert nicht, wenn Sie ein Gerät mit einem sogenannten S-ON verwenden. Viele HTC-Geräte besitzen diese »Funktion«, welche unterbindet, dass AdAway die Hosts-Datei beschreiben kann.

    + +

    S-ON/S-OFF?

    +

    S-OFF bedeutet, dass der NAND-Bereich des Gerätes entsperrt ist und somit beschrieben werden kann. Die Standardeinstellung bei HTC-Geräten ist S-ON, was wiederum heißt, dass Sie weder auf bestimmte Systembereiche zugreifen können, noch einen dauerhaften Root-Zugriff gewährleistet bekommen. Durch das S-ON-Flag wird außerdem die Signaturprüfung von Firmware-Abbildern sichergestellt.

    + +

    Ist mein Gerät im Modus S-ON oder S-OFF?

    +

    Starten Sie in das Boot-Menü, indem Sie bei gedrückter Lautstärke verringern-Taste Ihr Gerät einschalten. Der Status »S-OFF« oder »S-ON« wird oben im Menü angezeigt. Voller Root-Zugriff ist im Allgemeinen gleichbedeutend mit »S-OFF«. +

    Mehr Informationen hierzu finden Sie unter www.addictivetips.com. Neben der Unrevokable-Methode, um »S-OFF« zu erhalten (siehe Verknüpfung), haben Sie eventuell Interesse an weiteren Methoden. Nennenswert: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Behelfslösung

    +

    Voraussetzung: Ein auf Ihrem PC installiertes, funktionsfähiges Android-SDK mit ADB-Shell.

    +
      +
    1. Starten Sie in das Boot-Menü, indem Sie bei gedrückter Leiser-Taste Ihr Gerät einschalten.
    2. +
    3. Betätigen Sie die Leiser-Taste, um zum Menüpunkt »Recovery« zu navigieren. Drücken Sie anschließend den An-/Aus-Schalter, um in den Recovery-Modus zu booten.
    4. +
    5. Wechseln Sie in der Clockwork Recovery ins »Partitions Menu«.
    6. +
    7. Wählen Sie mount /system, mount /sdcard und mount /data aus.
    8. +
    9. Verbinden Sie das Gerät per USB mit dem PC und öffnen Sie ein Kommandozeilenfenster.
    10. +
    11. ADB-Shell starten und ln -s /data/hosts /system/etc/hosts eingeben (Es wird ein symbolischer Verweis erstellt, der es AdAway erlaubt, die Hosts-Datei unter /data zu verändern, während es für das Betriebssystem so aussieht, als wäre sie unter /system vorhanden.)
    12. +
    13. Starten Sie das Gerät neu und legen Sie in den Einstellungen von AdAway das Zielverzeichnis der Hosts-Datei auf /data/hosts fest.
    14. +
    15. AdAway sollte nun funktionieren.
    16. +
    + + diff --git a/app/src/main/res/raw-el/help_faq.html b/app/src/main/res/raw-el/help_faq.html new file mode 100644 index 0000000..51c5d3c --- /dev/null +++ b/app/src/main/res/raw-el/help_faq.html @@ -0,0 +1,30 @@ + + + +Συχνές ΕÏωτήσεις + +

    Έσοδα από διαφημίσεις

    +

    ΥπάÏχει η λάθος αντίληψη ότι εφόσον ένας χÏήστης επιλέγει να μην κάνει ποτέ κλίκ σε διαφημίσεις, αποκλείοντάς τες δεν θα οδηγοÏσε σε οικονομική ζημιά σε έναν ιστότοπο ή μια εφαÏμογή. Αυτό είναι λάθος, γιατί οι Ï€ÏογÏαμματιστές έχουν έσοδα και μόνο εμφανίζοντας τες. Είναι δική σας απόφαση αν θέλετε να εμποδίσετε την εμφάνιση των διαφημίσεων ή όχι. ΠÏοσωπικά δεν θα χÏησιμοποιοÏσα εφαÏμογές που εμφανίζουν διαφημίσεις γιατί τις βÏίσκω Ï€Î¿Î»Ï ÎµÎ½Î¿Ï‡Î»Î·Ï„Î¹ÎºÎ­Ï‚, οπότε χωÏίς την εφαÏμογή φÏαγής τους δεν θα τις εγκαθιστοÏσα.

    + +

    Πως λειτουÏγεί η εφαÏμογή AdAway;

    +

    Το AdAway χÏησιμοποιεί το αÏχείο hosts για να αποκλείσει hostnames, που Ï€Ïοβάλλουν διαφημίσεις. Το αÏχείο hosts είναι ένα αÏχείο που βÏίσκεται στο /system/etc/hosts που αντιστοιχίζει hostnames σε διευθÏνσεις IP. Είναι ένας παÏαδοσιακός Ï„Ïόπος για να οÏίσετε το hostname σε ζεÏγη διευθÏνσεων IP χωÏίς να βασίζεστε στο Domain Name System (DNS). Όλα τα ανεπιθÏμητα hostnames ανακατευθÏνονται στο 127.0.0.1 Ï€Ïάγμα που σημαίνει ότι οδηγοÏνται στη δική σας συσκευή.
    +Εάν το αÏχείο hosts δεν είναι εγγÏάψιμο, μια εναλλακτική λÏση είναι να χÏησιμοποιήσετε την ενσωματωμένη υπηÏεσία VPN. Θα φιλτÏάÏει τις συνδέσεις σε ανεπιθÏμητα hostnames και θα αφήσει άλλους να πεÏάσουν.

    + +

    Γιατί χÏειάζεται να επανεκκινήσω τη συσκευή μου για να ισχÏσουν οι αλλαγές;

    +

    Η Java στο Android χÏησιμοποιεί μια δική της εσωτεÏική κÏυφή μνήμη DNS. Το λειτουÏγικό σÏστημα αντανακλά τις αλλαγές στο αÏχείο hosts άμεσα (επαληθεÏστε με την εντολή ping σε γÏαμμή εντολών) αλλά θα χÏειαστεί να επανεκκινήσετε το Android για να ενημεÏώσει την κÏυφή μνήμη DNS της Java.

    + +

    Πώς χÏησιμοποιείται ο διακομιστής ιστοσελίδων στο AdAway;

    +

    Το AdAway λειτουÏγεί επίσης και χωÏίς τον διακομιστή ιστοσελίδων!

    ΜποÏείτε να ενεÏγοποιήσετε έναν τοπικό διακομιστή ιστοσελίδων στις Ïυθμίσεις του AdAway για να εξυπηÏετεί αιτήσεις στην τοπική διεÏθυνση IP 127.0.0.1. Αυτό σημαίνει πως αιτήσεις από εφαÏμογές Ï€Ïος παÏόχους διαφημίσεων οι οποίες ανακατευθÏνονται Ï€Ïος το 127.0.0.1 εξυπηÏετοÏνται από τον διακομιστή ιστοσελίδων του AdAway.
    ΜεÏικές εφαÏμογές δεν λειτουÏγοÏν αν δεν έχουν Ï€Ïόσβαση σε παÏόχους διαφημίσεων. Με αυτή τη μέθοδο θα είναι πάλι διαθέσιμοι, απαντώντας με μια λευκή σελίδα και χωÏίς εικόνες διαφημίσεων.

    + +

    Πώς μποÏÏŽ να αποκλείσω/άÏω τονο αποκλεισμό συγκεκÏιμένων ονομάτων διακομιστών;

    +

    ΠÏοσθέστε τα hostnames που θέλετε να αποκλείσετε στη λίστα Blocked από την αÏχική οθόνη. Επιπλέον, τα hostnames που θέλετε να αποκλείσετε απο τον αποκλεισμό μποÏοÏν να Ï€ÏοστεθοÏν στα ΕπιτÏεπόμενα και ta hostnames που θέλετε να ανακατευθÏνετε σε μια συγκεκÏιμένη διεÏθυνση IP ανήκουν στην ΑνακατεÏθυνση.

    + +

    Î Î¿Ï Î¼Ï€Î¿ÏÏŽ να βÏω πεÏισσότεÏες πηγές αÏχείων hosts;

    +

    Δείτε την Λίστα επιπλέον πηγών αÏχείων hosts για το AdAway.

    + +

    Βοήθεια στη μετάφÏαση/αναφοÏά σφαλμάτων

    +

    ΠαÏακαλώ επισκεφτείτε το https://adaway.org.

    + + diff --git a/app/src/main/res/raw-el/help_problems.html b/app/src/main/res/raw-el/help_problems.html new file mode 100644 index 0000000..0043480 --- /dev/null +++ b/app/src/main/res/raw-el/help_problems.html @@ -0,0 +1,36 @@ + + + +Συνηθισμένα Ï€Ïοβλήματα + +

    Η ΑντιγÏαφή του αÏχείου hosts απέτυχε στο Android 9+

    +

    Οι τελευταίες εκδόσεις του Android χÏησιμοποιοÏν read-only /system partition.
    +Αν χÏησιμοποιείτε το Magisk ως root solution, βεβαιωθείτε ότι έχετε ενεÏγοποιήσει το systemless hosts στοιχείο και στη συνέχεια επανεκκινήσετε.

    + +

    Δεν υπάÏχει επαÏκής χώÏος στο διαμέÏισμα.

    +

    ΠÏοσπαθήστε να αλλάξετε το αÏχείο Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï hosts στις Ïυθμίσεις σε /data/data/hosts (ή /data/hosts) και εφαÏμόστε ξανά το AdAway.

    + +

    Δεν λειτουÏγεί στο Android 4.4+

    +

    ΠÏοσπαθήστε να αλλάξετε το αÏχείο Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï hosts στις Ïυθμίσεις από /data/data/hosts σε /data/hosts ή /system/etc/hosts και εφαÏμόστε ξανά το AdAway.

    + +

    Δεν αποκλείει τις διαφημίσεις στην εφαÏμογή XYZ!

    +

    ΟÏισμένα hostsnames ενδέχεται να λείπουν στα αÏχεία hosts από Hosts Sources ή η εφαÏμογή έχει συγκεντÏώσει τις εικόνες για να παÏέχει διαφημίσεις χωÏίς Ï€Ïόσβαση στο διαδίκτυο.

    +ΜποÏείτε να καταγÏάψετε τα αιτήματα DNS (Menu->Log DNS Requests) από το AdAway για να μάθετε ποιά επιπλέον hostnames Ï€Ïέπει να αποκλειστοÏν. +

    ΠÏοσθέστε τα Ïποπτα hostnames στη δική σας ΜαÏÏη λίστα πατώντας παÏατεταμένα τις καταχωÏήσεις στο αÏχείο καταγÏαφής και αναφέÏετε αυτά τα hostnames, όταν τα επαληθεÏσατε στο Forum Hosts Inbox of hosts-file.net.

    + +

    Αποθηκευμένες διαφημίσεις

    +

    ΜεÏικές φοÏές οι εφαÏμογές αποθηκεÏουν τοπικά τις διαφημίσεις Î±Ï†Î¿Ï Ï„Î¹Ï‚ μεταφοÏτώσουν. Αυτό οδηγεί σε παÏαμένουσες διαφημίσεις σε μεÏικές εφαÏμογές. ΜποÏείτε να δοκιμάσετε να διαγÏάψετε την κÏυφή μνήμη των εφαÏμογών αυτών στη λίστα εφαÏμογών του Android για να παÏακάμψετε αυτό το Ï€Ïόβλημα.

    + +

    Δε λειτουÏγεί πλέον η εφαÏμογή XYZ!

    +

    Κάποιες εφαÏμογές απαιτοÏν την επικοινωνία μέ ενα διακομιστή που έχει αποκλειστεί από το AdAway ή αÏνοÏνται να λειτουÏγήσουν όταν οι διακομιστές που εξυπηÏετοÏν διαφημίσεις δεν είναι διαθέσιμοι. Επισκεφτείτε το https://github.com/AdAway/AdAway/wiki/ProblematicApps για μια λίστα γνωστών Ï€Ïοβληματικών εφαÏμογών. Ειδάλλως, βÏείτε ποιοι διακομιστές είναι απαÏαίτητοι και Ï€Ïοσθέστε τους στη Λευκή Λίστα στο Οι Λίστες Σας και αναφέÏετέ τους στον ανιχνευτή σφαλμάτων του ΑdAway.

    + +

    Το κουμπί "πίσω" στους πεÏιηγητές ιστοσελίδων δεν λειτουÏγεί

    +

    ΜποÏείτε να ενεÏγοποιήσετε τον τοπικό διακομιστή ιστοσελίδων του AdAway σαν παÏάκαμψη.

    + +

    Το κουμπί "πίσω" στους πεÏιηγητές ιστοσελίδων δεν λειτουÏγεί

    +

    ΜποÏείτε να ενεÏγοποιήσετε τον τοπικό διακομιστή ιστοσελίδων του AdAway σαν παÏάκαμψη.

    + + + diff --git a/app/src/main/res/raw-el/help_s_on_s_off.html b/app/src/main/res/raw-el/help_s_on_s_off.html new file mode 100644 index 0000000..3aa014e --- /dev/null +++ b/app/src/main/res/raw-el/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON σχετική βοήθεια. + +

    Συσκευές HTC

    +

    Το AdAway δε λειτουÏγεί όταν χÏησιμοποίεται σε συσκευή με τη ÏÏθμιση S-ON. Αυτή η λειτουÏγία υπάÏχει σε πολλές συσκευές HTC και αποτÏέπει το AdAway απ' το να γÏάψει στο αÏχείο hosts.

    + +

    S-ON/S-OFF;

    +

    Το S-OFF σημαίνει ότι η πεÏιοχή NAND της συσκευής είναι ξεκλειδωμένη και μποÏεί να γÏαφτεί. Η Ï€Ïοεπιλεγμένη ÏÏθμιση για τις συσκευές HTC είναι S-ON, που σημαίνει ότι οÏτε έχετε Ï€Ïόσβαση οÏτε μποÏείτε να εγγυηθείτε μόνιμα δικαιώματα υπεÏχÏήστη. Επιπλέον, έλεγχος υπογÏαφών για τις εικόνες του firmware διασφαλίζεται από το S-ON.

    + +

    Έχω S-ON ή S-OFF;

    +
    + +

    ΠαÏάκαμψη

    +

    ΠÏοαπαιτοÏμενο: ΧÏειάζεται εγκατάσταση του Android SDK με ADB shell στον υπολογιστή σας.

    +
      +
    1. Boot στο Boot Menu της συσκευής σας πατώντας κÏατημένο το volume down κουμπί καθώς πατάτε το κουμπί ενεÏγοποίησης της συσκευής.
    2. +
    3. ΧÏησιμοποιήστε το volume down για να επιλέξετε recoveryέπειτα power για να το εκκινήσετε.
    4. +
    5. Στο clockwork recovery πηγαίνετε στο "partions menu".
    6. +
    7. Επιλέξτε mount /system, mount /sdcard και mount /data.
    8. +
    9. Συνδέστε το καλώδιο USB σας και ανοίξτε μια γÏαμμή εντολών στον υπολογιστή σας.
    10. +
    11. Μπείτε στο adb shell και πληκτÏολογήστε In -s /data/hosts /system/etc/hosts (Αυτό δημιουÏγεί έναν συμβολικό σÏνδεσμο, που επιτÏέπει στο AdAway να επεξεÏγαστεί το αÏχείο hosts που είναι αποθηκευμένο στο /data ενώ επιτÏέπει στο ΛειτουÏγικό να χÏησιμοποιεί το αÏχείο σαν να ήταν αποθηκευμένο στο /system.)
    12. +
    13. Επανεκκινήστε την συσκευή σας και οÏίστε ΑÏχείο Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï hosts σε /data/hosts στις Ïυθμίσεις του AdAway.
    14. +
    15. Το AdAway Ï€Ïέπει να λειτουÏγεί τώÏα.
    16. +
    + + diff --git a/app/src/main/res/raw-en-rUS/help_faq.html b/app/src/main/res/raw-en-rUS/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-en-rUS/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-en-rUS/help_problems.html b/app/src/main/res/raw-en-rUS/help_problems.html new file mode 100644 index 0000000..b4d45e9 --- /dev/null +++ b/app/src/main/res/raw-en-rUS/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Chrome still displays ads

    +

    Ensure you disable lite mode (previously known as data saver) from Chrome settings. This features allows Chrome to use private DNS solution and bypass AdAway.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in our GitHub issue tracker.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-en-rUS/help_s_on_s_off.html b/app/src/main/res/raw-en-rUS/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-en-rUS/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-eo/help_faq.html b/app/src/main/res/raw-eo/help_faq.html new file mode 100644 index 0000000..3c2042f --- /dev/null +++ b/app/src/main/res/raw-eo/help_faq.html @@ -0,0 +1,32 @@ + + + +Oftaj demandoj + +

    enspezo pri anuncoj

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-eo/help_problems.html b/app/src/main/res/raw-eo/help_problems.html new file mode 100644 index 0000000..71db530 --- /dev/null +++ b/app/src/main/res/raw-eo/help_problems.html @@ -0,0 +1,36 @@ + + + +Komunaj problemoj + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Ne estas sufiĉe dispartigspaco.

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-eo/help_s_on_s_off.html b/app/src/main/res/raw-eo/help_s_on_s_off.html new file mode 100644 index 0000000..2fdd2d2 --- /dev/null +++ b/app/src/main/res/raw-eo/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON-on helpo + +

    HTC aranÄaĵoj

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-es-rMX/help_faq.html b/app/src/main/res/raw-es-rMX/help_faq.html new file mode 100644 index 0000000..964d6be --- /dev/null +++ b/app/src/main/res/raw-es-rMX/help_faq.html @@ -0,0 +1,31 @@ + + + +Preguntas frecuentes + +

    Ingresos por anuncios

    +

    Hay una idea errónea expresada frecuentemente que dice que, si un usuario nunca hace clic en los anuncios, bloquearlos no dañará las finanzas del sitio o la aplicación. Esto no es verdad, los desarrolladores también ganan dinero sólo por mostrar anuncios. Depende de ti si bloqueas los anuncios o no. Personalmente no usaría aplicaciones que muestran anuncios porque me parecen muy molestas, así que sin un bloqueador de anuncios ni siquiera las instalaría.

    + +

    ¿Cómo funciona AdAway?

    +

    AdAway usa el archivo hosts para bloquear los nombres de host. El archivo /system/etc/hosts asigna los nombres de host a las direcciones IP. Es un método común para definir pares de nombres de hosts y direcciones IP sin utilizar un sistema de nombres de dominio (DNS). Se redireccionan todos los nombres de hosts no deseados a 127.0.0.1 (es decir, tu propio dispositivo).
    Si no es posible escribir en el archivo hosts, puedes usar el servicio de VPN integrado como alternativa. Este filtrará las conexiones a los nombres de host no deseados y permitirá que se realicen las demás.

    + +

    ¿Por qué debo reiniciar Android para que surtan efecto los cambios?

    +

    Java en Android guarda su propio caché interno de DNS. El sistema operativo mostrará el nuevo archivo host inmediatamente (verifícalo con un ping en la línea de comando) pero deberás reiniciar Android para reconstruir el caché DNS de Java.

    + +

    ¿Cómo se utiliza el servidor web de AdAway?

    +

    ¡AdAway funcionará sin usar el servidor web! +

    Puedes activar un servidor web local en las preferencias de AdAway para responder pedidos de la dirección IP local 127.0.0.1. Esto significa que los pedidos de las aplicaciones que son redirigidos a127.0.0.1 son respondidos por el servidor web de AdAway. +
    Algunas aplicaciones se rehusan a funcionar cuando los servidores de anuncios no son alcanzables. Con este método serán alcanzables de nuevo, devolviendo una página en blanco sin imágenes de publicidad.

    + +

    ¿Cómo puedo bloquear/desbloquear nombres de host específicos?

    +

    Desde la pantalla principal, agrega los nombres de hosts que quieres bloquear a la lista Bloqueados. Además, puedes agregar los nombres de host que no quieres bloquear a la lista Permitidos y los que quieres redirigir a una dirección IP específica a la lista Redireccionados.

    + +

    ¿Dónde puedo encontrar más proveedores de hosts?

    +

    Consulta la lista de fuentes de hosts adicionales de AdAway.

    + +

    Quiero informar errores o ayudar a traducir la app

    +

    Visita https://adaway.org.

    + + diff --git a/app/src/main/res/raw-es-rMX/help_problems.html b/app/src/main/res/raw-es-rMX/help_problems.html new file mode 100644 index 0000000..dd9382b --- /dev/null +++ b/app/src/main/res/raw-es-rMX/help_problems.html @@ -0,0 +1,36 @@ + + + +Problemas comunes + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    No hay suficiente espacio en la partición

    +

    Intenta cambiar en las preferencias el archivo hosts de destino a /data/data/hosts (o /data/hosts) y aplica AdAway otra vez.

    + +

    No funciona en Andrioid 4.4+

    +

    Intenta cambiar en las preferencias el archivo hosts de destino de /data/data/hosts a /data/hosts o /system/etc/hosts y aplica AdAway otra vez.

    + +

    ¡No bloquea anuncios en aplicación XYZ!

    +

    Algunos nombres de hosts pueden faltar en los archivos de hosts proporcionados de las Fuentes de Hosts o la aplicación ha agrupado las imágenes para proporcionar anuncios sin acceder a Internet.

    +Puede registrar las peticiones DNS (Menu->Log DNS Requests) desde AdAway para averiguar qué nombres de hosts adicionales tienen que ser bloqueados. +

    Añada los nombres de hosts sospechosos a su propia Lista negra pulsando las entradas en el Log e informe de estos nombres de hosts cuando los haya verificado en la bandeja de entrada de hosts-file.net.

    + +

    Anuncios en Caché

    +

    A veces las aplicaciones almacenan anuncios en caché después de su descarga. Esto lleva a que queden anuncios en algunas aplicaciones. Puedes tratar de borrar la memoria caché de éstas en la lista de aplicaciones Android para esquivar este problema.

    + +

    ¡La aplicación XYZ no funciona más!

    +

    Algunas aplicaciones necesitan comunicarse con un hostname que está bloqueado por AdAway o negarse a trabajar cuando los hostnames que deberían servir anuncios no son accesibles. Ver https://github.com/AdAway/AdAway/wiki/ProblematicApps para obtener una lista de aplicaciones conocidas que tienen problemas. De lo contrario, averigüe qué nombres de hosts se necesitan y añádelos a su Lista blanca en sus Listas y repórtelos al rastreador de errores de AdAway..

    + +

    El botón de volver no funciona en navegadores web

    +

    Puedes activar el servidor web local de AdAway en las preferencias como solución.

    + +

    El botón de volver no funciona en navegadores web

    +

    Puedes activar el servidor web local de AdAway en las preferencias como solución.

    + + + diff --git a/app/src/main/res/raw-es-rMX/help_s_on_s_off.html b/app/src/main/res/raw-es-rMX/help_s_on_s_off.html new file mode 100644 index 0000000..e4cffa5 --- /dev/null +++ b/app/src/main/res/raw-es-rMX/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Ayuda relacionada al S-ON + +

    Dispositivos HTC

    +

    AdAway no funciona cuando utilizas un dispositivo con el tan llamado S-ON. Esta 'característica' existe en varios dispositivos HTC y evita que AdAway escriba el archivo hosts.

    + +

    ¿S-ON o S-OFF?

    +

    S-OFF significa que la porción NAND del dispositivo está desbloqueada y se puede escribir en ella. La configuración predeterminada para dispositivos HTC es S-ON, lo que significa que no se puede acceder a ciertas áreas del sistema ni tampoco se puede garantizar el root permanente. Además, la comprobación de la firma para las imágenes de firmware también está garantizada por el indicador S-ON.

    + +

    ¿Tengo S-ON o S-OFF?

    +

    Reinicia al Boot Menu en tu dispositivo manteniendo presionando el botón de bajar volumen mientras presionas el botón de encendido y el texto en la parte superior mostrará el estado del indicador como S-OFF o S-ON. Un dispositivo completamente rooteado se mostrará como S-OFF. +

    Puedes encontrar más información en www.addictivetips.com. Métodos S-OFF adicionales con Unrevoked (en el link) pueden interesarte, es decir: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Solución

    +

    Prerequisito: Usted tiene que instalar un SDK de Android que funciona con el shell de ADB en su PC.

    +
      +
    1. Ingresa al Menú de Arranque en tu dispositivo presionando el botón de bajar volumen y el botón de encendido a la vez.
    2. +
    3. Utilice el volume abajo para seleccionar el modo recovery y luego presione el botón de encendido para iniciar.
    4. +
    5. En clockwork recovery vaya a "menu de particiones".
    6. +
    7. Seleccione mount /system, mount /sdcard y mount /data.
    8. +
    9. Conecte su cable USB y abra una línea de comandos en su PC.
    10. +
    11. Ingrese al adb shell y escriba ln -s /data/hosts /system/etc/hosts (Esto crea un enlace simbólico, que le permite a AdAway editar el archivo hosts almacenado en /data mientras permite al SO usarlo como si estuviera guardado en /system.)
    12. +
    13. Reinicie su dispositivo y establezca Archivo hosts de destino a /data/hosts en las preferencias de AdAway.
    14. +
    15. AdAway debería funcionar ahora.
    16. +
    + + diff --git a/app/src/main/res/raw-es/help_faq.html b/app/src/main/res/raw-es/help_faq.html new file mode 100644 index 0000000..00af468 --- /dev/null +++ b/app/src/main/res/raw-es/help_faq.html @@ -0,0 +1,32 @@ + + + +Preguntas frecuentes + +

    Ingresos por anuncios

    +

    Existe una idea errónea de que si un usuario nunca hace clic en anuncios, bloquearlos no dañará financieramente un sitio o una aplicación. Esto es incorrecto, los desarrolladores también ganan dinero con solo mostrar anuncios. Depende de usted si bloquea los anuncios o no. Personalmente, no usaría aplicaciones que muestren anuncios porque los encuentro muy molestos, así que sin un bloqueador de anuncios no instalaría estas aplicaciones.

    + +

    ¿Cómo funciona AdAway?

    +

    AdAway utiliza el archivo hosts para bloquear los nombres de hosts, que proporcionan anuncios. El archivo hosts es un archivo que se encuentra en /system/etc/hosts que asigna los nombres de hosts a las direcciones IP. Es una forma tradicional de definir los nombres de hosts a direcciones IP sin depender del sistema de nombres de dominio (DNS). Todos los nombres de hosts no deseados son redirigidos a 127.0.0.1, lo que significa que apuntarán a tu propio dispositivo.
    +Si el archivo hosts no es escribible, una solución de respaldo es usar el servicio VPN incorporado. Filtrará las conexiones a nombres de hosts no deseados y dejará pasar a otros.

    + +

    ¿Por qué tengo que reiniciar Android para que los cambios surtan efecto?

    +

    Java sobre Android mantiene su propia caché interna de DNS. El sistema operativo reflejará el nuevo fichero hosts inmediatamente (verifique esto con un ping desde la línea de comandos) pero tendrá que reiniciar Android para reconstruir la caché de DNS de Java.

    + +

    ¿Cómo usar el servidor web en AdAway?

    +

    ¡AdAway también funcionará sin utilizar el servidor web! +

    Puede habilitar un servidor web local en las preferencias de AdAway para responder las peticiones a la dirección IP local 127.0.0.1. Esto significa que las peticiones de las aplicaciones a los servidores de anuncios que se redirigen a 127.0.0.1 son respondidas por el servidor web de AdAway. +
    Algunas aplicaciones se niegan a trabajar, cuando los servidores de anuncios no son accesibles. Con este método, serán accesibles nuevamente, respondiendo con una página en blanco y sin imágenes de anuncios.

    + +

    ¿Cómo puedo bloquear/desbloquear nombres de servidor específicos?

    +

    Añade los nombres de host que quieres bloquear a la lista Bloqueado de la pantalla de inicio. Además, los nombres de host que desees excluir del bloqueo pueden añadirse a la lista Permitido y los nombres de host que desees redirigir a una dirección IP específica pertenecen a la lista Redireccionado.

    + +

    ¿Dónde puedo encontrar más fuentes de ficheros hosts?

    +

    Vea la lista de fuentes de archivos hosts adicionales para AdAway.

    + +

    Ayude a traducir/informar de fallos.

    +

    Por favor vaya a https://adaway.org.

    + + diff --git a/app/src/main/res/raw-es/help_problems.html b/app/src/main/res/raw-es/help_problems.html new file mode 100644 index 0000000..50e6a11 --- /dev/null +++ b/app/src/main/res/raw-es/help_problems.html @@ -0,0 +1,36 @@ + + + +Problemas comunes + +

    La copia del archivo hosts falló en Android 9+.

    +

    Las últimas versiones de Android utilizan la partición /system de solo lectura.
    +Si estás usando Magisk como solución root, asegúrate de habilitar el módulo hosts sin sistema y luego reinicia.

    + +

    No hay suficiente espacio en la partición

    +

    Intenta cambiar el archivo hosts de destino en preferencias a /data/data/hosts (o /data/hosts) y aplicar AdAway nuevamente.

    + +

    Chrome todavía muestra anuncios

    +

    Asegúrate de deshabilitar el modo lite (anteriormente conocido como ahorro de datos) en la configuración de Chrome. Esta función permite a Chrome utilizar una solución DNS privada y evitar AdAway.

    + +

    ¡No bloquea anuncios en la aplicación XYZ!

    +

    Es posible que falten algunos nombres de hosts en los archivos hosts proporcionados por las fuentes de hosts o que la aplicación haya agrupado las imágenes para proporcionar anuncios sin acceder a Internet.

    +Puede registrar las peticiones DNS (Menú -> Registro de peticiones DNS) desde AdAway para averiguar qué nombres de hosts adicionales deben ser bloqueados. +

    Añade los nombres de host sospechosos a tu propia lista negra presionando largamente las entradas en el registro y reporta estos nombres de hosts cuando los hayas verificado en nuestro registro de problemas en GitHub.

    + +

    Anuncios almacenados en caché

    +

    A veces, las aplicaciones almacenan anuncios en caché después de la descarga. Esto lleva a los anuncios restantes en algunas aplicaciones. Puedes intentar eliminar la memoria caché para estas aplicaciones en la lista de aplicaciones de Android para evitar este problema.

    + +

    ¡La aplicación XYZ ya no funciona!

    +

    Algunas aplicaciones deben comunicarse con un nombre de host bloqueado por AdAway o negarse a trabajar cuando no se puede acceder a los nombres de host que deberían servir anuncios. Visite https://github.com/AdAway/AdAway/wiki/ProblematicApps para obtener una lista de aplicaciones conocidas que tienen problemas. De lo contrario, averigüe qué nombres de host se necesitan y agréguelos a su lista blanca en sus listas e informe de ellos al rastreador de errores de AdAway.

    + +

    No funciona en Android 4.4+

    +

    Intente cambiar el archivo de hosts de destino en las preferencias de /data/data/hosts a /data/hosts o /system/etc/hosts y vuelva a aplicar AdAway.

    + +

    El botón de retroceso de los navegadores web no funciona

    +

    Puedes activar el servidor web local de AdAway en las preferencias como una solución alternativa.

    + + + diff --git a/app/src/main/res/raw-es/help_s_on_s_off.html b/app/src/main/res/raw-es/help_s_on_s_off.html new file mode 100644 index 0000000..2ecc4b9 --- /dev/null +++ b/app/src/main/res/raw-es/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Ayuda relacionada con S-ON + +

    Dispositivos HTC

    +

    AdAway no funciona cuando estés usando un dispositivo con el llamado S-ON. Esta 'característica' existe en muchos dispositivos HTC e impide que AdAway escriba en el archivo hosts.

    + +

    ¿S-ON/S-OFF?

    +

    S-OFF significa que la parte de la (memoria) NAND del dispositivo está desbloqueada y se puede escribir sobre ella. La configuración predeterminada para los dispositivos HTC es S-ON, lo que significa que usted ni puede acceder a ciertas áreas del sistema, ni puede garantizarse un rooteado permanente. Más aún, la comprobación de firmas para imágenes de firmware está asegurada por el indicativo S-ON.

    + +

    ¿Tengo S-ON o S-OFF?

    +

    Arranque en el menú de arranque de su dispositivo manteniendo pulsado el botón de volumen mientras presiona el botón de encendido y el texto de la parte superior mostrará el estado de la bandera como S-OFF o S-ON. Una root completo generalmente significa S-OFF. +

    Puede encontrar más información en www.addictivetips.com. Métodos adicionales de S-OFF ya que Unrevokable (en enlace) puede ser de su interés, es decir: Revolucionario, Revone, Aguardiente, RumRunner, Moonshine, SunShine…

    + +

    Solución indirecta

    +

    Prerrequisito: Tiene que instalar un Android SDK con shell ADB funcional en su PC.

    +
      +
    1. Arranque en el menú de arranque de su dispositivo manteniendo pulsado el botón de volumen mientras presiona el botón de encendido.
    2. +
    3. Utilice el volumen hacia abajo para seleccionar la recuperación y luego enciéndala para arrancarla.
    4. +
    5. En la recuperación del sistema de reloj vaya a "menú de particiones".
    6. +
    7. Seleccione mount /system, mount /sdcard y mount /data.
    8. +
    9. Conecte su cable USB y abra una línea de comandos en su PC.
    10. +
    11. Ingresa adb shell y escribe ln -s /data/hosts /system/etc/hosts (Esto crea un enlace simbólico que permite a AdAway editar el archivo hosts almacenado en /data mientras que permite al sistema operativo utilizar el archivo como si estuviera almacenado en /system).
    12. +
    13. Reinicia tu dispositivo y establece el archivo hosts de destino en /data/hosts en las preferencias de AdAway.
    14. +
    15. AdAway ahora debe funcionar.
    16. +
    + + diff --git a/app/src/main/res/raw-et/help_faq.html b/app/src/main/res/raw-et/help_faq.html new file mode 100644 index 0000000..e26014e --- /dev/null +++ b/app/src/main/res/raw-et/help_faq.html @@ -0,0 +1,32 @@ + + + +KKK + +

    Sissetulek reklaamidega

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    Kuidas AdAway töötab?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Miks ma pean Androidi taaskäivitama, et muutused jõustuksid?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    Kuidas kasutada veebiserverit AdAways?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    Kuidas ma saan blokeerida/eemaldada blokeeringu kindlatel hostinimedel?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Kust ma leian veel hosts-allikaid?

    +

    Vaata Nimekiri ekstra hosts-allikatest AdAwayle

    + +

    Aita tõlkida/vigu teatada

    +

    Palun mine aadressile https://adaway.org.

    + + diff --git a/app/src/main/res/raw-et/help_problems.html b/app/src/main/res/raw-et/help_problems.html new file mode 100644 index 0000000..32ae2db --- /dev/null +++ b/app/src/main/res/raw-et/help_problems.html @@ -0,0 +1,36 @@ + + + +Sagedased probleemid + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Partitsioonil pole piisavalt ruumi

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Ei toimi Androidi versioonis 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    Rakenduses XYZ pole reklaamid blokeeritud!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Puhverdatud reklaamid

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Rakendus XYZ ei tööta enam!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Tagasinupp ei toimi veebibrauserites

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    Tagasinupp ei toimi veebibrauserites

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-et/help_s_on_s_off.html b/app/src/main/res/raw-et/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-et/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-eu/help_faq.html b/app/src/main/res/raw-eu/help_faq.html new file mode 100644 index 0000000..e8eca70 --- /dev/null +++ b/app/src/main/res/raw-eu/help_faq.html @@ -0,0 +1,32 @@ + + + +SEG + +

    Iragarkiengaitiko irabazia

    +

    Uste oso zabaldua dago erabiltzaileak ez badu inoiz iragarki batean klikatzen, hura blokeatzeak ez diola kalterik egiten gune edo aplikazio bati finantzari dagokionez. Hau okerra da, garatzaileek dirua ere irabazten dute iragarkiak erakutsiz. Zure esku dago iragarkiak blokeatzea edo ez. Nik neuk ez dut iragarkirik erakusten duen aplikaziorik erabiltzen oso eragozgarritzat hartzen ditudalako, hortaz iragarki blokeatzaile bat gabe ez nituzke aplikazio hauek ezarriko.

    + +

    Nola egiten du lan AdAway-ek?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Zergaitik berrabiarazi behar dut Android aldaketek eragina izateko?

    +

    Java -k Android-en bere barneko DNS katxea mantentzen du. Sistema eragileak hostalari izen berriak berehala isladatuko ditu (egiaztatu ping bat eginez agindu lerroan) baina Android berrabiarazi beharko duzu Java-ren DNS katxea berreraikitzeko.

    + +

    Nola erabili web-zerbitzaria AdAway-n?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    Nola blokeatu/desblokeatu ditzaket hostalari-izen jakinak?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Non aurkitu ditzaket hostalari iturburu gehiago?

    +

    Ikusi AdAway-rako hostalari iturburu gehigarrien zerrenda.

    + +

    Lagundu itzultzen/akatsak jakinarazten

    +

    Mesedez joan https://adaway.org-ra.

    + + diff --git a/app/src/main/res/raw-eu/help_problems.html b/app/src/main/res/raw-eu/help_problems.html new file mode 100644 index 0000000..9c49d10 --- /dev/null +++ b/app/src/main/res/raw-eu/help_problems.html @@ -0,0 +1,36 @@ + + + +Ohiko arazoak + +

    Huts egin du ostalari-fitxategia kopiatzeak Android 9+en

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Ez dago nahikoa toki partizioan

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Chromek iragarkiak erakusten ditu oraindik ere

    +

    Ensure you disable lite mode (previously known as data saver) from Chrome settings. This features allows Chrome to use private DNS solution and bypass AdAway.

    + +

    Ez du iragarkirik blokeatzen XYZ aplikazioan!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in our GitHub issue tracker.

    + +

    Katxeatutako Iragarkiak

    +

    Batzuetan aplikazioek iragarkiak katxeatzen dituzte jeitsi ondoren. Honek zenbait aplikazioetan iragarkiak gelditzera eramaten du. Aplikazio hauen katxea ezabatzen saiatu zaitezke Android-en Aplikazio zerrendan arazo hau saihesteko.

    + +

    XYZ aplikazioa ez dabil gehiago!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Ez dabil Android 4.4+en

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    Web nabigatzaileetako atzera botoiak ez du lan egiten

    +

    AdAway-ren tokiko web-zerbitzaria gaitu dezakezu hobespenetan aldibaterako konponbide bat bezala.

    + + + diff --git a/app/src/main/res/raw-eu/help_s_on_s_off.html b/app/src/main/res/raw-eu/help_s_on_s_off.html new file mode 100644 index 0000000..8aac845 --- /dev/null +++ b/app/src/main/res/raw-eu/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Gailuak

    +

    AdAway-k ez du lan egiten S-ON deituriko gailu bat erabiltzen duzunean. 'ezaugarri' hau HTC gailu askotan aurkitzen da eta AdAway-k hostalari agiria idaztea saihesten du.

    + +

    S-ON/S-OFF?

    +

    S-OFF esanahi du gailuaren NAND zatia desblokeatuta dagoela eta bertan idatzi daitekeela. HTC gailuen berezko ezarpena S-ON da, honek esanahi du ezin duzula sistemako zenbait eremutara sarbiderik izan ezta errotze egonkor bat bermatu. Gainera, firmware irudien sinadura egiaztapena ere segurtaturik dago S-ON ikurrarekin.

    + +

    Nik S-ON edo S-OFF dut?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Konponbidea

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway-ek lan egin behar du orain.
    16. +
    + + diff --git a/app/src/main/res/raw-fa/help_faq.html b/app/src/main/res/raw-fa/help_faq.html new file mode 100644 index 0000000..a06b3ee --- /dev/null +++ b/app/src/main/res/raw-fa/help_faq.html @@ -0,0 +1,31 @@ + + + +پرسش و پاسخ + +

    درآمد با تبلیغات

    +

    این یک باور غلطی میباشد Ú©Ù‡ اگر کاربر هرگز بر روی تبلیغات کلیک ننماید درنتیجه مسدود نمودن آنها به یک سایت Ùˆ یا برنامه ضرر مالی نخواهد رساند. این اشتباه است، توسعه دهندگان برنامه میتوانند تنها با نمایش تبلیغات کسب درآمد نمایند. این به شما بستگی دارد Ú©Ù‡ جلوی تبلیغات را بگیرید یا نه. من شخصا از برنامه هایی Ú©Ù‡ تبلیغات نشان میدهند Ø§Ø³ØªÙØ§Ø¯Ù‡ نمیکنم زیرا Ú©Ù‡ آنها بسیار آزاردهنده هستند، بنابراین بدون مسدود کننده تبلیغات من از اینگونه برنامه ها Ø§Ø³ØªÙØ§Ø¯Ù‡ نمینمایم.

    + +

    برنامه AdAway چگونه کار میکند؟

    +

    AdAway از ÙØ§ÛŒÙ„ hosts برای مسدود کردن نام های host Ú©Ù‡ تبلیغات را ارائه Ù…ÛŒ دهند Ø§Ø³ØªÙØ§Ø¯Ù‡ Ù…ÛŒ کند ÙØ§ÛŒÙ„ host ÙØ§ÛŒÙ„ÛŒ است Ú©Ù‡ در system/etc/hosts/ ÛŒØ§ÙØª Ù…ÛŒ شود Ú©Ù‡ نام های host را به آدرس های IP نگاشت Ù…ÛŒ کند این یک روش سنتی برای تعری٠نام host به Ø¬ÙØª آدرس IP بدون تکیه بر سیستم نام دامنه (DNS) است همه نام‌ های host ناخواسته به 127.0.0.1 منتقل می‌شوند Ùˆ به این معنی Ú©Ù‡ آن ها به دستگاه شما اشاره Ù…ÛŒ کنند
    ÙØ§ÛŒÙ„ hosts قابل نوشتن نیست یک راه حل بازگشتی Ø§Ø³ØªÙØ§Ø¯Ù‡ از سرویس VPN داخلی است Ú©Ù‡ اتصالات به نام های host ناخواسته را Ùیلتر Ù…ÛŒ کند Ùˆ به دیگران اجازه Ù…ÛŒ دهد تا از آن عبور کنند

    + +

    چرا برای انجام تغییرات باید گوشی خود را خاموش و روشن کنم؟

    +

    جاوا در اندروید Ø­Ø§ÙØ¸Ù‡ پنهان DNS داخلی خود را Ø­ÙØ¸ Ù…ÛŒ کند سیستم عامل گوشی شما ÙØ§ÛŒÙ„ hosts جدید را Ùورا منعکس Ù…ÛŒ کند (این را با پینگ در خط ÙØ±Ù…ان تایید کنید) اما برای بازسازی Ø­Ø§ÙØ¸Ù‡ پنهان DNS جاوا باید گوشی خود را خاموش Ùˆ روشن کنید

    + +

    چگونه از وب سرور در AdAway Ø§Ø³ØªÙØ§Ø¯Ù‡ کنیم؟

    +

    AdAway همچنین بدون Ø§Ø³ØªÙØ§Ø¯Ù‡ از وب سرور کار خواهد کرد +

    شما Ù…ÛŒ توانید یک وب سرور محلی را در تنظیمات برگزیده AdAway ÙØ¹Ø§Ù„ کنید تا به درخواست ها با آدرس IP محلی 127.0.0.1 پاسخ دهد این به این معناست Ú©Ù‡ درخواست‌ های برنامه‌ ها به سرورهای تبلیغاتی به 127.0.0.1 منتقل می‌ شوند توسط وب سرور AdAway پاسخ داده می‌شوند +
    وقتی سرورهای تبلیغاتی در دسترس نیستند برخی از برنامه‌ ها Ú©Ù‡ از کار کردن خودداری می‌کنند با این روش دوباره در دسترس خواهند بود Ùˆ با ØµÙØ­Ù‡ خالی Ùˆ بدون تصاویر تبلیغاتی پاسخ داده Ù…ÛŒ شوند

    + +

    چگونه می توانم نام host خاصی را مسدود یا آزاد کنم؟

    +

    نام‌ host هایی را Ú©Ù‡ می‌خواهید مسدود کنید از ØµÙØ­Ù‡ اصلی به لیست مسدود شده اضاÙÙ‡ کنید Ùˆ همچنین نام‌ های host مورد نظر Ú©Ù‡ می‌ خواهید از مسدود کردن حذ٠شوند را به مجاز شده اضاÙÙ‡ کنید همچنین نام‌ های host Ú©Ù‡ می‌خواهید به یک آدرس IP خاص هدایت کنید متعلق به تغییر مسیر هستند

    + +

    از کجا می توانم منابع hosts بیشتری پیدا کنم؟

    +

    Ùهرست منابع hosts اضاÙÛŒ برای AdAway را ببینید

    + +

    کمک به ترجمه و گزارش مشکلات برنامه

    +

    Ù„Ø·ÙØ§ سایت https://adaway.org را مشاهده کنید

    + + diff --git a/app/src/main/res/raw-fa/help_problems.html b/app/src/main/res/raw-fa/help_problems.html new file mode 100644 index 0000000..9ccefff --- /dev/null +++ b/app/src/main/res/raw-fa/help_problems.html @@ -0,0 +1,37 @@ + + + +مشکلات معمول + +

    Ú©Ù¾ÛŒ ÙØ§ÛŒÙ„ hosts در اندروید 9 به بالا انجام نشد

    +

    آخرین نسخه‌ های اندروید از پارتیشن سیستم Ùقط خواندنی Ø§Ø³ØªÙØ§Ø¯Ù‡ می‌ کنند +
    +اگر از Magisk به عنوان راه حل روت Ø§Ø³ØªÙØ§Ø¯Ù‡ Ù…ÛŒ کنید مطمئن شوید Ú©Ù‡ ماژول hosts بدون سیستم را ÙØ¹Ø§Ù„ کرده Ùˆ سپس گوشی خود را خاموش Ùˆ روشن کنید

    + +

    ÙØ¶Ø§ÛŒ کاÙÛŒ در پارتیشن موجود نیست

    +

    سعی کنید ÙØ§ÛŒÙ„ های hosts هد٠را در تنظیمات برگزیده به /data/data/hosts (یا /data/hosts) تغییر دهید Ùˆ دوباره AdAway را انجام دهید

    + +

    کروم همچنان تبلیغات را نمایش می دهد

    +

    مطمئن شوید Ú©Ù‡ حالت ساده (Ú©Ù‡ قبلا به عنوان ذخیره داده شناخته Ù…ÛŒ شد) را در تنظیمات Chrome ØºÛŒØ±ÙØ¹Ø§Ù„ کرده اید این ویژگی به Chrome اجازه Ù…ÛŒ دهد تا از راه DNS خصوصی Ø§Ø³ØªÙØ§Ø¯Ù‡ کند Ùˆ AdAway را دور بزند

    + +

    تبلیغات را در برنامه XYZ مسدود نمی کند

    +

    ممکن است برخی از نام‌ های host در ÙØ§ÛŒÙ„‌ های میزبان ارائه شده در منبع Hosts وجود نداشته باشد یا برنامه تصاویر را برای ارائه تبلیغات بدون دسترسی به اینترنت همراه کرده است

    +شما همچنین می‌توانید درخواست‌ های DNS (درخواست‌ های منوی گزارش DNS) را به AdAway وارد کنید تا بÙهمید کدام نام میزبان اضاÙÛŒ باید مسدود شود +

    با ÙØ´Ø§Ø± دادن طولانی ورودی‌ ها در گزارش نام host مشکوک را به لیست سیاه خود اضاÙÙ‡ کنید Ùˆ هنگامی Ú©Ù‡ آن ها را در ردیاب مشکل گیت هاب ما تایید کردید این نام‌ ها را گزارش کنید

    + +

    تبلیغات در Ø­Ø§ÙØ¸Ù‡ پنهان ذخیره شده

    +

    گاهی اوقات برنامه ها پس از دانلود تبلیغات را در Ø­Ø§ÙØ¸Ù‡ پنهان Ù†Ú¯Ù‡ Ù…ÛŒ دارند این کار باعث باقی ماندن تبلیغات در برخی از برنامه ها Ù…ÛŒ شود برای دور زدن این مشکل Ù…ÛŒ توانید Ø­Ø§ÙØ¸Ù‡ پنهان این برنامه ها را از لیست برنامه های اندروید حذ٠کنید

    + +

    برنامه XYZ دیگر کار نمی کند

    +

    برخی از برنامه‌ ها باید با نام host هایی Ú©Ù‡ توسط AdAway مسدود شده ارتباط برقرار کنند یا هنگامی Ú©Ù‡ نام host های مورد نظر Ú©Ù‡ باید تبلیغات را ارائه دهند در دسترس نیستند از کار کردن خودداری کنند به لینک گیت هاب ما به آدرس https://github.com/AdAway/AdAway/wiki/ProblematicApps مراجعه کنید تا لیستی از برنامه های شناخته شده ای Ú©Ù‡ مشکل دارند را Ø¯Ø±ÛŒØ§ÙØª کنید در غیر این صورت متوجه شوید Ú©Ù‡ کدام نام host لازم است Ùˆ آن ها را به لیست سÙید موجود در لیست های خود اضاÙÙ‡ کنید Ùˆ آن ها را به ردیاب اشکال AdAway گزارش دهید

    + +

    در اندروید 4.4 به بالا کار نمی کند

    +

    سعی کنید ÙØ§ÛŒÙ„ های hosts هد٠را در تنظیمات برگزیده از /data/data/hosts به /data/hosts یا /system/etc/hosts تغییر دهید Ùˆ دوباره AdAway را انجام دهید

    + +

    دکمه برگشت در مرورگر های وب کار نمی کند

    +

    شما Ù…ÛŒ توانید وب سرور محلی AdAway را در تنظیمات برگزیده به عنوان یک راه حل ÙØ¹Ø§Ù„ کنید

    + + + diff --git a/app/src/main/res/raw-fa/help_s_on_s_off.html b/app/src/main/res/raw-fa/help_s_on_s_off.html new file mode 100644 index 0000000..461198e --- /dev/null +++ b/app/src/main/res/raw-fa/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    دستگاه های HTC

    +

    اگر دستگاه شما از S-ON Ø§Ø³ØªÙØ§Ø¯Ù‡ نماید برنامه AdAway کار نخواهد کرد. این قابلیت در اکثر دستگاه های HTC وجود دارد Ùˆ جلوی AdAway را برای تغییر ÙØ§ÛŒÙ„ hosts میگیرد.

    + +

    S-ON/S-OFF?

    +

    قابلیت S-OFF این معنی را میدهد Ú©Ù‡ NAND portion دستگاه آنلاک شده Ùˆ قابل ویرایش میباشد. در دستگاه های HTC حالت پیش ÙØ±Ø¶ S-ON میباشد، به این معنی Ú©Ù‡ نه به شما اجازه دسترسی به قسمت هایی از سیستم را میدهد Ùˆ نه گارانتی روت دائمی میباشد. علاوه بر این بررسی اصالت امضای ایمیج ÙØ±Ù…ویر توسط S-ON مراقبت میشود.

    + +

    من کدامیک از حالت های S-ON یا S-OFF را دارم؟

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    راه حل

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. برنامه AdAway میبایستی الان کار کند.
    16. +
    + + diff --git a/app/src/main/res/raw-fi/help_faq.html b/app/src/main/res/raw-fi/help_faq.html new file mode 100644 index 0000000..cf217f7 --- /dev/null +++ b/app/src/main/res/raw-fi/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Tuotot mainoksilla

    +

    Yleinen harhaluulo on, että jos käyttäjä ei koskaan klikkaa mainoksia, niin niiden estäminen ei haittaa sivua tai sovellusta taloudellisesti. Tämä ei kuitenkaan pidä paikkaansa, sillä kehittäjät tienaavat rahaa myös vain näyttämällä mainoksia. Riippuu itsestäsi haluatko estää mainokset vai et. Henkilökohtaisesti en käyttäisi sovelluksia, jotka näyttävät mainoksia, sillä mainokset ovat mielestäni ärsyttäviä, joten ilman mainostenesto-ohjelmaa en asentaisi kyseisiä sovelluksia.

    + +

    Kuinka AdAway toimii?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Miksi minun täytyy käynnistää Android uudelleen ottaakseni muutokset voimaan?

    +

    Androidin Java ylläpitää omaa sisäistä DNS-välimuistia. Käyttöjärjestelmä kuvastaa uuttaa hosts-tiedostoa heti (varmista se pingillä komentorivillä), mutta sinun täytyy käynnistää Android uudelleen jälleenrakentaaksesi Javan DNS-välimuisti.

    + +

    Kuinka AdAwayn web-palvelinta käytetään?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    Kuinka voin estää/sallia tiettyjen palvelinten nimet?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Mistä löydän lisää hosts-lähteitä?

    +

    Katso Luettelo hosts-lähteistä.

    + +

    Auta kääntämisessä tai ilmoita virheistä

    +

    Mene https://adaway.org.

    + + diff --git a/app/src/main/res/raw-fi/help_problems.html b/app/src/main/res/raw-fi/help_problems.html new file mode 100644 index 0000000..cce4ea7 --- /dev/null +++ b/app/src/main/res/raw-fi/help_problems.html @@ -0,0 +1,36 @@ + + + +Yleiset ongelmat. + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Ei tarpeeksi tilaa osiossa

    +

    Yritä vaihtaa kohde hosts tiedosto asetuksissa /data/data/hosts (tai /data/hosts) tiedostoon ja käynnistä AdAway uudestaan.

    + +

    Ei toimi Android 4.4:stä ylemmillä Android versioilla

    +

    Yritä vaihtaa kohde hosts tiedosto asetuksissa /data/data/hosts tiedostosta /data/hosts taisystem/etc/hosts ja käynnistä AdAway uudelleen.

    + +

    Se ei estä mainoksia XYZ-sovelluksesta!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Välimuistiin tallennetut mainokset

    +

    Joskus sovellukset laittavat mainokset välimuistiin lataamisen jälkeen. Siitä johtuen joissakin sovelluksissa näkyy mainoksia. Voit yrittää poistaa näiden sovellusten välimuistin tämän ongelman kiertämiseksi.

    + +

    XYZ-sovellus ei toimi enää!

    +

    Joidenkin sovellusten tarvitsee kommunikoida AdAwayn estämän palvelimen kanssa tai ne eivät suostu toimimaan, koska palvelimet joista mainosten pitäisi tulla ovat estetty. Katso https://github.com/AdAway/AdAway/wiki/ProblematicApps saadaksesi listan tiedetyistä ohjelmista joilla on ongelmia. Muutoin, ota selvää mitkä palvelimet ovat tarpeen ja lisää ne kohtaan whitelist alla Your List ja ilmoita ne AdAwayn bug trackerille

    + +

    Takaisin-painike selaimissa ei toimi.

    +

    Voit ottaa asetuksista käyttöön AdAwayn paikallisen web-palvelimen väliaikaisena korjauksena.

    + +

    Takaisin-painike selaimissa ei toimi.

    +

    Voit ottaa asetuksista käyttöön AdAwayn paikallisen web-palvelimen väliaikaisena korjauksena.

    + + + diff --git a/app/src/main/res/raw-fi/help_s_on_s_off.html b/app/src/main/res/raw-fi/help_s_on_s_off.html new file mode 100644 index 0000000..5dbfbd0 --- /dev/null +++ b/app/src/main/res/raw-fi/help_s_on_s_off.html @@ -0,0 +1,32 @@ + + + +S-ON liittyvä apu. + +

    HTC-laitteet

    +

    AdAway ei toimi, kun käytät niin sanottua S-ON-laitetta. tämä 'ominaisuus' on monissa HTC-laitteissa ja estää AdAwayn kirjoittamasta hosts-tiedoston.

    + +

    S-ON/S-OFF?

    +

    S-OFF tarkoittaa, että laitteen NAND-osio on lukitsematon ja siihen voidaan kirjoittaa. HTC-laitteissa oletuksena on S-ON, mikä tarkoittaa, että myöskään sinä et voi käyttää tiettyjä järjestelmän alueita, eikä ole myöskään mahdollista varmistaa pysyvää pääkäyttäjäoikeutta. Tämän lisäksi S-ON -lipulla varmistetaan allekirjoituksen tarkistaminen laiteohjelmiston otoksista .

    + +

    Onko minulla S-ON tai S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Kiertotapa

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Käynnistä laitteesi laitteen käynnistys menuun pitämällä painiketta volume alas pohjassa painaen samalla virta painiketta pohjaan.
    2. +
    3. Käytä äänenvoimakkuus alas painiketta valitaksesi recoveryn sen jälkeen virtapainiketta käynnistääksesi laitteen.
    4. +
    5. Clockwork recoveryssä valitse "partitions menu".
    6. +
    7. Valitsemount/ system, mount /sdcard ja mount /data.
    8. +
    9. Kytke USB johto ja avaa komentokehote tietokoneessasi.
    10. +
    11. Avaa adb komentorivi ja kirjoita In -s /data/hosts /system/etc/hosts (Tämä luo symbolisen linkin, joka sallii AdAwayn muokata hosts tiedostoa joka on osiossa /data sallien käyttöjärjestelmän käyttää tiedostoa aivan kuin se tallennettu osioon /system.)
    12. +
    13. Käynnistä laite uudelleen ja aseta Target hosts tiedosto</ /data/hosts osioon AdAwayn asetuksissa. +
    14. +
    15. AdAway:n pitäisi toimia nyt.
    16. +
    + + diff --git a/app/src/main/res/raw-fil/help_faq.html b/app/src/main/res/raw-fil/help_faq.html new file mode 100644 index 0000000..5c6d504 --- /dev/null +++ b/app/src/main/res/raw-fil/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Kita sa pamamagitan ng mga advertisement

    +

    Mayroong isang madalas na sinasabing maling kuru-kuro na kung ang isang user ay hindi kailanman nag-click sa mga ad, ang pagharang sa kanila ay hindi makakasama sa isang site o aplikasyon sa pananalapi. Mali ito, kumikita rin ang mga developer sa pamamagitan lamang ng pagpapakita ng mga ad. Nasa sa iyo kung ha-harangan mo ang mga ad o hindi. Sa personal, hindi ako gagamit ng mga aplikasyon na nagpapakita ng mga ad dahil sa tingin ko ay nakakainis ang mga ito, kaya kung walang ad blocker hindi ko mai-install ang mga aplikasyon na ito.

    + +

    Paano gumagana ang AdAway?

    +

    Ginagamit ng AdAway ang hosts file upang harangan ang mga hostname, na naghahatid ng mga advertisement. Ang file ng host ay isang file na matatagpuan sa /system/etc/hosts na nagmamapa ng mga hostname sa mga IP address. Ito ay isang tradisyonal na paraan upang tukuyin ang hostname sa mga pares ng IP address nang hindi umaasa sa Domain Name System (DNS). Ang lahat ng hindi gustong hostname ay na-redirect sa 127.0.0.1 na nangangahulugang ituturo nila ang iyong sariling device.
    +Kung ang file ng mga host ay hindi maisusulat, ang isang fallback na solusyon ay ang paggamit ng builtin na serbisyo ng VPN. Sasalain nito ang mga koneksyon sa mga hindi gustong hostname at hahayaan ang iba na dumaan.

    + +

    Bakit kailangan kong i-restart ang Android para gumana ang mga pagbabago?

    +

    Ang Java sa Android ay nagpapanatili ng sarili nitong panloob na DNS cache. Ipapakita kaagad ng operating system ang bagong hosts file (i-verify iyon gamit ang ping sa command line) ngunit kakailanganin mong i-restart ang Android upang muling buuin ang DNS cache ng Java.

    + +

    Paano gamitin ang webserver sa AdAway?

    +

    Gagana rin ang AdAway nang hindi ginagamit ang webserver! +

    Maaari mong paganahin ang isang lokal na webserver sa mga kagustuhan ng AdAway upang sagutin ang mga kahilingan sa lokal na IP address na 127.0.0.1. Nangangahulugan ito na ang mga kahilingan mula sa mga aplikasyon patungo sa mga server ng ad na na-redirect sa 127.0.0.1 ay sinasagot ng webserver ng AdAway. +Ang ilang mga aplikasyon ay tumangging gumana, kapag ang mga server ng ad ay hindi maabot. Sa pamamaraang ito, muli silang maaabot, tumutugon nang may blangkong pahina at walang mga imahe ng ad.

    + +

    Paano ko mai-block/i-unblock ang mga partikular na hostname?

    +

    Idagdag ang mga hostname na gusto mong i-block sa Naka-block na listahan mula sa homescreen. Bilang karagdagan, ang mga hostname na gusto mong ibukod mula sa pagba-block ay maaaring idagdag sa Allowed at ang mga hostname na gusto mong i-redirect sa isang partikular na IP address ay nabibilang sa Redirected.

    + +

    San makikita ang mga ibang pinagmulang ng hosts?

    +

    Tignan Listahan ng mga ibang pinagmulang ng AdAway.

    + +

    Tumulong sa pagsasalin at pagsumbong ng bugs

    +

    Pumunta sa https://adaway.org.

    + + diff --git a/app/src/main/res/raw-fil/help_problems.html b/app/src/main/res/raw-fil/help_problems.html new file mode 100644 index 0000000..c3d86b0 --- /dev/null +++ b/app/src/main/res/raw-fil/help_problems.html @@ -0,0 +1,36 @@ + + + +Mga karaniwang problema + +

    Nabigo ang kopya ng hosts file sa Android 9+

    +

    Ang mga pinakabagong bersyon ng Android ay gumagamit ng read-only /system partition.
    +Kung gumagamit ka ng Magisk bilang root solution, tiyaking enable mo ang systemless hosts module pagkatapos ay i-reboot.

    + +

    Walang sapat na space sa partition

    +

    Subukang palitan ang mga target host file sa preferences sa /data/data/hosts (o /data/hosts) at i-apply muli ang AdAway.

    + +

    Nagpapakita pa rin ng mga ad ang Chrome

    +

    Tiyaking hindi mo pinagana ang lite mode (dating kilala bilang data saver) mula sa Chrome settings. Nagbibigay-daan ang mga feature na ito sa Chrome na gumamit ng pribadong solusyon sa DNS at i-bypass ang AdAway.

    + +

    Hindi nito naba-block ang mga ad sa application na XYZ!

    +

    Ang ilang mga hostname ay maaaring nawawala sa ibinigay na mga file ng host mula sa Hosts Sources o ang aplikasyon ay nag-bundle ng mga larawan upang magbigay ng mga ad nang hindi ina-access ang internet.

    +Maaari kang mag-log ng mga kahilingan sa DNS (Menu->Log DNS Requests) mula sa AdAway upang malaman kung aling mga karagdagang hostname ang kailangang i-block. +

    Idagdag ang mga kahina-hinalang hostname sa iyong sariling Blacklist sa pamamagitan ng pagpindot nang matagal sa mga entry sa Log at iulat ang mga hostname na ito kapag na-verify mo na ang mga ito sa aming GitHub issue tracker.

    + +

    Cached Advertisements

    +

    Minsan ang mga aplikasyon ay nag-cache ng mga ad pagkatapos ng pag-download. Ito ay humahantong sa mga natitirang advertisement sa ilang mga applikasyon. Maaari mong subukang burahin ang cache para sa mga aplikasyon na ito sa Android's Application list upang iwasan ang problemang ito.

    + +

    Hindi na gumagana ang Application XYZ!

    +

    Ang ilang mga applikasyon ay kailangang makipag-ugnayan sa isang hostname na na-block ng AdAway o tumangging paganahin kapag ang mga hostname na dapat maghatid ng mga ad ay hindi maabot. Tingnan ang https://github.com/AdAway/AdAway/wiki/ProblematicApps upang makakuha ng listahan ng mga kilalang aplikasyon na may mga problema. Kung hindi, alamin kung aling mga hostname ang kailangan at idagdag ang mga ito sa iyong Whitelist sa ilalim ng Your Lists at iulat ang mga ito sa bug tracker ng AdAway.

    + +

    Hindi gumagana sa Android 4.4+

    +

    Subukang baguhin ang target hosts file sa preferences mula sa /data/data/hosts patungo sa /data/hosts o /system/etc/hosts at muling i-apply ang AdAway.

    + +

    Ang back button sa mga web browser ay hindi gumagana

    +

    Maaari mong paganahin ang lokal na webserver ng AdAway sa preferences bilang isang solusyon.

    + + + diff --git a/app/src/main/res/raw-fil/help_s_on_s_off.html b/app/src/main/res/raw-fil/help_s_on_s_off.html new file mode 100644 index 0000000..020da13 --- /dev/null +++ b/app/src/main/res/raw-fil/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    Mga producto ng HTC

    +

    Ang AdAway ay hindi gumagana kapag ang ginagamit mo ay may S-ON. Itong feature ay matatapuan sa maraming produkto ng HTC, ito ay nakakapaghintulot ng pagsulat ng hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. Ang AdAway ay gumagana na dapat.
    16. +
    + + diff --git a/app/src/main/res/raw-fr/help_faq.html b/app/src/main/res/raw-fr/help_faq.html new file mode 100644 index 0000000..72dfba9 --- /dev/null +++ b/app/src/main/res/raw-fr/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Recettes publicitaires

    +

    Une idée fausse courante veut que si un utilisateur ne clique jamais sur les publicités, alors les bloquer n’ait pas de conséquences pécuniaires pour le site ou l’application. Cela est faux. Les développeurs gagnent aussi de l’argent juste en affichant des publicités. C’est à vous de décider de bloquer ou non les publicités. Personnellement, je n’utiliserais pas d’applications qui affichent des publicités, car je les trouve très agaçantes. Donc sans blocage des publicités, je n’installerais pas ces applications.

    + +

    Comment AdAway fonctionne-t-il ?

    +

    AdAway utilise le fichier hosts pour bloquer les noms d’hôtes qui servent des publicités. Le fichier hosts se situe dans /system/etc/hosts et mappe les noms d’hôtes à des adresses IP. C’est une façon habituelle de définir des paires noms de serveurs/adresses IP sans avoir recours au système de noms de domaine (DNS). Tous les noms d’hôtes indésirables sont redirigés vers 127.0.0.1, c’est-à-dire votre propre appareil.
    +S’il est impossible d’écrire dans le fichier hosts, vous pouvez utiliser le service de RPV intégré comme solution de rechange. Il filtrera les connexions vers les noms d’hôte indésirables et laissera passer les autres.

    + +

    Pourquoi dois-je redémarrer Android pour que les changements prennent effet ?

    +

    Java sur Android maintient son propre cache DNS interne. Le système d’exploitation appliquera immédiatement le nouveau fichier hosts (vérifiez-le avec ping en ligne de commande), mais vous devrez redémarrer Android pour reconstruire le cache DNS de Java.

    + +

    Comment utiliser le serveur Web d’AdAway ?

    +

    AdAway fonctionnera aussi sans utiliser le serveur Web. +

    Vous pouvez activer un serveur Web local dans les préférences d’AdAway pour répondre aux requêtes à l’adresse IP locale 127.0.0.1. Ainsi, le serveur Web d’AdAway répondra aux requêtes des applications vers les serveurs de publicités redirigées vers 127.0.0.1. +
    Certaines applications refusent de fonctionner si les serveurs de publicités ne sont pas accessibles. Avec cette méthode, ils le seront de nouveau et répondront par une page blanche et sans images publicitaires.

    + +

    Comment puis-je bloquer ou débloquer certains noms d’hôtes ?

    +

    À partir de l’écran d’accueil, ajoutez à la liste Bloqués le nom des hôtes que vous souhaitez bloquer. De plus, le nom des hôtes que vous souhaitez exclure du blocage peut être ajouté à la liste Autorisés, et le nom des hôtes que vous voulez rediriger vers une adresse IP précise peut être ajouté à la liste Redirigés.

    + +

    Où puis-je trouver d’autres sources de fichiers hosts ?

    +

    Consultez la liste des sources de fichiers hosts supplémentaires pour AdAway.

    + +

    Aider à la traduction, signaler des bogues

    +

    Veuillez visiter https://adaway.org.

    + + diff --git a/app/src/main/res/raw-fr/help_problems.html b/app/src/main/res/raw-fr/help_problems.html new file mode 100644 index 0000000..e4a342d --- /dev/null +++ b/app/src/main/res/raw-fr/help_problems.html @@ -0,0 +1,36 @@ + + + +Problèmes courants + +

    La copie du fichier hosts a échoué sur Android 9+

    +

    Les dernières versions d’Android utilisent une partition /system en lecture seule.
    +Si vous utilisez Magisk comme solution de débridage, assurez-vous d’activer le module « Systemless Hosts », puis redémarrez.

    + +

    Il manque d’espace sur la partition

    +

    Essayez de changer le fichier hosts cible dans les préférences pour /data/data/hosts (ou /data/hosts) et appliquez AdAway de nouveau.

    + +

    Chrome affiche encore des publicités

    +

    Assurez-vous de désactiver le mode simplifié (anciennement économiseur de données) dans les paramètres de Chrome. Cette fonction permet à Chrome d’utiliser une solution de DNS privée et de contourner AdAway.

    + +

    Les publicités ne sont pas bloquées dans l’application XYZ.

    +

    Il pourrait manquer des noms d’hôtes dans les fichiers hosts dessources d’hosts ou l’application a intégré les images afin de servir des publicités sans accéder à Internet.

    +Vous pouvez utiliser AdAway pour journaliser les requêtes DNS (Menu->Journaliser les requêtes DNS) et découvrir quels noms d’hôtes supplémentaires doivent être bloqués. +

    Ajoutez les noms d’hôte suspects à votre propre liste noire en appuyant longuement sur les entrées du journal et après les avoir vérifiés, signalez ces noms d’hôte dans notre gestionnaire de problèmes sur GitHub (site en anglais).

    + +

    Publicités mises en cache

    +

    Parfois, les applications mettent dans le cache les publicités après téléchargement. C’est pourquoi, il reste des publicités dans certaines applications. Vous pouvez essayer de supprimer le cache de ces applications dans le gestionnaire d’applications d’Android pour contourner ce problème.

    + +

    L’application XYZ ne fonctionne plus.

    +

    Certaines applications doivent communiquer avec un nom d’hôte qui est bloqué par AdAway ou refusent de fonctionner quand les noms d’hôte qui devraient servir des publicités ne sont pas accessibles. Consultez https://github.com/AdAway/AdAway/wiki/ProblematicApps pour obtenir une liste d’applications connues qui posent des problèmes. Autrement, déterminez quels noms d’hôtes sont nécessaires, ajoutez-les à votre liste blanche dans Vos listes et signalez-les au gestionnaire de bogues d’AdAway.

    + +

    Ne fonctionne pas sur Android 4.4+

    +

    Dans les préférences, essayez de changer le fichier hosts cible de /data/data/hosts à /data/hosts ou /system/etc/hosts, et appliquez AdAway de nouveau.

    + +

    Le bouton retour des navigateurs Web ne fonctionne pas

    +

    Vous pouvez activer le serveur Web local d’AdAway dans les préférences comme palliatif.

    + + + diff --git a/app/src/main/res/raw-fr/help_s_on_s_off.html b/app/src/main/res/raw-fr/help_s_on_s_off.html new file mode 100644 index 0000000..7c5a797 --- /dev/null +++ b/app/src/main/res/raw-fr/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Aide sur S-ON + +

    Appareils HTC

    +

    AdAway ne fonctionne pas si vous utilisez un appareil équipé de S-ON. Cette « fonction » existe sur de nombreux appareils HTC et empêche AdAway d’écrire le fichier hosts.

    + +

    S-ON/S-OFF ?

    +

    S-OFF signifie que la partie NAND de l’appareil est déverrouillée et qu’on peut y écrire. Le réglage par défaut des appareils HTC est S-ON, ce qui signifie que vous ne pouvez ni accéder à certaines parties du système ni obtenir un accès racine permanent. De plus, la vérification de la signature des images du micrologiciel est aussi assurée par S-ON.

    + +

    Ai-je S-ON ou S-OFF ?

    +

    Lancez le menu d’amorçage de votre appareil en appuyant sur le bouton volume bas en même temps que sur le bouton de mise en marche. Le texte en haut affichera l’état du drapeau, soit S-ON soit S-OFF. Un débridage complet de l’appareil entraîne généralement S-OFF. +

    Plus de précisions se trouvent sur www.addictivetips.com (site en anglais). D’autres méthodes S-OFF depuis Unrevokable (dans le lien) pourraient vous intéresser : Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Palliatif

    +

    Prérequis : vous devez installer une trousse SDK Android fonctionnelle avec « ADB shell » sur votre ordinateur.

    +
      +
    1. Lancez le menu d’amorçage de votre appareil en appuyant sur le bouton volume bas en même temps que sur le bouton de mise en marche.
    2. +
    3. Utilisez volume bas pour sélectionner recovery, puis appuyez sur le bouton de mise en marche pour redémarrer en mode récupération.
    4. +
    5. Dans « clockwork recovery », allez dans « partitions menu ».
    6. +
    7. Sélectionnez mount /system, mount /sdcard et mount /data.
    8. +
    9. Branchez votre câble USB et ouvrez une ligne de commande sur votre ordinateur.
    10. +
    11. Saisissez « adb shell » et tapez ln -s /data/hosts /system/etc/hosts (cela crée un lien symbolique qui permet à AdAway de modifier le fichier hosts enregistré dans /data tout en permettant au SE d’utiliser le fichier comme s’il était enregistré dans /system).
    12. +
    13. Redémarrez votre appareil, puis définissez Fichier hosts cible à data/hosts dans les préférences d’AdAway.
    14. +
    15. AdAway devrait fonctionner maintenant.
    16. +
    + + diff --git a/app/src/main/res/raw-gl/help_faq.html b/app/src/main/res/raw-gl/help_faq.html new file mode 100644 index 0000000..7966128 --- /dev/null +++ b/app/src/main/res/raw-gl/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    Como funciona AdAway?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Porqué teño que reiniciar Android para que xurda efecto?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-gl/help_problems.html b/app/src/main/res/raw-gl/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-gl/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-gl/help_s_on_s_off.html b/app/src/main/res/raw-gl/help_s_on_s_off.html new file mode 100644 index 0000000..8a6ddcd --- /dev/null +++ b/app/src/main/res/raw-gl/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    Dispositivos HTC

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-hi/help_faq.html b/app/src/main/res/raw-hi/help_faq.html new file mode 100644 index 0000000..eef0819 --- /dev/null +++ b/app/src/main/res/raw-hi/help_faq.html @@ -0,0 +1,32 @@ + + + +सवाल + +

    इनकम बाय अदà¥à¤µà¥‡à¤°à¥à¤¤à¤¿à¤¸à¥‡à¤®à¥‡à¤¨à¥à¤Ÿà¥à¤¸

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-hi/help_problems.html b/app/src/main/res/raw-hi/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-hi/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-hi/help_s_on_s_off.html b/app/src/main/res/raw-hi/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-hi/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-hr/help_faq.html b/app/src/main/res/raw-hr/help_faq.html new file mode 100644 index 0000000..5d2ab6c --- /dev/null +++ b/app/src/main/res/raw-hr/help_faq.html @@ -0,0 +1,32 @@ + + + +ÄŒesta pitanja + +

    Zarada od oglasa

    +

    Postoji općenito nerazumijevanje da ukoliko korisnik nikada ne klika na oglase, tada se blokiranje istih neće negativno financijski odraziti na stranicu ili aplikaciju. To je pogrešno, razvijatelji isto tako zarađuju novac samim prikazom oglasa. Na vama je hoćete li, ili nećete blokirati oglase. Osobno ne bih koristio aplikacije koje prikazuju oglase jer ih smatram vrlo iritantnima, stoga bez blokatora oglasa ne bih instalirao aplikacije te vrste.

    + +

    Kako AdAway radi?

    +

    AdAway koristi datoteku poslužitelja za blokiranje naziva poslužitelja koji dostavljaju oglase. Datoteka poslužitelja može se pronaći u /system/etc/hosts , a mapira nazive poslužitelja na IP adrese. To je tradicionalan naÄin za odreÄ‘ivanja naziva poslužitelja uparivanjem s parovima IP adresa bez oslanjanja na DNS (Domain Name System). Svi neželjeni nazivi poslužitelja se preusmjeravaju na 127.0.0.1, Å¡to znaÄi da će biti usmjereni na vaÅ¡ ureÄ‘aj.
    +Ako datoteka poslužitelja nije zapisiva, priÄuvno rjeÅ¡enje je koriÅ¡tenje VPN usluge. Filtrirat će povezivanja s neželjenim nazivima poslužitelja i ostale propustiti.

    + +

    Zašto moram ponovno pokrenuti Android kako bi se promjene primijenile?

    +

    Java na Androidu ima svoju unutrašnju DNS predmemoriju. Operativni sustav će primijeniti novu datoteku poslužitelja odmah (to možete provjeriti pomoću ping naredbe u naredbenom redku), ali je potrebno ponovno pokrenuti Android kako bi se DNS predmemorija Jave ponovno izgradila.

    + +

    Kako koristiti web poslužitelj u AdAwayu?

    +

    AdAway isto može raditi bez web poslužitelja! +

    Možete omogućiti lokalnog web poslužitelja u postavkama AdAwaya kako bi preusmjerio zahtjeve na lokalnu IP adresu 127.0.0.1. o znaÄi da zahtjevi aplikacije prema poslužiteljima za oglase su preusmjereni na 127.0.0.1 odgovaraju AdAway web poslužitelju. +
    Neke aplikacije odbijaju raditi kada poslužitelji oglaÅ¡avanja nisu dostupni. Ovim naÄinom postati će opet dostupni, prikazom prazne stranice bez slika oglasa.

    + +

    Kako mogu blokirati/odblokirati određene nazive poslužitelja?

    +

    Dodajte nazive poslužitelja koje želite blokirati u popisu Blokirani iz vaÅ¡eg PoÄetnog zaslona. Dodatno, nazive poslužitelja koje želite iskljuÄiti iz blokiranja možete dodati u popis DopuÅ¡teni a nazive poslužitelja koje želite preusmjeriti na odreÄ‘enu IP adresu pripadaju u popis Preusmjereni.

    + +

    Gdje mogu pronaći više izvora poslužitelja?

    +

    Pogledajte Popis dodatnih izvora poslužitelja za AdAway.

    + +

    Pomozite u prijevodu/prijavi grešaka.

    +

    Posjetite http://adaway.org.

    + + diff --git a/app/src/main/res/raw-hr/help_problems.html b/app/src/main/res/raw-hr/help_problems.html new file mode 100644 index 0000000..bde0c98 --- /dev/null +++ b/app/src/main/res/raw-hr/help_problems.html @@ -0,0 +1,36 @@ + + + +UÄestali problemi + +

    Neuspjelo kopiranje datoteke poslužitelja na Androidu 9+

    +

    Posljednja inaÄica Androida koristi /system particiju samo s dozvolama Äitanja.
    +Ako koristite Magisk kao root rješenje, omogućite systemless modul poslužitelja i ponovno pokrenite uređaj.

    + +

    Nedovoljno prostora na particiji

    +

    Pokušajte promijeniti odredište datoteke poslužitelja u postavkama u /data/data/hosts (ili /data/hosts) pa ponovno preuzmite i primijenite datoteku poslužitelja.

    + +

    Chrome još uvijek prikazuje oglase

    +

    Provjerite jeste li onemogućili Lagan naÄin (prije poznat kao podatkovni poslužitelj) iz Chrome postavki. Ova znaÄajka omogućuje Chromu koriÅ¡tenje privatnih DNS rjeÅ¡enja i zaobilaženje AdAwaya.

    + +

    Ne blokira oglase u aplikaciji XYZ!

    +

    Određeni nazivi poslužitelja mogu nedostajati u datoteci poslužitelja u postavkama Izvori poslužitelja ili aplikacija ima ugrađene slike kako bi pružile oglase bez pristupa internetu.

    +Možete zapisivati DNS zahtjeve u (Izbornik -> Zapisuj DNS zahtjeve) iz AdAwaya kako bi saznali koji se dodatni poslužitelj treba blokirati. +

    Dodajte sumnjive nazive poslužitelja na vaš vlastiti Popis blokiranih dugim pritiskom unosa u Zapisu i prijavite te nazive poslužitelja nakon što ste ih provjerili na naš GitHub pratitelj grešaka.

    + +

    Oglasi spremljeni u predmemoriju

    +

    Ponekad aplikacije spremaju oglase u predmemoriju nakon što ih preuzmu. To dovodi do ostajanja oglasa u nekim aplikacijama. Možete pokušati obrisati predmemoriju tih aplikacija u popisu aplikacija unutar Android sustava kako biste zaobišli taj problem.

    + +

    Aplikacija XYZ više ne radi!

    +

    OdreÄ‘enim aplikacijama je potrebna komunikacija s nazivima poslužitelja koje je blokirao AdAway ili odbijaju raditi kada nazivi poslužitelja koji poslužuju reklame nisu dostupni. Pogledajte https://github.com/AdAway/AdAway/wiki/ProblematicApps kako bi dobili popis poznatih problematiÄnih aplikacija. U suprotnome, potražite koji nazivi poslužitelja su potrebni i dodajte ih u vaÅ¡ Popis neblokiranih u izborniku VaÅ¡i popisi i prijavite ih na AdAway pratitelj greÅ¡aka.

    + +

    Ne radi na Androidu 4.4+

    +

    Pokušajte promijeniti odredište datoteke poslužitelja u postavkama iz /data/data/hosts u /data/hosts ili /system/etc/hosts i primijenite AdAway ponovno.

    + +

    Tipka za povratak u web pregledniku ne radi

    +

    Možete omogućiti AdAway lokalni web poslužitelj u postavkama kao zaobilazno rješenje.

    + + + diff --git a/app/src/main/res/raw-hr/help_s_on_s_off.html b/app/src/main/res/raw-hr/help_s_on_s_off.html new file mode 100644 index 0000000..ae7f251 --- /dev/null +++ b/app/src/main/res/raw-hr/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON pomoć + +

    HTC uređaji

    +

    AdAway ne radi kada koristite takozvane S-ON ureÄ‘aje. Ta "znaÄajka" je prisutna na mnogim HTC ureÄ‘ajima i sprjeÄava AdAway u pisanju datoteke poslužitelja.

    + +

    S-ON/S-OFF?

    +

    S-OFF oznaÄava da je NAND dio ureÄ‘aja otkljuÄan i može se zapisivati na njega. Zadana postavka za HTC ureÄ‘aje je S-ON, Å¡to znaÄi da ne možete pristupiti odreÄ‘enim dijelovima sustava, niti vam može jamÄiti trajni root pristup. Å toviÅ¡e, provjera potpisa za slike firmvera isto je osigurana S-ON oznakom.

    + +

    Imam li S-ON ili S-OFF?

    +

    Pokrenite u Boot Menu vaÅ¡ ureÄ‘aj držeći tipku smanjivanja glasnoće zvuka i istovremeno držeći tipku iskljuÄivanja a tekst na vrhu zaslona će prikazati oznaku stanja kao S-OFF ili kao S-ON. Potpuni root uobiÄajeno znaÄi S-OFF. +

    ViÅ¡e informacija možete pronaći na www.addictivetips.com. Dodatni S-OFF naÄini od Unrevokable (na poveznici) vas mogu zanimati, imenima: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Zaobilaženje

    +

    Preduvjet: instalirani i funkcionalni Android SDK s ADB ljuskom na vašem PC-u.

    +
      +
    1. Pokrenite u Boot Menu vaÅ¡ ureÄ‘aj držeći tipku smanjivanja glasnoće zvuka i istovremeno držeći tipku iskljuÄivanja.
    2. +
    3. Koristite tipku smanjivanja glasnoće zvuka za odabir izbornika oporavka zatim tipku iskljuÄivanja pokretanje u naÄin oporavka.
    4. +
    5. U Clockwork recoveriju idite na stavku "Partitions menu".
    6. +
    7. Odaberite mount /system, mount /sdcard i mount /data.
    8. +
    9. PrikljuÄite USB kabel i otvorite naredbeni redak na svome PC-u.
    10. +
    11. Pokrenite adb ljusku i upiÅ¡ite ln -s /data/hosts /system/etc/hosts (Ovo će stvoriti simboliÄku poveznicu, koja dopuÅ¡ta AdAwayu ureÄ‘ivanje datoteke poslužitelja pohranjene u /data dopuÅ¡tajući operativnom sustavu da koristi tu datoteku kao da je pohranjena u /system.)
    12. +
    13. Ponovno pokrenite svoj uređaj i postavite Odredišnu datoteku poslužitelja u /data/hosts u postavkama AdAwaya.
    14. +
    15. AdAway bi sada trebao raditi.
    16. +
    + + diff --git a/app/src/main/res/raw-hu/help_faq.html b/app/src/main/res/raw-hu/help_faq.html new file mode 100644 index 0000000..c81cb21 --- /dev/null +++ b/app/src/main/res/raw-hu/help_faq.html @@ -0,0 +1,32 @@ + + + +GYIK + +

    Bevétel hirdetéseken keresztül

    +

    Van egy gyakran elhangzó félreértés mely szerint, ha amúgy se kattintanánk a reklámokra, akkor azzal se ártunk egy oldalnak vagy alkalmazásnak, ha meg se jelenítjük a reklámot. Ez nem igaz, mert a fejlesztők már azért is kaphatnak pénzt, hogy megjelenítik a hirdetést. Az csak a felhasználón múlik, hogy használ-e reklám blokkolót vagy nem.

    + +

    Hogy működik az AdAway?

    +

    Az AdAway hosts file segítségével blokkolja a reklámokat kiszolgáló hostneveket.. A hosts fájl a /system/etc/hosts könyvtárban található fájl, amely a gazdagépneveket IP-címekre térképezi fel. Hagyományos módszer a gazdanév IP-címpárokhoz történő definiálására anélkül, hogy a Domain Name Systemre (DNS) támaszkodna. Az összes nem kívánt gazdagépnév átirányításra kerül a 127.0.0.1 címre, ami azt jelenti, hogy a saját eszközre mutatnak.
    +Ha a gazdagépfájl nem írható, akkor egy tartalék megoldás a beépített VPN szolgáltatás használata. Szűri a kapcsolatokat a nem kívánt gazdagépnevekkel, és másokat is átenged.

    + +

    Miért kell újraindítani az Androidot, hogy a változások életbe lépjenek?

    +

    Java az Android rendszeren saját belső DNS tárat tart fenn. Az operációs rendszer azonnal használja az új hosts fájlt (ezt ellenőrizni is lehet pingeléssel), de a DNS cache tárának újraépítéséhez újra kell indítani az Androidot.

    + +

    Hogy kell használni a web kiszolgálót az AdAway-ben?

    +

    Az AdAway a web kiszolgáló használata nélkül is működni fog. +

    Engedélyezni lehet az AdAway beállításainál egy helyi web kiszolgálót , hogy válaszoljon a 127.0.0.1 helyi IP címre érkező kérésekre. Ez olyan kéréseket jelent, amelyeket alkalmazások kezdeményeztek a hirdetés kiszolgálójukhoz, de a 127.0.0.1 címre lettek átirányítva, így az AdAway válaszol ezekre a kérésekre. +
    Néhány alkalmazás nem hajlandó működni, ha a reklám kiszolgálóik nem érhető el. Ezzel a módszerrel újra elérhetőnek hiszi azt, és egy üres oldalt kapnak vissza.

    + +

    Hogyan tudok adott kiszolgálókat (hosts) blokkolni/engedélyezni?

    +

    Add hozzá a blokkolni kívánt hosztneveket a Blokolt listához akezdÅ‘lapról. Ezenkívül a blokkolásból kizárni kívánt gazdagépnevek hozzáadhatók a Megengedve és az adott IP-címre átirányítani kívánt hosztnevek a Ãtirányítvahelyhez.

    + +

    Hol találhatok további hosts forrásokat?

    +

    Tekintse meg az AdAwayhez való hosts fájlok forrásainak listáját!

    + +

    Segítsen fordítani/jelentsen hibákat

    +

    Keresse fel a https://adaway.org weboldalt!

    + + diff --git a/app/src/main/res/raw-hu/help_problems.html b/app/src/main/res/raw-hu/help_problems.html new file mode 100644 index 0000000..e334bbf --- /dev/null +++ b/app/src/main/res/raw-hu/help_problems.html @@ -0,0 +1,36 @@ + + + +Gyakori problémák + +

    A hosts fájl másolása nem sikerült Android 9 vagy újabb rendszeren

    +

    Az újabb Android verziókban a /system partíció csak-olvasható.
    +Ha Magisk-ot használ roothoz, nézzen utána, hogy bekapcsolta-e a systemless hosts modult, majd indítsa újra a készüléket.

    + +

    Nincs elég hely a partíción

    +

    Próbálja meg átállítani a cél hosts fájl elérési helyét a beállításokban /data/data/hosts-ra (vagy /data/hosts-ra) és alkalmazza az AdAway-t újra.

    + +

    Chrome továbbra is megjeleníti a hirdetéseket

    +

    Győződjön meg arról, hogy letiltotta az egyszerűsített módot (korábban adatforgalom csökkentés). Ez a funkció lehetővé teszi a Chrome számára a Chrome számára, hogy privát DNS megoldást használjon, és megkerülje az AdAway-t.

    + +

    Nem blokkolja a hirdetéseket XYZ alkalmazásban!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Gyorstárazott reklámok

    +

    Néhány alkalmazás gyorstárazza a reklámokat letöltés után. Ãgy reklámok maradhatnak egyes alkalmazásokban. Megpróbálhatja kitörölni ezen alkalmazások gyorstárát az Android Alkalmazások listájában, hogy ezek a reklámok is eltűnjenek.

    + +

    Az XYZ alkalmazás már nem működik!

    +

    Egyes alkalmazásoknak kommunikálniuk kell az AdAway által blokkolt hosztnévvel, vagy különben megtagadja a munkát, amikor a hosztnév, mely szolgáltatja a reklámokat, nem elérhető. Lásd 1https://github.com/AdAway/AdAway/wiki/ProblematicApps1, hogy tudomást szerezzen az összes problémás alkalmazásról. Ellenkező esetben ki kell tapasztalnia, hogy mely hosztneveket kell hozzáadni a Fehérlistáhoza Saját Listamenüpont alatt, majd jelentheti azAdAway bug tracker-jében.

    + +

    Nem működik Android 4.4 vagy újabb verziókon

    +

    Próbálja meg átállítani a cél hosts fájl elérési helyét a beállításokban /data/data/hosts-ról /data/hosts-ra vagy /system/etc/hosts-ra és alkalmazza az AdAway-t újra.

    + +

    A vissza gombok nem működnek a böngészőkben

    +

    Engedélyezheti az AdAway helyi webszerverét a beállításokban, a probléma megkerüléséhez.

    + + + diff --git a/app/src/main/res/raw-hu/help_s_on_s_off.html b/app/src/main/res/raw-hu/help_s_on_s_off.html new file mode 100644 index 0000000..1209ea7 --- /dev/null +++ b/app/src/main/res/raw-hu/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON kapcsoló súgó + +

    HTC eszközök

    +

    AdAway nem működik S-ON-t használó eszközön. Ez a 'képesség' számos HTC eszközön létezik, és megakadályozza az AdAway alkalmazást a hosts fájl írásában.

    + +

    S-ON/S-OFF?

    +

    Az S-OFF azt jelenti, hogy az eszköz NAND rész nem zárolt, és írható. A HTC eszközök alapértéke S-ON, ami azt jelenti, hogy a rendszer bizonyos részeit nem érheti el és nem lehet állandó root jogot adni. Továbbá a firmware aláírásának ellenőrzése is be van kapcsolva az S-ON jelző miatt.

    + +

    Nálam S-ON vagy S-OFF van?

    +

    Indítsd a készüléket Boot Menu-be a hangerő le gomb nyomva tartásával, miközben lenyomod a bekapcsoló gombot, és a felül lévő szöveg S-OFF vagy S-ON állapotot mutat. A teljes root általában S-OFF állapotot jelent. +

    Bővebb információ a következő oldalon található: www.addictivetips.com. További S-OFF módszerek, mivel az Unrevokable (linkben) érdekelhet, nevezetesen: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Kerülő megoldás

    +

    Előfeltétel: Telepítened kell egy működő Android SDK-t ADB shell-el a számítógépedre.

    +
      +
    1. Indítsd a készüléket Boot Menü-be a hangerő le gomb nyomva tartásával, miközben lenyomod a bekapcsoló gombot.
    2. +
    3. A hangerő le gombbal válaszd a recovery-t majd a bekapcsoló gomb az indításhoz.
    4. +
    5. A clockwork recovery-ben lépj a "partíciók menübe".
    6. +
    7. Válaszd ki ezeket: mount /system, mount /sdcard és mount /data.
    8. +
    9. Csatlakoztasd az USB kábelt, és nyiss egy parancssort a számítógépen.
    10. +
    11. adb shell és Enter majd írd be ln -s /data/hosts /system/etc/hosts (Ez létrehoz egy szimbolikus linket, ami lehetővé teszi az AdAway számára a /data helyen tárolt hosts fájlt szerkesztését, miközben azt az OS úgy használhatja, mintha a /systempartíció tárolná.)
    12. +
    13. Indítsd újra az eszközt és állítsd be a Cél hosts fájlt a /data/hosts helyre az AdAway beállításainál.
    14. +
    15. Az AdAway alkalmazásnak így már működnie kell.
    16. +
    + + diff --git a/app/src/main/res/raw-in/help_faq.html b/app/src/main/res/raw-in/help_faq.html new file mode 100644 index 0000000..4280767 --- /dev/null +++ b/app/src/main/res/raw-in/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Pendapatan dari iklan

    +

    Terdapat kesalahpahaman yang sering menyatakan bahwa jika pengguna tidak mengklik iklan, kemudian memblokirnya tidak akan merugikan keuangan situs atau aplikasi. Ini salah, pengembang juga memperoleh uang dengan hanya menampilkan iklan. Itu terserah kepada Anda apakah Anda memblokir iklan atau tidak. Secara pribadi saya tidak akan menggunakan aplikasi yang menampilkan iklan karena saya merasakan mereka sangatlah mengganggu, sehingga tanpa pemblokir iklan saya tidak akan memasang aplikasi tersebut.

    + +

    Bagaimana cara kerja AdAway?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Mengapa saya harus memulai ulang Android untuk mendapatkan perubahan?

    +

    Java pada Android mengelola DNS cache internalnya sendiri. Sistem operasi akan merefleksikan berkas host yang baru segera (memverifikasi dengan ping pada command line), tetapi Anda harus memulai kembali Android untuk membangun kembali cache DNS dari Java.

    + +

    Bagaimana menggunakan web server di AdAway?

    +

    AdAway juga akan bekerja tanpa menggunakan webserver! +

    Anda dapat mengaktifkan sebuah webserver lokal di preferensi dalam AdAway untuk menjawab permintaan dari alamat IP lokal 127.0.0.1. Ini adalah permintaan dari aplikasi ke server iklan yang akan diteruskan ke 127.0.0.1 yang dijawab oleh webserver AdAway. +
    Beberapa aplikasi menolak untuk bekerja, ketika server iklan tidak dapat dijangkau. Dengan metode ini mereka dapat dijangkau kembali, menjawab dengan sebuah laman kosong dan tidak ada gambar iklan.

    + +

    Bagaimana saya memblokir/membuka blokir hostname tertentu?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Di mana saya dapat menemukan lebih banyak sumber host?

    +

    Lihat Daftar sumber host tambahan untuk AdAway List of additional hosts sources for AdAway.

    + +

    Bantu menerjemahkan/melaporkan kesalahan

    +

    Silakan menuju https://adaway.org.

    + + diff --git a/app/src/main/res/raw-in/help_problems.html b/app/src/main/res/raw-in/help_problems.html new file mode 100644 index 0000000..14392ce --- /dev/null +++ b/app/src/main/res/raw-in/help_problems.html @@ -0,0 +1,36 @@ + + + +Masalah yang umum + +

    Penyalinan berkas hosts gagal pada Android 9+

    +

    Versi mutahir dari Android menggunakan hanya-baca /system partisi.
    +Jika Anda menggunakan Magisk sebagai solusi root, pastikan Anda mengaktifkan systemless modul hosts kemudian mulai ulang.

    + +

    Tidak cukup ruang pada partisi

    +

    Cobalah mengganti target berkas hosts di preferensi ke /data/data/hosts (or /data/hosts) dan terapkan AdAway lagi.

    + +

    Tidak dapat bekerja di Android 4.4+

    +

    Cobalah mengganti target berkas hosts di preferensi dari /data/data/hosts ke /data/hosts atau /system/etc/hosts dan terapkan AdAway lagi.

    + +

    iklan tidak dapat di blok pada aplikasi XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Iklan tembolok

    +

    Kadangkala aplikasimelakukan cache iklan setelah diunduh. Ini menyebabkan iklan yang tersisa pada beberapa aplikasi. Kamu bisa mencoba menghapus cache untuk aplikasi ini dalam daftar Aplikasi Android untuk menghindari masalah ini.

    + +

    Aplikasi XYZ tidak lagi berfungsi!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Tombol kembali pada web browser tidak berfungsi

    +

    Anda dapat mengaktifkan webserver lokal AdAway di preferensi sebagai solusi.

    + +

    Tombol kembali pada web browser tidak berfungsi

    +

    Anda dapat mengaktifkan webserver lokal AdAway di preferensi sebagai solusi.

    + + + diff --git a/app/src/main/res/raw-in/help_s_on_s_off.html b/app/src/main/res/raw-in/help_s_on_s_off.html new file mode 100644 index 0000000..40da9d0 --- /dev/null +++ b/app/src/main/res/raw-in/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    Perangkat HTC

    +

    AdAway tidak bekerja ketika Anda menggunakan perangkat dengan apa yang disebut S-ON. 'Fitur' ini ada pada banyak perangkat HTC dan mencegah AdAway menulis file host.

    + +

    S-ON/S-OFF?

    +

    S-OFF berarti bahwa bagian NAND pada perangkat tidak terkunci dan dapat ditulis. Pengaturan standar untuk perangkat HTC adalah S-ON, yang berarti bahwa tidak dapat mengakses area tertentu dari sistem juga tidak bisa menjamin root permanen. Selanjutnya, memeriksa tanda tangan untuk gambar firmware juga dijamin oleh S-ON flag.

    + +

    Apakah saya harus S-ON atau S-OFF?

    +

    Boot ke Menu Boot pada perangkat Anda dengan menekan tombol volume bawah sambil menekan tombol power dan keterangan di atas layar akan menampilkan status mungkin S-OFF atau S-ON. Sebuah root penuh umumnya bertanda S-OFF. +

    Informasi lebih lanjut dapat ditemukan di www.addictivetips.com. Metode S-OFF tambahan pada Unrevokable (di link) mungkin menarik bagi Anda, yaitu : Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Solusi

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Gunakan volume bawah untuk memilih recovery kemudian power untuk menghidupkan itu.
    4. +
    5. Di clockwork recovery pergi ke "menu partisi".
    6. +
    7. Pilih mount /system, mount /sdcard dan mount /data.
    8. +
    9. Masukkan kabel USBmu dan buka sebuah command line pada pcmu.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Mulai ulang perangkat dan tetapkan Target berkas hosts ke /data/hosts di preferensi AdAway.
    14. +
    15. AdAway seharusnya bekerja sekarang.
    16. +
    + + diff --git a/app/src/main/res/raw-is/help_faq.html b/app/src/main/res/raw-is/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-is/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-is/help_problems.html b/app/src/main/res/raw-is/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-is/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-is/help_s_on_s_off.html b/app/src/main/res/raw-is/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-is/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-it/help_faq.html b/app/src/main/res/raw-it/help_faq.html new file mode 100644 index 0000000..379de21 --- /dev/null +++ b/app/src/main/res/raw-it/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Guadagni dalle pubblicità

    +

    Esiste un malinteso diffuso sul fatto che se un utente non clicca mai sulle pubblicità, allora bloccarle non danneggia finanziariamente il sito o l'applicazione. Questo è errato: gli sviluppatori guadagnano denaro anche semplicemente mostrando le pubblicità. Spetta a te decidere se bloccare gli annunci o meno. Personalmente non utilizzerei applicazioni che mostrano annunci perché li trovo molto fastidiosi, quindi senza un programma per bloccare le pubblicità non installerei queste applicazioni.

    + +

    Come funziona AdAway?

    +

    AdAway usa il file hosts per bloccare hostnames che forniscono annunci. Il file hosts si trova in /system/etc/hosts e mappa gli hostnames in indirizzi IP. E' un modo per associare un indirizzo IP al suo hostname senza utilizzare il Domain Name System (DNS). Tutti gli hostnames non desiderati sono reindirizzati a 127.0.0.1, il che significa che punteranno al tuo dispositivo.
    +Se il file hosts non è scrivibile, una soluzione alternativa è utilizzare il servizio VPN. Potrà filtrare le connessioni non desiderate, facendo passare le altre.

    + +

    Perché devo riavviare Android per rendere effettivi i cambiamenti?

    +

    Java su Android ha la sua propria cache DNS interna. Il sistema operativo rispecchierà il nuovo file hosts immediatamente (verificalo con un ping tramite linea di comando) ma dovrai riavviare Android per ricostruire la cache DNS di Java.

    + +

    Come usare il web server in AdAway?

    +

    AdAway funziona anche senza usare il web server! +

    Puoi abilitare nelle preferenze di AdAway un web server locale per rispondere alle richieste tramite l'IP locale 127.0.0.1. Questo significa che le richieste dalle applicazioni ai server pubblicitari che vengono inoltrate verso 127.0.0.1 ricevono risposta dal web server di Adaway. +
    Alcune applicazioni infatti si rifiutano di funzionare quando i server pubblicitari non sono raggiungibili. Con questo metodo ritornano di nuovo raggiungibili, fornendo come risposta una pagina bianca e nessuna immagine pubblicitaria.

    + +

    Come posso bloccare/sbloccare specifici hostname?

    +

    Aggiungi gli hostname che vuoi bloccare alla lista Bloccati dalla schermata home. Inoltre, puoi aggiungere gli hostname che vuoi escludere dal blocco alla lista Autorizzati e gli hostname che vuoi reindirizzare ad un indirizzo IP personalizzato alla lista Reindirizzati.

    + +

    Dove posso trovare più sorgenti host?

    +

    Consulta la Lista delle sorgenti hosts aggiuntive per AdAway.

    + +

    Aiuta a tradurre/segnala bug

    +

    Visita https://adaway.org

    + + diff --git a/app/src/main/res/raw-it/help_problems.html b/app/src/main/res/raw-it/help_problems.html new file mode 100644 index 0000000..8c0db86 --- /dev/null +++ b/app/src/main/res/raw-it/help_problems.html @@ -0,0 +1,36 @@ + + + +Problemi comuni + +

    Copia del file hosts fallita su Android 9+

    +

    Le ultime versioni di Android hanno la partizione /system di sola lettura.
    +Se stai usando Magisk come root manager assicurati di aver attivato il modulo 'Systemless Hosts' e fai un reboot.

    + +

    Spazio insufficiente nella partizione

    +

    Prova a cambiare il percorso del file hosts nelle preferenze in /data/data/hosts (o /data/hosts) e applica di nuovo AdAway.

    + +

    Chrome continua a mostrare le pubblicità

    +

    Assicurati di disabilitare la modalità lite (precedentemente nota come risparmio dati) dalle impostazioni di Chrome. Questa opzione permette a Chrome di usare i DNS privati ed eludere AdAway.

    + +

    Non blocca le pubblicità nell'app XYZ!

    +

    Alcuni hostname potrebbero mancare nei file hosts forniti da Sorgenti host oppure l'applicazione dispone delle immagini per fornire annunci senza dover accedere a Internet.

    +Puoi registrare le richieste DNS (Menù->Log richieste DNS) da AdAway per scoprire quali hostname aggiuntivi devono essere bloccati. +

    Aggiungi gli hostnames sospetti alla tua Blacklist premendo a lungo le voci nel Log e segnala questi hostnames quando li hai verificati nel Forum Hosts Inbox di hosts-file.net.

    + +

    Pubblicità conservata nella cache

    +

    Alcune applicazioni conservano le pubblicità nella cache dopo il download. Questo fa sì che la pubblicità rimanga in alcune app. Provare ad eliminare la cache di queste applicazioni dalla Lista delle Applicazioni in impostazioni Android per risolvere questo problema.

    + +

    L'app XYZ non funziona più!

    +

    Alcune applicazioni devono comunicare con un hostname bloccato da AdAway o rifiutarsi di funzionare quando i nomi degli host, che dovrebbero pubblicare annunci, non sono raggiungibili. Consulta https://github.com/AdAway/AdAway/wiki/ProblematicAppsper ottenere un elenco di applicazioni note che hanno problemi. Altrimenti, scopri quali hostnames sono necessari e aggiungili alla tua Whitelist sotto Le tue listee segnalali al bug tracker di AdAway.

    + +

    Non funziona in Android 4.4+

    +

    Prova a cambiare il percorso del file hosts nelle preferenze da /data/data/hosts a /data/hosts o /system/etc/hosts e applica di nuovo AdAway.

    + +

    Il pulsante indietro nei browser non funziona

    +

    Abilitare il web server locale di AdAway nelle preferenze per aggirare il problema.

    + + + diff --git a/app/src/main/res/raw-it/help_s_on_s_off.html b/app/src/main/res/raw-it/help_s_on_s_off.html new file mode 100644 index 0000000..acd5b3c --- /dev/null +++ b/app/src/main/res/raw-it/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Aiuto riguardo S-ON + +

    Dispositivi HTC

    +

    AdAway non funziona se usi un dispositivo con il cosiddetto S-ON. Questa "caratteristica" è presente in molti dispositivi HTC e impedisce a AdAway di scrivere il file hosts.

    + +

    S-ON/S-OFF?

    +

    S-OFF significa che la porzione NAND del dispositivo è sbloccata e può essere scritta. L'impostazione predefinita nel dispositivi HTC è S-ON, il che significa che non si può né accedere a determinate aree del sistema, né puoi garantirti il root permanente. Inoltre, anche il controllo della firma per i firmware è assicurato dal flag S-ON.

    + +

    Ho S-ON o S-OFF?

    +

    Accedi al menu di avvio del tuo dispositivo tenendo premuto il pulsante volume giù mentre premi il pulsante di accensione e sul display in alto apparirà l'indicazione dello status come S-OFF o S-ON. Un root completo generalmente comporta S-OFF. +

    Puoi trovare altre informazioni su www.addictivetips.com. Ti potrebbero interessare altri metodi per lo S-OFF oltre Unrevokable (nel link): Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Soluzione

    +

    Prerequisito: installare una versione funzionante dell'SDK Android con shell ADB sul PC.

    +
      +
    1. Accedi al menù di avvio del tuo dispositivo tenendo premuto il pulsante volume giù mentre premi il pulsante di accensione.
    2. +
    3. Utilizza volume - per selezionare recovery quindi power per avviarlo.
    4. +
    5. Nella ClockWork Recovery andare al menu "partitions".
    6. +
    7. Seleziona mount /system, mount /sdcard e mount /data.
    8. +
    9. Collega il cavo USB e apri una riga di comando sul PC.
    10. +
    11. Entra nella shell adb e digita ln -s /data/hosts /system/etc/hosts (In questo modo si crea un link simbolico che consente ad AdAway di modificare il file hosts situato in /data, consentendo allo stesso tempo al sistema operativo di usare il medesimo file come se fosse situato in /system).
    12. +
    13. Riavvia il tuo dispositivo e imposta il Percorso file hosts in /data/hosts nelle preferenze di AdAway.
    14. +
    15. Ora AdAway dovrebbe funzionare.
    16. +
    + + diff --git a/app/src/main/res/raw-iw/help_faq.html b/app/src/main/res/raw-iw/help_faq.html new file mode 100644 index 0000000..01f4dd2 --- /dev/null +++ b/app/src/main/res/raw-iw/help_faq.html @@ -0,0 +1,32 @@ + + + +ש×לות ותשובות + +

    הכנסות על ידי פרסומות

    +

    יש תפיסה ×œ× × ×›×•× ×” ש×פליקציות / ×ž×¤×ª×—×™× / ××ª×¨×™× ×œ× ×™×¨×•×•×™×—×• כסף ×× ××ª× ×ª×©×ª×ž×© ×‘×—×•×¡× ×¤×¨×¡×•×ž×•×ª בגלל ×©×œ× ×ª×œ×—×¥ ×¢×œ×™×”× ×•×–×” ×œ× × ×›×•×Ÿ ×”× ×ž×¨×•×•×™×—×™× ×›×¡×£ ×’× ×¢×œ הצגת פרסומות ×œ× ×¨×§ על לחיצות

    + +

    ×יך AdAway עובד ?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    למה ×× ×™ צריך לעשות ריסט למכשיר בשביל ש AdAway תפעל

    +

    ×’'×ווה של ×נדרו×יד שומר DNS על ×”×§×ש המערכת תכתוב מחדש ×ת קובץ הרשימות ×חרי שתעשה ריסט למכשיר

    + +

    ×יך להשתמש בשרת ×ינטרנט ב AdAway ?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    ×יך ×× ×™ יכול ×œ×—×¡×•× / להוריד חסימה למסור ספציפי ?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    ×יפה ×× ×™ יכול ×œ×ž×¦×•× ×¢×•×“ מקורות של מ×רחי×?

    +

    ר×הרשימת מקורות לתוכנת AdAway.

    + +

    עזור בתרגו×/דיווח בעיות

    +

    בקר ב×תר https://adaway.org.

    + + diff --git a/app/src/main/res/raw-iw/help_problems.html b/app/src/main/res/raw-iw/help_problems.html new file mode 100644 index 0000000..5bfb42b --- /dev/null +++ b/app/src/main/res/raw-iw/help_problems.html @@ -0,0 +1,36 @@ + + + +תקלות נפוצות + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    ×ין מספיק זיכרון פנוי במחיצה

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    ×œ× ×¢×•×‘×“ ×¢× ×נדרו×יד 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    ×–×” ×œ× ×—×•×¡× ×¤×¨×¡×•×ž×•×ª ב×פליקציות XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    פרסומות בק×ש

    +

    ×œ×¤×¢×ž×™× ×”×¤×¨×¡×•×ž×•×ª נחסמו ×בל הפרסומות שכבר הורדו ×œ× ×™×—×¡×ž×• ×תה יכול למחוק ×ת זיכרון ×”×™×©×•× ×‘×ž× ×”×œ ×”×™×©×•×ž×™× ×©×œ המכשיר

    + +

    ×פליקציות XYZ ×œ× ×¢×•×‘×“×•×ª יותר!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    הכפתור חזרה ×ינו עובד בדפדפן

    +

    ×תה יכול להפעיל ×ת השרת המקומי של AdAway ב×פשרויות בתור פתרון זמני.

    + +

    הכפתור חזרה ×ינו עובד בדפדפן

    +

    ×תה יכול להפעיל ×ת השרת המקומי של AdAway ב×פשרויות בתור פתרון זמני.

    + + + diff --git a/app/src/main/res/raw-iw/help_s_on_s_off.html b/app/src/main/res/raw-iw/help_s_on_s_off.html new file mode 100644 index 0000000..eb5086f --- /dev/null +++ b/app/src/main/res/raw-iw/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    מכשירי HTC

    +

    AdAway ×œ× ×¢×•×‘×“ טוב ×¢× ×”×ž×›×©×™×¨ שלך בגלל משהו ×©× ×§×¨× S-ON / S-OFF ×–×” משהו ×©× ×ž×¦× ×‘×”×¨×‘×” ×ž×›×©×™×¨×™× ×©×œ HTC ×” S-ON מונע מAdAway ×œ×¨×©×•× ×§×•×‘×¥ HOST ובגלל ×–×” יכול להיות ש AdAway ×œ× ×™×¢×‘×•×“ טוב על מכשירך / ×œ× ×™×¢×‘×•×“ בכלל

    + +

    S-ON/S-OFF?

    +

    AdAway ×œ× ×¢×•×‘×“ טוב ×¢× ×”×ž×›×©×™×¨ שלך בגלל משהו ×©× ×§×¨× S-ON / S-OFF ×–×” משהו ×©× ×ž×¦× ×‘×”×¨×‘×” ×ž×›×©×™×¨×™× ×©×œ HTC ×” S-ON מונע מAdAway ×œ×¨×©×•× ×§×•×‘×¥ HOST ובגלל ×–×” יכול להיות ש AdAway ×œ× ×™×¢×‘×•×“ טוב על מכשירך / ×œ× ×™×¢×‘×•×“ בכלל

    + +

    יש לך תכונת S-ON ×ו S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    לעקיפת הבעיה

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway ×מור לעבוד עכשיו
    16. +
    + + diff --git a/app/src/main/res/raw-ja/help_faq.html b/app/src/main/res/raw-ja/help_faq.html new file mode 100644 index 0000000..f630596 --- /dev/null +++ b/app/src/main/res/raw-ja/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    広告ã‹ã‚‰ã®åŽå…¥

    +

    仕様ã§ã™ã€‚ファイルをダウンロードã—ã¦é©ç”¨ã—ãŸã¨ãã«æˆåŠŸã—ã¦ã„れã°ã€æ—¥æ™‚䏿˜Žã¨æ›¸ã‹ã‚Œã¦ã„ã¦ã‚‚åæ˜ ã•れã¦ã„ã¾ã™

    + +

    AdAwayã¯ã©ã†ã‚„ã£ã¦å‹•作ã—ã¦ã„ã‚‹ã®ï¼Ÿ

    +

    AdAwayã¯ã€hostsファイルを使用ã—ã¦ã€åºƒå‘Šã‚’é…ä¿¡ã™ã‚‹ãƒ›ã‚¹ãƒˆåをブロックã—ã¾ã™ã€‚hostsファイルã¯ã€/system/etc/hostsã«ã‚るファイルã§ã€ãƒ›ã‚¹ãƒˆåã‚’IPアドレスã«ãƒžãƒƒãƒ”ングã—ã¾ã™ã€‚ã“れã¯ã€ãƒ‰ãƒ¡ã‚¤ãƒ³ãƒãƒ¼ãƒ ã‚·ã‚¹ãƒ†ãƒ ï¼ˆDNS)ã«é ¼ã‚‰ãšã«ã€ãƒ›ã‚¹ãƒˆåã¨IPアドレスã®ãƒšã‚¢ã‚’定義ã™ã‚‹ä¼çµ±çš„ãªæ–¹æ³•ã§ã™ã€‚ä¸è¦ãªãƒ›ã‚¹ãƒˆåã¯ã™ã¹ã¦127.0.0.1ã«ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã•れã€è‡ªåˆ†ã®ãƒ‡ãƒã‚¤ã‚¹ã‚’指ã™ã“ã¨ã«ãªã‚Šã¾ã™ã€‚
    +hostsãƒ•ã‚¡ã‚¤ãƒ«ãŒæ›¸ãè¾¼ã‚ãªã„å ´åˆã¯ã€å†…蔵ã®VPNサービスを利用ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ä¸è¦ãªãƒ›ã‚¹ãƒˆåã¸ã®æŽ¥ç¶šã¯ãƒ•ィルタリングã•れã€ãã®ä»–ã®ãƒ›ã‚¹ãƒˆåã¯ã‚¹ãƒ«ãƒ¼ã•れã¾ã™ã€‚

    + +

    ãªãœå†èµ·å‹•ã—ãªã„ã¨å¤‰æ›´ãŒé©ç”¨ã•れãªã„ã®ï¼Ÿ

    +

    Androidã®å†…部DNSキャッシュã®ã›ã„ã§ã™ã€‚OSã¯hostsファイルをã™ãã«å映ã—ã¾ã™ãŒ(コマンドラインã§ç¢ºèªã§ãã¾ã™)DNSキャッシュã®å†æ§‹æˆã«å†èµ·å‹•ãŒå¿…è¦ã§ã™

    + +

    ウェブサーãƒãƒ¼ã¯ã©ã†ã‚„ã£ã¦ä½¿ã†ã®ï¼Ÿ

    +

    AdAwayã¯Webサーãƒãƒ¼ã‚’使用ã›ãšã«ã‚‚動作ã—ã¾ã™ï¼ +

    AdAwayã®ç’°å¢ƒè¨­å®šã§ãƒ­ãƒ¼ã‚«ãƒ«Webサーãƒã‚’有効ã«ã—ã¦ã€ãƒ­ãƒ¼ã‚«ãƒ«IPアドレス127.0.0.1ã¸ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ç­”ãˆã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ ã“れã¯ã€127.0.0.1ã«ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã•れる広告サーãƒãƒ¼ã¸ã®ã‚¢ãƒ—リã‹ã‚‰ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒã€AdAwayã®Webサーãƒãƒ¼ã«ã‚ˆã£ã¦å¿œç­”ã•れるã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚ +
    一部ã®ã‚¢ãƒ—リã§ã¯ã€åºƒå‘Šã‚µãƒ¼ãƒãƒ¼ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ããªã„å ´åˆã¯å‹•作ã—ã¾ã›ã‚“。 ã“ã®æ–¹æ³•ã§ã¯ã€å†ã³ç©ºç™½ã®ãƒšãƒ¼ã‚¸ã¨åºƒå‘Šç”»åƒã§è¡¨ç¤ºã—ã¾ã™

    + +

    特定ã®ãƒ›ã‚¹ãƒˆåをブロック/アンブロックã™ã‚‹ã«ã¯ã©ã†ã—ãŸã‚‰ã„ã„?

    +

    ホーム画é¢ã§ã€ãƒ–ロックã—ãŸã„ホストãƒãƒ¼ãƒ ã‚’ã€Œç¦æ­¢ã€ãƒªã‚¹ãƒˆã«è¿½åŠ ã—ã¾ã™ã€‚ã¾ãŸã€ãƒ–ロックã‹ã‚‰é™¤å¤–ã—ãŸã„ホストåã¯ã€Œè¨±å¯ã€ã«ã€ç‰¹å®šã®IPアドレスã«ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã—ãŸã„ホストåã¯ã€Œè»¢é€ã€ã«å±žã—ã¾ã™ã€‚

    + +

    hostsファイルã¯ã©ã“ã§è¦‹ã¤ã‘られる?

    +

    AdAwayã®ãƒ›ã‚¹ãƒˆã‚½ãƒ¼ã‚¹ã®ãƒªã‚¹ãƒˆè¿½åŠ ã‚’å‚ç…§ã—ã¦ãã ã•ã„

    + +

    ç¿»è¨³ã®æ‰‹ä¼ã„/ãƒã‚°å ±å‘Š

    +

    https://adaway.orgã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ãã ã•ã„

    + + diff --git a/app/src/main/res/raw-ja/help_problems.html b/app/src/main/res/raw-ja/help_problems.html new file mode 100644 index 0000000..4332860 --- /dev/null +++ b/app/src/main/res/raw-ja/help_problems.html @@ -0,0 +1,35 @@ + + + +一般的ãªå•題 + +

    Android 9以é™ã§hostsファイルã®ã‚³ãƒ”ーã«å¤±æ•—ã™ã‚‹

    +

    最新版ã®Androidã¯ã€/systemパーティションãŒèª­ã¿å–ã‚Šå°‚ç”¨ã§æ‰±ã‚れã¾ã™ã€‚
    +Magiskを使用ã—ã¦ã„ã‚‹å ´åˆã¯ã€Systemless hostsモジュールを有効ã«ã—ã¦ã‹ã‚‰å†èµ·å‹•ã—ã¦ãã ã•ã„。

    + +

    領域ã«å分ãªå®¹é‡ãŒã‚りã¾ã›ã‚“

    +

    環境設定ã®ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒ›ã‚¹ãƒˆãƒ•ァイルを/data/data/hosts(ã¾ãŸã¯/data/hosts)ã«å¤‰æ›´ã—ã€å†åº¦AdAwayã‚’é©ç”¨ã—ã¦ã¿ã¦ãã ã•ã„

    + +

    Android 4.4以é™ã§å‹•作ã—ã¾ã›ã‚“

    +

    環境設定ã®ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒ›ã‚¹ãƒˆãƒ•ァイルを/data/data/hostsã‹ã‚‰/data/hostsã¾ãŸã¯/system/etc/hostsã«å¤‰æ›´ã—ã€å†åº¦AdAwayã‚’é©ç”¨ã—ã¦ã¿ã¦ãã ã•ã„

    + +

    ã‚ã®ã‚¢ãƒ—リã®åºƒå‘Šã‚’ブロックã—ã¦ãれãªã„!

    +

    一部ã®ãƒ›ã‚¹ãƒˆåã¯ã€æä¾›ã•れ㟠hostsソースã‹ã‚‰æ¼ã‚Œã¦ã„ãŸã‚Šã€ç”»åƒã‚’åŒæ¢±ã—ã¦ã„ã¦ãƒãƒƒãƒˆæŽ¥ç¶šãªã—ã«åºƒå‘Šã‚’表示ã™ã‚‹å ´åˆãŒã‚ã‚‹ã§ã—ょã†ã€‚

    DNSè¦æ±‚をログã«è¨˜éŒ²ã™ã‚‹(メニュー→DNSè¦æ±‚を記録ã™ã‚‹)ã“ã¨ã§ã€ãƒ–ロックã™ã¹ãホストåãŒã‚ã‹ã‚Šã¾ã™ã€‚ +

    怪ã—ã’ãªãƒ›ã‚¹ãƒˆåã¯ã€ãƒ­ã‚°é …目上ã§é•·æŠ¼ã—ã™ã‚‹ã¨ãƒ–ラックリストã«è¿½åŠ å‡ºæ¥ã¾ã™ã€‚確èªãŒå–れãŸã‚‰hosts-file.netã®Hosts Inboxフォーラムã«å ±å‘Šã—ã¦ãã ã•ã„。

    + +

    キャッシュã•れãŸåºƒå‘Š

    +

    アプリã«ã¯ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ãŸåºƒå‘Šãƒ‡ãƒ¼ã‚¿ã‚’キャッシュã™ã‚‹ã‚‚ã®ãŒã‚りã¾ã™ã€‚ã“れã«ã‚ˆã‚Šä¸€éƒ¨ã®ã‚¢ãƒ—リã§ã¯åºƒå‘ŠãŒæ®‹ã‚Šã¾ã™ã€‚ã“ã®å•題を回é¿ã™ã‚‹ã«ã¯ã€Androidã®ã‚¢ãƒ—リ一覧ã§ã‚¢ãƒ—リã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’削除ã—ã¦ã¿ã¦ãã ã•ã„。

    + +

    ã‚ã®ã‚¢ãƒ—リãŒå‹•作ã—ãªã„!

    +

    一部ã®ã‚¢ãƒ—リã¯ã€AdAwayã«ã‚ˆã£ã¦ãƒ–ロックã•れã¦ã„るホストåã¨é€šä¿¡ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‚‚ã®ã®ã€åºƒå‘Šã‚’é…ä¿¡ã™ã‚‹ã¯ãšã®ãƒ›ã‚¹ãƒˆåã«åˆ°é”ã§ããªã„å ´åˆã¯ã€å‹•作をやã‚ã¦ã—ã¾ã„ã¾ã™ã€‚ 既知ã®å•題ã®ã‚るアプリã®ãƒªã‚¹ãƒˆã‚’入手ã™ã‚‹ã«ã¯ã€https://github.com/AdAway/AdAway/wiki/ProblematicAppsã‚’å‚ç…§ã—ã¦ãã ã•ã„。 ãれ以外ã®å ´åˆã¯ã€å¿…è¦ãªãƒ›ã‚¹ãƒˆåを見ã¤ã‘ã¦ã€ã‚ãªãŸã®ãƒªã‚¹ãƒˆã®ãƒ›ãƒ¯ã‚¤ãƒˆãƒªã‚¹ãƒˆã«è¿½åŠ ã—ã¦ã€AdAwayã®ãƒã‚°ãƒˆãƒ©ãƒƒã‚«ãƒ¼ã«å ±å‘Šã—ã¦ãã ã•ã„。

    + +

    ãƒ–ãƒ©ã‚¦ã‚¶å†…ã®æˆ»ã‚‹ãƒœã‚¿ãƒ³ãŒå‹•作ã—ãªã„!

    +

    AdAwayã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚¦ã‚§ãƒ–サーãƒãƒ¼ã‚’è¨­å®šã§æœ‰åйã«ã—ã¦ãã ã•ã„。

    + +

    ãƒ–ãƒ©ã‚¦ã‚¶å†…ã®æˆ»ã‚‹ãƒœã‚¿ãƒ³ãŒå‹•作ã—ãªã„!

    +

    AdAwayã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚¦ã‚§ãƒ–サーãƒãƒ¼ã‚’è¨­å®šã§æœ‰åйã«ã—ã¦ãã ã•ã„。

    + + + diff --git a/app/src/main/res/raw-ja/help_s_on_s_off.html b/app/src/main/res/raw-ja/help_s_on_s_off.html new file mode 100644 index 0000000..9faae98 --- /dev/null +++ b/app/src/main/res/raw-ja/help_s_on_s_off.html @@ -0,0 +1,33 @@ + + + +S-ON 関連ヘルプ + +

    HTC製デãƒã‚¤ã‚¹

    +

    S-ONã¨å‘¼ã°ã‚Œã‚‹ãƒ‡ãƒã‚¤ã‚¹ã§ã¯AdAwayã¯å‹•作ã—ã¾ã›ã‚“。ã“ã®'機能'ã¯å¤šãã®HTC製デãƒã‚¤ã‚¹ã«ã‚りhostsãƒ•ã‚¡ã‚¤ãƒ«ã®æ›¸ãè¾¼ã¿ã‚’ã§ããªãã•ã›ã¾ã™ã€‚

    + +

    S-ON/S-OFF?

    +

    S-OFFã¨ã¯ãƒ‡ãƒã‚¤ã‚¹ã®NANDã‚’ã‚¢ãƒ³ãƒ­ãƒƒã‚¯ã—æ›¸ãè¾¼ã‚るよã†ã«ã™ã‚‹ã“ã¨ã§ã™ã€‚HTC製デãƒã‚¤ã‚¹ã®ãƒ‡ãƒ•ォルト設定ã¯S-ONã§ã‚·ã‚¹ãƒ†ãƒ ã®ã‚るエリアã«ã‚¢ã‚¯ã‚»ã‚¹å‡ºæ¥ãªã‹ã£ãŸã‚Šå¸¸æ™‚rootã«ã§ãã¾ã›ã‚“。(日本ã§ã¯ã‚·ãƒ£ãƒ¼ãƒ—製もåŒã˜ã‚ˆã†ãªçŠ¶æ…‹ã§ã™)

    + +

    ç§ã®ãƒ‡ãƒã‚¤ã‚¹ã«ã¯S-ONã‚„S-OFFãŒã‚りã¾ã™ã‹?

    +

    é›»æºãƒœã‚¿ãƒ³ã‚’押ã—ãªãŒã‚‰ãƒœãƒªãƒ¥ãƒ¼ãƒ ãƒ€ã‚¦ãƒ³ãƒœã‚¿ãƒ³ã‚’押ã—ç¶šã‘ã‚‹ã¨ã€ãƒ‡ãƒã‚¤ã‚¹ã®ãƒ–ートメニューãŒè¡¨ç¤ºã•れã€ä¸Šéƒ¨ã®ãƒ†ã‚­ã‚¹ãƒˆã«ãƒ•ラグステータスãŒS-OFFã¾ãŸã¯S-ONã®ã„ãšã‚Œã‹ã«è¡¨ç¤ºã•れã¾ã™ã€‚ フルRootã¨ã¯ã€ä¸€èˆ¬ã«S-OFFã‚’æ„味ã—ã¾ã™ã€‚
    +詳細ã¯www.addictivetips.comã‚’ã”覧ãã ã•ã„。
    Unrevokable(リンク先)ã‹ã‚‰ã€Revolutionaryã€Revoneã€Firewaterã€RumRunnerã€Moonshineã€SunShineãªã©èˆˆå‘³æ·±ã„追加S-OFFãƒ¡ã‚½ãƒƒãƒ‰ãŒæœ‰ã‚Šã¾ã™

    + +

    å›žé¿æ–¹æ³•

    +

    å‰æï¼š PCã« ADB シェルãŒä»˜å±žã™ã‚‹ Android SDK をインストールã—ã¦ãŠãå¿…è¦ãŒã‚りã¾ã™ã€‚

    +
      +
    1. é›»æºãƒœã‚¿ãƒ³ã‚’押ã—ãªãŒã‚‰éŸ³é‡ä½Žä¸‹ãƒœã‚¿ãƒ³ã‚’押ã—ã¦ã€ãƒ‡ãƒã‚¤ã‚¹ã®ãƒ–ートメニューを起動ã—ã¾ã™ã€‚
    2. +
    3. +音é‡ä½Žä¸‹ãƒœã‚¿ãƒ³ を使用ã—㦠recovery ã‚’é¸ã³ é›»æºãƒœã‚¿ãƒ³ ã§èµ·å‹•ã—ã¾ã™ã€‚
    4. +
    5. Clockwork リカãƒãƒªãƒ¼ã§ã¯ "partitions menu" ã«é€²ã‚“ã§ãã ã•ã„。
    6. +
    7. +mount /systemã€mount /sdcardã€mount /dataã‚’é¸æŠžã—ã¾ã™
    8. +
    9. USBケーブルを差ã—込ん㧠PC ã§ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³ã‚’ç«‹ã¡ä¸Šã’ã¦ãã ã•ã„。
    10. +
    11. adbシェルを入力ã—ã€ln -s /data/hosts /system/etc/hostsã¨å…¥åŠ›ã—ã¾ã™ï¼ˆã“れã«ã‚ˆã‚Šã‚·ãƒ³ãƒœãƒªãƒƒã‚¯ãƒªãƒ³ã‚¯ãŒä½œæˆã•れã€AdAwayã¯/dataã«æ ¼ç´ã—ã€OSã¯/systemã«æ ¼ç´ã•れã¦ã„ã‚‹ã‹ã®ã‚ˆã†ã«ãƒ•ァイルを使用出æ¥ã¾ã™ï¼‰
    12. +
    13. デãƒã‚¤ã‚¹ã‚’å†èµ·å‹•ã—ã€AdAwayã®è¨­å®šã§Target hostsファイルを/data/hostsã«è¨­å®šã—ã¾ã™
    14. +
    15. AdAwayãŒå‹•作ã™ã‚‹ã¯ãšã§ã™ã€‚
    16. +
    + + diff --git a/app/src/main/res/raw-km/help_faq.html b/app/src/main/res/raw-km/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-km/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-km/help_problems.html b/app/src/main/res/raw-km/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-km/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-km/help_s_on_s_off.html b/app/src/main/res/raw-km/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-km/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-ko/help_faq.html b/app/src/main/res/raw-ko/help_faq.html new file mode 100644 index 0000000..9b3edc2 --- /dev/null +++ b/app/src/main/res/raw-ko/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    ê´‘ê³  수ìµ

    +

    ìžì£¼ 언급ë˜ëŠ” 오해 중 하나는 사용ìžê°€ 광고를 절대로 í´ë¦­í•˜ì§€ 않거나 차단할 경우, 사ì´íŠ¸ë‚˜ ì•±ì— ê¸ˆì „ì ì¸ 피해가 ìžˆì„ ê²ƒì´ë¼ëŠ” 것입니다. ì´ê±´ ê±°ì§“ì´ë©°, 개발ìžë“¤ì€ 광고를 단순히 표시함으로 ëˆì„ 법니다. ê´‘ê³  차단 여부는 ì—¬ëŸ¬ë¶„ì˜ ì„ íƒìž…니다. ê°œì¸ì ìœ¼ë¡œ 저는 광고를 표시하는 ì•±ì´ ë§¤ìš° 성가셔서 사용하지 않습니다. 그래서 ê´‘ê³  차단기 ì—†ì´ëŠ” ì´ëŸ° ê´‘ê³ ê°€ 표시ë˜ëŠ” ì•±ë“¤ì„ ì„¤ì¹˜í•˜ì§€ ì•Šì„ ê²ƒìž…ë‹ˆë‹¤.

    + +

    AdAway는 어떻게 ìž‘ë™í•©ë‹ˆê¹Œ?

    +

    AdAway는 호스트 파ì¼ì„ ì´ìš©í•˜ì—¬ 광고를 제공하는 호스트ì´ë¦„ì„ ì°¨ë‹¨í•©ë‹ˆë‹¤. 호스트 파ì¼ì€ í˜¸ìŠ¤íŠ¸ëª…ì„ IP ì£¼ì†Œì— ë§¤í•‘í•˜ëŠ” /system/etc/hostsì— ìžˆìŠµë‹ˆë‹¤. ë„ë©”ì¸ ë„¤ìž„ 시스템(DNS)ì— ì˜ì¡´í•˜ì§€ 않고 호스트 ì´ë¦„ì„ IP 주소로 ì •ì˜í•˜ëŠ” 전통ì ì¸ 방법입니다. 모든 ì›ì¹˜ 않는 호스트ì´ë¦„ì€ 127.0.0.1로 리다ì´ë ‰íЏ ë˜ë©°, ì´ëŠ” 해당 호스트 ì´ë¦„ì´ ì‚¬ìš©ìž ìž¥ì¹˜ë¡œ 가리킨다는 ê²ƒì„ ì˜ë¯¸ìž…니다.
    +호스트 파ì¼ì´ 쓰기가 안ë˜ëŠ” 경우, 예비 ì†”ë£¨ì…˜ì€ ë‚´ìž¥ëœ VPN 서비스를 사용하는 것입니다. ì›í•˜ì§€ 않는 호스트 ì´ë¦„ì— ëŒ€í•œ ì—°ê²°ì„ í•„í„°ë§í•˜ê³  다른 호스트가 통과할 수 있ë„ë¡ í•©ë‹ˆë‹¤.

    + +

    변경 ì‚¬í•­ì„ ì ìš©í•˜ë ¤ë©´ 왜 안드로ì´ë“œë¥¼ 재부팅해야 합니까?

    +

    안드로ì´ë“œì˜ ìžë°”는 ìžì²´ ë‚´ë¶€ DNS ìºì‹œë¥¼ 유지합니다. ìš´ì˜ì²´ì œëŠ” 새로운 호스트 파ì¼ì„ 즉시 ë°˜ì˜(명령어 줄ì—서 í•‘ì„ í†µí•´ ê²€ì¦)하지만 ìžë°”ì˜ DNS ìºì‹œë¥¼ 재구성하려면 안드로ì´ë“œë¥¼ 재시작하셔야 합니다.

    + +

    AdAwayì—서 웹서버를 어떻게 사용합니까?

    +

    AdAway는 웹서버를 사용하지 ì•Šê³ ë„ ìž‘ë™í•©ë‹ˆë‹¤! +

    AdAwayì˜ í™˜ê²½ 설정ì—서 로컬 웹서버를 활성화하여 로컬 IP 주소 127.0.0.1 ìš”ì²­ì— ì‘답할 수 있습니다. 즉, 앱ì—서 광고서버로 127.0.0.1로 리다ì´ë ‰íŠ¸ëœ ìš”ì²­ì€ AdAwayì˜ ì›¹ì„œë²„ë¡œ 대신 ì‘ë‹µì„ í•´ì¤ë‹ˆë‹¤. +
    ì¼ë¶€ 앱ì—서는 ê´‘ê³  ì„œë²„ì— ì—°ê²°í•  수 ì—†ì„ ë•Œ ìž‘ë™ì„ 거부할 수 있습니다. ì´ ë°©ë²•ì„ ì‚¬ìš©í•˜ë©´ ê´‘ê³  ì„œë²„ì— ë‹¤ì‹œ ì—°ê²° í•  수 있으며, ê´‘ê³  ì´ë¯¸ì§€ê°€ 없는 빈 페ì´ì§€ë¡œ 회신합니다.

    + +

    특정 í˜¸ìŠ¤íŠ¸ëª…ì„ ì–´ë–»ê²Œ 차단/차단해제합니까?

    +

    í™ˆí™”ë©´ì— ìžˆëŠ” 차단 ë¨ ëª©ë¡ì—서 차단하고 ì‹¶ì€ í˜¸ìŠ¤íŠ¸ ì´ë¦„ì„ ì¶”ê°€í•©ë‹ˆë‹¤. 추가ì ìœ¼ë¡œ 차단ì—서 제외할 호스트 ì´ë¦„ì„ í—ˆìš© ë¨ì— 추가할 수 있으며 특정 IP 주소로 리다ì´ë ‰íŠ¸í•  호스트 ì´ë¦„ì„ ë¦¬ë‹¤ì´ë ‰íЏ ë¨ì— 추가할 수 있습니다.

    + +

    ë” ë§Žì€ í˜¸ìŠ¤íŠ¸ 소스는 어디서 ì°¾ì„ ìˆ˜ 있습니까?

    +

    AdAwayì˜ ì¶”ê°€ 호스트 소스 목ë¡ì„ 확ì¸í•˜ì‹­ì‹œì˜¤.

    + +

    번역 ë•기/버그 ë³´ê³ 

    +

    https://adaway.org로 와 주시기 ë°”ëžë‹ˆë‹¤.

    + + diff --git a/app/src/main/res/raw-ko/help_problems.html b/app/src/main/res/raw-ko/help_problems.html new file mode 100644 index 0000000..44badaf --- /dev/null +++ b/app/src/main/res/raw-ko/help_problems.html @@ -0,0 +1,36 @@ + + + +공통 문제 + +

    안드로ì´ë“œ 9 ì´ìƒì˜ 환경ì—서 호스트 íŒŒì¼ ë³µì‚¬ì— ì‹¤íŒ¨ë©ë‹ˆë‹¤

    +

    ìµœì‹ ë²„ì „ì˜ ì•ˆë“œë¡œì´ë“œëŠ” /system íŒŒí‹°ì…˜ì„ ì½ê¸° 모드만 사용하게 ë˜ì–´ì¡ŒìŠµë‹ˆë‹¤.
    +만약 ë£¨íŒ…ì„ Magisk로 하셨다면, 시스템 없는 호스트 ëª¨ë“ˆì„ ì‚¬ìš©í•˜ë„ë¡ ì„¤ì •í•œ ë‹¤ìŒ ìž¬ë¶€íŒ…í•˜ì‹­ì‹œì˜¤.

    + +

    파티션 공간 부족

    +

    환경설정ì—서 ëŒ€ìƒ í˜¸ìŠ¤íŠ¸ 파ì¼ì„ /data/data/hosts (í˜¹ì€ /data/hosts)로 변경한 후 AdAway를 다시 ì ìš©í•˜ì‹­ì‹œì˜¤.

    + +

    Chromeì—서 여전히 ê´‘ê³ ê°€ 나옵니다

    +

    Chrome 설정ì—서 ë¼ì´íЏ 모드(ì´ì „ì—는 ë°ì´í„° 세ì´ë²„로 명칭 ë¨)ê°€ 비활성화 ë˜ì–´ìžˆëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤. Chromeì€ ì´ ê¸°ëŠ¥ì„ í†µí•´ ì „ìš© DNS ì†”ë£¨ì…˜ì„ ì‚¬ìš©í•˜ê³  AdAway를 우회할 수 있습니다.

    + +

    XYZ 앱ì—서는 광고를 차단하지 않습니다!

    +

    ì¼ë¶€ 호스트 ì´ë¦„ì€ í˜¸ìŠ¤íŠ¸ 소스ì—서 ì¼ë¶€ 호스트 ì´ë¦„ì´ ëˆ„ë½ë  수 있거나 í˜¹ì€ ì‘ìš© í”„ë¡œê·¸ëž¨ì´ ì¸í„°ë„·ì— 액세스하지 않고 광고를 제공하기 위해 ì´ë¯¸ì§€ë§Œ 사용했ì„ì§€ë„ ëª¨ë¦…ë‹ˆë‹¤.

    +AdAwayì—서 DNS 요청(메뉴->Log DNS 요청)ì„ ë¡œê¹…í•˜ì—¬ 차단해야 하는 추가 호스트 ì´ë¦„ì„ í™•ì¸í•  수 있습니다. +

    ë¡œê·¸ì˜ í•­ëª©ì„ ê¸¸ê²Œ 눌러 ì˜ì‹¬ìŠ¤ëŸ¬ìš´ 호스트 ì´ë¦„ì„ ê°œì¸ ë¸”ëž™ë¦¬ìŠ¤íŠ¸ì— ì¶”ê°€í•˜ê³  GitHub 문제 ì¶”ì ê¸°ì—서 확ì¸í•œ 후 ì´ í˜¸ìŠ¤íŠ¸ ì´ë¦„ì„ ë³´ê³ í•˜ì‹­ì‹œì˜¤.

    + +

    ìºì‹œëœ ê´‘ê³ 

    +

    간혹 ì•±ì´ ë‹¤ìš´ë¡œë“œ ì´í›„ 광고를 ìºì‹±í•©ë‹ˆë‹¤. ì´ë¡œ ì¸í•´ ì¼ë¶€ ì•±ì— ê´‘ê³ ê°€ 잔존하게 ë©ë‹ˆë‹¤. ì´ ë¬¸ì œë¥¼ 피하려면 안드로ì´ë“œì˜ 앱 목ë¡ì—서 해당 ì•±ì˜ ìºì‹œë¥¼ 삭제를 시ë„해보십시오.

    + +

    XYZ ì•±ì€ ë” ì´ìƒ ìž‘ë™í•˜ì§€ 않습니다!

    +

    ì¼ë¶€ ì‘ìš©í”„ë¡œê·¸ëž¨ë“¤ì€ ê´‘ê³ ë¥¼ 제공해야 하는 í˜¸ìŠ¤íŠ¸ì— ì—°ê²°í•  수 ì—†ì„ ë•Œ AdAwayì— ì˜í•´ 차단ë˜ê±°ë‚˜ ìž‘ë™ì„ 거부하는 호스트와 통신해야 합니다. 문제가 있는 알려진 ì‘ìš© 프로그램 목ë¡ì„ 확ì¸í•˜ë ¤ë©´ https://github.com/AdAway/AdAway/wiki/ProblematicAppsì—서 참조하십시오. 아니면, 필요한 호스트 ì´ë¦„ì„ ì°¾ì•„ ì‚¬ìš©ìž ëª©ë¡ì— 있는 í™”ì´íŠ¸ë¦¬ìŠ¤íŠ¸ì— ì¶”ê°€í•œ 후 AdAway 버그 íŠ¸ëž˜ì»¤ì— ë³´ê³ í•˜ì‹­ì‹œì˜¤.

    + +

    안드로ì´ë“œ 4.4 ì´ìƒì—서는 ìž‘ë™í•˜ì§€ 않ìŒ

    +

    환경설정ì—서 ëŒ€ìƒ í˜¸ìŠ¤íŠ¸ 파ì¼ì„ /data/data/hosts ì—서 /data/hosts í˜¹ì€ /system/etc/hosts 으로 변경한 후 AdAway를 다시 ì ìš©í•˜ì‹­ì‹œì˜¤.

    + +

    웹 브ë¼ìš°ì €ì—서 뒤로 가기 ë²„íŠ¼ì´ ìž‘ë™í•˜ì§€ 않ìŒ

    +

    í•´ê²° 방법으로 환경 설정ì—서 AdAwayì˜ ë¡œì»¬ 서버를 활성화 í•  수 있습니다.

    + + + diff --git a/app/src/main/res/raw-ko/help_s_on_s_off.html b/app/src/main/res/raw-ko/help_s_on_s_off.html new file mode 100644 index 0000000..330c4f1 --- /dev/null +++ b/app/src/main/res/raw-ko/help_s_on_s_off.html @@ -0,0 +1,33 @@ + + + +S-ON 관련 ë„ì›€ë§ + +

    HTC 장치

    +

    AdAway는 S-ONì´ë¼ 불리는 ê¸°ëŠ¥ì„ íƒ‘ìž¬í•œ 기기를 사용 시 ìž‘ë™í•˜ì§€ 않습니다. ì´ '기능'ì€ ë‹¤ìˆ˜ì˜ HTC ê¸°ê¸°ì— ì¡´ìž¬í•˜ë©° AdAwayê°€ 호스트 íŒŒì¼ ì“°ê¸°ë¥¼ 차단합니다.

    + +

    S-ON/S-OFF?

    +

    S-OFF는 NAND ì˜ì—­ì´ 잠금 í•´ì œë˜ì—ˆê³  쓰기가 ê°€ëŠ¥í•¨ì„ ì˜ë¯¸í•©ë‹ˆë‹¤. 기본 ì„¤ì •ì€ S-ONì´ë©°, ì´ëŠ” ì‹œìŠ¤í…œì˜ íŠ¹ì • ì˜ì—­ì— 대한 ì ‘ê·¼ì´ ë¶ˆê°€í•˜ê³  ì˜êµ¬ì ì¸ ë£¨íŒ…ì„ ë³´ìž¥í•  수 없다는 ì˜ë¯¸ìž…니다. 게다가 펌웨어 ì´ë¯¸ì§€ì˜ 서명 í™•ì¸ ë˜í•œ S-ON í”Œëž˜ê·¸ì— ì˜í•´ ê²€ì¦ë©ë‹ˆë‹¤.

    + +

    S-ON ë˜ëŠ” S-OFF 중 어떻게 설정ë˜ì–´ 있습니까?

    +

    부팅메뉴 화면으로 ì „í™˜ë  ë•Œê¹Œì§€ ì „ì› ë²„íŠ¼ 누름과 ë™ì‹œì— 볼륨 아래 ë²„íŠ¼ì„ ëˆ„ë¦…ë‹ˆë‹¤. ìƒë‹¨ì— 있는 í…스트가 S-OFF ë˜ëŠ” S-ON로 ìƒíƒœë¥¼ 표시가 ë˜ëŠ”ë°, 완전 ê¶Œí•œì„ ì–»ì€ ë£¨íŒ…ì€ ë³´í†µ S-OFF를 ì˜ë¯¸í•©ë‹ˆë‹¤. +

    ìžì„¸í•œ ë‚´ìš©ì€ www.addictivetips.comì—서 확ì¸í•  수 있습니다. 복구가 불가능하기 때문ì—(ë§í¬ 참조) ì´ì™¸ì˜ S-OFF ë°©ë²•ì— ê´€ì‹¬ ìžˆì„ ìˆ˜ 있습니다. 예를 들어: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    해결 방법

    +

    필수 구성 요소: ADB shell로 ìž‘ë™í•˜ëŠ” 안드로ì´ë“œ SDK를 PCì— ì„¤ì¹˜ë˜ì–´ 있어야 합니다.

    +
      +
    1. 부팅메뉴 화면으로 ì „í™˜ë  ë•Œê¹Œì§€ ì „ì› ë²„íŠ¼ 누름과 ë™ì‹œì— 볼륨 아래 ë²„íŠ¼ì„ ëˆ„ë¦…ë‹ˆë‹¤.
    2. +
    3. +볼륨 아래를 사용하여 recovery를 ì„ íƒí•©ë‹ˆë‹¤. 그러고 난 ë’¤ì— power ì„ íƒ í›„ 부팅합니다.
    4. +
    5. clockwork 리커버리ì—서 "partitions menu"로 ì´ë™í•˜ì‹­ì‹œì˜¤.
    6. +
    7. +mount /system, mount /sdcard 그리고 mount /data ì„ íƒí•˜ì‹­ì‹œì˜¤.
    8. +
    9. USB 단ìžë¥¼ 연결하고 ì—°ê²°ëœ PCì—서 명령프롬프트를 실행하십시오.
    10. +
    11. adb shell 진입한 ë’¤ ln -s /data/hosts /system/etc/hosts를 입력하십시오. (AdAwayê°€ /dataì— ì €ìž¥ëœ í˜¸ìŠ¤íŠ¸ 파ì¼ì„ 편집과 ë™ì‹œì— ìš´ì˜ì²´ì œê°€ /systemì— ì €ìž¥ëœ ê²ƒì²˜ëŸ¼ 파ì¼ì„ 사용할 수 있는 심볼릭ë§í¬ë¥¼ ìƒì„±í•©ë‹ˆë‹¤.)
    12. +
    13. 기기를 재부팅하고 AdAwayì˜ í™˜ê²½ì„¤ì •ì—서 ëŒ€ìƒ í˜¸ìŠ¤íŠ¸ 파ì¼ì„ /data/hosts로 설정하십시오.
    14. +
    15. ì´ì œ AdAwayê°€ ìž‘ë™í•  것입니다.
    16. +
    + + diff --git a/app/src/main/res/raw-ku/help_faq.html b/app/src/main/res/raw-ku/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-ku/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ku/help_problems.html b/app/src/main/res/raw-ku/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-ku/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-ku/help_s_on_s_off.html b/app/src/main/res/raw-ku/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-ku/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-lt/help_faq.html b/app/src/main/res/raw-lt/help_faq.html new file mode 100644 index 0000000..6f095f9 --- /dev/null +++ b/app/src/main/res/raw-lt/help_faq.html @@ -0,0 +1,32 @@ + + + +DUK + +

    Alga iš reklamų

    +

    Egzistuoja vienas nesusipratimas, jog jeigu vartotojas niekada nespaudžia ant reklamu, tada jas užblokavus niekuom nepakenks svetainÄ—s ar programos kÅ«rejui finansiÅ¡kai. Tai yra netiesa, kÅ«rÄ—jai taip pat uždirba vien už reklamos peržiÅ«ras. AÅ¡ asmeniÅ¡kai niekada nenaudoÄiau programų kurios rodo reklamas, man tai labai įkyru, tad be reklamos blokuotojo aÅ¡ nenaudoÄiau tų programų.

    + +

    Kaip veikia AdAway?

    +

    AdAway naudoja Domeno hosts failą kad galėtų blokuoti reklamų domenus. Hosts failas yra /system/etc/hosts kuris nukreipia domenus į jų IP adresus. Tai yra tradiciškas būdas juos nukreipti nenaudojant DNS sistemos. Visi nenorimi domenai yra nukreipiami 127.0.0.1 tai reiškia kad jie eis per jūsų įrenginį.
    +Jei domeno failas nėra redaguojamas, kitas sprendimas yra naudoti įdiegtą VPN funkciją. Ji filtruos nenorimus sujungimus su domenais o kitus praleis.

    + +

    Kodėl aš turiu perkrauti Android įrenginį kad įsigaliotų pakeitimai?

    +

    Java, Android platformoje palaiko savo vidinį DNS slėptuvėje cahce. Operatyvioji sistema pritaiko nauja domeno hosts failą iš karto (patvirtina tai su ping atsako komanda) bet jums reikės perkrauti Android įrenginį kad būtų rekonstruojama Java DNS saugykla.

    + +

    Kaip naudoti web serverį su AdAway?

    +

    AdAway veiks ir nenaudojant web serverio! +

    Jūs galite įjungti lokalų web serverį AdAway nustatymuose kuris atsakys į lokalių IP adresą127.0.0.1. Tai reiškia kad užklausos iš aplikacijų į reklamų serverius kurios bus nukreiptos į 127.0.0.1 bus filtruojamos AdAway web serverio. +
    Kai kurios aplikacijos atsisako veikti kada reklamos serveris yra nepasiekiamas. Su Å¡iuo metodu jos vÄ—l veiks, taÄiau atsakys su tuÅ¡Äiu puslapiu, be reklamos ir be reklamos nuotraukos.

    + +

    Kaip aš galiu užblokuoti/atblokuoti specifinius domeno adresus?

    +

    Pridėkite domenų adresus kuriuos jūs norite blokuoti į Užblokuoti sąrašą iš namų ekrano. Papildomai, domenų adresai kuriuos jūs norite išskirti iš blokavimo gali būti pridėti Leidžiami ir domenų adresai kuriuos norite nukreipti į specifišką IP adresą priklauso Nukreipti.

    + +

    Kur aš galiu rasti daugiau host šaltinių?

    +

    Žiūrėkite Sąrašas papildomų domenų šaltinių skirtų AdAway.

    + +

    Padėkite išversti/praneškite apie klaidas

    +

    Pereikite į https://adaway.org.

    + + diff --git a/app/src/main/res/raw-lt/help_problems.html b/app/src/main/res/raw-lt/help_problems.html new file mode 100644 index 0000000..af76b4f --- /dev/null +++ b/app/src/main/res/raw-lt/help_problems.html @@ -0,0 +1,36 @@ + + + +PagrindinÄ—s problemos + +

    Hosts file kopijavimas nepavyko Android 9+

    +

    Paskiausios Android versijos nauja tik skaitomÄ… /system particijÄ….
    +Jei naudojate Magisk kaip root sprendimą, įsitikinkite kad įjungėte ne sisteminį domeno hosts modulį ir perkovėte.

    + +

    Neužtenka laisvos vietos jūsų pasirinktoje atmintyje

    +

    Pabandykite pakeisti hosts failą nustatymuose į /data/data/hosts (arba /data/hosts) ir įjungkite AdAway vėl.

    + +

    Chrome vistiek rodo reklamas

    +

    Išjungkite lengvajį lite rėžimą (dar žinomą kaip duomenų mažinimą) iš Chrome nustatymų. Ši funkcija leidžia Chrome naudoti privatų DNS serverį ir apeiti AdAway.

    + +

    Man neblokuoja reklamu AYZ programoje!

    +

    Kai kurie domeno adresai gali būti trūkti pateiktų hosts failų iš Hosts domeno šaltininiai arba applikacijos sujungė nuotraukas kad pateiktų reklamas be interneto prieigos

    +Jūs galite įrašyti DNS užklausas (Menu-->Log DNS Užklausos) su AdAway kad matytumėte kokie papildomi domeno adresai gali būti blokuojami. +

    Pridėkite įtariamus domeno adresus į jūsų Juodąjį sąrašą ilgai palaikydami įvedimus Įrašuose Log ir praneškite šiuos adresus kai juos patvirtinote mūsų GitHub probelmų sekėjas issue tracker.

    + +

    Reklamos laikinoje atmintyje

    +

    Kartais aplikacijos išsaugo reklamas po atsisiuntimo. Tai lemia likusias reklamas kai kuriose aplikacijose. Jūs galite bandyti ištrinti saugyklas cache šioms aplikacijoms Android applikacijų saraše kad apeiti šią problemą.

    + +

    Programa AYZ nebeveikia!

    +

    Kai kurios programos privalo komunikuoti su domenų adresais kurie yra blokuojami AdAway arba atsisako veikti kai reklamų naudojami adresai yra nepasiekiami. Žiūrėti https://github.com/AdAway/AdAway/wiki/ProblematicApps kad gautumėte sąrašą žinomų aplikacijų kurios turi problemų. Kitu atvėju, atraskite kurie adresai reikalingi ir juos pridėkite į savo Baltajį sąrašą kurie randasi Jūsų Sarašai ir pateikite juos AdAway klaidų sekėjas.

    + +

    Neveikia ant Android 4.4+

    +

    Pabandykite pakeisti taikomą hosts failą nustatymuose, iš /data/data/hosts į /data/hosts arba /system/etc/hosts ir įjungkite AdAway iš naujo.

    + +

    Naršyklėje mygtukas Atgal neveikia

    +

    Jūs galite įjungti AdAway lokalų web serverį nustatymuose kaip apėjimą.

    + + + diff --git a/app/src/main/res/raw-lt/help_s_on_s_off.html b/app/src/main/res/raw-lt/help_s_on_s_off.html new file mode 100644 index 0000000..90c97ff --- /dev/null +++ b/app/src/main/res/raw-lt/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Prietaisai

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Ar aš turiu S-ON arba S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    ApÄ—jimas

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-ml/help_faq.html b/app/src/main/res/raw-ml/help_faq.html new file mode 100644 index 0000000..a171942 --- /dev/null +++ b/app/src/main/res/raw-ml/help_faq.html @@ -0,0 +1,32 @@ + + + +പതിവàµà´šàµ‡à´¾à´¦àµà´¯à´™àµà´™àµ¾ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ml/help_problems.html b/app/src/main/res/raw-ml/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-ml/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-ml/help_s_on_s_off.html b/app/src/main/res/raw-ml/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-ml/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-ms/help_faq.html b/app/src/main/res/raw-ms/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-ms/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ms/help_problems.html b/app/src/main/res/raw-ms/help_problems.html new file mode 100644 index 0000000..b4d45e9 --- /dev/null +++ b/app/src/main/res/raw-ms/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Chrome still displays ads

    +

    Ensure you disable lite mode (previously known as data saver) from Chrome settings. This features allows Chrome to use private DNS solution and bypass AdAway.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in our GitHub issue tracker.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-ms/help_s_on_s_off.html b/app/src/main/res/raw-ms/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-ms/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-my/help_faq.html b/app/src/main/res/raw-my/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-my/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-my/help_problems.html b/app/src/main/res/raw-my/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-my/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-my/help_s_on_s_off.html b/app/src/main/res/raw-my/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-my/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-nb-rNO/help_faq.html b/app/src/main/res/raw-nb-rNO/help_faq.html new file mode 100644 index 0000000..f0f190f --- /dev/null +++ b/app/src/main/res/raw-nb-rNO/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Inntekt gjennom reklamer

    +

    Det er en ofte sagt misoppfatning at dersom en bruker aldri klikker på reklamer, vil det å blokkere dem ikke skade et nettsted eller app finansielt. Dette er feil, utviklere tjener også penger bare ved å vise reklamer. Det er opp til deg om du vil blokkere reklamer eller ikke. Selv ville jeg ikke brukt reklamer som viser reklamer fordi jeg anser dem for å være veldig irriterende, så uten en reklameblokkerer ville jeg ikke installert de appene.

    + +

    Hvordan virker AdAway?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Hvorfor må jeg starte Android på nytt for at endringene skal bli tatt i bruk?

    +

    Java på Android vedlikeholder sitt eget interne DNS-mellomlager. Operativsystemet vil gjenspeile den nye vertsfilen umiddelbart (Dobbeltsjekk det med ping i ledeteksten), men du vil måtte starte Android på nytt for å bygge opp DNS-mellomlageret til Java på nytt.

    + +

    Hvordan bruker man nettjeneren i AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    Hvordan kan jeg blokkere/ublokkere spesifikke vertsnavn?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Hvor kan jeg finne flere vertsfilkilder?

    +

    Se Liste over ytterligere vertskilder for AdAway.

    + +

    Hjelp til med å oversette og å melde i fra om bugs

    +

    Vennligst gå til https://adaway.org/.

    + + diff --git a/app/src/main/res/raw-nb-rNO/help_problems.html b/app/src/main/res/raw-nb-rNO/help_problems.html new file mode 100644 index 0000000..a06fbcc --- /dev/null +++ b/app/src/main/res/raw-nb-rNO/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Ikke nok plass på partisjonen

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Virker ikke på Android ≥4.4

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    Den blokkerer ikke reklamer i ____-appen!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Mellomlagrede reklamer

    +

    Noen ganger mellomlagrer apper reklamer etter nedlasting. Dette fører til at reklamer blir igjen i noen apper. Du kan prøve å slette mellomlageret til disse appene i Android sin appliste for å omgå dette problemet.

    + +

    _____-appen virker ikke lengre!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Tilbake-knappen i nettlesere virker ikke

    +

    Du kan skru på AdAway sin lokal nettjener i innstillingene som en nødløsning.

    + +

    Tilbake-knappen i nettlesere virker ikke

    +

    Du kan skru på AdAway sin lokal nettjener i innstillingene som en nødløsning.

    + + + diff --git a/app/src/main/res/raw-nb-rNO/help_s_on_s_off.html b/app/src/main/res/raw-nb-rNO/help_s_on_s_off.html new file mode 100644 index 0000000..9a24e71 --- /dev/null +++ b/app/src/main/res/raw-nb-rNO/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC-enheter

    +

    AdAway virker ikke når du bruker en enhet som har en såkalt S-ON. Denne "funksjonen" finnes på mange HTC-enheter og hindrer AdAway fra å skrive til vertsfilen.

    + +

    S-ON/S-OFF?

    +

    S-OFF betyr at NAND-området i enheten din er låst opp og at den kan bli skrevet til. Standardinnstillingen for HTC-enheter er S-ON, som betyr at du hverken kan få tilgang til bestemte områder i systemet eller å garantere for en permanent rooting. I tillegg er signatursjekker for systemoppdateringer også avhengige av S-ON-flagget.

    + +

    Har jeg S-ON eller S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Nødløsning

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway burde virke nå.
    16. +
    + + diff --git a/app/src/main/res/raw-ne/help_faq.html b/app/src/main/res/raw-ne/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-ne/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ne/help_problems.html b/app/src/main/res/raw-ne/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-ne/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-ne/help_s_on_s_off.html b/app/src/main/res/raw-ne/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-ne/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-nl/help_faq.html b/app/src/main/res/raw-nl/help_faq.html new file mode 100644 index 0000000..aaea30c --- /dev/null +++ b/app/src/main/res/raw-nl/help_faq.html @@ -0,0 +1,32 @@ + + + +VGV + +

    Inkomsten via reclames

    +

    Er is een vaak voorkomende misvatting dat als een gebruiker nooit op reclames klikt, het blokkeren van deze reclames een site of app financieel niet schaad. Dit klopt niet, aangezien ontwikkelaars ook geld verdienen door het alleen tonen van reclames. Het is aan u of u deze wel of niet blokkeert. Persoonlijk zou ik applicaties die reclames tonen niet gebruiken, omdat ik deze hinderlijk vind, dus zonder adblocker zou ik deze applicaties niet eens installeren.

    + +

    Hoe werkt AdAway?

    +

    AdAway gebruikt het hosts bestandom hostnamen te blokkeren die reclames aanbieden. Het hosts-bestand is een bestand in /system/etc/hosts Het zet hostnamen om naar IP-adressen. Het is een veelgebruikte manier om hostnamen naar IP-adressen om te leiden zonder het Domain Name System (DNS) te gebruiken. Alle ongewenste hostnamen worden doorverwezen naar 127.0.0.1.Dit betekent dat ze naar uw eigen apparaat verwijzen.
    +Als het host bestand niet kan worden weggeschreven, dan is de ingebouwde VPN service een alternatieve oplossing. Dit zal connecties naar ongewenste host namen filteren en zal anderen door laten gaan.

    + +

    Waarom moet ik Android herstarten om veranderingen effect te laten hebben?

    +

    Java op Android houd zijn eigen interne DNS-cache bij. Het besturingssysteem zal het nieuwe hosts-bestand meteen gebruiken (controleer dit met ping via de command line), maar u zult Android opnieuw moeten opstarten om de DNS-cache van Java opnieuw op te bouwen.

    + +

    Hoe gebruik ik de webserver in AdAway?

    +

    AdAway zal ook werken zonder het gebruik van de webserver! +

    U kunt een lokale webserver inschakelen vanuit de voorkeuren van AdAway om verzoeken te om te leiden naar het lokale IP-adres 127.0.0.1. Dit betekent dat verzoeken van applicaties aan reclameservers die doorverwezen worden naar 127.0.0.1 beantwoord worden door de webserver van AdAway. +
    Sommige applicaties weigeren te werken als reclameservers niet bereikbaar zijn. Met deze methode zullen de servers weer 'bereikbaar' zijn, alleen wordt er geen reclame maar een witte pagina weergegeven.

    + +

    Hoe kan ik specifieke hostnamen (de)blokkeren?

    +

    Voeg de hostnamen die u wilt blokkeren toe aan de Blokkeer lijst van het homescreen. Daarnaast kunt u ook hostnamen die u wilt uitzonderenn van blokkeren toevoegen aan de Toegestane lijst en hostnamen die u wilt doorverwijzen naar een specifiek IP-adres toevoegen aan Doorverwijzing lijst.

    + +

    Waar kan ik meer hosts-bronnen vinden?

    +

    Zie deze lijst van andere hosts-bronnen voor AdAway.

    + +

    Help vertalen of meld een fout

    +

    Ga naar https://adaway.org.

    + + diff --git a/app/src/main/res/raw-nl/help_problems.html b/app/src/main/res/raw-nl/help_problems.html new file mode 100644 index 0000000..b5add3e --- /dev/null +++ b/app/src/main/res/raw-nl/help_problems.html @@ -0,0 +1,36 @@ + + + +Veel voorkomende problemen + +

    Kopieren van het hosts bestand mislukt onder Android 9+

    +

    De laatste versies van Android maken gebruik van read-only /system partitie.
    +Als je Magisk gebruikt als root oplossing, zorg er dan voor dat je de systemless hosts module inschakelt en dan opnieuw opstart.

    + +

    Niet genoeg ruimte op partitie

    +

    Probeer de gekozen locatie van het hosts-bestand in de voorkeuren te veranderen naar /data/data/hosts (of /data/hosts) en pas AdAway opnieuw toe.

    + +

    Werkt niet op Android 4.4 en hoger

    +

    Zorg ervoor dat je de lite mode (voorheen data saver) uitschakelt in de Chrome settings. Deze functionaliteit zorgt ervoor dat Chrome de prive DNS oplossing gebruikt en AdAway negeert.

    + +

    AdAway blokkeert geen reclames in applicatie XYZ!

    +

    Some hostnamen kunnen ontbreken in de standaard hosts files van de Hosts bronnen of the applicatie heeft de afbeeldingen gebundeld om advertenties te laten zien zonder internettoegang.

    +U kan DNS verzoeken (Menu->Log DNS Requests) van AdAway loggen om uit te zoeken welke aanvullende bronnen zouden moeten worden geblockt. +

    Voeg de verdachte hostnamen toe aan uw eigen zwarte lijst door de regels in het logbestand lang aan te raken en rapporteer deze hostnamen als ze bevestigd zijn op het forum Hosts Inbox of hosts-file.net.

    + +

    Reclames uit cache

    +

    Soms plaatsen applicaties reclames in hun cache na de download. Dit zorgt ervoor dat er soms reclames in apps achterblijven. U kunt proberen de cache van deze applicaties te verwijderen vanuit de lijst met apps om dit probleem te omzeilen.

    + +

    Applicatie XYZ werkt niet meer!

    +

    Sommige applicaties moeten communiceren met een hostnaam die geblokkeerd is door AdAway en weigeren te werken wanneer de hostnamen die de advertenties doorgeven niet bereikbaar zijn. Zie https://github.com/AdAway/AdAway/wiki/ProblematicApps voor een lijst met bekende apps die deze problemen hebben. U kunt proberen uit te zoeken welke hostnamen nodig zijn en deze toevoegen aan uw witte lijst onder de optie Uw lijsten, en ze melden op de bugtracker van AdAway.

    + +

    De terugknop in webbrowsers werkt niet

    +

    U kunt AdAway's lokale webserver in de voorkeuren inschakelen als een tijdelijke oplossing.

    + +

    De terugknop in webbrowsers werkt niet

    +

    U kunt AdAway's lokale webserver in de voorkeuren inschakelen als een tijdelijke oplossing.

    + + + diff --git a/app/src/main/res/raw-nl/help_s_on_s_off.html b/app/src/main/res/raw-nl/help_s_on_s_off.html new file mode 100644 index 0000000..2d268c5 --- /dev/null +++ b/app/src/main/res/raw-nl/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON-gerelateerde hulp + +

    HTC-apparaten

    +

    AdAway werkt niet als u een apparaat gebruikt met zogenaamde S-ON. Deze 'functie' bestaat op veel HTC-apparaten en voorkomt dat AdAway het hosts-bestand kan bewerken.

    + +

    S-ON/S-OFF?

    +

    S-OFF betekend dat het NAND-gedeelte van het apparaat is vrijgegeven en dat ernaar geschreven kan worden. De standaard instelling op HTC-apparaten is S-ON, wat betekend dat sommige gedeelten van het systeem niet benaderd kunnen worden en dat een permanente root niet gegarandeerd kan worden. Verder is de handtekeningscontrole voor firmware updates ook geforceerd door S-ON.

    + +

    Heb ik S-ON of S-OFF?

    +

    Start op in het Boot Menu op uw apparaat door het ingedrukt houden van volume down knop samen met de power knop. De tekst bovenaan zal de status S-OFF of S-ON aangeven. Een volledige oor toegang betekent in het algemeen S-OFF. +

    Meer informatie kan worden gevonden op www.addictivetips.com. U kunt wellicht geïnteresseerd zijn in andere methodes om S-OFF te krijgen naast Unrevokable (zie link), namelijk: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine...

    + +

    Tijdelijke oplossing

    +

    Vereiste: U moet een werkende Android SDK met ADB shell installeren op uw computer.

    +
      +
    1. Kom in het opstartmenu op uw apparaat door tegelijk de onderste volumeknop ingedrukt te houden en de power knop terwijl u uw apparaat opstart.
    2. +
    3. Kom in het opstartmenu op uw apparaat door tegelijk de onderste volumeknop ingedrukt te houden en de power knop terwijl u uw apparaat opstart.
    4. +
    5. In clockwork recovery ga naar "partitions menu".
    6. +
    7. Selecteer mount /system, mount /sdcard en mount /data.
    8. +
    9. Sluit je USB-kabel aan en open een terminalvenster/opdrachtprompt op je computer.
    10. +
    11. Start de adb shell en type ln -s /data/hosts /system/etc/hosts (Dit maakt een symbolische string aan die het AdAway mogelijk maakt om de the hosts file te bewerken opgeslagen in /data en ondertussen het OS het bestand te laten gebruiken alsof het zich bevindt in /system.)
    12. +
    13. Herstart uw apparaat en selecteer Doel hosta bestand op /data/hosts in de voorkeuren van AdAway's.
    14. +
    15. AdAway zou nu moeten werken.
    16. +
    + + diff --git a/app/src/main/res/raw-no/help_faq.html b/app/src/main/res/raw-no/help_faq.html new file mode 100644 index 0000000..8cff1fc --- /dev/null +++ b/app/src/main/res/raw-no/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Reklamefinansiering

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-no/help_problems.html b/app/src/main/res/raw-no/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-no/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-no/help_s_on_s_off.html b/app/src/main/res/raw-no/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-no/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-pa/help_faq.html b/app/src/main/res/raw-pa/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-pa/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-pa/help_problems.html b/app/src/main/res/raw-pa/help_problems.html new file mode 100644 index 0000000..b4d45e9 --- /dev/null +++ b/app/src/main/res/raw-pa/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Chrome still displays ads

    +

    Ensure you disable lite mode (previously known as data saver) from Chrome settings. This features allows Chrome to use private DNS solution and bypass AdAway.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in our GitHub issue tracker.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-pa/help_s_on_s_off.html b/app/src/main/res/raw-pa/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-pa/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-pl/help_faq.html b/app/src/main/res/raw-pl/help_faq.html new file mode 100644 index 0000000..660a8ae --- /dev/null +++ b/app/src/main/res/raw-pl/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Dochód z reklam

    +

    Istnieje mylne przekonanie, że jeśli użytkownik nie klika na reklamy, to zablokowanie ich nie naraża autora programu na straty finansowe. Jest to nieprawdą, gdyż deweloperzy zarabiają również poprzez samo wyświetlanie reklam. Do Ciebie należy decyzja czy blokować je czy nie. +Osobiście (autor) nie korzystałbym z aplikacji, które wyświetlają reklamy, ponieważ uważam je za bardzo denerwujące. Tak więc bez blokera reklam nie zainstalowałbym tych aplikacji.

    + +

    Jak działa AdAway?

    +

    AdAway używa pliku hosts do blokowania nazw hostów, które wyświetlają reklamy. Plik hosts jest plikiem znajdującym się w /system/etc/hosts, który mapuje nazwy hostów na adresy IP. Jest to tradycyjny sposób definiowania nazw hostów na pary IP bez polegania na systemie Domain Name System (DNS). Wszystkie niechciane nazwy hostów są przekierowywane do 127.0.0.1, co oznacza, że ​​wskażą na twoje własne urządzenie.
    Jeżeli plik hosts nie jest zapisywalny, zapasowym rozwiązaniem jest użycie wbudowanego VPN. Przefiltruje połączenia do niechcianych nazw hostów i pozwoli pozostałym przejść.

    + +

    Dlaczego powinienem zrestartować system Android, aby zmiany przyniosły efekt?

    +

    Java w Androidzie utrzymuje własną wewnętrzną podręczną pamięć DNS. System operacyjny od razu wykryje nowy plik hosts (możesz to sprawdzić poleceniem ping w wierszu poleceń). Konieczny będzie jednak restart systemu Android w celu odbudowy pamięci podręcznej DNS Javy.

    + +

    Jak użyć lokalnego serwera www w AdAway?

    +

    AdAway będzie działać również bez korzystania z serwera www! +

    Możesz włączyć lokalny serwer www w preferencjach AdAway, aby odbierać żądania do lokalnego adresu IP 127.0.0.1. Oznacza to, że żądania od aplikacji do serwerów reklamowych, które są przekierowywane do 127.0.0.1, są odbierane przez serwer AdAway. +
    Niektóre aplikacje nie działają, gdy serwery reklam są niedostępne. Dzięki tej metodzie będą ponownie dostępne, odpowiadając pustą stroną i bez reklam.

    + +

    Jak mogę zablokować/odblokować określone nazwy hostów?

    +

    Dodaj nazwy hostów, które chcesz zablokować do listyZablokowanych w swoich listach. Ponadto nazwy hostów, które chcesz wykluczyć z blokowania, można dodać do Dozwolonych, a nazwy hostów, które chcesz przekierować do określonego adresu IP, do Przekierowanych.

    + +

    Gdzie znajdę wiecej źródeł hostów?

    +

    Zobacz: Lista dodatkowych plików hosts dla AdAway.

    + +

    Pomóż przetłumaczyć/zgłoś błędy

    +

    Przejdź na stronę https://adaway.org.

    + + diff --git a/app/src/main/res/raw-pl/help_problems.html b/app/src/main/res/raw-pl/help_problems.html new file mode 100644 index 0000000..dda8b66 --- /dev/null +++ b/app/src/main/res/raw-pl/help_problems.html @@ -0,0 +1,36 @@ + + + +Typowe problemy + +

    Kopiowanie pliku hosts nie powiodło się na Androidzie 9+

    +

    Najnowsze wersje Androida używają partycji /system jako tylko do odczytu.
    +Jeśli używasz Magisk jako roota, upewnij się, że włączyłeś bezsystemowy moduł hostów, a następnie uruchom ponownie.

    + +

    Brak wystarczajÄ…cego miejsca na partycji

    +

    Spróbuj zmienić docelowy plik hosts w preferencjach na /data/data/hosts (lub /data/hosts) i ponownie zastosuj AdAway.

    + +

    Nie działa na systemie Android 4.4+

    +

    Spróbuj zmienić docelowy plik hosts w preferencjach z /data/data/hosts na /data/hosts lub /system/etc/hosts i ponownie zastosuj AdAway.

    + +

    Nie blokuje reklam w aplikacji XYZ!

    +

    Niektóre nazwy hostów mogą być niedostępne w dostarczonych plikach hostów ze źródeł hostów lub aplikacja zawiera załączone treści, aby wyświetlać reklamy bez dostępu do internetu.

    +Możesz rejestrować żądania DNS (Menu->Rejestruj żądania DNS) od AdAway, aby dowiedzieć się, które dodatkowe nazwy hostów muszą być blokowane. +

    Dodaj podejrzane nazwy hostów do swojej Czarnej listy przez długie naciśnięcie wpisów w dzienniku i zgłoś te nazwy hostów po ich zweryfikowaniu w temacie Hosts Inbox na forum hosts-file.net.

    + +

    Reklamy buforowane

    +

    Zdarza się, że aplikacje cachują reklamy po pobraniu. Prowadzi to do tego, że pomimo blokowania, reklamy nadal są wyświetlane w niektórych aplikacjach. W celu usunięcia problemu możesz spróbować usunąć pamięć podręczną tych aplikacji.

    + +

    Aplikacja XYZ nie działa teraz prawidłowo!

    +

    Niektóre aplikacje muszą komunikować się z nazwą hosta zablokowaną przez AdAway lub odmówić pracy, gdy nazwy hostów, które powinny wyświetlać reklamy, są niedostępne. Zobacz https://github.com/AdAway/AdAway/wiki/ProblematicApps aby uzyskać listę znanych aplikacji, które mają problemy. W przeciwnym razie sprawdź, które nazwy hostów są potrzebne i dodaj je do Białej listy pod Twoimi listami i zgłoś je do modułu śledzenia błędów AdAway.

    + +

    Nie działa przycisk Wstecz w przeglądarkach internetowych

    +

    Możesz włączyć w opcjach lokalny serwer www jako tymczasowe rozwiązanie problemu.

    + +

    Nie działa przycisk Wstecz w przeglądarkach internetowych

    +

    Możesz włączyć w opcjach lokalny serwer www jako tymczasowe rozwiązanie problemu.

    + + + diff --git a/app/src/main/res/raw-pl/help_s_on_s_off.html b/app/src/main/res/raw-pl/help_s_on_s_off.html new file mode 100644 index 0000000..dc24988 --- /dev/null +++ b/app/src/main/res/raw-pl/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Pomoc zwiÄ…zana z S-ON + +

    UrzÄ…dzenia HTC

    +

    AdAway nie działa, gdy używasz urządzeń z funkcją zwaną S-ON. 'Funkcja' ta występuje w wielu urządzeniach HTC i zabrania aplikacji AdAway nadpisywania pliku hosts.

    + +

    S-ON/S-OFF?

    +

    S-OFF oznacza, że fragment pamięci NAND urządzenia jest odblokowany i może zostać zapisany. Domyślne ustawienie dla urządzeń HTC to S-ON, co oznacza, że ani nie można uzyskać dostępu do niektórych części systemu, ani nie można zagwarantować trwałego roota. Dodatkowo flaga S-ON implikuje sprawdzanie podpisu wgrywanego firmware'u.

    + +

    Mam S-ON czy S-OFF?

    +

    Uruchom urządzenie w trybie menu rozruchu, przytrzymując przycisk zmniejszania głośności i naciskając przycisk zasilania, a tekst na górze pokaże status flagi jako S-OFF lub S-ON. Pełny root na ogół oznacza S-OFF. +

    Więcej informacji można znaleźć na stronie www.addictivetips.com. Dodatkowe metody S-OFF od Unrevokable (w linku) mogą Cię zainteresować, a mianowicie: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Obejście problemu

    +

    Wymóg: Musisz zainstalować w komputerze działający Android SDK zawierający powłokę ADB (wiersz poleceń ADB).

    +
      +
    1. Uruchom w menu rozruchowym urządzenia, przytrzymując przycisk zmniejszania głośności, naciskając jednocześnie przycisk zasilania.
    2. +
    3. Użyj zmniejszania głośności aby wybrać odzyskiwanie a następnie włącz go.
    4. +
    5. Podczas odzyskiwania zegara przejdź do "menu partycji".
    6. +
    7. Wybierz mount /system, mount /sdcard i mount /data.
    8. +
    9. Podłącz przewód USB i otwórz wiersz poleceń na komputerze.
    10. +
    11. Wprowadź adb shell i wpisz ln -s /data/hosts /system/etc/hosts (Tworzy to dowiązanie symboliczne, które pozwala AdAway na edycję pliku hosts przechowywanego w / data, zezwalając systemowi na używanie pliku tak, jakby był on przechowywany w /system.)
    12. +
    13. Uruchom ponownie urzÄ…dzenie i ustaw Docelowy plik hosts na /data/hosts w preferencjach AdAway.
    14. +
    15. AdAway powinien działać już poprawnie.
    16. +
    + + diff --git a/app/src/main/res/raw-ps/help_faq.html b/app/src/main/res/raw-ps/help_faq.html new file mode 100644 index 0000000..756bb2d --- /dev/null +++ b/app/src/main/res/raw-ps/help_faq.html @@ -0,0 +1,32 @@ + + + +بيابيا ÙƒÛØ¯ÙˆÙ†ÙƒÛ Ù¾ÙˆÚšØªÙ†Û + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ps/help_problems.html b/app/src/main/res/raw-ps/help_problems.html new file mode 100644 index 0000000..b4d45e9 --- /dev/null +++ b/app/src/main/res/raw-ps/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Chrome still displays ads

    +

    Ensure you disable lite mode (previously known as data saver) from Chrome settings. This features allows Chrome to use private DNS solution and bypass AdAway.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in our GitHub issue tracker.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-ps/help_s_on_s_off.html b/app/src/main/res/raw-ps/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-ps/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-pt-rBR/help_faq.html b/app/src/main/res/raw-pt-rBR/help_faq.html new file mode 100644 index 0000000..caea9fb --- /dev/null +++ b/app/src/main/res/raw-pt-rBR/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Renda por anúncios

    +

    Existe um equívoco declarado de que se um usuário nunca clicar em anúncios, logo bloqueá-los não prejudicará um site ou app financeiramente. Isto está errado, os desenvolvedores também ganham dinheiro apenas mostrando anúncios. Depende de você, se você bloqueia os anúncios ou não. Pessoalmente, eu não usaria apps que mostrassem anúncios porque os acho muito irritantes, logo sem um bloqueador de anúncios eu não instalaria estes apps.

    + +

    Como AdAway funciona?

    +

    O AdAway usa o arquivo de hosts para bloquear nomes de hosts que veiculam anúncios. O arquivo hosts é um arquivo encontrado em /system/etc/hosts que mapeia nomes de host para endereços IP. É uma maneira tradicional de definir pares de nome de host para endereço IP sem depender do DNS (Sistema de Nomes de Domínio). Todos os nomes de host indesejados são redirecionados para 127.0.0.1, o que significa que eles apontarão para o seu próprio dispositivo.
    + Se o arquivo hosts não for gravável, uma solução alternativa é usar o serviço VPN interno. Ele filtrará as conexões com nomes de host indesejados e permitirá que outras pessoas passem.

    + +

    Por que tenho que reiniciar o Android para as alterações fazerem efeito?

    +

    Java no Android mantém seu próprio cache DNS interno. O sistema operacional refletirá o novo arquivo hosts imediatamente (verifique isto com uma solicitação na linha de comando), mas você precisará reiniciar o Android para reconstruir o cache DNS de Java.

    + +

    Como usar o servidor web no AdAway?

    +

    AdAway também funcionará sem usar o servidor da web! +

    Você pode ativar um servidor local nas preferências da AdAway para responder a solicitações para o endereço IP local 127.0.0.1. Isso significa que as solicitações de aplicativos para servidores de anúncios redirecionados para 127.0.0.1 são respondidas pelo servidor da AdAway. +
    Alguns aplicativos se recusam a funcionar, quando os servidores de anúncios não estão acessíveis. Com esse método, eles poderão ser acessados novamente, respondendo com uma página em branco e sem imagens de anúncios.

    + +

    Como posso bloquear/desbloquear nomes de hosts específicos?

    +

    Adicione os nomes de host que você deseja bloquear na lista Bloqueado na tela inicial. Além disso, os nomes de host que você deseja excluir do bloqueio podem ser adicionados ao Permitido e os nomes de host que você deseja redirecionar para um endereço IP específico pertencem ao Redirecionado.

    + +

    Onde posso encontrar mais fontes de hosts?

    +

    Consulte Lista de fontes de hosts adicionais para AdAway.

    + +

    Ajudar com tradução/reportar erros

    +

    Visite https://adaway.org.

    + + diff --git a/app/src/main/res/raw-pt-rBR/help_problems.html b/app/src/main/res/raw-pt-rBR/help_problems.html new file mode 100644 index 0000000..14ca7cd --- /dev/null +++ b/app/src/main/res/raw-pt-rBR/help_problems.html @@ -0,0 +1,36 @@ + + + +Problemas comuns + +

    Falha na cópia do arquivo hosts no Android 9 ou superior

    +

    As versões mais recentes do Android usam a partição /system somente leitura.
    +Se você estiver usando o Magisk como solução raiz, ative o módulo hosts sem sistema e reinicie.

    + +

    Espaço insuficiente na partição

    +

    Tente alterar o arquivo de hosts de destino em preferências para /data/data/hosts (ou /data/hosts) e aplique AdAway novamente.

    + +

    Não funciona no Android 4.4+

    +

    Tente alterar o arquivo de hosts de destino nas preferências de /data/data/hosts para /data/hosts ou /system/etc/hosts e aplique AdAway novamente.

    + +

    Não bloqueia anúncios no app XYZ!

    +

    Alguns hostnames podem estar ausentes nos arquivos de hosts fornecidos das Fontes de Hosts ou o aplicativo agrupou as imagens para fornecer anúncios sem acessar a Internet.

    +Você pode registrar solicitações de DNS (Menu->Registrar solicitações de DNS) a partir do AdAway para descobrir quais nomes de host adicionais devem ser bloqueados. +

    Adicione os nomes de host suspeitos à sua própria Lista Negra pressionando por muito tempo as entradas no Registro e informe esses nomes de host quando os tiver verificado na Caixa de Entrada dos Hosts do Fórum em hosts-file.net.

    + +

    Anúncios no Cache

    +

    Algumas vezes os apps armazenam anúncios no cache após baixados. Isto gera resíduos de anúncios em alguns apps. Você pode tentar excluir o cache destes apps na lista de Apps do Android para contornar este problema.

    + +

    App XYZ não está funcionando mais!

    +

    Alguns aplicativos precisam se comunicar com um nome de host bloqueado pela AdAway ou se recusar a funcionar quando os nomes de host que devem veicular anúncios não podem ser acessados. Consulte https://github.com/AdAway/AdAway/wiki/ProblematicApps para obter uma lista de aplicativos conhecidos que apresentam problemas. Caso contrário, descubra quais nomes de host são necessários e adicione-os à sua Lista Branca em Suas listas e informe-os ao rastreador de erros da AdAway.

    + +

    O botão Voltar nos navegadores web não está funcionando

    +

    Você pode ativar o servidor web local do AdAway nas preferências como uma solução alternativa.

    + +

    O botão Voltar nos navegadores web não está funcionando

    +

    Você pode ativar o servidor web local do AdAway nas preferências como uma solução alternativa.

    + + + diff --git a/app/src/main/res/raw-pt-rBR/help_s_on_s_off.html b/app/src/main/res/raw-pt-rBR/help_s_on_s_off.html new file mode 100644 index 0000000..ffa9b01 --- /dev/null +++ b/app/src/main/res/raw-pt-rBR/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Ajuda relacionada ao S-ON + +

    Dispositivos HTC

    +

    AdAway não funciona quando você está usando um dispositivo com então chamado S-ON. Este 'recurso' existe em muitos dispositivos HTC e evita AdAway de escrever o arquivo hosts.

    + +

    S-ON/S-OFF?

    +

    S-OFF significa que a partição NAND do dispositivo está desbloqueada e pode ser escrita. A definição padrão para dispositivos HTC é S-ON, que significa que você não pode acessar certas áreas do sistema nem garantir um root permanente. Além disto, a verificação de assinatura para imagens de firmware é também assegurada pela bandeira S-ON.

    + +

    Tenho S-ON ou S-OFF?

    +

    Inicialize no Boot Menu no seu dispositivo mantendo pressionado o botão de volume para baixo enquanto pressiona a energia e o texto na parte superior mostrará o status do sinalizador como S-OFF ou S-ON. Uma raiz completa geralmente significa S-OFF. +

    Mais informações podem ser encontradas em www.addictivetips.com. Métodos adicionais S-OFF desde Unrevokable (no link) podem lhe interessar, a saber: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Solução Alternativa

    +

    Pré-requisito: Você tem que instalar um Android SDK com o shell ADB no seu PC.

    +
      +
    1. Inicialize no Boot Menu do seu dispositivo pressionando o botão de diminuir o volume enquanto pressiona a energia.
    2. +
    3. Use o volume para baixo para selecionar a recuperação e depois o de ligar para inicializá-la.
    4. +
    5. Na recuperação do clockwork, acesse "menu de partições".
    6. +
    7. Selecione mount /system, mount /sdcard e mount /data.
    8. +
    9. Conecte seu cabo USB e abra uma linha de comando no seu computador.
    10. +
    11. Entre no ADB Shell e digite ln -s /data/hosts /system/etc/hosts (Isso cria um link simbólico que permite que o AdAway edite o arquivo hosts que é guardado em /datapermitindo que o OS use o arquivo como se ele estivesse guardado em /system.)
    12. +
    13. Reinicialize seu dispositivo e defina o Arquivo de Hosts de destino para /data/hosts nas preferências da AdAway.
    14. +
    15. AdAway deve funcionar agora.
    16. +
    + + diff --git a/app/src/main/res/raw-pt/help_faq.html b/app/src/main/res/raw-pt/help_faq.html new file mode 100644 index 0000000..f1181b5 --- /dev/null +++ b/app/src/main/res/raw-pt/help_faq.html @@ -0,0 +1,32 @@ + + + +Perguntas frequentes + +

    Rendimento com anúncios

    +

    Existe uma ideia errada muito repetida de que, se um utilizador nunca clicar em anúncios, bloqueá-los não vai prejudicar um site ou aplicação financeiramente. Isto é errado; os programadores também ganham dinheiro apenas por mostrar anúncios. Cabe-lhe a si decidir bloquear anúncios ou não. Pessoalmente, não utilizaria aplicações que mostram anúncios, visto que as acho muito irritantes, portanto, sem um bloqueador de anúncios, não instalaria estas aplicações.

    + +

    Como funciona o AdAway?

    +

    O AdAway usa o ficheiro de hosts para bloquear nomes de hosts que veiculam anúncios. O ficheiro de hosts é um ficheiro encontrado em /system/etc/hosts que mapeia nomes de host para endereços IP. É uma maneira tradicional de definir pares de nome de host para endereços IP sem depender do DNS (Sistema de Nomes de Domínio). Todos os nomes de host indesejados são redirecionados para 127.0.0.1, o que significa que eles irão apontar para o seu próprio dispositivo.
    +Se o ficheiro hosts não for gravável, uma solução alternativa é usar o serviço de VPN interno. Ele filtrará as conexões com nomes de host indesejados e permitirá que outros passem.

    + +

    Porque tenho de reiniciar o Android para as alterações entrarem em efeito?

    +

    No Android, o Java mantém a sua própria cache interna de DNS. O sistema operativo refletirá o novo ficheiro de hosts imediatamente (verifique com um ping na linha de comandos), mas terá de reiniciar o Android para reconstruir a cache de DNS do Java.

    + +

    Como utilizar o servidor web do AdAway?

    +

    AdAway também irá funcionar sem utilizar o servidor da Web! +

    Pode ativar um servidor da Web local nas preferências do AdAway para responder aos pedidos para o endereço de IP local 127.0.0.1. Isto significa que os pedidos das aplicações para os servidores da Web que forem redirecionados para 127.0.0.1 serão respondidos pelo servidor da Web do AdAway. +
    Algumas aplicações recusam-se a funcionar quando os servidores de anúncios não se encontram alcançáveis. Com este método, estes irão estar novamente alcançáveis, respondendo com uma página em branco sem imagens de anúncios.

    + +

    Como é que eu posso bloquear/desbloquear nomes de hospedeiro específicos?

    +

    Adicione os nomes de host que deseja bloquear na lista Bloqueado no ecrã inicial. Adicionalmente, os nomes de host que deseja excluir do bloqueio podem ser adicionados ao Permitido e os nomes de host que deseja redirecionar para um endereço IP específico pertencem ao Redirecionado.

    + +

    Onde é que eu encontro mais fontes de hospedeiros?

    +

    Consulte a lista de fontes de hosts adicionais para o AdAway.

    + +

    Ajude a traduzir/relatar erros

    +

    Por favor, visite https://adaway.org.

    + + diff --git a/app/src/main/res/raw-pt/help_problems.html b/app/src/main/res/raw-pt/help_problems.html new file mode 100644 index 0000000..1d38153 --- /dev/null +++ b/app/src/main/res/raw-pt/help_problems.html @@ -0,0 +1,36 @@ + + + +Problemas comuns + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Espaço insuficiente na partição

    +

    Tente alterar o ficheiro hosts de destino nas preferências para /data/data/hosts (ou /data/hosts) e aplique o AdAway novamente.

    + +

    Não funciona no Android 4.4+

    +

    Tente alterar o ficheiro hosts de destino nas preferências de /data/data/hosts para /data/hostsou /system/etc/hosts e aplique o AdAway novamente.

    + +

    Não bloqueia anúncios na aplicação XYZ!

    +

    Alguns nomes de hospedeiros podem estar ausentes nos ficheiros de hospedeiros fornecidos das Fontes de Hospedeiros ou a aplicação agrupou as imagens para fornecer anúncios sem aceder à Internet.

    +Pode registar pedidos de DNS (Menu->Registar pedidos de DNS) a partir do AdAway para descobrir quais os nomes de hospedeiros adicionais que devem ser bloqueados. +

    Adicione os nomes de hospedeiros suspeitos à sua própria Lista Negra com um premir longo nas entradas no Registo e reporte esses nomes de hospedeiros quando os tiver verificado na Caixa de Entrada dos Hospedeiros (Hosts Inbox) do Fórum em hosts-file.net.

    + +

    Anúncios em cache

    +

    Por vezes, as aplicações colocam anúncios em cache depois de os descarregarem. Isto faz com que fiquem alguns anúncios nalgumas aplicações. Poderá tentar remover a cache destas aplicações na lista de aplicações do Android para resolver este problema.

    + +

    A aplicação XYZ já não funciona!

    +

    Algumas aplicações precisam de comunicar com um nome de hospedeiro que é bloqueado pelo AdAway ou recusa-se a funcionar quando os nomes de hospedeiro que deveriam fornecer os anúncios não estão ao alcance. Consulte https://github.com/AdAway/AdAway/wiki/ProblematicApps para obter uma lista de aplicações conhecidas que têm problemas. Caso contrário, descubra quais os nomes de hospedeiro necessários e adicione-os à sua Lista Branca em As Suas Listas e comunique-as no registo de problemas do AdAway.

    + +

    O botão de retroceder nos navegadores web não funciona

    +

    Em alternativa, pode ativar o servidor web local do AdAway nas preferências.

    + +

    O botão de retroceder nos navegadores web não funciona

    +

    Em alternativa, pode ativar o servidor web local do AdAway nas preferências.

    + + + diff --git a/app/src/main/res/raw-pt/help_s_on_s_off.html b/app/src/main/res/raw-pt/help_s_on_s_off.html new file mode 100644 index 0000000..c1c4a10 --- /dev/null +++ b/app/src/main/res/raw-pt/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Ajuda relacionada com S-ON + +

    Dispositivos HTC

    +

    O AdAway não funciona quando utiliza um dispositivo com o chamado S-ON. Esta "funcionalidade" existe em muitos dispositivos HTC e impede que o AdAway escreva no ficheiro de hosts.

    + +

    S-ON/S-OFF?

    +

    S-OFF significa que a porção NAND do dispositivo está desbloqueada e que pode ser escrita. A definição predefinida para dispositivos HTC é S-ON, o que significa que o utilizador não pode aceder a certas áreas do sistema nem pode garantir root permanente. Além disso, a verificação de assinatura das imagens de firmware também é realizada pela flag S-ON.

    + +

    Tenho S-ON ou S-OFF?

    +

    Inicie no 'Menu de Arranque' do seu dispositivo pressionando o botão de diminuir o volume e o de ligar/desligar ao mesmo tempo e o texto no topo mostrará o estado da "flag" como S-OFF ou S-ON. Um "root" completo geralmente significa S-OFF. +

    Pode ser encontrada mais informação em www.addictivetips.com. Os métodos de S-OFF adicionais desde Unrevokable (na hiperligação) poderão interessar-lhe, nomeadamente: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Solução alternativa

    +

    Pré-requisito: tem de instalar o Android SDK com a shell ADB no seu PC.

    +
      +
    1. Inicie no 'Menu de Arranque' do seu dispositivo pressionando o botão de diminuir o volume e o de ligar/desligar ao mesmo tempo.
    2. +
    3. Use diminuir o volume para selecionar recuperar te então ligue para ver o menu de arranque.
    4. +
    5. No ClockworkMod Recovery vá a "menu de partições".
    6. +
    7. Selecione mount /system, mount /sdcard e mount /data.
    8. +
    9. Introduza o cabo USB e abra uma linha de comandos no seu PC.
    10. +
    11. Entre na shell do ADB e introduza ln -s /data/hosts /system/etc/hosts (Isto cria uma hiperligação simbólica, que permite que o AdAway edite o ficheiro hosts guardado em /data ao mesmo tempo que permite que o SO utilize o ficheiro como se estivesse guardado em /system.)
    12. +
    13. Reinicie o seu dispositivo e defina Ficheiro hosts de destino para /data/hosts nas preferências de AdAway.
    14. +
    15. O AdAway deverá agora funcionar.
    16. +
    + + diff --git a/app/src/main/res/raw-ro/help_faq.html b/app/src/main/res/raw-ro/help_faq.html new file mode 100644 index 0000000..ccd59ca --- /dev/null +++ b/app/src/main/res/raw-ro/help_faq.html @@ -0,0 +1,32 @@ + + + +Listă cu întrebări frecvente + +

    Venitul obținut din reclame

    +

    Există o confuzie legată de banii obținuți din reclame, și anume, dacă un utilizator nu interacționează cu reclamele atunci nici blocarea acestora nu afectează financiar site-ul web sau aplicația în cauză. Acest lucru este greșit deoarece dezvoltatorii primesc bani doar afișând reclamele indiferent dacă se interacționează cu ele sau nu. Personal, eu nu aș folosi aplicații care aleg să afișeze reclame deoarece le consider deranjante, deci fără un alt program de blocare a reclamelor nici măcar nu le-aș fi instalat.

    + +

    Cum funcționează AdAway?

    +

    AdAway folosește fișierul hosts pentru a bloca domeniile care trimit reclame. Fișierul host se găsește în /system/etc/hosts și asociază domeniul cu o adresă IP. Este o metoda tradițională de alocare pentru domenii de adrese IP pereche fără a mai avea nevoie de Sistemul de Nume de Domeniu (DNS). Domeniile nedorite vor fi redirectate către 127.0.0.1 ceea ce înseamnă că vor fi trimise local către dispozitivul dumneavoastră.
    +Dacă fișierul hosts nu poate fi suprascris, o soluție de rezervă este utilizarea serverului dedicat VPN. Acesta va filtra pe conexiune domeniile nedorite și va permite trecerea celorlalte.

    + +

    De ce trebuie să repornesc Android pentru ca modificările să aibă efect?

    +

    Java in Android mentine un cache DNS intern. Sistemul de operare va vedea noul fișier hosts imediat după aplicarea modificărilor (se poate verifica acest lucru printr-o comanda ping în consolă) dar o repornire este totuși necesară pentru a reface cache-ul DNS din Java.

    + +

    Cum se folosește serverul web în AdAway?

    +

    AdAway poate funcționa și fără server local! +

    Poți activa serverul local din setările AdAway pentru a răspunde cererilor pe adresa IP locală 127.0.0.1. Așadar cererile aplicațiilor către serverele de reclame for fi redirecționate către 127.0.0.1 fiind gestionate de serverul web AdAway. +
    Unele aplicații pot să nu mai funcționeze dacă nu reușesc să descarce reclamele. Cu această metodă, aplicațiile vor avea răspuns la cereri, răspunsul fiind o pagină goală fără reclame sau imagini.

    + +

    Cum pot bloca/debloca domenii mai specifice?

    +

    Adăugați domeniile pe care doriți să le blocați pe Lista neagră din ecranul principal. Opțional, domeniile pe care doriți să le excludeți din blocare pot fi adăugate pe Lista albă iar domeniile pe care doriți să le redirecționați spre o adresă IP specifică, se află în Lista de redirecționare.

    + +

    Unde pot găsi mai multe surse hosts?

    +

    Accesați Lista adițională de surse hosts pentru AdAway

    + +

    Ajută la traducere/Raportare erori.

    +

    Vizitați pagina https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ro/help_problems.html b/app/src/main/res/raw-ro/help_problems.html new file mode 100644 index 0000000..6b7b644 --- /dev/null +++ b/app/src/main/res/raw-ro/help_problems.html @@ -0,0 +1,36 @@ + + + +Probleme comune + +

    Copierea fișierului 'hosts' nereușită pe Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Spațiu insuficient pe partiție

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Încă apar reclame în Chrome

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    Nu blochează reclamele în aplicația XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Uneori,aplicatiile salveaza reclamele dupa downloadare. Asta inseamna ca unele aplicatii vor avea reclame ramase nesterse. O solutie este stergerea cache-ului acestor aplicatii din meniul Setari->Aplicatii.

    + +

    Aplicația XYZ nu mai funcționează!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Nu funcționează pe Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    The back button in web browsers is not working

    +

    O soluție ar fi activarea serverului web local AdAway din setări.

    + + + diff --git a/app/src/main/res/raw-ro/help_s_on_s_off.html b/app/src/main/res/raw-ro/help_s_on_s_off.html new file mode 100644 index 0000000..d89fac3 --- /dev/null +++ b/app/src/main/res/raw-ro/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    Dispozitive HTC

    +

    AdAway nu funcționează pe dispozitivele cu S-ON. Această 'funcție' este întâlnită pe multe dispozitive HTC și nu permite AdAway să scrie în fișierul hosts.

    + +

    S-ON sau S-OFF?

    +

    S-OFF inseamna ca partitia NAND a dispozitivului este deblocata si poate fi scrisa. Setarea din fabrica a dispozitivelor HTC este S-ON,ceea ce inseamna ca anumite parti ale sistemului nu pot fi accesate si nu exista certitudinea unui root permanent.De asemenea,S-ON face obligatorie verificarea semnaturilor pentru imaginile de sistem.

    + +

    Dispozitivul meu este S-ON sau S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Soluție

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Conectați cablul USB și deschideți o linie de comandă pe calculator.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway ar trebui să funcționeze acum.
    16. +
    + + diff --git a/app/src/main/res/raw-ru/help_faq.html b/app/src/main/res/raw-ru/help_faq.html new file mode 100644 index 0000000..5cdd2e3 --- /dev/null +++ b/app/src/main/res/raw-ru/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Доходы от рекламы

    +

    СущеÑтвует чаÑто вÑтречающееÑÑ Ð·Ð°Ð±Ð»ÑƒÐ¶Ð´ÐµÐ½Ð¸Ðµ, что еÑли пользователь никогда не нажимает на рекламу, то, заблокировав её, не нанеÑёт вреда Ñайту или приложению в финанÑовом плане. Это неверно, разработчики также зарабатывают деньги проÑто за показ рекламы. Вам решать, блокировать рекламу или нет. Лично Ñ Ð±Ñ‹ не Ñтал иÑпользовать Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¾Ð¹, так как Ñчитаю, что она очень раздражает, поÑтому без блокировщика рекламы Ñ Ð±Ñ‹ не Ñтал уÑтанавливать такие приложениÑ.

    + +

    Как работает AdAway?

    +

    AdAway иÑпользует файл hosts Ð´Ð»Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ хоÑтов, которые Ñлужат иÑточниками рекламы. Файл hosts раÑположен по пути /system/etc/hosts и ÑопоÑтавлÑет имена хоÑтов Ñ Ð¸Ñ… IP-адреÑами. Это обычный ÑпоÑоб Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ñ‹ "Ð¸Ð¼Ñ Ñ…Ð¾Ñта - Ð°Ð´Ñ€ÐµÑ IP" без иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑиÑтемы доменных имён (DNS). Ð’Ñе нежелательные имена хоÑтов будут перенаправлены на Ð°Ð´Ñ€ÐµÑ 127.0.0.1, что означает, что они будут указывать на ваше ÑобÑтвенное уÑтройÑтво.
    +ЕÑли файл hosts недоÑтупен Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи, запаÑным решением ÑвлÑетÑÑ Ð¸Ñпользование вÑтроенной Ñлужбы VPN . Она будет фильтровать Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº нежелательным именам хоÑтов и пропуÑкать оÑтальные.

    + +

    Почему мне нужно перезагружать уÑтройÑтво, чтобы Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²Ñтупили в Ñилу?

    +

    Java на Android имеет Ñвой внутренний кÑш DNS. ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð°Ñ ÑиÑтема будет иÑпользовать обновлённый файл hosts Ñразу же (проверьте Ñто Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ команды ping в командной Ñтроке), но вы должны перезагрузить уÑтройÑтво, чтобы переÑоздать кÑш DNS в Java.

    + +

    Как иÑпользовать веб-Ñервер в AdAway?

    +

    AdAway также будет работать и без иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð²ÐµÐ±-Ñервера! +

    Ð’Ñ‹ можете включить локальный веб-Ñервер в наÑтройках AdAway Ð´Ð»Ñ Ð¾Ñ‚Ð²ÐµÑ‚Ð¾Ð² на запроÑÑ‹ к локальному IP-адреÑу 127.0.0.1. Это означает, что тогда на вÑе запроÑÑ‹ хоÑтов Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¾Ð¹, которые перенаправлÑÑŽÑ‚ÑÑ Ð½Ð° ваш локальный IP-Ð°Ð´Ñ€ÐµÑ 127.0.0.1, будет отвечать веб-Ñервер AdAway. +
    Ðекоторые Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¾Ñ‚ÐºÐ°Ð·Ñ‹Ð²Ð°ÑŽÑ‚ÑÑ Ñ€Ð°Ð±Ð¾Ñ‚Ð°Ñ‚ÑŒ, еÑли не имеют доÑтупа к хоÑту Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¾Ð¹. Этот метод позволит запуÑкать такие приложениÑ, но вмеÑто рекламы будет подÑтавлÑтьÑÑ Ð¿ÑƒÑтое меÑто и отÑутÑтвовать изображение рекламы.

    + +

    Как Ñ Ð¼Ð¾Ð³Ñƒ заблокировать/разблокировать определенное Ð¸Ð¼Ñ Ñ…Ð¾Ñта?

    +

    Добавить имена хоÑтов, которые вы хотите заблокировать, можно в ÑпиÑок Блокировано, находÑщийÑÑ Ð½Ð° главном Ñкране. Кроме того, имена хоÑтов, которые вы хотите иÑключить из блокировки, могут быть добавлены в Разрешено, а имена хоÑтов, которые вы хотите перенаправить на определённый IP-адреÑ, надо внеÑти в Перенаправлено.

    + +

    Где Ñ Ð¼Ð¾Ð³Ñƒ найти больше иÑточников ÑпиÑков хоÑтов?

    +

    Смотрите CпиÑок дополнительных иÑточников хоÑтов Ð´Ð»Ñ AdAway.

    + +

    Помогите Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð¾Ð¼/Ñообщите об ошибках

    +

    ПожалуйÑта, перейдите на https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ru/help_problems.html b/app/src/main/res/raw-ru/help_problems.html new file mode 100644 index 0000000..51ae7f8 --- /dev/null +++ b/app/src/main/res/raw-ru/help_problems.html @@ -0,0 +1,37 @@ + + + +РаÑпроÑтраненные проблемы + +

    Ошибка ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° hosts на Android 9+

    +

    ПоÑледние верÑии Android иÑпользуют раздел /system, доÑтупный только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ.
    +ЕÑли вы иÑпользуете Magisk Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð°Ð² root, убедитеÑÑŒ, что вы включили беÑÑиÑтемный модуль hosts, а затем перезагрузитеÑÑŒ.

    + +

    Ðе хватает меÑта в диÑковом разделе

    +

    Попробуйте изменить путь к файлу hosts в наÑтройках на /data/data/hosts (или /data/hosts) и Ñнова примените AdAway.

    + +

    Chrome по-прежнему отображает рекламу

    +

    УбедитеÑÑŒ, что у Ð²Ð°Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½ Упрощенный режим (ранее извеÑтный как Ð­ÐºÐ¾Ð½Ð¾Ð¼Ð¸Ñ Ñ‚Ñ€Ð°Ñ„Ð¸ÐºÐ°) в наÑтройках Chrome. Из-за Ñтой наÑтройки Chrome иÑпользует приватный DNS, который обходит AdAway.

    + +

    Ðе блокируетÑÑ Ñ€ÐµÐºÐ»Ð°Ð¼Ð° в том или ином приложении!

    +

    Ðекоторые имена хоÑтов могут отÑутÑтвовать в ÑоответÑтвующих файлах хоÑтов из ИÑточники хоÑтов или приложение объединило Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ð° рекламы без доÑтупа к Интернету. +

    +Ð’Ñ‹ можете зайти в журнал запроÑов DNS (Меню-> Журнал запроÑов DNS) AdAway, чтобы выÑÑнить, какие дополнительные имена хоÑтов должны быть заблокированы. +

    Добавьте подозрительные имена хоÑтов в ваш Черный ÑпиÑок долгим нажатием на запиÑÑŒ в журнале, и поÑле проверки Ñообщите об Ñтих именах хоÑтов в наш багтрекер на GitHub.

    + +

    КÑÑˆÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð°

    +

    Иногда Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÐºÑшируют рекламу поÑле загрузки. Это приводит к тому, что в некоторых приложениÑÑ… оÑтаетÑÑ Ñ€ÐµÐºÐ»Ð°Ð¼Ð°. Ð’Ñ‹ можете попробовать удалить кÑш Ð´Ð»Ñ Ñтих приложений в ÑпиÑке приложений Android Ð´Ð»Ñ ÑƒÑÑ‚Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñтой проблемы.

    + +

    То или иное приложение больше не работает!

    +

    Ðекоторым приложениÑм необходимо ÑвÑзыватьÑÑ Ñ Ð°Ð´Ñ€ÐµÑами, заблокированными AdAway, или Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ работают, когда имена хоÑтов отображающих рекламу недоÑтупны. ПоÑетите https://github.com/AdAway/AdAway/wiki/ProblematicApps, чтобы ознакомитьÑÑ Ñо ÑпиÑком приложений, имеющих подобные проблемы. Либо выÑÑните какие имена хоÑтов необходимы приложениÑм и добавьте их в Белый ÑпиÑок в категории Ваши ÑпиÑки и Ñообщите об Ñтом на багтрекере AdAway.

    + +

    Ðе работает на Android 4.4+

    +

    Попробуйте изменить путь к файлу hosts в наÑтройках Ñ /data/data/hosts на /data/hosts или /system/etc/hosts и Ñнова примените AdAway.

    + +

    Кнопка "назад" в веб-браузерах не работает

    +

    Ð’Ñ‹ можете включить локальный веб-Ñервер AdAway в наÑтройках в качеÑтве обходного пути.

    + + + diff --git a/app/src/main/res/raw-ru/help_s_on_s_off.html b/app/src/main/res/raw-ru/help_s_on_s_off.html new file mode 100644 index 0000000..a1e2b78 --- /dev/null +++ b/app/src/main/res/raw-ru/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Справка по S-ON + +

    УÑтройÑтва HTC

    +

    AdAway не работает еÑли вы иÑпользуете уÑтройÑтво Ñ Ñ‚Ð°Ðº называемым S-ON. Эта «функциÑ» ÑущеÑтвует на многих уÑтройÑтвах HTC и не позволÑет AdAway изменÑть файл hosts.

    + +

    S-ON/S-OFF?

    +

    S-OFF означает, что чаÑть памÑти NAND разблокирована, и позволÑет производить в нее запиÑÑŒ. По умолчанию уÑтройÑтва HTC работают в режиме S-ON, а Ñто означает, что вы не можете получить доÑтуп к определённым облаÑÑ‚Ñм памÑти и не можете гарантировать поÑтоÑнный root-доÑтуп. Кроме того, проверка цифровых подпиÑей образов прошивок также оÑущеÑтвлÑетÑÑ Ñ„Ð»Ð°Ð³Ð¾Ð¼ S-ON.

    + +

    Моё уÑтройÑтво работает в режиме S-ON или S-OFF?

    +

    ЗагрузитеÑÑŒ в меню загрузчика на вашем уÑтройÑтве, ÑƒÐ´ÐµÑ€Ð¶Ð¸Ð²Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÑƒ уменьшить громкоÑть и одновременно Ð·Ð°Ð¶Ð¸Ð¼Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÑƒ включениÑ, поÑле чего вы увидите вверху текÑÑ‚, который покажет Ñтатут флага — S-OFF или S-ON. Полный рут-доÑтуп обычно означает S-OFF. +

    Более подробную информацию вы Ñможете найти на www.addictivetips.com. Дополнительные методоы S-OFF, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Unrevokable (по ÑÑылке), которые могут Ð²Ð°Ñ Ð·Ð°Ð¸Ð½Ñ‚ÐµÑ€ÐµÑовать, а именно: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Решение

    +

    Предварительное уÑловие: Ð’Ñ‹ должны уÑтановить рабочий Android SDK Ñ Ð¾Ð±Ð¾Ð»Ð¾Ñ‡ÐºÐ¾Ð¹ ADB на ваш ПК.

    +
      +
    1. ЗагрузитеÑÑŒ в меню загрузки уÑтройÑтва, ÑƒÐ´ÐµÑ€Ð¶Ð¸Ð²Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÑƒ уменьшить громкоÑть одновременно Ð½Ð°Ð¶Ð¸Ð¼Ð°Ñ Ð½Ð° кнопку включениÑ.
    2. +
    3. ИÑпользуйте кнопку уменьшить громкоÑть чтобы выбрать режим воÑÑтановлениÑ, затем кнопку включениÑ, чтобы загрузить его.
    4. +
    5. В Clockwork Recovery перейдите в "меню разделов".
    6. +
    7. Выберите mount /system, mount /sdcard и mount /data.
    8. +
    9. Подключите ваш телефон к ПК через кабель USB и откройте окно командной Ñтроки на ПК.
    10. +
    11. ЗапуÑтите оболочку ADB и введите ln -s /data/hosts /system/etc/hosts (Это ÑоздаÑÑ‚ ÑимволичеÑкую "мÑгкую" ÑÑылку, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ð¸Ñ‚ AdAway редактировать файл hosts, раÑположенный по пути /data, одновременно позволÑÑ ÐžÐ¡ иÑпользовать Ñтот файл так, как еÑли бы он находилÑÑ Ð² /system.)
    12. +
    13. Перезагрузите ваше уÑтройÑтво и уÑтановите Путь к файлу hostsв значение /data/hosts в наÑтройках AdAway.
    14. +
    15. Теперь AdAway должен заработать.
    16. +
    + + diff --git a/app/src/main/res/raw-si/help_faq.html b/app/src/main/res/raw-si/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-si/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-si/help_problems.html b/app/src/main/res/raw-si/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-si/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-si/help_s_on_s_off.html b/app/src/main/res/raw-si/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-si/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-sk/help_faq.html b/app/src/main/res/raw-sk/help_faq.html new file mode 100644 index 0000000..0d07c60 --- /dev/null +++ b/app/src/main/res/raw-sk/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Príjmy z reklamy

    +

    Užívatelia sa mylne domnievajú, že pokiaľ nikdy neklikajú na reklamy, blokovanie nijak finanÄne nepoÅ¡kodí aplikácie alebo webové stránky. To je nesprávne, vývojári taktiež zarábajú jednoduchým zobrazením reklamy. Je iba na vás, Äi budete reklamy blokovaÅ¥ alebo nie. Osobne by som aplikácie, ktoré reklamy zobrazujú nepoužíval, reklamy mi prídu veľmi otravné, takže bez blokovaÄa reklám by som si tieto aplikácie neinÅ¡taloval.

    + +

    Ako funguje AdAway?

    +

    AdAway používa súbor hosts na blokovanie názvov hostiteľa, ktoré poskytujú reklamy. Súbor hosts je súbor, ktorý sa nachádza v /system/etc/hosts, ktorý prevádza názvy serverov na IP adresy. Je to typický spôsob ako definovaÅ¥ párovanie adries a IP bez spoliehania sa na Domain Name System (DNS). VÅ¡etky nechcené adresy sú presmerované na 127.0.0.1, Äo znamená, že budú ukazovaÅ¥ na vaÅ¡e zariadenie.
    +Ak sa do súboru host nedá zapisovať, použije sa núdzové riešenie v podobe služby VPN. Služba bude filtrovať nechcené pripojenia a ostatné nechá prejsť.

    + +

    PreÄo musím reÅ¡tartovaÅ¥ zariadenie aby sa zmeny prejavili?

    +

    Java na Androide udržiava svoju vlastnú internú DNS cache. OperaÄný systém bude pracovaÅ¥ s novým hosts súborom okamžite (overiÅ¥ si to môžete cez ping v príkazovom riadku), ale zariadenie musíte reÅ¡tartovaÅ¥ kvôli obnoveniu DNS cache Javy.

    + +

    Ako používať webserver v AdAway?

    +

    AdAway funguje aj bez použitia webservera! +

    Lokálny webserver môžete povoliÅ¥ v nastaveniach AdAway pre odpovedanie na požiadavky na lokálnu IP adresu 127.0.0.1. To znamená, že požiadavky smerujúce z aplikácií na reklamné servery budú presmerované na 127.0.0.1 a odpoveÄ bude smerovaÅ¥ z webservera AdAway. +
    Niektoré aplikácie odmietajú fungovaÅ¥, ak reklamné servery nie sú dostupné. S touto metódou sa stanú dostupnými a odpoveÄou bude prázdna stránka bez reklamných banerov.

    + +

    Ako môžem blokovať/povoliť špecifické adresy?

    +

    Pridajte adresy, ktoré chcete blokovaÅ¥ do zoznamu Blokované z domovskej obrazovky. Adresy, ktoré chcete vylúÄiÅ¥ z blokovania môžete pridaÅ¥ do zoznamu Povolené a adresy, ktoré chcete presmerovaÅ¥ na Å¡pecifickú IP patria do Presmerovania.

    + +

    Kde môžem nájsÅ¥ ÄalÅ¡ie hosts zdroje?

    +

    Pozrite Zoznam Äalších hosts zdrojov pre AdAway.

    + +

    Pomôžte s prekladom/nahláste chyby

    +

    Prosím, navštívte stránku https://adaway.org.

    + + diff --git a/app/src/main/res/raw-sk/help_problems.html b/app/src/main/res/raw-sk/help_problems.html new file mode 100644 index 0000000..7c7598a --- /dev/null +++ b/app/src/main/res/raw-sk/help_problems.html @@ -0,0 +1,36 @@ + + + +Bežné problémy, + +

    Kopírovanie súboru hosts na Android 9+ zlyhalo

    +

    Pre najnovší Android nastavte partíciu /system iba na Äítanie.
    +Ak používate na root Magisk, overte povolenie modulu systemless hosts a reštartujte.

    + +

    Nedostatok miesta na partícii

    +

    Skúste zmeniť umiestnenie hosts súboru v nastaveniach na /data/data/hosts (alebo /data/hosts) a povoľte AdAway znova.

    + +

    Nefunguje na Android 4.4+

    +

    V nastaveniach prehliadaÄa Chrome vypnite zjednoduÅ¡ený režim (predtým známy ako Å¡etriÄ dát). Táto funkcia umožňuje prehliadaÄu Chrome používaÅ¥ súkromné rieÅ¡enie DNS a obchádzaÅ¥ AdAway.

    + +

    Neblokuje reklamy v aplikácii XYZ!

    +

    Niektoré názvy hostiteľov môžu chýbať v poskytnutých súboroch hosts z Zdroje hosts alebo aplikácia obsahuje obrázky, ktoré sa zobrazujú ako reklama bez internetu.

    +DNS požiadavky môžete zaznamenať (Menu->Zaznamenať DNS požiadavky) v AdAway a nájdené hosts môžu byť blokované. +

    Podozrivých hostiteľov pridajte na Čiernu listinu dlhým podržaním na položku v zázname a nahláste týchto hostiteľov po overení na našom GitHub issue tracker.

    + +

    Reklamy vo vyrovnávacej pamäti

    +

    Niekedy aplikácie ukladajú reklamy do vyrovnávacej pamäti. To niekedy spôsobuje zobrazovanie reklám v niektorých aplikáciách, Môžete skúsiť vymazať vyrovnávaciu pamäť pre tieto aplikácie Nastaveniach - Aplikácie vo vašom zariadení.

    + +

    Aplikácia XYZ už nefunguje!

    +

    Niektoré aplikácie potrebujú komunikovať s názvami hostiteľa, ktoré sú blokované v AdAway alebo odmietajú fungovať, ak adresy s reklamami nie sú dosiahnuteľné. Na stránke https://github.com/AdAway/AdAway/wiki/ProblematicApps nájdete zoznam známych aplikácií, ktoré majú s týmto problém. Alebo, zistite adresy, ktoré sú potrebné a pridajte ich na vašu Bielu listinu pod Vaše zoznamy a nahláste ich na stránke pre hlásenie chýb v AdAway.

    + +

    Nefunguje na Androide 4.4+

    +

    Skúste zmeniť umiestnenie hosts súboru v nastaveniach z /data/data/hosts na /data/hosts alebo /system/etc/hosts a povoľte AdAway znova.

    + +

    TlaÄidlo späť v internetovom prehliadaÄi nefunguje

    +

    Môžete povoliÅ¥ Miestny webserver v nastaveniach AdAway ako doÄasné rieÅ¡enie.

    + + + diff --git a/app/src/main/res/raw-sk/help_s_on_s_off.html b/app/src/main/res/raw-sk/help_s_on_s_off.html new file mode 100644 index 0000000..7e4b0f0 --- /dev/null +++ b/app/src/main/res/raw-sk/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Pomocník súvisiaci s S-ON + +

    HTC zariadenia

    +

    AdAway nefunguje na S-ON zariadeniach. Táto "funkcia" existuje na veľkom množstve HTC zariadení a bráni AdAway zapisovať hosts súbor.

    + +

    S-ON/S-OFF?

    +

    S-OFF znamená, že NAND partícia na zariadení je odomknutá a je možné do nej zapisovaÅ¥. Predvolené nastavenie pre HTC zariadenia je S-ON, Äo znamená, že nie je možné získaÅ¥ prístup k urÄitej Äasti systému. Okrem toho, kontrola podpisu pre firmware obrazy je tiež zabezpeÄená S-ON znaÄkou.

    + +

    Mám S-ON alebo S-OFF?

    +

    NaÅ¡tartujte zariadenie do boot menu, stlaÄte a podržte súÄasne tlaÄidlo na zníženie hlasitosti a tlaÄidlo napájania, navrchu sa zobrazí stav S-OFF alebo S-ON. Úplný root vÅ¡eobecne znamená S-OFF. +

    Viac informácií môžete nájsť na www.addictivetips.com. Ďalšie S-OFF metódy od Unrevokable (v odkaze) by vás mohli zaujímať, menovite: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Riešenie

    +

    Podmienka: Musíte mať nainštalovaný Android SDK s ADB vo vašom PC.

    +
      +
    1. NaÅ¡tartujte zariadenie do boot menu, stlaÄte a podržte súÄasne tlaÄidlo pre zníženie hlasitosti a tlaÄidlo napájania.
    2. +
    3. Pre oznaÄenie recovery použite tlaÄidlo pre zníženie hlasitosti, potom tlaÄidlo napájania pre nabootovanie.
    4. +
    5. V CWM prejdite do "partitions menu"
    6. +
    7. Vyberte mount /system , mount /sdcard a mount /data .
    8. +
    9. Pripojte k USB a otvorte príkazový riadok na poÄítaÄi.
    10. +
    11. Zadajte adb shell and napíšte v -s /data/hosts /system/etc/hosts (Týmto vytvoríte symbolický odkaz, ktorý umožní AdAway upravovaÅ¥ súbor hosts v /data zatiaľ, Äo OS používa súbor uložený v /system .)
    12. +
    13. Reštartujte zariadenie a nastavte Umiestnenie hosts súboru na /data/hosts v nastaveniach AdAway.
    14. +
    15. AdAway by teraz mal fungovať.
    16. +
    + + diff --git a/app/src/main/res/raw-sl/help_faq.html b/app/src/main/res/raw-sl/help_faq.html new file mode 100644 index 0000000..f740908 --- /dev/null +++ b/app/src/main/res/raw-sl/help_faq.html @@ -0,0 +1,32 @@ + + + +Pogosto postavljena vprašanja + +

    Prihodki od oglaševanja

    +

    Pogosto miÅ¡ljenje je, da Äe uporabnik nikoli ne klikne na oglas, potem blokiranje le-teh ne bo finanÄno oÅ¡kodovalo aplikacije. TakÅ¡no miÅ¡ljenje je napaÄno, saj imajo razvijalci prihodek tudi od prikazovanja oglasov. Ali blokirate oglase ali ne, je vaÅ¡a odloÄitev. Osebno, aplikacij ki prikazujejo oglase, ne bi prenaÅ¡al brez ad blockerja, ker znajo biti zelo nadležne.

    + +

    Kako deluje AdAway?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Zakaj moram ponovno zagnati napravo, da so spremembe vidne?

    +

    Java na Androidu vzdržuje lastno notranje DNS pomnjenje. Operacijski sistem bo spremembe zaznal takoj (prepriÄajte se z uporabo ukaza ping), kljub temu pa morate napravo ponovno zagnati za ponovno izgradnjo DNS spomina Jave.

    + +

    Kako uporabljati spletni strežnik v aplikaciji AdAway?

    +

    AdAway bo deloval tudi brez uporabe spletnega strežnika<\strong> +

    Lokalnemu spletnemu strežniku lahko v nastavitvah AdAway omogoÄite odgovarjanje na zahteve na lokalni naslov IP 127.0.0.1. To pomeni, da na zahteve aplikacij do oglasnih strežnikov, ki so preusmerjene na 127.0.0.1, odgovarja spletni strežnik AdAway. +
    Nekatere aplikacije noÄejo delovati, ko oglasni strežniki niso dosegljivi. S to metodo bodo spet dosegljivi, odgovorili bodo s prazno stranjo in brez oglasnih slik.

    + +

    Kako lahko onemogoÄim/dovolim specifiÄna imena gostiteljev?

    +

    Dodajte imena gostiteljev, ki jih želite blokirati, na <clte>Seznam onemogoÄenih</clte> na <clte>zaÄetnem zaslonu</clte>. Dodatno lahko imena gostiteljev, ki jih želite izkljuÄiti iz zaviranja, dodate na <clte>Dovoljena</clte>, imena gostiteljev, ki jih želite preusmeriti na doloÄen naslov IP, pa spadajo na <clte>Preusmerjena</clte>.

    + +

    Kje lahko najdem veÄ hosts seznamov?

    +

    ObiÅ¡Äi Seznam dodatnih virov gostiteljev za AdAway.

    + +

    PomoÄ pri prevajanju/prijava programskih napak

    +

    Prosimo, obiÅ¡Äite https://adaway.org.

    + + diff --git a/app/src/main/res/raw-sl/help_problems.html b/app/src/main/res/raw-sl/help_problems.html new file mode 100644 index 0000000..bebb86c --- /dev/null +++ b/app/src/main/res/raw-sl/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Na particiji ni dovolj prostora

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Ne deluje na Android verziji 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    Ne blokira oglasov v aplikaciji XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Pomnjeni oglasi

    +

    VÄasih aplikacije pomnijo oglase po prenosu. To vodi k prikazovanju oglasov, kljub blokiranju. Poizkusite lahko z brisanjem pomnilnika teh aplikacij na seznamu aplikacij v nastavitvah naprave.

    + +

    Aplikacije XYZ ne deluje veÄ!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Gumb za povratek v brskalnikih ne deluje

    +

    Kot reÅ¡itev lahko vkljuÄite AdAway lokalni spletni strežnik v nastavitvah.

    + +

    Gumb za povratek v brskalnikih ne deluje

    +

    Kot reÅ¡itev lahko vkljuÄite AdAway lokalni spletni strežnik v nastavitvah.

    + + + diff --git a/app/src/main/res/raw-sl/help_s_on_s_off.html b/app/src/main/res/raw-sl/help_s_on_s_off.html new file mode 100644 index 0000000..55ebf80 --- /dev/null +++ b/app/src/main/res/raw-sl/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC naprave

    +

    AdAway ne deluje na napravah s takoimenovano funkcijo S-ON. Ta funkcija obstaja na mnogih HTC napravah in prepreÄuje AdAway-u pisanje v hosts datoteko.

    + +

    S-ON/S-OFF?

    +

    S-OFF pomeni, da je NAND del naprave odklenjen in je pisanje mogoÄe. Privzeta nastavitev na HTC napravah je S-ON, kar pomeni, da do nekaterih delov sistema ne morete dostopati, prav tako pa ne morate zagotoviti trajnega root dostopa. Preverjanje 'podpisov' slik programske opreme je tudi zagotovljeno z nastavitvijo S-ON.

    + +

    Ali imam S-ON ali S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Rešitev

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway bi moral sedaj delovati.
    16. +
    + + diff --git a/app/src/main/res/raw-sq/help_faq.html b/app/src/main/res/raw-sq/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-sq/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-sq/help_problems.html b/app/src/main/res/raw-sq/help_problems.html new file mode 100644 index 0000000..b4d45e9 --- /dev/null +++ b/app/src/main/res/raw-sq/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Chrome still displays ads

    +

    Ensure you disable lite mode (previously known as data saver) from Chrome settings. This features allows Chrome to use private DNS solution and bypass AdAway.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in our GitHub issue tracker.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-sq/help_s_on_s_off.html b/app/src/main/res/raw-sq/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-sq/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-sr/help_faq.html b/app/src/main/res/raw-sr/help_faq.html new file mode 100644 index 0000000..27eaafb --- /dev/null +++ b/app/src/main/res/raw-sr/help_faq.html @@ -0,0 +1,32 @@ + + + +ÄŒesto Postavljena Pitanja + +

    Prihodi od reklama

    +

    Postoji zabluda, da ukoliko korisnik nikada ne klikće na reklame, da se blokiranje istih neće negativno finansijski odraziti na stranicu ili aplikaciju. To je pogreÅ¡no jer programeri isto tako zaraÄ‘uju novac samim prikazom reklama. VaÅ¡a je stvar hoćete li ili nećete blokirati reklame. LiÄno ne bih koristio aplikacije koje prikazuju oglase jer smatram da su vrlo iritantne, tako da bez aplikacije za spreÄavanje prikaza reklama aplikacije te vrste ne bih ni instalirao.

    + +

    Kako AdAway radi?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Zašto moram ponovo pokrenuti Android da bi promene imale efekta?

    +

    Java na Androidu održava svoju sopstvenu DNS keš. Operativni Sistem će reflektovati nove hosts fajlove odmah (verifikovati sa pingom na komandnoj liniji) ali ćete morati da restartujete Android da bi obnovili DNS keš Jave.

    + +

    Kako koristiti webserver u AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    Kako mogu da blokiram/odblokiram posebna imena domena

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Gde mogu pronaći još host izvora?

    +

    Pogledajte Listu dodatnih izvora hostova za AdAway.

    + +

    Pomozite prevođenje/Prijavite greške

    +

    Molimo idite na https://adaway.org.

    + + diff --git a/app/src/main/res/raw-sr/help_problems.html b/app/src/main/res/raw-sr/help_problems.html new file mode 100644 index 0000000..fc66986 --- /dev/null +++ b/app/src/main/res/raw-sr/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Nema dovoljno memorije na particiji

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Ne radi na Androidu 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    Ne blokira reklame na aplikaciji XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Keširane reklame

    +

    Neke aplikacije keširaju reklame posle preuzimanja. Ovo dovodi do ostajanja reklama u nekim aplikacijama. Možete pokušati da uklonite keš ovih aplikacija u Androidovoj Application listi kako bi zaobišli ovaj problem

    + +

    Aplikacija XYZ ne više ne radi!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    "Back" dugme u web browser-u ne radi

    +

    Možete omogućiti lokalni webserver u podešavanjima kao rešenje.

    + +

    "Back" dugme u web browser-u ne radi

    +

    Možete omogućiti lokalni webserver u podešavanjima kao rešenje.

    + + + diff --git a/app/src/main/res/raw-sr/help_s_on_s_off.html b/app/src/main/res/raw-sr/help_s_on_s_off.html new file mode 100644 index 0000000..2dab61b --- /dev/null +++ b/app/src/main/res/raw-sr/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC uređaji

    +

    AdAway ne radi kada koristite ureÄ‘jaje sa S-ON-om. Ova "funkcija" postoji na mnogim HTC ureÄ‘ajima i spreÄava AdAway da menja host fajl.

    + +

    S-ON/S-OFF?

    +

    S-OFF znaÄi da je NAND deo ureÄ‘jaja otkljuÄan i da se na njega može pisati. FabriÄki je podeÅ¡en S-On na HTC ureÄ‘ajima, Å¡to znaÄi da ne možete da pristupite pojedinim oblastima sistema niti možete da garantujete trajni "Root". Å taviÅ¡e, provera potpisa za sistemske nadogradnje je takoÄ‘je osiguran S-ON-om.

    + +

    Da li ja imam S-ON ili S-OFF?

    +

    Pokrenite Boot Menu na vaÅ¡em ureÄ‘aju držanjem dugmeta volume down dok pritiskate dugme Power i tekst na vrhu će prikazati status S-OFF ili S-ON. Potpun "Root" obiÄno znaÄi S-OFF. +

    Više informacija možete pronaći na www.addictivetips.com. Dodatne S-OFF metode od Unrevokable (na linku) vas mogu zanimati, imenom: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine...

    + +

    Rešenje

    +

    Preduslov: Morate da instalirate Android SDK sa ADB-om na vaš PC

    +
      +
    1. Pokrenite "Boot Menu" na vašem uređaju držanjem volume down dugme dok pritiskate "power" dugme.
    2. +
    3. Koristite volume down dugme da selektujete recovery, zatim power da udjete u njega.
    4. +
    5. U clockwork recovery-u udjite u "partitions menu".
    6. +
    7. Selektujte mount /system, mount /sdcard i mount /data.
    8. +
    9. PrikljuÄite svoje USB kabl i zatim otvoride command line na svom raÄunaru.
    10. +
    11. Otvorite adb shell i ukucajte ln -s /data/hosts /system/etc/hosts (Ovo kreira symbolic link, koji doyvoljava AdAway-u da edituje host file saÄuvan u /data istovremeno dozvoljavajući OS-u da koristi fajl kao da je saÄuvan u /system.)
    12. +
    13. Restartujte svoj uredjaj i namestite Target hosts file na /data/hosts u AdAway's podešavanjima.
    14. +
    15. AdAway bi trebalo da radi sada.
    16. +
    + + diff --git a/app/src/main/res/raw-sv/help_faq.html b/app/src/main/res/raw-sv/help_faq.html new file mode 100644 index 0000000..5571887 --- /dev/null +++ b/app/src/main/res/raw-sv/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Annonsinkomster

    +

    Det finns en vanlig missuppfattning om att en användare som aldrig klickar på annonser inte skadar en webbsida eller applikation ekonomiskt genom att blockera annonser helt. Detta är fel, utvecklare får även betalt för att annonser visas. Det är upp till dig om du blockerar annonser eller ej. Personligen skulle jag inte använda applikationer som visar annonser eftersom jag tycker det är mycket irriterande, så utan en annonsblockerare skulle jag inte installera dessa applikationer.

    + +

    Hur fungerar AdAway?

    +

    AdAway använder värdfilen till att blockera värdnamn som skickar ut annonser. Värdfilen är en fil du hittar i /system/etc/hosts som översätter värdnamn till IP-adresser. Det är ett vanligt sätt att definiera värdnamnet till IP-adress utan att vara beroende av domännamnsystemet (DNS). Alla oönskade värdnamn skickas till 127.0.0.1 vilket innebär att de i stället pekar till din enhet..
    +Om värdfilen är skrivskyddad används en inbyggd VPN-tjänst som en reservlösning. Det filtrerar anslutningar till oönskade värdnamn och låter andra gå igenom.

    + +

    Varför måste jag starta om Android för att de nya ändringarna ska träda i kraft?

    +

    Java i Android tar hand om sin egna interna DNS-cache. Operativsystemet kommer att återspegla den nya värdfilen direkt (du kan kontrollera det med ping på kommandoraden) men du måste starta om Android för att återskapa DNS-cachen i Java.

    + +

    Hur använder man webbservern i AdAway?

    +

    AdAway fungerar utan att använda en webbserver! +

    Du kan aktivera en lokal webbserver i inställningarna för AdAway som kan svara på den lokala IP-adressen 127.0.0.1. Detta innebär att förfrågningar till appens annonsservrar skickas till 127.0.0.1 och i stället svarar AdAways webbserver. +
    En del applikationer vägrar fungera när annonsservern inte går att nå. Med denna metod kommer de att bli nåbara igen, men en tom sida utan annonser kommer att visas.

    + +

    Hur kan jag blockera/tillåta enskilda värdnamn?

    +

    Lägg till värdnamn som du vill blockera till Blockerad från hemskärmen. Dessutom kan värdnamn som du vill utesluta från blockering läggas till i Tillåtna och värdnamn som du vill omdirigera till ett specifik IP-adress tillhör Omdirigerad.

    + +

    Var hittar jag fler värdkällor?

    +

    Gå till Lista över ytterligare värdkällor för AdAway.

    + +

    Hjälp till att översätta/rapportera fel

    +

    GÃ¥ till https://adaway.org.

    + + diff --git a/app/src/main/res/raw-sv/help_problems.html b/app/src/main/res/raw-sv/help_problems.html new file mode 100644 index 0000000..0660b45 --- /dev/null +++ b/app/src/main/res/raw-sv/help_problems.html @@ -0,0 +1,36 @@ + + + +Vanliga problem + +

    Kopiering av värdfil misslyckades på Android 9+

    +

    På senaste versionen av Android är /system-partitionen skrivskyddad.
    +Om du använder Magisk som din root-hanterare, se då till att du aktiverar modulen systemless hosts och sen startar om.

    + +

    Inte tillräckligt med utrymme på partitionen

    +

    Försök ändra målvärdfilen i inställningar till /data/data/hosts (eller /data/hosts) och verkställ AdAway igen.

    + +

    Fungerar ej på Android 4.4+

    +

    Se till att du inaktiverar lite mode (kallades tidigare för datasparare) från Chrome-inställningar. Den här funktionen gör det möjligt för Chrome att använda privat DNS-lösning och gå förbi AdAway.

    + +

    Den blockerar inte annonser i applikationen XYZ!

    +

    Vissa värdnamn kan saknas i de medföljande värdfilerna från Hosts Sources eller programmet har buntat bilderna för att ge annonser utan att komma åt internet.

    +YDu kan logga DNS-förfrågningar (Meny->logga DNS-förfrågningar) från AdAway för att ta reda på vilka ytterligare värdnamn som måste blockeras. +

    Lägg till misstänkta värdnamn i din egen svarta lista genom att länge trycka på posterna i loggen och rapportera dessa värdnamn när du har verifierat dem i vår GitHub issue tracker.

    + +

    Cachade annonser

    +

    Ibland cachar applikationer sina annonser efter hämtning. Detta leder till att annonserna finns kvar i vissa applikationer. Du kan testa att rensa cache för applikationen i Androids Applista för att kringgå detta problem.

    + +

    Applikation XYZ fungerar inte längre!

    +

    En del applikationer måste kommunicera med ett värdnamn som är blockerad av AdAway eller så vägrar de att fungera när värdnamnet som skickar annonser inte går att nå. Gå till https://github.com/AdAway/AdAway/wiki/ProblematicApps för en lista över kända applikationer som har detta problemet. Annars, ta reda på vilka värdnamn som behövs och lägg till dem till din Vitlista under Dina listor och rapportera dem till felsökaren för AdAway.

    + +

    Fungerar inte på Android 4.4+

    +

    Prova med att ändra målvärdfilen i inställningar från /data/data/hosts till /data/hosts eller /system/etc/hosts och verkställ AdAway igen.

    + +

    Bakåtknappen i webbläsaren fungerar inte

    +

    Du kan aktivera AdAways lokala webbserver i inställningarna för att komma förbi problemet.

    + + + diff --git a/app/src/main/res/raw-sv/help_s_on_s_off.html b/app/src/main/res/raw-sv/help_s_on_s_off.html new file mode 100644 index 0000000..f65875d --- /dev/null +++ b/app/src/main/res/raw-sv/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON relaterad hjälp + +

    HTC-enheter

    +

    AdAway fungerar inte när du använder en enhet med så kallad S-ON. Denna "egenskap" finns på många HTC-enheter och hindrar AdAway från att skriva till värdfilen.

    + +

    S-ON/S-OFF?

    +

    S-OFF betyder att NAND-delen av enheten är upplåst och kan skrivas till. Standardvärdet för HTC-enheter är S-ON, vilket betyder att du inte har tillgång till vissa delar av systemet inte heller kan permanent root garanteras. Vidare är signaturkontroll av mjukvaruavbilder garanterad av S-ON-flaggan.

    + +

    Har jag S-ON eller S-OFF?

    +

    Boota till boot-menyn på enheten genom att hålla nere volym ned-knappen samtidigt med på/av-knappen och texten längst upp på skärmen kommer att visa flaggans status som antingen S-OFF eller S-ON. En total rootning innebär generellt sett S-OFF. +

    Mer information kan hittas på www.addictivetips.com. Fler S-OFF-metoder sedan "Unrevokable" (i länk) kanske intresserar dig, närmare: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Tillfällig lösning

    +

    Förutsättning: Du måste installera en fungerade Android SDK med ADB på din PC.

    +
      +
    1. Starta upp i Boot-menyn på din enhet genom att hålla in knappen volym ner medans du trycker på strömknappen.
    2. +
    3. Använd volym ner för att välja recovery sen ström för att starta det.
    4. +
    5. I clockwork recovery gå till "partitions menu".
    6. +
    7. Välj mount /system, mount /sdcard och mount /data.
    8. +
    9. Anslut din USB-kabel och öppna kommandotolken på din PC.
    10. +
    11. Öppna "adb shell" och skriv ln -s /data/hosts /system/etc/hosts (Detta skapar en symbolisk länk, vilket tillåter AdAway att redigera hosts-filen i /data medan operativsystemet tillåts använda filen som om den ligger i /system.)
    12. +
    13. Starta om din enhet och ställ in Målvärdfil till /data/hosts i AdAway's inställningar.
    14. +
    15. AdAway borde nu fungera.
    16. +
    + + diff --git a/app/src/main/res/raw-ta/help_faq.html b/app/src/main/res/raw-ta/help_faq.html new file mode 100644 index 0000000..20f6721 --- /dev/null +++ b/app/src/main/res/raw-ta/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    விளமà¯à®ªà®°à®™à¯à®•ள௠மூலம௠வரà¯à®®à®¾à®©à®®à¯

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ta/help_problems.html b/app/src/main/res/raw-ta/help_problems.html new file mode 100644 index 0000000..5c7a5df --- /dev/null +++ b/app/src/main/res/raw-ta/help_problems.html @@ -0,0 +1,36 @@ + + + +பொதà¯à®µà®¾à®© பிரசà¯à®šà®©à¯ˆà®•ள௠+ +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    பகà¯à®¤à®¿à®•ளாகப௠பிரிகà¯à®• இடம௠போதாதà¯

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    ஆணà¯à®Ÿà¯à®°à®¾à®¯à¯à®Ÿà¯ 4.4 மறà¯à®±à¯à®®à¯ அதறà¯à®•௠மேல௠வேலை செயà¯à®¯à®¾à®¤à¯

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-ta/help_s_on_s_off.html b/app/src/main/res/raw-ta/help_s_on_s_off.html new file mode 100644 index 0000000..e5f4f6a --- /dev/null +++ b/app/src/main/res/raw-ta/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC சாதனஙà¯à®•ளà¯

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-th/help_faq.html b/app/src/main/res/raw-th/help_faq.html new file mode 100644 index 0000000..502af5e --- /dev/null +++ b/app/src/main/res/raw-th/help_faq.html @@ -0,0 +1,31 @@ + + + +ถาม-ตอบ + +

    รายได้จาà¸à¸à¸²à¸£à¹‚ฆษณา

    +

    มีความเข้าใจผิดที่ระบุบ่อยๆว่าหาà¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¹„ม่เคยคลิà¸à¹‚ฆษณาà¸à¸²à¸£à¸›à¸´à¸”à¸à¸±à¹‰à¸™à¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸”ังà¸à¸¥à¹ˆà¸²à¸§à¸ˆà¸°à¹„ม่ส่งผลเสียหายต่อไซต์หรือà¹à¸­à¸žà¸žà¸¥à¸´à¹€à¸„ชันทางà¸à¸²à¸£à¹€à¸‡à¸´à¸™ ซึ่งเป็นสิ่งที่ผิดนัà¸à¸žà¸±à¸’นายังมีรายได้ด้วยà¸à¸²à¸£à¹à¸ªà¸”งโฆษณา ทั้งนี้ขึ้นอยู่à¸à¸±à¸šà¸„ุณว่าคุณบล็อà¸à¹‚ฆษณาหรือไม่ ส่วนตัวฉันจะไม่ใช้à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันที่à¹à¸ªà¸”งโฆษณาเนื่องจาà¸à¸žà¸šà¸§à¹ˆà¸²à¸™à¹ˆà¸²à¸£à¸³à¸„าà¸à¸¡à¸²à¸à¸”ังนั้นหาà¸à¹„ม่มีตัวบล็อà¸à¹‚ฆษณาฉันจะไม่ติดตั้งà¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันเหล่านี้

    + +

    AdAway นี้ทำงานอย่างไร?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    ทำไมถึงต้องรีสตาร์ทเพื่อให้มีผลเปลี่ยนà¹à¸›à¸¥à¸‡?

    +

    Java บน Android มีà¹à¸„ช DNS ภายในของตัวเอง ระบบปà¸à¸´à¸šà¸±à¸•ิà¸à¸²à¸£à¸ˆà¸°à¹à¸ªà¸”งà¹à¸Ÿà¹‰à¸¡ hosts ใหม่ทันที (ตรวจสอบว่ามี ping ในบรรทัดคำสั่ง) à¹à¸•่คุณจะต้องเริ่มต้นใหม่ Android เพื่อสร้างà¹à¸„ช DNS ของ Java

    + +

    วิธีใช้เว็บเซิร์ฟเวอร์ใน AdAway

    +

    AdAway จะทำงานโดยไม่ใช้เว็บเซิร์ฟเวอร์! +

    คุณสามารถเปิดใช้งานเว็บเซิร์ฟเวอร์ในลัà¸à¸©à¸“ะที่ AdAway ต้องà¸à¸²à¸£à¹€à¸žà¸·à¹ˆà¸­à¸•อบรับคำขอไปยังที่อยู่ IP ในเครื่อง 127.0.0.1ซึ่งหมายถึงคำขอจาà¸à¹à¸­à¸žà¸¯à¸—ี่ปà¸à¸•ิจะส่งไปเว็บโฆษณาจะถูà¸à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹€à¸ªà¹‰à¸™à¸—างไปยัง 127.0.0.1
    ดังนั้นจะทำให้พวà¸à¹‚ฆษณาจะไม่สามารถใช้งานได้

    + +

    บล็อคหรือปลดบล็อคชื่อโฮสต์?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    ฉันสามารถหาà¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาของโฮสต์ได้จาà¸à¸—ี่ไหน?

    +

    ดู รายชื่อà¹à¸«à¸¥à¹ˆà¸‡à¹‚ฮสต์เพิ่มเติมจาภAdAway.

    + +

    ช่วยà¹à¸›à¸¥à¸ à¸²à¸©à¸²/รายงานบัค

    +

    à¸à¸£à¸¸à¸“าไปยังเว็บไซต์ https://adaway.org.

    + + diff --git a/app/src/main/res/raw-th/help_problems.html b/app/src/main/res/raw-th/help_problems.html new file mode 100644 index 0000000..9e4f2e0 --- /dev/null +++ b/app/src/main/res/raw-th/help_problems.html @@ -0,0 +1,36 @@ + + + +ปัà¸à¸«à¸²à¸—ี่พบบ่อย + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    เนื้อที่ไม่พอ

    +

    ลองเปลี่ยนไฟล์เป้าหมายโฮสต์ในตั้งค่าไปที่ /data/data/hosts (หรือ /data/hosts) à¹à¸¥à¸°à¹ƒà¸Šà¹‰ AdAway อีà¸à¸„รั้ง

    + +

    Chrome still displays ads

    +

    Ensure you disable lite mode (previously known as data saver) from Chrome settings. This features allows Chrome to use private DNS solution and bypass AdAway.

    + +

    AdAway ไม่รองรับà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¹‚ฆษณาในà¹à¸­à¸žà¸žà¸¥à¸´à¹€à¸„ชั่น XYZ

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in our GitHub issue tracker.

    + +

    มีà¸à¸²à¸£à¹€à¸à¹‡à¸šà¹‚ฆษณาไว้ในà¹à¸„ช

    +

    บางครั้งà¹à¸­à¸žà¸žà¸¥à¸´à¹€à¸„ชันà¹à¸„ชโฆษณาหลังจาà¸à¸”าวน์โหลด ซึ่งนำไปสู่à¸à¸²à¸£à¹‚ฆษณาที่เหลืออยู่ในบางà¹à¸­à¸žà¸žà¸¥à¸´à¹€à¸„ชัน คุณสามารถลองลบà¹à¸„ชสำหรับà¹à¸­à¸žà¸žà¸¥à¸´à¹€à¸„ชันเหล่านี้ในรายà¸à¸²à¸£à¹à¸­à¸žà¸žà¸¥à¸´à¹€à¸„ชันของà¹à¸­à¸™à¸”รอยด์เพื่อหลีà¸à¹€à¸¥à¸µà¹ˆà¸¢à¸‡à¸›à¸±à¸à¸«à¸²à¸™à¸µà¹‰

    + +

    à¹à¸­à¸žà¸žà¸¥à¸´à¹€à¸„ชั่น XYZ ไม่ทำงาน

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    ไม่รองรับระบบปà¸à¸´à¸šà¸±à¸•ิà¸à¸²à¸£ à¹à¸­à¸™à¸”รอยด์ 4.4 ขึ้นไป

    +

    ลองเปลี่ยนเป้าหมายไฟล์โฮสต์ในà¸à¸²à¸£à¸•ั้งค่าจาà¸/data/data/hosts เป็น /data/hosts หรือ /system/etc/hosts à¹à¸¥à¸°à¹ƒà¸Šà¹‰ AdAway อีà¸à¸„รั้ง

    + +

    à¸à¸”ปุ่มย้อนà¸à¸¥à¸±à¸šà¸«à¸²à¸à¹€à¸šà¸£à¸²à¹€à¸‹à¸­à¸£à¹Œà¹„ม่ทำงาน

    +

    คุณสามารถเปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ AdAway ได้จาภเว็บเซิร์ฟเวอร์ท้องถิ่นในà¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ลัà¸à¸©à¸“ะเป็นà¸à¸²à¸£à¹à¸à¹‰à¸›à¸±à¸à¸«à¸²

    + + + diff --git a/app/src/main/res/raw-th/help_s_on_s_off.html b/app/src/main/res/raw-th/help_s_on_s_off.html new file mode 100644 index 0000000..1b9b4b4 --- /dev/null +++ b/app/src/main/res/raw-th/help_s_on_s_off.html @@ -0,0 +1,33 @@ + + + +ความช่วยเหลือเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸š S-ON + +

    โทรศัพท์ HTC

    +

    AdAway ไม่สามารถใช้งานได้เนื่องจาà¸à¸„ุณà¸à¸³à¸¥à¸±à¸‡à¹ƒà¸Šà¹‰ "S-ON" คุณลัà¸à¸©à¸“ะนี้มีอยู่ในอุปà¸à¸£à¸“์ HTC จำนวนมาà¸à¹à¸¥à¸°à¸›à¹‰à¸­à¸‡à¸à¸±à¸™ AdAway ไม่ให้เขียนไฟล์ hosts

    + +

    S-ON/S-OFF?

    +

    "S-OFF" หมายถึง หน่วยความหลัà¸à¸ˆà¸³à¹ƒà¸™à¸­à¸¸à¸›à¸à¸£à¸“์ที่สามารถเข้าถึงà¹à¸¥à¸°à¹à¸à¹‰à¹„ขข้อมูลได้. ค่ามาตรà¸à¸²à¸™à¸‚อง HTC จะเป็น "S-ON" นั่นคืออุปà¸à¸£à¸“์นั้นไม่สามารถเข้าถึงหน่วยความจำหลัà¸à¹„ด้ à¹à¸¥à¸°à¹„ด้รับà¸à¸²à¸£à¸£à¸±à¸šà¸£à¸­à¸‡à¹€à¸£à¸·à¹ˆà¸­à¸‡à¸à¸²à¸£ รูท นอà¸à¸ˆà¸²à¸à¸™à¸µà¹‰à¸¢à¸±à¸‡à¹ƒà¸Šà¹‰à¹€à¸Ÿà¸´à¸£à¹Œà¸¡à¹à¸§à¸£à¹Œà¹€à¸žà¸·à¹ˆà¸­à¸•รวจสอบลายเซนต์ว่าเป็น "S-ON" หรือไม่

    + +

    ฉันมี S-ON หรือ S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    วิธีà¹à¸à¹‰à¸›à¸±à¸à¸«à¸²

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. เริ่มต้นที่หน้าบูตในอุปà¸à¸£à¸“์ของคุณโดยà¸à¸²à¸£à¸à¸” ปุ่มลดเสียง ค้างไว้à¹à¸¥à¹‰à¸§à¸à¸”ปุ่มพาวเวอร์
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. เลือภmount /system,mount /sdcard à¹à¸¥à¸° mount /data +
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. ป้อน adb shell à¹à¸¥à¹‰à¸§à¸•ามด้วย ln -s /data/hosts /system/etc/hosts (ซึ่งจะสร้างลิงà¸à¹Œà¹€à¸ªà¸¡à¸·à¸­à¸™à¸‹à¸¶à¹ˆà¸‡à¸Šà¹ˆà¸§à¸¢à¹ƒà¸«à¹‰ AdAway สามารถà¹à¸à¹‰à¹„ขไฟล์โฮสต์ที่เà¸à¹‡à¸šà¹„ว้ใน /data ได้ในขณะที่อนุà¸à¸²à¸•ให้ระบบปà¸à¸´à¸šà¸±à¸•ิà¸à¸²à¸£à¹ƒà¸Šà¹‰à¹„ฟล์เสมือนà¸à¸±à¸šà¸—ี่ถูà¸à¹€à¸à¹‡à¸šà¹„ว้ใน /system +
    12. +
    13. รีบูตอุปà¸à¸£à¸“์à¹à¸¥à¸°à¸•ั้ง à¸à¸³à¸«à¸™à¸”เป้าหมายไฟล์ hosts ไปยัง /data/hosts2 ในตั้งค่าของà¹à¸­à¸žà¸¯ AdAway
    14. +
    15. AdAway ควรทำงานได้à¹à¸¥à¹‰à¸§
    16. +
    + + diff --git a/app/src/main/res/raw-tl/help_faq.html b/app/src/main/res/raw-tl/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-tl/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-tl/help_problems.html b/app/src/main/res/raw-tl/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-tl/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-tl/help_s_on_s_off.html b/app/src/main/res/raw-tl/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-tl/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-tr/help_faq.html b/app/src/main/res/raw-tr/help_faq.html new file mode 100644 index 0000000..767c16d --- /dev/null +++ b/app/src/main/res/raw-tr/help_faq.html @@ -0,0 +1,32 @@ + + + +SSS + +

    Reklamlardan gelen gelirler

    +

    Bir kullanıcı hiçbir reklamı zaten tıklamıyor ve reklamları engelliyorsa bunun siteyi ya da uygulamayı zarara sokmayacağı gibi bir yanlış anlaşılma var. Geliştiriciler sadece reklamları göstererek bile para kazanabiliyor. Kişisel olarak ben reklam gösteren uygulamaları kullanmam çünkü çok sinir bozucu olabiliyorlar. Bu yüzden bir reklam engelleyici olmadan bu programları yüklemem.

    + +

    AdAway nasıl çalışır?

    +

    AdAway, reklam sunan ana makine adlarını engellemek için hosts dosyasını kullanır. Hosts dosyası, /system/etc/hosts konumunda bulunan ve ana makine adlarını IP adresleriyle eşleyen bir dosyadır. Etki Alanı Adı Sistemi'ne (DNS) dayanmadan IP adresi çiftlerine anasistem adı tanımlamanın geleneksel bir yoludur. Tüm istenmeyen ana bilgisayar adları 127.0.0.1'e yönlendirilir, bu da kendi cihazınızı gösterecekleri anlamına gelir.
    +Hosts dosyası yazılabilir değilse, yerleşik VPN hizmetini kullanmak için bir yedek çözümdür. İstenmeyen ana bilgisayar adlarına bağlantıları filtreleyecek ve başkalarının geçmesine izin verecektir.

    + +

    Neden değişikliklerin uygulanması için Androidi yeniden başlatmalıyım?

    +

    Android üzerinde Java'nın korumalı kendi iç DNS ön belleği vardır. İşletim sistemi yeni sunucu dosyasını hemen oluşturacaktır (komut satırı üzerinde ping ile doğrulanır) fakat Java DNS önbelleğinin yeniden derlenmesi için Android yeniden başlatılmalıdır.

    + +

    AdAway içinde web sunucusu nasıl kullanılır?

    +

    AdAway, web sunucu olmadan da çalışabilmektedir! +

    Yerel IP adresinizden 127.0.0.1 gelen isteklere cevap vermek için AdAway seçeneklerinden yerel web sunucu'yu aktifleştirebilirsiniz. Bu, 127.0.0.1'e yönlendirilmiş uygulama isteklerini AdAway web sunucuları cevaplandıracaktır. +
    Bazı uygulamalar, web sunucuya ulaşılamadığında çalışmamaktadır. Bu yöntemle istek, boş ve reklamsız bir sayfa ile cevaplanır ve böylece web sunucular ulaşılabilir durumda olmaktadır.

    + +

    Özel alanadlarını nasıl engelleyip/engelini kaldırabilirim?

    +

    Engellemek istediğiniz ana makine adlarını ana ekrandan Engellenenler listesine ekleyin. Ayrıca, engellemeden hariç tutmak istediğiniz ana makine adları İzin Verilenlere eklenebilir ve Yönlendirilen'e ait belirli bir IP adresine yönlendirmek istediğiniz ana makine adları eklenebilir.

    + +

    Daha fazla sunucu kaynağını nereden bulabilirim?

    +

    Lütfen AdAway için daha fazla kaynak adresi listesine bakınız .

    + +

    Çeviriye yardım et/hata raporla

    +

    Lütfen adrese gidin https://adaway.org.

    + + diff --git a/app/src/main/res/raw-tr/help_problems.html b/app/src/main/res/raw-tr/help_problems.html new file mode 100644 index 0000000..49d4090 --- /dev/null +++ b/app/src/main/res/raw-tr/help_problems.html @@ -0,0 +1,36 @@ + + + +Ortak sorunlar + +

    Hosts dosyasının kopyası Android 9+ sürümünde başarısız

    +

    Android'in en son sürümlerinde salt okunur /system bölümü kullanılır.
    +Kök erişimi çözümü olarak Magisk kullanıyorsanız, sistemsiz hosts modülünü etkinleştirdiğinizden emin olun ve yeniden başlatın.

    + +

    Bölümde yeterli alan yok

    +

    Tercihler doğrultusunda ayarlardan hedef host kaynak dosyasını /data/data/hosts (veya /data/hosts) olarak değiştirin ve AdAway'i tekrar uygulayın.

    + +

    Chrome hala reklam gösteriyor

    +

    Chrome ayarlarından lite modunu (daha önce veri tasarrufu olarak biliniyordu) devre dışı bıraktığınızdan emin olun. Bu özellikler Chrome'un özel DNS çözümünü kullanmasına ve AdAway'i atlatmasına olanak tanır.

    + +

    XYZ! uygulamasındaki reklamları engellemez!

    +

    Bazı ana bilgisayar adları, Hosts Kaynaklarından sağlanan hosts dosyalarında eksik olabilir veya uygulama, internete erişmeden reklam sağlamak için görüntüleri bir araya getirmiştir.

    +Hangi ek host adlarının engellenmesi gerektiğini öğrenmek için AdAway'den DNS isteklerini (Menü0->DNS İsteklerini Günlüğe Kaydet) AdAway'den kaydedebilirsiniz. +

    Günlükteki girişlere uzun süre basarak şüpheli ana makine adlarını kendi Kara Listenize ekleyin ve GitHub sorun izleyicimizde doğruladığınız zaman bu ana makine adlarını bildirin.

    + +

    Önbelleğe Alınmış Reklamlar

    +

    Bazen yüklemeden sonra uygulamalar reklamları önbelleğe ekleyebilir. Bu bazı uygulamalarda reklam görülmesine neden olabilir. Bu uygulamaların önbelleklerini Android'in uygulama listesine giderek temizleyebilir ve bu sorunu çözebilirsiniz.

    + +

    XYZ uygulaması artık çalışmıyor!

    +

    Bazı uygulamalar AdAway tarafından engellenmiş sunucu adlarıyla iletişim kurmalıdır, reklam servisi için kullanılan sunucu adına ulaşamazsa çalışmayı reddeder. Bu soruna sahip bilinen uygulamaların listesi için https://github.com/dschuermann/ad-away/wiki/ProblematicApps adresine bakın. Bunun dışında, hangi sunucu adlarının gerekli olduğunu bulun ve Beyazlisteye ekleyin, bu liste Listeleriniz altındadır ve AdAway'in hata izleyicisine bildirin.

    + +

    Android 4.4+ sürümlerinde çalışmaz

    +

    Ayarlardan host kaynak dosya ayarını /data/data/hosts'dan /data/hosts ya da/system/etc/hosts'a değiştirin ve AdAway'i tekrar uygulayın.

    + +

    Web tarayıcısında geri tuşu çalışmıyor

    +

    AdAway'in kendi yerel web sunucusunu geçici çözüm olarak tercihlerden etkinleştirebilirsiniz.

    + + + diff --git a/app/src/main/res/raw-tr/help_s_on_s_off.html b/app/src/main/res/raw-tr/help_s_on_s_off.html new file mode 100644 index 0000000..1d54fba --- /dev/null +++ b/app/src/main/res/raw-tr/help_s_on_s_off.html @@ -0,0 +1,33 @@ + + + +S-ON ile ilgili yardım + +

    HTC Cihazlar

    +

    Cihazınızda "S-ON" özelliği kullandığınızda AdAway programı çalışmaz. Bu 'özellik' bir çok HTC markalı cihazda vardır ve AdAway programının sunucu dosyasına (hosts) yazmasını engeller.

    + +

    S-ON/S-OFF NEDİR?

    +

    S-OFF cihazınızda ki NAND bölümünün kilidinin açık olduğu ve üzerine yazılabilir olduğu anlamına gelir. HTC cihazlar için varsayılan ayar S-ON'dur, bu da hem sizin sistemin belli alanlarına erişiminizin olmadığını, hem de kalıcı bir kök erişimini garanti edemeyeceğiniz anlamına gelir. Ayrıca, cihaz yazılımı (firmware) imajları için imza kontrolü de S-ON işaretinin varlığıyla gerçekleştirilir.

    + +

    Cihazım S-ON modunda mı yoksa S-OFF modunda mı?

    +

    Güç tuşuna basarken ses kısma tuşuna basılı tutarak cihazınızda ki Önyükleme Menüsünden önyükleme yapın ve üstteki metin S-OFF veya S-ON olarak durumunu gösterir. Tam bir kök erişimi genellikle S-OFF anlamına gelir

    . +Daha fazla bilgi www.addictivetips.com adresinde bulunabilir. Değiştirilemeyen (bağlantıda) olduğundan sonraki S-OFF yöntemleri ilginizi çekebilir: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Geçici çözüm

    +

    Önkoşul: Bilgisayarınıza ADB kabuğu ile çalışan bir Android SDK yüklemelisiniz.

    +
      +
    1. Güç tuşuna basarken ses kısma tuşuna basılı tutarak cihazınızda ki Önyükleme Menüsünden önyükleme yapın.
    2. +
    3. +Kurtarma moduna geçmek için ses kısma ve güç tuşuna basarak cihazınızı başlatın.
    4. +
    5. Clockwork kurtarma modunda "bölümler menüsü" ne gidin.
    6. +
    7. +mount /system, mount /sdcard ve mount /dataseçin.
    8. +
    9. USB kablonuzu takın ve pc'nizde bir komut satırı açın.
    10. +
    11. Adb kabuğunu girin ve ln -s /data /hosts/system/etc/hosts yazın (Bu, AdAway'in /data'da saklanan sunucu dosyasını düzenlerken, İşletim Sistemi'nin dosyayı /system'da depolanmış gibi kullanmasına izin veren sembolik bir bağlantı oluşturur.)
    12. +
    13. Cihazınızı yeniden başlatın ve AdAway'in tercihlerinde Hedef host dosyasını /data/hosts olarak ayarlayın.
    14. +
    15. AdAway şimdi çalışıyor olmalı.
    16. +
    + + diff --git a/app/src/main/res/raw-uk/help_faq.html b/app/src/main/res/raw-uk/help_faq.html new file mode 100644 index 0000000..2add6a2 --- /dev/null +++ b/app/src/main/res/raw-uk/help_faq.html @@ -0,0 +1,32 @@ + + + +ЧаПи + +

    Прибутки від реклами

    +

    ІÑнує одне поширене переконаннÑ, що Ñкщо кориÑтувач ніколи не натиÑкає на рекламу, то, заблокувавши Ñ—Ñ—, він не завдаÑть фінанÑової шкоди Ñайту чи заÑтоÑункові. Така думка хибна: розробники також зароблÑють гроші на Ñамому показі реклами. Блокувати рекламу, чи ні — вирішувати вам. ОÑобиÑто Ñ Ð½Ðµ Ñтав би викориÑтовувати заÑтоÑунки з рекламою, бо вона дуже дратує, тому без блокувальника реклами Ñ Ð± взагалі не вÑтановлював такі заÑтоÑунки.

    + +

    Як працює AdAway?

    +

    AdAway викориÑтовує файл hosts, щоб блокувати імена хоÑтів, Ñкі забезпечують рекламу. Файли hosts - це файл, Ñкий знаходитÑÑ Ñƒ /system/etc/hosts, Ñкий відображає імена хоÑтів Ñк IP-адреÑи. Це звичайний шлÑÑ…, щоб визначити ім'Ñ Ñ…Ð¾Ñта Ð´Ð»Ñ Ð¿Ð°Ñ€ IP-адреÑ, не покладаючиÑÑŒ на ÑиÑтему доменних імен (DNS). Ð’ÑÑ– небажані імена хоÑтів буде перенаправлено до 127.0.0.1, що означає, що вони будуть направлені до вашого приÑторю.
    +Якщо файл hosts неможливо редагувати, іншим рішеннÑм Ñ” викориÑÑ‚Ð°Ð½Ð½Ñ Ð²Ð±ÑƒÐ´Ð¾Ð²Ð°Ð½Ð¾Ñ— Ñлужби VPN. Він буде фільтрувати з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· небажаними іменами хоÑтів Ñ– пропуÑкати інші.

    + +

    Чому треба перезавантажувати приÑтрій, щоб зміни вÑтупили в Ñилу?

    +

    Java в Android має Ñвій внутрішній кеш DNS. Операційна ÑиÑтема буде викориÑтовувати оновлений файл hosts відразу ж (можете в цьому переконатиÑÑ Ð·Ð° допомогою команди PING в командному Ñ€Ñдку), але ви повинні перезавантажити приÑтрій, щоб наново Ñтворити кеш DNS в Java.

    + +

    Як викориÑтовувати веб-Ñервер в AdAway?

    +

    AdAway також буде працювати без викориÑÑ‚Ð°Ð½Ð½Ñ Ð²ÐµÐ±-Ñервера! +

    Ви можете увімкнути локальний веб-Ñервер в налаштуваннÑÑ… AdAway, Ñкий буде відповідати на запити до локальної IP-адреÑи 127.0.0.1. Це означає, що вÑÑ– запити заÑтоÑунка до хоÑтів з рекламою, Ñкі перенаправлÑютьÑÑ Ð½Ð° ваш локальний IP-Ð°Ð´Ñ€ÐµÑ 127.0.0.1, будуть оброблÑтиÑÑ Ð²ÐµÐ±-Ñервером AdAway. +
    ДеÑкі заÑтоÑунки відмовлÑютьÑÑ Ð¿Ñ€Ð°Ñ†ÑŽÐ²Ð°Ñ‚Ð¸, Ñкщо хоÑти з рекламою не доÑтупні. Цей метод дозволить запуÑкати такі заÑтоÑунки, але заміÑть реклами буде пуÑте міÑце без зображень з рекламою.

    + +

    Як Ñ Ð¼Ð¾Ð¶Ñƒ блокувати/розблоковувати конкретне ім'Ñ Ñ…Ð¾Ñта?

    +

    Імена хоÑтів, Ñкі ви хочете заблокувати потрібно додати до Чорного ÑпиÑку, Ñкий знаходитьÑÑ Ð½Ð° головному екрані. Також, імена хоÑтів, Ñкі не потрібно блокувати, потрібно додавати в Білий ÑпиÑок, а імена хоÑтів, Ñкі потрібно перенаправити на конкретний IP-адреÑ, потрібно внеÑти в СпиÑок перенаправлень.

    + +

    Де Ñ Ð¼Ð¾Ð¶Ñƒ знайти більше ÑпиÑків заблокованих хоÑтів?

    +

    ПереглÑньте додаткові ÑпиÑки заблокованих хоÑтів Ð´Ð»Ñ AdAway.

    + +

    Допомогти з перекладом/повідомити про помилку

    +

    Перейдіть на Ñайт AdAway.

    + + diff --git a/app/src/main/res/raw-uk/help_problems.html b/app/src/main/res/raw-uk/help_problems.html new file mode 100644 index 0000000..ad4aba4 --- /dev/null +++ b/app/src/main/res/raw-uk/help_problems.html @@ -0,0 +1,36 @@ + + + +ЧаÑті проблеми + +

    Ðе вдаєтьÑÑ Ñкопіювати файл hosts на Android 9+

    +

    Ð’ оÑтанніх верÑÑ–ÑÑ… Android розділ /system доÑтупний лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ.
    +Якщо у Ð²Ð°Ñ Ð²Ñтановлений рут через Magisk, тоді увімкніть модуль позаÑиÑтемних хоÑтів (в налаштуваннÑÑ… Magisk Manager), а потім перезавантажте приÑтрій.

    + +

    Ðе виÑтачає міÑÑ†Ñ Ð½Ð° розділі

    +

    Спробуйте змінити шлÑÑ… до файлу hosts в налаштуваннÑÑ… на /data/data/hosts (або /data/hosts) Ñ– знову заÑтоÑуйте AdAway.

    + +

    Ðе працює на Ðндроїд 4.4+

    +

    Спробуйте змінити шлÑÑ… до файлу hosts в налаштуваннÑÑ… з /data/data/hosts на /data/hosts або /system/etc/hosts Ñ– знову заÑтоÑуйте AdAway.

    + +

    Ðе блокуєтьÑÑ Ñ€ÐµÐºÐ»Ð°Ð¼Ð° у програмі XYZ!

    +

    ДеÑкі імена хоÑтів можуть бути відÑутні у файлах hosts з Джерел ÑпиÑків хоÑтів, або розробник вбудував зображеннÑ-рекламу у заÑтоÑунок, щоб показувати Ñ—Ñ— без з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· інтернетом.

    +Ви можете веÑти журнал DNS запитів (Меню->Ð–ÑƒÑ€Ð½Ð°Ð»ÑŽÐ²Ð°Ð½Ð½Ñ DNS запитів) в AdAway, щоб дізнатиÑÑ, Ñкі додаткові імена хоÑтів потрібно заблокувати. +

    Додайте підозрілі імена хоÑтів до вашого Чорного ÑпиÑку довгим натиÑканнÑм на Ð·Ð°Ð¿Ð¸Ñ Ñƒ журналі Ñ– повідомте про ці імена піÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк ви підтвердите Ñ—Ñ… на форумі Host Inbox на Ñайті hosts-file.net.

    + +

    Закешована реклама

    +

    ДеÑкі програми кешують рекламу піÑÐ»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ. Через це реклама може залишатиÑÑ Ð² цих програмах. Ви можете Ñпробувати видалити кеш Ð´Ð»Ñ Ñ†Ð¸Ñ… програм в ÑпиÑку програм Android Ð´Ð»Ñ ÑƒÑÑƒÐ½ÐµÐ½Ð½Ñ Ñ†Ñ–Ñ”Ñ— проблеми.

    + +

    Програма XYZ переÑтала працювати!

    +

    ДеÑким програмам необхідно взаємодіÑти з хоÑтами, Ñкі блокує AdAway, Ð´Ð»Ñ Ð½Ð¾Ñ€Ð¼Ð°Ð»ÑŒÐ½Ð¾Ñ— роботи. Вони відмовлÑютьÑÑ Ð¿Ñ€Ð°Ñ†ÑŽÐ²Ð°Ñ‚Ð¸, Ñкщо імена хоÑтів, що Ñлужать рекламою, недоÑтупні. ДивітьÑÑ Ð¿ÐµÑ€ÐµÐ»Ñ–Ðº програм, Ñкі мають такі проблеми https://github.com/AdAway/AdAway/wiki/ProblematicApps. Ð”Ð»Ñ Ð²Ð¸Ñ€Ñ–ÑˆÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð¸, з'ÑÑуйте необхідні програмі імена хоÑтів Ñ– внеÑіть Ñ—Ñ… у ваш Білий ÑпиÑок в пункті меню Ваш ÑпиÑок, піÑÐ»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ відправлÑйте Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñƒ відÑтежувач вад AdAway.

    + +

    Кнопка «ÐÐЗÐД» у веб-браузерах не працює

    +

    Ви можете увімкнути локальний веб-Ñервер AdAway в налаштуваннÑÑ… Ñк обхідний шлÑÑ….

    + +

    Кнопка «ÐÐЗÐД» у веб-браузерах не працює

    +

    Ви можете увімкнути локальний веб-Ñервер AdAway в налаштуваннÑÑ… Ñк обхідний шлÑÑ….

    + + + diff --git a/app/src/main/res/raw-uk/help_s_on_s_off.html b/app/src/main/res/raw-uk/help_s_on_s_off.html new file mode 100644 index 0000000..ade25cb --- /dev/null +++ b/app/src/main/res/raw-uk/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Допомога ÑтоÑовно S-ON + +

    ПриÑтрої HTC

    +

    AdAway не працює на приÑтроÑÑ…, що працюють в режимі S-ON. Ð¦Ñ "оÑобливіÑть" Ñ” в багатьох приÑтроÑÑ… HTC Ñ– не дозволÑÑ” AdAway змінювати файл hosts.

    + +

    S-ON/S-OFF?

    +

    S-OFF означає, що чаÑтина пам'Ñті NAND розблокована Ñ– дозволÑÑ” проводити запиÑ. УÑталено приÑтрої HTC працюють у режимі S-ON, а це означає, що ви не можете отримати доÑтуп до певних облаÑтей пам'Ñті. Крім того, прапорець S-ON перевірÑÑ” цифровий Ð¿Ñ–Ð´Ð¿Ð¸Ñ ÑƒÑÑ–Ñ… прошивок.

    + +

    Чи мій приÑтрій працює у режимі S-ON або S-OFF?

    +

    ЗавантажтеÑÑ Ð´Ð¾ Меню Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð½Ð° приÑтрої, утримуючи кнопку Ð·Ð¼ÐµÐ½ÑˆÐµÐ½Ð½Ñ Ð³ÑƒÑ‡Ð½Ð¾Ñті при натиÑканні кнопки Ð¶Ð¸Ð²Ð»ÐµÐ½Ð½Ñ Ñ– вгорі з'ÑвитьÑÑ Ñ‚ÐµÐºÑÑ‚ Ð¿Ñ€Ð°Ð¿Ð¾Ñ€Ñ†Ñ ÑтатуÑу — S-OFF або S-ON. Повні root права зазвичай означають S-OFF. +

    Докладнішу інформацію можна знайти на www.addictivetips.com. Ð’Ð°Ñ Ð¼Ð¾Ð¶ÑƒÑ‚ÑŒ зацікавити додаткові методи ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ S-OFF, наприклад, Unrevokable (у поÑиланні), а також: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Обхід проблеми

    +

    Вимога: Вам необхідно вÑтановити робочий Android SDK з оболонкою ADB на Ваш комп'ютер.

    +
      +
    1. ЗавантажтеÑÑ Ð´Ð¾ Меню Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ñтрою — утримуючи кнопку Ð·Ð¼ÐµÐ½ÑˆÐµÐ½Ð½Ñ Ð³ÑƒÑ‡Ð½Ð¾Ñті увімкніть приÑтрій кнопкою живленнÑ.
    2. +
    3. ВикориÑтовуйте кнопку Ð·Ð¼ÐµÐ½ÑˆÐµÐ½Ð½Ñ Ð³ÑƒÑ‡Ð½Ð¾Ñті, щоб вибрати режим відновленнÑ.
    4. +
    5. У режимі clockwork recovery кнопкою Ð·Ð¼ÐµÐ½ÑˆÐµÐ½Ð½Ñ Ð³ÑƒÑ‡Ð½Ð¾Ñті виберіть "partitions menu".
    6. +
    7. Виберіть mount /system, mount /sdcard та mount /data.
    8. +
    9. Підключіть ваш телефон до ПК через кабель USB Ñ– відкрийте вікно командного Ñ€Ñдка на ПК.
    10. +
    11. Увійдіть в оболонку adb та введіть команду ln -s /data/hosts /system/etc/hosts (це Ñтворить Ñимволічне поÑиланнÑ, Ñке дозволить AdAway редагувати файл hosts, що зберігаєтьÑÑ Ð² /data, дозволÑючи операційній ÑиÑтемі викориÑтовувати файл, мовби він був збережений в /system).
    12. +
    13. Перезавантажте ваш приÑтрій Ñ– в налаштуваннÑÑ… AdAway змініть Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñƒ ШлÑÑ… до файлу hosts на /data/hosts.
    14. +
    15. Тепер AdAway має запрацювати.
    16. +
    + + diff --git a/app/src/main/res/raw-ur/help_faq.html b/app/src/main/res/raw-ur/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-ur/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-ur/help_problems.html b/app/src/main/res/raw-ur/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-ur/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-ur/help_s_on_s_off.html b/app/src/main/res/raw-ur/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-ur/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-uz/help_faq.html b/app/src/main/res/raw-uz/help_faq.html new file mode 100644 index 0000000..f88c28f --- /dev/null +++ b/app/src/main/res/raw-uz/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw-uz/help_problems.html b/app/src/main/res/raw-uz/help_problems.html new file mode 100644 index 0000000..cf4ffb2 --- /dev/null +++ b/app/src/main/res/raw-uz/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw-uz/help_s_on_s_off.html b/app/src/main/res/raw-uz/help_s_on_s_off.html new file mode 100644 index 0000000..10b59ce --- /dev/null +++ b/app/src/main/res/raw-uz/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/raw-vi/help_faq.html b/app/src/main/res/raw-vi/help_faq.html new file mode 100644 index 0000000..09d8d3a --- /dev/null +++ b/app/src/main/res/raw-vi/help_faq.html @@ -0,0 +1,32 @@ + + + +Há»i đáp + +

    Thu nhập từ quảng cáo

    +

    Có má»™t quan niệm cho rằng nếu ngưá»i dùng không bao giá» nhấp chuá»™t vào quảng cáo thì việc chặn chúng sẽ không làm trang web hoặc ứng dụng bị tổn thất vá» mặt tài chính. Äiá»u này thật sai lầm vì các nhà phát triển cÅ©ng kiếm được tiá»n cho dù chỉ hiển thị quảng cáo. Việc chặn quảng cáo hay không tuỳ thuá»™c vào bạn. Cá nhân tôi sẽ không dùng các ứng dụng có hiển thị quảng cáo bởi vì tôi thấy chúng rất khó chịu, chính vì vậy mà khi không có phần má»m chặn quảng cáo tôi sẽ không cài đặt những ứng dụng này.

    + +

    AdAway hoạt động như thế nào?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Tại sao tôi phải khởi động lại Android để thay đổi có hiệu lực?

    +

    Java trên Android duy trì bá»™ nhá»› đệm DNS bên trong cá»§a chính nó. Hệ Ä‘iá»u hành sẽ phản xạ tập tin tên miá»n má»›i ngay lập tức (xác minh nó vá»›i ping trên dòng lệnh) nhưng bạn cần khởi động lại Android để xây dá»±ng lại bá»™ nhá»› đệm DNS cá»§a Java.

    + +

    Cách sử dụng webserver trong AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    Làm sao có thể chặn/bá» chặn tên miá»n cụ thể?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Tôi có thể tìm thêm các nguồn tên miá»n ở đâu?

    +

    Xem Danh sách tên miá»n được bổ sung cho AdAway.

    + +

    Giúp dịch thuật/báo cáo lỗi

    +

    Xin hãy truy cập vào https://adaway.org.

    + + diff --git a/app/src/main/res/raw-vi/help_problems.html b/app/src/main/res/raw-vi/help_problems.html new file mode 100644 index 0000000..0720efe --- /dev/null +++ b/app/src/main/res/raw-vi/help_problems.html @@ -0,0 +1,36 @@ + + + +Các vấn đỠphố biến + +

    Sao chép tệp miá»n thất bại trên Android 9+

    +

    Các phiên bản má»›i nhất cá»§a Android sá»­ dụng phân vùng /system chỉ Ä‘á»c.
    +Nếu bạn đang root bằng Magisk, hãy đảm bảo rằng bạn bật mô-đun systemless hosts và khởi động lại.

    + +

    Không đủ dung lượng trên phân vùng

    +

    Hãy thá»­ đổi tệp miá»n mục tiêu trong cài đặt thành /data/data/hosts (hoặc /data/hosts) và áp dụng lại AdAway.

    + +

    Chrome vẫn hiển thị quảng cáo

    +

    Hãy đảm bảo bạn tắt chế độ lite (trước kia được biết đến là trình tiết kiệm dữ liệu) trong cài đặt của Chrome. Tính năng này cho phép Chrome sử dụng giải pháp DNS riêng và vượt qua AdAway.

    + +

    Nó không chặn quảng cáo trong ứng dụng XYZ!

    +

    Má»™t số tên miá»n có thể bị thiếu trong các tệp miá»n được cung cấp từ Nguồn miá»n hoặc ứng dụng đó đã tích hợp các hình ảnh để cung cấp quảng cáo mà không truy cập internet.

    +Bạn có thể ghi nhật ký các yêu cầu DNS (Menu->Ghi nhật ký các yêu cầu DNS) từ AdAway để tìm xem những tên miá»n bổ sung nào cần phải bị chặn. +

    Thêm các tên miá»n đáng nghi vào Danh sách Ä‘en cá»§a bạn bằng cách nhấn giữ các mục trong Nhật ký và báo cáo những tên miá»n đó khi bạn đã xác minh chúng trong trình theo dõi vấn đỠtrên GitHub cá»§a chúng tôi.

    + +

    Các quảng cáo đã tạm lưu

    +

    Äôi lúc ứng dụng lưu giữ quảng cáo sau khi tải vá». Äiá»u này dẫn đến quảng cáo vẫn tồn tại trong má»™t vài ứng dụng. Bạn có thể thá»­ xoá bá»™ nhá»› đệm cá»§a những ứng dụng này trong danh sách Ứng dụng cá»§a Android để ngăn chặn tình trạng này.

    + +

    Ứng dụng XYZ không còn hoạt động nữa!

    +

    Má»™t số ứng dụng cần giao tiếp vá»›i tên miá»n bị AdAway chặn hoặc từ chối hoạt động khi không truy cập được các tên miá»n phục vụ quảng cáo. Hãy xem https://github.com/dschuermann/ad-away/wiki/ProblematicApps để xem danh sách các ứng dụng có vấn đỠđã biết. Nếu không, hãy tìm hiểu xem những tên miá»n nào được cần đến và thêm chúng vào Danh sách trắng dưới Danh sách cá»§a bạn và báo cáo chúng trong trình theo dõi lá»—i cá»§a AdAway.

    + +

    Không hoạt động trên Android 4.4+

    +

    Hãy thá»­ đổi tệp miá»n mục tiêu trong cài đặt từ /data/data/hosts thành /data/hosts hoặc /system/etc/hosts và áp dụng lại AdAway.

    + +

    Nút trở vỠtrên trình duyệt hiện không hoạt động

    +

    Bạn có thể bật webserver cục bộ của AdAway trong tuỳ chỉnh để giải quyết.

    + + + diff --git a/app/src/main/res/raw-vi/help_s_on_s_off.html b/app/src/main/res/raw-vi/help_s_on_s_off.html new file mode 100644 index 0000000..ffe2b0d --- /dev/null +++ b/app/src/main/res/raw-vi/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +Trợ giúp liên quan đến S-ON + +

    Các thiết bị HTC

    +

    AdAway sẽ không hoạt động khi thiết bị bạn Ä‘ang sá»­ dụng có S-ON. "Tính năng" này hiện hữu trên nhiá»u thiết bị HTC và ngăn không cho AdAway ghi tập tin tên miá»n.

    + +

    S-ON/S-OFF?

    +

    S-OFF có nghĩa là bộ phận NAND của thiết bị được mở khoá và có thể được ghi đè. Cài đặt mặc định cho các thiết bị HTC là S-ON, nghĩa là bạn không thể truy cập một số khu vực cụ thể của hệ thống lẫn khả năng root máy vĩnh viễn. Hơn nữa, việc kiểm tra chữ ký cho các ảnh phần cứng cũng bị hạn chế bởi cỠS-ON.

    + +

    Thiết bị của tôi là S-ON hay S-OFF?

    +

    Khởi động vào Boot Menu trên thiết bị cá»§a bạn và giữ nút giảm âm lượng đồng thá»i vá»›i nút nguồn và phần văn bản ở phía trên sẽ hiển thị trạng thái flag là S-OFF hoặc S-ON. Root đầy đủ thưá»ng có nghÄ©a là S-OFF. +

    Thông tin thêm có thể được tìm thấy tại www.addictivetips.com. Bổ sung một số cách S-OFF do không thể bị thu hồi (ở link) có thể làm bạn quan tâm, cụ thể: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Giải pháp

    +

    Äiá»u kiện tiên quyết: Bạn cần phải cài đặt Android SDK vá»›i shell ADB trên PC cá»§a bạn.

    +
      +
    1. Khởi động vào Boot Menu trên thiết bị cá»§a bạn và giữ nút giảm âm lượng đồng thá»i vá»›i nút nguồn
    2. +
    3. Sá»­ dụng giảm âm lượng để chá»n recovery rồi nguồn để khởi động nó.
    4. +
    5. Trong clockwork recovery, đi đến "menu phân vùng".
    6. +
    7. Chá»n mount /system, mount /sdcard và mount /data.
    8. +
    9. Cắm dây USB và mở một dòng lệnh trên PC.
    10. +
    11. Nhập adb shell và đánh vào ln -s /data/hosts /system/etc/hosts (Việc này sẽ tạo má»™t liên kết biểu tượng, nó cho phép AdAway chỉnh sá»­a tệp miá»n được lưu trữ trong /data trong khi cÅ©ng cho phép HÄH sá»­ dụng tệp đó như thể nó được lưu trữ trong /system.)
    12. +
    13. Khởi động lại thiết bị và đặt Tệp miá»n mục tiêu thành /data/hosts trong cài đặt cá»§a AdAway.
    14. +
    15. AdAway sẽ hoạt động bình thưá»ng.
    16. +
    + + diff --git a/app/src/main/res/raw-zh-rTW/help_faq.html b/app/src/main/res/raw-zh-rTW/help_faq.html new file mode 100644 index 0000000..f3ce157 --- /dev/null +++ b/app/src/main/res/raw-zh-rTW/help_faq.html @@ -0,0 +1,32 @@ + + + +常見å•題 + +

    廣告收入

    +

    很多人誤以為,如果用戶ä¸é»žæ“Šå»£å‘Šï¼Œé‚£éº¼é˜»æ“‹å®ƒå€‘就䏿œƒå°ç¶²ç«™æˆ–應用程å¼é€ æˆè²¡å‹™æå¤±ã€‚這是錯誤的,開發者僅僅通éŽé¡¯ç¤ºå»£å‘Šä¹Ÿèƒ½è³ºéŒ¢ã€‚是å¦é˜»æ“‹å»£å‘Šå–æ±ºæ–¼ä½ ã€‚æˆ‘å€‹äººä¸æœƒä½¿ç”¨é¡¯ç¤ºå»£å‘Šçš„æ‡‰ç”¨ç¨‹å¼ï¼Œå› ç‚ºæˆ‘覺得它們éžå¸¸ç…©äººï¼Œæ‰€ä»¥å¦‚æžœæ²’æœ‰å»£å‘Šé˜»æ“‹å™¨ï¼Œæˆ‘å°±ä¸æœƒå®‰è£é€™äº›æ‡‰ç”¨ç¨‹å¼ã€‚

    + +

    AdAway 是如何é‹ä½œçš„?

    +

    AdAway 利用 hosts 檔案來阻擋æä¾›å»£å‘Šçš„主機å稱。hosts æª”æ¡ˆæ˜¯ä¸€å€‹ä½æ–¼ /system/etc/hosts 的檔案,用於將主機å稱映射到 IP ä½å€ã€‚這是一種傳統的方å¼ï¼Œç”¨æ–¼å®šç¾©ä¸»æ©Ÿå稱與 IP ä½å€é…å°ï¼Œè€Œä¸ä¾è³´æ–¼ç¶²åŸŸå稱系統(DNSï¼‰ã€‚æ‰€æœ‰ä¸æƒ³è¦çš„主機åç¨±éƒ½æœƒè¢«é‡æ–°å°Žå‘到 127.0.0.1,這æ„味著它們將指å‘你自己的è£ç½®ã€‚
    + 如果 hosts 檔案ä¸å¯å¯«å…¥ï¼Œå‰‡å¯ä»¥ä½¿ç”¨å…§ç½®çš„ VPN æœå‹™ä½œç‚ºå¾Œå‚™è§£æ±ºæ–¹æ¡ˆã€‚å®ƒæœƒéŽæ¿¾åˆ°ä¸æƒ³è¦çš„主機å稱的連接,其他的則å¯ä»¥æ­£å¸¸é€šéŽã€‚

    + +

    為什麼我需è¦é‡æ–°å•Ÿå‹• Android æ‰èƒ½ä½¿è®Šæ›´ç”Ÿæ•ˆï¼Ÿ

    +

    Android 上的 Java æ“æœ‰è‡ªå·±çš„內部 DNS å¿«å–。作業系統將立å³å映新的 hosts 檔案(å¯ä»¥ç”¨å‘½ä»¤åˆ—上的 ping 來驗證),但你需è¦é‡æ–°å•Ÿå‹• Android 以é‡å»º Java çš„ DNS å¿«å–。

    + +

    如何使用 AdAway 中的網é ä¼ºæœå™¨ï¼Ÿ

    +

    AdAway 也å¯ä»¥åœ¨ä¸ä½¿ç”¨ç¶²é ä¼ºæœå™¨çš„æƒ…æ³ä¸‹é‹ä½œï¼ +

    ä½ å¯ä»¥åœ¨ AdAway çš„å好設定中啟用一個本機網é ä¼ºæœå™¨ï¼Œä»¥å›žæ‡‰æŒ‡å‘本機 IP ä½å€ 127.0.0.1 的請求。這æ„味著從應用程å¼åˆ°å»£å‘Šä¼ºæœå™¨çš„è«‹æ±‚ï¼Œå¦‚æžœè¢«é‡æ–°å°Žå‘到 127.0.0.1,將由 AdAway 的網é ä¼ºæœå™¨å›žæ‡‰ã€‚ +
    有些應用程å¼åœ¨å»£å‘Šä¼ºæœå™¨ç„¡æ³•é€£æŽ¥æ™‚æœƒæ‹’çµ•å·¥ä½œã€‚ä½¿ç”¨é€™ç¨®æ–¹æ³•ï¼Œå®ƒå€‘å°‡å†æ¬¡å¯ä»¥é€£æŽ¥ï¼Œä½†æœƒå›žæ‡‰ä¸€å€‹ç©ºç™½é é¢å’Œæ²’有廣告圖片。

    + +

    如何阻擋/å–æ¶ˆé˜»æ“‹ç‰¹å®šä¸»æ©Ÿå稱?

    +

    從主畫é¢çš„阻擋清單裡,您å¯ä»¥åŠ å…¥æ‚¨æƒ³è¦é˜»æ“‹çš„主機å稱。此外,如果有主機åç¨±æ‚¨ä¸æƒ³é˜»æ“‹ï¼Œå¯ä»¥å°‡å…¶åŠ å…¥åˆ°å…許。若您想將特定的主機åç¨±é‡æ–°å°Žå‘至æŸä¸€ç‰¹å®š IP ä½å€ï¼Œå‰‡å°‡å…¶åŠ å…¥åˆ°é‡æ–°å°Žå‘å³å¯ã€‚

    + +

    è¦æ‰¾åˆ°æ›´å¤šçš„ hosts 來æºï¼Œè©²å¦‚何æ“作?

    +

    è«‹åƒè¦‹ AdAway çš„é¡å¤– hosts ä¾†æºæ¸…單。

    + +

    需è¦å¹«åŠ©ç¿»è­¯æˆ–å›žå ±è‡­èŸ²ï¼Ÿ

    +

    è«‹å‰å¾€ https://adaway.org。

    + + diff --git a/app/src/main/res/raw-zh-rTW/help_problems.html b/app/src/main/res/raw-zh-rTW/help_problems.html new file mode 100644 index 0000000..fbb13a2 --- /dev/null +++ b/app/src/main/res/raw-zh-rTW/help_problems.html @@ -0,0 +1,36 @@ + + + +常見å•題 + +

    在 Android 9+ 上複製 hosts 檔案失敗

    +

    新版的 Android 使用唯讀的 /system 分割å€
    。 +如果您使用 Magisk 作為 root 解決方案,請確ä¿å•Ÿç”¨ç„¡ç³»çµ± hosts æ¨¡çµ„ï¼Œç„¶å¾Œé‡æ–°å•Ÿå‹•手機。

    + +

    分割å€ç©ºé–“ä¸è¶³

    +

    嘗試在å好設定中將目標 hosts 檔案更改為 /data/data/hosts(或 /data/hostsï¼‰ï¼Œç„¶å¾Œå†æ¬¡æ‡‰ç”¨ AdAway。

    + +

    Chrome ä»ç„¶é¡¯ç¤ºå»£å‘Š

    +

    請在 Chrome 設定中åœç”¨lite 模å¼ï¼ˆä»¥å‰ç¨±ç‚ºdata saver)。此功能使 Chrome å¯ä»¥ä½¿ç”¨ç§æœ‰ DNS è§£æ±ºæ–¹æ¡ˆï¼Œå¾žè€Œç¹žéŽ AdAway。

    + +

    æŸå€‹æ‡‰ç”¨ç¨‹å¼ä¸­æœªé˜»æ“‹å»£å‘Šï¼

    +

    æŸäº›ä¸»æ©Ÿå稱å¯èƒ½åœ¨ã€Œä¸»æ©Ÿæºã€æ‰€æä¾›çš„ hosts 來æºä¸­ç¼ºå¤±ï¼Œæˆ–者是應用程å¼å°‡å»£å‘Šåœ–片直接嵌入,因此ä¸éœ€è¦ç¶²è·¯å­˜å–。

    +您å¯ä»¥é€éŽ AdAway 的記錄 DNS 請求(é¸å–® -> 記錄 DNS 請求)功能,找出還需è¦è¢«é˜»æ“‹çš„é¡å¤–主機å稱。 +

    é€éŽé•·æŒ‰è¨˜éŒ„中的項目,將å¯ç–‘的主機å稱加入您自己的「黑åå–®ã€ï¼Œä¸¦åœ¨é©—證後報告到我們的 GitHub å•題追蹤系統。

    + +

    已存於快å–中的廣告

    +

    æœ‰æ™‚ï¼Œæ‡‰ç”¨ç¨‹å¼æœƒåœ¨ä¸‹è¼‰å¾Œå¿«å–廣告,導致æŸäº›æ‡‰ç”¨ç¨‹å¼å…§ä»ç„¶å‡ºç¾å»£å‘Šã€‚您å¯ä»¥å˜—試在 Android çš„æ‡‰ç”¨ç¨‹å¼æ¸…單中刪除這些應用程å¼çš„å¿«å–,以解決此å•題。

    + +

    æŸå€‹æ‡‰ç”¨ç¨‹å¼å¤±æ•ˆäº†ï¼

    +

    有些應用程å¼éœ€è¦èˆ‡ AdAway 所阻擋的æŸå€‹ä¸»æ©Ÿå稱進行通訊,或者在應該æä¾›å»£å‘Šçš„主機å稱無法連接時會拒絕é‹è¡Œã€‚è«‹å‰å¾€ https://github.com/AdAway/AdAway/wiki/ProblematicApps 查看已知有å•é¡Œçš„æ‡‰ç”¨ç¨‹å¼æ¸…單。或者,找出需è¦çš„主機å稱並將其加入您的白å單,然後報告到 AdAway çš„å•題追蹤系統。

    + +

    無法在 Android 4.4+ 中執行

    +

    嘗試在å好設定中更改目標 hosts 檔案的路徑,從 /data/data/hosts 改為 /data/hosts 或 /system/etc/hostsï¼Œç„¶å¾Œé‡æ–°å¥—用 AdAway。

    + +

    退出功能在ç€è¦½ç¶²é æ™‚是無效的。

    +

    å¯åœ¨ AdAway 的設定中啟用本地網é ä¼ºæœå™¨ä½œç‚ºè§£æ±ºè¾¦æ³•。

    + + + diff --git a/app/src/main/res/raw-zh-rTW/help_s_on_s_off.html b/app/src/main/res/raw-zh-rTW/help_s_on_s_off.html new file mode 100644 index 0000000..0b6824b --- /dev/null +++ b/app/src/main/res/raw-zh-rTW/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +S-ON 相關的說明 + +

    HTC 的產å“

    +

    AdAway 無法在所謂具有 S-ON 功能的è£ç½®ä¸Šé‹ä½œã€‚這個「功能ã€å­˜åœ¨æ–¼è¨±å¤š HTC è£ç½®ä¸Šï¼Œä¸¦é˜»æ­¢ AdAway 寫入 hosts 檔案。

    + +

    什麼是 S-ON / S-OFF ?

    +

    S-OFF æ„味著è£ç½®çš„ NAND 部分已解鎖,並且å¯ä»¥é€²è¡Œå¯«å…¥ã€‚HTC è£ç½®çš„é è¨­è¨­å®šæ˜¯ S-ON,這æ„味著你既ä¸èƒ½è¨ªå•系統的æŸäº›å€åŸŸï¼Œä¹Ÿä¸èƒ½ä¿è­‰æ°¸ä¹… root。此外,韌體映åƒçš„æ•¸å­—ç°½åæª¢æŸ¥ä¹Ÿç”± S-ON 標誌來確ä¿ã€‚

    + +

    我的是 S-ON 還是 S-OFF?

    +

    在您的è£ç½®ä¸Šï¼ŒæŒ‰ä½éŸ³é‡æ¸›éµçš„åŒæ™‚按下電æºéµä»¥é€²å…¥ã€Œé–‹æ©Ÿé¸å–®ã€ã€‚åœ¨é ‚éƒ¨çš„æ–‡å­—æœƒé¡¯ç¤ºæ——æ¨™ç‹€æ…‹ï¼Œå³æ˜¯ã€ŒS-OFFã€æˆ–「S-ONã€ã€‚一般而言,完全的 root æ¬Šé™æ„味著是「S-OFFã€ã€‚ +

    更多的相關資訊å¯ä»¥åœ¨ www.addictivetips.com 找到。自 Unrevokable(該連çµå…§ï¼‰ä¹‹å¾Œçš„é¡å¤– S-OFF 方法å¯èƒ½æœƒå¼•起您的興趣,包括:Revolutionaryã€Revoneã€Firewaterã€RumRunnerã€Moonshineã€SunShine 等。

    + +

    解決辦法

    +

    å‰æï¼šå¿…é ˆåœ¨é›»è…¦ä¸Šå®‰è£Android SDKï¼ŒåŠæœ‰å¯åŸ·è¡Œçš„ADB 指令介é¢ã€‚

    +
      +
    1. 按ä½é™ä½ŽéŸ³é‡æŒ‰éµä¸æ”¾ä¸¦é–‹å•Ÿæ‰‹æ©Ÿé›»æºï¼Œæ‰‹æ©Ÿæœƒé€²å…¥é–‹æ©Ÿé¸å–®ã€‚
    2. +
    3. 使用 volume down 鏿“‡ recovery 冿Œ‰ä¸‹ power 來啟動。
    4. +
    5. 在 clockwork recovery 中å‰å¾€ "partitions menu".
    6. +
    7. 鏿“‡ mount /system,mount /sdcard ä»¥åŠ mount /data。
    8. +
    9. 在PC上æ’入您的USB傳輸線並開啟命令列。
    10. +
    11. 進入 adb 介é¢ï¼Œè¼¸å…¥ ln -s /data/data/hosts /system/etc/hosts (這會建立一個符號連çµï¼Œè®“ AdAway å¯ä»¥ä¿®æ”¹å­˜æ”¾åœ¨ /data 中的 hosts æª”æ¡ˆï¼ŒåŒæ™‚å…許作業系統使用檔案,如åŒå­˜æ”¾åœ¨ /system 一樣)。
    12. +
    13. 釿–°å•Ÿå‹•ä½ çš„è£ç½®ï¼Œä¸¦ä¸”在 AdAway 的設定中將 目標 hosts 檔案 設定為 /data/hosts。
    14. +
    15. AdAway ç¾åœ¨æ‡‰è©²å¯ä»¥æ­£å¸¸é‹ä½œäº†ã€‚
    16. +
    + + diff --git a/app/src/main/res/raw-zh/help_faq.html b/app/src/main/res/raw-zh/help_faq.html new file mode 100644 index 0000000..01b77fe --- /dev/null +++ b/app/src/main/res/raw-zh/help_faq.html @@ -0,0 +1,32 @@ + + + +常问问题 + +

    广告收入

    +

    通常有一ç§è¯¯è§£è®¤ä¸ºï¼Œå¦‚果用户从æ¥ä¸ç‚¹å‡»å¹¿å‘Šï¼Œé‚£ä¹ˆå±è”½å¹¿å‘Šå¹¶ä¸ä¼šç»™ç½‘站或开å‘人员带æ¥è´¢åŠ¡ä¸Šçš„æŸå¤±ã€‚然而,事实是,仅展示广告也å¯ä»¥ä½¿å¼€å‘人员获得收入。是å¦å±è”½å¹¿å‘Šå–决于你。就我个人æ¥è¯´ï¼Œæˆ‘很讨厌那些展示广告的应用,所以,如果没有广告å±è”½å™¨çš„è¯ï¼Œæˆ‘是ä¸ä¼šå®‰è£…那些应用的。

    + +

    AdAway 是如何è¿ä½œçš„?

    +

    AdAway使用hosts文件阻止æä¾›å¹¿å‘Šçš„主机å。 hosts文件是在/system/etc/hostsä¸­æ‰¾åˆ°çš„æ–‡ä»¶ï¼Œè¯¥æ–‡ä»¶å°†ä¸»æœºåæ˜ å°„到IP地å€ã€‚ 这是一ç§å°†ä¸»æœºå定义为IP 地å€å¯¹çš„传统方法,而无需ä¾èµ–域å系统(DNS)。 所有ä¸éœ€è¦çš„主机å都将é‡å®šå‘到127.0.0.1,这æ„味ç€å®ƒä»¬å°†æŒ‡å‘您自己的设备。
    +如果hosts文件ä¸å¯å†™ï¼Œåˆ™åŽå¤‡è§£å†³æ–¹æ¡ˆæ˜¯ä½¿ç”¨å†…置的VPNæœåŠ¡ã€‚ 它将过滤与ä¸éœ€è¦çš„主机å的连接,并å…许其他主机å通过。

    + +

    为什么我需è¦é‡å¯ Android 以使更改生效?

    +

    Android 上的 Java è¿è¡Œæ—¶ä¼šç»´æŠ¤ä¸€ä»½å†…部 DNS 缓存。新增的 hosts 文件内容将会立å³ç”Ÿæ•ˆï¼ˆå¯åœ¨å‘½ä»¤è¡Œä¸­ä½¿ç”¨ ping 验è¯ï¼‰ï¼Œä½†è‹¥è¦ä½¿å¯¹å·²æœ‰ hosts æ¡ç›®çš„修改生效,需è¦é‡å¯ Android 系统以é‡å»º Java çš„ DNS 缓存。

    + +

    如何在 AdAway 里使用 Web æœåŠ¡å™¨ï¼Ÿ

    +

    å³ä½¿ä¸ä½¿ç”¨ Web æœåŠ¡å™¨åŠŸèƒ½ï¼ŒAdAway ä¹Ÿèƒ½æ­£å¸¸å·¥ä½œï¼ +

    ä½ å¯ä»¥åœ¨ AdAway 的设置里å¯ç”¨ä¸€ä¸ªæœ¬åœ°çš„ Web æœåС噍以å“应对本地 IP 地å€127.0.0.1的请求。对于那些 IP 地å€è¢«é‡å®šå‘到127.0.0.1的广告æœåŠ¡å™¨ï¼Œè¿™æ„å‘³ç€ AdAway çš„ Web æœåŠ¡å™¨ä¼šä»£å¹¿å‘ŠæœåС噍å“应对它们的请求。 +
    当ä¸èƒ½è®¿é—®å¹¿å‘ŠæœåŠ¡å™¨çš„æ—¶å€™ï¼Œä¸€äº›åº”ç”¨ä¼šæ‹’ç»æ­£å¸¸è¿è¡Œã€‚借助这个功能,广告æœåС噍就åˆå¯ä»¥è¢«è¿™äº›åº”用“访问â€äº†â€”—但它们没有访问到真正的广告æœåŠ¡å™¨ï¼Œä¾æ—§æ²¡æ³•获å–到广告图片之类的东西,而是åªèƒ½æ”¶åˆ°ä¸€ä¸ªç©ºç™½é¡µé¢ã€‚

    + +

    如何å±è”½æˆ–å–æ¶ˆå±è”½ç‰¹å®šçš„主机å?

    +

    从主å±å¹•å°†è¦é˜»æ­¢çš„ä¸»æœºåæ·»åŠ åˆ°é˜»æ­¢åˆ—è¡¨ã€‚ 此外,å¯ä»¥å°†è¦æŽ’é™¤åœ¨é˜»æ­¢ä¹‹å¤–çš„ä¸»æœºåæ·»åŠ åˆ°å…许中,而è¦é‡å®šå‘到特定IP地å€çš„主机å则属于é‡å®šå‘。

    + +

    å¯ä»¥ä»Žå“ªé‡Œæ‰¾åˆ°æ›´å¤š hosts æºï¼Ÿ

    +

    查看 AdAway çš„é¢å¤– hosts æº

    + +

    帮助翻译 / å馈 bug

    +

    请访问 https://adaway.org.

    + + diff --git a/app/src/main/res/raw-zh/help_problems.html b/app/src/main/res/raw-zh/help_problems.html new file mode 100644 index 0000000..922ef53 --- /dev/null +++ b/app/src/main/res/raw-zh/help_problems.html @@ -0,0 +1,36 @@ + + + +常è§é—®é¢˜ + +

    在 Android 9 åŠä»¥ä¸Šç‰ˆæœ¬ hosts 文件å¤åˆ¶å¤±è´¥

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    分区空间ä¸è¶³

    +

    å°è¯•把设置中的目标 hosts 文件修改为 /data/data/hosts(或 /data/hostsï¼‰å¹¶å†æ¬¡åº”用 AdAway。

    + +

    Chrome æµè§ˆç½‘页还是有广告

    +

    ä¿è¯ä½ å·²ç»ä»Ž Chrome 的设置中ç¦ç”¨äº†è½»é‡æ¨¡å¼ï¼ˆä»¥å‰å«åšèŠ‚çœæ•°æ®ï¼‰ã€‚å¯ç”¨æ­¤åŠŸèƒ½åŽï¼ŒChrome 会使用ç§äºº DNS 绕过 AdAway。

    + +

    它ä¸ä¼šé˜»æ­¢åº”用 XYZ 中的广告ï¼

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in the Forum Hosts Inbox of hosts-file.net.

    + +

    广告被缓存了

    +

    有时,在下载广告åŽï¼Œåº”用程åºè¿˜ä¼šå°†å…¶ç¼“存,这会导致æŸäº›åº”用程åºä¸­å­˜åœ¨å‰©ä½™å¹¿å‘Šã€‚您å¯ä»¥å°è¯•在Android 的应用程åºåˆ—表中删除这些应用程åºçš„ç¼“å­˜ï¼Œä»¥è§„é¿æ­¤é—®é¢˜ã€‚

    + +

    åº”ç”¨ç¨‹åº XYZ 无法使用ï¼

    +

    æŸäº›åº”用程åºéœ€è¦ä¸Žè¢« AdAway 阻止的主机å通信,或者在无法访问应æä¾›å¹¿å‘Šçš„ä¸»æœºåæ—¶æ‹’ç»å·¥ä½œã€‚请å‚阅 https://github.com/AdAway/AdAway/wiki/ProblematicApps以获å–存在问题的已知应用程åºåˆ—表。当然,您也å¯ä»¥æ‰¾å‡ºé‚£äº›ä¸»æœºå并将它们添加到您的列表下的白åå•,并将它们报告给 AdAway 的错误跟踪器。

    + +

    ä¸é€‚用于 Android 4.4+

    +

    å°è¯•将首选项中的目标 hosts 文件从 /data/data/hosts 更改为 /data/hosts 或 /system/etc/hostsåŽï¼Œå¹¶å†æ¬¡åº”用 AdAway。

    + +

    Web æµè§ˆå™¨ä¸­çš„åŽé€€æŒ‰é’®æ— æ³•工作

    +

    å¯ä»¥é€šè¿‡åœ¨ AdAway 的设置中å¯ç”¨æœ¬åœ° Web æœåС噍æ¥è§£å†³ã€‚

    + + + diff --git a/app/src/main/res/raw-zh/help_s_on_s_off.html b/app/src/main/res/raw-zh/help_s_on_s_off.html new file mode 100644 index 0000000..5cea0ee --- /dev/null +++ b/app/src/main/res/raw-zh/help_s_on_s_off.html @@ -0,0 +1,31 @@ + + + +与 S-ON 相关的帮助 + +

    HTC 设备

    +

    AdAway 无法在 S-ON 的设备上起效果。这个“功能â€å­˜åœ¨äºŽè®¸å¤š HTC 设备中,且会阻止 AdAway 写入 hosts 文件。

    + +

    S-ON/S-OFF 是什么?

    +

    S-OFF 表示设备的 NAND 部分已解é”并且å¯ä»¥å†™å…¥ã€‚HTC 设备的默认设置是 S-ON,这æ„å‘³ç€æ‚¨æ—¢ä¸èƒ½è®¿é—®ç³»ç»Ÿçš„æŸäº›åŒºåŸŸï¼Œä¹Ÿä¸èƒ½ä¿è¯èƒ½æ°¸ä¹… root ç³»ç»Ÿã€‚æ­¤å¤–ï¼Œå›ºä»¶çš„ç­¾åæ£€æŸ¥ä¹Ÿæ˜¯ç”± S-ON ä¿è¯çš„。

    + +

    我的设备是 S-ON 还是 S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    解决方案

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC.

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. æ’å…¥USB线并在电脑上打开命令行。
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway 现在应该生效了。
    16. +
    + + diff --git a/app/src/main/res/raw/help_faq.html b/app/src/main/res/raw/help_faq.html new file mode 100644 index 0000000..91e6e75 --- /dev/null +++ b/app/src/main/res/raw/help_faq.html @@ -0,0 +1,32 @@ + + + +FAQ + +

    Income by advertisements

    +

    There is an oft-stated misconception that if a user never clicks on ads, then blocking them won't hurt a site or application financially. This is wrong, developers also earn money by just displaying ads. It is up to you whether you block ads or not. Personally I would not use applications that display ads because I find them very annoying, so without an ad blocker I would not install these applications.

    + +

    How does AdAway work?

    +

    AdAway uses the hosts file to block hostnames, that serve advertisements. The hosts file is a file found in /system/etc/hosts that maps hostnames to IP addresses. It is a traditional way to define hostname to IP address pairs without relying on the Domain Name System (DNS). All unwanted hostnames are redirected to 127.0.0.1 which means they will point to your own device.
    +If the hosts file is not writable, a fallback solution is to use the builtin VPN service. It will filter connections to unwanted hostnames and let others go through.

    + +

    Why do I have to restart Android for changes to take effect?

    +

    Java on Android maintains its own internal DNS cache. The operating system will reflect the new hosts file immediately (verify that with ping on the command line) but you'll need to restart Android to rebuild the DNS cache of Java.

    + +

    How to use the webserver in AdAway?

    +

    AdAway will also work without using the webserver! +

    You can enable a local webserver in preferences of AdAway to answer requests to the local IP address 127.0.0.1. This means requests from applications to ad servers which are redirected to 127.0.0.1 are answered by AdAway's webserver. +
    Some applications refuse to work, when ad servers are not reachable. With this method they will be reachable again, replying with a blank page and no ad images.

    + +

    How can I block/unblock specific hostnames?

    +

    Add the hostnames you want to block to the Blocked list from thehomescreen. Additionally, hostnames you want to exclude from blocking can be added to the Allowed and hostnames you want to redirect to a specific IP address belong to the Redirected.

    + +

    Where can I find more hosts sources?

    +

    See List of additional hosts sources for AdAway.

    + +

    Help translating/report bugs

    +

    Please go to https://adaway.org.

    + + diff --git a/app/src/main/res/raw/help_problems.html b/app/src/main/res/raw/help_problems.html new file mode 100644 index 0000000..43111ab --- /dev/null +++ b/app/src/main/res/raw/help_problems.html @@ -0,0 +1,36 @@ + + + +Common problems + +

    Copy of hosts file failed on Android 9+

    +

    Latest versions of Android use read-only /system partition.
    +If you are using Magisk as root solution, ensure you enable the systemless hosts module then reboot.

    + +

    Not enough space on partition

    +

    Try changing the target hosts file in preferences to /data/data/hosts (or /data/hosts) and apply AdAway again.

    + +

    Chrome still displays ads

    +

    Ensure you disable lite mode (previously known as data saver) from Chrome settings. This features allows Chrome to use private DNS solution and bypass AdAway.

    + +

    It does not block ads in application XYZ!

    +

    Some hostnames may be missing in the provided hosts files from the Hosts Sources or the application has bundled the images to provide ads without accessing the internet.

    +You can log DNS requests (Menu->Log DNS Requests) from AdAway to find out which additional hostnames have to be blocked. +

    Add the suspicious hostnames to your own Blacklist by long pressing the entries in the Log and report these hostnames when you have verified them in our GitHub issue tracker.

    + +

    Cached Advertisements

    +

    Sometimes applications cache advertisements after download. This leads to remaining advertisements in some applications. You can try to delete the cache for these applications in Android's Application list to circumvent this problem.

    + +

    Application XYZ is not working anymore!

    +

    Some applications need to communicate with a hostname that is blocked by AdAway or refuse to work when the hostnames which should serve ads are not reachable. See https://github.com/AdAway/AdAway/wiki/ProblematicApps to get a list of known applications that have problems. Otherwise, find out which hostnames are needed and add them to your Whitelist under Your Lists and report them to the bug tracker of AdAway.

    + +

    Does not work on Android 4.4+

    +

    Try changing the target hosts file in preferences from /data/data/hosts to /data/hosts or /system/etc/hosts and apply AdAway again.

    + +

    The back button in web browsers is not working

    +

    You can enable AdAway's local webserver in preferences as a workaround.

    + + + diff --git a/app/src/main/res/raw/help_s_on_s_off.html b/app/src/main/res/raw/help_s_on_s_off.html new file mode 100644 index 0000000..1c02e45 --- /dev/null +++ b/app/src/main/res/raw/help_s_on_s_off.html @@ -0,0 +1,32 @@ + + + +S-ON related help + +

    HTC Devices

    +

    AdAway does not work when you are using a device with so called S-ON. This 'feature' exists on many HTC devices and prevents AdAway from writing the hosts file.

    + +

    S-ON/S-OFF?

    +

    S-OFF means that the NAND portion of the device is unlocked and can be written to. The default setting for HTC devices is S-ON, which means that neither can you access certain areas of the system nor can you guarantee a permanent root. Furthermore, signature check for firmware images is also ensured by the S-ON flag.

    + +

    Do I have S-ON or S-OFF?

    +

    Boot into the Boot Menu on your device by holding down volume down button while pressing power and the text on top will show the flag status as either S-OFF or S-ON. A full root generally means S-OFF. +

    More information can be found on www.addictivetips.com. Additional S-OFF methods since Unrevokable (in link) might interest you, namely: Revolutionary, Revone, Firewater, RumRunner, Moonshine, SunShine…

    + +

    Workaround

    +

    Prerequisite: You have to install a working Android SDK with ADB shell on your PC. +

    +
      +
    1. Boot into the Boot Menu on your device by holding down volume down button while pressing power.
    2. +
    3. Use volume down to select recovery then power to boot it.
    4. +
    5. In clockwork recovery go to "partitions menu".
    6. +
    7. Select mount /system, mount /sdcard and mount /data.
    8. +
    9. Plug in your USB cord and open a command line on your pc.
    10. +
    11. Enter adb shell and type ln -s /data/hosts /system/etc/hosts (This creates a symbolic link, which allows AdAway to edit the hosts file stored in /data while allowing the OS to use the file as if it were stored in /system.)
    12. +
    13. Reboot your device and set Target hosts file to /data/hosts in AdAway's preferences.
    14. +
    15. AdAway should work now.
    16. +
    + + diff --git a/app/src/main/res/values-af/strings.xml b/app/src/main/res/values-af/strings.xml new file mode 100644 index 0000000..6f410ae --- /dev/null +++ b/app/src/main/res/values-af/strings.xml @@ -0,0 +1,97 @@ + + + + Gaan uit + Maak toe + Ja + Nnn + Voeg by + Kanselleer + Stoor + Help + + Alle gas lêers van die omskrewe bronne word afgelaai, en geïntegreer met jou eie lys en dan as een lys geinstalleer in jou sisteem. + Aktiveer webbediener + + Redigeer Inskrywing + Redigeer + Vee uit + + + Besig met invoering… + Besig met Uitvoer… + Skep standaard gasheer lêer + Opdatering beskikbaar + Nuwer Gasheer lêers is beskikbaar + Geen internet konneksie + Geen internet konneksie beskikbaar nie + Bronne nie beskikbaar + Geen gasheer bronne bereikbaar nie! + Geaktiveer + Nuutste Gasheer lêers geaktiveer + Afgeskakel + Simskakel ontbreek + Nie genoeg spasie nie + Afgelaaide lêer kon nie gelees word nie. + Privaat lêer het misluk + Toegang tot partisie as lees/skryf het misluk! + Koppeling het misluk + Kopieer van gasheer lêers het misluk + Kopieering het misluk + Toepassing was suksesvol + Skep van Simskakel was suksesvol + Simskakel skepping het misluk + Lees asb. help vir meer informasie. + APN volmag gestel! + Die internet konneksie werk nie + Geen konneksie + Besig om af te laai… + Besig met toepassing… + Witlys en Swartlys word toegepas + Besig met ontleding en samesmelting van gas lêers + Besig om gas lêers te bou + Besig om gas lêers toe te pas + Toepassing het misluk + Terugkering suksesvol + Ommekeer het misluk vir onbekende redes. + Terugkeer het misluk! + Geen van jou geaktiveerde gasheer bronne is beskikbaar nie! Is jy behoorlik gekoppel aan die internet? + Aflaai het misluk + Private lêer kan nie geskep word nie. + Skep van Privaat Lêer het misluk + + Voeg BA by gas lêer: + Hierdie is nie \'n geldige gasheer naam nie! + Foutief geformateerde gasheernaam + Nie \'n geldige IP nie! + Foutief geformateerde IP + Besig om te laai… + + + Verfris + Voeg by + Help + + S-ON/S-OFF + Vrae + Probleme + + + Ad Blokkeerder + Geen teks redigeerder geïnstalleer nie + Geen lêerbestuurder geinstalleer + Tcpdump is \'n hulpmiddel om DNS versoeke te moniteer en in \'n Log lêer te stoor. Jy kan dit in die agtergrond begin, gebruik dan programme wat advertensie vertoon en ontleed die DNS dan na die tyd, deur die log lêer te gebruik. Moontlike advertensie bedieners kan dan na die tyd by jou swartlys gevoeg word. + + + Home + Gaste bronne + Your lists + Maak Gasheer lêer oop + Log DNS requests + Scan for adware + Voorkeure + Help + + Voorkeure + + diff --git a/app/src/main/res/values-af/strings_app.xml b/app/src/main/res/values-af/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-af/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-af/strings_errors.xml b/app/src/main/res/values-af/strings_errors.xml new file mode 100644 index 0000000..4b3f294 --- /dev/null +++ b/app/src/main/res/values-af/strings_errors.xml @@ -0,0 +1,6 @@ + + + + Geen internet konneksie + Nie genoeg spasie nie + \ No newline at end of file diff --git a/app/src/main/res/values-af/strings_home.xml b/app/src/main/res/values-af/strings_home.xml new file mode 100644 index 0000000..a17dd0c --- /dev/null +++ b/app/src/main/res/values-af/strings_home.xml @@ -0,0 +1,9 @@ + + + + Voorkeure + + + Lees asb. help vir meer informasie. + + \ No newline at end of file diff --git a/app/src/main/res/values-af/strings_hosts.xml b/app/src/main/res/values-af/strings_hosts.xml new file mode 100644 index 0000000..b937898 --- /dev/null +++ b/app/src/main/res/values-af/strings_hosts.xml @@ -0,0 +1,6 @@ + + + Gaste bronne + + nie beskikbaar nie + diff --git a/app/src/main/res/values-af/strings_lists.xml b/app/src/main/res/values-af/strings_lists.xml new file mode 100644 index 0000000..671c808 --- /dev/null +++ b/app/src/main/res/values-af/strings_lists.xml @@ -0,0 +1,6 @@ + + + Your lists + Gasheer naam: + IP (IPv4 of IPv6): + diff --git a/app/src/main/res/values-af/strings_log.xml b/app/src/main/res/values-af/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-af/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-af/strings_notification.xml b/app/src/main/res/values-af/strings_notification.xml new file mode 100644 index 0000000..dae9c3d --- /dev/null +++ b/app/src/main/res/values-af/strings_notification.xml @@ -0,0 +1,4 @@ + + + Opdatering beskikbaar + \ No newline at end of file diff --git a/app/src/main/res/values-af/strings_prefs_backup_restore.xml b/app/src/main/res/values-af/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-af/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-af/strings_prefs_main.xml b/app/src/main/res/values-af/strings_prefs_main.xml new file mode 100644 index 0000000..63f8b17 --- /dev/null +++ b/app/src/main/res/values-af/strings_prefs_main.xml @@ -0,0 +1,6 @@ + + + Voorkeure + + Herstel foute + diff --git a/app/src/main/res/values-af/strings_prefs_root.xml b/app/src/main/res/values-af/strings_prefs_root.xml new file mode 100644 index 0000000..2277b9d --- /dev/null +++ b/app/src/main/res/values-af/strings_prefs_root.xml @@ -0,0 +1,19 @@ + + + Maak Gasheer lêer oop + Teiken Gasheer lêers + Voordat jy hierdie instelling verander lees Hulp aangaande die funksie. + + /system/etc/hosts + /data/hosts + /data/data/hosts + Doelwit teiken + + Doelwit teiken + Versteek her-aansit dialoog + + Herleiding + + Plaaslike Webbediener + Aktiveer webbediener + diff --git a/app/src/main/res/values-af/strings_prefs_update.xml b/app/src/main/res/values-af/strings_prefs_update.xml new file mode 100644 index 0000000..bd3f605 --- /dev/null +++ b/app/src/main/res/values-af/strings_prefs_update.xml @@ -0,0 +1,5 @@ + + + Kyk daagliks vir opdaterings + Kyk daagliks vir opdaterings + diff --git a/app/src/main/res/values-af/strings_prefs_vpn.xml b/app/src/main/res/values-af/strings_prefs_vpn.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-af/strings_prefs_vpn.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-af/strings_support.xml b/app/src/main/res/values-af/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-af/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-af/strings_update.xml b/app/src/main/res/values-af/strings_update.xml new file mode 100644 index 0000000..10b7513 --- /dev/null +++ b/app/src/main/res/values-af/strings_update.xml @@ -0,0 +1,4 @@ + + + Opdatering beskikbaar + diff --git a/app/src/main/res/values-af/strings_welcome.xml b/app/src/main/res/values-af/strings_welcome.xml new file mode 100644 index 0000000..60aadf6 --- /dev/null +++ b/app/src/main/res/values-af/strings_welcome.xml @@ -0,0 +1,4 @@ + + + Kern beskikbare (rooted) Android benodig + diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml new file mode 100644 index 0000000..29c6aed --- /dev/null +++ b/app/src/main/res/values-ar/strings.xml @@ -0,0 +1,279 @@ + + + + خروج + إغلاق + نعم + لا + Ø¥Ø¶Ø§ÙØ© + إلغاء + Ø­ÙØ¸ + المساعدة + + + مرحباً! + AdAway هو تصميم برامج مجاني ÙˆÙ…ÙØªÙˆØ­ المصدر لمنع الإعلانات. إنه يجلب عناوين الشبكات الإعلانية لمنعها من الظهور على جهازك. \nهل تود Ù…Ø¹Ø±ÙØ© المزيد؟ يرجى رؤية المساعدة أدناه! + إظهار المزيد من المساعدة + حالة التحديث + جميع Ù…Ù„ÙØ§Øª المضي٠ستحمل Ùˆ ستدمج مع قوائمك Ùˆ ستثبت ÙÙŠ مل٠واحد على نظامك. + تشغيل حجب الإعلانات + إيقا٠حجب الإعلانات + خادم الويب + يعمل + موقو٠+ بدء أو إيقا٠خادم الويب على المضي٠المحلي للرد على طلبات أسماء المضيÙين المحظورة. + تشغيل خادم الويب + إيقا٠خادم الويب + Ùي بي إن + تشغيل + ØªÙˆÙ‚ÙØª + تشغيل أو إيقا٠VPN لتصÙية الطلبات + ØªÙØ¹ÙŠÙ„ VPN + إيقا٠VPN + + + تحرير المدخلة + تنÙيذ + تحرير + حذ٠+ + + استيراد… + تم ادخال النسخة الاحتياطية من الذاكرة الخارجية بنجاح. + ÙØ´Ù„ ادخال النسخة الاحتياطية,هل هي بالصيغة الصحيحة؟ +تÙقد السجل لمزيد من المعلومات. + تصدير… + تم أخذ النسخة الإحتياطية بنجاح وتصديرها للمل٠%sعلى وسيط التخزين الخارجي الخاص بك + تعذر تصدير مل٠نسخة إحتياطية %s + + + مل٠المضي٠+ مل٠المضي٠هو مل٠نظام يقوم بربط أسماء المضي٠مع عناوين الإنترنت بروتوكول .إنه عبارة عن مل٠نصّي ويهتم AdAway به ويقوم بإعداده. تبدو بعض الخطوط الأولى Ùيه كما يلي: + جار٠تحميل محتوى مل٠المضيÙ… + ÙØªØ­ مل٠المضي٠+ + + التأكد من التحديثات + جاري تÙقد مصدر %sللبحث عن تحديثات + جلب المصادر + تحميل المصدر %s + جاري قراءة المصدر %s + جاري نسخ المصدر %s + جاري مزامنة قاعدة البيانات + إستعادة إعدادات مل٠hosts Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠØ© + إستعادة مل٠hosts Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ Ø§ÙƒØªÙ…Ù„ + إنشاء Ù…Ù„ÙØ§Øª المضي٠الأساسية + يوجد تحديث Ù…ØªÙˆÙØ± + Ù…Ù„ÙØ§Øª المضي٠الجديدة Ù…ØªÙˆÙØ±Ø© + لم يعثر على تحديث للمصدر + غير متصل بالشبكة + لا يوجد اتصال بالشبكة Ù…ØªÙˆÙØ± + الملقمات غير Ù…ØªÙˆÙØ±Ø© + لا يمكن الوصول إلى مصادر المضيÙ! + صلاحيات الرووت مرÙوضة. + اسمح لصلاحيات الرووت من البرنامج المسؤول عن الرووت؟ + حدث خطأٌ ما + للمزيد من المعلومات يرجى التحقّق من الـ logcat + Ù…ÙØ¹Ù„ + Ù…Ù„ÙØ§Øª المضي٠الحديثة Ù…ÙØ¹Ù„Ø© + معطل + Ù…Ù„Ù Ø§Ù„Ù…Ø¶ÙŠÙ Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ Ù…ÙØ«Ø¨Ù‘ت + تطبيق آحدث المصادر + تكوين مل٠hosts جديد + نسخ مل٠hosts جديد + التأكد من نسخ مل٠hosts + تم تحديث مل٠hosts بنجاح + تم تحديث تكوين ÙÙŠ بي إن بنجاح + تم تغيير التكوين الخاص بك. تحتاج إلى تطبيقه. + تنÙيذ + جار٠تثبيت مل٠المضيÙ… + ÙØ´Ù„ ÙÙŠ تثبيت Ù…Ù„Ù Ø§Ù„Ù…Ø¶ÙŠÙØ§Øª + + + الارتباط الرمزي إلى هد٠مل٠المضيÙين Ù…Ùقود + symlink من مسارك الى /system/etc/hosts غير موجود او غير صحيح . البرنامج لن يعمل اذا لم يتم تحديد المل٠الصحيح . هل تريد محاولة انشاء symlink ØŸ + الارتباط الرمزي Ù…Ùقود + لا توجد مساحة كاÙية على القرص حاول تغيير المسار من الاعدادت الى /data/data/hosts + لا توجد مساحة كاÙية + لا يمكن قراءة المل٠الذي تم تنزيله. + ÙØ´Ù„ المل٠الخاص + ÙØ´Ù„ تحويل القسم لوضع القراءة/الكتابة! + ÙØ´Ù„ التحويل + ÙØ´Ù„ نسخ مل٠المضيÙين + ÙØ´Ù„ نسخ Ù…Ù„ÙØ§Øª المضيÙ! + ÙØ´Ù„ النسخ + مصادر المضي٠المطبّقة + تم التنÙيذ بنجاح + تم التثبيت بنجاح. \nيستوجب إعادة تشغيل الجهاز الآن. \n\nهل تريد إعادة تشغيل جهازك؟ \n(يرجى التأكد من عدم وجود تطبيقات تستخدم بطاقة الذاكرة الآن لتجنّب Ùقدان أي معلومات!) + تم إنشاء الرابط الرمزي بنجاح. \nيستوجب إعادة تشغيل الجهاز الآن. \n\nهل تريد إعادة تشغيل جهازك؟ \n(يرجى التأكد من عدم وجود تطبيقات تستخدم بطاقة الذاكرة الآن لتجنّب Ùقدان أي معلومات!) + الارتباط الرمزي أنشئ بنجاح + تعذر إنشاء الوصلة اللينة Symlink بواسطة Android.\n وهذا Ø§Ù„ÙØ´Ù„ غالبًا بسبب \"ميزة\" ØªÙØ¹Ø±Ù باسم S-ON على HTC هواتÙ!\n\n الحل هو تشغيل الهات٠ÙÙŠ وضع الاسترداد وإنشاء الرابط التراÙقي Symlink هناك باستخدام \'ln -s /data/data/hosts /system/etc/hosts\'.\n\n إذا لم يعمل ذلك ØŒ ابحث ÙÙŠ الإنترنت عن S-OFF وكذلك ÙÙŠ هاتÙÙƒ. + الارتباط الرمزي لم ينشئ + يرجى قراءة التعليمات للمزيد من المعلومات. + تم تعيين بروكسي APN على جهاز Android الخاص بك! \ n لن تعمل ميزة ADAway بشكل موثوق به عندما تكون على شبكات المحمول مثل 3G. يمكنك إلغاء تنشيط هذا الوكيل بالانتقال إلى APN المحدد (من تطبيق الإعدادات: الشبكة & الإنترنت-> شبكة الهات٠المحمول-> خيارات متقدمة-> أسماء نقاط الوصول) وإزالة القيمة ÙÙŠ حقل خادم الوكيل. + تعيين وكيل APN! + الاتصال بالشبكة لا يعمل + غير متصل + جار٠التحميل… + يتم التنÙيذ… + تنÙيذ القائمة السوداء والبيضاء + تحليل ودمج Ù…Ù„ÙØ§Øª المضي٠+ بناء Ù…Ù„ÙØ§Øª المضي٠+ تنÙيذ Ù…Ù„ÙØ§Øª المضي٠+ ÙØ´Ù„ ÙÙŠ تطبيق مل٠المضيÙين الجديد. + لقد ÙØ´Ù„ت عملية تثبيت Ù…Ù„ÙØ§Øª المضيÙ! حاول تغيير مسار Ø§Ù„Ù…Ù„ÙØ§Øª من الاعدادات الى /data/data/hosts + ÙØ´Ù„ التنÙيذ + الرجاء تÙقد برنامج ادارة الرووت للتأكد من أن صلاحيات الرووت مسموحة. + تم استرجاع Ù…Ù„Ù Ø§Ù„Ù…Ø¶ÙŠÙ Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ. \nيستوجب إعادة تشغيل الجهاز الآن. \n\nهل تريد إعادة تشغيل جهازك؟ \n(يرجى التأكد من عدم وجود تطبيقات تستخدم بطاقة الذاكرة الآن لتجنّب Ùقدان أي معلومات!) + تم الاسترجاع + غير قادر على إعادة مل٠المضيÙين + الاسترجاع ÙØ´Ù„ لأسباب غير Ù…Ø¹Ø±ÙˆÙØ©. + ÙØ´Ù„ الاسترجاع! + مصادر المضي٠لا يمكن الوصول إليها! هل أنت متصل بالإنترنت؟ + ÙØ´Ù„ التحميل + ÙØ´Ù„ كتابة مل٠مضيÙين خاصين جدد + لا يمكن إنشاء مل٠خاص. + ÙØ´Ù„ إنشاء مل٠خاص + تم ØªÙØ¹ÙŠÙ„ الوضع اللّانظامي. \nيستوجب إعادة تشغيل الجهاز الآن. \n\nهل تريد إعادة تشغيل جهازك؟ \n(يرجى التأكد من عدم وجود تطبيقات تستخدم بطاقة الذاكرة الآن لتجنّب Ùقدان أي معلومات!) + تم التنÙيذ بنجاح + تم تعطيل الوضع اللّانظامي. \nيستوجب إعادة تشغيل الجهاز الآن. \n\nهل تريد إعادة تشغيل جهازك؟ \n(يرجى التأكد من عدم وجود تطبيقات تستخدم بطاقة الذاكرة الآن لتجنّب Ùقدان أي معلومات!) + تم التعطيل بنجاح + تعذر عن ØªÙØ¹ÙŠÙ„ إعلانات VPN + تعذر عن إيقا٠إعلانات VPN + تمكين وحدة Magisk Ø§Ù„Ù…Ø¶ÙŠÙØ© + تمكين ميزة المضيÙين بدون نظام من Magisk manager. من إعداداته ØŒ قم بتمكين خيار Hostless hosts ثم أعد تشغيل جهازك. + تعطيل وحدة Magisk Ø§Ù„Ù…Ø¶ÙŠÙØ© + تعطيل ميزة المضيÙين بدون نظام من Magisk manager. من قائمة الوحدات ØŒ قم بإلغاء تثبيت وحدة Systemless hosts ØŒ ثم أعد تشغيل جهازك. + + + أدخل عنوان URL Ù„Ù…Ù„ÙØ§Øª المضيÙ: + اسم الموقع غير صالح! + صيغة اسم المضي٠غير صحيحية + IP غير صالح! + صيغة IP غير صحيحة + لا تـقـم بإعادة التشغيل وعدم إظهار هذا السؤال ÙÙŠ المرة القادمة! + تحميل… + + + تحديث + Ø¥Ø¶Ø§ÙØ© + المساعدة + استرجاع النسخة الاحتياطية. + استخراج نسخة احتياطية. + + + S-ON/S-OFF + الأسئلة الشائعة + المشاكل + + + الإعلانات Ø§Ù„Ù…ÙØªØ³Ù„ّلة + هنا يمكنك العثور على تطبيقات Adware مثبّتة ØŒ وهي تطبيقات سيئة لا يمكن منعها من Ù‚ÙØ¨ÙŽÙ„ AdAway . على سبيل المثال تستخدم هذه التطبيقات إشعارات Airpush التي تظهر حتى عند عدم تشغيل التطبيق وتستطيع حتى تغيير نغمة الرنين لجهازك . الحل الوحيد هو حذ٠هذه التطبيقات التي Ø¹ÙØ«Ùرَ عليها من خلال النقر على أسماء التطبيقات ÙÙŠ الأسÙÙ„ . + Ø¬Ø§Ø±Ù Ø§Ù„ÙØ­Øµ + لم يتم العثور على إعلانات Ù…ÙØªØ³Ù„ّلة! + + + حاجب الإعلانات + لا يوجد محرر نصوص مثبت + تعذر العثور على محرر نصوص Ù„ÙØªØ­ مل٠المضيÙ. يمكنك تثبيت محرر النصوص JOTA او اي محرر نصوص اخر لتجاوز هذا. هل تريد تثبيت JOTA ØŸ + لا يوجد مدير Ù…Ù„ÙØ§Øª مثبت + تعذر العثور على مدير Ù…Ù„ÙØ§Øª Ù„ÙØªØ­ الملÙ. يمكنك تثبيت مدير Ù…Ù„ÙØ§Øª OI او أي مدير Ù…Ù„ÙØ§Øª اخر لتجاوز هذا. هل تريد تثبيت OIØŸ + + + Tcpdump + Tcpdump هي أداة لمراقبة طلبات DNS ÙˆØ­ÙØ¸Ù‡Ø§ ÙÙŠ مل٠سجل. يمكنكم تشغيله ÙÙŠ الخلÙية، ثم تشغيل التطبيقات التي تعرض الإعلانات على الشاشة، بعد ذلك سيتم تحليل طلبات DNS باستخدام مل٠السجل.الأن يمكن Ø¥Ø¶Ø§ÙØ© مصدر الإعلانات إلى قائمتك السوداء. + Ø¥ÙŠÙ‚Ø§Ù Ø§Ù„Ù…ÙØ±Ø§Ù‚بة + تشغيل Ø§Ù„Ù…ÙØ±Ø§Ù‚بة + عرض النتائج + ترتيب الـ domains + محي السّجلّ + Ø¥Ø¶Ø§ÙØ© Ø§Ù„Ù…ÙØ¯Ø®ÙŽÙ„ للقائمة السوداء + Ø¥Ø¶Ø§ÙØ© Ø§Ù„Ù…ÙØ¯Ø®ÙŽÙ„ للقائمة البيضاء + Ø¥Ø¶Ø§ÙØ© Ø§Ù„Ù…ÙØ¯Ø®ÙŽÙ„ إلى قائمة إعادة التوجيه + + تحرير قيمة إعدادات النص + ÙØªØ­ القائمة + إغلاق القائمة + + + + Ø§Ù„ØµÙØ­Ø© الرئيسية + مصادر المضي٠+ قوائمك + ÙØªØ­ Ù…Ù„ÙØ§Øª المضي٠+ سجل طلبات الDNS + البحث عن البرامج الداعمة للإعلانات + الخيارات + المساعدة + + + + + طلبات DNS + قوائمك + الخيارات + + + تم تنصيبه قبل %1$s + حالي لـ %1$s + مطلوب تحديث لـ %1$s + آخر تحديث قبل %1$s + حالة تحديث غير Ù…Ø¹Ø±ÙˆÙØ© + معطل + بضع دقائق + + إنتهى تقريبا%d + دقيقة %d + دقيقتان %d + القليل %d + دقائق %d + دقائق %d + + + إنتهى تقريبا%d + ساعة %d + ساعتان %d + ساعات %d + الساعات %d + الساعات %d + + + إنتهى تقريبا %d + يوم %d + يومان %d + بعض الايام %d + ايام %d + ايام %d + + + انتهى تقريبا %d + شهر واحد %d + شهران %d + Ø£Ø´Ù‡ÙØ± %d + Ø£Ø´Ù‡ÙØ± %d + Ø£Ø´Ù‡ÙØ± %d + + + + تم نسخ المضي٠إلى Ø§Ù„Ø­Ø§ÙØ¸Ø© + + + تشغيل + ÙØ¹Ø§Ù„ + جاري الإيقا٠+ بإنتظار شبكة + إعادة الإتصال + خطأ بإعادة الإتصال + متوق٠مؤقتا + متوق٠+ إيقا٠إعلانات VPN %1$s + إيقا٠مؤقت + إستئنا٠+ + + صلاحيات AdAway + السماح لـ AdAway بالوصول لـ + أرسل الأوامر لـ AdAway + السماح بإرسال أوامر إلى AdAway مثل تمكين أو تعطيل حظر الإعلانات على مستوى النظام + + diff --git a/app/src/main/res/values-ar/strings_app.xml b/app/src/main/res/values-ar/strings_app.xml new file mode 100644 index 0000000..6d25748 --- /dev/null +++ b/app/src/main/res/values-ar/strings_app.xml @@ -0,0 +1,6 @@ + + + آدواي AdAway + مانع إعلانات Ù…ÙØªÙˆØ­ المصدر + أيقونة AdAway + diff --git a/app/src/main/res/values-ar/strings_errors.xml b/app/src/main/res/values-ar/strings_errors.xml new file mode 100644 index 0000000..b46c088 --- /dev/null +++ b/app/src/main/res/values-ar/strings_errors.xml @@ -0,0 +1,22 @@ + + + + غير متصل بالشبكة + تعذر إنشاء اتصال بالإنترنت. يرجى التحقق من اتصال جهازك. + ÙØ´Ù„ تحميل مصدر المضيÙين + لا يمكن الوصول إلى أي من مصادر المضيÙين Ø§Ù„Ù…ÙØ¹Ù„Ø©. يرجى التحقق من أنك متصل بشكل صحيح بالإنترنت. + + ÙØ´Ù„ إنشاء مل٠خاص + تعذر إنشاء مل٠خاص لبناء مصدر مضي٠جديد. يرجى التحقق من المساحة الخالية Ø§Ù„Ù…ØªÙˆÙØ±Ø© على جهازك. + لا توجد مساحة كاÙية + تعذر نسخ مل٠المضيÙين إلى قسم النظام لديك. يرجى التحقق من تمكين Magisk systemless module ثم إعادة التشغيل. + ÙØ´Ù„ تثبيت مل٠المضيÙين الجديد + تعذر نسخ مل٠المضيÙين إلى / قسم النظام. يرجى التحقق من تمكين Magisk systemless module ثم إعادة التشغيل. + ÙØ´Ù„ت إعادة مل٠المضيÙين + غير قادر على استعادة الإعداد Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠ Ù„Ù…Ù„Ù Ø§Ù„Ù…Ø¶ÙŠÙين. + + تعذر عن ØªÙØ¹ÙŠÙ„ إعلانات VPN + يرجى التحقق من إعدادات VPN الخاصة بك للسماح Ù„ VPN التطبيق للبدء. + تعذر عن إيقا٠إعلانات VPN + يرجى التحقق من إعدادات VPN الخاصة بك لتعطيلها يدويًا. + diff --git a/app/src/main/res/values-ar/strings_home.xml b/app/src/main/res/values-ar/strings_home.xml new file mode 100644 index 0000000..9cb8ada --- /dev/null +++ b/app/src/main/res/values-ar/strings_home.xml @@ -0,0 +1,54 @@ + + + + + محظور + مسموح + معاد توجيهه + + + + %d المصادر محدث + %d المصدر محدث + %d المصادر محدثة + %d المصادر محدثة + %d المصادر محدثة + %d المصادر محدثة + + + %d المصدر بحاجة لتحديث + %d المصدر بحاجة لتحديث + %d المصادر بحاجة لتحديث + %d المصادر بحاجة لتحديث + %d المصادر بحاجة لتحديث + %d المصادر بحاجة لتحديث + + تحقق من وجود تحديثات المضيÙين + تحديث Ù…Ù„ÙØ§Øª المضي٠+ + + إظهار سجل طلب DNS + + + إظهار التعليمات n والنصائح + + + Ø¥ÙØªØ­ ØµÙØ­Ø© GitHub + + + إدعم المشروع + + + مشروع جيثب + الخيارات + + + Ø¥ÙØªØ­ قائمة التوجيه + إيقاÙ/إستئنا٠منع الإعلانات + تحديث الروابط المحظورة + أظهر الروابط التي تم طلبها + + + يرجى قراءة التعليمات للمزيد من المعلومات. + + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings_hosts.xml b/app/src/main/res/values-ar/strings_hosts.xml new file mode 100644 index 0000000..17477b0 --- /dev/null +++ b/app/src/main/res/values-ar/strings_hosts.xml @@ -0,0 +1,17 @@ + + + مصادر المضي٠+ + لائحة المستخدم + لائحة AdAway الرسمية + لائحة StevenBlack + لائحة Pete Lowe + + غير Ù…ØªÙˆÙØ± + %s مضيÙين + + Ø¥Ø¶Ø§ÙØ© مصدر + تحرير مصدر + الرابط: (إمّا مصدر https:// أو file://) + مصدر رابط المضي٠+ diff --git a/app/src/main/res/values-ar/strings_lists.xml b/app/src/main/res/values-ar/strings_lists.xml new file mode 100644 index 0000000..356b3ea --- /dev/null +++ b/app/src/main/res/values-ar/strings_lists.xml @@ -0,0 +1,24 @@ + + + قوائمك + Ø¥Ø¶Ø§ÙØ© مضي٠+ + محظور + مسموح + معاد توجيهه + + تصÙية المضيÙين + البحث عن اسم المضيÙ… + تبديل المصادر + + Ø¥Ø¶Ø§ÙØ© المضي٠للقائمة السوداء + Ø¥Ø¶Ø§ÙØ© المضي٠للقائمة البيضاء + Ø¥Ø¶Ø§ÙØ© عملية إعادة توجيه المضي٠+ تحرير Ø§Ù„Ù…Ø¶ÙŠÙ Ø§Ù„Ù…ÙØ¯Ø±Ø¬ ÙÙŠ القائمة السوداء + تحرير Ø§Ù„Ù…Ø¶ÙŠÙ Ø§Ù„Ù…ÙØ¯Ø±Ø¬ ÙÙŠ القائمة البيضاء + تحرير عملية إعادة التوجيه + اسم المضيÙ: + مصدر رابط المضي٠+ (يسمح اسخدام رموز البدل * Ùˆ ?) + بروتكول الانترنت (IPv4 أو IPv6): + diff --git a/app/src/main/res/values-ar/strings_log.xml b/app/src/main/res/values-ar/strings_log.xml new file mode 100644 index 0000000..7e87144 --- /dev/null +++ b/app/src/main/res/values-ar/strings_log.xml @@ -0,0 +1,12 @@ + + + تشغيل أو إيقا٠تسجيل السّجل + اضغط على زر التسجيل لبدء تسجيل الطلبات وقم Ø¨ØªØµÙØ­ الويب أو استخدام بعض التطبيقات، ثم Ø¹ÙØ¯ أو اسحب بإصبعك للأسÙÙ„ لتحديث السجلات. + \n\nلن يتم تسجيل الطلبات المحظورة. قم بتعطيل حظر الإعلانات أولاً إذا كنت تريد تسجيلها أيضًا. + + + ترتيب أبجدي + ترتيب Top level domain + + إعادة توجيه الـ domain + diff --git a/app/src/main/res/values-ar/strings_notification.xml b/app/src/main/res/values-ar/strings_notification.xml new file mode 100644 index 0000000..8228e5c --- /dev/null +++ b/app/src/main/res/values-ar/strings_notification.xml @@ -0,0 +1,13 @@ + + + + تحديثات + إشعارات تحديث جديد + يوجد تحديث Ù…ØªÙˆÙØ± + أحدث Ø§Ù„Ù…Ù„ÙØ§Øª Ø§Ù„Ù…Ø¶ÙŠÙØ© المتاحة للتنزيل. + تحديث التطبيق متاح + إصدار جديد من AdAway متاح للتنزيل. + + Ùي بي إن + إشعارات تشغيل VPN + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings_prefs_backup_restore.xml b/app/src/main/res/values-ar/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..6f9e6c2 --- /dev/null +++ b/app/src/main/res/values-ar/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + النسخ الاحتياطي Ùˆ الإستعادة + النسخ الاحتياطي + نسخ احتياطي إلى ذاكرة خارجية + إستعادة + إستعادة نسخة إحتياطية من مل٠+ diff --git a/app/src/main/res/values-ar/strings_prefs_main.xml b/app/src/main/res/values-ar/strings_prefs_main.xml new file mode 100644 index 0000000..5a5d0a2 --- /dev/null +++ b/app/src/main/res/values-ar/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + الخيارات + + عام + ثيم داكن + + مضيئ + داكن + الإعداد Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ Ù„Ù„Ù†Ø¸Ø§Ù… + + تحديثات تلقائية + + منع إعلانات + مانع إعلانات يعتمد على الرووت + مانع إعلانات يعتمد على ال VPN + ØªÙØ¹ÙŠÙ„ دعم IPv6 + قواعد حظر النسخ الاحتياطي / الاستعادة + + التصحيح + إرسال تقارير الأعطال + إرسال تقارير الأعطال إلى Sentry (sentry.io) + غير مدعوم ÙÙŠ هذا الإصدار + تسجيل التقارير Ø§Ù„Ù…ÙØµÙ„ + إعادة التشغيل مطلوبة لتطبيق الإعدادات + diff --git a/app/src/main/res/values-ar/strings_prefs_root.xml b/app/src/main/res/values-ar/strings_prefs_root.xml new file mode 100644 index 0000000..e4ae6d3 --- /dev/null +++ b/app/src/main/res/values-ar/strings_prefs_root.xml @@ -0,0 +1,38 @@ + + + مانع إعلانات يعتمد على الرووت + + تثبيت المضيÙين + ÙØªØ­ Ù…Ù„ÙØ§Øª المضي٠+ مسار Ù…Ù„ÙØ§Øª المضي٠+ قبل تغيير هذا الإعداد، يجب قراءة التعليمات حول هذه Ø§Ù„ÙˆØ¸ÙŠÙØ©. + + /system/etc/hosts + /data/hosts + /data/data/hosts + مسار مخصص + + مسار مخصص + Ø¥Ø®ÙØ§Ø¡ Ù…ÙØ­Ø§ÙˆØ± إعادة التشغيل + + إعادة التوجيه + حدد مكان إعادة توجيه المضيÙين المحظورين + عنوان إعادة التوجيه IPv4 + عنوان إعادة التوجيه IPv6 + إعادة توجيه غير صالحة + + خادم الويب المحلي + يستمع خادم الويب المحلي إلى عناوين IP المحلية للرد على طلبات اسم المضي٠المحظورة. قد يساعد ÙÙŠ حالة تجمد التطبيق عند الاتصالات المحظورة. + ØªÙØ¹ÙŠÙ„ خادم الويب + اختبار خادم الويب + قم بتثبيت شهادة موقعة ذاتيًا + التثبيت اليدوي للشهادة + بدءًا من أندرويد 11 (R)ØŒ لم يعد بإمكان التطبيق التثبيت التلقائي للمرجع المصدق (CA). +انتقل إلى إعدادات \"الأمان\" ØŒ Ùˆ \"بيانات الاعتماد والتشÙير\" ثم \"تثبيت شهادة\". من هناك ØŒ اختر \"شهادة CA\" وحدد مل٠الشهادة الذي تم تصديره حديثًا. + Ø§ÙØªØ­ إعدادات \"الأمان\" + تدقيق… + لا يعمل + قيد التشغيل ولكن الشهادة غير مثبتة + قيد التشغيل والشهادة مثبتة + استبدل المساحة الإعلانية Ø§Ù„ÙØ§Ø±ØºØ© بأيقونة التطبيق + diff --git a/app/src/main/res/values-ar/strings_prefs_update.xml b/app/src/main/res/values-ar/strings_prefs_update.xml new file mode 100644 index 0000000..4051005 --- /dev/null +++ b/app/src/main/res/values-ar/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + تحديثات + الإشعارات معطلة + اشعارات التطبيق لن تظهر. اضغط Ù„ØªÙØ¹ÙŠÙ„ها + + تحديثات التطبيق + تحقق من التحديث عند بدء التشغيل + تحقق بشكل دوري من التحديثات + تضمين إصدارات بيتا + + تحديثات المضيÙين + تحقق من التحديث عند بدء التشغيل + تحقق بشكل دوري من التحديثات + مزامنة عند التحديث + المزامنة على شبكة غير مقيَّدة Ùقط + diff --git a/app/src/main/res/values-ar/strings_prefs_vpn.xml b/app/src/main/res/values-ar/strings_prefs_vpn.xml new file mode 100644 index 0000000..59cd7e7 --- /dev/null +++ b/app/src/main/res/values-ar/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + مانع إعلانات يعتمد على ال VPN + + التمكين عند بدء تشغيل الجهاز + مراقبة الاتصال + تحقق بشكل دوري من حالة الشبكة لإعادة تشغيل VPN عند قطع الاتصال. + + التطبيقات المستبعدة + إعداد التطبيقات التي يجب ألا تستخدم VPN حتى لا يتم حظر أي اتصالات. + استبعد تطبيقات النظام + + None + All except browsers + All + + استبعد تطبيقات المستخدم + + + التطبيقات المستبعدة + تحديد الكل + إلغاء تحديد الكل + أيقونة التطبيق + diff --git a/app/src/main/res/values-ar/strings_source_edit.xml b/app/src/main/res/values-ar/strings_source_edit.xml new file mode 100644 index 0000000..092f99e --- /dev/null +++ b/app/src/main/res/values-ar/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + تحرير مصدر + Ø¥Ø¶Ø§ÙØ© مصدر + + تسمية + التسمية مطلوبة + نوع + URL + مل٠+ موقع + https:// + الموقع مطلوب + اضغط على مل٠لتحديد مل٠المصدر + موقع غير صالح + قائمة التنسيق + حظر + سماح + تطبيق المضيÙين الموجهين + السماح بالمضيÙين الموجهين قد يسبب مشاكل أمان. استخدم هذا الإعداد Ùقط على مصدر موثوق به حيث يمكن أن يعيد توجيه بعض حركة المرور الحساسة إلى أي خادم يريده. + diff --git a/app/src/main/res/values-ar/strings_support.xml b/app/src/main/res/values-ar/strings_support.xml new file mode 100644 index 0000000..84d5e17 --- /dev/null +++ b/app/src/main/res/values-ar/strings_support.xml @@ -0,0 +1,5 @@ + + + الدعم + كن راعياً + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings_update.xml b/app/src/main/res/values-ar/strings_update.xml new file mode 100644 index 0000000..5fba093 --- /dev/null +++ b/app/src/main/res/values-ar/strings_update.xml @@ -0,0 +1,21 @@ + + + تحديث آدواي AdAway + + تحديث Ù…ØªÙˆÙØ±! + + + أنت لديك آخر إصدار + يوجد تحديث Ù…ØªÙˆÙØ± + جاري تحديث آدواي AdAway + حدث الآن + %1$s/%2$s + التغييرات الأخيرة + سجل التغييرات + دعم المشروع + التبرع + راعي + + + جاري تنزيل أحدث إصدار من AdAway… + diff --git a/app/src/main/res/values-ar/strings_welcome.xml b/app/src/main/res/values-ar/strings_welcome.xml new file mode 100644 index 0000000..3e2656e --- /dev/null +++ b/app/src/main/res/values-ar/strings_welcome.xml @@ -0,0 +1,53 @@ + + + مرحبا + أول خطوة لتحضير التطبيق + ثاني خطوة لتحضير التطبيق + آخر خطوة لتحضير التطبيق + + + مرحبًا بك ÙÙŠ AdAway ! + AdAway يقدم لك طريقتين لمنع الإعلانات + + أيقونة الرووت + منع إعلانات يعتمد على الرووت + أسرع + صديق للبطارية + الرووت مطلوب + + أيقونة ال VPN + مانع إعلانات يعتمد على ال VPN + أبطىْ + تشغيل ÙÙŠ الخلÙية + تواÙÙ‚ + + مطلوب روت للهات٠+ إما أن su binary لا يمكن العثور عليه أو أنك لم تسمح بإذن الجذر لـ AdAway. يمكن أن يحدث هذا عندما لا يكون جهازك بدون رووت. يمكنك العثور على معلومات حول كيÙية عمل رووت لجهازك على wiki.lineageos.org أو مواقع Android الأخرى. + + إحتراÙÙŠ + عيوب + + + تمت المزامنة + حصل خطأ أثناء المزامنة + + جاري المزامنة + تمت المزامنة + AdAway يقوم بتنزيل شبكات الإعلانات لمنعها من المصادر عبر الإنترنت. يمكنك تخصيصها لاحقًا ÙÙŠ الإعدادات. + أعد محاولة المزامنة + ÙØ´Ù„ مزامنة: %1$s إعادة المحاولة الآن + يمكنه إرسال إشعارات لعرض حالة حظر الإعلانات والتحكم Ùيها، وإعلامك بتحديث التطبيق المتاح (عدد قليل ÙÙŠ السنة). قم بتمكينها إذا كنت ترغب ÙÙŠ البقاء على اطلاع دائم. + + + الدعم + إدعمني! + Adaway هو برنامج Ù…ÙØªÙˆØ­ المصدر اقوم بتطويره ÙÙŠ وقت ÙØ±Ø§ØºÙŠ. اذا أعجبك. ÙƒÙÙ† حر بإظهار دعمك: + تبرع على PayPal + هل وجدت مشاكل ÙÙŠ التطبيق؟ ولا أنا. + قم Ø¨ØªÙØ¹ÙŠÙ„ إرسال تقارير مشاكل التطبيق + + + رجوع + التالي + إنتهاء + diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml new file mode 100644 index 0000000..c4cb392 --- /dev/null +++ b/app/src/main/res/values-ast/strings.xml @@ -0,0 +1,145 @@ + + + + Colar + Zarrar + Sí + Non + Amestar + Encaboxar + Guardar + Ayuda + + + ¡Afáyate! + Adaway ye un programa gratuitu y de códigu abiertu diseñáu pa bloquiar anuncios. Va en cata de les direiciones de les redes d\'anuncios pa bloquiales nel preséu.\n¿Quies saber más? ¡Mira l\'ayuda d\'embaxo! + Tolos ficheros «Hosts» de les fontes defeníes báxense, amiéstense coles tos propies llistes ya instálense como un ficheru «Hosts» nel sistema. + Activar el bloquéu d\'anuncios + Sirvidor web + N\'execución + En parada + VPN + + Editar entrada + Editar + Desaniciar + + + Importando… + Esportando… + + El ficheru hosts + Cargando\'l conteníu del ficheru hosts… + Abrir el ficheru hosts + + Creando ficheru hosts estándar + Anovamientu disponible + Hai disponible un ficheru hosts más nuevu + Ensin conexón d\'internet + Ensin conexón d\'internet disponible + Fontes non disponibles + ¡Nun pue algamase dal fonte d\'agospios! + Habilitáu + Habilitáronse los ficheros «hosts» más nuevos + Deshabilitáu + ¡Nun esiste o ye incorreutu l\'enllaz simbólicu dende\'l to oxetivu a /system/etc/hosts! Adaway nun furrulará si nun ta apuntando al ficheru correutu.\n\n¿Quies crear un enllaz simbólicu? + Falta l\'enllaz simbólicu + ¡Nun hai espaciu abondo na partición!\nIntenta camudar nes preferencies el ficheru «hosts» oxetivu a /data/data/hosts . + Nun hai espaciu abondo + Nun pudo lleese\'l ficheru baxáu. + Fallu nel ficheru priváu + ¡Fallu remontando la partición como llectura/escritura! + Fallu nel remontaxe + ¡Fallu copiando\'l ficheru «hosts»! + Copia fallida + Aplicadura esitosa + Creación esitosa del enllaz simbólicu + Fallu na creación d\'enllaz simbólicu + Por favor, llei l\'ayuda pa más información. + ¡Afitóse\'l proxy APN! + La conexón d\'internet nun ta furrulando. + Ensin conexón + Baxando… + Aplicando… + Aplicando llista prieta y blanca + Analizando y meciendo los ficheros «hosts» + Construyendo\'l ficheru «hosts» + Aplicando\'l ficheru «hosts» + ¡Falló l\'aplicadura del ficheru «hosts» nel sistema!\nIntenta camudar nes preferencies el ficheru «hosts» oxetivu a /data/data/hosts. + Falló l\'aplicadura + Desfechura esitosa + Fallu na desfechura pola mor de razones desconocíes. + ¡Fallu na desfechura! + ¡Nun s\'algamó dal fonte de «hosts» de to! ¿De xuru que tas coneutáu afayadizamente a internet? + Descarga fallida + Nun pue crease\'l ficheru priváu. + Fallu na creación del ficheru priváu + + Enllaz d\'entrada al ficheru hosts: + ¡Esto nun ye un nome d\'agospiu válidu! + Nome d\'agospiu mal formáu + ¡Esto nun ye una IP válida! + IP mal formada + Cargando… + + + Refrescar + Amestar + Ayuda + Importar una copia de seguranza + Esportar + + + S-ON/S-OFF + FAQ + Problemes + + + Adware + Equí pues alcontrar adware, aplicaciones malicioses qu\'AdAway nun pue bloquiar. Estes aplicaciones camuden el tonu d\'avisu del preséu o usen, por exemplu, avisos Airpush qu\'apaecen magar que l\'aplicación nun tea n\'execución. La única midida pa facer qu\'esto nun pase ye desinstalar eses aplicaciones calcando nos elementos de la llista. + + Bloquiador d\'anuncios + Nun hai dal editor de testos instaláu + Nun pudo alcontrase dal editor de testos p\'abrir el ficheru «hosts». Pues instalar Jota u otros pa remanar esto.\n\n¿Quies instalar Jota? + Nun hai instaláu dal xestor de ficheros + Nun pudo alcontrase dal xestor de ficheros. Pues instalar OI File Manager u otros pa remanar esto.\n\n¿Quies instalar OI File Manager? + + + Tcpdump + Tcpdump ye una ferramienta pa monitorizar les solicitúes DNS y guardales nun ficheru de rexistru. Pues anicialu de fondu, executar les aplicaciones qu\'amuesen anuncios y sero analizar les solicitúes DNS usando\'l ficheru de rexistru. Ye posible amestar el sirvidor d\'anuncios a la to llista prieta. + Desactivar la supervisión + Activar la supervisión + Amosar resultaos + + + Home + Fontes de hosts + Your lists + Abrir ficheru «hosts» + Log DNS requests + Scan for adware + Preferencies + Ayuda + + Llistes de to + Preferencies + + Desconozse l\'estáu d\'anovamientu + + %d minutu + %d minutos + + + %d hora + %d hores + + + %d día + %d díes + + + %d mes + %d meses + + + diff --git a/app/src/main/res/values-ast/strings_app.xml b/app/src/main/res/values-ast/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-ast/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-ast/strings_errors.xml b/app/src/main/res/values-ast/strings_errors.xml new file mode 100644 index 0000000..7dbde44 --- /dev/null +++ b/app/src/main/res/values-ast/strings_errors.xml @@ -0,0 +1,6 @@ + + + + Ensin conexón d\'internet + Nun hai espaciu abondo + \ No newline at end of file diff --git a/app/src/main/res/values-ast/strings_home.xml b/app/src/main/res/values-ast/strings_home.xml new file mode 100644 index 0000000..c922ba9 --- /dev/null +++ b/app/src/main/res/values-ast/strings_home.xml @@ -0,0 +1,19 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferencies + + + Llei l\'ayuda pa más información, por favor. + + \ No newline at end of file diff --git a/app/src/main/res/values-ast/strings_hosts.xml b/app/src/main/res/values-ast/strings_hosts.xml new file mode 100644 index 0000000..0f37f01 --- /dev/null +++ b/app/src/main/res/values-ast/strings_hosts.xml @@ -0,0 +1,7 @@ + + + Oríxenes d\'agospios + + non disponible + URL: (un recursu https:// o file:// ) + diff --git a/app/src/main/res/values-ast/strings_lists.xml b/app/src/main/res/values-ast/strings_lists.xml new file mode 100644 index 0000000..dc9795f --- /dev/null +++ b/app/src/main/res/values-ast/strings_lists.xml @@ -0,0 +1,11 @@ + + + Llistes de to + + Amiestu d\'un agospiu a la llista prieta + Amiestu d\'un agospiu a la llista blanca + Edición d\'un agospiu na llista prieta + Edición d\'un agospiu na llista blanca + Nome d\'agospiu: + IP (IPv4 o IPv6): + diff --git a/app/src/main/res/values-ast/strings_log.xml b/app/src/main/res/values-ast/strings_log.xml new file mode 100644 index 0000000..6c966ca --- /dev/null +++ b/app/src/main/res/values-ast/strings_log.xml @@ -0,0 +1,6 @@ + + + + Orde alfabéticu + + diff --git a/app/src/main/res/values-ast/strings_notification.xml b/app/src/main/res/values-ast/strings_notification.xml new file mode 100644 index 0000000..a7e352d --- /dev/null +++ b/app/src/main/res/values-ast/strings_notification.xml @@ -0,0 +1,6 @@ + + + Anovamientu disponible + + VPN + \ No newline at end of file diff --git a/app/src/main/res/values-ast/strings_prefs_backup_restore.xml b/app/src/main/res/values-ast/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ast/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ast/strings_prefs_main.xml b/app/src/main/res/values-ast/strings_prefs_main.xml new file mode 100644 index 0000000..6f3b927 --- /dev/null +++ b/app/src/main/res/values-ast/strings_prefs_main.xml @@ -0,0 +1,9 @@ + + + Preferencies + + Xeneral + Estilu escuru + + Depuración + diff --git a/app/src/main/res/values-ast/strings_prefs_root.xml b/app/src/main/res/values-ast/strings_prefs_root.xml new file mode 100644 index 0000000..7327f0d --- /dev/null +++ b/app/src/main/res/values-ast/strings_prefs_root.xml @@ -0,0 +1,13 @@ + + + Ficheru hosts + Ficheru «hosts» oxetivu + + /system/etc/hosts + /data/hosts + /data/data/hosts + Oxetivu personalizáu + + + Redireiciones + diff --git a/app/src/main/res/values-ast/strings_prefs_update.xml b/app/src/main/res/values-ast/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ast/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ast/strings_prefs_vpn.xml b/app/src/main/res/values-ast/strings_prefs_vpn.xml new file mode 100644 index 0000000..717b1e6 --- /dev/null +++ b/app/src/main/res/values-ast/strings_prefs_vpn.xml @@ -0,0 +1,9 @@ + + + Configura les aplicaciones que nun deberíen usar la VPN pa que nenguna conexón se bloquie. + + None + All except browsers + All + + diff --git a/app/src/main/res/values-ast/strings_support.xml b/app/src/main/res/values-ast/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ast/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ast/strings_update.xml b/app/src/main/res/values-ast/strings_update.xml new file mode 100644 index 0000000..b5ae7ed --- /dev/null +++ b/app/src/main/res/values-ast/strings_update.xml @@ -0,0 +1,4 @@ + + + Anovamientu disponible + diff --git a/app/src/main/res/values-ast/strings_welcome.xml b/app/src/main/res/values-ast/strings_welcome.xml new file mode 100644 index 0000000..5daf335 --- /dev/null +++ b/app/src/main/res/values-ast/strings_welcome.xml @@ -0,0 +1,4 @@ + + + Riquese\'l permisu root + diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml new file mode 100644 index 0000000..de361e5 --- /dev/null +++ b/app/src/main/res/values-az/strings.xml @@ -0,0 +1,147 @@ + + + + Çıxış + BaÄŸla + BÉ™li + Xeyr + ÆlavÉ™ Et + Ləğv Et + Yadda saxla + KömÉ™k + + + XoÅŸ GÉ™ldiniz! + AdAway reklamları bloklamaq üçün pulsuz vÉ™ açıq-köklü tÉ™tbiqetmÉ™dir. O reklamları bloklamaq üçün cihazınızdakı reklam ÅŸÉ™bÉ™kÉ™lÉ™rini dÉ™yiÅŸdirir.\nÆlavÉ™ mÉ™lumat lazımdır? AÅŸağıdan kömÉ™yÉ™ göz gÉ™zdirin! + Daha çox kömÉ™k göstÉ™r + YenilÉ™mÉ™ vÉ™ziyÉ™ti + Bütün mÉ™nbÉ™ faylları yüklÉ™nmiÅŸ, ÅŸÉ™xsi siyahınız ilÉ™ birləşdirilmiÅŸ vÉ™ sisteminizdÉ™ tam bir host faylı kimi qurulmuÅŸdur. + Reklam-bloklamanı aç + Reklam-bloklamanı baÄŸla + Web serveri + IÅŸlÉ™nir + Dayanmışdır + Web serveri aç + Web serveri baÄŸla + VPN + İşlÉ™yir + Dayanıb + VPN Aç + + GiriÅŸi RedaktÉ™ Et + TÉ™tbiq et + RedaktÉ™ Et + Sil + + + Daxil edilir… + Çıxarılır.. + + Hosts faylı + Hosts faylı host adlarını IP adreslÉ™rinÉ™ yönlÉ™ndirÉ™n sistem faylıdır. Bu idarÉ™si AdAway tÉ™rÉ™findÉ™n aparılan sadÉ™ bir mÉ™tn faylıdır. Bu da ilk bir neçə sÉ™tir: + Hosts fayl mÉ™lumatı yüklÉ™nir… + Hosts faylını aç + + Standart hosts faylı yaradılır + Yeni hosts faylları var + İnternetÉ™ çıxış yoxdur + İnternetÉ™ çıxış É™lçatan deyil + Ælçatmaz qaynaqlar + Heç bir hosts qaynaqları É™lçatan deyil! + Root icazÉ™si verilmÉ™di + Root tÉ™tbiqinizdÉ™n root icazÉ™si verin + XÉ™ta baÅŸ verdi + ÆlavÉ™ mÉ™lumat üçün logcat\'É™ baxın + Açıqdır + Æn yeni hosts faylları açıldı + BaÄŸlıdır + Standart hosts faylı quruldu + TÉ™tbiq et + HÉ™dÉ™finizdÉ™n /system/etc/hosts \'a olan symlink mövcud deyil yaxud sÉ™hvdir. ÆgÉ™r o düzgün fayla hÉ™dÉ™flÉ™nmÉ™yibsÉ™ AdAway iÅŸlÉ™mÉ™yÉ™cÉ™k.\n\nSymlink yaratmaÄŸa cÉ™hd etmÉ™k istÉ™yirsiniz? + Symlink tapılmır + BölmÉ™dÉ™ kifayÉ™t qÉ™dÉ™r yer yoxdur!\nSeçimlÉ™rdÉ™n hosts faylının hÉ™dÉ™fini /data/data/hosts \'a dÉ™yiÅŸmÉ™yÉ™ cÉ™hd edin. + KifayÉ™t qÉ™dÉ™r yer yoxdur + YüklÉ™nmiÅŸ fayl oxunmur + FÉ™rdi fayl xÉ™tası + BölmÉ™ni yaz/oxu ÅŸÉ™klindÉ™ yenidÉ™n qoÅŸmaq alınmadı! + YenidÉ™n qoÅŸma alınmadı + Hosts faylını kopyalamaq alınmadı! + Kopyalamaq alınmadı + Hosts qaynaqları tÉ™tbiq edildi + TÉ™tbiq uÄŸurla baÅŸa çatdı + TÉ™tbiqetmÉ™ uÄŸurla baÅŸa çatdı.\nDÉ™yiÅŸikliklÉ™rin iÅŸlÉ™mÉ™si üçün Android\'i yenidÉ™n baÅŸlatmaq vacib ola bilÉ™r.\n\nYenidÉ™n baÅŸlatmaq istÉ™yirsiniz?\n(HÉ™min an SD kartı baÅŸqa tÉ™tbiqin istifadÉ™ etmÉ™diyindÉ™n É™min olmaq vÉ™ mÉ™lumat itgisinin qarşısını almaq üçün!) + Symlink uÄŸurla yaradıldı.\nDÉ™yiÅŸikliklÉ™rin iÅŸlÉ™mÉ™si üçün Android\'i yenidÉ™n baÅŸlatmaq vacib ola bilÉ™r.\n\nYenidÉ™n baÅŸlatmaq istÉ™yirsiniz?\n(HÉ™min an SD kartı baÅŸqa tÉ™tbiqin istifadÉ™ etmÉ™diyindÉ™n É™min olmaq vÉ™ mÉ™lumat itgisinin qarşısını almaq üçün!) + Symlink yaratmaq uÄŸurla bitdi + İnternet baÄŸlantısı qurula bilmÉ™di. + ÆlaqÉ™ qurulmadı + YüklÉ™nir… + TÉ™tbiq edilir… + Hosts faylını tÉ™tbiq et + TÉ™tbiqetmÉ™k alınmadı + YüklÉ™mÉ™ alınmadı + FÉ™rdi fayl yaradıla bilmÉ™z. + FÉ™rdi fayl yaratmaq alınmadı + UÄŸurla açıldı + UÄŸurla qapadıldı + + URL\'ni hosts faylına daxil et: + Bu host adı etibarsızdır! + Host adı düzgün formatda deyil + Bu IP etibarsızdır! + YenidÉ™n baÅŸlatma vÉ™ bu sualı gÉ™lÉ™n dÉ™fÉ™ göstÉ™rmÉ™! + YüklÉ™nir… + + + YenilÉ™ + ÆlavÉ™ Et + KömÉ™k + + S-ON/S-OFF + FAQ + ProblemlÉ™r + + + Reklam bloker + Menyunu aç + Menyunu qapat + + + + Ev + Hosts resursları + Siyahılarınız + Open hosts file + Log DNS requests + Scan for adware + TÉ™nzimlÉ™mÉ™lÉ™r + KömÉ™k + + + + + DNS istÉ™klÉ™ri + Siyahılarınız + TÉ™nzimlÉ™mÉ™lÉ™r + + %1$s üçün yenidir + %1$s üçün yenilÉ™mÉ™ lazımdır + Son yenilÉ™mÉ™ %1$s É™vvÉ™l + BilinmÉ™yÉ™n yenilÉ™mÉ™ vÉ™ziyÉ™ti + + %d dÉ™qiqÉ™ + %d dÉ™qiqÉ™ + + + %d saat + %d saat + + + %d gün + %d gün + + + %d ay + %d ay + + + diff --git a/app/src/main/res/values-az/strings_app.xml b/app/src/main/res/values-az/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-az/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-az/strings_errors.xml b/app/src/main/res/values-az/strings_errors.xml new file mode 100644 index 0000000..1e5bf39 --- /dev/null +++ b/app/src/main/res/values-az/strings_errors.xml @@ -0,0 +1,6 @@ + + + + İnternetÉ™ çıxış yoxdur + KifayÉ™t qÉ™dÉ™r yer yoxdur + \ No newline at end of file diff --git a/app/src/main/res/values-az/strings_home.xml b/app/src/main/res/values-az/strings_home.xml new file mode 100644 index 0000000..6ae4eb0 --- /dev/null +++ b/app/src/main/res/values-az/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + TÉ™nzimlÉ™mÉ™lÉ™r + + \ No newline at end of file diff --git a/app/src/main/res/values-az/strings_hosts.xml b/app/src/main/res/values-az/strings_hosts.xml new file mode 100644 index 0000000..bbea683 --- /dev/null +++ b/app/src/main/res/values-az/strings_hosts.xml @@ -0,0 +1,10 @@ + + + Hosts resursları + + É™lçatan deyil + + Qaynaq É™lavÉ™ et + Qaynağı dÉ™yiÅŸ + Hostların kök URL\'ı + diff --git a/app/src/main/res/values-az/strings_lists.xml b/app/src/main/res/values-az/strings_lists.xml new file mode 100644 index 0000000..b294260 --- /dev/null +++ b/app/src/main/res/values-az/strings_lists.xml @@ -0,0 +1,15 @@ + + + Siyahılarınız + + Host\'u qara siyahıya at + Host\'u aÄŸ siyahıya at + Host yönlÉ™ndirici É™lavÉ™ et + Qara siyahıdakı host\'u dÉ™yiÅŸ + AÄŸ siyahıdakı host\'u dÉ™yiÅŸ + YönlÉ™ndirmÉ™ni dÉ™yiÅŸ + Host adı: + Hostların kök URL\'ı + (Wildkart * vÉ™ ? iÅŸarÉ™lÉ™rinÉ™ icazÉ™ verilir) + IP (IPv4 or IPv6): + diff --git a/app/src/main/res/values-az/strings_log.xml b/app/src/main/res/values-az/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-az/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-az/strings_notification.xml b/app/src/main/res/values-az/strings_notification.xml new file mode 100644 index 0000000..0626048 --- /dev/null +++ b/app/src/main/res/values-az/strings_notification.xml @@ -0,0 +1,7 @@ + + + + YenilÉ™mÉ™lÉ™r + + VPN + \ No newline at end of file diff --git a/app/src/main/res/values-az/strings_prefs_backup_restore.xml b/app/src/main/res/values-az/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-az/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-az/strings_prefs_main.xml b/app/src/main/res/values-az/strings_prefs_main.xml new file mode 100644 index 0000000..9286409 --- /dev/null +++ b/app/src/main/res/values-az/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + TÉ™nzimlÉ™mÉ™lÉ™r + diff --git a/app/src/main/res/values-az/strings_prefs_root.xml b/app/src/main/res/values-az/strings_prefs_root.xml new file mode 100644 index 0000000..7fddad3 --- /dev/null +++ b/app/src/main/res/values-az/strings_prefs_root.xml @@ -0,0 +1,13 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + FÉ™rdi hÉ™dÉ™f + + + YönlÉ™ndirmÉ™k + Web serveri aç + diff --git a/app/src/main/res/values-az/strings_prefs_update.xml b/app/src/main/res/values-az/strings_prefs_update.xml new file mode 100644 index 0000000..02be844 --- /dev/null +++ b/app/src/main/res/values-az/strings_prefs_update.xml @@ -0,0 +1,4 @@ + + + YenilÉ™mÉ™lÉ™r + diff --git a/app/src/main/res/values-az/strings_prefs_vpn.xml b/app/src/main/res/values-az/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-az/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-az/strings_support.xml b/app/src/main/res/values-az/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-az/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-az/strings_update.xml b/app/src/main/res/values-az/strings_update.xml new file mode 100644 index 0000000..708cec4 --- /dev/null +++ b/app/src/main/res/values-az/strings_update.xml @@ -0,0 +1,4 @@ + + + YenilÉ™mÉ™ var + diff --git a/app/src/main/res/values-az/strings_welcome.xml b/app/src/main/res/values-az/strings_welcome.xml new file mode 100644 index 0000000..6e98ea1 --- /dev/null +++ b/app/src/main/res/values-az/strings_welcome.xml @@ -0,0 +1,4 @@ + + + Rootlu Android tÉ™lÉ™b olunur + diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml new file mode 100644 index 0000000..ba46e44 --- /dev/null +++ b/app/src/main/res/values-be/strings.xml @@ -0,0 +1,267 @@ + + + + ВыйÑці + Закрыць + Так + Ðе + Дадаць + СкаÑаваць + Захаваць + Дапамога + + + СÑрдÑчна запрашаем! + AdAway - гÑта бÑÑÐ¿Ð»Ð°Ñ‚Ð½Ð°Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ð° з адкрытым зыходным кодам Ð´Ð»Ñ Ð±Ð»Ð°ÐºÑ–Ñ€Ð¾ÑžÐºÑ– Ñ€Ñкламы. Яна збірае адраÑÑ‹ з Ñ€Ñкламнай Ñеткі Ñ– блакуе Ñ–Ñ… на вашай прыладзе.\nХочаце даведацца больш? Чытайце даведку! + Паказаць дадатковую дапамогу + Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð°Ð±Ð½Ð°ÑžÐ»ÐµÐ½Ð½ÑÑž + УÑе файлы hosts, Ñпампаваных з пÑўных крыніц, зліваюцца з вашым улаÑным ÑпіÑам Ñ– ÑžÑталёўваюцца Ñž вашай ÑÑ–ÑÑ‚Ñме Ñž выглÑдзе аднаго файла host + Уключыць блакаванне Ñ€Ñкламы + Ðдключыць блакаванне Ñ€Ñкламы + Ð’Ñб-Ñервер + Працуе + Прыпынена + ЗапуÑціце або Ñпыніце вÑб-Ñервер у лакальнай Ñеткі, каб адказваць на запыты на Ð·Ð°Ð±Ð»Ð°ÐºÐ°Ð²Ð°Ð½Ñ‹Ñ Ñ–Ð¼Ñ‘Ð½Ñ‹ host. + Уключыць вÑб-Ñервер + Ðдключыць вÑб-Ñервер + VPN + Запушчана + Спынена + ЗапуÑціць або Ñпыніць VPN Ð´Ð»Ñ Ñ„Ñ–Ð»ÑŒÑ‚Ñ€Ð°Ñ†Ñ‹Ñ– запытаў. + Уключыць VPN + Ðдключыць VPN + + + РÑдагаваць Ð·Ð°Ð¿Ñ–Ñ + ПрымÑніць + РÑдагаваць + Выдаліць + + + Імпарт… + РÑÐ·ÐµÑ€Ð²Ð¾Ð²Ð°Ñ ÐºÐ¾Ð¿Ñ–Ñ Ð¿Ð°ÑпÑхова імпартавана з вашага знешнÑга Ñховішча. + Ðе ўдалоÑÑ Ñ–Ð¼Ð¿Ð°Ñ€Ñ‚Ð°Ð²Ð°Ñ†ÑŒ Ñ€Ñзервовую копію. Магчыма Ñе фармат не дакладны? Праверце logcat Ð´Ð»Ñ Ð¿Ð°Ð´Ñ€Ð°Ð±ÑзнаÑцÑÑž. + ЭкÑпарт… + РÑзервовае капіраванне паÑпÑхова ÑкÑпартавана Ñž файл \'%s\' на вашым знешнім Ñховішчы. + Ðе атрымалаÑÑ ÑкÑпартаваць файл Ñ€Ñзервовай копіі \'%s\'. + + + Файл hosts + Файл hosts - гÑта ÑÑ–ÑÑ‚Ñмны файл, ÑупаÑтаўлÑючы імёны вузлоў з IP-адраÑамі. ГÑта звычайны Ñ‚ÑкÑтавы файл, змеÑціва Ñкога апрацоўвае AdAway. ВоÑÑŒ Ñго Ð¿ÐµÑ€ÑˆÑ‹Ñ Ñ€Ð°Ð´ÐºÑ–: + Загрузка змеÑціва файла hosts + Ðдкрыць файл hosts + + + Праверка абнаўленнÑÑž + Праверка%s на абнаўленне + Ðтрыманне крыніц + Спампоўка крыніцы %s + Чытанне крыніцы%s + Разбор крыніцы %s + Ð¡Ñ–Ð½Ñ…Ñ€Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ‹Ñ Ð±Ð°Ð·Ñ‹ дадзеных з правіламі + Ðднаўленне Ñтандартнага файла hosts + Стандартны файл hosts адноўлены + СтварÑнне Ñтандартнага файла hosts + ДаÑтупна абнаўленне + ДаÑтупны Ð½Ð¾Ð²Ñ‹Ñ Ñ„Ð°Ð¹Ð»Ñ‹ host + ÐбнаўленнÑÑž крыніц не знойдзены + ÐÑма злучÑÐ½Ð½Ñ Ð· інтÑрнÑтам + ÐÑма падлучÑÐ½Ð½Ñ Ð´Ð° ІнтÑрнÑту + ÐедаÑÑ‚ÑƒÐ¿Ð½Ñ‹Ñ ÐºÑ€Ñ‹Ð½Ñ–Ñ†Ñ‹ + ÐÑма даÑтупных крыніц host! + ДоÑтуп root быў адхілены + Дазвольце root-доÑтуп з вашай праграмы Ð´Ð»Ñ root + Ðешта пайшло не так + Праверце logcat Ð´Ð»Ñ Ð°Ñ‚Ñ€Ñ‹Ð¼Ð°Ð½Ð½Ñ Ð±Ð¾Ð»ÑŒÑˆ падрабÑзнай інфармацыі + Уключана + ВыкарыÑтоўваюцца Ð½Ð¾Ð²Ñ‹Ñ ÑпіÑÑ‹ host + Выключана + УÑталÑваны Ñтандартны файл hosts + ПрымÑніць ÑÐ²ÐµÐ¶Ñ‹Ñ ÐºÑ€Ñ‹Ð½Ñ–Ñ†Ñ‹ + СтварÑнне новага файла hosts + КапіÑванне новага файла hosts + Праверка копіі файла hosts + Файл hosts паÑпÑхова абноўлены + ÐšÐ°Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ‹Ñ VPN паÑпÑхова абноўлена + ÐšÐ°Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ‹Ñ Ð·Ð¼ÐµÐ½ÐµÐ½Ð°. Вам трÑба ўжыць Ñе. + ПрымÑніць + ПрымÑненне новай канфігурацыі + Ðе атрымалаÑÑ Ð¿Ñ€Ñ‹Ð¼Ñніць новую канфігурацыю. + + + ÐдÑутнічае ÑÑ–Ð¼Ð²Ð°Ð»Ñ–Ñ‡Ð½Ð°Ñ ÑпаÑылка на мÑтавай файл hosts + СпаÑылка на ваш /system/etc/hosts нÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ð°Ñ Ð°Ð±Ð¾ не Ñ–Ñнуе! AdAway не будзе працаваць, калі не паказаць правільны файл. Ð’Ñ‹ хочаце паÑпрабаваць Ñтварыць ÑпаÑылку? + СпаÑылка адÑутнічае + Ðе хапае меÑца на раздзеле! ПаÑпрабуйце змÑніць шлÑÑ… да файла Ñž наладах на /data/data/hosts. + Ðе хапае меÑца + Спампаваны файл не можа быць прачытаны. + Збой файла + Ðе атрымалаÑÑ Ð¿ÐµÑ€Ð°Ð¼Ð°Ð½Ñ‚Ð°Ð²Ð°Ñ†ÑŒ раздзел Ð´Ð»Ñ Ñ‡Ñ‹Ñ‚Ð°Ð½Ð½Ñ/запіÑу! + Перамантаваць не ўдалоÑÑ + Ðе атрымалаÑÑ ÑкапіÑваць файл hosts + КапіÑванне файла hosts не ўдалоÑÑ! + КапіÑванне не ўдалоÑÑ + ВыкарыÑтоўваюцца крыніцы hosts + ПрымÑненне прайшло паÑпÑхова + ПрымÑненне прайшло паÑпÑхова.\nМагчыма, ÑпатрÑбіцца перазагрузіць Android, каб змены ÑžÑтупілі Ñž Ñілу.\n\nÐ’Ñ‹ хочаце перагрузіць Android?\n(Ð”Ð»Ñ Ð¿Ñ€Ð°Ð´ÑƒÑ…Ñ–Ð»ÐµÐ½Ð½Ñ Ñтраты дадзеных пераканайцеÑÑ, што ніÑÐºÑ–Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ Ñž дадзены момант не выкарыÑтоўваюць карту памÑці!) + СпаÑылка Ñтворана паÑпÑхова.\nМагчыма, ÑпатрÑбіцца перазагрузіць Android, каб змены ÑžÑтупілі Ñž Ñілу.\n\nÐ’Ñ‹ хочаце перагрузіць Android?\n(Ð”Ð»Ñ Ð¿Ñ€Ð°Ð´ÑƒÑ…Ñ–Ð»ÐµÐ½Ð½Ñ Ñтраты дадзеных пераканайцеÑÑ, што ніÑÐºÑ–Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ Ñž дадзены момант не выкарыÑтоўваюць карту памÑці!) + СпаÑылка Ñтворана паÑпÑхова + Android не змог Ñтварыць ÑпаÑылку.\nМагчыма гÑта з-за аÑабліваÑці Ñ‚Ñлефонаў HTC, званай S-ON!\n\nРашÑнне заключаецца Ñž загрузцы Ñ‚Ñлефона Ñž Ñ€Ñжыме Ð°Ð´Ð½Ð°ÑžÐ»ÐµÐ½Ð½Ñ Ñ– ÑтварÑÐ½Ð½Ñ ÑпаÑылкі пры дапамозе \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nКалі гÑта не дапаможа, то трÑба шукаць інфармацыю Ñž інтÑрнÑце па S-OFF Ñ– вашаму Ñ‚Ñлефоне. + Памылка ÑтварÑÐ½Ð½Ñ ÑпаÑылкі + Калі лаÑка, чытайце Даведку Ð´Ð»Ñ Ð°Ñ‚Ñ€Ñ‹Ð¼Ð°Ð½Ð½Ñ Ð±Ð¾Ð»ÑŒÑˆÐ°Ð¹ інфармацыі. + У наладах APN вашага Android паказаны прокÑÑ–-Ñервер!\nAdAway не будзе працаваць у мабільных Ñетках, такіх Ñк 3G. Ð’Ñ‹ можаце адключыць гÑты Ñервер прокÑÑ– у наладах выкарыÑтаннай APN (з праграмы Ðалад: Сетка Ñ– ІнтÑрнÑÑ‚ -> ÐœÐ°Ð±Ñ–Ð»ÑŒÐ½Ð°Ñ Ñетка -> Дадаткова -> Кропкі доÑтупу APN) Ñ– выдаліць значÑнне Ñž полі ПрокÑÑ–. + ВыкарыÑÑ‚Ð¾ÑžÐ²Ð°Ð½Ð°Ñ ÐºÑ€Ð¾Ð¿ÐºÐ° доÑтупу працуе праз прокÑÑ–-Ñервер! + ÐдÑутнічае падключÑнне да інтÑрнÑту. + ÐÑма злучÑÐ½Ð½Ñ + Спампоўка… + ПрымÑненне… + ПрымÑніць чорны Ñ– белы ÑÐ¿Ñ–Ñ + Разбор Ñ– аб\'Ñднанне файлаў Ñа ÑпіÑамі hosts + Пабудова файла hosts + ПрымÑненне файла hosts + Ðе атрымалаÑÑ Ð¿Ñ€Ñ‹Ð¼Ñніць новы файл hosts. + Ðе атрымалаÑÑ Ð¿Ñ€Ñ‹Ð¼Ñніць файл Hosts на вашай ÑÑ–ÑÑ‚Ñме! +ПаÑпрабуйце змÑніць шлÑÑ… да файла Hosts Ñž наладах на /data/data/hosts + ПрымÑненне не ўдалоÑÑ + Калі лаÑка, праверце, вашу праграму, ÑÐºÐ°Ñ Ð¿Ñ€Ð°Ð´Ð°ÑтаўлÑе root-доÑтуп. + Ð’Ñ‹ вÑрнуліÑÑ Ð´Ð° файла Hosts па змаўчанні.\nМагчыма, ÑпатрÑбіцца перазагрузіць Android, каб змены ÑžÑтупілі Ñž Ñілу.\n\nÐ’Ñ‹ хочаце перагрузіць Android?\n(Ð”Ð»Ñ Ð¿Ñ€Ð°Ð´ÑƒÑ…Ñ–Ð»ÐµÐ½Ð½Ñ Ñтраты дадзеных пераканайцеÑÑ, што ніÑÐºÑ–Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ Ñž дадзены момант не выкарыÑтоўваюць карту памÑці!) + Ð’Ñртанне адбылоÑÑ Ð¿Ð°ÑпÑхова + Ðе атрымалаÑÑ Ð°Ð´Ð½Ð°Ð²Ñ–Ñ†ÑŒ файл hosts + Ðднаўленне не атрымалаÑÑ Ð¿Ð° невÑдомых прычынах. + Ðднаўленне не атрымалаÑÑ! + ÐÑ–Ð²Ð¾Ð´Ð½Ð°Ñ Ð· вашых актыўных крыніц host недаÑтупнаÑ! Ð’Ñ‹ правільна Ð¿Ð°Ð´Ð»ÑƒÑ‡Ð°Ð½Ñ‹Ñ Ð´Ð° інтÑрнÑту? + Памылка Ñпампоўкі + Ðе атрымалаÑÑ Ð·Ð°Ð¿Ñ–Ñаць новы файл hosts + Файл не можа быць Ñтвораны. + Ðе атрымалаÑÑ Ñтварыць файл + Ð’Ñ‹ актывавалі беÑÑÑ–ÑÑ‚Ñмны Ñ€Ñжым.\nМагчыма, ÑпатрÑбіцца перазагрузіць Android, каб змены ÑžÑтупілі Ñž Ñілу.\n\nÐ’Ñ‹ хочаце перагрузіць Android?\n(Ð”Ð»Ñ Ð¿Ñ€Ð°Ð´ÑƒÑ…Ñ–Ð»ÐµÐ½Ð½Ñ Ñтраты дадзеных пераканайцеÑÑ, што ніÑÐºÑ–Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ Ñž дадзены момант не выкарыÑтоўваюць карту памÑці!) + ÐÐºÑ‚Ñ‹Ð²Ð°Ñ†Ñ‹Ñ Ð¿Ñ€Ð°Ð¹ÑˆÐ»Ð° паÑпÑхова + Ð’Ñ‹ адключылі беÑÑÑ–ÑÑ‚Ñмны Ñ€Ñжым.\nМагчыма, ÑпатрÑбіцца перазагрузіць Android, каб змены ÑžÑтупілі Ñž Ñілу.\n\nÐ’Ñ‹ хочаце перагрузіць Android?\n(Ð”Ð»Ñ Ð¿Ñ€Ð°Ð´ÑƒÑ…Ñ–Ð»ÐµÐ½Ð½Ñ Ñтраты дадзеных пераканайцеÑÑ, што ніÑÐºÑ–Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ Ñž дадзены момант не выкарыÑтоўваюць карту памÑці!) + ПаÑпÑхова адключана + Ðе атрымалаÑÑ ÑžÐºÐ»ÑŽÑ‡Ñ‹Ñ†ÑŒ VPN блакаванне Ñ€Ñкламы. + Ðе атрымалаÑÑ Ð°Ð´ÐºÐ»ÑŽÑ‡Ñ‹Ñ†ÑŒ VPN блакаванне Ñ€Ñкламы. + Уключыць модуль hosts Magisk + Уключыць беÑÑÑ–ÑÑ‚Ñмную функцыю hosts з мÑнÑджара Magisk. СÑрод Ñго налад уключыце параметр БеÑÑÑ–Ñтемны hosts, затым перазагрузіце вашу прыладу. + Ðдключыць модуль Magisk hosts + Ðдключыць беÑÑÑ–ÑÑ‚Ñмную функцыю hosts з мÑнÑджара Magisk. СÑрод Ñго налад выдаліце ​​модуль БеÑÑÑ–Ñтемны hosts, затым перазагрузіце вашу прыладу. + + + УÑтаўце URL у файл hosts: + ГÑта недапушчальнае Ñ–Ð¼Ñ ÐºÑ€Ñ‹Ð½Ñ–Ñ†Ñ‹! + ÐÑправільна адфарматаванае Ñ–Ð¼Ñ host + ГÑта недапушчальны IP-адраÑ! + ÐÑправільна адфарматаваны IP-Ð°Ð´Ñ€Ð°Ñ + ÐÑ Ð¿ÐµÑ€Ð°Ð·Ð°Ð³Ñ€ÑƒÐ¶Ð°Ñ†ÑŒ Ñ– не паказваць гÑтае пытанне Ñž далейшым + Загрузка… + + + Ðбнавіць + Дадаць + Дапамога + Імпартаваць Ñ€Ñзервовую копію + ЭкÑпарт Ñ€Ñзервовай копіі + + + S-ON/S-OFF + FAQ + Праблемы + + + Праграмы з Ñ€Ñкламай + Пошук праграм з Ñ€Ñкламай, Ð·Ð²Ð°Ð½Ñ‹Ñ Adware, Ñ– ÑÐºÑ–Ñ AdAway не можа заблакаваць. ГÑÑ‚Ñ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ выкарыÑтоўваюць, напрыклад, ÑÑ–ÑÑ‚Ñму апавÑшчÑннÑÑž Airpush, ÑÐºÐ°Ñ Ð¿Ð°ÐºÐ°Ð·Ð²Ð°Ðµ Ñ€Ñкламу нават тады, калі праграма не працуе, ці нават можа змÑніць мелодыю вашага званка. Пазбавіцца ад такой Ñ€Ñкламы можна толькі выдаліўшы праграму, Ð½Ð°Ð·Ð²Ð°Ð½Ñ‹Ñ Ñž выніках ÑканаваннÑ, шлÑхам націÑку на Ñкладнікі ÑпіÑаў. + Сканаванне… + Праграм з Ñ€Ñкламай не знойдзена! + + + Блакавальнік Ñ€Ñкламы + Ðе ÑžÑталÑваны Ñ‚ÑкÑтавы Ñ€Ñдактар + Ðе знойдзены Ñ‚ÑкÑтавы Ñ€Ñдактар â€‹â€‹Ð´Ð»Ñ Ð°Ð´ÐºÑ€Ñ‹Ñ†Ñ†Ñ Ñ„Ð°Ð¹Ð»Ð° hosts. Ð’Ñ‹ можаце ÑžÑталÑваць Ñ€Ñдактар ​​Jota ці іншай Ñ‚ÑкÑтавы Ñ€Ñдактар, каб гÑта выправіць.\n\nÐ’Ñ‹ жадаеце ÑžÑталÑваць Ñ€Ñдактар ​​Jota? + Ðе ÑžÑталÑваны файлавы менеджÑÑ€ + ÐÑма файлавага мÑнÑджара Ð´Ð»Ñ Ð°Ð´ÐºÑ€Ñ‹Ñ†Ñ†Ñ Ñ„Ð°Ð¹Ð»Ð°. Ð’Ñ‹ можаце ÑžÑталÑваць OI File Manager ці іншы файлавы менеджÑÑ€, каб гÑта выправіць.\n\nÐ’Ñ‹ жадаеце ÑžÑталÑваць OI File Manager? + + + Tcpdump + Tcpdump гÑта інÑтрумент Ð´Ð»Ñ Ð¼Ð°Ð½Ñ–Ñ‚Ð¾Ñ€Ñ‹Ð½Ð³Ñƒ запытаў DNS Ñ– Ñ–Ñ… Ð·Ð°Ñ…Ð°Ð²Ð°Ð½Ð½Ñ Ñž файле журнала. ЗапуÑціце Tcpdump, ён будзе працаваць у фонавым Ñ€Ñжыме да перазагрузкі прылады - запуÑціце праграму, у Ñкой на Ñкране паказваецца Ñ€Ñклама - прааналізуйце запыты DNS, выкарыÑтоўваючы файл журнала. Ð—Ð½Ð¾Ð¹Ð´Ð·ÐµÐ½Ñ‹Ñ Ñž ім Ð¿Ð°Ð´Ð°Ð·Ñ€Ð¾Ð½Ñ‹Ñ Ñервера, Ð¼Ð°Ð³Ñ‡Ñ‹Ð¼Ñ‹Ñ Ñк крыніцы Ñ€Ñкламы, могуць быць унеÑены Ñž чорны ÑпіÑ. + Ðдключыць маніторынг + Уключыць маніторынг + Паказаць вынікі + Сартаваць дамены + ÐчыÑціць журнал + Дадаць Ð·Ð°Ð¿Ñ–Ñ Ñƒ Чорны ÑÐ¿Ñ–Ñ + Дадаць Ð·Ð°Ð¿Ñ–Ñ Ñƒ Белы ÑÐ¿Ñ–Ñ + Дадаць Ð·Ð°Ð¿Ñ–Ñ Ñƒ ÑÐ¿Ñ–Ñ Ð¿ÐµÑ€Ð°Ð½Ð°ÐºÑ–Ñ€Ð°Ð²Ð°Ð½Ð½ÑÑž + + РÑдагаваць значÑнне Ñ‚ÑкÑтавай перавагі + Ðдкрыць меню + Закрыць меню + + + + Ð“Ð°Ð»Ð¾ÑžÐ½Ð°Ñ + Крыніцы hosts + Вашы ÑпіÑÑ‹ + Ðдкрыць файл hosts + ЗапіÑваць запыты DNS + Сканаванне Adware + Ðалады + Дапамога + + + + + Запыты DNS + Вашы ÑпіÑÑ‹ + Ðалады + + + УÑталÑвана %1$s назад + Ðктуальна %1$s + Патрабуецца абнаўленне %1$s + ÐпошнÑе абнаўленне %1$s таму + ÐевÑдомы ÑÑ‚Ð°Ñ‚ÑƒÑ Ð°Ð±Ð½Ð°ÑžÐ»ÐµÐ½Ð½Ñ + некалькі хвілін + + %d хвіліна + %d хвіліны + %d хвілін + %d хвілін + + + %d гадзіна + %d гадзіны + %d гадзін + %d гадзін + + + %d дзень + %d дні + %d дзён + %d дзён + + + %d меÑÑц + %d меÑÑцы + %d меÑÑцаў + %d меÑÑцаў + + + + пачынаецца + актыўна + Ñпынена + чаканне Ñеткі + перападключÑнне + памылка перападключÑнне + прыпынена + Ñпынена + VPN блакіроўшчыка %1$s + Паўза + Ðднавіць + + + Дазволы AdAway + Дазволіць узаемадзеÑнне з AdAway + ÐдпраўлÑць каманды на AdAway + Дазволіць адпраўку каманд у AdAway, напрыклад, уключÑнне або адключÑнне ÑÑ–ÑÑ‚Ñмнай блакіроўкі Ñ€Ñкламы + + diff --git a/app/src/main/res/values-be/strings_app.xml b/app/src/main/res/values-be/strings_app.xml new file mode 100644 index 0000000..75b320c --- /dev/null +++ b/app/src/main/res/values-be/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Блакіроўшчык Ñ€Ñкламы з адкрытым зыходным кодам + Лагатып AdAway + diff --git a/app/src/main/res/values-be/strings_errors.xml b/app/src/main/res/values-be/strings_errors.xml new file mode 100644 index 0000000..1574310 --- /dev/null +++ b/app/src/main/res/values-be/strings_errors.xml @@ -0,0 +1,22 @@ + + + + ÐÑма злучÑÐ½Ð½Ñ Ð· інтÑрнÑтам + Ðемагчыма ÑžÑталÑваць злучÑнне з інтÑрнÑтам. Калі лаÑка, праверце падлучÑнне вашай прылады. + Ðе атрымалаÑÑ Ð·Ð°Ð³Ñ€ÑƒÐ·Ñ–Ñ†ÑŒ крыніцу hosts + ÐÑ– Ð²Ð¾Ð´Ð½Ð°Ñ Ð· вашых уключаных крыніц hosts недаÑтупна. Калі лаÑка, праверце падлучÑнне да інтÑрнÑту. + + Ðе атрымалаÑÑ Ñтварыць прыватны файл + Ðе атрымалаÑÑ Ñтварыць прыватны файл Ð´Ð»Ñ Ð³ÐµÐ½ÐµÑ€Ð°Ñ†Ñ‹Ñ– hosts. ПераканайцеÑÑ, што на вашай прыладзе Ñ‘Ñць меÑца. + Ðе хапае меÑца + Ðе ўдалоÑÑ ÐºÐ°Ð¿Ñ–Ñ€Ð°Ð²Ð°Ñ†ÑŒ файл hosts Ñž ÑÑ–ÑÑ‚Ñмны падзел. Калі лаÑка, праверце, ці ўключаны ÑÑ–ÑÑ‚Ñмны модуль Magisk, затым перазагрузіце Ñмартфон. + Ðе атрымалаÑÑ ÑžÑталÑваць новы файл hosts. + Ðе ўдалоÑÑ ÑкапіÑваць файл hosts Ñž раздзел /system. ПераканайцеÑÑ, што Ñž ÑÑ–ÑÑ‚Ñмным модулі Magisk ўключана перазагрузка. + Ðе атрымалаÑÑ Ð°Ð´Ð½Ð°Ð²Ñ–Ñ†ÑŒ файл hosts + Ðемагчыма аднавіць канфігурацыю файла host па змаўчанні. + + Ðе атрымалаÑÑ ÑžÐºÐ»ÑŽÑ‡Ñ‹Ñ†ÑŒ VPN блакаванне Ñ€Ñкламы. + Калі лаÑка, праверце налады VPN, каб аўтарызаваць праграму VPN Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку. + Ðе атрымалаÑÑ Ð°Ð´ÐºÐ»ÑŽÑ‡Ñ‹Ñ†ÑŒ VPN блакаванне Ñ€Ñкламы. + Калі лаÑка, праверце налады VPN, каб адключыць Ñго ўручную. + diff --git a/app/src/main/res/values-be/strings_home.xml b/app/src/main/res/values-be/strings_home.xml new file mode 100644 index 0000000..ae9f88d --- /dev/null +++ b/app/src/main/res/values-be/strings_home.xml @@ -0,0 +1,50 @@ + + + + + Заблакавана + Дазволена + Перанакіравана + + + + %d up-to-date source + %d up-to-date sources + %d up-to-date sources + %d up-to-date sources + + + %d outdated source + %d outdated sources + %d outdated sources + %d outdated sources + + Праверка наÑўнаÑці абнаўленнÑÑž hosts + Ðбнаўленне hosts + + + Паказаць журнал запытаў DNS + + + Паказаць падказкі + + + Ðдкрыць Ñтаронку GitHub + + + Падтрымаць праект + + + GitHub праект + Ðалады + + + Ðдкрыць навігацыйную шторку + Прыпыніць/працÑгнуць блакаванне Ñ€Ñкламы + Ðбнавіць Ð·Ð°Ð±Ð»Ð°ÐºÐ°Ð²Ð°Ð½Ñ‹Ñ Ð´Ð°Ð¼ÐµÐ½Ñ‹ + Паказаць Ð·Ð°Ð¿Ñ‹Ñ‚Ð°Ð½Ñ‹Ñ Ð´Ð°Ð¼ÐµÐ½Ñ‹ + + + Калі лаÑка, чытайце Даведку Ð´Ð»Ñ Ð°Ñ‚Ñ€Ñ‹Ð¼Ð°Ð½Ð½Ñ Ð±Ð¾Ð»ÑŒÑˆÐ°Ð¹ інфармацыі. + + \ No newline at end of file diff --git a/app/src/main/res/values-be/strings_hosts.xml b/app/src/main/res/values-be/strings_hosts.xml new file mode 100644 index 0000000..6a1b1b9 --- /dev/null +++ b/app/src/main/res/values-be/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Крыніцы hosts + + Ð¡Ð¿Ñ–Ñ ÐºÐ°Ñ€Ñ‹Ñтальнікаў + AdAway афіцыйны hosts + StevenBlack уніфікаваны hosts + Pete Lowe blocklist hosts + + недаÑтупны + %s hosts + + Дадаць крыніцу + РÑдагаваць крыніцу + URL: (Ñ€ÑÑÑƒÑ€Ñ https:// ці file://) + URL крыніцы hosts + diff --git a/app/src/main/res/values-be/strings_lists.xml b/app/src/main/res/values-be/strings_lists.xml new file mode 100644 index 0000000..9a19718 --- /dev/null +++ b/app/src/main/res/values-be/strings_lists.xml @@ -0,0 +1,23 @@ + + + Вашы ÑпіÑÑ‹ + + Заблакавана + Дазволена + Перанакіравана + + Фільтраваць hosts + Пошук назвы host… + Пераключыць крыніцы + + Дадаць host у чорны ÑÐ¿Ñ–Ñ + Дадаць host у белы ÑÐ¿Ñ–Ñ + Дадаць перанакіраванне host + РÑдагаваць чорны ÑÐ¿Ñ–Ñ host + РÑдагаваць белы ÑÐ¿Ñ–Ñ host + ЗмÑніць перанакіраванне + Ðазва крыніцы: + URL крыніцы hosts + (ДапуÑкаюцца падÑÑ‚Ð°Ð½Ð¾ÑžÐ½Ñ‹Ñ Ñімвалы * Ñ– ?) + IP (IPv4 ці IPv6): + diff --git a/app/src/main/res/values-be/strings_log.xml b/app/src/main/res/values-be/strings_log.xml new file mode 100644 index 0000000..a748898 --- /dev/null +++ b/app/src/main/res/values-be/strings_log.xml @@ -0,0 +1,8 @@ + + + + Сартаваць па алфавіту + Сартаванне па найвышÑйшаму ўзроўню дамена + + Перанакіраваць дамен + diff --git a/app/src/main/res/values-be/strings_notification.xml b/app/src/main/res/values-be/strings_notification.xml new file mode 100644 index 0000000..6912475 --- /dev/null +++ b/app/src/main/res/values-be/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Ðбнаўленне + ÐÐ¾Ð²Ñ‹Ñ Ð°Ð¿Ð°Ð²ÑшчÑнні аб абнаўленні + ДаÑтупна абнаўленне + Ð”Ð»Ñ Ñпампоўкі даÑтупны Ð½Ð¾Ð²Ñ‹Ñ Ñ„Ð°Ð¹Ð»Ñ‹ hosts. + ДаÑтупна абнаўленне праграмы + ÐÐ¾Ð²Ð°Ñ Ð²ÐµÑ€ÑÑ–Ñ AdAway даÑтупна Ð´Ð»Ñ Ñпампоўкі + + VPN + ÐпавÑшчÑнне VPN запушчана + \ No newline at end of file diff --git a/app/src/main/res/values-be/strings_prefs_backup_restore.xml b/app/src/main/res/values-be/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..5c8c767 --- /dev/null +++ b/app/src/main/res/values-be/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + РÑÐ·ÐµÑ€Ð²Ð¾Ð²Ð°Ñ ÐºÐ¾Ð¿Ñ–Ñ Ñ– аднаўленне + РÑÐ·ÐµÑ€Ð²Ð¾Ð²Ð°Ñ ÐºÐ¾Ð¿Ñ–Ñ + Захаваць Ñ€Ñзервовую копію вашых правілаў Ð±Ð»Ð°ÐºÐ°Ð²Ð°Ð½Ð½Ñ Ð½Ð° знешні ноÑьбіт + Ðднаўленне + Ðднавіць Ð²Ð°ÑˆÑ‹Ñ Ð¿Ñ€Ð°Ð²Ñ–Ð»Ñ‹ Ð±Ð»Ð°ÐºÐ°Ð²Ð°Ð½Ð½Ñ Ð· файла Ñ€Ñзервовай копіі + diff --git a/app/src/main/res/values-be/strings_prefs_main.xml b/app/src/main/res/values-be/strings_prefs_main.xml new file mode 100644 index 0000000..a93f303 --- /dev/null +++ b/app/src/main/res/values-be/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Ðалады + + Галоўные + Ð¦Ñ‘Ð¼Ð½Ð°Ñ Ñ‚Ñма + + Ð¡Ð²ÐµÑ‚Ð»Ð°Ñ + Ð¦Ñ‘Ð¼Ð½Ð°Ñ + СіÑÑ‚ÑÐ¼Ð½Ð°Ñ + + Ðўтаматычнае абнаўленне + + Блакіроўка Ñ€Ñкламы + Блакавальнік Ñ€Ñкламы на аÑнове root + Блакавальнік Ñ€Ñкламы на аÑнове VPN + Уключыць падтрымку IPv6 + РÑÐ·ÐµÑ€Ð²Ð¾Ð²Ð°Ñ ÐºÐ¾Ð¿Ñ–Ñ / аднаўленне правілаў Ð±Ð»Ð°ÐºÐ°Ð²Ð°Ð½Ð½Ñ + + РÑжым адладкі + ÐдпраўлÑць Ñправаздачы аб памылках + ÐдпраўлÑць у Sentry (sentry.io) + Ðе падтрымліваецца Ñž гÑтай зборцы + Журнал адладкі + Ð”Ð»Ñ Ð¿Ñ€Ñ‹Ð¼ÑÐ½ÐµÐ½Ð½Ñ Ð¿Ð°Ñ‚Ñ€Ð°Ð±ÑƒÐµÑ†Ñ†Ð° перазапуÑк праграмы + diff --git a/app/src/main/res/values-be/strings_prefs_root.xml b/app/src/main/res/values-be/strings_prefs_root.xml new file mode 100644 index 0000000..505cd78 --- /dev/null +++ b/app/src/main/res/values-be/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Блакавальнік Ñ€Ñкламы на аÑнове root + + УÑталёўка hosts + Ðдкрыць файл hosts + ШлÑÑ… да файла hosts + Прачытайце даведку перад выкарыÑтаннем гÑтай магчымаÑці + + /system/etc/hosts + /data/hosts + /data/data/hosts + КарыÑÑ‚Ð°Ñ†ÐºÑ–Ñ Ð½Ð°Ð»Ð°Ð´Ñ‹ + + КарыÑтацкае мÑтавае размÑшчÑнне + Схаваць дыÑлог перазагрузкі паÑÐ»Ñ Ð¿Ñ€Ñ‹Ð¼ÑÐ½ÐµÐ½Ð½Ñ + + Перанакіраванне + Вызначыць куды пераадраÑоўваць Ð·Ð°Ð±Ð»Ð°ÐºÐ°Ð²Ð°Ð½Ñ‹Ñ hosts + Перанакіраванне IPv4 + Перанакіраванне IPv6 + ÐÑправільнае перанакіраванне + + Лакальны вÑб-Ñервер + Лакальны вÑб-Ñервер праÑлухоўвае Ð»Ð°ÐºÐ°Ð»ÑŒÐ½Ñ‹Ñ IP адраÑÑ‹ Ñ– адказвае на запыты да заблакаваных hosts. ГÑта дапаможа пазбÑгаць завіÑаннÑÑž пры блакаванні падключÑннÑÑž. + Уключыць вÑб-Ñервер + ТÑÑтавы вÑб-Ñервер + УÑталÑваць ÑамападпіÑаны Ñертыфікат + Ð ÑƒÑ‡Ð½Ð°Ñ ÑžÑталёўка Ñертыфіката + Пачынаючы з Android 11 (R), праграма больш не можа аўтаматычна ÑžÑталёўваць цÑнтр Ñертыфікацыі (CA).\n\nПерайдзіце Ñž налады «БÑÑпека», «Шыфраванне Ñ– ÑžÐ»Ñ–ÐºÐ¾Ð²Ñ‹Ñ Ð´Ð°Ð½Ñ‹Ñ», затым «УÑталÑваць Ñертыфікат». Ðдтуль выберыце «Сертыфікат ЦС» Ñ– абÑрыце новы ÑкÑпартаваны файл Ñертыфіката. + Ðдкрыйце налады «БÑÑпека». + Праверка… + Ðе запушчана + Запушчаны, але Ñертыфікат не ÑžÑталÑваны + Запушчаны, Ñертыфікат уÑталÑваны + ЗамÑніць пуÑтое Ñ€Ñкламнае меÑца на значок праграмы + diff --git a/app/src/main/res/values-be/strings_prefs_update.xml b/app/src/main/res/values-be/strings_prefs_update.xml new file mode 100644 index 0000000..f23f4d8 --- /dev/null +++ b/app/src/main/res/values-be/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + Ðбнаўленне + + Ðбнаўленне праграмы + Праверце наÑўнаÑць абнаўленнÑÑž пры запуÑку + ПерыÑÐ´Ñ‹Ñ‡Ð½Ð°Ñ Ð¿Ñ€Ð°Ð²ÐµÑ€ÐºÐ° абнаўленнÑÑž + Шукаць бÑта-верÑÑ–Ñ– + + Ðбнаўленне hosts + Праверце наÑўнаÑць абнаўленнÑÑž пры запуÑку + ПерыÑÐ´Ñ‹Ñ‡Ð½Ð°Ñ Ð¿Ñ€Ð°Ð²ÐµÑ€ÐºÐ° абнаўленнÑÑž + Ð¡Ñ–Ð½Ñ…Ñ€Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ‹Ñ Ð¿Ñ€Ñ‹ абнаўленні + Ð¡Ñ–Ð½Ñ…Ñ€Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ‹Ñ Ñ‚Ð¾Ð»ÑŒÐºÑ– Ñž неабароненай Ñеткі + diff --git a/app/src/main/res/values-be/strings_prefs_vpn.xml b/app/src/main/res/values-be/strings_prefs_vpn.xml new file mode 100644 index 0000000..8c5abf4 --- /dev/null +++ b/app/src/main/res/values-be/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Блакавальнік Ñ€Ñкламы на аÑнове VPN + + Уключыць пры запуÑку + Праверка злучÑнне + ПерыÑдычна правÑрайце Ñтан Ñеткі, каб перазапуÑціць VPN пры адключÑнні. + + Ð’Ñ‹ÐºÐ»ÑŽÑ‡Ð°Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ + Ðаладзьце, ÑÐºÑ–Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ не павінны выкарыÑтоўваць VPN, каб злучÑнні не былі заблакаваныÑ. + Выключыць ÑÑ–ÑÑ‚ÑÐ¼Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ + + ÐÑма + УÑе, Ð°ÐºÑ€Ð°Ð¼Ñ Ð±Ñ€Ð°ÑžÐ·Ñраў + УÑе + + Выключыце карыÑÑ‚Ð°Ñ†ÐºÑ–Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ + + + Ð’Ñ‹ÐºÐ»ÑŽÑ‡Ð°Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ + Выбраць уÑе + ЗнÑць выбар уÑÑ–Ñ… + Значок праграмы + diff --git a/app/src/main/res/values-be/strings_support.xml b/app/src/main/res/values-be/strings_support.xml new file mode 100644 index 0000000..613ad2d --- /dev/null +++ b/app/src/main/res/values-be/strings_support.xml @@ -0,0 +1,5 @@ + + + Падтрымаць + Стань ÑпонÑарам + \ No newline at end of file diff --git a/app/src/main/res/values-be/strings_update.xml b/app/src/main/res/values-be/strings_update.xml new file mode 100644 index 0000000..a216a32 --- /dev/null +++ b/app/src/main/res/values-be/strings_update.xml @@ -0,0 +1,21 @@ + + + Ðбнавіць AdAway + + ДаÑтупна абнаўленне! + + + У Ð²Ð°Ñ Ð°ÐºÑ‚ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ Ð²ÐµÑ€ÑÑ–Ñ + ДаÑтупна абнаўленне + Ðбнаўленне AdAway + Ðбнавіць зараз + %1$s / %2$s + ÐÐ¿Ð¾ÑˆÐ½Ñ–Ñ Ð·Ð¼ÐµÐ½Ñ‹ + Ð¡Ð¿Ñ–Ñ Ð·Ð¼ÐµÐ½ + Падтрымаць раÑпрацоўку + ÐхвÑраваць + СпонÑар + + + Ідзе Ñпампоўка апошнÑй верÑÑ–Ñ– AdAway … + diff --git a/app/src/main/res/values-be/strings_welcome.xml b/app/src/main/res/values-be/strings_welcome.xml new file mode 100644 index 0000000..ffdac8b --- /dev/null +++ b/app/src/main/res/values-be/strings_welcome.xml @@ -0,0 +1,52 @@ + + + СардÑчна запрашаем + Першы крок + Другі крок + Ðпошні крок + + + СардÑчна запрашаем у AdAway! + AdAway падае два метаду Ð±Ð»Ð°ÐºÐ°Ð²Ð°Ð½Ð½Ñ Ñ€Ñкламы. Выберыце той, Ñкі вам паÑуе: + + Лагатып root + Root\n блакіроўка Ñ€Ñкламы + ХутчÑй + Эканоміць батарÑÑŽ + Патрабуюцца рут правы + + Лагатып VPN + VPN\nблакіроўка Ñ€Ñкламы + Павольней + Працуе Ñž фоне + СумÑшчальны + + Ð”Ð»Ñ Android патрабуюцца правы Root + Ðльбо двайковы файл su не знойдзены, альбо вы не далі права root Ð´Ð»Ñ AdAway.\n\nГÑта можа здарыцца, калі ваша прылада не мае root-правоў. Ð’Ñ‹ можаце знайÑці інфармацыю аб тым, Ñк атрымаць root правы на вашай прыладзе, на wiki.lineageos.org або іншых Ñайтах Android. + + ПлюÑÑ‹ + МінуÑÑ‹ + + + Ð¡Ñ–Ð½Ñ…Ñ€Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ‹Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐ°Ð½Ð° + Памылка пры Ñінхранізацыі + + Ð¡Ñ–Ð½Ñ…Ñ€Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ‹Ñ + Сінхранізавана! + AdAway загружае ÑпіÑÑ‹ Ð±Ð»Ð°ÐºÐ°Ð²Ð°Ð½Ð½Ñ Ð· анлайн-крыніц. Ð’Ñ‹ можаце змÑніць Ñ–Ñ… пазней у наладах. + Паўтарыць Ñінхранізацыю + Ð¡Ñ–Ð½Ñ…Ñ€Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ‹Ñ Ð½Ðµ ўдалаÑÑ: %1$s nПаўтарыць зараз? + + + Падтрымаць + Падтрымай мÑне! + ГÑта бÑÑÐ¿Ð»Ð°Ñ‚Ð½Ð°Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ð° з адкрытым зыходным кодам. Я займаюÑÑ Ð³Ñтым у вольны чаÑ. Так што, калі вам гÑта падабаецца, не ÑаромейцеÑÑ Ð¿Ð°ÐºÐ°Ð·Ð°Ñ†ÑŒ Ñваю падтрымку: + ÐхвÑраваць на PayPal + Вам не падабаюцца памылкі? Мне такÑама. + Уключыць Ñ‚Ñлеметрыю Ð´Ð»Ñ Ð°Ð´Ð¿Ñ€Ð°ÑžÐºÑ– мне Ñправаздач аб збоÑÑ… + + + Ðазад + Далей + Завершыць + diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml new file mode 100644 index 0000000..27bdf08 --- /dev/null +++ b/app/src/main/res/values-bg/strings.xml @@ -0,0 +1,262 @@ + + + + Изход + ЗатварÑне + Да + Ðе + ДобавÑне + Отказ + Запазване + Помощ + + + Добре дошли! + AdAway е безплатно приложение Ñ Ð¾Ñ‚Ð²Ð¾Ñ€ÐµÐ½ код, Ñъздадено да Ñпира рекламите. То Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ Ð°Ð´Ñ€ÐµÑите на рекламните мрежи и Ñпира заÑвките от уÑтройÑтвото към Ñ‚ÑÑ….\nИÑкате ли да научите повече? ПотърÑете помощ по-долу! + Помощ + СъÑтоÑние на обновÑване + Ð’Ñички hosts файлове от зададените източници Ñе изтеглÑÑ‚, Ñливат Ñе Ñ Ð²Ð°ÑˆÐ¸Ñ‚Ðµ ÑпиÑъци и Ñе инÑталират като един host файл във вашата ÑиÑтема. + Включване блокирането на реклами + Изключване блокирането на реклами + Уеб Ñървър + Включен + Изключен + Включване или изключване на меÑтен уеб Ñървър, отговарÑщ на заÑвки към блокирани хоÑтове. + Включване на уеб Ñървър + Изключване на уеб Ñървър + VPN + Работи + СпрÑн + Включване или изключване на VPN, който да филтрира на заÑвки. + Включване на VPN + Изключване на VPN + + + Редактиране + Прилагане + Редактиране + Изтриване + + + ВнаÑÑне… + Резервното копие е внеÑено уÑпешно от външната памет. + Грешка при внаÑÑне на резервно копие. Форматът правилен ли е? Проверете дневника за подробноÑти. + ИзнаÑÑне… + Резервното копие е изнеÑено във файла „%s“ на външното хранилище. + Грешка при изнаÑÑне на резервното копие „%s“. + + + Файлът hosts + Файлът hosts е ÑиÑтемен файл, който Ñвързва имена на хоÑтове Ñ Ð°Ð´Ñ€ÐµÑи по IP. Той е обикновен текÑтов файл, наÑтройката на който Ñе извършва от AdAway. Ето първите нÑколко реда: + Зареждане Ñъдържанието на файла hosts… + ОтварÑне на файла hosts + + + Проверка за обновÑване + Проверка за обновÑване на %s + Извличане на източници + ИзтеглÑне на източник%s + Прочитане на %s + Ðнализ на %s + Синхронизиране на базата данни Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð° + Връщане към файл Ñ Ñ…Ð¾Ñтове по подразбиране + Файлът Ñ Ñ…Ð¾Ñтове по подразбиране е възÑтановен + Създаване на Ñтандартен файл Hosts + Ðалично е обновÑване + Ðалични Ñа нови файлове hosts + ÐÑма обновен източник + ÐÑма връзка Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð½ÐµÑ‚ + ÐÑма връзка Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð½ÐµÑ‚ + Ðе Ñа доÑтипни източници + ÐÑма доÑтъпни източници на файлове hosts! + ДоÑтъпът до ÑÑƒÐ¿ÐµÑ€Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ñ Ðµ отказан + Дайте доÑтъп до ÑÑƒÐ¿ÐµÑ€Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ñ Ð¾Ñ‚ Ñъответното приложение + Ðещо Ñе обърка + Проверете дневника за повече подробноÑти + Ðктивиран + Ðай-новите Hosts файлове Ñа активирани + Деактивиран + Hosts файлът по подразбиране е инÑталиран + Прилагане на поÑледните източници + Създаване на нов хоÑÑ‚ файл + Копиране на нов хоÑÑ‚ файл + ПроверÑване на копието на хоÑÑ‚ файла + Файлът hosts е уÑпешно обновен + ÐаÑтройката на VPN е уÑпешно обновена + ÐаÑтройките Ñа променени. ТрÑбва да бъдат приложени. + Прилагане + Прилагане на наÑтройки… + Грешка при прилагане на наÑтройките. + + + Символната връзка целта на хоÑÑ‚ файла липÑва + Символната връзка от Ñ†ÐµÐ»ÐµÐ²Ð¸Ñ Ñ„Ð°Ð¹Ð» към /system/etc/hosts не ÑъщеÑтвува или е недейÑтвителна! AdAway нÑма да работи ако Ñ‚Ñ Ð½Ðµ е правилна.\n\nЖелаете ли да бъде Ñъздадена Ñимволна връзка? + ЛипÑва Ñимволна връзка + ÐÑма доÑтатъчно мÑÑто на дÑла!\nОпитайте да промените Ñ†ÐµÐ»ÐµÐ²Ð¸Ñ Hosts файл в наÑтройките на /data/data/hosts. + ÐÑма доÑтатъчно мÑÑто + ИзтеглениÑÑ‚ файл не може да бъде прочетен. + ÐеуÑпех Ñ Ð»Ð¸Ñ‡Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð» + ÐеуÑпешно монтиране на дÑла за четене / запиÑ! + Повторното монтиране Ñе провали + Копирането на хоÑÑ‚ файла Ñе провали + ÐеуÑпешно копиране на Hosts файла! + Копирането е неуÑпешно + Приложени източници на Hosts + УÑпешно прилагане + УÑпешно прилагане.\nМоже да Ñе наложи да реÑтартирате Android, за да влÑзат в Ñила промените.\n\nИÑкате ли да реÑтартирате?\n(За да предотвратите загуба на данни, уверете Ñе, че в момента никое приложение не използва SD картата!) + Символичната връзка е Ñъздадена уÑпешно.\nМоже да Ñе наложи да реÑтартирате Android, за да влÑзат в Ñила промените.\n\nИÑкате ли да реÑтартирате?\n(За да предотвратите загуба на данни, уверете Ñе, че в момента никое приложение не използва SD картата!) + УÑпешно Ñъздаване на Ñимволична връзка + Символната връзка не може да бъде Ñъздадена от Android.\nТова Ñе дължи най-вече на „функциÑ“, наречена S-ON при телефоните на HTC!\n\nЕдно от възможните Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ðµ да заредите телефона Ñи в режим на възÑтановÑване и там да Ñъздадете Ñимволна връзка Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ñ‚Ð° „ln -s /data/data/hosts /system/etc/hosts“.\n\nÐко това и не работи, потърÑете в интернет за S-OFF и Ð²Ð°ÑˆÐ¸Ñ Ð¼Ð¾Ð´ÐµÐ» на телефона. + Грешка при Ñъздаване на Ñимволна връзка. + МолÑ, прочетете Помощ за повече информациÑ. + Зададено е APN прокÑи на Ð²Ð°ÑˆÐ¸Ñ Android!\nAdAway нÑма да работи надеждно, когато Ñте на мобилни мрежи като 3G. Можете да деактивирате това прокÑи като отидете на Ð²Ð°ÑˆÐ¸Ñ Ð¸Ð·Ð±Ñ€Ð°Ð½ APN (От ÐаÑтройки: Мрежа и интернет -> Мобилна мрежа -> Разширени -> Имена на точки за доÑтъп) и премахнете ÑтойноÑтта в полето за прокÑи. + APN прокÑи е зададено! + Връзката Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð½ÐµÑ‚ не работи. + ÐÑма връзка + ИзтеглÑне… + Прилагане… + Прилагане на Ñ‡ÐµÑ€Ð½Ð¸Ñ Ð¸ Ð±ÐµÐ»Ð¸Ñ ÑпиÑък + Ðнализ и обединÑване на Hosts файловете + Изграждане на Hosts файла + Прилагане на Hosts файла + Прилагането на Ð½Ð¾Ð²Ð¸Ñ Ñ…Ð¾ÑÑ‚ файл Ñе провали. + Прилагането на Hosts файла във вашата ÑиÑтема е неуÑпешно!\nОпитайте да промените Ñ†ÐµÐ»ÐµÐ²Ð¸Ñ Hosts файл в наÑтройките на /data/data/hosts. + ÐеуÑпешно прилагане + ÐœÐ¾Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐµÑ‚Ðµ Вашето root приложение за управление, за да Ñте Ñигурни, че root правата Ñа дадени. + Върнахте Hosts файла по подразбиране.\nМоже да Ñе наложи да реÑтартирате Android, за да влÑзат в Ñила промените.\n\nИÑкате ли да реÑтартирате?\n(За да предотвратите загуба на данни, уверете Ñе, че в момента никое приложение не използва SD картата!) + Връщането е уÑпешно + ХоÑÑ‚ файлът не може да Ñе върне + Връщането Ñе провали по неизвеÑтни причини. + Връщането е неуÑпешно! + Ðито един от включените източници на Hosts файлове не е доÑтъпен! Правилно ли Ñте Ñвързани към Интернет? + ИзтеглÑнето е неуÑпешно + ЗапиÑването на нов чаÑтен хоÑÑ‚ файл Ñе провали + Личен файл не може да бъде Ñъздаден. + ÐеуÑпешно Ñъздаване на личен файл + Ðктивирахте безÑиÑтемен режим.\nМоже да Ñе наложи да реÑтартирате Android, за да влÑзат в Ñила промените.\n\nИÑкате ли да реÑтартирате?\n(За да предотвратите загуба на данни, уверете Ñе, че в момента никое приложение не използва SD картата!) + УÑпешно активиране + Деактивирахте безÑиÑÑ‚ÐµÐ¼Ð½Ð¸Ñ Ñ€ÐµÐ¶Ð¸Ð¼.\nМоже да Ñе наложи да реÑтартирате Android, за да влÑзат в Ñила промените.\n\nИÑкате ли да реÑтартирате?\n(За да предотвратите загуба на данни, уверете Ñе, че в момента никое приложение не използва SD картата!) + Деактивирането е уÑпешно + Включването на VPN блокирането на реклами Ñе провали. + Спирането на VPN блокирането на реклами Ñе провали. + Включване на хоÑтове от модула Magisk + Включване на функциÑта безÑиÑтемни хоÑтове от управлението на Magisk. От неговите наÑтройките включете опциÑта БезÑиÑтемни хоÑтове, Ñлед което реÑтартирайте уÑтройÑтвото Ви. + Изключване на хоÑтове от модула Magisk + Изключване на функциÑта безÑиÑтемни хоÑтове от управлението на Magisk. От ÑпиÑъка на модула, деинÑталирайте модула БезÑиÑтемни хоÑтове, Ñлед което реÑтартирайте уÑтройÑтвото Ви. + + + Въведете URL на Hosts файла: + Това не е валидно име на хоÑÑ‚! + Ðеправилно форматирано име на хоÑÑ‚ + Това не е валиден IP адреÑ! + Ðеправилно форматиран IP Ð°Ð´Ñ€ÐµÑ + Ðикога да не Ñе реÑтартира и да не Ñе показва този Ð²ÑŠÐ¿Ñ€Ð¾Ñ ÑÐ»ÐµÐ´Ð²Ð°Ñ‰Ð¸Ñ Ð¿ÑŠÑ‚! + Зареждане… + + + ОпреÑнÑване + ДобавÑне + Помощ + ВнаÑÑне на резервно копие + ИзнаÑÑне на резервно копие + + + S-ON/S-OFF + ВъпроÑи и отговори + Проблеми + + + Рекламен Ñофтуер + Тук може на намерите инÑталиран рекламен Ñофтуер, лоши приложениÑ, които не могат да бъдат блокирани от AdAway. Тези Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¿Ð¾Ð»Ð·Ð²Ð°Ñ‚ например изÑкачащи извеÑтиÑ, които Ñе поÑвÑват дори когато приложението не работи. Могат дори да променÑÑ‚ мелодиÑта ви. ЕдинÑтвеното налично противодейÑтвие е да деинÑталирате тези Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÐºÐ°Ñ‚Ð¾ натиÑнете върху елементите в ÑпиÑъка. + Сканиране… + Ðе Ñа открити рекламни приложениÑ! + + + Спира рекламите + Ðе е инÑталиран текÑтов редактор + Ðе е намерен текÑтов редактор, за да Ñе отвори файла Hosts. Можете да инÑталирате Jota или друг текÑтов редактор.\n\nИÑкате ли да инÑталирате Jota? + Ðе е инÑталиран файлов мениджър + Ðе е намерен файлов мениджър, който да Ð¾Ñ‚Ð²Ð°Ñ€Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð²Ðµ. Можете да инÑталирате OI File Manager или друг файлов мениджър, който да Ñе Ñправи Ñ Ñ‚Ð¾Ð²Ð°.\n\nИÑкате ли да инÑталирате OI File Manager? + + + Tcpdump + Tcpdump е инÑтрумент за наблюдение на DNS заÑвките и запиÑването им във файл. Можете да го Ñтартирате във фонов режим, да Ñтартирате приложениÑ, които показват реклами, а Ñлед това да анализирате DNS заÑвките Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰Ñ‚Ð° на този файл. Възможен рекламен Ñървър може да бъде добавен към Ð²Ð°ÑˆÐ¸Ñ Ñ‡ÐµÑ€ÐµÐ½ ÑпиÑък. + Изключване на мониторинг + Включване на мониторинг + Показване на резултатите + Сортиране на домейните + ИзчиÑтване на дневника + ДобавÑне на Ð·Ð°Ð¿Ð¸Ñ Ð² Ñ‡ÐµÑ€Ð½Ð¸Ñ ÑпиÑък + ДобавÑне на Ð·Ð°Ð¿Ð¸Ñ Ð² Ð±ÐµÐ»Ð¸Ñ ÑпиÑък + ДобавÑне на Ð·Ð°Ð¿Ð¸Ñ Ð² ÑпиÑъка за пренаÑочване + + Редактиране ÑтойноÑÑ‚ на Ð¿Ñ€ÐµÐ´Ð¿Ð¾Ñ‡Ð¸Ñ‚Ð°Ð½Ð¸Ñ Ð·Ð° текÑÑ‚ + ОтварÑне на менюто + ЗатварÑне на менюто + + + + Ðачало + Източници за Hosts файла + Вашите ÑпиÑъци + ОтварÑне на Hosts файла + РегиÑтриране на DNS заÑвките + Сканиране за рекламен Ñофтуер + ÐаÑтройки + Помощ + + + + + DNS заÑвки + Вашите ÑпиÑъци + ÐаÑтройки + + + ИнÑталиран преди %1$s + Без обновÑване от %1$s + За обновÑване %1$s + ПоÑледно обновÑване преди %1$s + СъÑтоÑнието на обновÑване е неизвеÑтно + Изключено + нÑколко минути + + %d минута + %d минути + + + %d Ñ‡Ð°Ñ + %d чаÑа + + + %d ден + %d дни + + + %d меÑец + %d меÑеца + + + + ХоÑтът е копиран + + + Ñтартиране + активно + Ñпиране + изчакване за мрежа + повторно Ñвързване + грешка при повторно Ñвързване + пауза + ÑпрÑн + VPN блокер на реклами %1$s + Пауза + ВъзÑтановÑване + + + Ð Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° AdAway + Разрешаване на взаимодейÑтвие Ñ AdAway + Изпращане на команди към AdAway + Разрешете изпращането на команди към AdAway като включване или изключване на Ñпирането на реклами на ниво ÑиÑтема. + + diff --git a/app/src/main/res/values-bg/strings_app.xml b/app/src/main/res/values-bg/strings_app.xml new file mode 100644 index 0000000..427e1c5 --- /dev/null +++ b/app/src/main/res/values-bg/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Рекламен блокер Ñ Ð¾Ñ‚Ð²Ð¾Ñ€ÐµÐ½ код + AdAway лого + diff --git a/app/src/main/res/values-bg/strings_errors.xml b/app/src/main/res/values-bg/strings_errors.xml new file mode 100644 index 0000000..51f267a --- /dev/null +++ b/app/src/main/res/values-bg/strings_errors.xml @@ -0,0 +1,22 @@ + + + + ÐÑма връзка Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð½ÐµÑ‚ + Ðе може да Ñе уÑтанови връзка Ñ Ð˜Ð½Ñ‚ÐµÑ€Ð½ÐµÑ‚. МолÑ, проверете ÑвързаноÑтта на уÑтройÑтвото Ви. + СвалÑнето източника на хоÑтове Ñе провали + Ðикои от Вашите включени източници на хоÑтове Ñа доÑтъпни. МолÑ, проверете дали Ñте Ñвързани към Интернет. + + Създаването на чаÑтен файл Ñе провали + Ðевъзможно е Ñъздаването на чаÑтен файл за ÑглобÑване на нов източник на хоÑтове. МолÑ, проверете Ñвободното проÑтранÑтво на Вашето уÑтройÑтво. + ÐÑма доÑтатъчно мÑÑто + Ðевъзможно е копирането на хоÑÑ‚ файл на ÑиÑÑ‚ÐµÐ¼Ð½Ð¸Ñ Ð¿Ð°Ñ€Ñ‚Ð¸ÑˆÑŠÐ½. ÐœÐ¾Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐµÑ‚Ðµ дали безÑиÑÑ‚ÐµÐ¼Ð½Ð¸Ñ Ð¼Ð¾Ð´ÑƒÐ» на Magisk е включен и Ñлед това реÑтартирайте. + ИнÑталирането на нов хоÑÑ‚ файл Ñе провали + Копирането на файла hosts в /system е невъзможно. Проверете дали безÑиÑтемниÑÑ‚ модул на Magisk е включен и реÑтартирайте. + ОтменÑнето на хоÑÑ‚ файла Ñе провали + Ðевъзможно е възÑтановÑването на конфигурациÑта по подразбиране на хоÑÑ‚ файла. + + Включването на VPN блокирането на реклами Ñе провали. + МолÑ, проверете Вашите VPN наÑтройки, за да Ñе авторизира VPN на приложението да Ñтартира. + Спирането на VPN блокирането на реклами Ñе провали. + МолÑ, проверете Вашите VPN наÑтройки, за да ги изключите ръчно. + diff --git a/app/src/main/res/values-bg/strings_home.xml b/app/src/main/res/values-bg/strings_home.xml new file mode 100644 index 0000000..031ba02 --- /dev/null +++ b/app/src/main/res/values-bg/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Блокирани + Позволени + ПренаÑочени + + + + %d обновен източник + %d обновени източника + + + %d източник за обновÑване + %d източника за обновÑване + + Проверка за актуализации на хоÑтовете + Ðктуализиране на хоÑтовете + + + ЗаÑвки към DNS + + + Помощ + + + Страница в GitHub + + + ДарÑване + + + Проект в GitHub + ÐаÑтройки + + + ОтварÑне на чекмеджето за Ð½Ð°Ð²Ð¸Ð³Ð°Ñ†Ð¸Ñ + Пауза/възобновÑване на блокирането на реклами + Ðктуализиране на блокирани домейни + Показване на заÑвените домейни + + + МолÑ, прочетете Помощ за повече информациÑ. + + \ No newline at end of file diff --git a/app/src/main/res/values-bg/strings_hosts.xml b/app/src/main/res/values-bg/strings_hosts.xml new file mode 100644 index 0000000..ec255dd --- /dev/null +++ b/app/src/main/res/values-bg/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Източници за Hosts файла + + ПотребителÑки ÑпиÑък + Официален ÑпиÑък на AdAway + Обединени хоÑтове на StevenBlack + СпиÑък Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð°Ð½Ð¸ хоÑтове на Pete Lowe + + не е наличен + %s хоÑта + + ДобавÑне на източник + Редактиране на източник + URL: (https:// или file:// реÑурÑ) + URL Ð°Ð´Ñ€ÐµÑ Ð½Ð° източника на Hosts + diff --git a/app/src/main/res/values-bg/strings_lists.xml b/app/src/main/res/values-bg/strings_lists.xml new file mode 100644 index 0000000..fb4c559 --- /dev/null +++ b/app/src/main/res/values-bg/strings_lists.xml @@ -0,0 +1,24 @@ + + + Вашите ÑпиÑъци + ДобавÑне на hosts + + Блокирани + Позволени + ПренаÑочени + + Филтриране на хоÑтове + ТърÑене на име на хоÑт… + Превключване на източници + + ДобавÑне на хоÑÑ‚ в Ñ‡ÐµÑ€Ð½Ð¸Ñ ÑпиÑък + ДобавÑне на хоÑÑ‚ в Ð±ÐµÐ»Ð¸Ñ ÑпиÑък + ДобавÑне на пренаÑочване на хоÑÑ‚ + Редактиране на хоÑÑ‚ от Ñ‡ÐµÑ€Ð½Ð¸Ñ ÑпиÑък + Редактиране на хоÑÑ‚ от Ð±ÐµÐ»Ð¸Ñ ÑпиÑък + Редактиране на пренаÑочване + Име на хоÑÑ‚: + URL Ð°Ð´Ñ€ÐµÑ Ð½Ð° източника на Hosts + (Позволени Ñа замеÑтващи Ñимволи * и ?) + IP (IPv4 или IPv6): + diff --git a/app/src/main/res/values-bg/strings_log.xml b/app/src/main/res/values-bg/strings_log.xml new file mode 100644 index 0000000..593a083 --- /dev/null +++ b/app/src/main/res/values-bg/strings_log.xml @@ -0,0 +1,11 @@ + + + Превключване на дневника + ÐатиÑнете бутона за запиÑ, за да започнат да Ñе запиÑват заÑвките в дневника. Разглеждайте в интернет или използвайте приложениÑ, Ñлед това Ñе върнете тук и дръпнете надолу, за да презаредите на дневника. + \n\nСпрените заÑвки нама да приÑÑŠÑтват в дневника. Ðко желаете да приÑÑŠÑтват, тогава първо изключете Ñпирането на рекламите. + + Ðзбучно Ñортиране + Сортиране на домейн от първо ниво + + ПренаÑочване на домейн + diff --git a/app/src/main/res/values-bg/strings_notification.xml b/app/src/main/res/values-bg/strings_notification.xml new file mode 100644 index 0000000..8584e67 --- /dev/null +++ b/app/src/main/res/values-bg/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Ðктуализации + Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð·Ð° нови актуализации + Ðалице е Ð°ÐºÑ‚ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° източник + Ðови хоÑÑ‚ файлове Ñа доÑтъпни за ÑвалÑне. + Ðалице е Ð°ÐºÑ‚ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° приложението + Ðова верÑÐ¸Ñ Ð½Ð° AdAway е налице за изтеглÑне. + + VPN + Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð·Ð° работещ VPN + \ No newline at end of file diff --git a/app/src/main/res/values-bg/strings_prefs_backup_restore.xml b/app/src/main/res/values-bg/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..fe2e3bd --- /dev/null +++ b/app/src/main/res/values-bg/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Резервно копие и възÑтановÑване + Резервно копие + Създава резервно копие на правилата във външното хранилище + ВъзÑтановÑване + ВъзÑтановÑва правилата от резервно копие + diff --git a/app/src/main/res/values-bg/strings_prefs_main.xml b/app/src/main/res/values-bg/strings_prefs_main.xml new file mode 100644 index 0000000..5ccea96 --- /dev/null +++ b/app/src/main/res/values-bg/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + ÐаÑтройки + + Общи + Тъмна тема + + Светла + Тъмна + По подразбиране + + Ðвтоматично обновÑване + + Блокиране на реклами + Руут базиран блокер на реклами + VPN базиран блокер на реклами + Включване на IPv6 поддръжка + Резерено копие / възÑтановÑване на правила + + ОтÑтранÑване на грешки + Изпращане на доклади за Ñривове + Докладване до Sentry (sentry.io) + Ðе Ñе поддържа в тази Ñглобка + ПодробноÑти в дневника + Ðеобходимо е реÑтартиране на приложението за прилагане + diff --git a/app/src/main/res/values-bg/strings_prefs_root.xml b/app/src/main/res/values-bg/strings_prefs_root.xml new file mode 100644 index 0000000..ffafd12 --- /dev/null +++ b/app/src/main/res/values-bg/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Спиране на реклами чрез Ñуперпотребител + + ИнÑталиране на хоÑтове + ОтварÑне на файла hosts + Целеви файл hosts + Прочетете Помощ преди да използвате тази Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ + + /system/etc/hosts + /data/hosts + /data/data/hosts + Папка по избор + + ПерÑонализирано целево меÑтоположение + Без реÑтарт Ñлед прилагане + + ПренаÑочване + Дефиниране къде да Ñе пренаÑочват блокирани хоÑтове + ПренаÑочване на IPv4 + ПренаÑочване на IPv6 + ÐедопуÑтимо пренаÑочване + + МеÑтен уеб Ñървър + МеÑтниÑÑ‚ уеб Ñървър Ñлуша на меÑтен Ð°Ð´Ñ€ÐµÑ Ð¿Ð¾ IP, за да отговори на заÑвки към блокиран хоÑÑ‚. Може да помогне при замръзване на приложение при блокирана реклама. + Включване на уеб Ñървър + ТеÑтване на уеб Ñървър + ИнÑталиране на ÑамоподпиÑан Ñертификат + Ръчно инÑталиране на Ñертификати + Започващо от Ðндроид 11 (R), приложението не може да инÑталира авторитарни Ñертификати (CA) автоматично.\n\nОтидете в наÑтройките за \"Защита\", \"Криптиране & идентификационни данни\", Ñлед това \"ИнÑталиране на Ñертификат\". От тук изберете \"CA Ñертификат\" и изберете новиÑÑ‚ екÑпортиран Ñертификационен файл. + Отворете наÑтройките за \"СигурноÑÑ‚\" + Проверка… + Ðе работи + Работи, но не е инÑталиран Ñертификат + Работи и е инÑталиран Ñертификат + ЗамÑна на празно рекламно проÑтранÑтво Ñ Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð° на приложението + diff --git a/app/src/main/res/values-bg/strings_prefs_update.xml b/app/src/main/res/values-bg/strings_prefs_update.xml new file mode 100644 index 0000000..8f748ad --- /dev/null +++ b/app/src/main/res/values-bg/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + ОбновÑване + ИзвеÑтиÑта Ñа изключени + Приложението нÑма да показва извеÑтиÑ. За да ги включите, докоÑнете. + + ОбновÑване на приложението + Проверка за обновÑване при Ñтартиране + Периодична проверка за обновÑване + Включително бета Ð¸Ð·Ð´Ð°Ð½Ð¸Ñ + + ОбновÑване на хоÑтове + Проверка за обновÑване при Ñтартиране + Периодична проверка за обновÑване + Синхронизиране при обновÑване + Синхронизиране Ñамо в мрежи без такÑуване на трафика + diff --git a/app/src/main/res/values-bg/strings_prefs_vpn.xml b/app/src/main/res/values-bg/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1c7276 --- /dev/null +++ b/app/src/main/res/values-bg/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN базиран блокер на реклами + + Разрешаване при Ñтартиране + Ðабюдаване на връзката + Периодично проверÑване на ÑÑŠÑтоÑнието на мрежата за реÑтартиране на VPN връзката при откачане. + + Изключени Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + Конфигурирайте кои Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ трÑбва да използват VPN, така че нÑма да бъдат блокирани връзки. + Изключване на ÑиÑтемни Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + + Ðищо + All except browsers + All + + Изключване на потребителÑки Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + + + Изключени Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + Избиране на вÑички + Премахване на вÑички + Икона на приложението + diff --git a/app/src/main/res/values-bg/strings_source_edit.xml b/app/src/main/res/values-bg/strings_source_edit.xml new file mode 100644 index 0000000..a54c99e --- /dev/null +++ b/app/src/main/res/values-bg/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Редактиране на източник + ДобавÑне на източник + + Етикет + Етикетът е задължителен + Вид + URL + Файл + МеÑтоположение + https:// + МеÑтоположението е задължително + За да изберете изходен файл докоÑнете Файл + МеÑтоположението е неприемливо + Формат на ÑпиÑъка + ЗабранÑване + Разрешаване + Прилагане на пренаÑочените + Разрешаването на пренаÑочените адреÑи може да доведе до проблеми ÑÑŠÑ ÑигурноÑтта. Използвайте тази наÑтройка Ñамо при доверен източник, тъй като Ñ‚Ñ Ð¼Ð¾Ð¶Ðµ да пренаÑочи чувÑтвителен трафик към произволен Ñървър. + diff --git a/app/src/main/res/values-bg/strings_support.xml b/app/src/main/res/values-bg/strings_support.xml new file mode 100644 index 0000000..4d8c36e --- /dev/null +++ b/app/src/main/res/values-bg/strings_support.xml @@ -0,0 +1,5 @@ + + + Поддръжка + Станете ÑпонÑор + \ No newline at end of file diff --git a/app/src/main/res/values-bg/strings_update.xml b/app/src/main/res/values-bg/strings_update.xml new file mode 100644 index 0000000..048e149 --- /dev/null +++ b/app/src/main/res/values-bg/strings_update.xml @@ -0,0 +1,22 @@ + + + ОбновÑване на AdAway + + Ðалично е ново издание! + + + Ползвате поÑледно издание + Ðалично е ново издание + ОбновÑване на AdAway + ОбновÑване + %1$s / %2$s + Готово + ПоÑледни промени + Дневник на промените + Подкрепете разработката + ДарÑване + Подпомагане + + + ИзтеглÑне на поÑледната верÑÐ¸Ñ Ð½Ð° AdAway… + diff --git a/app/src/main/res/values-bg/strings_welcome.xml b/app/src/main/res/values-bg/strings_welcome.xml new file mode 100644 index 0000000..601d502 --- /dev/null +++ b/app/src/main/res/values-bg/strings_welcome.xml @@ -0,0 +1,55 @@ + + + Добре дошли + Първа Ñтъпка на помощника + Втора Ñтъпка на помощника + ПоÑледна Ñтъпка на помощника + + + Добре дошли от AdAway! + AdAway предлага два метода за Ñпиране на реклами. +Изберете Ð¿Ñ€ÐµÐ´Ð¿Ð¾Ñ‡Ð¸Ñ‚Ð°Ð½Ð¸Ñ Ð¾Ñ‚ ваÑ: + + Логотип на Ñуперпотребител + Чрез доÑтъп до\nÑуперпотребител + По-бърз + ПеÑти Ð±Ð°Ñ‚ÐµÑ€Ð¸Ñ + Ðужен е Ñуперпотребител + + Логотип на VPN + VPN базирано\nблокиране на реклами + По-бавно + Работи във фонов режим + СъвмеÑтимоÑÑ‚ + + ИзиÑква Ñе Android Ñ Ð´Ð¾Ñтъп до Ñуперпотребител + ИзпълниимиÑÑ‚ файл на su не е намерен или AdAway нÑма разрешение за доÑтъп до правата на ÑуперпотребителÑ.\n\n +Това може да Ñе Ñлучи, когато тройÑтвото ви нÑма доÑтъп до ÑуперпотребителÑ. Можете да намерите Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ ÐºÐ°Ðº да получите доÑтъп до него на уÑтройÑтвото Ñи в wiki.lineageos.org или в други Ñтраници за Android. + + ПредимÑтва + ÐедоÑтатъци + + + Синхронизирането е извършено + Грешка при Ñинхронизиране. + + Синхронизиране + Синхронизирано! + AdAway Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ Ð¾Ñ‚ отдалечени източници рекламните мрежи, които да Ñпира. По-къÑно ще можете да ги променÑте в наÑтройките. + Повторно Ñинхронизиране + Грешка при Ñинхронизиране: %1$s Повторен опит? + Може да показва извеÑÑ‚Ð¸Ñ Ð·Ð° ÑÑŠÑтоÑнието и да ви извеÑÑ‚Ñва за налични обновÑÐ²Ð°Ð½Ð¸Ñ (нÑколко пъти в годината). Включете ги, за да научаеате поÑледните промени. + + + Поддръжка + Подкрепете ме! + AdAway е безплатно приложение Ñ Ð¾Ñ‚Ð²Ð¾Ñ€ÐµÐ½ код. Разработвам го в Ñвободното Ñи време. Ðко ви хареÑа, не Ñе колебайте да покажете вашата подкрепа: + ДарÑване в PayPal + ХареÑвате ли дефекти? Ðз Ñъщо. + Включване на телеметриÑ, за бъдат изпращани доклади за Ñрив + + + Ðазад + Ðапред + Край + diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml new file mode 100644 index 0000000..024fcf8 --- /dev/null +++ b/app/src/main/res/values-bn/strings.xml @@ -0,0 +1,22 @@ + + + + à¦à¦•à§à¦¸à¦¿à¦Ÿ + বনà§à¦§ + মà§à¦›à§‡ ফেলà§à¦¨ + + আপডেট উপলবà§à¦§ + ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ সংযোগ নেই + কোন ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ সংযোগ উপলবà§à¦§ নেই + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-bn/strings_app.xml b/app/src/main/res/values-bn/strings_app.xml new file mode 100644 index 0000000..c2ac018 --- /dev/null +++ b/app/src/main/res/values-bn/strings_app.xml @@ -0,0 +1,4 @@ + + + অà§à¦¯à¦¾à¦¡à¦…à§à¦¯à¦¾à¦“য়ে + diff --git a/app/src/main/res/values-bn/strings_errors.xml b/app/src/main/res/values-bn/strings_errors.xml new file mode 100644 index 0000000..c0126e0 --- /dev/null +++ b/app/src/main/res/values-bn/strings_errors.xml @@ -0,0 +1,5 @@ + + + + ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ সংযোগ নেই + \ No newline at end of file diff --git a/app/src/main/res/values-bn/strings_home.xml b/app/src/main/res/values-bn/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-bn/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-bn/strings_hosts.xml b/app/src/main/res/values-bn/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-bn/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-bn/strings_lists.xml b/app/src/main/res/values-bn/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-bn/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-bn/strings_log.xml b/app/src/main/res/values-bn/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-bn/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-bn/strings_notification.xml b/app/src/main/res/values-bn/strings_notification.xml new file mode 100644 index 0000000..1de8595 --- /dev/null +++ b/app/src/main/res/values-bn/strings_notification.xml @@ -0,0 +1,4 @@ + + + আপডেট উপলবà§à¦§ + \ No newline at end of file diff --git a/app/src/main/res/values-bn/strings_prefs_backup_restore.xml b/app/src/main/res/values-bn/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-bn/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-bn/strings_prefs_main.xml b/app/src/main/res/values-bn/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-bn/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-bn/strings_prefs_root.xml b/app/src/main/res/values-bn/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-bn/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-bn/strings_prefs_update.xml b/app/src/main/res/values-bn/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-bn/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-bn/strings_prefs_vpn.xml b/app/src/main/res/values-bn/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-bn/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-bn/strings_support.xml b/app/src/main/res/values-bn/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-bn/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-bn/strings_update.xml b/app/src/main/res/values-bn/strings_update.xml new file mode 100644 index 0000000..eb3aaeb --- /dev/null +++ b/app/src/main/res/values-bn/strings_update.xml @@ -0,0 +1,4 @@ + + + আপডেট উপলবà§à¦§ + diff --git a/app/src/main/res/values-bn/strings_welcome.xml b/app/src/main/res/values-bn/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-bn/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml new file mode 100644 index 0000000..aeb5857 --- /dev/null +++ b/app/src/main/res/values-ca/strings.xml @@ -0,0 +1,262 @@ + + + + Surt + Tanca + Si + No + Afegeix + Cancel·la + Desa + Ajuda + + + Us donem la benvinguda! + L\'AdAway és una aplicació de codi obert i gratuïta dissenyat per blocar anuncis. Obté adreces de xarxa publicitària per blocar-les al dispositiu.\nVoleu saber-ne més? Feu un cop d\'ull a l\'ajuda de sota! + Mostra més ajuda + Estat d\'actualització + Es baixen tots els fitxers d\'amfitrió d\'unes fonts definides, s\'uneixen amb les vostres llistes que personalitzeu i s\'instal·len com a un únic fitxer amfitrió al vostre sistema. + Activa el bloqueig d\'anuncis + Desactiva el bloqueig d\'anuncis + Servidor web + En execució + Aturat + Atura o inicia el servidor web local per respondre les peticions de les direccions blocades. + Activa el servidor web + Desactiva el servidor web + VPN + En execució + Aturat + Arrenca o para la VPN per a filtrar peticions + Activa la VPN + Desactiva la VPN + + + Edita l\'entrada + Aplica + Edita + Elimina + + + S\'està important…. + S\'ha importat correctament la còpia de l\'emmagatzematge extern. + Ha fallat en importar la còpia. El format és correcte? Mireu l\'informe del logcat per a més informació. + S\'està exportant… + S\'ha exportat correctament l\'arxiu \'%s\' a l\'emmagatzematge extern. + Error al exportar la còpia de seguretat \'%s\' + + + El fitxer d\'amfitrions + El fitxer d\'amfitrions és un fitxer del sistema on s\'associen noms d\'amfitrió a les corresponents adreces IP. És un fitxer en text pla on la seva configuració és administrada per l\'AdAway. Aquí podeu veure les primeres línies: + S\'està carregant el contingut del fitxer d\'amfitrions… + Obre el fitxer d\'amfitrions + + + S\'estan comprovant les actualitzacions + Comprovant a %s si hi han actualitzacions + Recuperant recursos + Descarregant recurs %s + Llegint font %s + Analitzant font %s + Sincronització de les regles de la base de dades + Retornant al fitxer hosts per defecte + Fitxer hosts per defecte restaurat + Creació del fitxer estàndard de servidors + Actualització disponible + Amfitrions nous disponibles + No s\'han trobat actualitzacions de la font + No hi ha connexió a internet + No hi ha connexió a internet disponible + Fonts no disponibles + No s\'ha pogut contactar amb els servidors de fonts! + Accés a Root rebutjat + Heu de facilitar permisos d\'administrador a l\'aplicació + Quelcom ha anat malament + Veieu l\'informe del logcat per a més informació + Activat + S\'han activat els fitxers d\'amfitrions més recents + Desactivat + S\'han instal·lat els fitxers d\'amfitrions per defecte + Aplicar ultimes fonts + Creant un nou fitxer hosts + Copiant un nou fitxer hosts + Comprovant còpia del fitxer hosts + Fitxer hosts actualitzat correctament + Configuració de la VPN actualitzada correctament + Ha canviat la configuració. Heu d\'aplicar els canvis. + Aplica + Aplicant nova configuració… + Error al aplicar la nova configuració + + + No es troba l\'enllaç simbolic al fitxer hosts escollit + L\'enllaç simbòlic cap a /system/etc/hosts no existeix o no és correcte! L\'AdAway no funcionarà si no apunta al fitxer correcte.\n\nVoleu intentar crear un enllaç simbòlic? + Falta l\'enllaç simbòlic + No hi ha prou espai a la partició!\nProveu canviant el fitxer a les preferències a /data/data/hosts. + No hi ha prou espai + No s\'ha pogut llegir el fitxer baixat. + Error al fitxer privat + Ha fallat al muntar la partició en mode lectura/escriptura! + Ha fallat en muntar + Error al copiar l\'arxiu de hosts + No s\'ha pogut copiar el fitxer! + Ha fallat la còpia + S\'han aplicat les fonts + S\'ha aplicat correctament + S\'ha aplicat correctament.\nÉs necessari reiniciar Android per aplicar els canvis.\n\nVoleu reiniciar ara?\n(Per evitar cap pèrdua a la targeta SD, assegureu-vos que cap altra aplicació l\'està utilitzant en aquest moment!) + S\'ha creat l\'enllaç simbòlic correctament.\nÉs necessari reiniciar Android per aplicar els canvis.\n\nVoleu reiniciar ara?\n(Per evitar cap pèrdua a la targeta SD, assegureu-vos que cap altra aplicació l\'està utilitzant en aquest moment!) + S\'ha creat l\'enllaç simbòlic correctament + L\'Android no ha pogut crear l\'enllaç simbòlic.\nAixò falla normalment per una característica anomenada S-ON als telèfons HTC.\n\nUna solució és iniciar el telèfon en mode recuperació i crear l\'enllaç simbòlic allà amb \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nSi no funciona, cerqueu a Internet S-OFF i el model del vostre telèfon. + S\'ha produït un error en la creació de l\'enllaç simbòlic + Veieu l\'ajuda per a més informació. + S\'ha configurat un servidor intermediari APN al vostre Android!\nL\'AdAway no funcionarà correctament amb xarxes com ara 3G. Podeu desactivar aquest servidor intermediari d\'aquest APN (des del menú Configuració -> Connexions sense fils i xarxes -> Xarxes mòbils -> APN -> Nom del vostre APN) i suprimint el valor del camp Servidor intermediari. + S\'ha desat el servidor intermediari d\'APN + La connexió a Internet no funciona. + Sense connexió + S\'està baixant… + S\'està aplicant… + Aplicant llista negra i llista blanca + Processant i unint els fitxers hosts + Construïnt fitxer hosts + Aplicant el fitxer hosts + Error al aplicar el nou arxiu de hosts + No s\'ha pogut aplicar el fitxer al sistema!\nProveu canviant la ruta del fitxer a les preferències a /data/data/hosts. + Aplicació fallida + Verifiqueu que l\'aplicació disposa de permisos d\'administrador (Root). + Heu restaurat al fitxer per defecte.\nÉs necessari reiniciar Android per aplicar els canvis.\n\nVoleu reiniciar ara?\n(Per evitar cap pèrdua a la targeta SD, assegureu-vos que cap altra aplicació l\'està utilitzant en aquest moment!) + S\'ha revertit correctament + No s\'ha pogut revertir l\'arxiu de hosts + Procés de revertiment fallit degut a causes desconegudes + Ha fallat en restaurar! + No es pot contactar amb cap font dels fitxers d\'amfitrions. Comproveu la connexió a internet. + Error amb la baixada + Error al escriure el nou arxiu de hosts privat + No s\'ha pogut crear el fitxer privat. + Error en la creació del fitxer privat + Heu activat el mode systemless.\nÉs necessari reiniciar Android per aplicar els canvis.\n\nVoleu reiniciar ara?\n(Per evitar cap pèrdua a la targeta SD, assegureu-vos que cap altra aplicació l\'està utilitzant en aquest moment!) + S\'ha habilitat correctament + Heu desactivat el mode systemless.\nÉs necessari reiniciar Android per aplicar els canvis.\n\nVoleu reiniciar ara?\n(Per evitar cap pèrdua a la targeta SD, assegureu-vos que cap altra aplicació l\'està utilitzant en aquest moment!) + S\'ha inhabilitat correctament + Error al activar el blocatge d\'anuncis per VPN + Error al desactivar el blocatge d\'anuncis per VPN + Activant mòdul Magisk de hosts + Activar funció \"systemless hosts\" del Magisk manager. Des de la configuració del Magisk, activar l\'opció Systemless hostsi reiniciar el dispositiu. + Desactivant mòdul Magisk de hosts + Desactivar funció \"systemless hosts\" del Magisk manager. Des del llistat de mòduls del Magisk, desinstalar el modulSystemless hostsi reiniciar el dispositiu. + + + Introduïu l\'adreça URL cap el fitxer hosts: + Aquest no és un nom de servidor vàlid! + Nom de màquina incorrecte + Aquesta no és una IP vàlida! + Format IP incorrecte + No reiniciïs mai i no mostris més aquest missatge. + Carregant.. + + + Refresca + Afegeix + Ajuda + Importar còpia de seguretat + Exportar còpia de seguretat + + + S-ON/S-OFF + PMF (FAQ) + Problemes + + + Adware + Aquí podeu trobar aplicacions Adware malignes que no es poden bloquejar amb AdAway. Aquestes aplicacions utilitzen, entre altres, notificacions Airpush que poden apareixer inclús quan l\'aplicació no està funcionant o poden inclús canviar el vostre to de trucada. La única defensa possible és desinstalar-les clicant en la llista de elements + S\'està escanejant… + No s\'ha trobat Adware! + + + Bloquejador d\'anuncis + No hi ha cap editor de text instal·lat + No s\'ha trobat cap editor de text per obrir el fitxer hosts. Podeu intal·lar Jota o d\'altres editors de text per gestionar-ho.\n\nVoleu instal·lar Jota? + No hi ha cap gestor de fitxers instal·lat + No s\'ha trobat cap gestor de fitxers per obrir fitxers. Podeu instal·lar l\'OI File Manager o d\'altres gestors de fitxers per gestionar-ho.\n\nVoleu instal·lar l\'OI File Manager? + + + Tcpdump + tcpdump és una eina per monitoritzar i desar les peticions DNS. Podeu iniciar-lo en segon pla, iniciar les aplicacions que mostrin anuncis i, més tard, analitzar les peticions DNS utilitzant el registre de tcpdump. Així podreu afegir els servidors d\'anuncis a la vostra llista. + Desactiva la supervisió + Activa la supervisió + Mostra els resultats + Ordena dominis + Esborra el registre + Afegeix una entrada a la llista negra + Afegeix una entrada a la llista blanca + Afegeix una entrada a la llista de redireccions + + Edita el valor de preferència del text + Obre el menú + Tanca el menú + + + + Home + Servidors de fitxers hosts + Les vostre llistes + Obriu el fitxer de hosts + Log DNS requests + Scan for adware + Preferències + Ajuda + + + + + Sol·licituds DNS + Les vostre llistes + Preferències + + + Instal·lat fa %1$s + Actualitzat per %1$s + Actualització necessària per %1$s + Darrera actualització fa %1$s + Estat d\'actualització desconegut + Desactivat + pocs minuts + + %d minut + %d minuts + + + %d hora + %d hores + + + %d dia + %d dies + + + %d mes + %d mesos + + + + L\'amfitrió s\'ha copiat al porta-retalls + + + començant + actiu + aturant + espera a tenir xarxa + reconnectant + error durant la reconnexió + pausat + aturat + VPN bloquejadora d\'anuncis %1$s + Pausa + Reprèn + + + Permisos del AdAway + Permetre la interacció amb l\'AdAway + Enviar ordres a l\'AdAway + Permet enviar ordres al AdAway com activar/desactivar el sistema de bloqueig d\'anuncis + + diff --git a/app/src/main/res/values-ca/strings_app.xml b/app/src/main/res/values-ca/strings_app.xml new file mode 100644 index 0000000..8529cd2 --- /dev/null +++ b/app/src/main/res/values-ca/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Blocador d\'anuncis de codi obert + Logotip de l\'AdAway + diff --git a/app/src/main/res/values-ca/strings_errors.xml b/app/src/main/res/values-ca/strings_errors.xml new file mode 100644 index 0000000..2c54460 --- /dev/null +++ b/app/src/main/res/values-ca/strings_errors.xml @@ -0,0 +1,22 @@ + + + + No hi ha connexió a internet + No es pot establir una connexió a Internet. Comproveu la connectivitat del vostre dispositiu. + No s\'ha pogut baixar la font dels amfitrions + Cap de les fonts dels vostres amfitrions habilitats és accessible. Comproveu que esteu connectat correctament a Internet. + + No s\'ha pogut crear el fitxer privat + No es pot crear un fitxer privat per crear una font d\'amfitrió nova. Comproveu l\'espai lliure disponible al vostre dispositiu. + No hi ha prou espai + No es pot copiar el fitxer hosts a la partició del sistema. Comproveu que el mòdul sense sistema Magisk està activat i reinicieu-lo. + No s\'ha pogut instal·lar el fitxer hosts nou + No es pot copiar el fitxer hosts a la partició /system. Comproveu que el mòdul sense sistema Magisk està activat i reinicieu-lo. + No s\'ha pogut revertir el fitxer hosts + No es pot restaurar la configuració per defecte del fitxer hosts. + + Error al activar el blocatge d\'anuncis per VPN + Comproveu la configuració de la vostra VPN per autoritzar l\'inici de l\'aplicació VPN. + Error al desactivar el blocatge d\'anuncis per VPN + Comproveu la configuració de la vostra VPN per desactivar-la manualment. + diff --git a/app/src/main/res/values-ca/strings_home.xml b/app/src/main/res/values-ca/strings_home.xml new file mode 100644 index 0000000..94e49c9 --- /dev/null +++ b/app/src/main/res/values-ca/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Bloquejat + Permès + Redirigit + + + + %d font actualitzada + %d fonts actualitzades + + + %d font obsoleta + %d fonts obsoletes + + Cerca actualitzacions dels amfitrions + Actualitza els amfitrions + + + Mostra el registre de sol·licituds del DNS + + + Mostra ajuda\ni consells + + + Obre la pàgina del GitHub + + + Ajudeu al projecte + + + Projecte GitHub + Preferències + + + Obriu el calaix de navegació + Pausa/reprèn el bloqueig d\'anuncis + Actualitza els dominis bloquejats + Mostra els dominis sol·licitats + + + Veieu l\'ajuda per a més informació. + + \ No newline at end of file diff --git a/app/src/main/res/values-ca/strings_hosts.xml b/app/src/main/res/values-ca/strings_hosts.xml new file mode 100644 index 0000000..d5e160c --- /dev/null +++ b/app/src/main/res/values-ca/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Servidors de fitxers hosts + + Llista d\'usuaris + Amfitrions oficials de l\'AdAway + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + no disponible + %s amfitrions + + Afegeix una font + Edita la font + URL: (un recurs https:// o fitxer://) + URL de la font de l\'amfitrió + diff --git a/app/src/main/res/values-ca/strings_lists.xml b/app/src/main/res/values-ca/strings_lists.xml new file mode 100644 index 0000000..fde29d0 --- /dev/null +++ b/app/src/main/res/values-ca/strings_lists.xml @@ -0,0 +1,24 @@ + + + Les vostre llistes + Afegeix un amfitrió + + Bloquejat + Permès + Redirigit + + Filtra els amfitrions + Cerca un nom d\'amfitrió… + Commuta les fonts + + Afegeix l\'amfitrió a la llista negra + Afegeix l\'amfitrió a la llista blanca + Afegeix la redirecció de l\'amfitrió + Edita l\'amfitrió d\'una llista negra + Edita l\'amfitrió d\'una llista blanca + Edita la redirecció + Servidor: + URL de la font de l\'amfitrió + (Els caràcters comodí * i ? estan permesos) + IP (IPv4 o IPv6): + diff --git a/app/src/main/res/values-ca/strings_log.xml b/app/src/main/res/values-ca/strings_log.xml new file mode 100644 index 0000000..e969fce --- /dev/null +++ b/app/src/main/res/values-ca/strings_log.xml @@ -0,0 +1,11 @@ + + + Commuta la gravació del registre + Premeu grava per començar a registrar les sol·licituds, navegueu pel web o utilitzeu aplicacions i, a continuació, torneu enrere o llisqueu per actualitzar els registres. + \n\nLes sol·licituds bloquejades no es registraran. Desactiveu primer el bloqueig d\'anuncis si també voleu registrar-los. + + Ordena alfabèticament + Ordena per nivell de domini + + Redirigeix domini + diff --git a/app/src/main/res/values-ca/strings_notification.xml b/app/src/main/res/values-ca/strings_notification.xml new file mode 100644 index 0000000..e5f62ec --- /dev/null +++ b/app/src/main/res/values-ca/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Actualitzacions + Noves notificacions d\'actualització + Actualització disponible + Fitxers d\'amfitrió més nous disponibles per baixar. + Actualització de l\'aplicació disponible + Hi ha disponible una versió nova d\'AdAway per baixar. + + VPN + Notificacions d\'execució de VPN + diff --git a/app/src/main/res/values-ca/strings_prefs_backup_restore.xml b/app/src/main/res/values-ca/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..7abef2d --- /dev/null +++ b/app/src/main/res/values-ca/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Copia i restaura + Copia + Feu una còpia de seguretat a l\'emmagatzematge extern de les vostres regles de bloqueig + Restaura + Restaura les regles de bloqueig des del fitxer de còpia de seguretat + diff --git a/app/src/main/res/values-ca/strings_prefs_main.xml b/app/src/main/res/values-ca/strings_prefs_main.xml new file mode 100644 index 0000000..6249411 --- /dev/null +++ b/app/src/main/res/values-ca/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Preferències + + General + Tema fosc + + Clar + Fosc + Valor per defecte del sistema + + Actualitzacions automàtiques + + Bloqueig d\'anuncis + Bloquejador d\'anuncis basat en root + Bloquejador d\'anuncis basat en VPN + Activa el suport d\'IPv6 + Copia/restaura les regles de bloqueig + + Depuració + Envia informes d\'error + Informa a Sentry (sentry.io) + No s\'admet en aquesta compilació + Registre detallat + Cal reiniciar l\'aplicació per aplicar + diff --git a/app/src/main/res/values-ca/strings_prefs_root.xml b/app/src/main/res/values-ca/strings_prefs_root.xml new file mode 100644 index 0000000..fb2630a --- /dev/null +++ b/app/src/main/res/values-ca/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Bloquejador d\'anuncis basat en root + + Instal·lació hosts + Obriu el fitxer de hosts + Fitxer hosts objectiu + Llegiu l\'ajuda abans d\'utilitzar aquesta funció + + /system/etc/hosts + /data/hosts + /data/data/hosts + Objectiu personalitzt + + Ubicació destí personalitzada + Amaga el diàleg de reinici després d\'aplicar + + Redirecció + Defineix on redirigir els amfitrions bloquejats + Configura la redirecció IPv4 + Configura la redirecció IPv6 + Redirecció no vàlida + + Servidor web local + El servidor web local escolta les adreces IP locals per respondre a les sol·licituds de nom d\'amfitrió bloquejades. Pot ser útil amb la congelació de l\'aplicació en connexió bloquejada. + Activa el servidor web + Prova el servidor web + Instal·la el certificat autofirmat + Instal·lació manual del certificat + A partir d\'Android 11 (R), l\'aplicació ja no pot instal·lar automàticament l\'autoritat de certificació (CA).\n\nAneu a la configuració de \"Seguretat\", \"Xifrat i credencials\" i després \"Instal·la un certificat\". A partir d\'aquí, trieu \"Certificat CA\" i seleccioneu el fitxer de certificat recent exportat. + Obriu la configuració de \"Seguretat\". + S\'està comprovant… + No s\'està executant + S\'està executant però el certificat no s\'ha instal·lat + S\'està executant i el certificat està instal·lat + Substituïu l\'espai publicitari en blanc per la icona de l\'aplicació + diff --git a/app/src/main/res/values-ca/strings_prefs_update.xml b/app/src/main/res/values-ca/strings_prefs_update.xml new file mode 100644 index 0000000..403e85c --- /dev/null +++ b/app/src/main/res/values-ca/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + Actualitzacions + + Actualitzacions de l\'aplicació + Comprova si hi ha actualitzacions a l\'inici + Comprova periòdicament actualitzacions + Inclou versions beta + + Actualitzacions dels amfitrions + Comprova si hi ha actualització a l\'inici + Comprova periòdicament actualitzacions + Sincronitza en l\'actualització + Sincronitza només a la xarxa sense mesura + diff --git a/app/src/main/res/values-ca/strings_prefs_vpn.xml b/app/src/main/res/values-ca/strings_prefs_vpn.xml new file mode 100644 index 0000000..75445dc --- /dev/null +++ b/app/src/main/res/values-ca/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Bloquejador d\'anuncis basat en VPN + + Activa a l\'inici + Analitza la connexió + Comprova periòdicament l\'estat de la xarxa per reiniciar la VPN en desconnectar-se. + + Aplicacions excloses + Configureu quines aplicacions no haurien d\'utilitzar la VPN perquè no es bloquegin les connexions. + Exclou les aplicacions del sistema + + None + All except browsers + All + + Exclou les aplicacions d\'usuari + + + Aplicacions excloses + Seleccioneu-ho tot + Anul·la la selecció + Icona de l\'aplicació + diff --git a/app/src/main/res/values-ca/strings_source_edit.xml b/app/src/main/res/values-ca/strings_source_edit.xml new file mode 100644 index 0000000..07ce5fc --- /dev/null +++ b/app/src/main/res/values-ca/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Edita la font + Afegeix una font + + Etiqueta + Etiqueta necessària + Tipus + URL + Fitxer + Enllaç + https:// + Enllaç necessari + Premeu Fitxer per seleccionar un fitxer com a origen + Enllaç no vàlid + Format de llista + Bloca + Permet + Aplica la redirecció + En permetre la redirecció del web pot causar problemes de seguretat . Utilitzeu aquesta opció només si prové d\'una font confiable, atès que podria redirigir informació confidencial cap a un servidor atacant. + diff --git a/app/src/main/res/values-ca/strings_support.xml b/app/src/main/res/values-ca/strings_support.xml new file mode 100644 index 0000000..ed79a73 --- /dev/null +++ b/app/src/main/res/values-ca/strings_support.xml @@ -0,0 +1,5 @@ + + + Ajuda + Feu-vos patrocinador + diff --git a/app/src/main/res/values-ca/strings_update.xml b/app/src/main/res/values-ca/strings_update.xml new file mode 100644 index 0000000..8f47bee --- /dev/null +++ b/app/src/main/res/values-ca/strings_update.xml @@ -0,0 +1,21 @@ + + + Actualització d\'AdAway + + Actualització disponible! + + + Actualitzat + Actualització disponible + S\'està actualitzant l\'AdAway + Actualitza ara + %1$s / %2$s + Últims canvis + Registre de canvis + Ajuda al desenvolupament + Fer un donatiu + Patrocinador + + + S\'està baixant la darrera versió d\'AdAway… + diff --git a/app/src/main/res/values-ca/strings_welcome.xml b/app/src/main/res/values-ca/strings_welcome.xml new file mode 100644 index 0000000..5a4d0c2 --- /dev/null +++ b/app/src/main/res/values-ca/strings_welcome.xml @@ -0,0 +1,52 @@ + + + Us donem la benvinguda + Primer pas de l\'assistent + Segon pas de l\'assistent + Últim pas de l\'assistent + + + Sigueu benvinguts a l\'AdAway! + L\'AdAway ofereix dos mètodes de bloqueig d\'anuncis. Trieu la que us agradi: + + Logo root + Bloqueig d\'anuncis\nbasat en root + Més ràpid + No consumeix molta bateria + Cal root + + Logo VPN + Bloqueig d\'anuncis\nbasat en VPN + Més lent + S\'executa en segon pla + Compatibilitat + + És necessari tenir l\'Android rootejat + No s\'ha pogut trobar el binari su o no heu permès el permís root per a l\'AdAway.\n\nAixò pot passar quan el dispositiu no té root. Podeu trobar informació sobre com activar el root al vostre dispositiu a wiki.lineageos.org o a altres llocs web d\'Android. + + Pros + Contres + + + Sincronització completada + Error durant la sincronització + + S\'està sincronitzant + S\'ha sincronitzat! + L\'AdAway baixa xarxes publicitàries per bloquejar-les de fonts en línia. Podeu personalitzar-los més endavant a la configuració. + Reintenta la sincronització + No s\'ha pogut sincronitzar: %1$s Voleu provar-ho de nou? + + + Ajuda + Ajudeu-me! + És una aplicació gratuïta i de codi obert. Ho desenvolupo en el meu temps lliure. Així que si us agrada, no dubteu a mostrar el vostre suport: + Feu un donatiu al PayPal + Us agraden els errors? A mi tampoc. + Activeu la telemetria per enviar-me informes d\'error + + + Enrere + Següent + Acaba + diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml new file mode 100644 index 0000000..e812fe9 --- /dev/null +++ b/app/src/main/res/values-cs/strings.xml @@ -0,0 +1,270 @@ + + + + UkonÄit + Zavřít + Ano + Ne + PÅ™idat + ZruÅ¡it + Uložit + NápovÄ›da + + + Vítejte! + AdAway je bezplatná open-source aplikace pro blokování reklam. AdAway stahuje síťové adresy reklam za úÄelem jejich blokování na vaÅ¡em zařízení.\nChcete vÄ›dÄ›t více? Podívejte se na nápovÄ›du níže! + Zobrazit další nápovÄ›du + Aktualizovat status + VÅ¡echny soubory hostitelů z vybraných zdrojů budou staženy, slouÄeny s vaÅ¡imi vlastními seznamy a aplikovány do vaÅ¡eho systému jako jeden soubor hostitelů. + Zapnout blokování reklam + Vypnout blokování reklam + Webový server + SpuÅ¡tÄ›n + Vypnut + Zapnout nebo vypnout webový server pro odpovídání na požadavky na jména zablokovaných hostitelů. + Povolit webový server + Zakázat webový server + VPN + SpuÅ¡tÄ›na + Vypnuta + Zapnout nebo vypnout VPN pro filtrování požadavků. + Povolit VPN + Zakázat VPN + + + Upravit položku + Aplikovat + Upravit + Smazat + + + Importování… + Záloha z vaÅ¡eho externího úložiÅ¡tÄ› úspěšnÄ› importována. + Importování zálohy se nezdaÅ™ilo. Je ve správném formátu? Pro více detailů zkontrolujte systémový protokol událostí. + Exportování… + Záloha úspěšnÄ› exportována do souboru \"%s\" na vaÅ¡em externím úložiÅ¡ti. + Exportování souboru zálohy \"%s\" se nezdaÅ™ilo. + + + Soubor hostitelů + Soubor hostitelů je systémový soubor, který pÅ™iÅ™azuje jména hostitelů IP adresám. Jedná se o textový soubor, který je spravován aplikací AdAway. Zde je jeho malá Äást: + NaÄítání obsahu souboru hostitelů… + Otevřít soubor hostitelů + + + Kontrola aktualizace + Kontrola aktualizací zdroje %s + NaÄítání zdrojů + Stahování zdroje %s + ÄŒtení zdroje %s + Zpracovávání zdroje %s + Synchronizování databáze pravidel + Obnovování výchozího souboru hostitelů + Výchozí soubor hostitelů obnoven + Vytváření standardního souboru hostitelů + Aktualizace zdroje k dispozici + Jsou dostupné novÄ›jší soubory hostitelů + Nebyla nalezena žádná aktualizace zdroje + Bez pÅ™ipojení k internetu + Bez dostupného pÅ™ipojení k internetu + Nedostupné zdroje + Nejsou dostupné žádné zdroje souborů hostitelů! + ROOT přístup odepÅ™en + Povolte ROOT přístup v aplikaci pro správu ROOT přístupů + NÄ›co se pokazilo + Pro více detailů zkontrolujte systémový protokol událostí + Povoleno + NejnovÄ›jší soubory hostitelů povoleny + Zakázáno + Výchozí soubor hostitelů aplikován + Aplikovat nejnovÄ›jší zdroje + Vytváření nového souboru hostitelů + Kopírování nového souboru hostitelů + Kontrola kopie souboru hostitelů + Soubor hostitelů úspěšnÄ› aktualizován + Nastavení VPN úspěšnÄ› aktualizováno + VaÅ¡e nastavení bylo zmÄ›nÄ›no. Musíte ho aplikovat. + Aplikovat + Aplikování nového nastavení… + Aplikování nového nastavení se nezdaÅ™ilo. + + + Chybí symbolický odkaz na cílový soubor hostitelů + Symbolický odkaz z vaÅ¡eho cíle na /system/etc/hosts neexistuje nebo je chybný! AdAway nebude fungovat, pokud neodkazuje na správný soubor.\n\nChcete se pokusit vytvoÅ™it symbolický odkaz? + ChybÄ›jící symbolický odkaz + Na oddílu není dostatek volného místa!\nZkuste v nastavení zmÄ›nit cílový soubor hostitelů na /data/data/hosts. + Nedostatek místa + Stažený soubor nelze pÅ™eÄíst. + Selhání soukromého souboru + PÅ™ipojení oddílu pro Ätení/zápis selhalo! + PÅ™ipojení oddílu selhalo! + NepodaÅ™ilo se zkopírovat soubor hostitelů + Kopírování souboru hostitelů selhalo! + Kopírování selhalo + Použité zdroje hostitelů + Aplikování úspěšné + Aplikování bylo úspěšné.\nAby se zmÄ›ny projevily, může být nutné restartovat vaÅ¡e zařízení.\n\nChcete zařízení restartovat?\n(Abyste pÅ™edeÅ¡li ztrátÄ› dat, ujistÄ›te se, že žádná aplikace momentálnÄ› nepoužívá SD kartu!) + Symbolický odkaz byl úspěšnÄ› vytvoÅ™en.\nAby se zmÄ›ny projevily, může být nutné restartovat vaÅ¡e zařízení.\n\nChcete zařízení restartovat?\n(Abyste pÅ™edeÅ¡li ztrátÄ› dat, ujistÄ›te se, že žádná aplikace momentálnÄ› nepoužívá SD kartu!) + Symbolický odkaz úspěšnÄ› vytvoÅ™en + Symbolický odkaz nemohl být vytvoÅ™en.\nTo se vÄ›tÅ¡inou stává na telefonech HTC kvůli \"vylepÅ¡ení\" nazývanému S-ON.\n\nŘeÅ¡ením je restartovat telefon do režimu obnovy a vytvoÅ™it symbolický odkaz příkazem \"ln -s /data/data/hosts /system/etc/hosts\".\n\nPokud to nepomůže, pak zkuste na internetu vyhledat frázi S-OFF a název modelu vaÅ¡eho telefonu. + VytvoÅ™ení symbolického odkazu selhalo + Pro více informací si prosím pÅ™eÄtÄ›te nápovÄ›du. + Na vaÅ¡em zařízení je nastaveno APN proxy!\nAdAway nebude správnÄ› fungovat pÅ™i pÅ™ipojení pÅ™es mobilní sítÄ›, jako je 3G. Proxy můžete deaktivovat v nastavení zvoleného APN (Z nastavení systému: Nastavení SIM & sítÄ› -> Nastavení SIM -> Názvy přístupových bodů) smazáním záznamu v poli proxy. + APN proxy nastaven! + PÅ™ipojení k internetu nefunguje. + Žádné pÅ™ipojení + Stahování… + Aplikování… + Aplikování bílé a Äerné listiny + Zpracovávání a sluÄování souborů hostitelů + Vytváření souboru hostitelů + Aplikování souboru hostitelů + NepodaÅ™ilo se aplikovat nový soubor hostitelů + PÅ™i aplikaci souboru hostitelů doÅ¡lo k chybÄ›!\nZkuste v nastavení zmÄ›nit cílový soubor hostitelů na /data/data/hosts. + Aplikování se nezdaÅ™ilo + UjistÄ›te se, prosím, že jste v aplikaci pro správu ROOT přístupů udÄ›lili oprávnÄ›ní pro ROOT přístup. + Obnovili jste výchozí soubor hostitelů.\nAby se zmÄ›ny projevily, může být nutné restartovat vaÅ¡e zařízení.\n\nChcete zařízení restartovat?\n(Abyste pÅ™edeÅ¡li ztrátÄ› dat, ujistÄ›te se, že žádná aplikace momentálnÄ› nepoužívá SD kartu!) + Obnova úspěšná + Soubor hostitelů nelze obnovit + Obnova souboru hostitelů z neznámých příÄin selhala! + Obnova souboru hostitelů selhala! + Žádný z povolených zdrojů souboru hostitelů není dostupný! Jste správnÄ› pÅ™ipojeni k internetu? + Stahování selhalo + NepodaÅ™ilo se zapsat nový soukromý soubor hostitelů + Soukromý soubor nelze vytvoÅ™it. + Vytváření soukromého souboru selhalo + Povolili jste mód systemless.\nAby se zmÄ›ny projevily, může být nutné restartovat vaÅ¡e zařízení.\n\nChcete zařízení restartovat?\n(Abyste pÅ™edeÅ¡li ztrátÄ› dat, ujistÄ›te se, že žádná aplikace momentálnÄ› nepoužívá SD kartu!) + ÚspěšnÄ› povoleno + Zakázali jste mód systemless.\nAby se zmÄ›ny projevily, může být nutné restartovat vaÅ¡e zařízení.\n\nChcete zařízení restartovat?\n(Abyste pÅ™edeÅ¡li ztrátÄ› dat, ujistÄ›te se, že žádná aplikace momentálnÄ› nepoužívá SD kartu!) + ÚspěšnÄ› zakázáno + Povolení blokování reklam pomocí VPN se nezdaÅ™ilo. + Zakázání blokování reklam pomocí VPN se nezdaÅ™ilo. + Povolování Magisk modulu hosts + Povolte funkci nesystémoví hostitelé v Magisk Manageru. V jeho nastavení povolte možnost Nesystémoví hostitelé a poté restartujte zařízení. + Zakazování Magisk modulu hosts + Zakažte funkci nesystémoví hostitelé v Magisk Manageru. V seznamu modulů odinstalujte modul Systemless Hosts a poté restartujte zařízení. + + + Zadejte URL k souboru hostitelů: + Toto není platné jméno hostitele! + Chybný formát jména hostitele + Toto není platná IP! + Chybný formát IP + Nikdy nerestartovat a příštÄ› již nezobrazovat tuto otázku! + NaÄítání… + + + Obnovit + PÅ™idat + NápovÄ›da + Importovat zálohu + Exportovat zálohu + + + S-ON/S-OFF + ÄŒasté otázky + Problémy + + + Adware + Zde můžete vyhledat nainstalovaný Adware, Å¡patné aplikace, které nemohou být aplikací AdAway zablokovány. Tyto aplikace používají například oznámení Airpush, které se objevují i v případÄ›, že aplikace není spuÅ¡tÄ›na, nebo dokonce zmÄ›ní vaÅ¡e vyzvánÄ›ní. Jediné protiopatÅ™ení je odinstalování tÄ›chto aplikací klepnutím na položky seznamu! + Skenování… + Žádný Adware nebyly nalezen! + + + Blokování reklam + Není nainstalován žádný textový editor + NepodaÅ™ilo se najít žádný textový editor pro otevÅ™ení souboru hostitelů. Můžete si nainstalovat Jota nebo jakýkoliv jiný textový editor.\n\nChcete nainstalovat Jota? + Není nainstalován žádný správce souborů + NepodaÅ™ilo se najít žádného správce souborů. Můžete si nainstalovat OI File Manager nebo jakéhokoliv jiného správce souborů.\n\nChcete nainstalovat OI File Manager? + + + Tcpdump + Tcpdump je nástroj pro monitorování DNS požadavků a jejich zaznamenávání do souboru. Můžete ho spustit na pozadí, spustit aplikace zobrazující reklamy a potom v záznamu analyzovat jejich DNS požadavky. Adresy možných serverů poskytujících reklamní obsah si pak můžete pÅ™idat na svou Äernou listinu. + Zakázat monitorování + Povolit monitorování + Zobrazit výsledky + Řazení domén + Vymazat záznam + PÅ™idat položku na Äernou listinu + PÅ™idat položku na bílou listinu + PÅ™idat položku na listinu pÅ™esmÄ›rování + + Upravit textovou hodnotu pÅ™edvolby + Otevřít menu + Zavřít menu + + + + Úvodní obrazovka + Zdroje hostitelů + VaÅ¡e seznamy + Otevřít soubor hostitelů + Zaznamenat DNS požadavky + Vyhledat Adware + Nastavení + NápovÄ›da + + + + + DNS požadavky + VaÅ¡e seznamy + Nastavení + + + Aplikováno pÅ™ed %1$s + Aktualizováno pÅ™ed %1$s + Dostupná aktualizace pÅ™ed %1$s + Poslední aktualizace pÅ™ed %1$s + Neznámý stav aktualizace + Zakázáno + pár minutami + + %d minutou + %d minutami + %d minutami + %d minutami + + + %d hodinou + %d hodinami + %d hodinami + %d hodinami + + + %d dnem + %d dny + %d dny + %d dny + + + %d mÄ›sícem + %d mÄ›síci + %d mÄ›síci + %d mÄ›síci + + + + Hostitel zkopírován do schránky + + + spouÅ¡tÄ›ní + spuÅ¡tÄ›no + vypínání + Äekání na síť + obnovování pÅ™ipojení + obnovování pÅ™ipojení selhalo + pozastaveno + vypnuto + Blokování reklam pomocí VPN: %1$s + Pozastavit + Obnovit + + + OprávnÄ›ní AdAway + Dovoluje interakci s AdAway + Odesílání příkazů do AdAway + Dovoluje odesílání příkazů do AdAway jako například povolení nebo zakázání blokování reklam v celém systému + + diff --git a/app/src/main/res/values-cs/strings_app.xml b/app/src/main/res/values-cs/strings_app.xml new file mode 100644 index 0000000..c9cc656 --- /dev/null +++ b/app/src/main/res/values-cs/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Open source blokovaÄ reklam + Logo AdAway + diff --git a/app/src/main/res/values-cs/strings_errors.xml b/app/src/main/res/values-cs/strings_errors.xml new file mode 100644 index 0000000..f068b30 --- /dev/null +++ b/app/src/main/res/values-cs/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Bez pÅ™ipojení k internetu + Není možné navázat pÅ™ipojení k internetu. Zkontrolujte, prosím, internetové pÅ™ipojení vaÅ¡eho zařízení. + Není možné stáhnout zdroj hostitelů + Žádný z vaÅ¡ich povolených zdrojů hostitelů není dostupný. Zkontrolujte, prosím, že je vaÅ¡e pÅ™ipojení k internetu v pořádku. + + Vytváření soukromého souboru selhalo + Není možné vytvoÅ™it soukromý soubor potÅ™ebný pro sestavení nového souboru hostitelů. Zkontrolujte, prosím, že je na vaÅ¡em zařízení dostatek volného místa. + Nedostatek místa + Není možné zkopírovat soubor hostitelů na váš systémový oddíl. Zkontrolujte, prosím, zda je funkce nesystémoví hostitelé v Magisk Manageru povolena a poté restartujte zařízení. + Aplikování nového souboru hostitelů selhalo + Není možné zkopírovat soubor hostitelů na oddíl /system. Zkontrolujte, prosím, zda je v Magisk Manageru pÅ™idán modul pro podporu nesystémových hostitelů a poté restartujte zařízení. + Obnovení souboru hostitelů selhalo + Výchozí soubor hostitelů nelze obnovit. + + Povolení blokování reklam pomocí VPN se nezdaÅ™ilo. + Zkontrolujte, prosím, vaÅ¡e nastavení VPN, aby aplikace byla autorizovaná ke spuÅ¡tÄ›ní VPN. + Zakázání blokování reklam pomocí VPN se nezdaÅ™ilo. + Zkontrolujte, prosím, vaÅ¡e nastavení VPN a deaktivujte jej ruÄnÄ›. + diff --git a/app/src/main/res/values-cs/strings_home.xml b/app/src/main/res/values-cs/strings_home.xml new file mode 100644 index 0000000..ec95966 --- /dev/null +++ b/app/src/main/res/values-cs/strings_home.xml @@ -0,0 +1,50 @@ + + + + + Zablokované + Povolené + PÅ™esmÄ›rované + + + + %d aktuální zdroj + %d aktuální zdroje + %d aktuální zdroje + %d aktuálních zdrojů + + + %d zastaralý zdroj + %d zastaralé zdroje + %d zastaralé zdroje + %d zastaralých zdrojů + + Zkontrolovat aktualizace hostitelů + Aktualizovat hostitele + + + Zobrazit záznam DNS požadavků + + + Zobrazit nápovÄ›du\na tipy + + + Otevřít stránku GitHub + + + PodpoÅ™it projekt + + + GitHub projekt + Nastavení + + + Otevřít navigaÄní panel + Pozastavit/pokraÄovat v blokování reklam + Aktualizovat zablokované domény + Zobrazit požadované domény + + + Pro více informací si prosím pÅ™eÄtÄ›te nápovÄ›du. + + \ No newline at end of file diff --git a/app/src/main/res/values-cs/strings_hosts.xml b/app/src/main/res/values-cs/strings_hosts.xml new file mode 100644 index 0000000..c13b926 --- /dev/null +++ b/app/src/main/res/values-cs/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Zdroje hostitelů + + Seznam uživatele + Oficiální AdAway hostitelé + StevenBlack Unified hostitelé + Pete Lowe blocklist hostitelé + + není k dispozici + %s hostitelů + + PÅ™idat zdroj + Upravit zdroj + URL: (https:// nebo file://) + URL adresa hostitele + diff --git a/app/src/main/res/values-cs/strings_lists.xml b/app/src/main/res/values-cs/strings_lists.xml new file mode 100644 index 0000000..eeb9f36 --- /dev/null +++ b/app/src/main/res/values-cs/strings_lists.xml @@ -0,0 +1,24 @@ + + + VaÅ¡e seznamy + PÅ™idat hostitele + + Zablokované + Povolené + PÅ™esmÄ›rované + + Filtrovat hostitele + Najít hostitele… + PÅ™epnout zdroje + + PÅ™idat hostitele na Äernou listinu + PÅ™idat hostitele na bílou listinu + PÅ™idat hostitele na listinu pÅ™esmÄ›rování + Upravit hostitele na Äerné listinÄ› + Upravit hostitele na bílé listinÄ› + Upravit hostitele na listinÄ› pÅ™esmÄ›rování + Jméno hostitele: + URL adresa hostitele + (Jsou povoleny zástupné znaky * a ?) + IP (IPv4 nebo IPv6): + diff --git a/app/src/main/res/values-cs/strings_log.xml b/app/src/main/res/values-cs/strings_log.xml new file mode 100644 index 0000000..b5c73cf --- /dev/null +++ b/app/src/main/res/values-cs/strings_log.xml @@ -0,0 +1,11 @@ + + + PÅ™epnout zaznamenávání + Stisknutím tlaÄítka nahrávání spusÅ¥te zaznamenávání požadavků, procházejte web nebo používáte aplikace a poté se vraÅ¥te zpÄ›t nebo pÅ™ejetím prstem dolů aktualizujte záznam. + \n\nZablokované požadavky nebudou zaznamenány. Pokud je chcete zaznamenat také, nejprve vypnÄ›te blokování reklam. + + Řazení podle abecedy + Řazení podle nejvyšší úrovnÄ› domény + + Doména pro pÅ™esmÄ›rování + diff --git a/app/src/main/res/values-cs/strings_notification.xml b/app/src/main/res/values-cs/strings_notification.xml new file mode 100644 index 0000000..f5d7ef2 --- /dev/null +++ b/app/src/main/res/values-cs/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Aktualizace + UpozornÄ›ní na nové aktualizace + Je k dispozici aktualizace zdroje + Ke stažení jsou dostupné novÄ›jší soubory hostitelů. + Je k dispozici aktualizace aplikace + Ke stažení je dostupná nová verze AdAway. + + VPN + UpozornÄ›ní na spuÅ¡tÄ›nou VPN + \ No newline at end of file diff --git a/app/src/main/res/values-cs/strings_prefs_backup_restore.xml b/app/src/main/res/values-cs/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..a70e80a --- /dev/null +++ b/app/src/main/res/values-cs/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Záloha a obnovení + Zálohovat + Zálohovat vaÅ¡e pravidla pro blokování na externí úložiÅ¡tÄ› + Obnovit + Obnovit vaÅ¡e pravidla pro blokování ze souboru zálohy + diff --git a/app/src/main/res/values-cs/strings_prefs_main.xml b/app/src/main/res/values-cs/strings_prefs_main.xml new file mode 100644 index 0000000..6c961df --- /dev/null +++ b/app/src/main/res/values-cs/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Nastavení + + Obecné + Tmavé téma + + SvÄ›tlé + Tmavé + Podle systému + + Automatické aktualizace + + Blokování reklamy + Blokování reklamy pomocí přístupu ROOT + Blokování reklamy pomocí VPN + Povolit podporu IPv6 + Zálohovat / obnovit pravidla pro blokování + + LadÄ›ní + Odesílat zprávy o selhání + NahlaÅ¡ovat na Sentry (sentry.io) + Na tomto sestavení není k dispozici + Záznam s více informacemi + Pro aplikování je potÅ™eba restartovat aplikaci + diff --git a/app/src/main/res/values-cs/strings_prefs_root.xml b/app/src/main/res/values-cs/strings_prefs_root.xml new file mode 100644 index 0000000..2b26d1f --- /dev/null +++ b/app/src/main/res/values-cs/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Blokování reklam pomocí přístupu ROOT + + Instalace hostitelů + Otevřít soubor hostitelů + Cílový soubor hostitelů + PÅ™ed používáním této funkce si pÅ™eÄtÄ›te nápovÄ›du + + /system/etc/hosts + /data/hosts + /data/data/hosts + Vlastní cíl + + UmístÄ›ní vlastního cíle + Skrýt dialogové okno restartu po aplikování + + PÅ™esmÄ›rování + UrÄit kam pÅ™esmÄ›rovat zablokované hostitele + PÅ™esmÄ›rování IPv4 + PÅ™esmÄ›rování IPv6 + Neplatné pÅ™esmÄ›rování + + Lokální webový server + Lokální webový server naslouchá na lokálních IP adresách a odpovídá na požadavky na zablokovaná jména hostitelů. To může pomoci se zamrzáváním aplikací po zablokování spojení. + Povolit webový server + Otestovat webový server + Nainstalovat certifikát podepsaný sám sebou + RuÄní instalace certifikátu + PoÄínaje Androidem 11 (R) již aplikace nemůže automaticky nainstalovat certifikaÄní autoritu (CA).\n\nPÅ™ejdÄ›te do nastavení zabezpeÄení, \"Å ifrování a identifikaÄní údaje\" a poté \"Nainstalovat certifikát\". Odtud zvolte možnost \"Certifikát CA\" a vyberte novÄ› exportovaný soubor certifikátu. + Otevřít nastavení zabezpeÄení + Kontrolování… + Neběží + Běží, ale není nainstalován certifikát + Běží a certifikát je nainstalován + Vyplnit prázdné místo reklamy ikonou aplikace + diff --git a/app/src/main/res/values-cs/strings_prefs_update.xml b/app/src/main/res/values-cs/strings_prefs_update.xml new file mode 100644 index 0000000..19e5990 --- /dev/null +++ b/app/src/main/res/values-cs/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Aktualizace + Oznámení jsou vypnuta + Oznámení aplikace se nezobrazí. Klepnutím je povolíte. + + Aktualizace aplikace + Zkontrolovat aktualizace pÅ™i spuÅ¡tÄ›ní + PravidelnÄ› kontrolovat aktualizace + Zahrnout beta verze + + Aktualizace hostitelů + Zkontrolovat aktualizace pÅ™i spuÅ¡tÄ›ní + PravidelnÄ› kontrolovat aktualizace + PÅ™i aktualizaci synchronizovat + Synchronizovat pouze na neměřených sítích + diff --git a/app/src/main/res/values-cs/strings_prefs_vpn.xml b/app/src/main/res/values-cs/strings_prefs_vpn.xml new file mode 100644 index 0000000..f48c92d --- /dev/null +++ b/app/src/main/res/values-cs/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Blokování reklamy pomocí VPN + + Povolit pÅ™i spuÅ¡tÄ›ní + Monitorovat pÅ™ipojení + PravidelnÄ› kontrolovat stav sítÄ› za úÄelem restartování VPN pÅ™i odpojení. + + VylouÄené aplikace + Nakonfigurujte, které aplikace by nemÄ›ly používat VPN, takže nebudou blokována žádná spojení. + VylouÄit systémové aplikace + + Žádné + VÅ¡echny kromÄ› prohlížeÄů + VÅ¡echny + + VylouÄit uživatelské aplikace + + + VylouÄené aplikace + Vybrat vÅ¡e + ZruÅ¡it výbÄ›r + Ikona aplikace + diff --git a/app/src/main/res/values-cs/strings_support.xml b/app/src/main/res/values-cs/strings_support.xml new file mode 100644 index 0000000..34e2f42 --- /dev/null +++ b/app/src/main/res/values-cs/strings_support.xml @@ -0,0 +1,5 @@ + + + PodpoÅ™it + Stát se sponzorem + \ No newline at end of file diff --git a/app/src/main/res/values-cs/strings_update.xml b/app/src/main/res/values-cs/strings_update.xml new file mode 100644 index 0000000..3fb61af --- /dev/null +++ b/app/src/main/res/values-cs/strings_update.xml @@ -0,0 +1,21 @@ + + + Aktualizace AdAway + + Aktualizace k dispozici! + + + Máte nejnovÄ›jší verzi + Aktualizace je k dispozici + Aktualizace AdAway + Aktualizovat nyní + %1$s / %2$s + Poslední zmÄ›ny + Seznam zmÄ›n + PodpoÅ™it vývoj + PÅ™ispÄ›t + Sponzorovat + + + Stahování poslední verze AdAway… + diff --git a/app/src/main/res/values-cs/strings_welcome.xml b/app/src/main/res/values-cs/strings_welcome.xml new file mode 100644 index 0000000..753fbaa --- /dev/null +++ b/app/src/main/res/values-cs/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Vítejte + Průvodce první krok + Průvodce druhý krok + Průvodce poslední krok + + + Vítejte v AdAway! + AdAway poskytuje dvÄ› metody blokování reklam. Vyberte si tu, která Vám vyhovuje: + + Logo ROOT přístupu + Blokování reklam\npomocí ROOT přístupu + Rychlejší + Å etrné k baterii + Vyžadován ROOT přístup + + Logo VPN + Blokování reklam\npomocí VPN + Pomalejší + Běží na pozadí + Kompatibilita + + Vyžaduje Android s ROOT přístupem + Spustitelný soubor su nebyl nalezen nebo jste AdAway neudÄ›lili oprávnÄ›ní ROOT přístupu.\n\nToto se může stát, pokud VaÅ¡e zařízení nemá ROOT přístup. Informace jak získat ROOT přístup naleznete na wiki.lineageos.org nebo jiných stránkách o Androidu. + + Výhody + Nevýhody + + + Synchronizace dokonÄena + Chyba bÄ›hem synchronizace + + Synchronizování + Synchronizováno! + AdAway stahuje reklamní sítÄ› k zablokování z online zdrojů. PozdÄ›ji si je můžete v nastavení pÅ™izpůsobit. + Opakovat synchonizaci + Selhala synchronizace: %1$s Opakovat nyní? + Může zasílat oznámení k zobrazení stavu blokování reklam a ovládání, zznamovat nové aktualizace aplikace (nÄ›kolikrát roÄnÄ›). Povolte je, pokud chcete zůstat informováni. + + + PodpoÅ™it + PodpoÅ™te mÄ›! + AdAway je aplikace se svobodným zdrojovým kódem, kterou jsem vyvinul ve svém volném Äase. Pokud se vám líbí, můžete mÄ› podpoÅ™it: + Darovat pÅ™es PayPal + Máte rádi chyby? Ani já ne. + Povolit temeterii, aby mi posílala zprávy o selhání + + + ZpÄ›t + Další + DokonÄit + diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml new file mode 100644 index 0000000..7f0e2b5 --- /dev/null +++ b/app/src/main/res/values-da/strings.xml @@ -0,0 +1,190 @@ + + + + Afslut + Luk + Ja + Nej + Tilføj + Annuller + Gem + Hjælp + + + Velkommen! + AdAway er et gratis og open source software design til blokering af reklamer. Det henter netværksadresser af reklame for at blokere dem pÃ¥ din enhed.\nVil du vide mere? Se hjælp nedenfor! + Se mere hjælp + Opdater status + Alle hosts-filer fra de definerede kilder er hentet, flettet sammen med dine egne lister og installeret som en hosts-fil pÃ¥ dit system. + Aktiver ad-blocking + Deaktiver ad-blocking + Webserver + Kører + Stoppet + Aktiver webserver + Deaktiver webserver + + Rediger opslag + Anvend + Rediger + Slet + + + Importerer… + Sikkerhedskopi importeret med succes fra dit eksterne lager. + Kunne ikke importere backup. Er dets format korrekt? Tjek logcat for flere detaljer. + Eksporterer… + + Hosts filen + Hosts filen er en systemfil, der kortlægger værtsnavne til IP-adresser. Det er en almindelig tekstfil, hvilken konfiguration hÃ¥ndteres af AdAway. Her er de fÃ¥ første linjer: + Indlæser indholdet af hosts filen… + Ã…bn hosts filen + + Opretter en standard hosts-fil + En nyere hosts-fil findes + Ingen Internetforbindelse + Ingen Internetforbindelse tilgængelig + Utilgængelige kilder + Ingen hostskilder kan nÃ¥s! + Root adgang nægtet + Tillad rootadgang fra din root-app + Noget gik galt + Tjek logcat for flere detaljer + Aktiveret + Nyeste hosts-fil aktiveret + Deaktiveret + Standard hostsfil installeret + Anvend + Symlink fra dit mÃ¥l til /system/etc/hosts findes ikke eller er sat forkert! AdAway virker ikke, hvis den ikke peger det rigtige sted hen.\n\nVil du prøve at lave et symlink? + Symlink mangler + Ikke nok plads pÃ¥ partitionen!\nPrøv at ændre hosts kildefilen i indstillingerne til /data/data/hosts. + Ikke nok plads + Den hentede fil kunne ikke læses. + Privat fil fejlede + Remontering af partitionen med læse/skrive-rettigheder fejlede! + Remontering fejlede + Kopiering af hosts filen fejlede + Kopiering fejlede + Anvendte værts kilder + Anvendt successfuldt + Anvend var succesfuldt.\nDer er muligvis nødvendigt at genstarte Android for ændringerne træder i kraft.\n\nVil du genstarte?\n(For at forhindre tab af data skal du sørge for, at ingen app bruger SD-kortet i øjeblikket!) + Symlink blev oprettet succesfuldt.\nDer er muligvis nødvendigt at genstarte Android for ændringerne træder i kraft.\n\nVil du genstarte?\n (For at forhindre tab af data skal du sørge for, at ingen app bruger SD-kortet i øjeblikket!) + Symlink oprettet successfuldt + Symlink kunne ikke oprettes af Android.\nDet mislykkes hovedsageligt pÃ¥ grund af en \"funktion\", der hedder S-ON pÃ¥ HTC-telefoner!\n\nDen løsning er at starte din telefon i gendannelsesmodus og oprette symlink der med \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nHvis dette ikke virker, søg pÃ¥ internettet for S-OFF og din telefon. + Oprettelse af symlink mislykkedes + Venligst læs Hjælp for mere information. + En APN-proxy er indstillet pÃ¥ din Android!\nAdAway fungerer ikke pÃ¥lideligt, nÃ¥r du er pÃ¥ mobilnetværk som 3G. Du kan deaktivere den pÃ¥gældende proxy ved at gÃ¥ til din valgte APN (Fra indstillingsappen: Netværk og internet -> Mobilnetværk -> Avanceret -> Adgangspunktnavn) og fjerne værdien i proxy-feltet. + APN proxy indstillet! + Internetforbindelsen virker ikke. + Ingen forbindelse + Henter… + Anvender… + Anvender godkendte og ikke godkendte lister + Parser og fletter hosts-filer + Opbygger hosts-filen + Anvender hosts-filen + Hosts-filen kunne ikke pÃ¥føres dit system!\nPrøv at ændre placeringen af hosts-filen i indstillingerne til \"/data/data/hosts\". + Anvendelse mislykkedes + Kontroller din root management-app for at sikre, at rootadgang er blevet tildelt. + Du vendte tilbage til standardværtsfilen.\nDu er muligvis nødt til at genstarte Android, for ændringerne træder i kraft.\n\nVil du genstarte?\n(For at forhindre tab af data skal du sørge for, at ingen app bruger SD-kortet i øjeblikket!) + Gendannelse successfuld + Gendannelse mislykkedes af ukendte Ã¥rsager. + Gendannelse mislykkedes! + Ingen af dine aktiverede hosts-kilder kunne nÃ¥s! Er du forbundet til internettet? + Download mislykkedes + Privat fil kan ikke oprettes. + Oprettelse af privat fil mislykkedes + Du har aktiveret systemløs tilstand.\nDet kan være nødvendigt at genstarte Android for at ændringerne skal træde i kraft.\n\nVil du genstarte?\n(For at forhindre tab af data skal du sørge for, at ingen apps bruger SD-kortet i øjeblikket!) + Aktivering succesfuldt + Du har deaktiveret systemløs tilstand.\nDet kan være nødvendigt at genstarte Android for at ændringerne skal træde i kraft.\n\nVil du genstarte?\n(For at forhindre tab af data skal du sørge for, at ingen apps bruger SD-kortet i øjeblikket!) + Deaktivering succesfuldt + + Indsæt URL til hosts fil: + Dette er ikke et gyldigt værtsnavn + Inkorrekt formateret hostnavn + Dette er ikke en gyldig IP! + Forkert formateret IP + Genstart aldrig og vis ikke dette spørgsmÃ¥l næste gang! + Indlæser… + + + Opdater + Tilføj + Hjælp + Importer sikkerhedskopieren + Eksporter sikkerhedskopieren + + + S-ON/S-OFF + OSS + Problemer + + + Adware + Her kan du finde installerede adware, dÃ¥rlige applikationer, som ikke kan blokeres af AdAway. Disse apps bruger f.eks. Airpush-underretninger, der dukker op, selvom appen ikke kører eller endda ændrer din ringetone. Den eneste tilgængelige modforanstaltning er at afinstallere disse apps ved at klikke pÃ¥ listeposterne. + Scanning… + Ingen Adware blev fundet! + + + Reklameblokering + Intet tekstredigeringsprogram installeret + Ingen tekst editor blev fundet til at Ã¥bne host filen. Du kan installere Jota eller andre tekst editorer til at hÃ¥ndtere dette.\n\nVil du installere Jota? + Intet filhÃ¥ndteringsprogram installeret + Intet filhÃ¥ndteringsprogram blev fundet til at Ã¥bne filen. Du kan installere OI File Manager eller andre filhÃ¥ndteringsprogrammer til at hÃ¥ndtere dette.\n\nVil du installere OI File Manager? + + + Tcpdump + Tcpdump er et værktøj til at overvÃ¥ge DNS-anmodninger og gemme dem i en logfil. Du kan starte den i baggrunden, køre programmer, der viser reklamer, for bagefter at analysere DNS-anmodningerne ved hjælp af logfilen. Mulig reklameværter kan derefter blive tilføjet til din blackliste. + Deaktiver overvÃ¥gning + Aktiver overvÃ¥gning + Vis resultater + Sorter domæner + Ryd log + Tilføj adgang til sort liste + Tilføj adgang til hvide liste + Tilføj adgang til omdirigeringsliste + + Rediger tekst præference værdi + Ã…ben menu + Luk menu + + + + Hjem + Hosts kilder + Dine lister + Ã…ben hosts-filen + Log DNS-anmodninger + Søg efter adware + Indstillinger + Hjælp + + + + + DNS forespørgsler + Dine lister + Indstillinger + + Aktuelt for %1$s + Brug for opdatering til %1$s + Sidste opdatering %1$s siden + Ukendt opdateringsstatus + + %d minut + %d minutter + + + %d time + %d timer + + + %d dag + %d dage + + + %d mÃ¥ned + %d mÃ¥neder + + + diff --git a/app/src/main/res/values-da/strings_app.xml b/app/src/main/res/values-da/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-da/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-da/strings_errors.xml b/app/src/main/res/values-da/strings_errors.xml new file mode 100644 index 0000000..a830a10 --- /dev/null +++ b/app/src/main/res/values-da/strings_errors.xml @@ -0,0 +1,6 @@ + + + + Ingen Internetforbindelse + Ikke nok plads + \ No newline at end of file diff --git a/app/src/main/res/values-da/strings_home.xml b/app/src/main/res/values-da/strings_home.xml new file mode 100644 index 0000000..fbe1fcb --- /dev/null +++ b/app/src/main/res/values-da/strings_home.xml @@ -0,0 +1,9 @@ + + + + Indstillinger + + + Venligst læs Hjælp for mere information. + + \ No newline at end of file diff --git a/app/src/main/res/values-da/strings_hosts.xml b/app/src/main/res/values-da/strings_hosts.xml new file mode 100644 index 0000000..7abd256 --- /dev/null +++ b/app/src/main/res/values-da/strings_hosts.xml @@ -0,0 +1,11 @@ + + + Hosts kilder + + Ikke tilgængelig + + Tilføj kilde + Rediger kilde + URL: (en https:// eller file:// ressource) + Værts kilde URL + diff --git a/app/src/main/res/values-da/strings_lists.xml b/app/src/main/res/values-da/strings_lists.xml new file mode 100644 index 0000000..221b2bf --- /dev/null +++ b/app/src/main/res/values-da/strings_lists.xml @@ -0,0 +1,15 @@ + + + Dine lister + + Tilføj host til sortliste + Tilføj host til hvidliste + Tilføj host omdirigering + Rediger sortlistet host + Rediger hvidlistet host + Rediger viderestilling + Værtsnavn: + Værts kilde URL + (Wildcard tegn * og ? er tilladt) + IP (IPv4 eller IPv6): + diff --git a/app/src/main/res/values-da/strings_log.xml b/app/src/main/res/values-da/strings_log.xml new file mode 100644 index 0000000..43353ce --- /dev/null +++ b/app/src/main/res/values-da/strings_log.xml @@ -0,0 +1,8 @@ + + + + Sorter alfabetisk + Sorter topniveau domæne + + Viderestil domæne + diff --git a/app/src/main/res/values-da/strings_notification.xml b/app/src/main/res/values-da/strings_notification.xml new file mode 100644 index 0000000..32dbdf9 --- /dev/null +++ b/app/src/main/res/values-da/strings_notification.xml @@ -0,0 +1,5 @@ + + + + Opdateringer + \ No newline at end of file diff --git a/app/src/main/res/values-da/strings_prefs_backup_restore.xml b/app/src/main/res/values-da/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-da/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-da/strings_prefs_main.xml b/app/src/main/res/values-da/strings_prefs_main.xml new file mode 100644 index 0000000..b89b530 --- /dev/null +++ b/app/src/main/res/values-da/strings_prefs_main.xml @@ -0,0 +1,12 @@ + + + Indstillinger + Aktiver mørkt tema + Aktivér IPv6 + + Debug + Aktivér nedbrudrapporter + Tillad, at applikationen sender fejl og nedbrudrapporter til Sentry (sentry.io). + Aktivér verbose logging + Du skal genstarte AdAway for at denne indstilling tages i brug + diff --git a/app/src/main/res/values-da/strings_prefs_root.xml b/app/src/main/res/values-da/strings_prefs_root.xml new file mode 100644 index 0000000..f75911b --- /dev/null +++ b/app/src/main/res/values-da/strings_prefs_root.xml @@ -0,0 +1,14 @@ + + + Ã…ben hosts-filen + Destinations-hostsfil + + /system/etc/hosts + /data/hosts + /data/data/hosts + Brugerdefineret destination + + + Omdirigering + Aktiver webserver + diff --git a/app/src/main/res/values-da/strings_prefs_update.xml b/app/src/main/res/values-da/strings_prefs_update.xml new file mode 100644 index 0000000..3c71d30 --- /dev/null +++ b/app/src/main/res/values-da/strings_prefs_update.xml @@ -0,0 +1,6 @@ + + + Opdateringer + Check for opdateringer dagligt + Check for opdateringer dagligt + diff --git a/app/src/main/res/values-da/strings_prefs_vpn.xml b/app/src/main/res/values-da/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-da/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-da/strings_support.xml b/app/src/main/res/values-da/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-da/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-da/strings_update.xml b/app/src/main/res/values-da/strings_update.xml new file mode 100644 index 0000000..ffdd7a2 --- /dev/null +++ b/app/src/main/res/values-da/strings_update.xml @@ -0,0 +1,4 @@ + + + Opdatering fundet + diff --git a/app/src/main/res/values-da/strings_welcome.xml b/app/src/main/res/values-da/strings_welcome.xml new file mode 100644 index 0000000..6802b2b --- /dev/null +++ b/app/src/main/res/values-da/strings_welcome.xml @@ -0,0 +1,4 @@ + + + En rootet Android kræves + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml new file mode 100644 index 0000000..fc65672 --- /dev/null +++ b/app/src/main/res/values-de/strings.xml @@ -0,0 +1,262 @@ + + + + Beenden + Schließen + Ja + Nein + Hinzufügen + Abbrechen + Speichern + Hilfe + + + Willkommen! + AdAway ist ein freier Open-Source Werbeblocker. Wenn eine Netzwerkadresse eines Werbeanbieters aufgerufen wird, blockiert er dies.\nMöchten Sie mehr darüber erfahren? Rufen Sie dazu weiter unten \"Hilfe anzeigen\" auf! + Hilfe anzeigen + Aktualisierungsstatus + Alle Hosts-Dateien aus den hinterlegten Quellen werden heruntergeladen. Anschließend werden diese zu Ihrer eigenen Liste hinzugefügt und als eine Hosts-Datei im System gespeichert. + Werbeblocker aktivieren + Werbeblocker deaktivieren + Webserver + Läuft + Gestoppt + Lokalen Webserver starten oder stoppen, um Anfragen an blockierte Hostnamen zu beantworten. + Webserver aktivieren + Webserver deaktivieren + VPN + Läuft + Angehalten + VPN zum Filtern von Anfragen starten oder beenden. + VPN aktivieren + VPN deaktivieren + + + Eintrag bearbeiten + Anwenden + Bearbeiten + Löschen + + + Importiere… + Sicherung erfolgreich aus externem Speicher importiert. + Einlesen der Sicherung fehlgeschlagen. Passt das Format? Weitere Infos dazu im Logcat Protokoll. + Exportiere… + Sicherung wurde erfolgreich in die Datei \'%s\' auf externem Speicher erstellt. + Erstellen der Sicherungsdatei \'%s\' ist fehlgeschlagen. + + + Die Hosts-Datei + Die Hosts-Datei ist eine Datei aus dem Systembereich, bei der Hostnamen(Webadressen) zu IP-Adressen zugewiesen werden. Die Konfiguration der reinen Text Datei wird von AdAway übernommen. Nachfolgend ihre ersten Zeilen: + Inhalt der Hosts-Datei laden… + Hosts-Datei öffnen + + + Prüfen auf Aktualisierung + Quelle %s auf Aktualisierung prüfen + Quellen abrufen + Quelle %s wird heruntergeladen + Lese Quelle %s + Analysiere Quelle %s + Abgleichen des Regelwerks + Hosts-Datei wird auf Standard zurückgesetzt + Standard-Hosts-Datei wiederhergestellt + Standard-Hosts-Datei wird generiert + Aktualisierung verfügbar + Neuere Hosts-Dateien verfügbar + Keine Quellaktualisierung gefunden + Keine Internetverbindung + Keine Internetverbindung verfügbar + Nicht verfügbare Quellen + Keine Hosts-Quellen erreichbar! + Root-Zugriff verweigert + Aus der Root-App den Root-Zugriff zulassen. + Ein Fehler ist aufgetreten + Logcat für weitere Details sichten + Aktiviert + Die neuesten Hosts-Dateien sind aktiv + Deaktiviert + Standard-Hosts-Datei installiert + Neueste Quellen anwenden + Neue Hosts-Datei wird erstellt + Neue Hosts-Datei wird kopiert + Kopie der Hosts-Datei wird geprüft + Hosts-Datei erfolgreich aktualisiert + VPN-Konfiguration erfolgreich aktualisiert + Ihre Konfiguration hat sich geändert. Zum Anwenden \'übernehmen\' betätigen. + Übernehmen + Neue Konfiguration wird übernommen … + Anwendung der neuen Konfiguration ist fehlgeschlagen. + + + Die symbolische Verknüpfung (symlink) zur Hosts-Datei fehlt + Die symbolische Verknüpfung (Symlink) zwischen Ziel und /system/etc/hosts ist nicht vorhanden oder falsch! Ohne diese Verknüpfung wird AdAway nicht funktionieren.\n\nMöchten Sie versuchen eine symbolische Verknüpfung zu erstellen? + Symbolische Verknüpfung fehlt + Nicht genügend Speicherplatz auf der Partition frei!\nVersuchen Sie die zu benutzende Hosts-Datei auf /data/data/hosts zu ändern. + Nicht genügend Speicherplatz + Die heruntergeladene Datei konnte nicht gelesen werden. + Private Datei fehlgeschlagen + Das Einbinden der Partition mit Schreibrechten ist fehlgeschlagen! + Neueinbinden ist fehlgeschlagen + Kopieren der Hosts-Datei fehlgeschlagen + Kopieren der Hosts-Datei fehlgeschlagen! + Kopieren fehlgeschlagen + Hosts-Quellen wurden angewandt + Erfolgreich angewendet + Änderungen waren erfolgreich.\nDamit alle Änderungen wirksam werden, kann es nötig sein Android neu zu starten.\n\nMöchten Sie neu starten?\n(Um Datenverlust zu vermeiden, stellen Sie bitte sicher, dass keine Anwendung gerade die SD-Karte verwendet!) + Symbolische Verknüpfung wurde erfolgreich erstellt.\nAndroid muss eventuell neu gestartet werden, damit alle Änderungen wirksam werden.\n\nMöchten Sie neu starten?\n(Um Datenverluste zu vermeiden darf momentan keine Anwendung die SD-Karte verwenden!) + Symbolische Verknüpfung erfolgreich erstellt + Symbolische Verknüpfung konnte nicht von Android erstellt werden.\nDies liegt wahrscheinlich an einer \'Funktion\' namens S-ON auf HTC-Geräten!\n\nEine Lösung ist es, Ihr Gerät im Wiederherstellungsmodus zu starten und die Verknüpfung von dort mit »ln -s /data/data/hosts /system/etc/hosts« zu erstellen.\n\nWenn dies nicht funktioniert, suchen Sie bitte im Internet nach S-OFF und Ihrem Gerät. + Symbolische Verknüpfung konnte nicht erstellt werden + Bitte Hilfe für mehr Informationen lesen. + Auf Ihrem Android-Gerät ist ein Zugangspunktvermittlungsserver (APN-Proxy) aktiviert!\nAdAway wird in Mobilfunknetzen (2G, 3G, 4G, 5G) nicht zuverlässig funktionieren. Sie können diesen Vermittlungsserver (Proxy) deaktivieren, indem Sie in den Einstellungen wechseln: Netzwerk & Internet -> Mobilfunknetz -> Zugangspunkte (APNs)) und den Wert im Proxy-Feld entfernen. + APN-Proxy eingestellt! + Die Internetverbindung funktioniert nicht. + Keine Verbindung + Wird heruntergeladen… + Wird angewendet… + Negativ- und Positivliste werden angewendet + Hosts-Dateien werden verarbeitet und zusammengefügt + Hosts-Datei wird erstellt + Neue Hosts-Datei im System aktivieren + Anwendung der neuen Hosts-Datei fehlgeschlagen + Das Ändern der Hosts-Datei auf Ihrem System ist fehlgeschlagen!\nVersuchen Sie bitte die Hosts-Datei in den Einstellungen auf /data/data/hosts zu ändern. + Anwendung fehlgeschlagen + Bitte in der Root-Verwaltungssoftware überprüfen, ob diese App Root-Zugriffsrechte hat. + Die originale Hosts-Datei wurde wiederhergestellt.\nDamit alle Änderungen wirksam werden muss Android eventuell neu gestartet werden, .\nMöchten Sie neu starten?\n(Um Datenverluste zu vermeiden darf aktuell keine Anwendung die SD-Karte verwenden!) + Erfolgreich zurückgesetzt + Zurücksetzen der Hosts-Datei nicht möglich + Zurücksetzen aus unbekannten Gründen fehlgeschlagen. + Zurücksetzen fehlgeschlagen! + Keine der aktivierten Hosts-Quellen ist erreichbar! Bitte Internetverbindung prüfen! + Herunterladen fehlgeschlagen + Schreiben der neuen privaten Hosts-Datei fehlgeschlagen + Private Datei konnte nicht erstellt werden. + Erstellen der privaten Datei fehlgeschlagen + Sie haben den Systemlosen Modus deaktiviert.\nDamit alle Änderungen wirksam werden, muss das System eventuell neu gestartet werden.\n\nMöchten Sie neu starten?\n(Um Datenverlust zu vermeiden, vergewissern Sie sich, dass gerade keine Anwendung die SD-Karte verwendet!) + Aktivierung erfolgreich + Sie haben den Systemlosen Modus deaktiviert.\nDamit alle Änderungen wirksam werden, muss das System eventuell neu gestartet werden.\n\nMöchten Sie neu starten?\n(Um Datenverlust zu vermeiden, vergewissern Sie sich, dass gerade keine Anwendung die SD-Karte verwendet!) + Deaktivieren erfolgreich + Aktivieren der VPN-Werbeblockade fehlgeschlagen + Deaktivieren der VPN-Werbeblockade fehlgeschlagen + Aktivieren des Hosts-Moduls von Magisk + Systemunabhängige Hosts-Funktion im Magisk Manager aktivieren. Dort in den Einstellungen die Option Systemless hosts wählen und anschließend das Gerät neustarten. + Deaktivieren des Hosts-Moduls von Magisk + Systemunabhängige Hosts-Funktion im Magisk Manager deaktivieren. In den Optionen Systemless hosts deinstallieren und anschließend das Gerät neustarten. + + + Bitte Adresse zur Hosts-Datei eingeben: + Das ist kein gültiger Hostname! + Falsch formatierter Hostname + Das ist keine gültige IP! + Falsch formatierte IP + Nie neu starten und diese Frage nicht mehr stellen! + Wird geladen … + + + Neu laden + Hinzufügen + Hilfe + Sicherung importieren + Sicherung exportieren + + + S-ON/S-OFF + FAQ + Probleme + + + Adware + Hier sind schlechte Werbesoftware Anwendungen aufgelistet, die nicht von AdAway blockiert werden können. Diese Apps nutzen zum Beispiel Airpush-Benachrichtigungen die selbst dann erscheinen, wenn die App gar nicht läuft oder es wird sogar Ihr Klingelton umgestellt. Die einzige Gegenmaßnahme ist solche Apps zu deinstalieren, indem Sie auf die Listeneinträge klicken. + Durchsuchen … + Keine Adware gefunden! + + + Werbeblocker + Kein Text Editor installiert + Es konnte kein Text Editor gefunden werden um die Hosts-Datei zu öffnen. Sie können Jota oder eine andere Editor installieren um Textdateien zu öffnen.\n\nMöchten Sie Jota installieren? + Keine Dateiverwaltung installiert + Es konnte keine Dateiverwaltung gefunden werden um Dateien zu öffnen. Sie können um dies zu beheben »OI File Manager« oder einen andere Dateimanager installieren.\n\n Möchten Sie »OI File Manager« installieren? + + + TCPdump + Mit TCPDump können DNS-Anfragen aufgezeichnet und in einer Protokolldatei gespeichert werden. Dazu TCPDump im Hintergrund starten und anschließend die App mit Werbung ausführen. Danach die Protokolldatei in AdAway analysieren. Mögliche Werbe-Server können nun zu Ihrer Negativliste(blacklist) hinzugefügt werden. + Aufzeichnung deaktivieren + Aufzeichnung aktivieren + Ergebnisse anzeigen + Domänen sortieren + Protokoll leeren + Eintrag zur Negativliste hinzufügen + Eintrag zur Positivliste hinzufügen + Eintrag zur Umleitungsliste hinzufügen + + Textvorgabe bearbeiten + Menü öffnen + Menü schließen + + + + Home + Hosts-Quellen + Meine Listen + Hosts-Datei öffnen + DNS-Anfragen protokollieren + Adware-Scanner + Einstellungen + Hilfe + + + + + DNS-Anfragen + Meine Listen + Einstellungen + + + Vor %1$s installiert + Seit %1$s aktuell + Update seit %1$snotwendig + Letzte Aktualisierung vor %1$s + Status der Aktualisierung unbekannt + Deaktiviert + wenigen Minuten + + %d Minute + %d Minuten + + + %d Stunde + %d Stunde(n) + + + %d Tag + %d Tag(en) + + + %d Monat + %d Monat(en) + + + + Host in Zwischenablage kopiert + + + wird gestartet + aktiv + wird angehalten + auf Netzwerk warten + wird erneut verbunden + Fehler beim erneuten Verbinden + pausiert + angehalten + Ad-blocker-VPN %1$s + Pause + Weiter + + + AdAway Bewilligung + Mit AdAway den Kontakt bewilligen + Befehle an AdAway senden + Bewillige das Senden von Befehlen an AdAway, wie \"Einschalten\" oder \"Ausschalten\" des Werbeblockers + + diff --git a/app/src/main/res/values-de/strings_app.xml b/app/src/main/res/values-de/strings_app.xml new file mode 100644 index 0000000..4a34dee --- /dev/null +++ b/app/src/main/res/values-de/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Open Source Werbeblocker + AdAway Logo + diff --git a/app/src/main/res/values-de/strings_errors.xml b/app/src/main/res/values-de/strings_errors.xml new file mode 100644 index 0000000..e33438a --- /dev/null +++ b/app/src/main/res/values-de/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Keine Internetverbindung + Es kann keine Verbindung zum Internet hergestellt werden. Prüfen Sie bitte die Verbindungsfähigkeit Ihres Geräts. + Download der Hosts-Quelle fehlgeschlagen + Keine der von Ihnen aktivierten Hosts-Quellen ist erreichbar. Prüfen Sie bitte, ob Ihre Internetverbindung funktioniert. + + Erstellung der privaten Datei fehlgeschlagen + Es ist nicht möglich, eine private Datei zu erstellen, um eine neue Hosts-Quelle aufzubauen. Prüfen Sie bitte, ob auf Ihrem Gerät ausreichend Speicherplatz zur Verfügung steht. + Nicht genügend Speicherplatz + Es ist nicht möglich, die Hosts-Datei in Ihre Systempartition zu kopieren. Prüfen Sie bitte, ob das systemlose Magisk-Modul aktiviert ist, und starten Sie dann das Gerät neu. + Installation der neuen Hosts-Datei fehlgeschlagen + Kopieren der Hosts Datei zur /System Partition nicht möglich. Bitte überprüfe ob das Magisk Systemless Modul aktiv ist, dann Gerät neu starten + Zurücksetzen der Hosts-Datei fehlgeschlagen + Es ist nicht möglich, die Standardkonfiguration der Hosts-Datei wiederherzustellen. + + Aktivierung der VPN-Werbeblockade fehlgeschlagen + Überprüfen Sie bitte Ihre VPN-Einstellungen, um der App den VPN-Start zu genehmigen. + Deaktivierung der VPN-Werbeblockade fehlgeschlagen + Überprüfen Sie bitte Ihre VPN-Einstellungen, um sie manuell zu deaktivieren. + diff --git a/app/src/main/res/values-de/strings_home.xml b/app/src/main/res/values-de/strings_home.xml new file mode 100644 index 0000000..69c2912 --- /dev/null +++ b/app/src/main/res/values-de/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Blockiert + Gestattet + Umgeleitet + + + + %d aktuelle Quelle + %d aktuelle Quellen + + + %d veraltete Quelle + %d veraltete Quellen + + Hosts-Aktualisierungen suchen + Hosts aktualisieren + + + DNS-Abfrage-Protokoll anzeigen + + + Hilfe\n und Tipps anzeigen + + + GitHub-Seite öffnen + + + Das Projekt unterstützen + + + GitHub Project + Einstellungen + + + App-Navigation öffnen + Werbeblockade anhalten/wiederaufnehmen + Blockierte Domänen aktualisieren + Abgefragte Domänen anzeigen + + + Bitte die Hilfe für mehr Informationen lesen. + + \ No newline at end of file diff --git a/app/src/main/res/values-de/strings_hosts.xml b/app/src/main/res/values-de/strings_hosts.xml new file mode 100644 index 0000000..2344634 --- /dev/null +++ b/app/src/main/res/values-de/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Hosts-Quellen + + Benutzerliste + AdAway official hosts + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + nicht verfügbar + %s hosts + + Quelle hinzufügen + Quelle bearbeiten + URL: (eine https:// oder file:// Quelle) + Die Quell-URL der Hosts + diff --git a/app/src/main/res/values-de/strings_lists.xml b/app/src/main/res/values-de/strings_lists.xml new file mode 100644 index 0000000..df82d87 --- /dev/null +++ b/app/src/main/res/values-de/strings_lists.xml @@ -0,0 +1,24 @@ + + + Meine Listen + Host hinzufügen + + Blockiert + Gestattet + Umgeleitet + + Host filtern + Suche Hostname… + Quellen wechseln + + Host zur Negativliste hinzufügen + Host zur Positivliste hinzufügen + Host-Umleitung hinzufügen + Host in Negativliste bearbeiten + Host in Positivliste bearbeiten + Umleitung bearbeiten + Hostname: + Die Quell-URL der Hosts + (Die Zeichen * und ? sind als Platzhalter zulässig) + IP (IPv4 oder IPv6): + diff --git a/app/src/main/res/values-de/strings_log.xml b/app/src/main/res/values-de/strings_log.xml new file mode 100644 index 0000000..6c37cc9 --- /dev/null +++ b/app/src/main/res/values-de/strings_log.xml @@ -0,0 +1,11 @@ + + + Protokoll-Aufzeichnung umschalten + Drücken Sie \"aufzeichnen\", um die Protokollierung von Anfragen zu starten, stöbern Sie im Netz oder verwenden Sie Apps, kehren Sie danach hierher zurück oder wischen Sie nach unten, damit die Protokolle erneuert werden. + \n\nBlockierte Anfragen werden nicht protokolliert. Deaktivieren Sie zunächst den Werbeblocker, wenn Sie diese auch protokollieren möchten. + + Alphabetische Sortierung + Nach Top-Level-Domänen sortieren + + Domäne umleiten + diff --git a/app/src/main/res/values-de/strings_notification.xml b/app/src/main/res/values-de/strings_notification.xml new file mode 100644 index 0000000..c1f2a95 --- /dev/null +++ b/app/src/main/res/values-de/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Aktualisierungen + Neue Aktualisierung verfügbar + Aktualisierung verfügbar + Neuere hosts-Datei vorhanden + App-Aktualisierung verfügbar + Neue Version von AdAway vorhanden + + VPN + Nachricht von VPN + \ No newline at end of file diff --git a/app/src/main/res/values-de/strings_prefs_backup_restore.xml b/app/src/main/res/values-de/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4b9f71f --- /dev/null +++ b/app/src/main/res/values-de/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Sichern & Wiederherstellen + Sichern + Sichern Ihrer Listen auf einen externen Speicher + Wiederherstellen + Wiederherstellen Ihrer Listen aus der Sicherungsdatei + diff --git a/app/src/main/res/values-de/strings_prefs_main.xml b/app/src/main/res/values-de/strings_prefs_main.xml new file mode 100644 index 0000000..078a1fd --- /dev/null +++ b/app/src/main/res/values-de/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Einstellungen + + Allgemein + Dunkles Design aktivieren + + Hell + Dunkel + Systemvorgabe + + Automatische Updates + + Werbung blockieren + Root-basierter Werbeblocker + VPN-basierter Werbeblocker + IPv6 aktivieren + Sichern / Wiederherstellen Ihrer Listen + + Fehlerdiagnose + Absturzberichte aktivieren + Der Anwendung erlauben, Fehler und Absturzberichte an Sentry (sentry.io) zu senden. + Nicht unterstützt in dieser Version + Ausführliche Protokollierung aktivieren + Sie müssen AdAway neustarten, damit diese Einstellung genutzt werden kann. + diff --git a/app/src/main/res/values-de/strings_prefs_root.xml b/app/src/main/res/values-de/strings_prefs_root.xml new file mode 100644 index 0000000..a13347a --- /dev/null +++ b/app/src/main/res/values-de/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Root-basierter Werbeblocker + + Hosts Installation + Hosts-Datei öffnen + Zu benutzende Hosts-Datei + Bevor Sie diese Einstellung ändern, bitte die Hilfe zu dem Thema lesen. + + /system/etc/hosts + /data/hosts + /data/data/hosts + Benutzerdefiniertes Ziel + + Benutzerdefiniertes Ziel + Neustartdialog verstecken + + Umleitung + Festlegen wohin blockierte Hosts umgeleitet werden sollen + Umleitungs-IPv4 + Umleitungs-IPv6 + Ungültige Umleitung + + Lokaler Webserver + Der lokale Webserver überwacht lokale IP-Adressen um auf blockierte Hostnamen zu antworten. Dies kann helfen wenn Apps einfrieren bei blockierter Verbindung. + Webserver aktivieren + Webserver testen + Selbstsigniertes Zertifikat installieren + Zertifikat manuell installieren + Ab Android 11 (R), kann die Anwendung die Zertifizierungsstelle (CA) nicht mehr automatisch installieren.\n\nGehen Sie zu \"Sicherheit\"-Einstellungen, \"Verschlüsselung und Anmeldeinformationen\" und dann zu \"Zertifikat installieren\". Wählen Sie dort \"CA-Zertifikat\" und wählen Sie die neu exportierte Zertifikatsdatei aus. + \"Sicherheit\"-Einstellungen öffnen + Überprüfe… + Läuft nicht + Läuft aber Zertifikat nicht installiert + Läuft und Zertifikat installiert + Ersetzt die leere Werbefläche durch das Anwendungssymbol + diff --git a/app/src/main/res/values-de/strings_prefs_update.xml b/app/src/main/res/values-de/strings_prefs_update.xml new file mode 100644 index 0000000..85724e2 --- /dev/null +++ b/app/src/main/res/values-de/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Aktualisierungen + Benachrichtigungen sind ausgeschaltet + App-Benachrichtigungen werden unterdrückt. Drücke, um sie anzuzeigen. + + App-Aktualisierungen + Beim Start nach Aktualisierungen suchen + Täglich nach Aktualisierungen suchen + Beta-Versionen einbeziehen + + Hosts-Aktualisierungen + Beim Start nach Aktualisierungen suchen + Täglich nach Aktualisierungen suchen + Synchronisiere beim Aktualisieren + Synchronisiere nur im gebührenfreien Netzwerk + diff --git a/app/src/main/res/values-de/strings_prefs_vpn.xml b/app/src/main/res/values-de/strings_prefs_vpn.xml new file mode 100644 index 0000000..ae6e1d8 --- /dev/null +++ b/app/src/main/res/values-de/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN-basierter Werbeblocker + + Beim Starten einschalten + Verbindung überwachen + Überprüfen Sie regelmäßig den Netzwerkstatus, um VPN beim Trennen der Verbindung neu zu starten. + + Ausgenommene Anwendungen + Konfiguriere welche Anwendungen das VPN nicht verwenden sollen, damit keine Verbindungen blockiert werden. + System-Anwendungen ausschließen + + Keine + Alle außer Web-Browser + Alle + + Benutzer-Anwendungen ausschließen + + + Ausgenommene Anwendungen + Alle anwählen + Alle abwählen + App-Icon + diff --git a/app/src/main/res/values-de/strings_source_edit.xml b/app/src/main/res/values-de/strings_source_edit.xml new file mode 100644 index 0000000..901e9ad --- /dev/null +++ b/app/src/main/res/values-de/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Quelle bearbeiten + Quelle hinzufügen + + Beschriftung + Beschriftung erforderlich + Typ + URL + Datei + Speicherort + https:// + Speicherort erforderlich + Drücke Datei, um Quelldatei auszuwählen + Ungültiger Speicherort + Format auflisten + Blockieren + Erlauben + Host-Weiterleitungen anwenden + Host-Weiterleitungen können ein Sicherheitsrisiko sein. Benutze diese Einstellungen nur, wenn du der Quelle vertraust, denn die Quelldatei kann den sensiblen Netzwerkverkehr auf jeden beliebigen Server umleiten. + diff --git a/app/src/main/res/values-de/strings_support.xml b/app/src/main/res/values-de/strings_support.xml new file mode 100644 index 0000000..5c3bbe1 --- /dev/null +++ b/app/src/main/res/values-de/strings_support.xml @@ -0,0 +1,5 @@ + + + Support + Werden Sie Förderer + \ No newline at end of file diff --git a/app/src/main/res/values-de/strings_update.xml b/app/src/main/res/values-de/strings_update.xml new file mode 100644 index 0000000..624fac3 --- /dev/null +++ b/app/src/main/res/values-de/strings_update.xml @@ -0,0 +1,21 @@ + + + AdAway aktualisieren + + Aktualisierung verfügbar! + + + Sie sind auf dem neusten Stand + Aktualisierung verfügbar + Aktualisierung AdAway + Jetzt Aktualisieren + %1$s / %2$s + Letzte Änderungen + Änderungen + Weiterentwicklung fördern + Spenden + Sponsor + + + Herunterladen der neuesten AdAway Version… + diff --git a/app/src/main/res/values-de/strings_welcome.xml b/app/src/main/res/values-de/strings_welcome.xml new file mode 100644 index 0000000..6aef315 --- /dev/null +++ b/app/src/main/res/values-de/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Willkommen + Assistent erste Schritte + Assistent zweiter Schritt + Assistent letzter Schritt + + + Willkommen bei AdAway! + AdAway bietet zwei Methoden zum Blockieren von Werbung. Wählen Sie die Methode, die Ihnen gefällt: + + Root logo + Root-basierter\nWerbeblocker + Schneller + Akku schonend + Benötigt Root + + VPN logo + VPN-basierter\nWerbeblocker + Langsamer + Läuft im Hintergrund + Kompatibilität + + Das System muss gerootet sein + Entweder konnte die su-Binärdatei nicht gefunden werden, oder Sie haben AdAway keine Root-Berechtigung erteilt.\n\nDies kann passieren, wenn Ihr Gerät nicht gerootet ist. Informationen darüber, wie Sie Ihr Gerät rooten können, finden Sie auf wiki.lineageos.org oder anderen Android-Webseiten. + + Pro + Kontra + + + Synchronisation erledigt + Fehler beim Synchronisieren + + Synchronisiere + Synchronisiert! + AdAway lädt Werbenetzwerke zum Blockieren aus Online-Quellen herunter. Sie können sie später in den Einstellungen anpassen. + Wiederhole Synchronisierung + Fehler beim Synchronisieren: %1$s. Jetzt erneut versuchen? + Es kann Benachrichtigungen anzeigen, die Informationen sowohl über den Status und das Blockieren von Werbung enthalten als auch über anstehende App-Aktualisierungen (einige pro Jahr). Schalte sie ein, wenn du auf dem Laufenden bleiben möchtest. + + + Support + Unterstützt mich! + AdAway ist eine quelloffene Software, die ich in meiner Freizeit entwickle. Wenn sie dir gefällt, dann freue ich mich über deine Unterstützung: + Spende über PayPal + Mögen Sie Fehler? Ich auch nicht + Telemetrie aktivieren, um Absturzberichte zu senden. + + + Zurück + Weiter + Fertig + diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml new file mode 100644 index 0000000..bfd169f --- /dev/null +++ b/app/src/main/res/values-el/strings.xml @@ -0,0 +1,284 @@ + + + + Έξοδος + Κλείσιμο + Îαι + Όχι + ΠÏοσθήκη + ΆκυÏο + Αποθήκευση + Βοήθεια + + + Καλώς ήÏθατε! + Το AdAway είναι μια δωÏεάν και Î±Î½Î¿Î¹Ï‡Ï„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± εφαÏγμογή σχεδιασμένη να μπλοκάÏει τις διαφημίσεις. ΠαίÏνει τις διαφημιστικές διευθÏνσεις των δικτÏων και τις μπλοκάÏει στην συσκευή σας. \nΘέλετε να μάθετε πεÏισσότεÏα; Δείτε την βοήθεια παÏακάτω! + Εμφάνιση πεÏισσότεÏης βοήθειας + Κατάσταση ενημέÏωσης + Όλα τα αÏχεία hosts από τις πηγές που οÏίστηκαν λήφθηκαν, συγχωνεÏθηκαν με τις δικές σας λίστες και εγκαταστάθηκαν ως ένα αÏχείο hosts στο σÏστημά σας. + ΕνεÏγοποίηση του Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ + ΑπενεÏγοποίηση του Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ + Διακομιστής διαδικτÏου + Εκτελείται + Διακόπηκε + Ξεκινήστε ή διακόψτε webserver στο localhost για να απαντήσετε σε αιτήματα σε αποκλεισμένα hostnames. + ΕνεÏγοποίηση του διακομιστή ιστοσελίδων + ΑπενεÏγοποήση διακομιστή διαδικτÏου + VPN + Εκτελείται + Διακόπηκε + Ξεκινήστε ή διακόψτε το VPN για να φιλτÏάÏετε αιτήματα. + ΕνεÏγοποίηση VPN + ΑπενεÏγοποίηση VPN + + + ΕπεξεÏγασία καταχώÏησης + ΕφαÏμογή + ΕπεξεÏγασία + ΔιαγÏαφή + + + Εισαγωγή… + Η δημιουÏγία αντιγÏάφων ασφαλείας έγινε με επιτυχία από το εξωτεÏικό αποθηκευτικό χώÏο. + Αποτυχία εισαγωγής αντιγÏάφων ασφαλείας. Είναι σωστή η μοÏφή του; Ελέγξτε το αÏχείο logcat για πεÏισσότεÏες λεπτομέÏειες. + Εξαγωγή… + Το αντίγÏαφο ασφαλείας εξήχθη με επιτυχία στο αÏχείο \'%s\' στον εξωτεÏικό χώÏο αποθήκευσης σας. + Αποτυχία εξαγωγής αÏχείου αντιγÏάφου ασφαλείας \'%s\'. + + + Το αÏχείο hosts + Το αÏχείο hosts είναι ένα αÏχείο συστήματος το οποίο αντιστοιχίζει ονόματα διακομιστών σε διευθÏνσεις IP. Είναι ένα αÏχείο Î±Ï€Î»Î¿Ï ÎºÎµÎ¹Î¼Î­Î½Î¿Ï… το οποίο Ïυθμίζει το AdAway. Εδώ παÏατίθενται οι Ï€Ïώτες του γÏαμμές: + Γίνεται φόÏτωση του πεÏιεχομένου του αÏχείου hosts… + Άνοιγμα του αÏχείου hosts + + + Έλεγχος για ενημέÏωση + Ελεγχος %s πηγής-ών για ενημέÏωση + Ανάκτηση πηγών + Λήψη πηγής %s + Ανάγνωση πηγής-ών %s + ΠαÏάθεση απο %s + ΣυγχÏονισμός κανόνων βάσης δεδομένων + ΕπαναφοÏά στο Ï€Ïοεπιλεγμένο hosts file + Τα Ï€Ïοεπιλεγμένα hosts file αποκαταστάθηκαν + ΔημιουÏγία ÏƒÏ„Î¬Î½Ï„Î±Ï Î±Ïχείου hosts + Διαθέσιμη ενημέÏωση πηγής + ΥπάÏχουν διαθέσιμα πιο Ï€Ïόσφατα αÏχεία hosts + Δεν βÏέθηκε ενημέÏωση πηγής + Δεν υπάÏχει σÏνδεση στο ίντεÏνετ + Δεν υπάÏχει διαθέσιμη σÏνδεση στο ίντεÏνετ + Μη διαθέσιμες πηγές + Δεν υπάÏχουν διαθέσιμες πηγές hosts! + Η Ï€Ïόσβαση Root αποÏÏίφθηκε + ΕπιτÏέψετε την Ï€Ïόσβαση Root από την Root εφαÏμογή σας + Κάτι πήγε λάθος + Δείτε το αÏχείο καταγÏαφής για πεÏισσότεÏες λεπτομέÏειες. + ΕνεÏγοποιημένο + ΕνεÏγοποιήθηκαν τα πιο Ï€Ïόσφατα αÏχεία hosts + ΑπενεÏγοποιημένο + Τα Ï€Ïοεπιλεγμένα αÏχεία hosts εγκαταστάθηκαν + ΕφαÏμογή των πιο Ï€Ïόσφατων πηγών + ΔημιουÏγία νέου hosts file + ΑντιγÏαφή νέου hosts file + Έλεγχος αντιγÏάφου hosts file + To host file ενημεÏώθηκε με επιτυχία + Η διαμόÏφωση VPN ενημεÏώθηκε με επιτυχία + Η διαμόÏφωσή σας άλλαξε. ΠÏέπει να την εφαÏμόσετε. + ΕφαÏμογή + ΕφαÏμογή νέας διαμόÏφωσης… + Αποτυχία εφαÏμογής νέας διαμόÏφωσης. + + + Το symlink με στόχο το hosts file λείπει + Ο σÏνδεσμος από τον Ï€ÏοοÏισμό στο /system/etc/hosts δεν υπάÏχει ή είναι λανθασμένος! Το AdAway δεν θα λειτουÏγήσει αν δεν δείχνει στο σωστό αÏχείο. + +Θέλετε να Ï€Ïοσπαθήσετε να δημιουÏγήσετε έναν σÏνδεσμο; + Η συντόμευση λείπει + Δεν υπάÏχει αÏκετός χώÏος στο διαμέÏισμα Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου! +ΠÏοσπαθήστε να αλλάξετε το αÏχείο Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï hosts στις Ïυθμίσεις σε /data/data/hosts. + Δεν υπάÏχει διαθέσιμος χώÏος + Δεν μποÏεί να διαβαστεί το κατεβασμένο αÏχείο. + Απέτυχε το Ï€Ïοσωπικό αÏχείο + Η επανατοποθέτηση του διαμεÏίσματος με δικαιώματα εγγÏαφής/ανάγνωσης απέτυχε! + Η επανατοποθέτηση απέτυχε + Αποτυχία αντιγÏαφής hosts file + Η αντιγÏαφή του αÏχείου hosts απέτυχε! + Η αντιγÏαφή απέτυχε + ΕφαÏμοσμένα hosts sources + Επιτυχής εφαÏμογή + Η εφαÏμογή ήταν επιτυχής. +Ίσως είναι απαÏαίτητο να επανεκκινήσετε το Android για να εφαÏμοστοÏν οι αλλαγές. +Θέλετε να γίνει επανεκκίνηση; +(Για να αποφÏγετε απώλεια δεδομένων, επαληθεÏστε ότι καμία εφαÏμογή δεν χÏησιμοποιεί την κάÏτα SD αυτή την στιγμή!) + Ο σÏνδεσμος δημιουÏγήθηκε με επιτυχία. +Ίσως είναι απαÏαίτητο να επανεκκινήσετε το Android για να εφαÏμοστοÏν οι αλλαγές. +Θέλετε να κάνετε επανεκκίνηση; +(Για να αποφÏγετε απώλεια δεδομένων, επαληθεÏστε ότι καμία εφαÏμογή δεν χÏησιμοποιεί την κάÏτα SD αυτή την στιγμή!) + Επιτυχής δημιουÏγία συντόμευσης + Δεν ήταν δυνατό να δημιουÏγηθεί ο σÏνδεσμος από το Android. +Η αποτυχία οφείλεται συνήθως σε ένα \'χαÏακτηÏιστικό\' που ονομάζεται S-ON στις συσκευές HTC! + +Μια λÏση είναι να επανεκκινήσετε την συσκευή σας σε κατάσταση ανάκτησης και να δημιουÏγήσετε τον σÏνδεσμο εκεί με την εντολή \'ln -s /data/data/hosts /system/etc/hosts\' + +Αν αυτό δεν επιτÏχει, αναζητήστε στο Internet για S-OFF και το μοντέλο της συσκευής σας. + Η δημιουÏγία συντόμευσης απέτυχε + ΠαÏακαλοÏμε ανατÏέξτε στην Βοήθεια για πεÏισσότεÏες πληÏοφοÏίες + Ένας διαμεσολαβητής APN είναι οÏίσμενος στο Android σας!\nΤο AdAway δεν λειτουÏγεί αξιόπιστα σε δίκυτα κινητής τηλεφωνίας όπως 3G. ΜποÏείτε να απενεÏγοποιήσετε τον διαμεσολαβητή πηγαίνοντας στο επιλεγμένο APN (Απο τα Settings app: Network & Internet -> Mobile network -> Advanced -> Access Point Names) και να αφαιÏέσετε την τιμή στο πεδίο proxy. + ΥπάÏχει οÏισμένος διαμεσολαβητής APN! + Η σÏνδεση στο ίντεÏνετ δεν λειτουÏγεί + Αδυναμία συνδεσης + Λήψη… + ΕφαÏμογή… + ΕφαÏμογή Λευκής και ΜαÏÏης λίστας + Ανάλυση και συγχώνευση αÏχείων hosts + ΔημιουÏγία αÏχείου hosts + ΕφαÏμογή αÏχείου hosts + Αποτυχία εφαÏμογής νέου hosts file. + Η εφαÏμογή του αÏχείου hosts στο σÏστημά σας απέτυχε! +ΠÏοσπαθήστε να αλλάξετε το αÏχείο Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï hosts στις Ïυθμίσεις σε /data/data/hosts. + ΕφαÏμογή απέτυχε + Ελέγξτε την εφαÏμογή διαχείÏισης Root για να διασφαλίσετε ότι έχει γίνει η Ï€Ïόσβαση σε Root. + ΕπαναφέÏατε το αÏχικό αÏχείο hosts. +Ίσως είναι απαÏαίτητο να επανεκκινήσετε το Android για να εφαÏμοστοÏν οι αλλαγές. +Θέλετε να κάνετε επανεκκίνηση; +(Για να αποφÏγετε απώλεια δεδομένων, επαληθεÏστε ότι καμία εφαÏμογή δεν χÏησιμοποιεί την κάÏτα SD αυτή την στιγμή!) + Επιτυχής επαναφοÏά + Δεν είναι δυνατή η επαναφοÏά του hosts file + Η επαναφοÏά απέτυχε λόγω μη γνωστής αιτίας + Η επαναφοÏά απέτυχε! + Καμία από τις ενεÏγοποιημένες πηγές hosts σας δεν είναι διαθέσιμη! Είστε συνδεδεμένοι στο Internet; + Το κατέβασμα απέτυχε + Αποτυχία εγγÏαφής νέου Î¹Î´Î¹Ï‰Ï„Î¹ÎºÎ¿Ï hosts file + Το Ï€Ïοσωπικό αÏχείο δεν μποÏεί να δημιουÏγηθεί. + Απέτυχε η δημιουÏγία Ï€ÏÎ¿ÏƒÏ‰Ï€Î¹ÎºÎ¿Ï Î±Ïχείου + Έχετε ενεÏγοποιήσει την λειτουÏγία systemless. \nΜποÏεί να χÏειαστεί επανεκκίνηση της συσκευής για να δουλέψει. \n\n(Για να αποφÏγετε απώλεια δεδομένων, επαληθεÏστε ότι καμία εφαÏμογή δεν χÏησιμοποιεί την κάÏτα SD αυτή την στιγμή!) + ΕνεÏγοποίηση επιτυχής + Έχετε απενεÏγοποιήσει την λειτουÏγία systemless. \nΜποÏεί να χÏειαστεί επανεκκίνηση της συσκευής για να δουλέψει. \n\n(Για να αποφÏγετε απώλεια δεδομένων, επαληθεÏστε ότι καμία εφαÏμογή δεν χÏησιμοποιεί την κάÏτα SD αυτή την στιγμή!) + ΑπενεÏγοποίηση επιτυχής + Αποτυχία ενεÏγοποίησης Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ VPN. + Αποτυχία απενεÏγοποίησης Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ VPN. + ΕνεÏγοποίηση hosts Magisk module + ΕνεÏγοποίηση δυνατότητας systemless hosts από το Magisk manager. Από τις Ïυθμίσεις του, ενεÏγοποιήστε την επιλογή Systemless hosts και στη συνέχεια επανεκκινήστε τη συσκευή σας. + ΑπενεÏγοποίηση hosts Magisk module + ΑπενεÏγοποίηση δυνατότητας systemless hosts από το Magisk manager. Από την λίστα στοιχείων, απεγκαταστήστε to Systemless hosts στοιχείο και στη συνέχεια επανεκκινήστε τη συσκευή σας. + + + Εισάγετε διεÏθυνση URL για το αÏχείο hosts: + Μη έγκυÏο όνομα διακομιστή! + Κακή μοÏφή ονόματος διακομιστή + Αυτή η διεÏθυνση IP δεν είναι έγκυÏη! + Κακή μοÏφή διεÏθυνσης IP + Îα μην γίνετε ποτέ επανεκκίνηση και να μην εμφανιστεί αυτή η εÏώτηση την επόμενη φοÏά! + ΦόÏτωση… + + + Ανανέωση + ΠÏοσθήκη + Βοήθεια + Εισαγωγή αντιγÏάφου ασφαλείας + Εξαγωγή αντιγÏάφου ασφαλείας + + + S-ON/S-OFF + Συχνές ΕÏωτήσεις + ΠÏοβλήματα + + + Κακόβουλο λογισμικό διαφημίσεων + Εδώ μποÏείτε να βÏείτε τα εγκατεστημένα κακόβουλα λογισμικά διαφημίσεων, εφαÏμογές τις οποίες το AdAway δεν μποÏεί να αποκλείσει. Αυτές οι εφαÏμογές χÏησιμοποιοÏν, για παÏάδειγμα, ειδοποιήσεις Airpush οι οποίες εμφανίζονται ακόμα και όταν οι κακόβουλες εφαÏμογές δεν εκτελοÏνται, ενώ μποÏοÏν ακόμα να αλλάξουν και τον ήχο κλήσης σας. Η μόνη διαθέσιμη μέθοδος αντιμετώπισής του είναι να τις απεγκαταστήσετε, κάνοντας κλικ στα πεÏιεχόμενα της λίστας. + ΣάÏωση… + Δεν βÏέθηκαν Adware! + + + ΦÏαγή διαφημίσεων + Δεν υπάÏχει εγκατεστημένος κειμενογÏάφος + Δεν ήταν δυνατή η εÏÏεση επεξεÏγαστή κειμένου για το άνοιγμα του αÏχείου hosts. ΜποÏείτε να εγκαταστήσετε το Jota ή άλλους επεξεÏγαστές κειμένου για τον χειÏισμό αυτοÏ. + +Θέλετε να εγκαταστήσετε το Jota; + Δεν υπάÏχει εγκατεστημένο Ï€ÏόγÏαμμα διαχείÏισης αÏχείων + Δεν βÏέθηκε διαχειÏιστής αÏχείων για το άνοιγμα αÏχείων. ΜποÏείτε να εγκαταστήσετε τον OI File Manager ή άλλους διαχειÏιστές αÏχείων για τον χειÏισμό αυτών. + +Θέλετε να εγκαταστήσετε τον OI File Manager; + + + Tcpdump + Το tcpdump είναι ένα εÏγαλείο για την παÏακολοÏθηση αιτήσεων DNS και την αποθήκευσή τους σε αÏχείο καταγÏαφών. ΜποÏείτε να το εκκινήσετε στο παÏασκήνιο, να εκτελέσετε εφαÏμογές που εμφανίζουν διαφημίσεις, και έπειτα να αναλÏσετε τις αιτήσεις DNS χÏησιμοποιώντας το αÏχείο αυτό. Ο πιθανός διακομιστής διαφημίσεων μποÏεί μετά να Ï€Ïοστεθεί στη μαÏÏη λίστα σας. + ΑπενεÏγοποίηση παÏακολοÏθησης + ΕνεÏγοποίηση παÏακολοÏθησης + Εμφάνιση αποτελεσμάτων + Ταξινόμηση τομέω + ΕκκαθάÏιση αÏχείου καταγÏαφής + ΠÏοσθήκη καταχώÏησης στη μαÏÏη λίστα + ΠÏοσθήκη καταχώÏησης στη λευκή λίστα + ΠÏοσθήκη καταχώÏησης στη λίστα ανακατεÏθυνσης + + ΕπεξεÏγασία της τιμής Ï€Ïοτιμήσεων κειμένου + Άνοιγμα Î¼ÎµÎ½Î¿Ï + Κλείσιμο Î¼ÎµÎ½Î¿Ï + + + + ΑÏχική + Πηγές Hosts + Οι λίστες σας + Άνοιγμα του αÏχείου hosts + ΕγγÏαφή αιτημάτων DNS + ΣάÏωση για adware + ΠÏοτιμήσεις + Βοήθεια + + + + + Αιτήματα DNS + Οι λίστες σας + ΠÏοτιμήσεις + + + Εγκαταστάθηκε %1$s Ï€Ïιν + ΕνήμεÏο εδώ και %1$s + Απαιτείται ενημέÏωηση εδώ και %1$s + Τελευταία ενημέÏωση Ï€Ïίν από %1$s + Άγνωστη κατάσταση ενημέÏωσης + ΑπενεÏγοποιημένο + λίγα λεπτά + + %d λεπτό + %d λεπτά + + + %d ÏŽÏα + %d ÏŽÏες + + + %d ημέÏα + %d ημέÏες + + + %d μήνα + %d μήνες + + + + Hosts αντιγÏάφηκε στο Ï€ÏόχειÏο + + + ξεκινάει + ενεÏγό + σταματάει + πεÏιμένετε για δίκτυο + επανασÏνδεση + σφάλμα επανασÏνδεσης + σε παÏση + σταμάτησε + Ad-blocker VPN %1$s + ΠαÏση + Συνέχεια + + + Δικαιώματα AdAway + ΕπιτÏέπει την αλληλεπίδÏαση με το AdAway + Αποστολή εντολών στο AdAway + Îα επιτÏέπεται η αποστολή εντολών στο AdAway όπως η ενεÏγοποίηση ή η απενεÏγοποίηση του Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ σε όλο το σÏστημα + + diff --git a/app/src/main/res/values-el/strings_app.xml b/app/src/main/res/values-el/strings_app.xml new file mode 100644 index 0000000..5c3da3e --- /dev/null +++ b/app/src/main/res/values-el/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Î‘Î½Î¿Î¹Ï‡Ï„Î¿Ï ÎšÏŽÎ´Î¹ÎºÎ± ΠÏόγÏαμμα Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ + AdAway logo + diff --git a/app/src/main/res/values-el/strings_errors.xml b/app/src/main/res/values-el/strings_errors.xml new file mode 100644 index 0000000..c4cdc07 --- /dev/null +++ b/app/src/main/res/values-el/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Δεν υπάÏχει σÏνδεση στο ίντεÏνετ + Δεν είναι δυνατή η σÏνδεση στο Διαδίκτυο. Ελέγξτε τη συνδεσιμότητα της συσκευής σας. + Αποτυχία λήψης πηγής hosts + Καμία από τις ενεÏγοποιημένες πηγές hosts σας δεν είναι Ï€Ïοσβάσιμη. Ελέγξτε ότι είστε σωστά συνδεδεμένοι στο Διαδίκτυο. + + Αποτυχία δημιουÏγίας Î¹Î´Î¹Ï‰Ï„Î¹ÎºÎ¿Ï Î±Ïχείου + Δεν είναι δυνατή η δημιουÏγία ενός Î¹Î´Î¹Ï‰Ï„Î¹ÎºÎ¿Ï Î±Ïχείου για τη δημιουÏγία μιας νέας πηγής hosts. Ελέγξτε τον διαθέσιμο χώÏο στη συσκευή σας. + Δεν υπάÏχει διαθέσιμος χώÏος + Δεν είναι δυνατή η αντιγÏαφή του αÏχείου hosts στο partition του συστήματός σας. Ελέγξτε ότι το Magisk systemless module είναι ενεÏγοποιημένο και στη συνέχεια κάντε επανεκκίνηση. + Αποτυχία εγκατάστασης νέου αÏχείου hosts + Δεν είναι δυνατή η αντιγÏαφή του αÏχείου hosts στο διαμέÏισμα /system. Ελέγξτε ότι το Magisk systemless module είναι ενεÏγοποιημένο και, στη συνέχεια, κάντε επανεκκίνηση. + Αποτυχία επαναφοÏάς αÏχείου hosts + Δεν είναι δυνατή η επαναφοÏά της Ï€Ïοεπιλεγμένης διαμόÏφωσης αÏχείου hosts. + + Αποτυχία ενεÏγοποίησης Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ VPN. + Ελέγξτε τις Ïυθμίσεις VPN για να εξουσιοδοτήσετε την εφαÏμογή VPN να ξεκινήσει. + Αποτυχία απενεÏγοποίησης Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ VPN. + Ελέγξτε τις Ïυθμίσεις VPN για να το απενεÏγοποιήσετε χειÏοκίνητα. + diff --git a/app/src/main/res/values-el/strings_home.xml b/app/src/main/res/values-el/strings_home.xml new file mode 100644 index 0000000..cd65142 --- /dev/null +++ b/app/src/main/res/values-el/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Αποκλείστηκε + ΕπιτÏάπηκε + ΑνακατευθÏνθηκε + + + + %d up-to-date source + %d ενημεÏωμένες πηγές + + + %d outdated source + %d ξεπεÏασμένες πηγές + + Έλεγχος για ενημεÏώσεις αÏχείου hosts + ΕνημέÏωση του αÏχείου hosts + + + Εμφάνιση αÏχείου καταγÏαφής αιτήσεων DNS + + + Εμφάνιση βοήθειας\nκαι συμβουλών + + + Ανοίξτε τη σελίδα GitHub + + + ΥποστήÏιξη το project + + + GitHub project + ΠÏοτιμήσεις + + + Ανοίξτε το συÏτάÏι πλοήγησης + ΠαÏση/συνέχιση Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ + ΕνημέÏωση αποκλεισμένων domains + Εμφάνιση ζητημένων domains + + + ΠαÏακαλοÏμε ανατÏέξτε στην Βοήθεια για πεÏισσότεÏες πληÏοφοÏίες + + \ No newline at end of file diff --git a/app/src/main/res/values-el/strings_hosts.xml b/app/src/main/res/values-el/strings_hosts.xml new file mode 100644 index 0000000..1867407 --- /dev/null +++ b/app/src/main/res/values-el/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Πηγές Hosts + + Λίστα χÏηστών + Επίσημοι πάÏοχοι AdAway + Ενοποιημένοι πάÏοχοι StevenBlack + ΠάÏοχοι λίστας κλειδώματος Pete Lowe + + δεν είναι διαθέσιμο + %s πάÏοχοι + + ΠÏοσθήκη πηγής + ΕπεξεÏγασία πηγής + URL: (a https:// or file:// resource) + Το πηγαίο URL του αÏχείου hosts + diff --git a/app/src/main/res/values-el/strings_lists.xml b/app/src/main/res/values-el/strings_lists.xml new file mode 100644 index 0000000..0cb0437 --- /dev/null +++ b/app/src/main/res/values-el/strings_lists.xml @@ -0,0 +1,24 @@ + + + Οι λίστες σας + ΠÏοσθήκη host + + Αποκλείστηκε + ΕπιτÏάπηκε + ΑνακατευθÏνθηκε + + ΦίλτÏο hosts + Αναζήτηση hostname… + Τoogle πηγών + + ΠÏόσθεση host στη μαÏÏη λίστα + ΠÏόσθεση host σε λευκή λίστα + ΠÏόσθεση host σε ανακατεÏθυνση + ΕπεξεÏγασία μαÏÏης λίστας host + ΕπεξεÏγασία λευκής λίστας host + ΕπεξεÏγασία ανακατευθÏνσεων + Όνομα: + Το πηγαίο URL του αÏχείου hosts + (ΕπιτÏέπονται οι χαÏακτήÏες Î¼Ï€Î±Î»Î±Î½Ï„Î­Ï * και ?) + IP (IPv4 ή IPv6): + diff --git a/app/src/main/res/values-el/strings_log.xml b/app/src/main/res/values-el/strings_log.xml new file mode 100644 index 0000000..ec16d97 --- /dev/null +++ b/app/src/main/res/values-el/strings_log.xml @@ -0,0 +1,11 @@ + + + Εναλλαγή καταγÏαφής αÏχείου εγγÏαφής + Πατήστε εγγÏαφή για να ξεκινήσετε την καταγÏαφή αιτημάτων, να πεÏιηγηθείτε στον Ιστό ή να χÏησιμοποιήσετε εφαÏμογές και, στη συνέχεια, επιστÏέψτε ή σÏÏετε για να ανανεώσετε τα αÏχεία καταγÏαφής. + \n\nΤα αποκλεισμένα αιτήματα δεν θα καταγÏάφονται. ΑπενεÏγοποιήστε Ï€Ïώτα τον αποκλεισμό διαφημίσεων εάν θέλετε να τα καταγÏάψετε επίσης. + + Ταξινόμηση αλφαβητικά + Ταξινόμηση κατά τομέα ανώτατου επιπέδου + + Τομέας ανακατεÏθυνσης + diff --git a/app/src/main/res/values-el/strings_notification.xml b/app/src/main/res/values-el/strings_notification.xml new file mode 100644 index 0000000..5508232 --- /dev/null +++ b/app/src/main/res/values-el/strings_notification.xml @@ -0,0 +1,13 @@ + + + + ΕνημεÏώσεις + Îέες ειδοποιήσεις ενημέÏωσης + Διαθέσιμη ενημέÏωση πηγής + ÎεότεÏα hosts files διαθέσιμα για λήψη. + ΕνημέÏωση εφαÏμογής διαθέσιμη + Μια νέα έκδοση του AdAway είναι διαθέσιμη για λήψη. + + VPN + Το VPN εκτελεί ειδοποιήσεις + \ No newline at end of file diff --git a/app/src/main/res/values-el/strings_prefs_backup_restore.xml b/app/src/main/res/values-el/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..864403c --- /dev/null +++ b/app/src/main/res/values-el/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + ΑντίγÏαφο ασφαλείας & επαναφοÏά + ΑντίγÏαφο ασφαλείας + ΑντίγÏαφο ασφαλείας σε εξωτεÏικό χώÏο αποθήκευσης τους κανόνες Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï ÏƒÎ±Ï‚ + ΕπαναφοÏά + ΕπαναφέÏετε τους κανόνες Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î±Ï€ÏŒ το εφεδÏικό αÏχείο + diff --git a/app/src/main/res/values-el/strings_prefs_main.xml b/app/src/main/res/values-el/strings_prefs_main.xml new file mode 100644 index 0000000..3103063 --- /dev/null +++ b/app/src/main/res/values-el/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Επιλογές + + Γενικά + Σκοτεινό θέμα + + Φωτεινό + Σκοτεινό + ΠÏοεπιλογή συστήματος + + Αυτόματες ενημεÏώσεις + + Αποκλεισμός διαφημίσεων + Αποκλεισμός διαφημίσεων βάσει Root + Αποκλεισμός διαφημίσεων βάσει VPN + ΕνεÏγοποίηση υποστήÏιξης IPv6 + Κανόνες Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î‘Î½Ï„Î¹Î³Ïάφων ασφαλείας / επαναφοÏάς + + Αποσφαλμάτωση + Αποστολή αναφοÏών σφαλμάτων + ΑναφοÏά στο Sentry (sentry.io) + Δεν υποστηÏίζεται σε αυτήν την έκδοση + Αναλυτική καταγÏαφή + Απαιτείται επανεκκίνηση εφαÏμογής για εφαÏμογή + diff --git a/app/src/main/res/values-el/strings_prefs_root.xml b/app/src/main/res/values-el/strings_prefs_root.xml new file mode 100644 index 0000000..521a2b1 --- /dev/null +++ b/app/src/main/res/values-el/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Αποκλεισμός διαφημίσεων βάσει Root + + Hosts εγκατάσταση + Άνοιγμα του αÏχείου hosts + ΑÏχείο hosts Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï + ΠÏιν μεταβάλετε αυτή την ÏÏθμιση, διαβάστε την Βοήθεια σχετικά με αυτή την λειτουÏγικότητα. + + /system/etc/hosts + /data/hosts + /data/data/hosts + ΠαÏαμετÏοποιημένος Ï€ÏοοÏισμός + + ΠαÏαμετÏοποιημένος Ï€ÏοοÏισμός + ΑπόκÏυψη διαλόγου επανεκκίνησης + + ΑνακατεÏθυνση + ΟÏίστε Ï€Î¿Ï Î¸Î± ανακατευθÏνετε αποκλεισμένα hosts + ΑνακατεÏθυνση IPv4 + ΑνακατεÏθυνση IPv6 + Μη έγκυÏη ανακατεÏθυνση + + Τοπικός διακομιστής ιστοσελίδων + Ο τοπικός διακομιστής Î¹ÏƒÏ„Î¿Ï Î±ÎºÎ¿Ïει τοπικές διευθÏνσεις IP για να απαντήσει σε αποκλεισμένες αιτήσεις hostsname. ΜποÏεί να βοηθήσει στην κατάψυξη εφαÏμογών σε αποκλεισμένη σÏνδεση. + ΕνεÏγοποίηση του διακομιστή ιστοσελίδων + Δοκιμή σέÏÎ²ÎµÏ + Εγκατάσταση αυτο-υπογÏαφόμενου Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï + ΧειÏοκίνητη εγκατάσταση Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï + Ξεκινώντας από το Android 11 (R), η εφαÏμογή δεν μποÏεί πλέον να εγκαταστήσει αυτόματα την αÏχή έκδοσης πιστοποιητικών (CA).\n\nΜεταβείτε στις Ïυθμίσεις \"Ασφάλεια\", \"ΚÏυπτογÏάφηση & διαπιστευτήÏια\" και στη συνέχεια, \"Εγκαταστήστε ένα πιστοποιητικό\". Από εκεί, επιλέξτε \"Πιστοποιητικό CA\" και επιλέξτε το αÏχείο Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Ï€Î¿Ï… εξήχθη Ï€Ïόσφατα. + Ανοίξτε τις Ïυθμίσεις \"Ασφάλεια\" + Ελεγχος… + Δεν εκτελείται + Εκτελείται αλλα το πιστοποιητικό δεν έχει εγκατασταθεί + Εκτελείται και το πιστοποιητικό έχει εγκατασταθεί + Αντικατάσταση ÎºÎµÎ½Î¿Ï Ï‡ÏŽÏου διαφημίσεων απο το εικονίδιο της εφαÏμογής + diff --git a/app/src/main/res/values-el/strings_prefs_update.xml b/app/src/main/res/values-el/strings_prefs_update.xml new file mode 100644 index 0000000..daf3fa5 --- /dev/null +++ b/app/src/main/res/values-el/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + ΕνημεÏώσεις + Οι ειδοποιήσεις είναι απενεÏγοποιημένες + Οι ειδοποιήσεις εφαÏμογών δεν θα εμφανίζονται. Πατήστε για να τις ενεÏγοποιήσετε. + + ΕνημεÏώσεις εφαÏμογής + Έλεγχος για ενημέÏωση κατά την εκκίνηση + ΗμεÏήσιος έλεγχος για ενημεÏώσεις + ΣυμπεÏιλάβετε εκδόσεις beta + + ΕνημεÏώσεις Hosts + Έλεγχος για ενημέÏωση κατά την εκκίνηση + ΗμεÏήσιος έλεγχος για ενημεÏώσεις + ΣυγχÏονισμός κατά την ενημέÏωση + ΣυγχÏονισμός μόνο σε δίκτυο χωÏίς μέτÏηση + diff --git a/app/src/main/res/values-el/strings_prefs_vpn.xml b/app/src/main/res/values-el/strings_prefs_vpn.xml new file mode 100644 index 0000000..e221243 --- /dev/null +++ b/app/src/main/res/values-el/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Αποκλεισμός διαφημίσεων βάσει VPN + + ΕνεÏγοποίηση κατά την εκκίνηση + ΠαÏακολοÏθηση σÏνδεσης + Ελέγχετε πεÏιοδικά την κατάσταση δικτÏου για επανεκκίνηση του VPN κατά την αποσÏνδεση. + + ΕξαιÏοÏμενες εφαÏμογές + ΔιαμοÏφώστε ποιες εφαÏμογές δεν Ï€Ïέπει να χÏησιμοποιοÏν το VPN, ώστε να μην αποκλείονται συνδέσεις. + ΕξαίÏεση εφαÏμογών συστήματος + + None + All except browsers + All + + ΕξαίÏεση εφαÏμογών χÏήστη + + + ΕξαιÏοÏμενες εφαÏμογές + Επιλογή όλων + Αποεπιλογή όλων + Εικονίδιο εφαÏμογής + diff --git a/app/src/main/res/values-el/strings_source_edit.xml b/app/src/main/res/values-el/strings_source_edit.xml new file mode 100644 index 0000000..9dd5efd --- /dev/null +++ b/app/src/main/res/values-el/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + ΕπεξεÏγασία πηγής + ΠÏοσθήκη πηγής + + Ετικέτα + Απαιτείται ετικέτα + ΤÏπος + URL + ΑÏχείο + Τοποθεσία + https:// + Απαιτείται τοποθεσία + Πατήστε ΑÏχείο για να επιλέξετε πηγαίο αÏχείο + Μη έγκυÏη τοποθεσία + ΜοÏφή λίστας + Αποκλεισμός + Îα επιτÏέπεται + ΕφαÏμογή ανακατευθυνόμενων hosts + Η αποδοχή ανακατευθυνόμενων hosts μποÏεί να Ï€Ïοκαλέσει Ï€Ïοβλήματα ασφαλείας. ΧÏησιμοποιήστε αυτές τις Ïυθμίσεις μόνο σε μια αξιόπιστη πηγή, καθώς θα μποÏοÏσε να ανακατευθÏνει κάποια ευαίσθητη κίνηση σε όποιον διακομιστή θέλει. + diff --git a/app/src/main/res/values-el/strings_support.xml b/app/src/main/res/values-el/strings_support.xml new file mode 100644 index 0000000..2d68f3c --- /dev/null +++ b/app/src/main/res/values-el/strings_support.xml @@ -0,0 +1,5 @@ + + + ΥποστήÏιξη + Γίνε χοÏηγός + \ No newline at end of file diff --git a/app/src/main/res/values-el/strings_update.xml b/app/src/main/res/values-el/strings_update.xml new file mode 100644 index 0000000..02c8a0e --- /dev/null +++ b/app/src/main/res/values-el/strings_update.xml @@ -0,0 +1,21 @@ + + + ΕνημέÏωση AdAway + + Διαθέσιμη ενημέÏωση! + + + Είστε ενημεÏωμένοι + ΥπάÏχει διαθέσιμη ενημέÏωση + Το AdAway ενημεÏώνεται + ΕνημέÏωση τώÏα + %1$s / %2$s + Τελευταίες αλλαγές + ΚαταγÏαφή αλλαγών + ΥποστήÏιξη ανάπτυξης + ΔωÏίστε + Sponsor + + + Λήψη της τελευταίας έκδοσης AdAway… + diff --git a/app/src/main/res/values-el/strings_welcome.xml b/app/src/main/res/values-el/strings_welcome.xml new file mode 100644 index 0000000..4b72b3c --- /dev/null +++ b/app/src/main/res/values-el/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Καλώς ήÏθατε + Wizard Ï€Ïώτο βήμα + Wizard δεÏτεÏο βήμα + Wizard τελευταίο βήμα + + + Καλώς ήλθατε στο AdAway! + Το AdAway παÏέχει δÏο μεθόδους Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½. Διαλέξτε αυτή που σας αÏέσει: + + Λογότυπο Root + Root based\nad blocking + ΓÏηγοÏότεÏo + Φιλικό Ï€Ïος την μπαταÏία + Απαιτείται Root + + Λογότυπο VPN + VPN based\nad blocking + Πιο αÏγό + Εκτελείτε στο παÏασκήνιο + Συμβατότητα + + Απαιτείται Android με Root + Είτε το su binary δεν βÏέθηκε είτε δεν επιτÏάψατε την άδεια root στο AdAway.\n\nΑυτό μποÏεί να συμβεί όταν η συσκευή σας δεν είναι rooted. ΜποÏείτε να βÏείτε πληÏοφοÏίες σχετικά με το πως how να rootάÏετε τη συσκευή σας στο wiki.lineageos.org ή σε άλλα Android websites. + + Πλεονεκτήματα + Μειονεκτήματα + + + Ο συγχÏονισμός ολοκληÏώθηκε + Σφάλμα κατά τον συγχÏονισμό + + ΣυγχÏονισμός + ΣυγχÏονίστηκε! + Το AdAway κατεβάζει δίκτυα διαφημίσεων για αποκλεισμό από διαδικτυακές πηγές. ΜποÏείτε να τα Ï€ÏοσαÏμόσετε αÏγότεÏα στις Ïυθμίσεις. + Επανάληψη συγχÏÎ¿Î½Î¹ÏƒÎ¼Î¿Ï + Αποτυχία συγχÏονισμοÏ: %1$s Επανάληψη τώÏα; + ΜποÏεί να στείλει ειδοποιήσεις για Ï€Ïοβολή της κατάστασης και έλεγχο του μπλοκαÏίσματος διαφημίσεων και να σας ειδοποιήσει εάν υπάÏξει διαθέσιμη ενημέÏωση εφαÏμογής (λίγες ανά έτος). ΕνεÏγοποιήστε το εάν θέλετε να παÏαμείνετε ενημεÏωμένοι. + + + ΥποστήÏιξη + ΥποστήÏιξε με! + Το AdAway είναι μια δωÏεάν και Î±Î½Î¿Î¹Ï‡Ï„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± εφαÏμογή την οποία αναπτÏσσω στον ελεÏθεÏο χÏόνο μου. Εάν την απολαμβάνετε, μη διστάσετε να δείξετε την υποστήÏιξή σας: + ΔωÏεά στο PayPal + Σας αÏέσουν τα bugs; ΟÏτε εμένα. + ΕνεÏγοποιήστε την τηλεμετÏία για να μου στέλνετε αναφοÏές σφαλμάτων + + + Πίσω + Επόμενο + Τέλος + diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml new file mode 100644 index 0000000..3e34fb7 --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -0,0 +1,258 @@ + + + + Exit + Close + Yes + No + Add + Cancel + Save + Help + + + Welcome! + AdAway is a free and open-source software design to block advertising. It fetches advertising network addresses to block them on your device.\nWant to know more? Check the help below! + Show more help + Update status + All hosts files from the defined sources are downloaded, merged with your own lists and installed as one hosts file on your system. + Enable ad-blocking + Disable ad-blocking + Web server + Running + Stopped + Start or stop webserver on localhost to answer requests to blocked hostnames. + Enable web server + Disable web server + VPN + Running + Stopped + Start or stop VPN to filter requests. + Enable VPN + Disable VPN + + + Edit Entry + Apply + Edit + Delete + + + Importing… + Backup successfully imported from your external storage. + Failed to import backup. Is its format correct? Check logcat for more details. + Exporting… + Backup successfully exported to file \'%s\' on your external storage. + Failed to export backup file \'%s\'. + + + The hosts file + The hosts file is a system file that maps hostnames to IP addresses. It is a plain text file which configuration is handled by AdAway. Here are its few first lines: + Loading the hosts file content… + Open the hosts file + + + Checking for update + Checking %s source for update + Retrieving sources + Downloading source %s + Reading source %s + Parsing %s source + Syncing rule database + Reverting to default hosts file + Default hosts file restored + Creating standard hosts file + Source update available + Newer hosts files available + No source update found + No Internet connection + No Internet connection available + Unavailable sources + No hosts sources are reachable! + Root access denied + Allow root access from your root app + Something went wrong + Check the logcat for more details + Enabled + Newest hosts files enabled + Disabled + Default hosts file installed + Apply latest sources + Creating a new hosts file + Copying a new hosts file + Checking hosts file copy + Hosts file successfully updated + VPN configuration successfully updated + Your configuration changed. You need to apply it. + Apply + Applying new configuration… + Failed to apply new configuration. + + + The symlink to the hosts file target is missing + Symlink from your target to /system/etc/hosts is not existing or incorrect! AdAway will not work if it is not pointing to the right file.\n\nDo you want to try creating a symlink? + Symlink missing + Not enough space on the partition!\nTry changing the target hosts file in preferences to /data/data/hosts. + Not enough space + Downloaded file could not be read. + Private file fail + Remounting the partition as read/write failed! + Remount failed + Failed to copy hosts file + Copying of hosts file failed! + Copy failed + Applied hosts sources + Applying successful + Applying was successful.\nIt may be necessary to reboot Android for the changes to take effect.\n\nDo you want to reboot?\n(To prevent data loss make sure no app uses the SD card at the moment!) + Symlink was created successful.\nIt may be necessary to reboot Android for the changes to take effect.\n\nDo you want to reboot?\n(To prevent data loss make sure no app uses the SD card at the moment!) + Symlink creation successful + Symlink could not be created by Android.\nThis fails mostly due to a \'feature\' called S-ON on HTC phones!\n\nA solution is to boot your phone into recovery mode and create the symlink there with \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nIf this does not work search the Internet for S-OFF and your phone. + Symlink creation failed + Please read Help for more information. + An APN proxy is set on your Android!\nAdAway will not work reliably when on Mobile Networks like 3G. You can deactivate that proxy by going to your selected APN (From the Settings app: Network & Internet -> Mobile network -> Advanced -> Access Point Names) and remove the value in the proxy field. + APN proxy set! + The connection to the Internet is not working. + No Connection + Downloading… + Applying… + Applying Blacklist and Whitelist + Parsing and merging hosts files + Building hosts file + Applying hosts file + Failed to apply new hosts file. + Applying the hosts file to your system failed!\nTry changing the target hosts file in preferences to /data/data/hosts. + Applying failed + Please check your root management app to ensure root access has been granted. + You reverted to the default hosts file.\nIt may be necessary to reboot Android for the changes to take effect.\n\nDo you want to reboot?\n(To prevent data loss make sure no app uses the SD card at the moment!) + Reverting successful + Unable to revert hosts file + Reverting failed due to unknown reasons. + Reverting failed! + None of your enabled hosts sources are reachable! Are you properly connected to the Internet? + Download failed + Failed to write new private hosts file + Private file can not be created. + Private file creation failed + You enabled systemless mode.\nIt may be necessary to reboot Android for the changes to take effect.\n\nDo you want to reboot?\n(To prevent data loss make sure no app uses the SD card at the moment!) + Enabling successful + You disabled systemless mode.\nIt may be necessary to reboot Android for the changes to take effect.\n\nDo you want to reboot?\n(To prevent data loss make sure no app uses the SD card at the moment!) + Disabling successful + Failed to enable VPN ad blocking. + Failed to disable VPN ad blocking. + Enabling hosts Magisk module + Enable systemless hosts feature from Magisk manager. From its settings, enable the Systemless hosts option then reboot your device. + Disabling hosts Magisk module + Disable systemless hosts feature from Magisk manager. From the module list, uninstall the Systemless hosts module then reboot your device. + + + Input URL to hosts file: + This is not a valid hostname! + Improperly formatted hostname + This is not a valid IP! + Improperly formatted IP + Never reboot and don\'t show this question next time! + Loading… + + + Refresh + Add + Help + Import backup + Export backup + + + S-ON/S-OFF + FAQ + Problems + + + Adware + Here you can find installed adware, bad applications which can\'t be blocked by AdAway. These apps use for example Airpush notifications that pop up even when the app is not running or even change your ringtone. The only available countermeasure is to uninstall those apps by clicking on the list items. + Scanning… + No Adware were found! + + + Ad blocker + No text editor installed + No text editor could be found to open the hosts file. You can install Jota or other text editors to handle this.\n\nDo you want to install Jota? + No file manager installed + No file manager could be found to open files. You can install OI File Manager or other file managers to handle this.\n\nDo you want to install OI File Manager? + + + Tcpdump + Tcpdump is a tool to monitor DNS requests and save them in a log file. You can start it in the background, run applications that display ads, and afterwards analyze the DNS requests using the log file. Possible ad server can then be added to your blacklist. + Disable monitoring + Enable monitoring + Show results + Sort domains + Clear log + Add entry to black list + Add entry to white list + Add entry to redirect list + + Edit text preference value + Open menu + Close menu + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + + + + DNS requests + Your lists + Preferences + + + Installed %1$s ago + Up-to-date for %1$s + Need update for %1$s + Last update %1$s ago + Unknown update status + few minutes + + %d minute + %d minutes + + + %d hour + %d hours + + + %d day + %d days + + + %d month + %d months + + + + starting + active + stopping + wait for network + reconnecting + reconnecting error + paused + stopped + Ad-blocker VPN %1$s + Pause + Resume + + + AdAway permissions + Allow to interact with AdAway + Send commands to AdAway + Allow to send commands to AdAway like enabling or disabling the system-wide ad-blocking + + diff --git a/app/src/main/res/values-en-rUS/strings_app.xml b/app/src/main/res/values-en-rUS/strings_app.xml new file mode 100644 index 0000000..af6a933 --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Open Source ad blocker + AdAway logo + diff --git a/app/src/main/res/values-en-rUS/strings_errors.xml b/app/src/main/res/values-en-rUS/strings_errors.xml new file mode 100644 index 0000000..da703ab --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_errors.xml @@ -0,0 +1,22 @@ + + + + No Internet connection + Unable to establish a connection to the Internet. Please check your device connectivity. + Failed to download hosts source + None of your enabled hosts sources are reachable. Please check you are properly connected to the Internet. + + Failed to create private file + Unable to create a private file to build a new hosts source. Please check the free space available on your device. + Not enough space + Unable to copy hosts file to your system partition. Please check Magisk systemless module is enabled then reboot. + Failed to install new hosts file + Unable to copy hosts file to /system partition. Please check Magisk systemless module is enabled then reboot. + Failed to revert hosts file + Unable to restore default hosts file configuration. + + Failed to enable VPN ad blocking. + Please check your VPN settings to authorize the application VPN to start. + Failed to disable VPN ad blocking. + Please check your VPN settings to disable it manually. + diff --git a/app/src/main/res/values-en-rUS/strings_home.xml b/app/src/main/res/values-en-rUS/strings_home.xml new file mode 100644 index 0000000..d4feb49 --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Blocked + Allowed + Redirected + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + Check for hosts updates + Update hosts + + + Show DNS request log + + + Show help\nand tips + + + Open GitHub page + + + Support the project + + + GitHub project + Preferences + + + Open navigation drawer + Pause/resume ad blocking + Update blocked domains + Show requested domains + + + Please read Help for more information. + + \ No newline at end of file diff --git a/app/src/main/res/values-en-rUS/strings_hosts.xml b/app/src/main/res/values-en-rUS/strings_hosts.xml new file mode 100644 index 0000000..9708f7a --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Hosts sources + + User list + AdAway official hosts + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + not available + %s hosts + + Add source + Edit source + URL: (a https:// or file:// resource) + The hosts source URL + diff --git a/app/src/main/res/values-en-rUS/strings_lists.xml b/app/src/main/res/values-en-rUS/strings_lists.xml new file mode 100644 index 0000000..112a0d0 --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_lists.xml @@ -0,0 +1,23 @@ + + + Your lists + + Blocked + Allowed + Redirected + + Filter hosts + Search hostname… + Toggle sources + + Add host to blacklist + Add host to whitelist + Add host redirect + Edit blacklisted host + Edit whitelisted host + Edit redirect + Hostname: + The hosts source URL + (Wildcard characters * and ? are allowed) + IP (IPv4 or IPv6): + diff --git a/app/src/main/res/values-en-rUS/strings_log.xml b/app/src/main/res/values-en-rUS/strings_log.xml new file mode 100644 index 0000000..88ceda5 --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_log.xml @@ -0,0 +1,8 @@ + + + + Alphabetical sort + Top level domain sort + + Redirect domain + diff --git a/app/src/main/res/values-en-rUS/strings_notification.xml b/app/src/main/res/values-en-rUS/strings_notification.xml new file mode 100644 index 0000000..46c6770 --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Updates + New update notifications + Source update available + Newer hosts files available for download. + App update available + A new version of AdAway is available for download. + + VPN + VPN running notifications + \ No newline at end of file diff --git a/app/src/main/res/values-en-rUS/strings_prefs_backup_restore.xml b/app/src/main/res/values-en-rUS/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..910b88b --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Backup & restore + Backup + Backup to external storage your block rules + Restore + Restore your block rules from backup file + diff --git a/app/src/main/res/values-en-rUS/strings_prefs_main.xml b/app/src/main/res/values-en-rUS/strings_prefs_main.xml new file mode 100644 index 0000000..ac8940e --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Preferences + + General + Dark theme + + Light + Dark + System default + + Automatic updates + + Ad blocking + Root based ad blocker + VPN based ad blocker + Enable IPv6 support + Backup / restore block rules + + Debug + Send crash reports + Report to Sentry (sentry.io) + Not supported on this build + Verbose logging + App restart is needed to apply + diff --git a/app/src/main/res/values-en-rUS/strings_prefs_root.xml b/app/src/main/res/values-en-rUS/strings_prefs_root.xml new file mode 100644 index 0000000..0f3ceaa --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Root based ad blocker + + Hosts install + Open hosts file + Target hosts file + Read Help before using this feature + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + Custom target location + Hide reboot dialog after apply + + Redirection + Define where to redirect blocked hosts + Configure IPv4 redirection + Configure IPv6 redirection + Invalid redirection + + Local web server + The local web server listens on local IP addresses to answer to blocked hostname requests. It may help with app freezing on blocked connection. + Enable web server + Test web server + Install self-signed certificate + Certificate manual install + Starting from Android 11 (R), application can no more automatically install certificate authority (CA).\n\nGo to \"Security\" settings, \"Encryption & credentials\" then \"Install a certificate\". From there, choose \"CA certificate\" and select the newly exported certificate file. + Open "Security" settings + Checking… + Not running + Running but certificate not installed + Running and certificate installed + Replace blank ad space by app icon + diff --git a/app/src/main/res/values-en-rUS/strings_prefs_update.xml b/app/src/main/res/values-en-rUS/strings_prefs_update.xml new file mode 100644 index 0000000..d58435a --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + Updates + + Application updates + Check for update at startup + Periodically check for update + Include beta releases + + Hosts updates + Check for update at startup + Periodically check for update + Sync on update + Sync on unmetered network only + diff --git a/app/src/main/res/values-en-rUS/strings_prefs_vpn.xml b/app/src/main/res/values-en-rUS/strings_prefs_vpn.xml new file mode 100644 index 0000000..43102a4 --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN based ad blocker + + Enable at startup + Monitor connection + Periodically check the network state to restart VPN on disconnection. + + Excluded applications + Configure which applications should not use the VPN so no connections will be blocked. + Exclude system applications + + None + All except browsers + All + + Exclude user applications + + + Excluded applications + Select all + Deselect all + Application icon + diff --git a/app/src/main/res/values-en-rUS/strings_support.xml b/app/src/main/res/values-en-rUS/strings_support.xml new file mode 100644 index 0000000..308ebf9 --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_support.xml @@ -0,0 +1,5 @@ + + + Support + Become a sponsor + \ No newline at end of file diff --git a/app/src/main/res/values-en-rUS/strings_update.xml b/app/src/main/res/values-en-rUS/strings_update.xml new file mode 100644 index 0000000..6cefde8 --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_update.xml @@ -0,0 +1,18 @@ + + + AdAway update + + Update available! + + + You are up-to-date + Update available + Updating AdAway + Update now + %1$s / %2$s + Last changes + Changelog + + + Downloading latest AdAway version… + diff --git a/app/src/main/res/values-en-rUS/strings_welcome.xml b/app/src/main/res/values-en-rUS/strings_welcome.xml new file mode 100644 index 0000000..42ba60a --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings_welcome.xml @@ -0,0 +1,52 @@ + + + Welcome + Wizard first step + Wizard second step + Wizard last step + + + Welcome to AdAway! + AdAway provides two ad blocking methods. Pick the one you like: + + Root logo + Root based\nad blocking + Faster + Battery friendly + Root required + + VPN logo + VPN based\nad blocking + Slower + Run in background + Compatibility + + Rooted Android required + Either the su binary could not be found or you did not allow root permission for AdAway.\n\nThis can happen when your device is not rooted. You can find information about how to root your device on wiki.lineageos.org or other Android websites. + + Pro + Con + + + Sync done + Error during sync + + Syncing + Synced! + AdAway downloads ad networks to block from online sources. You can customize them later in the settings. + Retry sync + Failed to sync: %1$s Retry now? + + + Support + Support me! + AdAway is a free and open-source app that I develop on my free time. If you enjoy it, feel free to show your support: + Donate on PayPal + Do you like bugs? Me neither. + Enable telemetry to send me crash reports + + + Back + Next + Finish + diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml new file mode 100644 index 0000000..b4c7ab4 --- /dev/null +++ b/app/src/main/res/values-eo/strings.xml @@ -0,0 +1,17 @@ + + + + Eliro + Oftaj demandoj + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-eo/strings_app.xml b/app/src/main/res/values-eo/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-eo/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-eo/strings_errors.xml b/app/src/main/res/values-eo/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-eo/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-eo/strings_home.xml b/app/src/main/res/values-eo/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-eo/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-eo/strings_hosts.xml b/app/src/main/res/values-eo/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-eo/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-eo/strings_lists.xml b/app/src/main/res/values-eo/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-eo/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-eo/strings_log.xml b/app/src/main/res/values-eo/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-eo/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-eo/strings_notification.xml b/app/src/main/res/values-eo/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-eo/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-eo/strings_prefs_backup_restore.xml b/app/src/main/res/values-eo/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-eo/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-eo/strings_prefs_main.xml b/app/src/main/res/values-eo/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-eo/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-eo/strings_prefs_root.xml b/app/src/main/res/values-eo/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-eo/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-eo/strings_prefs_update.xml b/app/src/main/res/values-eo/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-eo/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-eo/strings_prefs_vpn.xml b/app/src/main/res/values-eo/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-eo/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-eo/strings_support.xml b/app/src/main/res/values-eo/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-eo/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-eo/strings_update.xml b/app/src/main/res/values-eo/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-eo/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-eo/strings_welcome.xml b/app/src/main/res/values-eo/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-eo/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml new file mode 100644 index 0000000..95d8cc2 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings.xml @@ -0,0 +1,266 @@ + + + + Salir + Cerrar + Sí + No + Agregar + Cancelar + Guardar + Ayuda + + + Te damos la bienvenida + AdAway es un software gratuito y de código abierto diseñado para bloquear los anuncios. Para ello, recupera las direcciones de red de los anuncios y los bloquea en el dispositivo.\nPara obtener más información, consulta la ayuda más abajo. + Mostrar más ayuda + Actualizar estado + Se descargarán todos los archivos hosts de las fuentes definidas, se combinarán con las listas propias y se instalarán como un solo archivo hosts en el sistema. + Habilitar bloqueo de anuncios + Inhabilitar bloqueo de anuncios + Servidor web + En funcionamiento + Detenido + Iniciar o detener un servidor web en el host local para responder las solicitudes a los nombres de host bloqueados. + Habilitar servidor web + Inhabilitar servidor web + VPN + En ejecución + Detenido + Iniciar o detener la VPN para filtrar las solicitudes. + Habilitar la VPN + Inhabilitar la VPN + + + Editar entrada + Aplicar + Editar + Borrar + + + Importando… + Se importó correctamente la copia de seguridad del almacenamiento externo. + No se pudo importar la copia de seguridad. Asegúrate de que el formato sea correcto. Revisa el registro de logcat para obtener más detalles. + Exportando… + Copia de seguridad exportada con éxito a un archivo \'%s\' en su almacenamiento externo. + No se ha podido exportar el archivo de copia de seguridad \'%s\'. + + + El archivo hosts + El archivo hosts es un archivo del sistema que permite asignar los nombres de hosts a las direcciones IP. Es un archivo de texto sin formato cuya configuración administra AdAway. Estas son sus primeras líneas: + Cargando el contenido del archivo hosts… + Abrir el archivo hosts + + + Buscando actualizaciones + Buscando actualizaciones en la fuente %s + Recuperando fuentes + Descargando datos de la fuente %s + Fuente de lectura %s + Analizando fuente %s + Sincronizando la base de datos de reglas + Revirtiendo el archivo hosts a la versión predeterminada + Se restableció el archivo hosts predeterminado + Creando archivo hosts estándar + Hay una actualización de la fuente + Nuevos archivos hosts disponibles + No se encontraron actualizaciones de la fuente + No hay conexión a Internet + La conexión a Internet no está disponible + Fuentes no disponibles + No se puede acceder a las fuentes de hosts + Se denegó el acceso de administrador + Permite el acceso de administrador desde la app de root + Hubo un problema + Revisa el registro logcat para obtener información detallada + Habilitado + Los archivos hosts más recientes están habilitados + Inhabilitado + El archivo hosts predeterminado está instalado + Aplicar fuentes más recientes + Creando un nuevo archivo hosts + Copiando un nuevo archivo hosts + Verificando la copia del archivo hosts + Se actualizó correctamente el archivo hosts + Se actualizó correctamente la configuración de la VPN + La configuración cambió, por lo que debes aplicarla. + Aplicar + Aplicando la configuración nueva… + No se pudo aplicar la configuración nueva. + + + Falta el vínculo simbólico al archivo hosts del objetivo + El vínculo simbólico del objetivo a /system/etc/hosts no existe o es incorrecto. AdAway no funcionará si este vínculo no apunta al archivo correcto.\n\n¿Quieres intentar crear un vínculo simbólico? + Falta el vínculo simbólico + No queda espacio suficiente en la partición.\nIntenta cambiar el archivo hosts objetivo en la configuración a /data/data/hosts. + No queda espacio suficiente + No se pudo leer el archivo descargado. + Error de archivo privado + No se pudo reactivar la partición con permisos de lectura y escritura. + Error de reactivación + No se pudo copiar el archivo hosts + No se pudo copiar el archivo hosts. + Error de copia + Se aplicaron las fuentes de hosts + Aplicación correcta + Se aplicó el archivo hosts correctamente.\nEs posible que debas reiniciar Android para que los cambios se apliquen.\n\n¿Quieres reiniciar el dispositivo?\nNota: Para evitar la pérdida de datos, asegúrate de que ninguna app esté usando la tarjeta SD en este momento. + Se creó el vínculo simbólico correctamente.\nEs posible que debas reiniciar Android para que los cambios se apliquen.\n\n¿Quieres reiniciar el dispositivo?\nNota: Para evitar la pérdida de datos, asegúrate de que ninguna app esté usando la tarjeta SD en este momento. + Creación correcta del vínculo simbólico + Android no pudo crear el vínculo simbólico.\nEs probable que se deba a una función llamada S-ON de los teléfonos HTC.\n\nPara solucionar este problema, puedes iniciar el teléfono en modo de recuperación y crear el vínculo simbólico desde allí con el comando “ln -s /data/data/hosts /system/etc/hostsâ€.\n\nSi esta solución no funciona, busca en Internet cómo inhabilitar S-ON en el teléfono. + No se pudo crear el vínculo simbólico + Para obtener más información, consulta la ayuda. + El dispositivo Android tiene configurado un proxy de APN.\nAdAway no funcionará de manera confiable en redes móviles como 3G. Puedes desactivar el proxy desde el APN seleccionado. Para ello, ve a la app de Configuración > Internet y red > Red móvil > Avanzada > Nombres de puntos de acceso y quita el valor del campo Proxy. + Se detectó un proxy de APN + La conexión a Internet no funciona. + No hay conexión + Descargando… + Aplicando… + Aplicando listas negra y blanca + Analizando y uniendo archivos hosts + Compilando archivo hosts + Aplicando archivo hosts + No se pudo aplicar el nuevo archivo hosts. + No se pudo aplicar el archivo hosts en el sistema.\nIntenta cambiar el archivo hosts de destino en la configuración a /data/data/hosts. + Error de aplicación + Compruebe su aplicación de administración de root para asegurarse de que se haya concedido el acceso root. + Restableciste el archivo hosts predeterminado.\nEs posible que debas reiniciar Android para que los cambios se apliquen.\n\n¿Quieres reiniciar el dispositivo?\nNota: Para evitar la pérdida de datos, asegúrate de que ninguna app esté usando la tarjeta SD en este momento. + Reversión correcta + No se pudo revertir el archivo hosts + No se pudo revertir el archivo hosts por razones desconocidas. + Error de reversión + No se puede acceder a ninguna de las fuentes de hosts habilitadas. Comprueba la conexión a Internet. + Error de descarga + No se pudo escribir el nuevo archivo hosts privado + No se pudo crear el archivo privado. + Error de creación de archivo privado + Habilitaste el modo sin modificaciones a la partición del sistema.\nEs posible que debas reiniciar Android para que los cambios se apliquen.\n\n¿Quieres reiniciar el dispositivo?\nNota: Para evitar la pérdida de datos, asegúrate de que ninguna app esté usando la tarjeta SD en este momento. + Habilitación correcta + Inhabilitaste el modo sin modificaciones a la partición del sistema.\nEs posible que debas reiniciar Android para que los cambios se apliquen.\n\n¿Quieres reiniciar el dispositivo?\nNota: Para evitar la pérdida de datos, asegúrate de que ninguna app esté usando la tarjeta SD en este momento. + Inhabilitación correcta + No se pudo habilitar el bloqueo de anuncios mediante VPN. + No se pudo inhabilitar el bloqueo de anuncios mediante VPN. + Habilitar el módulo Magisk de hosts + Habilita la función de hosts sin modificar el sistema del administrador de Magisk. Para ello, ve a su configuración, habilita la opción Systemless hosts (Hosts sin modificar el sistema) y, luego, reinicia el dispositivo. + Deshabilitar el módulo Magisk de hosts + Deshabilita la función de hosts sin sistema del administrador Magisk. En la lista de módulos, desinstale el módulo Hosts sin sistema y reinicie su dispositivo. + + + Ingresa la URL del archivo hosts: + El nombre de host no es válido. + El nombre de host tiene un formato incorrecto + La dirección IP no es válida + La dirección IP tiene un formato incorrecto + No reiniciar ni volver a preguntar + Cargando… + + + Actualizar + Añadir + Ayuda + Importar copia de seguridad + Exportar copia de seguridad + + + S-ON/S-OFF + Preguntas frecuentes + Problemas + + + Adware + En esta sección, encontrarás el adware y las aplicaciones maliciosas que AdAway no puede bloquear. Por ejemplo, algunas de estas apps pueden usar notificaciones push que aparecen cuando la app no está en ejecución o incluso cambiar el tono de llamada. La única forma de solucionar estos problemas es desinstalar esas apps. Para ello, selecciónalas en esta lista. + Analizando… + No se encontró adware. + + + Bloqueador de anuncios + No tienes instalado ningún editor de texto + No se encontró ningún editor de texto para abrir el archivo hosts. Puedes instalar Jota u otro editor de texto para encargarte de esto.\n\n¿Quieres instalar Jota? + No tienes instalado ningún administrador de archivos + No se encontró ningún administrador que pueda abrir los archivos. Puedes instalar OI File Manager u otro administrador de archivos para hacerlo.\n\n¿Quieres instalar OI File Manager? + + + Tcpdump + Tcpdump es una herramienta que permite supervisar las solicitudes DNS y guardarlas en un archivo de registro. Puedes iniciarlo en segundo plano, ejecutar aplicaciones que muestren anuncios y, luego, analizar las solicitudes DNS con el archivo de registro. Posteriormente, puedes agregar a la lista negra el posible servidor de anuncios. + Inhabilitar supervisión + Habilitar supervisión + Mostrar resultados + Ordenar dominios + Limpiar registro + Agregar entrada a la lista negra + Agregar entrada a la lista blanca + Agregar entrada a la lista de redirección + + Editar valor de texto de la preferencia + Abrir menú + Cerrar menú + + + + Home + Fuentes de hosts + Tus listas + Abrir archivo hosts + Log DNS requests + Scan for adware + Preferencias + Ayuda + + + + + Solicitudes DNS + Tus listas + Preferencias + + + Se instaló hace %1$s + Actualizado desde %1$s + Necesita actualización desde %1$s + Última actualización hace %1$s + Estado de actualización desconocido + Inhabilitado + pocos minutos + + %d minuto + %d minutos + %d minutos + + + %d hora + %d horas + %d horas + + + %d día + %d días + %d días + + + %d mes + %d meses + %d meses + + + + Host copiado al portapapeles + + + iniciando + activo + deteniendo + en espera de la red + reconectando + error de reconexión + en pausa + detenido + Bloqueador de anuncios por VPN %1$s + Pausar + Presiona para continuar + + + AdAway permisos + Permite interactuar con AdAway + Habilitar e inhabilitar el bloqueo de anuncios del sistema + Permite enviar comandos a AdAway como habilitar o deshabilitar el bloqueo de anuncios en todo el sistema + + diff --git a/app/src/main/res/values-es-rMX/strings_app.xml b/app/src/main/res/values-es-rMX/strings_app.xml new file mode 100644 index 0000000..b107a83 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Bloqueador de anuncios de código libre + Logo de AdAway + diff --git a/app/src/main/res/values-es-rMX/strings_errors.xml b/app/src/main/res/values-es-rMX/strings_errors.xml new file mode 100644 index 0000000..f8e3aca --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_errors.xml @@ -0,0 +1,22 @@ + + + + No hay conexión a Internet + No se pudo conectar a Internet. Comprueba la conectividad del dispositivo. + No se pudo descargar la fuente del archivo hosts + No se pudo conectar a ninguna de las fuentes de hosts habilitadas. Comprueba que tienes conexión a Internet. + + No se pudo crear el archivo privado + No se pudo crear un archivo privado para generar una nueva fuente de hosts. Revisa que el dispositivo tenga espacio libre disponible. + No queda espacio suficiente + No se pudo copiar el archivo hosts a la partición del sistema. Verifica que esté habilitado el módulo de Magisk sin modificar el sistema y reinicia el dispositivo. + No se pudo instalar el nuevo archivo hosts + No se pudo copiar el archivo hosts a la partición /system. Verifica que esté habilitado el módulo de Magisk sin modificar el sistema y reinicia el dispositivo. + No se pudo revertir el archivo hosts + No se pudo restablecer la configuración predeterminada del archivo hosts + + No se pudo habilitar el bloqueo de anuncios mediante VPN. + Verifica la configuración de la VPN y autoriza que se inicie la aplicación correspondiente. + No se pudo inhabilitar el bloqueo de anuncios mediante VPN. + Verifica la configuración de la VPN e inhabilítala de forma manual. + diff --git a/app/src/main/res/values-es-rMX/strings_home.xml b/app/src/main/res/values-es-rMX/strings_home.xml new file mode 100644 index 0000000..09b5ad1 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_home.xml @@ -0,0 +1,40 @@ + + + + + Bloquead + Permitido + Redireccionado + + + + %d up-to-date source + %d fuentes actualizadas + + + %d outdated source + %d fuentes desactualizadas + + + + Mostrar ayuda + + + Abrir página de GitHub + + + Apoyar el proyecto + + + Preferencias + + + Abrir panel de navegación + Pausar o reanudar el bloqueo de anuncios + Actualizar los dominios bloqueados + Mostrar los dominios solicitados + + + Para obtener más información, consulta la ayuda. + + diff --git a/app/src/main/res/values-es-rMX/strings_hosts.xml b/app/src/main/res/values-es-rMX/strings_hosts.xml new file mode 100644 index 0000000..8419a3e --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_hosts.xml @@ -0,0 +1,16 @@ + + + Fuentes de los hosts + + Lista del usuario + Hosts oficiales de AdAway + Host unidos de StevenBlack + Lista hosts bloqueados de Pete Lowe + + no disponible + + Añadir fuente + Editar fuente + URL (recurso https:// o file://): + La URL fuente del archivo hosts + diff --git a/app/src/main/res/values-es-rMX/strings_lists.xml b/app/src/main/res/values-es-rMX/strings_lists.xml new file mode 100644 index 0000000..b46c2f5 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_lists.xml @@ -0,0 +1,23 @@ + + + Tus listas + + Bloqueado + Permitido + Redireccionado + + Filtrar hosts + Buscar nombre de host… + Activar fuentes + + Agregar host a la lista negra + Agregar host a la lista blanca + Agregar redireccionamiento de host + Editar host de la lista negra + Editar host de la lista blanca + Editar redireccionamiento + Nombre de host: + La URL fuente del archivo hosts + (Se admiten comodines * y ?) + IP (IPv4 o IPv6): + diff --git a/app/src/main/res/values-es-rMX/strings_log.xml b/app/src/main/res/values-es-rMX/strings_log.xml new file mode 100644 index 0000000..2693e35 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_log.xml @@ -0,0 +1,8 @@ + + + + Orden alfabético + Orden por dominio de nivel superior + + Redirigir dominio + diff --git a/app/src/main/res/values-es-rMX/strings_notification.xml b/app/src/main/res/values-es-rMX/strings_notification.xml new file mode 100644 index 0000000..86ed4d5 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Actualizaciones + Notificaciones de actualizaciones nuevas + Actualización disponible + Hay archivos hosts más nuevos disponibles para descargar. + Hay una actualización de la app + Hay una nueva versión de AdAway disponible para descargar. + + VPN + Notificaciones de ejecución de la VPN + \ No newline at end of file diff --git a/app/src/main/res/values-es-rMX/strings_prefs_backup_restore.xml b/app/src/main/res/values-es-rMX/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..7f06adb --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Copias de seguridad y restablecimiento + Crear copias de seguridad + Crear una copia de seguridad de las reglas de bloqueo en el almacenamiento externo + Restablecer + Restablecer las reglas de bloqueo desde un archivo de copia de seguridad + diff --git a/app/src/main/res/values-es-rMX/strings_prefs_main.xml b/app/src/main/res/values-es-rMX/strings_prefs_main.xml new file mode 100644 index 0000000..0e7006a --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Preferencias + + Generales + Tema oscuro + + Claro + Oscur + Predeterminado del sistema + + Actualizaciones automaticas + + Bloqueo de anuncios + Bloqueador de anuncios basado en acceso raíz + Bloqueador de anuncios basado en VPN + Habilitar compatibilidad con IPv6 + Crear copias de seguridad y restablecer reglas de bloqueo + + Depuración + Enviar informes de fallas + Enviar informes a Sentry (sentry.io) + No se admite en esta versión + Registro detallado + Debes reiniciar la app para aplicar esta opción + diff --git a/app/src/main/res/values-es-rMX/strings_prefs_root.xml b/app/src/main/res/values-es-rMX/strings_prefs_root.xml new file mode 100644 index 0000000..cdd2d77 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_prefs_root.xml @@ -0,0 +1,35 @@ + + + Bloqueador de anuncios basado en acceso raíz + + Instalación de hosts + Abrir archivo hosts + Archivo hosts de destino + Lee la ayuda antes de usar esta función + + /system/etc/hosts + /data/hosts + /data/data/hosts + Destino personalizado + + Ubicación del destino personalizado + Ocultar el cuadro de diálogo de reinicio después de aplicar + + Redirección + Define adónde se redireccionarán los hosts bloqueados + Redireccionamiento IPv4 + Redireccionamiento IPv6 + + Servidor web local + El servidor web local escucha en las direcciones IP locales para responder las solicitudes a los hosts bloqueados. Esto puede evitar que las apps dejen de funcionar cuando se bloquean las conexiones. + Habilitar servidor web + Probar servidor web + Instalar certificado autofirmado + Instalacion manual de Certificado + Abrir ajustes de \"Seguridad\" + Comprobando… + Inactivo + Activo (certificado no instalado) + Activo (certificado instalado) + Reemplazar espacio en blanco de los anuncios por ícono de la app + diff --git a/app/src/main/res/values-es-rMX/strings_prefs_update.xml b/app/src/main/res/values-es-rMX/strings_prefs_update.xml new file mode 100644 index 0000000..0bb1969 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + Actualizaciones + + Actualizaciones de la aplicación + Comprobar actualizaciones al iniciar + Buscar actualizaciones periódicamente + Incluir actualizaciones beta + + Actualizaciones del archivo de hosts + Comprobar actualizaciones al iniciar + Buscar actualizaciones periódicamente + Sincronizar durante la actualización + Sincronizar solo en redes sin medición de uso + diff --git a/app/src/main/res/values-es-rMX/strings_prefs_vpn.xml b/app/src/main/res/values-es-rMX/strings_prefs_vpn.xml new file mode 100644 index 0000000..30e3e18 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_prefs_vpn.xml @@ -0,0 +1,22 @@ + + + Bloqueador de anuncios basado en VPN + + Habilitar en el inicio + + Aplicaciones excluidas + Configura las aplicaciones que no deben usar la VPN (es decir, cuyas conexiones no se bloquearán). + Excluir aplicaciones del sistema + + Ninguna + Todas, excepto navegadores + Todas + + Excluir aplicaciones del usuario + + + Aplicaciones excluidas + Seleccionar todas + Anular selección de todas + Ãcono de la aplicación + diff --git a/app/src/main/res/values-es-rMX/strings_support.xml b/app/src/main/res/values-es-rMX/strings_support.xml new file mode 100644 index 0000000..62be33d --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_support.xml @@ -0,0 +1,5 @@ + + + Apoyo + Conviértete en patrocinador + \ No newline at end of file diff --git a/app/src/main/res/values-es-rMX/strings_update.xml b/app/src/main/res/values-es-rMX/strings_update.xml new file mode 100644 index 0000000..ef4ce96 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_update.xml @@ -0,0 +1,17 @@ + + + Actualizacion de AdAway + + Actualización disponible + + + Estás al día + Actualización disponible + Actualizando AdAway + Actualizar ahora + Ultimos cambios: + Lista de cambios: + + + Descargando la ultima version de AdAway + diff --git a/app/src/main/res/values-es-rMX/strings_welcome.xml b/app/src/main/res/values-es-rMX/strings_welcome.xml new file mode 100644 index 0000000..eb0f61b --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings_welcome.xml @@ -0,0 +1,48 @@ + + + Te damos la bienvenida + + Te damos la bienvenida a AdAway + AdAway tiene dos métodos de bloqueo de anuncios. Elige el que prefieras: + + Logotipo de acceso raíz + Bloqueo de anuncios\nbasado en acceso raíz + Es más rápido + Usa menos batería + Se necesita un dispositivo con acceso raíz + + Logotipo de VPN + Bloqueo de anuncios\nbasado en VPN + Es más lento + Se ejecuta en segundo plano + Compatibilidad + + Se necesita un dispositivo con acceso raíz + No se pudo encontrar el objeto binario su o no otorgaste permisos de superusuario a AdAway.\n\nEsto puede deberse a que no tienes acceso raíz al dispositivo. Para obtener más información sobre cómo obtener acceso raíz, consulta wiki.lineageos.org (en inglés) u otros sitios web sobre Android. + + Ventaja + Desventaja + + + Se realizó la sincronización + Error de sincronización + + Sincronizando + Sincronizado + AdAway usa fuentes en línea para descargar las redes de anuncios y bloquearlas. Puedes personalizar estas fuentes más adelante en la configuración. + Reintentar sincronización + No se pudo sincronizar : %1$s ¿Quieres volver a intentarlo? + + + Apoyo + ¡Apóyame! + Esta es una app gratuita y de código libre. La desarrollo en mi tiempo libre. Si la disfrutas, puedes demostrar tu apoyo: + Dona en PayPal + A nadie le gustan los errores. + Habilita la telemetría para enviarme informes de fallas + + + Atrás + Siguiente + Terminar + diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml new file mode 100644 index 0000000..ac6a68d --- /dev/null +++ b/app/src/main/res/values-es/strings.xml @@ -0,0 +1,266 @@ + + + + Salir + Cerrar + Sí + No + Añadir + Cancelar + Guardar + Ayuda + + + ¡Bienvenido! + AdAway es software libre y código abierto para bloquear anuncios. Descarga las direcciones de red publicitarias para bloquearlas en tu dispositivo.\n¿Quieres saber más? ¡Revisa la ayuda más abajo! + Mostrar más ayuda + Estado de la actualización + Todos los archivos hosts de las fuentes específicadas se descargan, se fusionan contsus propias listas y se instalan como un único archivo hosts en tu sistema. + Activar el bloqueo de anuncios + Desactivar el bloqueo de anuncios + Servidor web + Funcionando + Detenido + Inicia o detiene el servidor web en localhost para responder a las peticiones de nombres de host bloqueados. + Activar el servidor web + Desactivar el servidor web + VPN + Funcionando + Detenido + Iniciar o detener VPN para filtrar peticiones. + Activar la VPN + Desactivar la VPN + + + Modificar la entrada + Aplicar + Editar + Borrar + + + Importando… + Copia de seguridad importada correctamente desde el almacenamiento externo. + No se ha podido importar la copia de seguridad. ¿Es correcto su formato? Comprueba logcat para más detalles. + Exportando… + Copia de seguridad exportada correctamente al archivo \'%s\' en tu almacenamiento externo. + Error al exportar el archivo de la copia de seguridad \'%s\'. + + + El archivo hosts + El archivo hosts es un archivo del sistema que asigna los nombres de los hosts a las direcciones IP. Es un archivo de texto plano cuya configuración es manejada por AdAway. Estas son sus primeras líneas: + Cargando el contenido del archivo hosts… + Abrir el archivo hosts + + + Comprobando actualización + Comprobando la fuente %s para la actualización + Recuperando las fuentes + Descargando la fuente %s + Leyendo la fuente %s + Analizando la fuente %s + Sincronizando la base de datos de las reglas + Volviendo al archivo hosts predeterminado + Archivo de hosts predeterminado restaurado + Creando un archivo hosts estándar + Actualización disponible + Nuevos archivos hosts disponibles + No se encontró ninguna actualización de la fuente + No hay conexión a Internet + No hay ninguna conexión a Internet disponible + Fuentes no disponibles + ¡No hay fuentes de archivos hosts accesibles! + Acceso root denegado + Permitir el acceso root desde tu aplicación root + Algo salió mal + Comprueba el logcat para más detalles + Habilitado + Nuevos archivos hosts habilitados + Deshabilitado + Archivo hosts predeterminado instalado + Aplicar las últimas fuentes + Crear un nuevo archivo hosts + Copiando un nuevo archivo hosts + Comprobando la copia del archivo hosts + Archivo hosts actualizado correctamente + La configuración de la VPN se actualizó correctamente + Tu configuración ha cambiado. Necesitas aplicarla. + Aplicar + Aplicando la nueva configuración… + Error al aplicar la nueva configuración. + + + Falta el enlace simbólico al archivo hosts + El enlace simbólico a /system/etc/hosts no existe o es incorrecto. AdAway no funcionará si no apunta al archivo correcto.\n¿Quieres intentar crear un enlace simbólico? + Falta enlace simbólico + ¡No hay suficiente espacio en la partición!\nIntenta cambiar la ruta del archivo hosts a /data/data/hosts en las preferencias. + No hay suficiente espacio + No se pudo leer el archivo descargado. + El archivo privado falló + ¡Error al volver a montar la partición en modo lectura/escritura! + Error al volver a montar + Error al copiar el achivo hosts. + ¡La copia del archivo host ha fallado! + Ha fallado la copia + Fuentes de hosts aplicados + Aplicado correctamente + Se ha aplicado correctamente.\nPuede ser necesario reiniciar Android para que los cambios surtan efecto.\n\n¿Quieres reiniciar?\n(¡Para evitar una posible pérdida de datos, asegúrate que ninguna aplicación esté usando la memoria SD en este momento!) + El enlace simbólico fue creado correctamente.\nPuede ser necesario reiniciar Android para que los cambios surtan efecto.\n\n¿Quieres reiniciar?\n(¡Para evitar una posible pérdida de datos, asegúrate que ninguna aplicación esté usando la memoria SD en este momento!) + El enlace simbólico se creó correctamente + El enlace simbólico no pudo ser creado por Android.\nEste fallo principalmente se debe a una \'característica\' llamada S-ON en los teléfonos HTC!\n\nUna solución es arrancar el teléfono en modo de recuperación y crear el enlace simbólico allí con \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nSi esto no funciona busca en Internet S-OFF y tu modelo de teléfono. + No se pudo crear el enlace simbólico + Por favor lee la Ayuda para más información. + ¡Un proxy APN está configurado en tu Android!\nAdAway no funcionará de manera fiable cuando se encuentre en redes móviles como 3G. Puedes deshabilitar ese proxy al ir a su APN seleccionado (en la aplicación Configuración: Red e Internet -> Red móvil -> Avanzado -> Nombres de puntos de acceso) y borra el valor existente en el campo proxy. + ¡Proxy APN configurado! + La conexión a Internet no funciona. + Sin conexión + Descargando… + Aplicando… + Aplicando las listas negra y blanca + Analizando y fusionando los archivos hosts + Construyendo el archivo hosts + Aplicando el archivo hosts + Error al aplicar el nuevo archivo hosts. + ¡No se pudo aplicar el archivo hosts en tu sistema!\nIntenta cambiar la ruta del archivo hosts a /data/data/hosts en las preferencias. + Error al aplicar + Verifica tu aplicación de root para asegurarte de que se haya otorgado acceso root + Has vuelto al archivo de hosts predeterminado.\nPuede ser necesario reiniciar Android para que los cambios tengan efecto.\n\n¿Quieres reiniciar?\n(¡Para evitar una posible pérdida de datos, asegúrese que ninguna aplicación esté usando la memoria SD en este momento!) + Los cambios se revirtieron correctamente + No se pudo revertir el archivo hosts + No pudieron revertirse los cambios por razones desconocidas. + ¡Error al revertir! + ¡Ninguna de tus fuentes de archivos hosts habilitadas son accesibles! ¿Estás conectado adecuadamente a Internet? + Descarga fallida + Error al escribir el nuevo archivo hosts privado + No se pudo crear el archivo privado. + Error al crear el archivo privado + Has habilitado el modo sin sistema.\nPuede ser necesario reiniciar Android para que los cambios surtan efecto.\n\n¿Quieres reiniciar?\n(Para evitar una posible pérdida de datos, asegúrese que ninguna aplicación esté usando la memoria SD en este momento) + Habilitado correctamente + Has deshabilitado el modo sin sistema.\nPuede ser necesario reiniciar Android para que los cambios surtan efecto.\n\n¿Quieres reiniciar?\n(Para evitar una posible pérdida de datos, asegúrese que ninguna aplicación esté usando la memoria SD en este momento) + Deshabilitado correctamente + Error al habilitar el bloqueo de anuncios VPN. + Error al deshabilitar el bloqueo de anuncios VPN. + Habilitar el módulo Magisk de hosts + Habilita la función de hosts sin sistema del administrador Magisk. Desde la configuración, habilita la opción Hosts sin sistema y luego reinicia tu dispositivo. + Deshabilitar el módulo Magisk de hosts + Deshabilita la función de hosts sin sistema del administrador Magisk. En la lista de módulos, desinstala el módulo Hosts sin sistema y reinicia tu dispositivo. + + + Ingresar URL del archivo hosts: + ¡Este no es un nombre de host válido! + El nombre del host tiene un formato erróneo. + ¡Esta no es una IP válida! + Formato de IP incorrecto + ¡Nunca reiniciar y no mostrar esta pregunta la próxima vez! + Cargando… + + + Actualizar + Añadir + Ayuda + Importar la copia de seguridad + Exportar la copia de seguridad + + + S-ON/S-OFF + Preguntas frecuentes + Problemas + + + Adware + Aquí puedes encontrar adware instalado, aplicaciones malas que no pueden ser bloqueadas por AdAway. Estas aplicaciones utilizan, por ejemplo, notificaciones Airpush que aparecen incluso cuando la aplicación no se está ejecutando o incluso cambian el tono de llamada. La única contramedida disponible es desinstalar esas aplicaciones haciendo clic en los elementos de la lista. + Escaneando… + ¡No se ha encontrado Adware! + + + Bloqueador de anuncios + No hay ningún editor de texto instalado + No se pudo encontrar un editor de texto para abrir el archivo hosts. Puedes instalar Jota u otros editores de texto para solucionar esto.\n\n¿Quieres instalar Jota? + No hay ningún administrador de archivos instalado + No pudo encontrarse ningún administrador de archivos para abrir los archivos. Puedes instalar OI File Manager u otros administradores de archivos para solucionar esto.\n\n¿Quieres instalar OI File Manager? + + + Tcpdump + Tcpdump es una herramienta para monitorizar peticiones DNS y guardarlas en un archivo de registro. Puedes iniciarla en segundo plano, ejecutar aplicaciones que muestran anuncios, y luego analizar las peticiones DNS de ellas usando el archivo de registro. Los posibles servidores de anuncios utilizados podrán entonces ser añadidos a tu lista negra. + Deshabilitar monitorización + Habilitar monitorización + Mostrar resultados + Dominios cortos + Borrar registro + Añadir una entrada a la lista negra + Añadir una entrada a la lista blanca + Añadir una entrada a la lista de redirección + + Editar valor de preferencia de texto + Abrir menú + Cerrar menú + + + + Inicio + Fuentes de archivos hosts + Tus listas + Abrir el archivo hosts + Registro de peticiones DNS + Escanea en busca de adware + Preferencias + Ayuda + + + + + Peticiones DNS + Tus listas + Preferencias + + + Instalado hace %1$s + Actualizado para %1$s + Necesita actualización para %1$s + Última actualización hace %1$s + Estado de la actualización desconocido + Deshabilitado + pocos minutos + + %d minuto + %d minutos + %d minutos + + + %d hora + %d horas + %d horas + + + %d día + %d días + %d días + + + %d mes + %d meses + %d meses + + + + Host copiado al portapapeles + + + iniciando + activo + deteniendo + esperando a la red + reconectando + error al reconectar + pausado + detenido + Bloqueador de anuncios por VPN %1$s + Pausar + Reanudar + + + Permisos de AdAway + Permitir interactuar con AdAway + Enviar comandos a AdAway + Permite enviar comandos a AdAway como habilitar o deshabilitar el bloqueo de anuncios en todo el sistema + + diff --git a/app/src/main/res/values-es/strings_app.xml b/app/src/main/res/values-es/strings_app.xml new file mode 100644 index 0000000..d72ec0e --- /dev/null +++ b/app/src/main/res/values-es/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Bloqueador de anuncios de código abierto + Logo de AdAway + diff --git a/app/src/main/res/values-es/strings_errors.xml b/app/src/main/res/values-es/strings_errors.xml new file mode 100644 index 0000000..ba0edac --- /dev/null +++ b/app/src/main/res/values-es/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Sin conexión a Internet + No se puede establecer una conexión a Internet. Verifica la conectividad de tu dispositivo. + Error al descargar la fuente del hosts + No se puede acceder a ninguna de las fuentes de los hosts habilitadas. Comprueba que está correctamente conectado a Internet. + + Error al crear el archivo privado + No se puede crear un archivo privado para crear una nueva fuente de hosts. Comprueba el espacio libre disponible en tu dispositivo. + No hay suficiente espacio + No se pudo copiar el archivo hosts a la partición del sistema. Comprueba que el módulo Magisk systemless esté habilitado y luego reinícialo. + No se pudo instalar el nuevo archivo hosts + No se pudo copiar el archivo hosts en la partición /system. Por favor, comprueba que el módulo sin sistema Magisk está habilitado y luego reinícialo. + Error al revertir el archivo hosts + No se pudo restaurar la configuración predeterminada del archivo hosts. + + Error al habilitar el bloqueo de anuncios VPN. + Verifica la configuración de tu VPN para autorizar el inicio de la aplicación VPN. + Error al deshabilitar el bloqueo de anuncios VPN. + Comprueba la configuración de tu VPN para desactivarla manualmente. + diff --git a/app/src/main/res/values-es/strings_home.xml b/app/src/main/res/values-es/strings_home.xml new file mode 100644 index 0000000..23765ab --- /dev/null +++ b/app/src/main/res/values-es/strings_home.xml @@ -0,0 +1,48 @@ + + + + + Bloqueado + Permitido + Redirigido a + + + + %d fuente actualizada + %d fuentes actualizadas + %d fuentes actualizadas + + + %d fuente desactualizada + %d fuentes desactualizadas + %d fuentes desactualizadas + + Buscar las actualizaciones de los hosts + Actualizar los hosts + + + Mostrar el registro de las peticiones DNS + + + Mostrar la ayuda\ny los consejos + + + Abrir la página de GitHub + + + Apoyar el proyecto + + + Proyecto en GitHub + Preferencias + + + Abrir el cajón de navegación + Pausar/reanudar el bloqueo de anuncios + Actualizar los dominios bloqueados + Mostrar los dominios solicitados + + + Por favor para más información, consulta la Ayuda. + + \ No newline at end of file diff --git a/app/src/main/res/values-es/strings_hosts.xml b/app/src/main/res/values-es/strings_hosts.xml new file mode 100644 index 0000000..43e681b --- /dev/null +++ b/app/src/main/res/values-es/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Fuentes de los archivos hosts + + Lista del usuario + Hosts oficial de AdAway + Hosts unificados de StevenBlack + Lista de bloqueo de Pete Lowe + + no disponible + %s hosts + + Añadir una fuente + Editar una fuente + URL: (un recurso https:// o archivo file://) + La dirección URL del origen de los hosts + diff --git a/app/src/main/res/values-es/strings_lists.xml b/app/src/main/res/values-es/strings_lists.xml new file mode 100644 index 0000000..2faac41 --- /dev/null +++ b/app/src/main/res/values-es/strings_lists.xml @@ -0,0 +1,24 @@ + + + Tus listas + Añadir un host + + Bloqueado + Permitido + Redirigido a + + Filtrar los hosts + Buscar el nombre del host… + Alternar las fuentes + + Añadir un host a la lista negra + Añadir un host a la lista blanca + Añadir una redirección al host + Editar el host de la lista negra + Editar el host de la lista blanca + Editar la redirección + Nombre del host: + La dirección url de origen de los hosts + (se permiten los caracteres comodín * y ?) + IP (IPv4 ó IPv6): + diff --git a/app/src/main/res/values-es/strings_log.xml b/app/src/main/res/values-es/strings_log.xml new file mode 100644 index 0000000..664f6ee --- /dev/null +++ b/app/src/main/res/values-es/strings_log.xml @@ -0,0 +1,11 @@ + + + Activar la grabación del registro + Presiona en grabar para iniciar el registro de las solicitudes, navegar por la Web o usar las aplicaciones, luego regresa o desliza el dedo para actualizar los registros. + \n\nLas solicitudes bloqueadas no se registrarán. Desactiva el bloqueo de anuncios primero si también deseas registrarlas. + + Orden alfabético + Clasificación de los dominios de nivel superior + + Redirigir un dominio + diff --git a/app/src/main/res/values-es/strings_notification.xml b/app/src/main/res/values-es/strings_notification.xml new file mode 100644 index 0000000..bddfb3d --- /dev/null +++ b/app/src/main/res/values-es/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Actualizaciones + Nuevas notificaciones de actualización + Actualización de la fuente disponible + Nuevos archivos hosts disponibles para descargar. + Actualización de la aplicación disponible + Una nueva versión de AdAway está disponible para ser descargada. + + VPN + Notificaciones de la VPN funcionando + diff --git a/app/src/main/res/values-es/strings_prefs_backup_restore.xml b/app/src/main/res/values-es/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..2c487e1 --- /dev/null +++ b/app/src/main/res/values-es/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Respaldar y restaurar + Respaldar + Respalda tus reglas de bloqueo en el almacenamiento externo + Restaurar + Restaura tus reglas de bloqueo desde un archivo de respaldo + diff --git a/app/src/main/res/values-es/strings_prefs_main.xml b/app/src/main/res/values-es/strings_prefs_main.xml new file mode 100644 index 0000000..6fee688 --- /dev/null +++ b/app/src/main/res/values-es/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Preferencias + + General + Tema oscuro + + Claro + Oscuro + Predeterminado del sistema + + Actualizaciones automáticas + + Bloqueo de anuncios + Bloqueador de anuncios basado en root + Bloqueador de anuncios basado en VPN + Habilitar el soporte para IPv6 + Copia de seguridad / restauración de las reglas de bloqueo + + Depurar + Enviar los informes de los fallos + Informar a Sentry (sentry.io) + No es compatible con esta compilación + Registro detallado + Es necesario reiniciar la aplicación para aplicar los cambios + diff --git a/app/src/main/res/values-es/strings_prefs_root.xml b/app/src/main/res/values-es/strings_prefs_root.xml new file mode 100644 index 0000000..394ad04 --- /dev/null +++ b/app/src/main/res/values-es/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Bloqueador de anuncios basado en root + + Instalación de hosts + Abrir el archivo hosts + Ruta del archivo hosts + Antes de cambiar esta configuración, lea la Ayuda sobre esta funcionalidad. + + /system/etc/hosts + /data/hosts + /data/data/hosts + Ruta personalizada + + Ruta personalizada + Ocultar cuadro de diálogo de reinicio + + Redirección + Definir dónde redirigir los hosts bloqueados + Configurar redirección IPv4 + Configurar redirección IPv6 + Redirección no válida + + Servidor web local + El servidor web local escucha las direcciones IP locales para responder a las peticiones de nombres de host bloqueadas. Puede ayudar con la congelación de aplicaciones en conexiones bloqueadas. + Habilitar servidor web + Probar servidor web + Instalar certificado autofirmado + Instalación manual del certificado + A partir de Android 11 (R), la aplicación ya no puede instalar automáticamente la autoridad de certificación (CA).\n\nVe a la configuración de \"Seguridad\", \"Cifrado y credenciales\" y luego a \"Instalar un certificado\". Desde allí, elige \"Certificado de CA\" y seleccione el archivo del certificado recién exportado. + Abrir configuración de \"Seguridad\" + Comprobando… + No se está ejecutando + En ejecución pero el certificado no está instalado + En ejecución y certificado instalado + Reemplazar espacio en blanco del anuncio por el icono de la aplicación + diff --git a/app/src/main/res/values-es/strings_prefs_update.xml b/app/src/main/res/values-es/strings_prefs_update.xml new file mode 100644 index 0000000..f64db39 --- /dev/null +++ b/app/src/main/res/values-es/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Actualizaciones + Las notificaciones están deshabilitadas + Las notificaciones de la aplicación no se mostrarán. Toca para habilitarlas. + + Actualizaciones de la aplicación + Buscar actualizaciones al inicio + Buscar actualizaciones diariamente + Incluir las versiones beta + + Actualizaciones de los hosts + Buscar actualizaciones al inicio + Buscar actualizaciones diariamente + Sincronizar durante la actualización + Sincronizar sólo en redes sin limitaciones + diff --git a/app/src/main/res/values-es/strings_prefs_vpn.xml b/app/src/main/res/values-es/strings_prefs_vpn.xml new file mode 100644 index 0000000..5cdd196 --- /dev/null +++ b/app/src/main/res/values-es/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Bloqueador de anuncios basado en VPN + + Habilitar al inicio + Monitor de conexión + Comprobar periódicamente el estado de la red para reiniciar la VPN en caso de desconexión. + + Aplicaciones excluidas + Configura qué aplicaciones no deben usar la VPN para que no se bloquee ninguna conexión. + Excluir aplicaciones del sistema + + Ninguno + Todas excepto los navegadores + Todo + + Excluir aplicaciones del usuario + + + Aplicaciones excluidas + Seleccionar todo + Deseleccionar todo + Icono de la aplicación + diff --git a/app/src/main/res/values-es/strings_source_edit.xml b/app/src/main/res/values-es/strings_source_edit.xml new file mode 100644 index 0000000..1bb9751 --- /dev/null +++ b/app/src/main/res/values-es/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Editar una fuente + Añadir una fuente + + Etiqueta + La etiqueta es obligatoria + Tipo + Dirección url + Archivo + Ubicación + https:// + La ubicación es necesaria + Presiona en Archivo para seleccionar el archivo de origen + Ubicación no válida + Formato de la lista + Bloquear + Permitir + Aplicar la redirección a los hosts + Permitir la redirección de los hosts puede causar problemas de seguridad. Utiliza esta configuración sólo en una fuente de confianza, ya que podría redirigir el tráfico sensible a cualquier servidor que desee. + diff --git a/app/src/main/res/values-es/strings_support.xml b/app/src/main/res/values-es/strings_support.xml new file mode 100644 index 0000000..62be33d --- /dev/null +++ b/app/src/main/res/values-es/strings_support.xml @@ -0,0 +1,5 @@ + + + Apoyo + Conviértete en patrocinador + \ No newline at end of file diff --git a/app/src/main/res/values-es/strings_update.xml b/app/src/main/res/values-es/strings_update.xml new file mode 100644 index 0000000..c89c041 --- /dev/null +++ b/app/src/main/res/values-es/strings_update.xml @@ -0,0 +1,21 @@ + + + Actualización de AdAway + + ¡Actualización disponible! + + + Estás al día + Actualización disponible + Actualizando AdAway + Actualizar ahora + %1$s / %2$s + Últimos cambios + Registro de cambios + Apoyar el desarrollo + Donar + Patrocinador + + + Descargando la última versión de AdAway… + diff --git a/app/src/main/res/values-es/strings_welcome.xml b/app/src/main/res/values-es/strings_welcome.xml new file mode 100644 index 0000000..35f5657 --- /dev/null +++ b/app/src/main/res/values-es/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Bienvenido + Primer paso del asistente + Segundo paso del asistente + Último paso del asistente + + + ¡Bienvenido a AdAway! + AdAway proporciona dos métodos de bloqueo de anuncios. Escoge el que te gusta: + + Logo root + Basado en root\nbloqueo de anuncios + Más rápido + Amigable para la batería + Root necesario + + Logo VPN + Basado en VPN\nbloqueo de anuncios + Más lento + Ejecutar en segundo plano + Compatibilidad + + Se requiere un Android rooteado + O bien no se pudo encontrar el binario o no permitió el permiso de root para AdAway.\n\nEsto puede suceder cuando tu dispositivo no está rooteado. Puedes encontrar información acerca de cómo hacer funcionar tu dispositivo en wiki.lineageos.org u otros sitios web de Android. + + Pro + Con + + + Sincronización realizada + Error durante la sincronización + + Sincronización + ¡Sincronizado! + AdAway descarga redes publicitarias para bloquear las fuentes en línea. Puedes personalizarlas más tarde en la configuración. + Reintentar la sincronización + Error al sincronizar: %1$s ¿Reintentar ahora? + Puedes enviar notificaciones para mostrar el estado y el control del bloqueo de anuncios, y para notificar sobre las actualizaciones disponibles de la aplicación (unas pocas al año). Habilítalas si quieres estar actualizado. + + + Apoyo + ¡Apóyame! + AdAway es una aplicación libre y de código abierto. Lo desarrollo en mi tiempo libre. Entonces, si lo disfrutas, no dudes en mostrar tu apoyo: + Donar en PayPal + ¿Te gustan los errores? A mí tampoco. + Habilitar la telemetría para enviarme los informes de fallos + + + Atrás + Siguiente + Finalizar + diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml new file mode 100644 index 0000000..9b71133 --- /dev/null +++ b/app/src/main/res/values-et/strings.xml @@ -0,0 +1,166 @@ + + + + Välju + Sulge + Jah + Ei + Lisa + Tühista + Salvesta + Abi + + + Tere tulemast! + AdAway on vaba ja avatud lähtekoodiga tarkvara reklaamide blokeerimiseks. See hangib reklaamide võrguaadressid, et need sinu seadmes blokeerida.\nSoovid rohkem teada? Vaata abimaterjali allpool! + Kuva rohkem abi + Uuenduse olek + Kõik hosts-failid laetakse määratud allikatest, ühendatakse sinu loenditega ning paigaldatakse süsteemi ühe failina. + Luba reklaamiblokeering + Keela reklaamiblokeering + Veebiserver + Käimas + Peatatud + Luba veebiserver + Keela veebiserver + VPN + Käimas + Peatatud + Luba VPN + Keela VPN + + + Muuda üksust + Rakenda + Muuda + Kustuta + + + Importimine… + Eksportimine… + + Hosts-fail + Ava hosts-fail + + Uuendus saadaval + Uuemad hosts-failid saadaval + Ühendus puudub + Internetiühendus ei ole saadaval + Allikad pole saadaval + Juurkasutaja ligipääs keelatud + Võimalda juurkasutajale ligipääs oma juurkasutaja rakendusest + Midagi läks valesti + Rohkema teabe saamiseks vaata logcati + Lubatud + Uusimad hosts-failid kasutusel + Keelatud + Vaikimisi hosts-fail paigaldatud + Rakenda + Sümlink puudub + Pole piisavalt ruumi + Privaatse faili ebaõnnestumine + Taashaakimine ebaõnnestus + Hosts-faili kopeerimine ebaõnnestus! + Kopeerimine nurjus + Hosts-allikad rakendatud + Rakendamine edukas + Sümlingi loomine edukas + Sümlingi loomine nurjus + Palun loe abi rohkema teabe saamiseks. + APN-proksi määratud! + Ühendus puudub + Allalaadimine… + Rakendamine… + Musta ja valge loendi rakendamine + Hosts-failide töötlemine ja ühendamine + Hosts-faili koostamine + Hosts-faili rakendamine + Rakendamine nurjus + Palun kontrolli oma juurkasutaja haldusrakendust, et veenduda juurkasutaja ligipääsu andmises. + Taastamine edukas + Taastamine ebaõnnestus! + Allalaadimine nurjus + Lubamine edukas + Keelamine edukas + + Sisesta URL hosts-faili: + See ei ole kehtiv aadress! + See ei ole kehtiv IP! + Sobimatult vormistatud IP + Laadimine… + + + Värskenda + Lisa + Abi + Impordi varundus + Ekspordi varundus + + + S-ON/S-OFF + KKK + Probleemid + + + Reklaamvara + Skanneerimine… + Reklaamvara ei leitud! + + + Reklaamide blokeerija + Tekstitöötlejaid pole paigaldatud + Ühtegi failihaldurit pole installitud + + Tcpdump + Keela monitoorimine + Luba monitoorimine + Kuva tulemused + Sorteeri domeene + Tühjenda logi + Lisa üksus musta loendisse + Lisa üksus valgesse loendisse + Lisa üksus suunamisloendisse + + Ava menüü + Sulge menüü + + + + Kodu + Hosts-allikad + Sinu loendid + Ava hosts-fail + Logi DNS-taotlusi + Skanni reklaamvara + Eelistused + Abi + + + + + DNS-taotlused + Sinu loendid + Eelistused + + %1$s on kaasaegne + %1$s vajab uuendust + Viimane uuendus %1$s tagasi + Uuenduste olek teadmata + + %d minut + %d minutit + + + %d tund + %d tundi + + + %d päev + %d päeva + + + %d kuu + %d kuud + + + diff --git a/app/src/main/res/values-et/strings_app.xml b/app/src/main/res/values-et/strings_app.xml new file mode 100644 index 0000000..7f00b07 --- /dev/null +++ b/app/src/main/res/values-et/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Avatud lähtekoodiga reklaamiblokeerija + AdAway logo + diff --git a/app/src/main/res/values-et/strings_errors.xml b/app/src/main/res/values-et/strings_errors.xml new file mode 100644 index 0000000..619fa3c --- /dev/null +++ b/app/src/main/res/values-et/strings_errors.xml @@ -0,0 +1,6 @@ + + + + Ühendus puudub + Pole piisavalt ruumi + \ No newline at end of file diff --git a/app/src/main/res/values-et/strings_home.xml b/app/src/main/res/values-et/strings_home.xml new file mode 100644 index 0000000..12534cc --- /dev/null +++ b/app/src/main/res/values-et/strings_home.xml @@ -0,0 +1,35 @@ + + + + + Blokeeritud + Lubatud + Ümbersuunatud + + + + %d kaasaegne allikas + %d kaasaegset allikat + + + %d aegunud allikas + %d aegunud allikat + + + + Kuva abi + + + Ava GitHubi leht + + + Toeta projekti + + + Eelistused + + Peata/jätka reklaamiblokeerimist + + Palun loe abi rohkema teabe saamiseks. + + diff --git a/app/src/main/res/values-et/strings_hosts.xml b/app/src/main/res/values-et/strings_hosts.xml new file mode 100644 index 0000000..075d76d --- /dev/null +++ b/app/src/main/res/values-et/strings_hosts.xml @@ -0,0 +1,11 @@ + + + Hosts-allikad + + pole saadaval + + Lisa allikas + Muuda allikat + URL: (https:// või file:// ressurss) + Hosts-allika URL + diff --git a/app/src/main/res/values-et/strings_lists.xml b/app/src/main/res/values-et/strings_lists.xml new file mode 100644 index 0000000..f3c93dd --- /dev/null +++ b/app/src/main/res/values-et/strings_lists.xml @@ -0,0 +1,19 @@ + + + Sinu loendid + + Blokeeritud + Lubatud + Ümbersuunatud + + Lisa host musta loendisse + Lisa host valgesse loendisse + Lisa hosti suunamine + Muuda musta loendi hosti + Muuda valge loendi hosti + Muuda suunamist + Hostinimi: + Hosts-allika URL + (Lubatud on jokkermärgid * ja ?) + IP (IPv4 või IPv6): + diff --git a/app/src/main/res/values-et/strings_log.xml b/app/src/main/res/values-et/strings_log.xml new file mode 100644 index 0000000..9c2320b --- /dev/null +++ b/app/src/main/res/values-et/strings_log.xml @@ -0,0 +1,8 @@ + + + + Tähestikuline järjekord + TLD järjekord + + Suuna domeen + diff --git a/app/src/main/res/values-et/strings_notification.xml b/app/src/main/res/values-et/strings_notification.xml new file mode 100644 index 0000000..da7a0c2 --- /dev/null +++ b/app/src/main/res/values-et/strings_notification.xml @@ -0,0 +1,8 @@ + + + + Uuendused + Uuendus saadaval + + VPN + \ No newline at end of file diff --git a/app/src/main/res/values-et/strings_prefs_backup_restore.xml b/app/src/main/res/values-et/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-et/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-et/strings_prefs_main.xml b/app/src/main/res/values-et/strings_prefs_main.xml new file mode 100644 index 0000000..ffef65d --- /dev/null +++ b/app/src/main/res/values-et/strings_prefs_main.xml @@ -0,0 +1,11 @@ + + + Eelistused + Luba tume teema + Luba IPv6 + + Silumine + Luba krahhiaruanded + Luba rakendusel saata vigu ja krahhiaruandeid Sentryle (sentry.io) + Logimise jõustumiseks on vajalik AdAway taaskäivitamine. + diff --git a/app/src/main/res/values-et/strings_prefs_root.xml b/app/src/main/res/values-et/strings_prefs_root.xml new file mode 100644 index 0000000..e65fd18 --- /dev/null +++ b/app/src/main/res/values-et/strings_prefs_root.xml @@ -0,0 +1,21 @@ + + + Ava hosts-fail + Hosts-faili asukoht + Enne muutmist loe abist selle funktsiooni kohta. + + /system/etc/hosts + /data/hosts + /data/data/hosts + Muu asukoht + + Muu asukoht + Taaskäivitamise dialoog peidetud + + Suunamine + Suunamise IPv4 + Suunamise IPv6 + + Kohalik veebiserver + Luba veebiserver + diff --git a/app/src/main/res/values-et/strings_prefs_update.xml b/app/src/main/res/values-et/strings_prefs_update.xml new file mode 100644 index 0000000..1be2389 --- /dev/null +++ b/app/src/main/res/values-et/strings_prefs_update.xml @@ -0,0 +1,6 @@ + + + Uuendused + Uuenduste kontroll iga päev + Uuenduste kontroll iga päev + diff --git a/app/src/main/res/values-et/strings_prefs_vpn.xml b/app/src/main/res/values-et/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-et/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-et/strings_support.xml b/app/src/main/res/values-et/strings_support.xml new file mode 100644 index 0000000..41f6a1a --- /dev/null +++ b/app/src/main/res/values-et/strings_support.xml @@ -0,0 +1,4 @@ + + + Tugi + \ No newline at end of file diff --git a/app/src/main/res/values-et/strings_update.xml b/app/src/main/res/values-et/strings_update.xml new file mode 100644 index 0000000..558612d --- /dev/null +++ b/app/src/main/res/values-et/strings_update.xml @@ -0,0 +1,4 @@ + + + Uuendus saadaval + diff --git a/app/src/main/res/values-et/strings_welcome.xml b/app/src/main/res/values-et/strings_welcome.xml new file mode 100644 index 0000000..9b3b997 --- /dev/null +++ b/app/src/main/res/values-et/strings_welcome.xml @@ -0,0 +1,52 @@ + + + Tere tulemast + Viisardi esimene samm + Viisardi teine samm + Viisardi viimane samm + + + Tere tulemast AdAwaysse! + AdAway pakub kahte reklaamiblokeerimise viisi. Vali endale meeldiv: + + Juurkasutaja logo + Juurkasutaja-põhine\nreklaamiblokeerimine + Kiirem + Akusõbralik + Juurkasutaja nõutud + + VPNi logo + VPNi-põhine\nreklaamiblokeerimine + Aeglasem + Töötab taustal + Ühilduvus + + Vajalik juurkasutaja toega Android + Täitmisfaili \"su\" ei leitud või sa ei lubanud AdAwayle juurkasutaja õigusi.\n\nSee võib juhtuda, kui su seade ei oma juurkasutaja õigusi. Oma seadme juurkasutaja õiguste avamise kohta saad rohkem lugeda wiki.lineageos.org või teistelt Androidi veebilehtedelt. + + Eelis + Puudus + + + Sünkroonimine lõpetatud + Sünkroonimisel esines tõrge + + Sünkroonimine + Sünkroonitud! + AdAway laadib võrguallikatest reklaamivõrgustike nimed, et neid blokeerida. Neid saab hiljem seadetes kohandada. + Proovi uuesti sünkroonida + Sünkroonimine ebaõnnestus: %1$s Proovid uuesti? + + + Tugi + Toeta mind! + See on tasuta ja avatud lähtekoodiga rakendus. Ma arendan seda oma vabast ajast. Seega, kui see sulle meeldib võid vabalt oma toetust näidata: + Anneta PayPalis + Kas sulle meeldivad vead? Mulle ka mitte. + Luba krahhiaruannete saatmiseks telemeetria + + + Tagasi + Edasi + Lõpeta + diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml new file mode 100644 index 0000000..10c8eab --- /dev/null +++ b/app/src/main/res/values-eu/strings.xml @@ -0,0 +1,236 @@ + + + + Irten + Itxi + Bai + Ez + Gehitu + Ezeztatu + Gorde + Laguntza + + + Ongi etorri! + AdAway iragarkiak blokeatzeko diseinatuta dagoen librea eta kode irekikoa den softwarea da. Iragarkien sareko helbideak lortzen ditu zure gailuan blokeatzeko.\nGehiago jakin nahi duzu? Begiratu beheko laguntza. + Erakutsi laguntza gehiago + Eguneratu egoera + Zehaztutako iturburuetako hostalari agiri guztiak jeitsi eta batu dira zeure zerrendarekin eta hostalari agiri bat bezala ezarri dira zure sisteman. + Gaitu iragarki-blokeatzailea + Ezgaitu iragarki-blokeatzailea + Web zerbitzaria + Exekutatzen + Geldituta + Hasi edo gelditu web zerbitzua localhost-en, blokeatutako ostalari-izenen eskaerei erantzuteko. + Gaitu web zerbitzaria + Desgaitu web zerbitzaria + VPN + Abian + Geldirik + Hasi edo gelditu VPN-a eskaerak filtratzen. + VPN-a gaitu + VPN-a desgaitu + + + Editatu Sarrera + Aplikatu + Editatu + Ezabatu + + + Inportatzen… + Kanpoko biltegitik segurtasun-kopia ondo inportatuta. + Ezin izan da segurtasun-kopia inportatu. Zuzena al da formatua? Egiaztatu logcat-a xehetasunak ikusteko. + Esportatzen… + + Hostalari fitxategia + Hosts fitxategia IP helbideei host izenak ematen dizkien sistemaren fitxategi bat da. Formaturik gabeko testu-fitxategia da, AdAwayk konfiguratzen du. Hauek dira bere lehenengo lerroak: + Hostalari fitxategiaren edukia kargatzen… + Ireki hostalari fitxategia + + + Eguneraketak egiaztatzen + Iturriak berreskuratzen + %s iturria deskargatzen + Lehenetsitako host fitxategira itzultzen + Lehenetsitako host fitxategia zaharberritua + Hostalari agiri estandarra sortzen + eguneratze-jakinarazpen berriak + Hostalari agiri berrienak eskuragarri + Ez da iturriaren eguneraketarik aurkitu + Ez dago Internet elkarketarik + Ez dago Internet elkarketa eskuragarririk + Ez dago iturburu eskuragarririk + Ez dago hostalari ituruburu erdietsigarririk! + Root atzipena ukatua + Onartu root atzipena root aplikaziotik + Arazo bat izan da + Begiratu logcat xehetasun gehiagorako + Gaituta + Hostalari agiri berrienak gaituta + Ezgaituta + Hostalari fitxategi lehenetsia instalatuta + Azken iturriak aplikatu + Hosts fitxategi berri bat sortzen + Hosts fitxategi berri bat kopiatzen + Hosts fitxategiaren kopia egiaztatzen + Hosts fitxategia eguneratuta + VPN konfigurazioa eguneratuta + Zure konfigurazioa aldatuta. Aplikatzea behar da. + Aplikatu + Konfigurazio berria aplikatzen… + Errorea konfigurazio berria aplikatzen. + + + Hosts fitxategiaren helmugarako symlink-a falta da + Zure xedetiko Symlotura /system/etc/hosts-ra ez dago edo okerra da! AdAway-k ez du lan egingo ez bada agiri zuzenera zuzentzen.\n\nNahi duzu symlotura bat sortzen saiatzea? + Symlotura ez dago + Ez dago nahikoa toki partizioan!\nSaiatu xede hostalari agiria aldatzen hobespenetan: /data/data/hosts. + Ez dago nahikoa toki + Jeitsitako agiria ezin da irakurri. + Agiri pribatu hutsegitea + Hutsegitea partizioa idaz/irakurtzekoa bezala ber-muntatzerakoan. + Ber-muntatze hutsegitea + Errorea hosts fitxategia kopiatzen + Hostalari agiri kopiatze hutsegitea! + Kopiatze hutsegitea + Hostalari iturriak aplikatu dira + Ongi ezarri dira + Symlotura ongi sortu da + Symlotura sortze hutsegitea + Mesedez irakurri Laguntza argibide gehiagorako. + APN proxya ezarrita! + Interneteko elkarketa ez dabil. + Ez dago Elkarketarik + Jeisten… + Ezartzen… + Zerrenda-beltza eta Zerrenda-zuria ezartzen + Hostalari agiriak aztertzen eta batzen + Hostalari agiria eraikitzen + Hostalari agiria ezartzen + Errorea hosts fitxategi berria aplikatzen. + Hutsegitea hostalari agiria zure sisteman ezartzerakoan!\nSaiatu xede hostalari agiria aldatzen hobespenetan: /data/data/hosts. + Ezartze hutsegitea + Egiaztatu zure root kudeaketa aplikazioa root sarbidea eman dela ziurtatzeko. + Ongi leheneratu da + Ezin da hosts fitxategia irauli + Leheneratze hutsegitea zergaiti ezezagunengaitik. + Leheneratze hutsegitea! + Zure gaitutako hostalari iturburu bat ere ez da erdiesgarria! Zihur zaude Intenetera egoki elkartuta zaudela? + Jeisketa hutsegitea + Errorea hosts fitxategi pribatu berria idazten + Agiri pribatua ezin da sortu. + Agiri pribatu sortze hutsegitea + Ongi gaitu da + Ongi ezgaitu da + Errorea VPN ad blocking gaitzen. + Errorea VPN ad blocking desgaitzen. + Hosts Magisk modulua gaitzen. + Hosts Magisk modulua desgaitzen. + + Sartu hostalari agirirako URL-a: + Hau ez da baliozko hostalari-izen bat! + Hostalari-izena ezegoki heuskarrituta + Hau ez da baliozko IP bat! + IP-a ezegoki heuskarrituta + Inoiz eguneratu eta ez erakutsi galdera hau hurrengoan! + Gertatzen… + + + Berritu + Gehitu + Laguntza + Segurtasun-kopia inportatu + Segurtasun-kopia esportatu + + + S-ON/S-OFF + SEG + Arazoak + + + Adware + Eskaneatzen… + Ez da Adwarerik topatu! + + + Iragarki blokeatzailea + Ez dago idazki editatzailerik ezarrita + Ez da idazki editatzailerik aurkitu hostalari agiriak irekitzeko. Jota edo beste idazki editatzaile bat ezarri dezakezu hau kudeatzeko.\n\nNahi duzu Jota ezartzea? + Ez dago agiri kudeatzailerik ezarrita + Ez da agiri kudeatzailerik aurkitu hostalari agiriak irekitzeko. OI File Manager edo beste agiri kudeatzaile bat ezarri dezakezu hau kudeatzeko.\n\nNahi duzu OI File Manager ezartzea? + + + Tcpdump + Tcpdump DNS eskabideak monitorizatzeko eta hauek ohar agiri baten gordetzeko tresna bat da. Barrenean hasi dezakezu, iragarkiak erakusten dituzten aplikazioak ekin, eta ondoren DNS eskabideak aztertu ohar agiria erabiliz. Orduan ahalezko iragarki zerbitzaria zerrenda-beltzera gehitu daiteke. + Ezgaitu kontrola + Gaitu kontrola + Erakutsi emaitzak + Ordenatu domeinuak + Garbitu egunkaria + Gehitu sarrera zerrenda-beltzara + Gehitu sarrera zerrenda-zurira + Gehitu sarrera birbidalketa zerrendara + + Testuaren lehentasun-balioa editatu + Ireki menua + Itxi menua + + + + Hasiera + Hostalari iturburuak + Zure zerrendak + Ireki hostalari agiria + Erregistratu DNS eskaerak + Bilatu adware + Hobespenak + Laguntza + + + + + DNS eskaerak + Zure zerrendak + Hobespenak + + + Orain dela %1$sinstalatuta + %1$sarte eguneratuta + %1$srako eguneraketa behar du + Azken eguneraketa duela %1$s + Eguneratze egoera ezezaguna + + minutu %d + %d minutu + + + ordu %d + %d ordu + + + egun %d + %d egun + + + hilabete %d + %d hilabete + + + + abiarazten + aktibo + gelditzen + sareari itxaron + birkonektatzen + birkonekzio errorea + etenda + geldituta + Ad-blocker VPN %1$s + Eten + Ukitu berrekiteko + + + Gaitu eta desgaitu sitemako ad-blocking-a + + diff --git a/app/src/main/res/values-eu/strings_app.xml b/app/src/main/res/values-eu/strings_app.xml new file mode 100644 index 0000000..48ae0e1 --- /dev/null +++ b/app/src/main/res/values-eu/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Kode libreko iragarki-blokeatzailea + AdAway-ren logoa + diff --git a/app/src/main/res/values-eu/strings_errors.xml b/app/src/main/res/values-eu/strings_errors.xml new file mode 100644 index 0000000..b5aaa5a --- /dev/null +++ b/app/src/main/res/values-eu/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Ez dago Internet elkarketarik + Ezin izan da internetera konektatu. Egiaztatu zure gailuaren konexioa. + Huts egin du ostalari-iturburuak deskargatzeak + Gaitutako ostalari-iturburu bat ere ez dago eskuragarri! Egiaztatu intenetera konektatuta zaudela. + + Ezin izan da fitxategi pribatua sortu + Ezin izan da ostalari-iturburu berria idazteko fitxategi pribatua sortu. Egiaztatu gailuak nahikoa toki duela. + Ez dago nahikoa toki + Ezin izan da ostalari-fitxategia sistemaren partiziora kopiatu. Egiaztatu Magisk-en \'systemless\' modulua gaituta dagoela eta berrabiarazi gailua. + Huts egin du ostalari-fitxategi berria instalatzeak + Ezin izan da ostalari-fitxategia /system partiziora kopiatu. Egiaztatu Magisk-en \'systemless\' modulua gaituta dagoela eta berrabiarazi gailua. + Huts egin du ostalari-fitxategia leheneratzeak + Ezin izan dira lehenetsitako ostalari-fitxategiko ezarpenak leheneratu. + + Errorea VPN ad blocking gaitzen. + Egiaztatu zure VPN ezarpenak aplikazioaren VPNa baimentzeko, abiarazi dadin. + Errorea VPN ad blocking desgaitzen. + Egiaztatu zure VPNaren ezarpenak eskuz ezgaitzeko. + diff --git a/app/src/main/res/values-eu/strings_home.xml b/app/src/main/res/values-eu/strings_home.xml new file mode 100644 index 0000000..0102714 --- /dev/null +++ b/app/src/main/res/values-eu/strings_home.xml @@ -0,0 +1,46 @@ + + + + + blokeatuta + baimenduta + birhelbideratzea + + + + %d up-to-date source + %d iturri egunean + + + %d outdated source + %diturri zaharkitu + + Egiaztatu ostalarien eguneraketak + Eguneratu ostalariak + + + Erakutsi DNS eskariak + + + Erakutsi Laguntza\neta aholkuak + + + Ireki GitHub-en orria + + + Lagundu proiektua + + + GitHub proiektua + Hobespenak + + + Ireki nabigazio-tiradera + Eten/Jarraitu irakargien blokeoa + Eguneratu blokeatutako domeinuak + Erakutsi eskatutako domeinuak + + + Irakurri Laguntza argibide gehiagorako. + + \ No newline at end of file diff --git a/app/src/main/res/values-eu/strings_hosts.xml b/app/src/main/res/values-eu/strings_hosts.xml new file mode 100644 index 0000000..79833fe --- /dev/null +++ b/app/src/main/res/values-eu/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Ostalari-iturburuak + + Erabiltzailearen zerrenda + AdAway-ren ostalari ofizialak + StevenBlack-en ostalari bateratuak + Pete Lowe-ren ostalarien blokeo-zerrenda + + ez dago eskuragarri + %s ostalari + + Gehitu iturria + Editatu iturria + URL: (https:// edo file:// baliabidea) + Ostalari-iturburuaren URLa + diff --git a/app/src/main/res/values-eu/strings_lists.xml b/app/src/main/res/values-eu/strings_lists.xml new file mode 100644 index 0000000..68df7ae --- /dev/null +++ b/app/src/main/res/values-eu/strings_lists.xml @@ -0,0 +1,24 @@ + + + Zure zerrendak + Gehitu ostalaria + + blokeatuta + baimenduta + birbideratze + + Iragazi ostalariak + ostalari-izena bilatu… + Txandakatu iturriak + + Gehitu ostalaria zerrenda-beltzara + Gehitu ostalaria zerrenda-zurira + Gehitu birbideratze ostalaria + Editatu zerrenda-beltzeko ostalaria + Editatu zerrenda-zuriko ostalaria + Editatu birbideratzea + Ostalari-izena: + Ostalari-iturburuaren URLa + (* eta ? bezalako komodin karaktereak onartzen dira) + IP-a (IPv4 edo IPv6): + diff --git a/app/src/main/res/values-eu/strings_log.xml b/app/src/main/res/values-eu/strings_log.xml new file mode 100644 index 0000000..acea860 --- /dev/null +++ b/app/src/main/res/values-eu/strings_log.xml @@ -0,0 +1,8 @@ + + + + Ordenatu alfabetikoki + Ordenatu gai-mailako domeinukoki + + Birbideratu domeinua + diff --git a/app/src/main/res/values-eu/strings_notification.xml b/app/src/main/res/values-eu/strings_notification.xml new file mode 100644 index 0000000..26e3400 --- /dev/null +++ b/app/src/main/res/values-eu/strings_notification.xml @@ -0,0 +1,9 @@ + + + + Eguneraketak + eguneratze-jakinarazpen berriak + eguneratze-jakinarazpen berriak + + VPN + \ No newline at end of file diff --git a/app/src/main/res/values-eu/strings_prefs_backup_restore.xml b/app/src/main/res/values-eu/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..13b6233 --- /dev/null +++ b/app/src/main/res/values-eu/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Babes-kopia eta berreskuratzea + Babes-kopia + Egin blokeo-arauen babes-kopia kanpo biltegiratzean + Berreskuratu + Berreskuratu zure blokeo-arauak babes-kopia fitxategitik + diff --git a/app/src/main/res/values-eu/strings_prefs_main.xml b/app/src/main/res/values-eu/strings_prefs_main.xml new file mode 100644 index 0000000..de0d9ef --- /dev/null +++ b/app/src/main/res/values-eu/strings_prefs_main.xml @@ -0,0 +1,6 @@ + + + Hobespenak + + Garbiketa + diff --git a/app/src/main/res/values-eu/strings_prefs_root.xml b/app/src/main/res/values-eu/strings_prefs_root.xml new file mode 100644 index 0000000..b4951ea --- /dev/null +++ b/app/src/main/res/values-eu/strings_prefs_root.xml @@ -0,0 +1,21 @@ + + + Ireki hostalari agiria + Xede hostalari agiria + Ezarpen hau aldatu aurretik, irakurri bere eginkizunari buruz Laguntza. + + /system/etc/hosts + /data/hosts + /data/data/hosts + Norbere xedea + + Norbere xedea + Ezkutatu berrabiarazte elkarrizketa + + Berzuzenketa + IPv4 birbideratzea + IPv6 birbideratzea + + Tokiko Web-zerbitzaria + Gaitu web-zerbitzaria + diff --git a/app/src/main/res/values-eu/strings_prefs_update.xml b/app/src/main/res/values-eu/strings_prefs_update.xml new file mode 100644 index 0000000..0cee9e8 --- /dev/null +++ b/app/src/main/res/values-eu/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Eguneraketak + Jakinarazpenak ezgaituta daude + Ez dira aplikazioaren jakinarazpenak erakutsiko. Sakatu gaitzeko. + + Aplikazioaren eguneraketak + Egiaztatu eguneraketak abiatzean + Egiaztatu eguneraketak egunero + Barne hartu beta bertsioak + + Ostalarien eguneraketak + Egiaztatu eguneraketak abiatzean + Egiaztatu eguneraketak egunero + Sinkronizatu eguneratzean + Sinkronizatu nehurtu gabeko sareetan soilik + diff --git a/app/src/main/res/values-eu/strings_prefs_vpn.xml b/app/src/main/res/values-eu/strings_prefs_vpn.xml new file mode 100644 index 0000000..95172ed --- /dev/null +++ b/app/src/main/res/values-eu/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPNan oinarritutako iragarkien blokeoa + + Gaitu sistemaren abioan + Egin konexioaren segimendua + Egiaztatu noizean behin sarearen egoera VPNa deskonektatzen denean berrabiarazteko. + + Alde batera utzitako aplikazioak + Ezarri zein aplikaziok ez lukeen VPNa erabili beharko konexioa ez blokeatzeko. + Alde batera utzitako sistemaren aplikazioak + + Bat ere ez + Guztia nabigatzaileak izan ezik + Guztia + + Utzi alde batera erabiltzailearen aplikazioak + + + Alde batera utzitako aplikazioak + Hautatu guztia + Utzi guztia hautatzeari + Aplikazioaren ikonoa + diff --git a/app/src/main/res/values-eu/strings_source_edit.xml b/app/src/main/res/values-eu/strings_source_edit.xml new file mode 100644 index 0000000..6d9c413 --- /dev/null +++ b/app/src/main/res/values-eu/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Editatu iturria + Gehitu iturria + + Etiketa + Etiketa beharrezkoa da + Mota + URLa + Fitxategia + Kokalekua + https:// + Kokalekua beharrezkoa da + Sakatu Fitxategia iturburuaren fitxategia hautatzeko + Kokalekua ez da baliozkoa + Zerrendaren formatua + Blokeatu + Baimendu + Aplikatu birbideratutako ostalariak + Ostalarien birbideratzea baimentzeak segurtasun arazoak sor ditzake. Fidagarritzat dituzun iturburuekin soilik erabili ezarpen hau, trafiko sentsitiboa nahi duen zerbitzarira bidal lezakelako. + diff --git a/app/src/main/res/values-eu/strings_support.xml b/app/src/main/res/values-eu/strings_support.xml new file mode 100644 index 0000000..5d32053 --- /dev/null +++ b/app/src/main/res/values-eu/strings_support.xml @@ -0,0 +1,5 @@ + + + Lagundu + Babestu aplikazioa + diff --git a/app/src/main/res/values-eu/strings_update.xml b/app/src/main/res/values-eu/strings_update.xml new file mode 100644 index 0000000..00325f7 --- /dev/null +++ b/app/src/main/res/values-eu/strings_update.xml @@ -0,0 +1,21 @@ + + + AdAway eguneratzea + + Eguneraketa eskuragarri! + + + Egunean zaude + Eguneraketa eskuragarri + AdAway eguneratzen + Eguneratu orain + %1$s / %2$s + Azken aldaketak + Aldaketa-oharra + Babestu garapena + Dirulaguntza + Babesa + + + AdAway-ren azken bertsioa deskargatzen… + diff --git a/app/src/main/res/values-eu/strings_welcome.xml b/app/src/main/res/values-eu/strings_welcome.xml new file mode 100644 index 0000000..4b30b9d --- /dev/null +++ b/app/src/main/res/values-eu/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Ongi etorri + Laguntzailearen lehen pausua + Laguntzailearen bigarren pausua + Laguntzailearen azken pausua + + + Ongi etorri AdAway-ra! + AdAwayk iragarkiak blokeatzeko bi metodo eskaintzen ditu. Aukeratu gustuko duzuna: + + Erro logoa + Erroan oinarritutako blokeoa. + Azkarragoa + Bateriarekiko lagungarria + Erroa beharrezkoa da + + VPN logoa + VPNan oinarritutako blokeoa + Motelagoa + Atzeko planoan exekutatu + Bateragarritasuna + + Beharrezkoa Android errotua + Ezin izan da su binarioa aurkitu edo ez duzu root baimendu AdAway-rako.\n\nGailuaren fitxategi sistemako erroa atzitu ezin denean gerta daiteke. wiki.lineageos.org edo Android-i buruzko beste webgune batzuetan aurki dezakezu gailuaren fitxategi sistemako erroa nola atzitu. + + Alde + Kontra + + + Sinkroinazioa eginda + Errorea sinkronizatze-prozesuan + + Sinkronizatzen + Sinkronizatuta! + AdAway-k blokeatzeko iragarki-sareak deskargatzen ditu. Ezarpenetan moldatu ditzazkezu beranduago. + Saiatu berriro sinkronizatzen + Huts egin du %1$s sinkronizatzeak. Berriro saiatu? + Jakinarazpenak bidal ditzakezu iragarkien eta kontrolaren blokeo-egoera erakusteko, bai eta eskuragarri dagoen aplikazioaren eguneratzearen berri emateko ere (gutxi batzuk urtean). Gaitu egunean egon nahi baduzu. + + + Lagundu + Lagundu nazazu! + AdAway doako aplikazioa da, kode irekikoa, eta aisialdian garatzen dudana. Gogoko baduzu, erakutsi zure babesa: + Lagundu PayPal-en bidez + Zorriak gogoko al dituzu? Nik ere ez. + Gaitu telemetria erroreen erregistroak bidaltzeko + + + Atzera + Hurrengoa + Amaitu + diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml new file mode 100644 index 0000000..fb0d377 --- /dev/null +++ b/app/src/main/res/values-fa/strings.xml @@ -0,0 +1,139 @@ + + + + خروج + بستن + بله + خیر + اضاÙÙ‡ کردن + لغو + ذخیره + راهنما + + + خوش آمدید! + AdAway یک نرم Ø§ÙØ²Ø§Ø± مجانی Ùˆ اوپن سورس است Ú©Ù‡ به منظور بلاک کردن تبلیغات طراحی شده است.این برنامه آدرس های شبکه تبلیغات را واکشی میکند تا آنها را بر روی دستگاه شما بلاک کند./میخواهید بیشتر بدانید؟راهنمای زیر را بخوانید! + راهنمایی بیشتر + وضعیت به روزرسانی + تمامی ÙØ§ÛŒÙ„های hosts جدید از منابع تعری٠شده Ø¯Ø±ÛŒØ§ÙØª شدند Ùˆ با لیستی Ú©Ù‡ از قبل موجود بوده است در یک قالب یک ÙØ§ÛŒÙ„ hosts واحد یکی شدند. + ÙØ¹Ø§Ù„سازی توق٠تبلیغات + غیر ÙØ¹Ø§Ù„ کردن برنامه ضد تبلیغات + وب سرور + در حال اجرا + متوق٠شده + ÙØ¹Ø§Ù„سازی وب سرور + ØºÛŒØ±ÙØ¹Ø§Ù„سازی وب سرور + + ویرایش ورودی + اعمال تغییرات + ویرایش + حذ٠کردن + + + بارگیری… + ÙØ§ÛŒÙ„ پشتیبانی با موÙقیت از کارت Ø­Ø§ÙØ¸Ù‡ شما بارگذاری شد. + بارگذاری ÙØ§ÛŒÙ„ پشتبانی با شکست مواجه شد. ÙØ±Ù…ت ÙØ§ÛŒÙ„ درست است؟ ÙØ§ÛŒÙ„ ثبت رویدادها رو Ú†Ú© کنید. + در حال خروجی Ú¯Ø±ÙØªÙ†â€¦ + + ÙØ§ÛŒÙ„ هاست ها + ÙØ§ÛŒÙ„ هاست ها یک ÙØ§ÛŒÙ„ سیستمی است Ú©Ù‡ نام هاست ها را به Ø¢ÛŒ Ù¾ÛŒ آدرس ها مرتبط میکند.این یک ÙØ§ÛŒÙ„ متنی ساده است Ú©Ù‡ توسط AdAway تنظیم شده است.در اینجا چند خط ابتدایی آن را داریم: + بارگذاری محتوای ÙØ§ÛŒÙ„ هاست… + بازکردن هاست ÙØ§ÛŒÙ„ + + ایجاد ÙØ§ÛŒÙ„ hosts استاندارد + به روز رسانی موجود میباشد + ÙØ§ÛŒÙ„های hosts جدیدتری موجود میباشد + اتصال اینترنت برقرار نیست + اتصال اینترنت موجود نیست + منابع موجود نیستند + منابع hosts ها در درسترس نیستند! + دسترسی روت رد شد + از طریق برنامه روت خود به این برنامه دسترسی روت دهید + مشکلی پیش آمد + ÙØ§ÛŒÙ„ ثبت رویدادها رو Ú†Ú© کنید + ÙØ¹Ø§Ù„ + ÙØ§ÛŒÙ„ های hosts جدید ÙØ¹Ø§Ù„ شد + غیر ÙØ¹Ø§Ù„ + هاست ÙØ§ÛŒÙ„‌های Ù¾ÛŒØ´ÙØ±Ø¶ نصب شدند + اعمال تغییرات + پیوند نمادین از هد٠شما به /system/etc/hosts وجود ندارد Ùˆ یا درست نمیباشد! اگر مسیر ÙØ§ÛŒÙ„ به درستی تنظیم نشده باشد برنامه AdAway به درستی کار نخواهد کرد.\n\nآیا مایلید Ú©Ù‡ یک پیوند نمادین ایجاد نمایید؟ + پیوند نمادین موجود نیست + ÙØ¶Ø§ÛŒ کاÙÛŒ در پارتیشن موجود نیست!\nسعی نمایید مسیر ÙØ§ÛŒÙ„ hosts را در تنظیمات به /data/data/hosts تغییر دهید. + ÙØ¶Ø§ÛŒ کاÙÛŒ موجود نیست + ÙØ§ÛŒÙ„ دانلود شده قابل خواندن نیست. + ÙØ§ÛŒÙ„ خصوصی ایراد دارد + بارگیری پارتیشن برای خواندن/نوشتن ناموÙÙ‚ بود! + بارگیری ناموÙÙ‚ + Ú©Ù¾ÛŒ کردن ÙØ§ÛŒÙ„ hosts ناموÙÙ‚! + Ú©Ù¾ÛŒ ناموÙÙ‚ + اعمال موÙقیت آمیز + ایجاد موÙÙ‚ پیوند نمادین + ایجاد ناموÙÙ‚ پیوند نمادین + Ù„Ø·ÙØ§ برای اطلاعات بیشتر به راهنما مراجعه نمایید. + تنظیم پروکسی APN! + اتصال اینترنت بر قرار نیست + اتصال برقرار نیست + در حال Ø¯Ø±ÛŒØ§ÙØªâ€¦ + در حال اعمال… + اعمال لیست سیاه Ùˆ لیست سÙید + تجزیه Ùˆ ادغام ÙØ§ÛŒÙ„ های hosts + ساختن ÙØ§ÛŒÙ„ hosts + اعمال ÙØ§ÛŒÙ„ hosts + اعمال ناموÙÙ‚ ÙØ§ÛŒÙ„ hosts بر روی سیستم!\n\nمسیر ÙØ§ÛŒÙ„ hosts را در تنظیمات /data/data/hosts تغییر دهید. + اعمال ناموÙÙ‚ تغییرات + Ù„Ø·ÙØ§ برنامه مدیریت روت خود رو بررسی کنیدتا از دسترسی داشتن این برنامه به روت مطمئن شید. + بازنشانی موÙÙ‚ آمیز + بازنشانی نا موÙÙ‚ به دلایل ناشناخته. + بازنشانی ناموÙÙ‚ + هیچ یک از منابع hosts های انتخابی شما در دسترس نیستند! آیا از اتصال دستگاه خود به اینترنت مطمئن هستید؟ + خطا در Ø¯Ø±ÛŒØ§ÙØª + ÙØ§ÛŒÙ„ های خصوصی نمیتواند ایجاد گردد. + ایجاد ناموÙÙ‚ ÙØ§ÛŒÙ„ خصوصی + ÙØ¹Ø§Ù„ کردن با موÙقیت انجام شد + غیر ÙØ¹Ø§Ù„ کردن با موÙقیت انجام شد + + تارنما به ÙØ§ÛŒÙ„ hosts وارد نمایید + این یک hostname مجاز نیست + hostname با ÙØ±Ù…ت نادرست + این یک Ø¢ÛŒ Ù¾ÛŒ مجاز نیست! + Ø¢ÛŒ Ù¾ÛŒ با ÙØ±Ù…ت نادرست + در حال بارگیری… + + + تازه کردن + اضاÙÙ‡ کردن + راهنما + بارگذاری ÙØ§ÛŒÙ„ پشتیبان + خروجی Ú¯Ø±ÙØªÙ† ÙØ§ÛŒÙ„ پشتیبانی + + + S-روشن/S-خاموش + پرسش Ùˆ پاسخ + مشکلات + + + Adware + + مسدودگر تبلیغات + هیچ ویرایشگر متنی نصب نیست + هیچ برنامه ویرایشگر متنی برای باز کردن این ÙØ§ÛŒÙ„ ÛŒØ§ÙØª نشد. شما میتوانید از برنامه Jota یا دیگر برنامه های ویرایشگر متن برای حل این مشکل Ø§Ø³ØªÙØ§Ø¯Ù‡ نمایید.\n\nآیا مایل به نصب برنامه Jota هستید؟ + هیچ برنامه مدیریت ÙØ§ÛŒÙ„ÛŒ نصب نیست + هیچ برنامه مدیریت ÙØ§ÛŒÙ„ÛŒ برای باز کردن این ÙØ§ÛŒÙ„ ÛŒØ§ÙØª نشد. شما میتوانید از برنامه OI File Manager یا برنامه های مشابه برای حل این مشکل Ø§Ø³ØªÙØ§Ø¯Ù‡ نمایید.\n\nآیا مایل به نصب برنامه OI File Manager هستید؟ + + Tcpdump یک ابزاری برای نظارت بر روی درخواست های دی ان اس بوده Ùˆ آنها در ÙØ§ÛŒÙ„ گزارشات ذخیره مینماید. شما میتوانید آن را در پس زمینه اجرا نمایید، برنامه ای Ú©Ù‡ تبلیغات را نشان میدهد را اجرا نموده Ùˆ بعدا در ÙØ§ÛŒÙ„ گزارشات درخواست های دی ان اس را بررسی Ùˆ آنالیز نمایید. سرور تبلیغات مشکوک را میتوانید در لیست سیاه اضاÙÙ‡ نمایید. + نمایش نتایج + پاک کردن رویدادها + + + Home + منابع Hosts + Your lists + باز کردن ÙØ§ÛŒÙ„ hosts + Log DNS requests + Scan for adware + تنظیمات + راهنما + + تنظیمات + + diff --git a/app/src/main/res/values-fa/strings_app.xml b/app/src/main/res/values-fa/strings_app.xml new file mode 100644 index 0000000..710ffc4 --- /dev/null +++ b/app/src/main/res/values-fa/strings_app.xml @@ -0,0 +1,6 @@ + + + مسدود کننده تبلیغات AdAway + مسدود کننده تبلیغات منبع باز + نماد برنامه AdAway + diff --git a/app/src/main/res/values-fa/strings_errors.xml b/app/src/main/res/values-fa/strings_errors.xml new file mode 100644 index 0000000..b4040d0 --- /dev/null +++ b/app/src/main/res/values-fa/strings_errors.xml @@ -0,0 +1,22 @@ + + + + اتصال اینترنت برقرار نیست + امکان برقراری اتصال به اینترنت وجود ندارد Ù„Ø·ÙØ§ اتصال گوشی خود را بررسی کنید + منبع hosts دانلود نشد + هیچ یک از منابع hosts ÙØ¹Ø§Ù„ شما در دسترس نیست Ù„Ø·ÙØ§ بررسی کنید Ú©Ù‡ به درستی به اینترنت متصل هستید + + ÙØ§ÛŒÙ„ خصوصی ساخته نشد + امکان ساخت یک ÙØ§ÛŒÙ„ خصوصی برای ساخت یک منبع hosts جدید وجود ندارد Ù„Ø·ÙØ§ ÙØ¶Ø§ÛŒ خالی موجود در گوشی خود را بررسی کنید + ÙØ¶Ø§ÛŒ کاÙÛŒ موجود نیست + امکان Ú©Ù¾ÛŒ ÙØ§ÛŒÙ„ hosts به پارتیشن سیستم شما وجود ندارد Ù„Ø·ÙØ§ بررسی کنید Ú©Ù‡ ماژول بدون سیستم Magisk ÙØ¹Ø§Ù„ است Ùˆ سپس گوشی خود را خاموش Ùˆ روشن کنید + ÙØ§ÛŒÙ„ hosts جدید نصب نشد + Ú©Ù¾ÛŒ ÙØ§ÛŒÙ„ hosts در پارتیشن سیستم / امکان پذیر نیست Ù„Ø·ÙØ§ بررسی کنید Ú©Ù‡ ماژول بدون سیستم Magisk ÙØ¹Ø§Ù„ است Ùˆ سپس گوشی خود را خاموش Ùˆ روشن کنید + ÙØ§ÛŒÙ„ hosts بازگردانده نشد + نمی توان پیکربندی ÙØ§ÛŒÙ„ hosts Ù¾ÛŒØ´â€ŒÙØ±Ø¶ را بازیابی کرد + + مسدود کننده تبلیغات VPN ÙØ¹Ø§Ù„ نشد + Ù„Ø·ÙØ§ تنظیمات VPN خود را بررسی کنید تا برنامه VPN شروع به کار کند + مسدود کننده تبلیغات VPN ØºÛŒØ±ÙØ¹Ø§Ù„ نشد + Ù„Ø·ÙØ§ تنظیمات VPN خود را بررسی کنید تا آن را به صورت دستی ØºÛŒØ±ÙØ¹Ø§Ù„ کنید + diff --git a/app/src/main/res/values-fa/strings_home.xml b/app/src/main/res/values-fa/strings_home.xml new file mode 100644 index 0000000..fb64ef3 --- /dev/null +++ b/app/src/main/res/values-fa/strings_home.xml @@ -0,0 +1,46 @@ + + + + + مسدود شده + اجازه داده شده + منتقل شده + + + + %d up-to-date source + %d منابع به روز + + + %d outdated source + %d منابع قدیمی + + بررسی به روز رسانی hosts + به روز رسانی hosts + + + نمایش گزارش درخواست DNS + + + نمایش راهنما Ùˆ نکات + + + باز کردن ØµÙØ­Ù‡ گیت هاب + + + حمایت از پروژه + + + پروژه گیت هاب + تنظیمات + + + کشوی ناوبری را باز کنید + توق٠/ ادامه مسدودسازی تبلیغات + به روز رسانی دامنه های مسدود شده + نمایش دامنه های درخواستی + + + Ù„Ø·ÙØ§ برای اطلاعات بیشتر به راهنما مراجعه نمایید. + + \ No newline at end of file diff --git a/app/src/main/res/values-fa/strings_hosts.xml b/app/src/main/res/values-fa/strings_hosts.xml new file mode 100644 index 0000000..2433bc1 --- /dev/null +++ b/app/src/main/res/values-fa/strings_hosts.xml @@ -0,0 +1,17 @@ + + + منابع Hosts + + Ùهرست کاربر + hosts رسمی AdAway + hosts یکپارچه StevenBlack + hosts لیست مسدود کردن Pete Lowe + + موجود نیست: + %s hosts + + Ø§ÙØ²ÙˆØ¯Ù† منبع + ویرایش منبع + لینک : (a https:// or file:// resource) + لینک منبع hosts + diff --git a/app/src/main/res/values-fa/strings_lists.xml b/app/src/main/res/values-fa/strings_lists.xml new file mode 100644 index 0000000..826ec07 --- /dev/null +++ b/app/src/main/res/values-fa/strings_lists.xml @@ -0,0 +1,24 @@ + + + لیست های شما + Ø§ÙØ²ÙˆØ¯Ù† host + + مسدود شده + اجازه داده شده + منتقل شده + + Ùیلتر hosts + جستجوی نام host … + تغییر وضعیت منابع + + Ø§ÙØ²ÙˆØ¯Ù† host به لیست سیاه + Ø§ÙØ²ÙˆØ¯Ù† host به لیست سÙید + Ø§ÙØ²ÙˆØ¯Ù† تغییر مسیر host + ویرایش host موجود در لیست سیاه + ویرایش host موجود در لیست سÙید + ویرایش Ùˆ تغییر مسیر + نام Host : + لینک منبع hosts + (کاراکترهای جامع * Ùˆ ØŸ مجاز هستند) + IP (IPv4 یا IPv6) : + diff --git a/app/src/main/res/values-fa/strings_log.xml b/app/src/main/res/values-fa/strings_log.xml new file mode 100644 index 0000000..2597eea --- /dev/null +++ b/app/src/main/res/values-fa/strings_log.xml @@ -0,0 +1,11 @@ + + + تغییر وضعیت ثبت گزارش + برای شروع گزارش درخواست‌ ها درباره مرور وب یا Ø§Ø³ØªÙØ§Ø¯Ù‡ از برنامه‌ ها دکمه ثبت را ÙØ´Ø§Ø± دهید سپس به عقب برگردید یا برای تازه سازی ØµÙØ­Ù‡ گزارش‌ ها انگشت خود را به پایین بکشید + درخواست های مسدود شده گزارش نمی شوند اگر می‌خواهید آن‌ ها را نیز وارد کنید ابتدا مسدود کردن تبلیغات را ØºÛŒØ±ÙØ¹Ø§Ù„ کنید. + + مرتب‌سازی بر اساس Ø­Ø±ÙˆÙ Ø§Ù„ÙØ¨Ø§ + مرتب سازی دامنه سطح بالا + + تغییر مسیر دامنه + diff --git a/app/src/main/res/values-fa/strings_notification.xml b/app/src/main/res/values-fa/strings_notification.xml new file mode 100644 index 0000000..e8e081b --- /dev/null +++ b/app/src/main/res/values-fa/strings_notification.xml @@ -0,0 +1,13 @@ + + + + به روز رسانی ها + اطلاعیه های به روز رسانی جدید + به روز رسانی منبع موجود است + ÙØ§ÛŒÙ„ های hosts جدید برای دانلود در دسترس هستند + به روز رسانی برنامه موجود است + نسخه جدید AdAway برای دانلود در دسترس است + + VPN + اعلان در حال اجرای VPN + diff --git a/app/src/main/res/values-fa/strings_prefs_backup_restore.xml b/app/src/main/res/values-fa/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..e2e9fea --- /dev/null +++ b/app/src/main/res/values-fa/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + پشتیبان گیری Ùˆ بازگردانی + پشتیبان گیری + از قوانین مسدود سازی در Ø­Ø§ÙØ¸Ù‡ خارجی یک نسخه پشتیبان گیری شده تهیه کنید + بازگردانی + قوانین مسدود سازی را از طریق ÙØ§ÛŒÙ„ پشتیبان گیری شده بازیابی کنید + diff --git a/app/src/main/res/values-fa/strings_prefs_main.xml b/app/src/main/res/values-fa/strings_prefs_main.xml new file mode 100644 index 0000000..05040a3 --- /dev/null +++ b/app/src/main/res/values-fa/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + تنظیمات + + عمومی + پس زمینه سیاه + + سÙید + سیاه + پیش ÙØ±Ø¶ سیستم + + به روز رسانی های خودکار + + مسدود کردن تبلیغات + مسدود کننده تبلیغات مبتنی بر روت + مسدود کننده تبلیغات مبتنی بر VPN + ÙØ¹Ø§Ù„ کردن پشتیبانی از IPv6 + پشتیبان گیری / بازیابی از قوانین مسدود کردن + + عیب یابی + ارسال گزارش خرابی + گزارش به نگهبان (sentry.io) + در این نسخه پشتیبانی نمی شود + ثبت نام کامل + برای انجام به خاموش Ùˆ روشن کردن گوشی نیاز است + diff --git a/app/src/main/res/values-fa/strings_prefs_root.xml b/app/src/main/res/values-fa/strings_prefs_root.xml new file mode 100644 index 0000000..401d152 --- /dev/null +++ b/app/src/main/res/values-fa/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + مسدود کننده تبلیغات مبتنی بر روت + + نصب Hosts + باز کردن ÙØ§ÛŒÙ„ hosts + Ù‡Ø¯Ù ÙØ§ÛŒÙ„ hosts + قبل از Ø§Ø³ØªÙØ§Ø¯Ù‡ از این ویژگی راهنما را بخوانید + + /system/etc/hosts + /data/hosts + /data/data/hosts + Ù‡Ø¯Ù Ø³ÙØ§Ø±Ø´ÛŒ + + مکان Ù‡Ø¯Ù Ø³ÙØ§Ø±Ø´ÛŒ + مخÙÛŒ کردن Ú¯ÙØªÚ¯ÙˆÛŒ خاموش Ùˆ روشن کردن گوشی بعد از انجام + + تغییر مسیر + تعیین کنید Ú©Ù‡ hosts مسدود شده به کجا منتقل شود + پیکربندی تغییر مسیر IPv4 + پیکربندی تغییر مسیر IPv6 + تغییر مسیر نامعتبر است + + وب سرور محلی + وب سرور محلی به آدرس های IP محلی گوش Ù…ÛŒ دهد تا به درخواست های نام host مسدود شده پاسخ دهد Ùˆ ممکن است به مسدود شدن برنامه در اتصال مسدود شده Ú©Ù…Ú© کند + ÙØ¹Ø§Ù„ کردن وب سرور + آزمایش وب سرور + نصب گواهی امضا شده شما + نصب دستی گواهی + از اندروید 11 (R) به بعد برنامه دیگر نمی تواند به طور خودکار مرجع گواهی (CA) را نصب کند برای برطر٠شدن این مشکل به تنظیمات گوشی / \"امنیت\" / \"رمزگذاری Ùˆ اعتبار\" Ùˆ سپس \"نصب گواهی\" بروید از آنجا \" گواهی CA\" را انتخاب کنید Ùˆ ÙØ§ÛŒÙ„ گواهی صادر شده جدید را انتخاب کنید + باز کردن تنظیمات امنیت + در حال بررسی ..‌. + در حال اجرا نیست + در حال اجرا است اما گواهی نصب نشده + در حال اجرا است Ùˆ گواهی نصب شده + ÙØ¶Ø§ÛŒ خالی تبلیغات را با نماد برنامه جایگزین کنید + diff --git a/app/src/main/res/values-fa/strings_prefs_update.xml b/app/src/main/res/values-fa/strings_prefs_update.xml new file mode 100644 index 0000000..1b06ff9 --- /dev/null +++ b/app/src/main/res/values-fa/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + به روز رسانی ها + اعلان ها ØºÛŒØ±ÙØ¹Ø§Ù„ هستند + اعلان‌ های برنامه نمایش داده نمی‌شوند برای ÙØ¹Ø§Ù„ کردن آن ها ÙØ´Ø§Ø± دهید + + به روز رسانی های برنامه + بررسی به روز رسانی در استارت آپ + به صورت دوره ای به روز رسانی را بررسی کنید + شامل نسخه های بتا + + به روز رسانی های Hosts + بررسی به روز رسانی در استارت آپ + به صورت دوره ای به روز رسانی را بررسی کنید + همگام سازی در به روز رسانی + Ùقط در شبکه بدون اندازه‌ گیری همگام‌ سازی شود + diff --git a/app/src/main/res/values-fa/strings_prefs_vpn.xml b/app/src/main/res/values-fa/strings_prefs_vpn.xml new file mode 100644 index 0000000..bf23f35 --- /dev/null +++ b/app/src/main/res/values-fa/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + مسدود کننده تبلیغات مبتنی بر VPN + + ÙØ¹Ø§Ù„ کردن در هنگام استارت آپ + نظارت بر اتصال + به طور دوره ای وضعیت شبکه را بررسی کنید تا VPN در صورت قطع اتصال دوباره متصل شود + + برنامه های کاربردی استثنا شده + پیکربندی کنید Ú©Ù‡ کدام برنامه ها نباید از VPN Ø§Ø³ØªÙØ§Ø¯Ù‡ کنند تا هیچ اتصالی مسدود نشود + استثنا کردن برنامه های سیستمی + + هیچ کدام + همه به جز مرورگر ها + همه + + استثنا کردن برنامه های کاربر + + + برنامه های کاربردی استثنا شده + انتخاب همه + لغو انتخاب همه + نماد برنامه + diff --git a/app/src/main/res/values-fa/strings_source_edit.xml b/app/src/main/res/values-fa/strings_source_edit.xml new file mode 100644 index 0000000..becf539 --- /dev/null +++ b/app/src/main/res/values-fa/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + ویرایش منبع + Ø§ÙØ²ÙˆØ¯Ù† منبع + + برچسب + برچسب لازم است + بنویسید + لینک + ÙØ§ÛŒÙ„ + مکان + https:// + مکان لازم است + برای انتخاب ÙØ§ÛŒÙ„ منبع ÙØ§ÛŒÙ„ را ÙØ´Ø§Ø± دهید + مکان نامعتبر است + قالب Ùهرست + مسدود کردن + اجازه + انجام انتقال hosts + اجازه دادن به hosts منتقل شده ممکن است باعث ایجاد مشکلات امنیتی شود از این تنظیمات Ùقط در یک منبع قابل اعتماد Ø§Ø³ØªÙØ§Ø¯Ù‡ کنید زیرا Ù…ÛŒ تواند برخی از تراÙیک حساس را به هر سروری Ú©Ù‡ Ù…ÛŒ خواهد هدایت کند + diff --git a/app/src/main/res/values-fa/strings_support.xml b/app/src/main/res/values-fa/strings_support.xml new file mode 100644 index 0000000..c9066eb --- /dev/null +++ b/app/src/main/res/values-fa/strings_support.xml @@ -0,0 +1,5 @@ + + + حمایت + یک حامی مالی شوید + diff --git a/app/src/main/res/values-fa/strings_update.xml b/app/src/main/res/values-fa/strings_update.xml new file mode 100644 index 0000000..40f45de --- /dev/null +++ b/app/src/main/res/values-fa/strings_update.xml @@ -0,0 +1,22 @@ + + + به روز رسانی AdAway + + به روز رسانی موجود است + + + شما به روز هستید + به روز رسانی موجود است + در حال به روز رسانی AdAway + اکنون به روز رسانی کنید + %1$s / %2$s + کامل + آخرین تغییرات + گزارش تغییرات + پشتیبانی از توسعه + حمایت مالی + حامی مالی + + + در حال دانلود آخرین نسخه AdAway … + diff --git a/app/src/main/res/values-fa/strings_welcome.xml b/app/src/main/res/values-fa/strings_welcome.xml new file mode 100644 index 0000000..1ded78e --- /dev/null +++ b/app/src/main/res/values-fa/strings_welcome.xml @@ -0,0 +1,53 @@ + + + خوش آمدید + اولین قدم جادوگر + گام دوم جادوگر + آخرین مرحله جادوگر + + + به برنامه AdAway مسدود کننده تبلیغات خوش آمدید + برنامه AdAway به دو روش ویژگی مسدود کردن تبلیغات را ارائه Ù…ÛŒ دهد Ù„Ø·ÙØ§ یکی از روش ها را انتخاب کنید : + + نماد روت + مسدود کردن تبلیغات با Ø§Ø³ØªÙØ§Ø¯Ù‡ از روت + سریع تر + سازگار با باتری + نیاز به روت دارد + + نماد vpn + مسدود کردن تبلیغات مبتنی بر VPN + کند تر + اجرا در پس زمینه + سازگاری + + به گوشی اندروید روت شده نیاز دارد + دسترسی روت به AdAway داده نشده یا باینری پیدا نشد این Ø§ØªÙØ§Ù‚ ممکن است زمانی Ø§ØªÙØ§Ù‚ Ø¨ÛŒÙØªØ¯ Ú©Ù‡ دستگاه شما روت نشده باشد شما Ù…ÛŒ توانید اطلاعات مورد نظر در مورد روش روت کردن گوشی خود را در سایت wiki.lineageos.org یا سایر سایت های اندروید پیدا کنید + + حرÙÙ‡ ای + همراه هم + + + همگام سازی انجام شد + خطا در هنگام همگام سازی + + در حال همگام سازی + همگام سازی شد + AdAway شبکه های تبلیغاتی را دانلود کرده Ùˆ آن ها را مسدود خواهد کرد شما Ù…ÛŒ توانید آن ها را در تنظیمات برنامه Ø³ÙØ§Ø±Ø´ÛŒ کنید + دوباره همگام سازی کنید + همگام‌ سازی انجام نشد : %1$s آیا دوباره امتحان می‌کنید؟ + این گزینه اعلان‌ هایی را برای نمایش وضعیت مسدود کردن تبلیغات Ùˆ مدیریت Ùˆ اطلاع‌ رسانی در مورد به‌ روز رسانی برنامه (تا چندین سال) ارسال کند اگر می‌خواهید به‌ روز بمانید آن‌ها را ÙØ¹Ø§Ù„ کنید + + + حمایت + حمایت از من + AdAway یک برنامه رایگان Ùˆ منبع باز است Ú©Ù‡ در اوقات ÙØ±Ø§ØºØª خود توسعه Ù…ÛŒ دهم اگر از آن لذت Ù…ÛŒ برید‌ با Ú©Ù…Ú© مالی از طریق Ù¾ÛŒ پال از توسعه برنامه حمایت کنید + Ú©Ù…Ú© مالی در Ù¾ÛŒ پال + آیا شما اشکالات را دوست دارید؟ من هم نه + ÙØ¹Ø§Ù„ کردن ارسال گزارش‌ های خرابی تله‌ متری + + + بازگشت + بعدی + پایان + diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml new file mode 100644 index 0000000..0761ee4 --- /dev/null +++ b/app/src/main/res/values-fi/strings.xml @@ -0,0 +1,182 @@ + + + + Sulje + Sulje + Kyllä + Ei + Lisää + Peruuta + Tallenna + Ohjeet + + + Tervetuloa! + Näytä enemmän ohjeita + Päivityksen tila + Kaikki hosts-tiedostot määritellyistä lähteistä ovat ladattu, yhdistyi luetteloihin ja asenettu yhdeksi hosts-tiedostoksi. + Web-palvelin + Käynnissä + Pysäytetty + Ota web-palvelin käyttöön + Ota web-palvelin pois käytöstä + VPN + Käynnissä + Pysäytetty + Aktivoi VPN + + Muokka merkintää + Hyväksy + Muokkaa + Poista + + + Tuodaan… + Varmuuskopion tuominen epäonnistui. Onko formaatti oikea? Tarkista logcat saadaksesi lisätietoja. + Viedään… + + Hosts-tiedosto + Avaa hosts-tiedosto + + + Tarkistetaan päivityksiä + Noudetaan lähteitä + Ladataan lähdettä %s + Luetaan lähdettä %s + Käsitellään lähdettä %s + Luodaan vakio-hosts-tiedostoa + Päivitys saatavilla + Uudempia hosts-tiedostoja on saatavilla + Ei verkkoyhteyttä + Verkkoyhtyettä ei ole saatavilla + Lähteet eivät ole käytettävissä + Hosts-lähteet eivät ole tavoitettavissa! + + Jokin meni pieleen + Käytössä + Uusimmat hosts-tiedostot ovat käytössä + Pois käytöstä + Hyväksy + Symbolista linkkiä kohteeseen /system/etc/hosts ei ole olemassa tai se on virheellinen! AdAway ei toimi, jos se ei osoita oikeaan tiedostoon.\n\nHaluatko yrittää luoda symbolisen linkin? + Symbolinen linkki puuttuu + Ei tarpeeksi tilaa osiossa!\nYritä muuttaa asetuksissa hosts-tiedoston kohde /data/data/hosts -vaihtoehdoksi. + Ei tarpeeksi tilaa + Ladattua tiedostoa ei voitu lukea. + Yksityinen tiedosto hylätty + Osion kokoaminen luku/kirjoitus-tilaksi epäonnistui! + Uudelleenkokoaminen epäonnistui + Hosts-tiedoston kopiointi epäonnistui! + Kopiointi epäonnistui + Soveltaminen onnistui + Symbolisen linkin luominen onnistui + Symbolisen linkin luominen epäonnistui + Lue ohjeet, jos haluat lisätietoja. + APN-välityspalvelin on asetettu! + Yhteys internettiin ei toimi. + Ei yhteyttä + Ladataan… + Hyväksytään… + Mustan listan ja valkoisen listan soveltaminen + Hosts-tiedostojen jäsentäminen ja yhdistäminen + Luodaan hosts-tiedostoa + Hyväksytään hosts-tiedosto + Hosts-tiedoston soveltaminen epäonnistui!\nYritä muuttaa hosts-tiedoston kohde /data/data/hosts -vaihtoehdoksi. + Soveltaminen epäonnistui + Palauttaminen onnistui + Palauttaminen epäonnistui tuntemattomasta syystä. + Palauttaminen epäonnistui! + Mikään käytössä olevista hosts-lähteistä ei ole tavoitettavissa! Onko sinulla verkkoyhteys? + Lataus epäonnistui + Yksityistä tiedostoa ei voi luoda. + Yksityisen tiedoston luominen epäonnistui + Käyttöönotto onnistui + Kytketty pois päältä + + Kirjoita hosts-tiedoston URL-osoite: + Tämä ei ole kelvollinen host-nimi! + Väärin muotoiltu host-nimi + Tämä ei ole kelvollinen IP-osoite! + Väärin muotoiltu iP + Ladataan… + + + Päivitä + Lisää + Ohjeet + Tuo varmuuskopio + Vie varmuuskopio + + + S-ON/S-OFF + FAQ + Ongelmat + + + Mainosohjelma + Tarkistetaan… + Adaware-sovellusta ei löydy! + + + Mainosten esto + Ei tekstieditoria asennettuna + Ei voitu avata hosts-tiedostoa, koska tekstieditoria ei löytynyt. Voit asentaa Jota tai toisen tekstieditorin.\n\nHaluatko asentaa Jota-sovelluksen? + Tiedostohallintasovellusta ei ole asennettu + Ei voitu avata tiedostoja, koska tiedostonhallintasovellusta ei löytynyt. Voit asentaa OI File Manager:n tai muun tiedostohallintasovelluksen.\n\nHaluatko asentaa OI File Manager:n? + + + Tcpdump + Tcpdump on työkalu, jolla voit seurata DNS-pyyntöjä ja tallentaa ne lokitiedostoon. Voit käynnistää sen taustalla, käyttää sovelluksia, jotka näyttävät mainoksia ja sen jälkeen analysoida DNS-pyyntöjä käyttäen lokitiedostoa. Mahdolliset mainospalvelimet voidaan sitten lisätä mustalle listalle. + Salli tarkkailu + Näytä tulokset + Tyhjennä loki + Avaa valikko + Sulje valikko + + + + Koti + Hosts-lähteet + Luettelosi + Avaa hosts-tiedosto + Log DNS requests + Scan for adware + Asetukset + Ohjeet + + + + + DNS-pyynnöt + Luettelosi + Asetukset + + muutama minuutti + + %d minuutti + %d minuuttia + + + %d tunti + %d tuntia + + + %d päivä + %d päivää + + + %d kuukausi + %d kuukautta + + + + käynnistetään + aktiivinen + pysäytetään + odotetaan verkkoa + uudelleen yhdistetään + tauotettu + pysäytetty + Tauko + Paina jatkaakseen + + diff --git a/app/src/main/res/values-fi/strings_app.xml b/app/src/main/res/values-fi/strings_app.xml new file mode 100644 index 0000000..1910e53 --- /dev/null +++ b/app/src/main/res/values-fi/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Avoimen lähdekoodin mainosesto + AdAway-logo + diff --git a/app/src/main/res/values-fi/strings_errors.xml b/app/src/main/res/values-fi/strings_errors.xml new file mode 100644 index 0000000..59fabfb --- /dev/null +++ b/app/src/main/res/values-fi/strings_errors.xml @@ -0,0 +1,9 @@ + + + + Ei verkkoyhteyttä + Isäntätiedoston lähteen lataaminen epäonnistui + Ei tarpeeksi tilaa + Uuden hosts-tiedoston asentaminen epäonnistui + Host-tiedoston palauttaminen epäonnistui + \ No newline at end of file diff --git a/app/src/main/res/values-fi/strings_home.xml b/app/src/main/res/values-fi/strings_home.xml new file mode 100644 index 0000000..3f8db40 --- /dev/null +++ b/app/src/main/res/values-fi/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Estetty + Sallittu + Ohjattu + + + + %d up-to-date source + %d lähdettä ajan tasalla + + + %d outdated source + %d vanhentunutta lähdettä + + Tarkista hosts-päivitykset + Päivitä hosts-tiedot + + + Näytä DNS-pyyntöhistoria + + + Näytä ohje\nja vinkit + + + Avaa GitHub-sivu + + + Tue projektia + + + GitHub-projekti + Asetukset + + + Avaa siirtymisvalikko + Keskeytä/palauta mainosesto + Päivitä estetyt verkkotunnukset + Näytä pyydetyt verkkotunnukset + + + Lue lisätietoja ohjeista. + + \ No newline at end of file diff --git a/app/src/main/res/values-fi/strings_hosts.xml b/app/src/main/res/values-fi/strings_hosts.xml new file mode 100644 index 0000000..140b1fd --- /dev/null +++ b/app/src/main/res/values-fi/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Hosts-lähteet + + Käyttäjälista + AdAwayn virallinen hosts-lähde + StevenBlackin yhtenäinen hosts-lähde + Pete Lowen estolista hosts-lähde + + ei saatavilla + %shostia + + Lisää lähde + Muokkaa lähdettä + Osoite: (https:// tai file:// -resurssi) + Isännän lähde URL + diff --git a/app/src/main/res/values-fi/strings_lists.xml b/app/src/main/res/values-fi/strings_lists.xml new file mode 100644 index 0000000..fc30bfd --- /dev/null +++ b/app/src/main/res/values-fi/strings_lists.xml @@ -0,0 +1,10 @@ + + + Luettelosi + + Torjuttu + Hyväksytty + host-nimi: + Isännän lähde URL + IP (IPv4 tai IPv6): + diff --git a/app/src/main/res/values-fi/strings_log.xml b/app/src/main/res/values-fi/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-fi/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-fi/strings_notification.xml b/app/src/main/res/values-fi/strings_notification.xml new file mode 100644 index 0000000..3d31d31 --- /dev/null +++ b/app/src/main/res/values-fi/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Päivitykset + Uusi päivitys ilmoitukset + Päivitys saatavilla + Uudet hosts-tiedostot ovat ladattavissa + Sovelluspäivitys saatavilla + Uusi AdAway versio ladattavissa + + VPN + VPN käynnissä ilmoitukset + \ No newline at end of file diff --git a/app/src/main/res/values-fi/strings_prefs_backup_restore.xml b/app/src/main/res/values-fi/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..ccdd4a6 --- /dev/null +++ b/app/src/main/res/values-fi/strings_prefs_backup_restore.xml @@ -0,0 +1,6 @@ + + + Varmuuskopioi & palauta + Varmuuskopioi + Palauta + diff --git a/app/src/main/res/values-fi/strings_prefs_main.xml b/app/src/main/res/values-fi/strings_prefs_main.xml new file mode 100644 index 0000000..1fb6270 --- /dev/null +++ b/app/src/main/res/values-fi/strings_prefs_main.xml @@ -0,0 +1,20 @@ + + + Asetukset + + Yleiset + Tummateema + + Vaalea + Tumma + Järjestelmän oletus + + Automaattiset päivitykset + + Mainostentorjunta + VPN pohjainen mainostenesto + + Virheenkorjaus + Lähetä virheraportteja + Ei ole tuettu tässä julkaisussa + diff --git a/app/src/main/res/values-fi/strings_prefs_root.xml b/app/src/main/res/values-fi/strings_prefs_root.xml new file mode 100644 index 0000000..9564b6f --- /dev/null +++ b/app/src/main/res/values-fi/strings_prefs_root.xml @@ -0,0 +1,21 @@ + + + Avaa hosts-tiedosto + Hosts-tiedoston kohde + + /system/etc/hosts + /data/hosts + /data/data/hosts + Mukautettu kohde + + Mukautetun kohteen sijainti + + Uudelleenohjaus + + Paikallinen web-palvelin + Ota web-palvelin käyttöön + Testaa web-palvelinta + Avaa \"Turvallisuus\'\" -asetukset + Tarkistetaan… + Ei käynnissä + diff --git a/app/src/main/res/values-fi/strings_prefs_update.xml b/app/src/main/res/values-fi/strings_prefs_update.xml new file mode 100644 index 0000000..84dce96 --- /dev/null +++ b/app/src/main/res/values-fi/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + Päivityksiä + + Ohjelmapäivitykset + Tarkista päivityksiä käynnistäessä + Säännöllisesti tarkista päivityksiä + Sisällytä beta-julkaisut + + Hosts-päivityksiä + Tarkista päivityksiä käynnistäessä + Säännöllisesti tarkista päivityksiä + Synkronoi päivittäessä + Synkronoi ainoastaan rajattomalla yhteydellä + diff --git a/app/src/main/res/values-fi/strings_prefs_vpn.xml b/app/src/main/res/values-fi/strings_prefs_vpn.xml new file mode 100644 index 0000000..d99beee --- /dev/null +++ b/app/src/main/res/values-fi/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN pohjainen mainostenesto + + Aktivoi käynnistyksessä + Valvo yhteyttä + Tarkista säännöllisesti verkon tilaa uudelleen käynnistääkseen VPN yhteyden katkettua. + + Pois jätetyt sovellukset + Valitse mitkä sovellukset eivät saa käyttää VPNää jotta mitään yhteyksiä ei estetä. + Jätä pois järjestelmäsovelluksia + + Ei mikään + All except browsers + Kaikki + + Jätä pois käyttäjän sovelluksiä + + + Pois jätetyt sovellukset + Valitse kaikki + Poista valinta kaikista + Sovelluksen kuvake + diff --git a/app/src/main/res/values-fi/strings_support.xml b/app/src/main/res/values-fi/strings_support.xml new file mode 100644 index 0000000..6e6a469 --- /dev/null +++ b/app/src/main/res/values-fi/strings_support.xml @@ -0,0 +1,5 @@ + + + Tue + Ryhdy sponsoriksi + \ No newline at end of file diff --git a/app/src/main/res/values-fi/strings_update.xml b/app/src/main/res/values-fi/strings_update.xml new file mode 100644 index 0000000..dbb6fa6 --- /dev/null +++ b/app/src/main/res/values-fi/strings_update.xml @@ -0,0 +1,21 @@ + + + AdAway-päivitys + + Päivitys saatavilla! + + + Olet ajan tasalla + Päivitys saatavilla + Päivitetään AdAwaytä + Päivitä nyt + %1$s / %2$s + Viimeisimmät muutokset + Muutokset + Tue kehitystä + Lahjoita + Sponsoroi + + + Ladataan uusinta versiota AdAwaystä… + diff --git a/app/src/main/res/values-fi/strings_welcome.xml b/app/src/main/res/values-fi/strings_welcome.xml new file mode 100644 index 0000000..efac78f --- /dev/null +++ b/app/src/main/res/values-fi/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Tervetuloa + Määrityksen ensimmäinen vaihe + Määrityksen toinen vaihe + Määrityksen viimeinen vaihe + + + Tervetuloa käyttämään AdAwaytä! + AdAway tarjoaa kaksi mainosten estotapaa. Valitse haluamasi: + + Root-logo + Root-pohjainen\nmainosesto + Nopeampi + Akkuystävällinen + Vaatii root-oikeudet + + VPN-logo + VPN-pohjainen\nmainosesto + Hitaampi + Suoritetaan taustalla + Yhteensopiva + + Vaatii rootatun Androidin + Joko su-binääriä ei löytynyt tai et myöntänyt AdAwaylle root-oikeuksia.\n\nTämä voi tapahtua jos laitetta ei ole rootattu. Löydät tietoja laitteen roottauksesta osoitteessa wiki.lineageos.org tai muilta Android-sivustoilta. + + Hyöty + Haitta + + + Synkronointi on suoritettu + Virhe synkronoitaessa + + Synkronoidaan + Synkronoitu! + AdAway lataa estettäviä mainosverkostoja verkkolähteistä. Voit mukauttaa niitä myöhemmin asetuksista. + Yritä synkronointia uudelleen + Synkronointi epäonnistui: %1$s Yritetäänkö uudelleen? + Sovellus voi näyttää ilmoituksia mainoseston tilasta, hallinnasta ja uusista sovellusversioista (muutama vuodessa). Ota ne käyttöön, jos haluat pysyä ajan tasalla. + + + Tue + Tue minua! + AdAway on ilmainen avoimen lähdekoodin sovellus, jota kehitän vapaa-ajallani. Jos pidät siitä, voit halutessasi ilmaista tukesi: + Lahjoita PayPalilla + Pidätkö vioista? En minäkään. + Lähetä minulle virheraportteja ottamalla telemetria käyttöön + + + Edellinen + Seuraava + Valmis + diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml new file mode 100644 index 0000000..5bc16a5 --- /dev/null +++ b/app/src/main/res/values-fil/strings.xml @@ -0,0 +1,39 @@ + + + + Lumabas + Isara + Oo + Hindi + Dagdagan + I-cancel + Tulong + + + Palitan ang entry + Palitan + Ibura + + + Nag-iimport… + Nag-eexport… + Gumagawa ng standard na hosts file + May bagong update + Walang koneksyong Internet + Walang connection + Dinadownload… + gumagawa ng hosts file + Dagdagan + Tulong + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Tulong + + diff --git a/app/src/main/res/values-fil/strings_app.xml b/app/src/main/res/values-fil/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-fil/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-fil/strings_errors.xml b/app/src/main/res/values-fil/strings_errors.xml new file mode 100644 index 0000000..e22f302 --- /dev/null +++ b/app/src/main/res/values-fil/strings_errors.xml @@ -0,0 +1,5 @@ + + + + Walang koneksyong Internet + \ No newline at end of file diff --git a/app/src/main/res/values-fil/strings_home.xml b/app/src/main/res/values-fil/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-fil/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-fil/strings_hosts.xml b/app/src/main/res/values-fil/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-fil/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-fil/strings_lists.xml b/app/src/main/res/values-fil/strings_lists.xml new file mode 100644 index 0000000..c3a387e --- /dev/null +++ b/app/src/main/res/values-fil/strings_lists.xml @@ -0,0 +1,5 @@ + + + Your lists + IP (IPv4 or IPv6): + diff --git a/app/src/main/res/values-fil/strings_log.xml b/app/src/main/res/values-fil/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-fil/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-fil/strings_notification.xml b/app/src/main/res/values-fil/strings_notification.xml new file mode 100644 index 0000000..7552073 --- /dev/null +++ b/app/src/main/res/values-fil/strings_notification.xml @@ -0,0 +1,4 @@ + + + May bagong update + \ No newline at end of file diff --git a/app/src/main/res/values-fil/strings_prefs_backup_restore.xml b/app/src/main/res/values-fil/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-fil/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-fil/strings_prefs_main.xml b/app/src/main/res/values-fil/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-fil/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-fil/strings_prefs_root.xml b/app/src/main/res/values-fil/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-fil/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-fil/strings_prefs_update.xml b/app/src/main/res/values-fil/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-fil/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-fil/strings_prefs_vpn.xml b/app/src/main/res/values-fil/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-fil/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-fil/strings_support.xml b/app/src/main/res/values-fil/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-fil/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-fil/strings_update.xml b/app/src/main/res/values-fil/strings_update.xml new file mode 100644 index 0000000..05f2a67 --- /dev/null +++ b/app/src/main/res/values-fil/strings_update.xml @@ -0,0 +1,4 @@ + + + May bagong update + diff --git a/app/src/main/res/values-fil/strings_welcome.xml b/app/src/main/res/values-fil/strings_welcome.xml new file mode 100644 index 0000000..41a4523 --- /dev/null +++ b/app/src/main/res/values-fil/strings_welcome.xml @@ -0,0 +1,4 @@ + + + Kailangan ng Android na may root + diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml new file mode 100644 index 0000000..87adc6d --- /dev/null +++ b/app/src/main/res/values-fr/strings.xml @@ -0,0 +1,266 @@ + + + + Quitter + Fermer + Oui + Non + Ajouter + Annuler + Enregistrer + Aide + + + Bienvenue ! + AdAway est un programme gratuit et à code source ouvert conçu pour bloquer les publicités. Il obtient les adresses des réseaux publicitaires afin de les bloquer sur votre appareil.\nVoulez-vous en apprendre davantage ? Consultez l’aide ci-dessous. + Afficher plus d’aide + Mettre à jour l’état + Tous les fichiers hosts des sources définies sont téléchargés, fusionnés avec vos propres listes, puis installés en un seul fichier hosts sur votre système. + Activer le blocage des publicités + Désactiver le blocage des publicités + Serveur Web + En fonction + Arrêté + Démarrer ou arrêter le serveur Web sur « localhost » pour répondre aux requêtes vers des noms d’hôtes bloqués. + Activer le serveur Web + Désactiver le serveur Web + RPV + En fonction + Arrêté + Démarrer ou arrêter le RPV pour filtrer les requêtes. + Activer le RPV + Désactiver le RPV + + + Modifier l’entrée + Appliquer + Modifier + Supprimer + + + Importation… + La sauvegarde a été importée avec succès de votre mémoire externe. + Échec d’importation de la sauvegarde. Le format est-il correct ? Consultez logcat pour plus de précisions. + Exportation… + La sauvegarde a été exportée avec succès vers le fichier « %s » de votre mémoire externe. + Échec d’exportation du fichier de sauvegarde « %s ». + + + Le fichier hosts + Le fichier hosts est un fichier système qui fait correspondre les noms d’hôtes à des adresses IP. C’est un simple fichier texte dont la configuration est gérée par AdAway. Voici ses premières lignes : + Chargement du contenu du fichier hosts… + Ouvrir le fichier hosts + + + Vérification de la présence de mises à jour + Vérification de la présence de mises à jour sur la source %s + Récupération des sources + Téléchargement de la source %s + Lecture de la source %s + Analyse de la source %s + Synchronisation de la base de données des règles + Rétablissement du fichier hosts par défaut + Le fichier hosts par défaut a été restauré + Création d’un fichier hosts standard + Une mise à jour des sources est proposée + De nouveaux fichiers hosts sont proposés + Aucune mise à jour des sources n’a été trouvée + Aucune connexion à Internet + Aucune connexion à Internet n’est accessible + Les sources ne sont pas accessibles + Aucune source de fichier hosts n’est accessible + L’accès racine a été refusé + Autorisez l’accès racine à partir de votre appli de débridage + Une erreur s’est produite + Vérifiez « logcat » pour plus de précisions. + Activé + Les fichiers hosts les plus récents sont activés + Désactivé + Le fichier hosts par défaut a été installé + Appliquer les sources les plus récentes + Création d’un nouveau fichier hosts + Copie d’un nouveau fichier hosts + Vérification de la copie du fichier hosts + Le fichier hosts a été mis à jour avec succès + La configuration du RPV a été mise à jour avec succès + Votre configuration a changé. Vous devez l’appliquer. + Appliquer + Application de la nouvelle configuration… + Échec d’application de la nouvelle configuration. + + + Le lien symbolique vers la cible du fichier hosts manque + Le lien symbolique de votre cible vers /system/etc/hosts est absent ou incorrect. AdAway ne fonctionnera pas sans un lien vers le bon fichier.\n\nVoulez-vous essayer de créer un lien symbolique ? + Le lien symbolique manque + Il manque d’espace sur la partition.\nEssayez de changer le fichier hosts cible dans les préférences par /data/data/hosts. + Il manque d’espace + Impossible de lire le fichier téléchargé. + Échec de fichier privé + Échec de remontage de la partition en lecture/écriture + Échec de remontage + Échec de copie du fichier hosts + La copie du fichier hosts a échoué + Échec de copie + Les sources de fichiers hosts ont été mises en place + La mise à en place a réussi + La mise en place est réussie.\nIl faudra peut-être redémarrer Android pour que les modifications prennent effet.\n\nVoulez-vous redémarrer ?\n(Pour éviter toute perte de données, assurez-vous qu’aucune appli n’utilise la carte SD actuellement.) + Le lien symbolique a été créé avec succès.\nIl faudra peut-être redémarrer Android pour que les modifications prennent effet.\n\nVoulez-vous redémarrer ? (Pour éviter toute perte de données, assurez-vous qu’aucune appli n’utilise la carte SD actuellement.) + Le lien symbolique a été créé avec succès + Le lien symbolique n’a pas pu être créé par Android.\nL’échec provient probablement d’une « fonction » appelée S-ON sur les téléphones HTC.\n\nUne solution possible est de démarrer votre téléphone en mode récupération et d’y créer un lien symbolique avec « ln-s /data/data/hosts/system/etc/hosts ».\n\nSi cela ne fonctionne pas, rechercher S-OFF et votre téléphone sur Internet. + Échec de création du lien symbolique + Pour plus de précisions, veuillez consulter l’aide. + Un mandataire APN est configuré sur votre Android.\nAdAway ne fonctionnera pas de manière fiable sur les réseaux mobiles tels que le 3G. Vous pouvez désactiver ce mandataire en allant à l’APN choisi (dans l’appli Paramètres : Réseau et Internet -> Réseau cellulaire -> Avancés -> Nom des points d’accès) et en supprimant la valeur dans le champ « Serveur mandataire » + Le mandataire APN est configuré + La connexion à Internet ne fonctionne pas. + Aucune connexion + Téléchargement… + Mise en place… + Mise en place des liste de rejet et d’autorisation + Analyse et fusion des fichiers hosts + Création du fichier hosts + Mise en place du fichier hosts + Échec d’application du nouveau fichier hosts. + Le fichier hosts n’a pas pu être mis en place dans votre système.\nEssayez de changer le fichier hosts cible dans les préférences par /data/data/hosts. + Échec de mise en place + Veuillez vérifier votre appli de débridage pour vous assurer que l’accès racine a été autorisé. + Vous avez rétabli le fichier hosts par défaut.\nUn redémarrage Android sera peut-être nécessaire pour que les changements prennent effet.\n\nVoulez-vous redémarrer ?\n(Afin d’éviter toute perte de données, assurez-vous qu’aucune appli n’utilise la carte SD actuellement.) + A été rétabli avec succès + Impossible de rétablir le fichier hosts + Échec de rétablissement pour des raisons inconnues. + Échec de rétablissement + Aucune de vos sources de fichiers hosts activées n’est accessible. Êtes-vous correctement connecté à internet ? + Échec de téléchargement + Échec d’écriture du nouveau fichier hosts privé + Le fichier privé ne peut pas être créé. + Échec de création du fichier privé + Vous avez activé le mode sans système.\nIl faudra peut-être redémarrer Android pour que les changements prennent effet.\n\nVoulez-vous redémarrer ?\n(Pour prévenir toute perte de données, assurez-vous qu’aucune autre appli n’utilise la carte SD en ce moment.) + L’activation a réussi + Vous avez désactivé le mode sans système.\nIl faudra peut-être redémarrer Android pour que les changements prennent effet.\n\nVoulez-vous redémarrer l’appareil ?\n(Pour prévenir toute perte de données, assurez-vous qu’aucune autre appli n’utilise la carte SD en ce moment.) + La désactivation a réussi + Échec d’activation du blocage des publicités par RPV. + Échec de désactivation du blocage des publicités par RPV. + Activation du module hosts de Magisk + Activer la fonction Fichier hosts sans système du gestionnaire Magisk. Dans ses paramètres, activez l’option Fichier hosts sans système, puis redémarrez votre appareil. + Désactivation du module hosts de Magisk + Désactiver la fonction Fichier hosts sans système du gestionnaire Magisk. Dans la liste des modules, désinstallez le module Systemless hosts, puis redémarrez votre appareil. + + + Ajouter une URL au fichier hosts : + Ce n’est pas un nom d’hôte valide + Nom d’hôte mal formaté + Ce n’est pas une IP valide + IP mal formatéee + Ne jamais redémarrer et ne plus afficher cette question. + Chargement… + + + Actualiser + Ajouter + Aide + Importer une sauvegarde + Exporter une sauvegarde + + + S-ON/S-OFF + FAQ + Problèmes + + + Logiciels publicitaires + Vous trouverez ici les logiciels publicitaires installés, des applications néfastes qui ne peuvent pas être bloquées par AdAway. Ces applis utilisent par exemple des notifications Airpush qui surgissent même si l’appli n’est pas en cours de fonctionnement. Elles peuvent même changer votre sonnerie. La seule contre-mesure à votre disposition est de désinstaller ces applis en cliquant sur les éléments de la liste. + Analyse… + Aucun logiciel publicitaire n’a été trouvé + + + Bloqueur de publicités + Aucun éditeur de texte n’est installé + Aucun éditeur de texte n’a été trouvé pour ouvrir le fichier hosts. Vous pouvez installer Jota ou d’autres éditeurs de texte pour ce faire.\n\nVoulez-vous installer Jota ? + Aucun gestionnaire de fichiers n’est installé + Aucun gestionnaire de fichier n’a trouvé pour ouvrir les fichiers. Vous pouvez installer OI File Manager ou d’autres gestionnaires de fichiers pour ce faire.\n\nVoulez-vous installer OI File Manager ? + + + Tcpdump + Tcpdump est un outil pour surveiller les requêtes DNS et les enregistrer dans un fichier journal. Vous pouvez le démarrer en arrière-plan, lancer des applications qui affichent des publicités et analyser ensuite les requêtes DNS d’après le fichier journal. Le serveur publicitaire candidat peut ensuite être ajouté à votre liste de rejet. + Désactiver la surveillance + Activer la surveillance + Afficher les résultats + Trier les domaines + Effacer le journal + Ajouter une entrée à la liste de rejet + Ajouter une entrée à la liste d’autorisation + Ajouter une entrée à la liste des redirections + + Modifier la valeur de préférence du texte + Ouvrir le menu + Fermer le menu + + + + Accueil + Sources de fichiers hosts + Vos listes + Ouvrir le fichier « hosts » + Journaliser les requêtes DNS + Chercher des logiciels publicitaires + Préférences + Aide + + + + + Requêtes DNS + Vos listes + Préférences + + + Installée il y a %1$s + À jour depuis %1$s + Mise à jour proposée depuis %1$s + Dernière mise à jour il y a %1$s + L’état de mise à jour est inconnu + Désactivée + quelques minutes + + %d minute + %d minutes + %d minutes + + + %d heure + %d heures + %d heures + + + %d jour + %d jours + %d jours + + + %d mois + %d mois + %d mois + + + + L’hôte a été copié dans le presse-papiers + + + démarrage + activé + arrêt + en attente du réseau + reconnexion + erreur de reconnexion + en pause + arrêté + RPV bloqueur de publicités %1$s + Pause + Reprendre + + + Autorisations d’AdAway + Permettre d’interagir avec AdAway + Envoyer des commandes à AdAway + Permettre d’envoyer des commandes à AdAway telles qu’activer ou désactiver le blocage des publicités pour le système entier + + diff --git a/app/src/main/res/values-fr/strings_app.xml b/app/src/main/res/values-fr/strings_app.xml new file mode 100644 index 0000000..2036e4e --- /dev/null +++ b/app/src/main/res/values-fr/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Bloqueur de publicités à code source ouvert + Logo AdAway + diff --git a/app/src/main/res/values-fr/strings_errors.xml b/app/src/main/res/values-fr/strings_errors.xml new file mode 100644 index 0000000..576e7f5 --- /dev/null +++ b/app/src/main/res/values-fr/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Aucune connexion à Internet + Impossible d’établir une connexion vers Internet. Veuillez vérifier la connectivité de votre appareil. + Échec de téléchargement de la source du fichier hosts + Aucune de vos sources de fichiers hosts activées n’est accessible. Veuillez vous assurer d’être correctement connecté à Internet ? + + Échec de création du fichier privé + Impossible de créer un fichier privé pour construire une nouvelle source d’hosts. Veuillez vérifier l’espace libre sur votre appareil. + Il manque d’espace + Impossible de copier le fichier hosts vers votre partition système. Veuillez vous assurer que le module « Systemless Hosts » de Magisk est activé, puis redémarrez. + Échec d’installation du nouveau fichier hosts. + Impossible de copier le fichier hosts vers la partition /system. Veuillez vous assurer que le module « Systemless Hosts » de Magisk est activé, puis redémarrez. + Échec de rétablissement du fichier hosts + Impossible de restaurer la configuration du fichier hosts par défaut. + + Échec d’activation du blocage des publicités par RPV. + Veuillez vérifier les paramètres de votre RPV pour autoriser le démarrage du RPV de l’application. + Échec de désactivation du blocage des publicités par RPV. + Veuillez vérifier les paramètres de votre RPV pour le désactiver manuellement. + diff --git a/app/src/main/res/values-fr/strings_home.xml b/app/src/main/res/values-fr/strings_home.xml new file mode 100644 index 0000000..1cf5a9f --- /dev/null +++ b/app/src/main/res/values-fr/strings_home.xml @@ -0,0 +1,48 @@ + + + + + Bloqués + Autorisés + Redirigés + + + + %d source à jour + %d sources à jour + %d sources à jour + + + %d source périmée + %d sources périmées + %d sources périmées + + Vérifier la présence de mises à jour des fichiers hosts + Mettre à jour le fichier hosts + + + Afficher le journal de requêtes DNS + + + Afficher l’aide\net les conseils + + + Ouvrir la page GitHub + + + Soutenir le projet + + + Projet GitHub + Préférences + + + Ouvrir le tiroir de navigation + Mettre en pause/Reprendre le blocage des publicités + Mettre à jour les domaines bloqués + Afficher les domaines interrogés + + + Veuillez consulter l’aide pour plus de précisions. + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings_hosts.xml b/app/src/main/res/values-fr/strings_hosts.xml new file mode 100644 index 0000000..f25acd6 --- /dev/null +++ b/app/src/main/res/values-fr/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Sources de fichiers hosts + + Liste de l’utilisateur + Fichier hosts officiel d’AdAway + Fichier hosts unifié de StevenBlack + Fichier hosts unifié de Pete Lowe + + non disponibles + Fichier(s) hosts de %s + + Ajouter une source + Modifier une source + URL : (une ressource https:// ou file://) + L’URL de la source du fichier hosts + diff --git a/app/src/main/res/values-fr/strings_lists.xml b/app/src/main/res/values-fr/strings_lists.xml new file mode 100644 index 0000000..c1f312c --- /dev/null +++ b/app/src/main/res/values-fr/strings_lists.xml @@ -0,0 +1,24 @@ + + + Vos listes + Ajouter un hôte + + Bloqués + Autorisés + Redirigés + + Filtrer les hôtes + Chercher un nom d’hôte… + Activer/désactiver les sources + + Ajouter un hôte à la liste noire + Ajouter un hôte à la liste blanche + Ajouter une redirection d’hôte + Modifier l’hôte mis en liste noire + Modifier l’hôte mis en liste blanche + Modifier la redirection + Nom de l’hôte : + L’URL de la source du fichier hosts + (Les métacaractères * et ? sont permis) + IP (IPv4 ou IPv6) : + diff --git a/app/src/main/res/values-fr/strings_log.xml b/app/src/main/res/values-fr/strings_log.xml new file mode 100644 index 0000000..54ed2f1 --- /dev/null +++ b/app/src/main/res/values-fr/strings_log.xml @@ -0,0 +1,11 @@ + + + Activer ou désactiver l’enregistrement du journal + Appuyez sur le bouton d’enregistrement pour lancer la journalisation des requêtes. Naviguez sur Internet ou utilisez des applis, puis revenez dans cet écran et balayez-le vers le bas pour actualiser les journaux. + \n\nLes requêtes bloquées ne seront pas journalisées. Désactivez d’abord le blocage des publicités si vous voulez aussi les journaliser. + + Tri alphabétique + Tri par domaines de premier niveau + + Rediriger un domaine + diff --git a/app/src/main/res/values-fr/strings_notification.xml b/app/src/main/res/values-fr/strings_notification.xml new file mode 100644 index 0000000..f4c0674 --- /dev/null +++ b/app/src/main/res/values-fr/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Mises à jour + Notification de nouvelles mises à jour + Une mise à jour des sources est proposée + Des fichiers hosts plus récents peuvent être téléchargés. + Une mise à jour de l’appli est proposée + Une nouvelle version d’AdAway est proposée en téléchargement. + + RPV + Notifications de l’exécution du RPV + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings_prefs_backup_restore.xml b/app/src/main/res/values-fr/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..87aafcc --- /dev/null +++ b/app/src/main/res/values-fr/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Sauvegarde et restauration + Sauvegarde + Sauvegardez vos règles de blocage sur une mémoire externe + Restaurer + Restaurez vos règles de blocage d’un fichier de sauvegarde + diff --git a/app/src/main/res/values-fr/strings_prefs_main.xml b/app/src/main/res/values-fr/strings_prefs_main.xml new file mode 100644 index 0000000..48e89fe --- /dev/null +++ b/app/src/main/res/values-fr/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Préférences + + Général + Thème sombre + + Clair + Sombre + Valeur par défaut du système + + Mises à jour automatiques + + Blocage des publicités + Bloqueur de publicités pour appareil débridé + Bloqueur de publicités fondé sur un RPV + Activer la prise en charge d’IPv6 + Sauvegarder/restaurer les règles de blocage + + Débogage + Envoyer des relevés de plantage + Signaler à Sentry (sentry.io) + N’est pas pris en charge dans cette version + Journalisation détaillée + Les changements prendront effet après redémarrage de l’appli + diff --git a/app/src/main/res/values-fr/strings_prefs_root.xml b/app/src/main/res/values-fr/strings_prefs_root.xml new file mode 100644 index 0000000..8a02397 --- /dev/null +++ b/app/src/main/res/values-fr/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Bloqueur de publicités pour appareil débridé + + Installation de fichier hosts + Ouvrir le fichier hosts + Fichier hosts cible + Consultez l’aide avant d’utiliser cette fonction + + /system/etc/hosts + /data/hosts + /data/data/hosts + Cible personnalisée + + Emplacement de la cible personnalisée + Cacher le message de redémarrage après application + + Redirection + Définir où rediriger les hôtes bloqués + Redirection IPv4 + Redirection IPv6 + La redirection est invalide + + Serveur Web local + Le serveur Web local écoute les adresses IP locales pour répondre aux requêtes vers des noms d’hôtes bloqués. Cela pourrait empêcher le gel de certaines applications lors de connexions bloquées. + Activer le serveur Web + Tester le serveur Web + Installer un certificat autosigné + Installation manuelle d’un certificat + À partir d’Android 11 Ⓡ, une application ne peut plus installer manuellement une autorité de certification (CA).\n\nAccédez aux paramètres Sécurité > Chiffrement et authentifiants, puis Installer un certificat. Choisissez ensuite Certificat CA et sélectionnez le fichier du certificat nouvellement exporté. + Ouvrir les paramètres « Sécurité » + Vérification… + N’est pas en fonction + En fonction, mais le certificat n’est pas installé + En fonction et le certificat est installé + Remplacer l’espace vide des publicités par l’icône de l’appli + diff --git a/app/src/main/res/values-fr/strings_prefs_update.xml b/app/src/main/res/values-fr/strings_prefs_update.xml new file mode 100644 index 0000000..85b6be1 --- /dev/null +++ b/app/src/main/res/values-fr/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Mises à jour + Les notifications sont désactivées + Les notifications de l’appli ne seront pas affichées. Touchez pour les activer. + + Mises à jour de l’application + Vérifier la présence d’une mise à jour au démarrage + Vérifier régulièrement la présence de mises à jour + Inclure les versions bêta + + Mises à jour des hôtes + Vérifier la présence d’une mise à jour au démarrage + Vérifier régulièrement la présence de mises à jour + Synchroniser lors d’une mise à jour + Ne synchroniser que sur les réseaux sans limite de données + diff --git a/app/src/main/res/values-fr/strings_prefs_vpn.xml b/app/src/main/res/values-fr/strings_prefs_vpn.xml new file mode 100644 index 0000000..a633c6e --- /dev/null +++ b/app/src/main/res/values-fr/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Bloqueur de publicités fondé sur un RPV + + Activer au démarrage + Surveiller la connexion + Vérifier régulièrement l’état du réseau pour relancer le RPV après une déconnexion. + + Applications exclues + Configurer les applis qui ne devraient pas utiliser le RPV, afin qu’aucune connexion ne soit bloquée. + Exclure les applications système + + Aucune + Toutes, sauf les navigateurs + Toutes + + Exclure des applications utilisateur + + + Applications exclues + Les sélectionner toutes + Les dessélectionner toutes + Icône de l’application + diff --git a/app/src/main/res/values-fr/strings_source_edit.xml b/app/src/main/res/values-fr/strings_source_edit.xml new file mode 100644 index 0000000..8aa1f0a --- /dev/null +++ b/app/src/main/res/values-fr/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Modifier une source + Ajouter une source + + Étiquette + Une étiquette est nécessaire + Type + URL + Fichier + Emplacement + https:// + Un emplacement est nécessaire + Touchez Fichier pour sélectionner le fichier source + L’emplacement est invalide + Format des listes + Bloquer + Autoriser + Appliquer les hôtes redirigés + Autoriser les hôtes redirigés peut entraîner des problèmes de sécurité. N’utilisez ces paramètres que sur une source de confiance, car du trafic sensible pourrait être redirigé à votre insu vers n’importe quel serveur. + diff --git a/app/src/main/res/values-fr/strings_support.xml b/app/src/main/res/values-fr/strings_support.xml new file mode 100644 index 0000000..e8f5220 --- /dev/null +++ b/app/src/main/res/values-fr/strings_support.xml @@ -0,0 +1,5 @@ + + + Soutien + Devenir commanditaire + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings_update.xml b/app/src/main/res/values-fr/strings_update.xml new file mode 100644 index 0000000..554c948 --- /dev/null +++ b/app/src/main/res/values-fr/strings_update.xml @@ -0,0 +1,22 @@ + + + Mise à jour d’AdAway + + Une mise à jour est proposée + + + AdAway est à jour + Une mise à jour est proposée + Mise à jour d’AdAway + Mettre à jour maintenant + %1$s / %2$s + Terminée + Derniers changements + Journal des changements + Soutenir le développement + Faire un don + Commanditer + + + Téléchargement de la version d’AdAway la plus récente… + diff --git a/app/src/main/res/values-fr/strings_welcome.xml b/app/src/main/res/values-fr/strings_welcome.xml new file mode 100644 index 0000000..fca5dc7 --- /dev/null +++ b/app/src/main/res/values-fr/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Bienvenue + Première étape de l’assistant + Deuxième étape de l’assistant + Dernière étape de l’assistant + + + Bienvenue dans AdAway ! + AdAway offre deux modes de blocage des publicités. Sélectionnez celui qui vous convient : + + Logo de la racine + Bloqueur de publicités\nfondé sur la racine + Plus rapide + Demande en énergie moins élevée + Exige un appareil débridé + + Logo du RPV + Bloqueur de publicités\nfondé sur un RPV + Plus lent + Exécution en arrière-plan + Compatibilité + + Un Android débridé est exigé + Soit le fichier binaire su est introuvable, soit vous n’avez pas donné l’accès racine à AdAway.\n\nCela peut arriver quand votre appareil n’est pas débridé. Vous trouverez des renseignements sur comment débrider votre appareil sur wiki.lineageos.org ou sur d’autres sites Web dédiés à Android. + + Avantages + Inconvénients + + + La synchronisation est terminée + Erreur de synchronisation + + Synchronisation + La synchronisation est terminée + AdAway télécharge de sources en ligne la liste de réseaux publicitaires à bloquer. Vous pouvez les personnaliser ultérieurement dans les paramètres. + Essayer de resynchroniser + Échec de synchronisation : %1$s Réessayer maintenant ? + Peut envoyer des notifications pour afficher l’état et le contrôle du blocage des publicités et vous signaler la présence de mise à jour de l’appli (quelques fois par an). Activez-les si vous voulez rester à jour. + + + Dons + Soutenez-moi ! + AdAway est une appli gratuite et à code source ouvert que je développe à temps perdu. Si vous l’aimez, n’hésitez pas à témoigner votre soutien : + Faire un don par PayPal + Aimez-vous les bogues ? Moi non plus. + Activer la télémétrie pour envoyer des relevés de plantage + + + Retour + Suivant + Terminer + diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml new file mode 100644 index 0000000..5d3c2f8 --- /dev/null +++ b/app/src/main/res/values-gl/strings.xml @@ -0,0 +1,81 @@ + + + + Saír + Pechar + Si + Non + Engadir + Desbotar + Gardar + Axuda + + + Benvido! + Amosar máis axuda + Estado da actualización + Habilitar bloqueo de publicidade + Deshabilitar bloqueo de publicidade + Servidor web + En execución + Detido + Habilitar servidor web + Deshabilitar servidor web + VPN + En execución + Detido + Habilitar VPN + Deshabilitar VPN + + Aplicar + Editar + Eliminar + + + Estase a importar… + Copia de seguridade importada correctamente dende o teu almacenamento externo. + Estase a exportar… + + O arquivo hosts + Cargando contido do arquivo hosts… + Abrir o arquivo hosts + + Descargando fonte %s + Reverter ó arquivo hosts por defecto + Arquivo hosts predeterminado restablecido + Creando arquivo hosts estándar + Actualización da fonte dispoñíbel + Arquivos hosts recentes dispoñíbeis + Sen conexión a Internet + Non hai conexión a Internet dispoñíbel + Fontes non dispoñíbeis. + Non hay fontes de hosts accesíbeis + Acceso root denegado + Habilitado + Deshabilitado + Arquivo hosts actualizado correctamente + Aplicar + Erro ao aplicar a nova configuración. + + Non hai espazo dabondo + O arquivo descargado non se puido ler. + Por favor ler Axuda para máis información. + Estase a descarregar… + Estase a aplicar… + Erro ao habilitar o bloqueo de publicidade VPN. + Erro ao deshabilitar o bloqueo de publicidade VPN. + Engadir + Axuda + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Axuda + + Túas listas + diff --git a/app/src/main/res/values-gl/strings_app.xml b/app/src/main/res/values-gl/strings_app.xml new file mode 100644 index 0000000..59a5cf7 --- /dev/null +++ b/app/src/main/res/values-gl/strings_app.xml @@ -0,0 +1,5 @@ + + + AdAway + Bloqueador de publicidade de Código Aberto + diff --git a/app/src/main/res/values-gl/strings_errors.xml b/app/src/main/res/values-gl/strings_errors.xml new file mode 100644 index 0000000..1769c79 --- /dev/null +++ b/app/src/main/res/values-gl/strings_errors.xml @@ -0,0 +1,16 @@ + + + + Non hai conexión a Internet + + Erro ao crear arquivo privado + Non hai espazo dabondo + Erro ao instalar novo arquivo hosts + Foi incapaz de copiar o arquivo hosts á partición do sistema. Verifica que o módulo systemless de Magisk esté habilitado para reiniciar. + Erro ao revertir o arquivo hosts + Non se é capaz de restaurar-la configuración predeterminada do arquivo hosts. + + Erro ao habilitar o bloqueo de publicidade VPN. + Erro ao deshabilitar o bloqueo de publicidade VPN. + Por favor comproba os axustes da túa VPN para deshabilitala manualmente. + \ No newline at end of file diff --git a/app/src/main/res/values-gl/strings_home.xml b/app/src/main/res/values-gl/strings_home.xml new file mode 100644 index 0000000..0262e09 --- /dev/null +++ b/app/src/main/res/values-gl/strings_home.xml @@ -0,0 +1,33 @@ + + + + + Bloqueado + Permitido + Redirixido + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + + Amosar axuda + + + Abrir páxina de GitHub + + Preferences + + Actualizar dominios bloqueados + Amosar dominios solicitados + + + Por favor ler Axuda para máis información. + + \ No newline at end of file diff --git a/app/src/main/res/values-gl/strings_hosts.xml b/app/src/main/res/values-gl/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-gl/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-gl/strings_lists.xml b/app/src/main/res/values-gl/strings_lists.xml new file mode 100644 index 0000000..ac2c73b --- /dev/null +++ b/app/src/main/res/values-gl/strings_lists.xml @@ -0,0 +1,14 @@ + + + Túas listas + + Bloqueado + Permitido + Redirixido + + Filtrar hosts + + Engadir host á lista negra + Engadir host á lista branca + Engadir host de redirección + diff --git a/app/src/main/res/values-gl/strings_log.xml b/app/src/main/res/values-gl/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-gl/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-gl/strings_notification.xml b/app/src/main/res/values-gl/strings_notification.xml new file mode 100644 index 0000000..de91780 --- /dev/null +++ b/app/src/main/res/values-gl/strings_notification.xml @@ -0,0 +1,11 @@ + + + + Actualizacións + Actualización da fonte dispoñibel + Novos arquivos hosts dispoñíbeis para descargar. + Actualización da app dispoñibel + Unha nova versión de AdAway está dispoñíbel para descargar + + VPN + \ No newline at end of file diff --git a/app/src/main/res/values-gl/strings_prefs_backup_restore.xml b/app/src/main/res/values-gl/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-gl/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-gl/strings_prefs_main.xml b/app/src/main/res/values-gl/strings_prefs_main.xml new file mode 100644 index 0000000..a855b2e --- /dev/null +++ b/app/src/main/res/values-gl/strings_prefs_main.xml @@ -0,0 +1,5 @@ + + + Preferences + Bloqueador de publicidade baseado en VPN + diff --git a/app/src/main/res/values-gl/strings_prefs_root.xml b/app/src/main/res/values-gl/strings_prefs_root.xml new file mode 100644 index 0000000..2f4b74b --- /dev/null +++ b/app/src/main/res/values-gl/strings_prefs_root.xml @@ -0,0 +1,11 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + Activar servidor web + diff --git a/app/src/main/res/values-gl/strings_prefs_update.xml b/app/src/main/res/values-gl/strings_prefs_update.xml new file mode 100644 index 0000000..364509a --- /dev/null +++ b/app/src/main/res/values-gl/strings_prefs_update.xml @@ -0,0 +1,4 @@ + + + Unha nova versión de AdAway está dispoñibel para descargar + diff --git a/app/src/main/res/values-gl/strings_prefs_vpn.xml b/app/src/main/res/values-gl/strings_prefs_vpn.xml new file mode 100644 index 0000000..1420979 --- /dev/null +++ b/app/src/main/res/values-gl/strings_prefs_vpn.xml @@ -0,0 +1,17 @@ + + + Bloqueador de publicidade baseado en VPN + + Habilitar no arranque + + Aplicacións excluídas + Configure cales aplicacións non deberían utilizar a VPN para que non se bloqueen súas conexións. + Excluír aplicacións do sistema + Excluír aplicacións do usuario + + + Aplicacións excluídas + Selecciona todas + Quitar selección a todas + Icona da aplicación + diff --git a/app/src/main/res/values-gl/strings_support.xml b/app/src/main/res/values-gl/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-gl/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-gl/strings_update.xml b/app/src/main/res/values-gl/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-gl/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-gl/strings_welcome.xml b/app/src/main/res/values-gl/strings_welcome.xml new file mode 100644 index 0000000..02e289f --- /dev/null +++ b/app/src/main/res/values-gl/strings_welcome.xml @@ -0,0 +1,23 @@ + + + Benvido + Primeiro paso do asistente + Segundo paso do asistente + Derradeiro paso do asistente + + + Benvido a AdAway! + AdAway proporciona dous métodos de bloqueo. Escolle un: + + Precisa root + + Executar en segundo plano + Compatibilidade + + Precisa ter Android rooteado + Podería ser que non se atopara o arquivo su binary ou que AdAway non teña autorización dos permisos root.\n\nIsto sucede cando o teu dispositivo non está rooteado. Podes atopar información sobre como rootear o teu dispositivo en wiki.lineageos.org ou noutros sitios web Android. + + Doar en PayPal + Gústanche os bugs? A min tampouco. + Seguinte + diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml new file mode 100644 index 0000000..8bd1807 --- /dev/null +++ b/app/src/main/res/values-hi/strings.xml @@ -0,0 +1,15 @@ + + + सवाल + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-hi/strings_app.xml b/app/src/main/res/values-hi/strings_app.xml new file mode 100644 index 0000000..34e2f06 --- /dev/null +++ b/app/src/main/res/values-hi/strings_app.xml @@ -0,0 +1,4 @@ + + + à¤à¤¡ अवे + diff --git a/app/src/main/res/values-hi/strings_errors.xml b/app/src/main/res/values-hi/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-hi/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-hi/strings_home.xml b/app/src/main/res/values-hi/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-hi/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-hi/strings_hosts.xml b/app/src/main/res/values-hi/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-hi/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-hi/strings_lists.xml b/app/src/main/res/values-hi/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-hi/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-hi/strings_log.xml b/app/src/main/res/values-hi/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-hi/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-hi/strings_notification.xml b/app/src/main/res/values-hi/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-hi/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-hi/strings_prefs_backup_restore.xml b/app/src/main/res/values-hi/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-hi/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-hi/strings_prefs_main.xml b/app/src/main/res/values-hi/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-hi/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-hi/strings_prefs_root.xml b/app/src/main/res/values-hi/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-hi/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-hi/strings_prefs_update.xml b/app/src/main/res/values-hi/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-hi/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-hi/strings_prefs_vpn.xml b/app/src/main/res/values-hi/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-hi/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-hi/strings_support.xml b/app/src/main/res/values-hi/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-hi/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-hi/strings_update.xml b/app/src/main/res/values-hi/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-hi/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-hi/strings_welcome.xml b/app/src/main/res/values-hi/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-hi/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml new file mode 100644 index 0000000..e73eec9 --- /dev/null +++ b/app/src/main/res/values-hr/strings.xml @@ -0,0 +1,266 @@ + + + + Zatvori + Zatvori + Da + Ne + Dodaj + Odustani + Spremi + Pomoć + + + DobrodoÅ¡li! + AdAway je slobodan softver otvorenog kôda dizajniran za blokiranje oglaÅ¡avanja. Preuzima popis adresa oglasa i podeÅ¡ava vaÅ¡ ureÄ‘aj kako bi ih mogao blokirati.\nŽelite li saznati viÅ¡e? Pogledajte pomoć ispod! + Prikaži viÅ¡e pomoći + Stanje ažuriranja + Sve datoteke poslužitelja su preuzete s odreÄ‘enih izvora, spojene s vaÅ¡im popisima i instalirane kao jedna datoteka na vaÅ¡em sustavu. + Omogući blokiranje oglasa + Onemogući blokiranje oglasa + Web poslužitelj + Pokrenuto + Zaustavljeno + Pokreni ili zaustavi web poslužitelj na lokalnom poslužitelju kako bi odgovarao na zahtjeve za blokiranje naziva poslužitelja. + Omogući web poslužitelja + Onemogući web poslužitelja + VPN + Pokrenuto + Zaustavljeno + Pokreni ili zaustavi VPN filtriranje zahtjeva. + Omogući VPN + Onemogući VPN + + + Uredi upis + Primijeni + Uredi + ObriÅ¡i + + + Uvažanje… + Sigurnosna kopija je uspjeÅ¡no uvezena iz vaÅ¡eg ureÄ‘aja vanjske pohrane. + Neuspjeli uvoz sigurnosne kopije. Je li format ispravan? Provjerite logcat za viÅ¡e pojedinosti. + Izvažanje… + Sigurnosna kopija uspjeÅ¡no je izvezena u datoteku \'%s\' na vaÅ¡em ureÄ‘aju vanjske pohrane. + Neuspjeli izvoz %s datoteke sigurnosne kopije. + + + Datoteka poslužitelja + Datoteka poslužitelja je datoteka sustava koja mapira nazive poslužitelja prema IP adresama. To je obiÄna tekstna datoteka Äijim se podeÅ¡avanjem rukuje putem AdAwaya. Ovdje je prvih nekoliko redaka: + UÄitavanje sadržaja datoteke poslužitelja… + Otvori datoteku poslužitelja + + + Provjeravanje ažuriranja + Provjeravanje ažuriranja na izvoru poslužitelja %s + Preuzimanje izvora poslužitelja + Preuzimanje izvora poslužitelja %s + UÄitavanje izvora poslužitelja%s + Obrada %s izvora poslužitelja + UsklaÄ‘ivanje baze podataka pravila + Preuzimanje u zadanu datoteku poslužitelja + Zadana datoteka poslužitelja je obnovljena + Stvaranje standardne datoteke poslužitelja + Dostupno je ažuriranje izvora poslužitelja + Dostupne su novije datoteke poslužitelja + Nema pronaÄ‘enih ažuriranja izvora poslužitelja + Internet nedostupan + Nema dostupnog pristupa internetu + Nedostupni izvori poslužitelja + Nema dostupnih izvora poslužitelja! + Korijenski (Root) pristup odbijen + Dopustite korijenski (root) pristup iz vaÅ¡e root aplikacije + NeÅ¡to je poÅ¡lo po krivu + Provjeri logcat zapis za viÅ¡e pojedinosti + Omogućeno + Najnovija datoteka poslužitelja je omogućena + Onemogućeno + Zadana datoteka poslužitelja je instalirana + Primijeni najnovije izvore poslužitelja + Stvaranje nove datoteke poslužitelja + Kopiranje nove datoteke poslužitelja + Provjeravanje kopiranja datoteke poslužitelja + Datoteka poslužitelja je uspjeÅ¡no ažurirana + VPN podeÅ¡avanja uspjeÅ¡no ažurirana + VaÅ¡a podeÅ¡avanja su promijenjena. Potrebno ih je primijeniti. + Primijeni + Primjenjivanje novih podeÅ¡avanja… + Nuspjelo primjenjivanje novih podeÅ¡avanja. + + + SimboliÄka poveznica na odrediÅ¡te datoteke poslužitelja nedostaje + SimboliÄka poveznica s vaÅ¡eg odrediÅ¡ta /system/etc/hosts ne postoji ili je neispravna! AdAway neće raditi ako nije usmjeren na ispravnu datoteku.\n\nŽelite li pokuÅ¡ati stvoriti simboliÄku poveznicu? + SimboliÄka poveznica nedostaje + Nema dovoljno prostora na particiji!\nPokuÅ¡ajte promijeniti odrediÅ¡nu datoteku poslužitelja u postavkama u /data/data/hosts. + Nedovoljno prostora + Preuzeta datoteka se ne može proÄitati. + Neuspjela privatna datoteka + Ponovno montiranje particije uslijed neuspjelog Äitanja/pisanja! + Neuspjelo ponovno montiranje + Neuspjelo kopiranje datoteke poslužitelja + Neuspjelo kopiranje datoteke poslužitelja! + Neuspjelo kopiranje + Primijenjeni izvori poslužitelja + UspjeÅ¡no primijenjivanje + Primjena je bila uspjeÅ¡na.\nPonekada je potrebno ponovo pokrenuti Android za primijenjivanje promjena.\n\n Želite li ponovno pokrenuti Android?\n (Kako biste izbjegli gubitak podataka pobrinite se da nijedna aplikacija trenutno ne koristi memorijsku karticu!) + SimboliÄka poveznica je uspjeÅ¡no stvorena.\nPonekada je potrebno ponovo pokrenuti Android za primijenjivanje promjena.\n\n Želite li ponovo pokrenuti Android?\n (Kako biste izbjegli gubitak podataka pobrinite se da nijedna aplikacija trenutno ne koristi memorijsku karticu!) + SimboliÄka poveznica je uspjeÅ¡no stvorena + SimboliÄka poveznica se ne može stvoriti na Androidu.\nOvo uobiÄajeno ne uspijeva zbog \'znaÄajke\' zvane S-ON na HTC telefonima!\n\nRjeÅ¡enje je u ponovnom pokretanju vaÅ¡eg telefona u naÄin oporavka i stvaranju simboliÄke poveznice sa naredbom \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nAko ovo ne radi potražite na internetu za S-OFF za vaÅ¡ telefon. + Stvaranje simboliÄke poveznice je neuspjeÅ¡no + ProÄitajte pomoć za viÅ¡e informacija. + APN proxy je postavljen na vaÅ¡em Androidu!\nAdAway neće pouzdano raditi na mobilnim 3G mrežama. Taj proxy možete deaktivirati odlaskom na vaÅ¡ odabrani APN (Iz aplikacije Postavke: Sim kartice -> Sim postavke -> Pristupne toÄke -> Uredi pristupnu toÄku) i obriÅ¡ite podatak u proxy polju. + APN proxy je postavljen! + Povezivanje s internetom ne radi. + Internet nedostupan + Preuzimanje… + Primijenjivanje… + Primijenjivanje blokiranih i neblokiranih popisa + Obrada i spajanje datoteka poslužitelja + Izgradnja datoteke poslužitelja + Primijenjivanje datoteke poslužitelja + Neuspjela primjena nove datoteke poslužitelja. + Primijenjivanje datoteke poslužitelja na vaÅ¡em sustavu nije uspjelo!\n PokuÅ¡ajte promijeniti odrediÅ¡nu datoteku poslužitelja u postavkama u /data/data/hosts. + Primijenjivanje neuspjelo + Provjerite vaÅ¡u aplikaciju root upravljanja kako bi osigurali da je vaÅ¡ korijenski (root) pristup dopuÅ¡ten. + Ponovno koristite izvornu datoteku poslužitelja.\nPonekada je potrebno ponovo pokrenuti Android za primijenjivanje promjena.\n\n Želite li ponovo pokrenuti Android?\n (Kako biste izbjegli gubitak podataka pobrinite se da nijedna aplikacija trenutno ne koristi memorijsku karticu!) + UspjeÅ¡no vraćanje na izvorno + Neuspjelo vraćanje izvorne datoteke poslužitelja + NeuspjeÅ¡no vraćanje na izvorno uslijed nepoznatih razloga. + NeuspjeÅ¡no vraćanje na izvorno! + Niti jedan od vaÅ¡ih omogućenih izvora poslužitelja nije dostupan! Jeste li ispravno povezani s internetom? + Neuspjelo preuzimanje + Neuspjelo zapisivanje nove privatne datoteke poslužitelja + Privatna datoteka se ne može stvoriti. + Neuspjelo stvaranje privatne datoteke + Omogućili ste bezsustavski naÄin rada.\nPonekada je potrebno ponovno pokrenuti Android za primijenjivanje promjena.\n\nŽelite li ponovno pokrenuti Android?\n(Kako biste izbjegli gubitak podataka pobrinite se da nijedna aplikacija trenutno ne koristi memorijsku karticu!) + UspjeÅ¡no omogućeno + Onemogućili ste bezsustavski naÄin rada.\nPonekada je potrebno ponovno pokrenuti Android za primijenjivanje promjena.\n\nŽelite li ponovno pokrenuti Android?\n(Kako biste izbjegli gubitak podataka pobrinite se da nijedna aplikacija trenutno ne koristi memorijsku karticu!) + UspjeÅ¡no onemogućeno + Neuspjelo omogućavanje VPN blokiranja oglasa. + Neuspjelo onemogućavanje VPN blokiranja oglasa. + Omogućavanje Magisk modula poslužitelja + Omogućite bezsustavsku (systemless) hosts znaÄajku iz Magisk upravitelja. Iz njegovih postavki, omogućite Systemless hosts mogućnost zatim ponovno pokrenite svoj ureÄ‘aj. + Onemogućavanje Magisk modula poslužitelja + Onemogućite bezsustavsku (systemless) hosts znaÄajku iz Magisk upravitelja. Iz popisa modula, deinstalirajte Systemless hosts modul zatim ponovno pokrenite svoj ureÄ‘aj. + + + URL unosa za datoteku poslužitelja: + Ovo nije valjan naziv poslužitelja! + Nepravilno oblikovan naziv poslužitelja + Ovo nije valjana IP adresa! + Nepravilno oblikovana IP adresa + Nikada ne pokreći ponovno i ne prikazuj ovo pitanje! + UÄitavanje… + + + Osvježi + Dodaj + Pomoć + Uvezi sigurnosnu kopiju + Izvezi sigurnosnu kopiju + + + S-ON/S-OFF + ÄŒesta pitanja + Problemi + + + Zlonamjerne aplikacije + Ovdje možete potražiti zlonamjerne aplikacije, loÅ¡e aplikacije koje AdAway ne može blokirati. Te aplikacije koriste, na primjer, Airpush obavijesti koje se pojavljuju Äak i ako aplikacija nije pokrenuta, a mogu Äak promijeniti i melodiju vaÅ¡eg zvona. Jedina moguća mjera koju možete poduzeti protiv takvih aplikacija je uklanjanje klikom na stavke popisa. + Pretraživanje… + Nema pronaÄ‘enih zlonamjernih aplikacija! + + + Blokator oglasa + Nema instaliranog ureÄ‘ivaÄa teksta + Nema instaliranog ureÄ‘ivaÄa teksta za otvaranje datoteke poslužitelja. Možete instalirati Jotu ili sliÄnog ureÄ‘ivaÄa teksta.\n\n Želite li instalirati Jotu? + Nema instaliranog upravitelja datoteka + Nemoguće je pronaći upravitelja datoteka. Možete instalirati OI File Managera ili drugog upravitelja datoteka.\n\n Želite li instalirati OI File Manager? + + + Tcpdump + TCPdump je alat za nadzor DNS zahtjeva i spremanje istih u datoteku zapisa. Možete ga pokrenuti u pozadini, zatim pokretati aplikacije koje prikazuju oglase, a nakon toga analizirati DNS zahtjeve koristeći datoteku zapisa. Zatim mogući poslužitelj oglasa može biti dodan na popis blokiranih. + Onemogći nadgledanje + Omogući nadgledanje + Prikaži rezultate + Razvrstaj domene + ObriÅ¡i zapis + Dodaj unos u popis nedopuÅ¡tenih + Dodaj unos u popis dopuÅ¡tenih + Dodaj unos u popis preusmjernih + + Uredi tekstnu vrijednost postavke + Otvori izbornik + Zatvori izbornik + + + + Naslovnica + Izvori poslužitelja + VaÅ¡i popisi + Otvori datoteku poslužitelja + Zapisuj DNS zahtjeve + Pretraži zlonamjerne aplikacije + Postavke + Pomoć + + + + + DNS zahtjevi + VaÅ¡i popisi + Postavke + + + Instalirano prije %1$s + Najnovija ažuriranja za %1$s + Potrebno je ažuriranje za %1$s + Posljednje ažuriranje prije %1$s + Nepoznato stanje ažuriranja + Onemogućeno + nekoliko minuta + + %d minuta + %d minute + %d minuta + + + %d sat + %d sata + %d sati + + + %d dan + %d dana + %d dana + + + %d mjesec + %d mjeseca + %d mjeseca + + + + Poslužitelj je kopiran u meÄ‘uspremnik + + + pokretanje + aktivan + zaustavljanje + Äekanje mreže + ponovno povezivanje + greÅ¡ka ponovnog povezivanja + pauziran + zaustavljen + VPN blokator oglasa %1$s + Pauziraj + Nastavi + + + AdAway dozvole + Dopusti interakciju sa AdAwayom + PoÅ¡alji naredbu u AdAway + Dopusti slanje naredbe AdAwayu poput omogućavanja ili onemogućavanja blokiranja oglasa Å¡irom sustava + + diff --git a/app/src/main/res/values-hr/strings_app.xml b/app/src/main/res/values-hr/strings_app.xml new file mode 100644 index 0000000..9acb094 --- /dev/null +++ b/app/src/main/res/values-hr/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Blokator oglasa otvorenog kôda + AdAway sliÄica + diff --git a/app/src/main/res/values-hr/strings_errors.xml b/app/src/main/res/values-hr/strings_errors.xml new file mode 100644 index 0000000..8ca3cfe --- /dev/null +++ b/app/src/main/res/values-hr/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Internet nedostupan + Nemoguće uspostavljanje povezivanja s internetom. Provjerite svoju mrežnu povezivost ureÄ‘aja. + Neuspjelo preuzimanje izvora poslužitelja + Niti jedan od vaÅ¡ih omogućenih izvora poslužitelja nije dostupan! Provjerite jeste li ispravno povezani na internet? + + Neuspjelo stvaranje privatne datoteke + Neuspjelo stvaranje privatne datoteke za izgradnju novog izvora poslužitelja. Provjerite slobodan prostor na vaÅ¡em ureÄ‘aju. + Nedovoljno prostora + Neuspjelo kopiranje datoteke poslužitelja na vaÅ¡u particiju sustava. Provjerite je li Magisk systemless modul omogućen a zatim ponovno pokrenite ureÄ‘aj. + Neuspjela instalacija nove datoteke poslužitelja. + Neuspjelo kopiranje datoteka poslužitelja na /system particiju. Provjerite da li je Magisk systemless mogul ukljuÄen te zatim ponovno pokrenite ureÄ‘aj. + Neuspjelo vraćanje datoteke poslužitelja + Neuspjelo vraćanje izvorne datoteke podeÅ¡avanja poslužitelja. + + Neuspjelo omogućavanje VPN blokiranja oglasa. + Provjerite svoje VPN postavke za dopuÅ¡tenje aplikaciji VPN pokretanje. + Neuspjelo onemogućavanje VPN blokiranja oglasa. + Provjerite svoje VPN postavke kako bi ih ruÄno onemogućili. + diff --git a/app/src/main/res/values-hr/strings_home.xml b/app/src/main/res/values-hr/strings_home.xml new file mode 100644 index 0000000..ada31d4 --- /dev/null +++ b/app/src/main/res/values-hr/strings_home.xml @@ -0,0 +1,48 @@ + + + + + Blokirani + DopuÅ¡teni + Preusmjereni + + + + %d ažurirani izvor + %d ažurirana izvora + %d ažuriranih izvora + + + %d zastarjeli izvor + %d zastarjela izvora + %d zastarjelih izvora + + Provjeri ažuriranja + Nadopuni poslužitelje + + + Prikaži zapis DNS zahtjeva + + + Prikaži pomoć\ni savjete + + + Otvori GitHub stranicu + + + Podržite projekt + + + Github projekat + Postavke + + + Otvori navigacijsku ladicu + Pauziraj/Nastavi blokiranje oglasa + Ažuriraj blokirane domene + Prikaži zahtijevane domene + + + ProÄitajte pomoć za viÅ¡e informacija. + + \ No newline at end of file diff --git a/app/src/main/res/values-hr/strings_hosts.xml b/app/src/main/res/values-hr/strings_hosts.xml new file mode 100644 index 0000000..9a4c960 --- /dev/null +++ b/app/src/main/res/values-hr/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Izvori poslužitelja + + Korisnikov popis + AdAway službeni poslužitelji + StevenBlack objedinjeni poslužitelji + Pete Lowe blokirani poslužitelji + + nedostupno + %sposlužitelj(a) + + Dodaj izvor + Uredi izvor + URL: (https:// ili file:// izvor) + URL izvora poslužitelja + diff --git a/app/src/main/res/values-hr/strings_lists.xml b/app/src/main/res/values-hr/strings_lists.xml new file mode 100644 index 0000000..7eb2726 --- /dev/null +++ b/app/src/main/res/values-hr/strings_lists.xml @@ -0,0 +1,24 @@ + + + VaÅ¡i popisi + Dodaj poslužitelja + + Blokirano + DopuÅ¡teno + Preusmjereni + + Filtriranje poslužitelja + Pretraga naziva poslužitelja… + Ukl/Isk izvore + + Dodaj poslužitelj na popis blokiranih + Dodaj poslužitelj u popis neblokiranih + Dodaj poslužitelj na popis preusmjernih + Uredi popis blokiranih poslužitelja + Uredi popis neblokiranih poslužitelja + Uredi preusmjeravanje + Naziv poslužitelja: + URL izvora poslužitelja + (Zamjenski znakovi * i ? su dopuÅ¡teni!) + IP (IPv4 ili IPv6): + diff --git a/app/src/main/res/values-hr/strings_log.xml b/app/src/main/res/values-hr/strings_log.xml new file mode 100644 index 0000000..6a3a24b --- /dev/null +++ b/app/src/main/res/values-hr/strings_log.xml @@ -0,0 +1,11 @@ + + + Uklj/Isklj bilježenje zapisa + Pritisnite tipku snimanja za pokretanje bilježenja zahtjeva, pregledavajte web ili koristite aplikacije, zatim se vratite natag ili povucite po zaslonu za osvježavanje. + \n\nBlokirani zahtjevi neće se bilježiti. Prvo onemogućite blokiranje oglasa ako želite i njih bilježiti. + + Abecedno razvrstavanje + Ravrstavanje najviÅ¡e razine + + Preusmjeri domenu + diff --git a/app/src/main/res/values-hr/strings_notification.xml b/app/src/main/res/values-hr/strings_notification.xml new file mode 100644 index 0000000..229a9f8 --- /dev/null +++ b/app/src/main/res/values-hr/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Ažuriranja + Nova obavijest ažuriranja + Dostupno je ažuriranje izvora + Nove datoteke poslužitelja su dostupne za preuzimanje. + Dostupno je ažuriranje aplikacije + Nova inaÄica AdAwaya je dostupna za preuzimanje. + + VPN + Obavijest o pokrenutom VPN-u + \ No newline at end of file diff --git a/app/src/main/res/values-hr/strings_prefs_backup_restore.xml b/app/src/main/res/values-hr/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4d896cb --- /dev/null +++ b/app/src/main/res/values-hr/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Sigurnosno kopiranje i obnova + Sigurnosno kopiraj + Sigurnosno kopirajte svoja pravila blokiranja na vanjsku pohranu + Obnovi + Obnovite svoja pravila blokiranja iz datoteke sigurnosne kopije + diff --git a/app/src/main/res/values-hr/strings_prefs_main.xml b/app/src/main/res/values-hr/strings_prefs_main.xml new file mode 100644 index 0000000..6df4a85 --- /dev/null +++ b/app/src/main/res/values-hr/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Postavke + + Općenito + Tamna tema + + Svjetla + Tamna + Zadano sustavom + + Automatska ažuriranja + + Blokiranje oglasa + Korijenski (root) temeljen blokator oglasa + VPN temeljen blokator oglasa + Omogući IPv6 podrÅ¡ku + Sigurnosno kopiraj / Obnovi pravila blokiranja + + Otklanjanje greÅ¡aka + PoÅ¡alji izvjeÅ¡taj ruÅ¡enja + PoÅ¡alji na Sentry (sentry.io). + Nije podržano na ovoj izgradnji + OpÅ¡irnije zapisivanje + Ponovno pokretanje aplikacije je potrebno za primjenjivanje. + diff --git a/app/src/main/res/values-hr/strings_prefs_root.xml b/app/src/main/res/values-hr/strings_prefs_root.xml new file mode 100644 index 0000000..3c8754d --- /dev/null +++ b/app/src/main/res/values-hr/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Korijenski (root) temeljen blokator oglasa + + Instalacija poslužitelja + Otvori datoteku poslužitelja + OdrediÅ¡na datoteka poslužitelja + Prije koriÅ¡tenja ove znaÄajke proÄitajte Pomoć + + /system/etc/hosts + /data/hosts + /data/data/hosts + PrilagoÄ‘eno odrediÅ¡te + + PrilagoÄ‘ena lokacija odrediÅ¡ta + Sakrij dijalog ponovnog pokretanja nakon primjenjivanja + + Preusmjeravanje + Odredite gdje će se preusmjeravati blokirani poslužitelji + IPv4 preusmjeravanja + IPv6 preusmjeravanja + Nevaljano preusmjeravanje + + Lokalni web poslužitelj + Lokalni web poslužitelj osluÅ¡kuje lokalne IP adrese u svrhu odgovora na blokirane nazive poslužitelja. Može pomoći pri smrzavanju aplikacija kod blokiranih povezivanja. + Omogući web poslužitelj + Testiraj web poslužitelj + Instaliraj samopotpisanu vjerodajnicu + RuÄna instalacija vjerodajnice + PoÄevÅ¡i od Androida 11 (R), aplikacije viÅ¡e ne mogu automatski instalirati izdavatelja vjerodajnice (CA).\n\nIdite u \"Sigurnost\" postavke, \"Å ifriranje i vjerodajnice\" zatim \" Instaliraj vjerodajnicu\". Tada, odaberite \"CA vjerodajnica\" i odaberite novo izvezvenu datoteku vjerodajnice. + Otvori \"Sigurnost\" postavke + Provjeravanje… + Nije pokrenuto + Pokrenuto ali vjerodajnica nije instalirana + Pokrenuto i vjerodajnica je instalirana + Zamijeni prazan prostor s ikonom aplikacije + diff --git a/app/src/main/res/values-hr/strings_prefs_update.xml b/app/src/main/res/values-hr/strings_prefs_update.xml new file mode 100644 index 0000000..17b21a0 --- /dev/null +++ b/app/src/main/res/values-hr/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + Ažuriranja + + Ažuriranja aplikacije + Provjeri ažuriranja pri pokretanju + Povremeno provjeri ažuriranja + UkljuÄi beta izdanja + + Ažurianja poslužitelja + Provjeri ažuriranja pri pokretanju + Povremeno provjeri ažuriranja + Uskladi pri ažuriranju + Uskladi samo na mrežama s neograniÄenim podacima + diff --git a/app/src/main/res/values-hr/strings_prefs_vpn.xml b/app/src/main/res/values-hr/strings_prefs_vpn.xml new file mode 100644 index 0000000..bde0556 --- /dev/null +++ b/app/src/main/res/values-hr/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN temeljen blokator oglasa + + Omogući pri pokretanju + Nadgledaj povezivanje + Povremeno provjeri stanje mreže za ponovno pokretanje VPN-a pri prekidanju povezivanja. + + Izuzete aplikacije + Postavite koja aplikacija neće koristiti VPN tako da se povezivanja ne blokiraju + Izuzmi aplikacije sustava + + Nijedna + Sve osim web preglednika + Sve + + Izuzmi korisnikove aplikacije + + + Izuzete aplikacije + Odaberi sve + Ukloni odabir svih + Ikona aplikacije + diff --git a/app/src/main/res/values-hr/strings_support.xml b/app/src/main/res/values-hr/strings_support.xml new file mode 100644 index 0000000..4833fbf --- /dev/null +++ b/app/src/main/res/values-hr/strings_support.xml @@ -0,0 +1,5 @@ + + + PodrÅ¡ka + Postanite sponzor + \ No newline at end of file diff --git a/app/src/main/res/values-hr/strings_update.xml b/app/src/main/res/values-hr/strings_update.xml new file mode 100644 index 0000000..7ef602e --- /dev/null +++ b/app/src/main/res/values-hr/strings_update.xml @@ -0,0 +1,21 @@ + + + AdAway ažuriranje + + Dostupno ažuriranje! + + + Ažurirano + Dostupno ažuriranje + Ažuriranje AdAwaya + Ažuriraj odmah + %1$s / %2$s + Zadnje promjene + Popis promjena + Podržite razvoj + Donirajte + Sponzor + + + Preuzimanje posljednje AdAway inaÄice… + diff --git a/app/src/main/res/values-hr/strings_welcome.xml b/app/src/main/res/values-hr/strings_welcome.xml new file mode 100644 index 0000000..26e3e37 --- /dev/null +++ b/app/src/main/res/values-hr/strings_welcome.xml @@ -0,0 +1,52 @@ + + + DobrodoÅ¡li + Prvi korak instalacije + Drugi korak instalacije + Posljednji korak instalacije + + + DobrodoÅ¡li u AdAway! + AdAway omogućuje dva naÄina blokiranja oglasa. Odaberite poželjni naÄin: + + Root logotip + Root temeljeno\nblokiranje oglasa + Brže + Baterijski prihvatljivije + Root je potreban + + VPN logotip + VPN temeljeno\nblokiranje oglasa + Sporije + Pokreni u pozadini + Kompatibilnost + + Potreban je rootani Android + Nemoguće je pronaći su izvrÅ¡nu datoteku ili AdAway nema root dozvole.\n\nOvo se može dogoditi kada vaÅ¡ ureÄ‘aj nije rootan. \n Možete pronaći informacije o rootanju vaÅ¡eg ureÄ‘aja na wiki.lineageos.org ili na drugim Android web stranicama. + + Prednosti + Mane + + + UsklaÄ‘ivanje zavrÅ¡eno + GreÅ¡ka tijekom usklaÄ‘ivanja + + UsklaÄ‘ivanje + UsklaÄ‘eno! + AdAway preuzima mrežna oglaÅ¡avanja kako bi ih blokirao iz mrežnih izvora. Možete ih prilagoditi kasnije u postavkama. + Ponovno pokuÅ¡aj uskladiti + Neuspjelo usklaÄ‘ivanje: %1$s Ponovno pokuÅ¡aj odmah? + + + PodrÅ¡ka + Podrži me! + Ovo je besplatna aplikacija otvorenog kôda. Razvijam ju u slobodno vrijeme. Stoga ako uživate u njoj, slobodno iskažite svoju podrÅ¡ku: + Donirajte na PayPalu + Volite li greÅ¡ke? Ni ja isto. + Omogući telemetriju kako bi mi poslali izvjeÅ¡taj ruÅ¡enja + + + Natrag + Sljedeće + ZavrÅ¡i + diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml new file mode 100644 index 0000000..e01df69 --- /dev/null +++ b/app/src/main/res/values-hu/strings.xml @@ -0,0 +1,264 @@ + + + + Kilépés + Bezárás + Igen + Nem + Hozzáadás + Mégse + Mentés + Súgó + + + Üdv! + Az AdAway egy ingyenes és nyílt forráskódú szoftver, amely blokkolja a hirdetéseket. A hirdetési hálózatok címeit letiltja, hogy blokkolja Å‘ket a készüléken.\nSzeretnél többet tudni? Nézd meg az alábbi súgót! + További információ megjelenítése + Státusz frissítése + A kijelölt hosts fájlok letöltése, összefűzése a saját listákkal, majd aktiválás a rendszeren közös hosts fájlként. + Hirdetésblokkolás engedélyezése + Hirdetésblokkolás letiltása + Webszerver + Fut + Megállítva + Webszerver indítása vagy leállítása a localhost-on, amely válaszol a letiltott hostoknak küldött lekérésekre. + Webszerver engedélyezése + Webszerver letiltása + VPN + Fut + Megállítva + Indítsa el vagy állítsa le a VPN-t a kérelmek szűréséhez + VPN Bekapcsolása + VPN Kikapcsolása + + + Bejegyzés szerkesztése + Alkalmaz + Szerkesztés + Törlés + + + Importálás… + A biztonsági mentés importja a külsÅ‘ tárolóból sikeres. + A biztonsági másolat importálás nem sikerült. MegfelelÅ‘ a formátuma? További részletekért ellenÅ‘rizd a logcat-et. + Exportálás… + A bizt.mentés sikeresen exportálva \'%s\' néven a külsÅ‘ tárhelyre. + Sikertelen a bizt.mentés exportja \'%s\' fájlba. + + + A hosts fájl + A hosts fájl egy olyan rendszerfájl, amely a hosztneveket IP címekhez társítja. Ez egy egyszerű szöveges fájl, melyet az AdAway kezeli. Ãme a néhány elsÅ‘ sora: + Hosts fájl tartalmának betöltése… + Hosts fájl megnyitása + + + Frissítés ellenÅ‘rzése… + %s forrás frissítésének ellenÅ‘rzése + Források lekérése + Források letöltése %s + Források olvasása %s + %s forrás elemzése + Szabály-adatbázis szinkronizálása + Alapértelmezett host fájl visszaállítása + Alapértelmezett host fájl visszaállítva + Alapértelmezett hosts fájl létrehozása + Frissítés érhetÅ‘ el + Újabb hosts fájlok érhetÅ‘k el + Nem található forrásfrissítés + Nincs internetkapcsolat + Nincs elérhetÅ‘ internetkapcsolat + Elérhetetlen források + Nincs elérhetÅ‘ hosts-fájl forrás! + Root hozzáférés megtagadva + Engedélyezd a root hozzáférést a root alkalmazásból + Valami nem stimmel + EllenÅ‘rizd a logcatet további részletekért + Engedélyezett + A legújabb hosts fájlok vannak engedélyezve + Letiltva + Az alapértelmezett hosts fájl van telepítve + Legújabb források alkalmazása + Új hosts fájl készítése + Hosts fájl másolása + Hosts fájl másolásának ellenÅ‘rzése + Hosts fájl sikeresen frissítve + VPN konfiguráció sikeresen frissítve + A konfiguráció megváltozott. Alkalmaznod kell. + Alkalmaz + Új konfiguráció alkalmazása… + Nem sikerült alkalmazni az új konfigurációt. + + + Hiányzik a hosts fájl symlink + A /system/etc/hosts fájlra mutató szimbolikus link nem létezik vagy hibás! Az AdAway nem fog működni, amíg ez nem mutat a megfelelÅ‘ fájlra. + +Szeretnéd megpróbálni létrehozni a szimbolikus linket? + Hiányzó symlink + Nincs elég hely a partíción!\nPróbáld meg módosítani a cél hosts fájlt /data/data/hosts -ra a beállításokban ! + Nincs elég hely + A letöltött fájlt nem lehet beolvasni. + Privát fájl hiba + Nem sikerült a partíciót írhatóként újracsatolni! + Sikertelen újracsatolás + A hosts fájl másolása nem sikerült + Nem sikerült a hosts fájl másolása! + Sikertelen másolás + A hosts források beállítása sikerült + Sikeresen alkalmazva + Sikeresen alkalmazva.\nElÅ‘fordulhat, hogy a módosítások érvényesítéséhez újra kell indítani az Androidot.\n\nSzeretnéd most újraindítani?\n(Az adatvesztés elkerülése érdekében gyÅ‘zÅ‘dj meg róla, hogy egyetlen alkalmazás sem használja az SD kártyát!) + A symlink sikeresen létrehozva.\nElÅ‘fordulhat, hogy a módosítások érvényesítéséhez újra kell indítani az Androidot.\n\nSzeretnéd most újraindítani?\n(Az adatvesztés elkerülése érdekében gyÅ‘zÅ‘dj meg róla, hogy egyetlen alkalmazás sem használja az SD kártyát!) + A symlink létrehozása sikeres + Nem tudta létrehozni a symlink-et az Android.\nEz elsÅ‘sorban a HTC telefonok S-ON \"funkciójának\" köszönhetÅ‘.\n\nA megoldás az, hogy telefonját recovery módba kapcsolja és létrehozza ott a symlink-et \'ln -s /data/data/hosts /system/etc/hosts\' paranccsal.\n\nHa ez sem működik keressen rá az interneten, arra a szövegre, hogy \"S-OFF + a telefonja\". + Szimbolikus link létrehozása sikertelen + Kérlek olvassa el a Súgót további információkért! + Egy APN proxy van beállítva az készülékén!\nAz AdAway nem fog megbízhatóan működni az olyan mobilhálózatokon, mint pl. a 3G. Ezt a proxy-t deaktiválhatod, ha a kiválasztott APN-hez lépsz (A Beállításokban: Hálózat & Internet -> Mobil hálózat -> Haladó -> Hozzáférési pontok nevei) ás távolítsd el az értéket a proxy mezÅ‘bÅ‘l. + APN proxy beállítva! + Az internetkapcsolat nem működik. + Nincs kapcsolat + Letöltés… + Alkalmazás… + Fekete- és fehérlista alkalmazása + Hosts fájlok feldolgozása és összefésülése + Hosts fájl felépítése + Hosts fájl alkalmazása + Az új hosts fájl alkalmazása nem sikerült + Nem sikerült a hosts fájl alkalmazása rendszeren!\nPróbálja meg /data/data/hosts-ra módosítani a cél hosts fájlt a beállításokban. + Az alkalmazás nem sikerült + EllenÅ‘rizze a root kezelÅ‘ alkalmazásban a root hozzáférés megadását. + Visszaállította az alapértelmezett hosts fájlt.\nElÅ‘fordulhat, hogy a módosítások érvényesítéséhez újra kell indítani az Androidot.\n\nSzeretné most újraindítani?\n(Az adatvesztés elkerülése érdekében gyÅ‘zÅ‘djön meg róla, hogy egyetlen alkalmazás sem használja az SD kártyát!) + Sikeres visszaállítás + A hosts fájl visszaállítása nem sikerült + A visszaállítás ismeretlen ok miatt nem sikerült. + Sikertelen visszaállítás! + Egyik engedélyezett hosts fájl sem érhetÅ‘ el! MegfelelÅ‘ az internetkapcsolat? + Sikertelen letöltés + A privát hosts fájl írása nem sikerült + Privát fájl nem hozható létre. + Privát fájl létrehozása sikertelen. + Engedélyezte a systemless módot.\nElÅ‘fordulhat, hogy a módosítások érvényesítéséhez újra kell indítani az Androidot.\n\nSzeretné most újraindítani?\n(Az adatvesztés elkerülése érdekében gyÅ‘zÅ‘dj meg róla, hogy egyetlen alkalmazás sem használja az SD kártyát!) + Engedélyezés sikeres + Kikapcsolta a systemless módot.\nElÅ‘fordulhat, hogy a módosítások érvényesítéséhez újra kell indítani az Androidot.\n\nSzeretné most újraindítani?\n(Az adatvesztés elkerülése érdekében gyÅ‘zÅ‘dj meg róla, hogy egyetlen alkalmazás sem használja az SD kártyát!) + Sikerült a letiltás + Nem sikerült a VPN reklámblokkolás engedélyezése. + Nem sikerült letiltani a VPN reklámblokkolást. + Magisk hosts modul engedélyezése + Systemless hosts funkció bekapcsolása a Magisk managerben. A beállításokban kapcsolja be a Systemless hosts lehetÅ‘séget, majd indítsa újra a készüléket. + Magisk hosts modul letiltása + Systemless hosts funkció kikapcsolása a Magisk managerben. A modul listából távolítssa el a Systemless hosts modult majd indítsa újra az eszközt. + + + Adja meg a host fájl URL címét: + Ez nem egy érvényes hosztnév! + Helytelenül formázott hosztnév + Ez nem érvényes IP! + Helytelenül formázott IP cím + Soha ne indítsa újra és ne jelenítse meg ezt a kérdést legközelebb! + Betöltés… + + + Frissítés + Hozzáadás + Súgó + Bizt.mentés import + Bizt.mentés export + + + S-ON/S-OFF + GYIK + Problémák + + + Adware + Itt megtalálhatja a telepített adware-eket, a rossz alkalmazásokat, amelyeket az AdAway nem blokkolhat. Ezek az alkalmazások például Airpush értesítéseket használnak, amelyek akkor is megjelennek, ha az alkalmazás nem fut, vagy akár csengÅ‘hangot is megváltoztathatnak. Az egyetlen használható megoldás az, hogy ezeket az alkalmazásokat a listaelemekre kattintva eltávolítja. + Keresés… + Nem található adware! + + + Hirdetésblokkoló + Nincs telepítve szövegszerkesztÅ‘ + Nem találni olyan szövegszerkesztÅ‘t, amely megnyitná a hosts fájlt. A fájl kezeléséhez feltelepítheti a Jota-t vagy más szövegszerkesztÅ‘t. Szeretné telepíteni a Jota-t? + Nincs telepítve fájlkezelÅ‘ + Nincs olyan fájlkezelÅ‘ telepítve, amely megnyithatná a fájlt. A fájl kezeléséhez telepítheti az OI File Manager-t, vagy bármilyen más fájlkezelÅ‘t. Szeretné telepíteni az OI File Manager-t? + + + Tcpdump + A tcpdump olyan eszköz, amely monitorozza és elmenti egy naplófájlba a DNS kéréseket. Futtassa a háttérben, majd a reklámokat megjelenítÅ‘ alkalmazások elindítását követÅ‘en után elemezze a DNS kérések a napló alapján. A lehetséges reklámkiszolgáló-szerverek ezután hozzáadhatóak a feketelistához. + Monitorozás tiltása + Monitorozás engedélyezése + Eredmények megjelenítése + Domainek rendezése + Napló törlése + Elem hozzáadása feketelistához + Elem hozzáadása fehérlistához + Elem hozzáadása az átirányítási listához + + Szöveges beállítási érték szerkesztése + Menü megnyitása + Menü bezárása + + + + KezdÅ‘lap + Hosts források + Saját listák + Hosts fájl megnyitása + A DNS kérések naplózása + Adware keresése + Beállítások + Súgó + + + + + DNS kérések + Saját listák + Beállítások + + + Telepítve %1$sezelÅ‘tt + Friss (frissítve %1$s ezelÅ‘tt) + %1$sfrissítése szükséges + Utolsó frissítés %1$s ezelÅ‘tt + Ismeretlen frissítési státusz + Letiltva + néhány perce + + %d perc + %d perc + + + %d óra + %d óra + + + %d nap + %d nap + + + %d hónap + %d hónap + + + + Host a vágólapra másolva + + + elindítás + aktív + megállítás + várakozás a hálózatra + újracsatlakozás + újracsatlakozási hiba + szüneteltetve + megállítva + Hirdetésblokkoló VPN %1$s + Szüneteltetés + Folytat + + + AdAway engedélyek + Engedélyezd az AdAway-interakciót + Parancsok küldése az AdAway-nek + Parancsküldés engedélyezése az AdAway számára, pl. a rendszerszintű hirdetésblokkolás engedélyezése vagy letiltása + + diff --git a/app/src/main/res/values-hu/strings_app.xml b/app/src/main/res/values-hu/strings_app.xml new file mode 100644 index 0000000..532361a --- /dev/null +++ b/app/src/main/res/values-hu/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Nyílt forráskódú hirdetésblokkoló + AdAway logo + diff --git a/app/src/main/res/values-hu/strings_errors.xml b/app/src/main/res/values-hu/strings_errors.xml new file mode 100644 index 0000000..cad3159 --- /dev/null +++ b/app/src/main/res/values-hu/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Nincs internetkapcsolat + Nem sikerült kapcsolatot létesíteni az internettel. EllenÅ‘rizze az eszköz csatlakozását. + Nem sikerült letölteni a host forrást + Egyik engedélyezett hosts forrás sem érhetÅ‘ el. EllenÅ‘rizze, megfelelÅ‘en csatlakozik-e az internethez. + + Nem sikerült létrehozni a privát fájlt + Nem lehet privát fájlt létrehozni új hosts forrás létrehozásához. EllenÅ‘rizze a készüléken a szabad tárhelyet. + Nincs elég hely + Nem lehet a hosts fájlt a rendszerpartícióra másolni. EllenÅ‘rizze, hogy a Magisk systemless modul engedélyezve van-e, majd indítsa újra. + Nem sikerült az új hosts fájl telepítése + A hosts fájl nem másolható a /system partícióra. EllenÅ‘rizd, hogy a Magisk systemless modul engedélyezve van-e, majd indítsd újra. + A hosts fájl visszaállítása nem sikerült + Nem sikerült visszaállítani az alapért. hosts fájl konfigurációt. + + Nem sikerült engedélyezni a VPN reklámblokkolást. + Jelöld be a VPN beállításoknál, hogy engedélyezze az app VPN indítását. + Nem sikerült letiltani a VPN reklámblokkolást. + EllenÅ‘rizd a VPN beállításokat a manuális letiltáshoz. + diff --git a/app/src/main/res/values-hu/strings_home.xml b/app/src/main/res/values-hu/strings_home.xml new file mode 100644 index 0000000..db39e71 --- /dev/null +++ b/app/src/main/res/values-hu/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Blokkolt + Megengedve + Ãtirányítva + + + + %d up-to-date source + %d naprakész forrás + + + %d outdated source + %d elavult forrás + + Hosts frissítések ellenÅ‘rzése + Hosztok frissítése + + + Mutassa a DNS kérések naplót + + + Mutassa a súgó\nand tippeket + + + GitHub oldal megnyitása + + + Projekt támogatása + + + GitHub projekt + Beállítások + + + Navigációs fiók megnyitása + Reklámblokkolás szünet/folytat + Blokkolt domainek frissítése + A kért domainek megjelenítése + + + Kérlek olvassa el a Súgót további információkért! + + \ No newline at end of file diff --git a/app/src/main/res/values-hu/strings_hosts.xml b/app/src/main/res/values-hu/strings_hosts.xml new file mode 100644 index 0000000..220ee21 --- /dev/null +++ b/app/src/main/res/values-hu/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Hosts források + + Felhasználói lista + AdAway official hosts + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + nem érhetÅ‘ el + %shoszt + + Forrás hozzáadása + Forrás szerkesztése + URL: (https:// vagy file:// erÅ‘forrás) + Hosts fájl forrása (URL) + diff --git a/app/src/main/res/values-hu/strings_lists.xml b/app/src/main/res/values-hu/strings_lists.xml new file mode 100644 index 0000000..d37b614 --- /dev/null +++ b/app/src/main/res/values-hu/strings_lists.xml @@ -0,0 +1,24 @@ + + + Saját listák + Host hozzáadása + + Blokkolt + Megengedett + Ãtirányítva + + Hosztok szűrése + Hosztnevek keresése + Források váltása + + Hoszt hozzáadása a feketelistához + Hoszt hozzáadása a fehérlistához + Hoszt átirányítás hozzáadása + Feketelistás hostok szerkesztése + Fehérlista szerkesztése + Ãtirányítás szerkesztése + Hosztnév: + Hosts fájl forrása (URL) + (HelyettesítÅ‘ karakterek * és ? használata is engedélyezett!) + IP (IPv4 vagy IPv6): + diff --git a/app/src/main/res/values-hu/strings_log.xml b/app/src/main/res/values-hu/strings_log.xml new file mode 100644 index 0000000..05210af --- /dev/null +++ b/app/src/main/res/values-hu/strings_log.xml @@ -0,0 +1,8 @@ + + + + Rendezés ABC sorrendben + Rendezés TLD szerint + + Domain átirányítása + diff --git a/app/src/main/res/values-hu/strings_notification.xml b/app/src/main/res/values-hu/strings_notification.xml new file mode 100644 index 0000000..d71c3cd --- /dev/null +++ b/app/src/main/res/values-hu/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Frissítések + Új frissítés értesítések + Frissítés érhetÅ‘ el + Újabb hosts fájl elérhetÅ‘. + Alkalmazás frissítés elérhetÅ‘ + Az AdAway új verziója letölthetÅ‘. + + VPN + VPN futása értesítések + \ No newline at end of file diff --git a/app/src/main/res/values-hu/strings_prefs_backup_restore.xml b/app/src/main/res/values-hu/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..ea88a90 --- /dev/null +++ b/app/src/main/res/values-hu/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Mentés & visszaállítás + Biztonsági mentés + Blokkszabályok biztonsági mentése külsÅ‘ tárhelyre + Visszaállítás + Blokkszabályok visszaállítása a biztonsági mentés fájlból + diff --git a/app/src/main/res/values-hu/strings_prefs_main.xml b/app/src/main/res/values-hu/strings_prefs_main.xml new file mode 100644 index 0000000..d675ddc --- /dev/null +++ b/app/src/main/res/values-hu/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Beállítások + + Ãltalános + Sötét téma + + Világos + Sötét + Rendszer alapértelmezett + + Automatikus frissítések + + Hirdetésblokkolás + Root alapú hirdetésblokkolás + VPN alapú hirdetésblokkolás + IPv6 engedélyezése + Blokkszabályok mentése / visszaállítása + + Hibakeresés + Összeomlási jelentések BE + Az alkalmazás hibaüzenet- és összeomlási jelentést küld a Sentry-nek (sentry.io). + Nem támogatott ezen a verzión + Részletes naplózás bekapcsolása + Újra kell indítani az AdAway-t a beállítás életbe léptetéséhez. + diff --git a/app/src/main/res/values-hu/strings_prefs_root.xml b/app/src/main/res/values-hu/strings_prefs_root.xml new file mode 100644 index 0000000..8b29bbd --- /dev/null +++ b/app/src/main/res/values-hu/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Root alapú hirdetésblokkolás + + Hosts telepítése + Hosts fájl megnyitása + Cél hosts fájl + Ezen beállítás módosítása elÅ‘tt olvassa el a Súgó vonatkozó fejezetét! + + /system/etc/hosts + /data/hosts + /data/data/hosts + Egyéni cél + + Egyéni cél + Újraindítási ablak elrejtése + + Ãtirányítás + Adja meg hova irányítsa a letiltott hosztokat + IPv4 átirányítás + IPv6 átirányítás + Érvénytelen átirányítás + + Helyi webszerver + A helyi webszerver meghallgatja a helyi IP-címeket, hogy válaszoljon a blokkolt gazdagép-kérelmekre. Segítheti az alkalmazás lefagyasztását blokkolt kapcsolat esetén. + Webszerver engedélyezése + Webszerver tesztelése + Önaláírt tanusítvány telepítése + Tanusítvány manuális telepítése + Az Android 11 (R) verziótól kezdve az alkalmazás már nem tudja automatikusan telepíteni a tanusítványt (CA).\n\nLépjen a \"biztonsági\" beállítások menübe, majd \"Titkosítás és hitelesítÅ‘ adatok\", azután a \"Tanusítvány telepítése\" opcióba. Ott válassza a \"CA tanusítványt\" és jelölje ki az újonnan exportált fájlt. + \"Biztonsági\" beállítások megnyitása + EllenÅ‘rzés… + Nem fut + Fut, de a tanusítvány nincs telepítve + Fut és a tanusítvány telepítve van + Üres hirdetési felület cseréje az alkalmazás ikonra + diff --git a/app/src/main/res/values-hu/strings_prefs_update.xml b/app/src/main/res/values-hu/strings_prefs_update.xml new file mode 100644 index 0000000..1df7dab --- /dev/null +++ b/app/src/main/res/values-hu/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + Frissítések + + Alkalmazás frissítések + Indításkor a frissítések ellenÅ‘rizése + Frissítések keresése naponta + Tartalmazza a béta verziókat + + Hosts frissítések + Indításkor a frissítések ellenÅ‘rizése + Frissítések keresése naponta + Szinkronizálás frissítéskor + Szinkronizálás csak nem mért hálózaton + diff --git a/app/src/main/res/values-hu/strings_prefs_vpn.xml b/app/src/main/res/values-hu/strings_prefs_vpn.xml new file mode 100644 index 0000000..410b0d3 --- /dev/null +++ b/app/src/main/res/values-hu/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN alapú hirdetésblokkolás + + Engedélyezés indításkor + Kapcsolat figyelÅ‘ + Rendszeresen ellenÅ‘rzi a hálózat állapotát a VPN újraindításához a szétkapcsoláskor. + + Kizárt alkalmazások + Ãllítsa be, mely alkalmazások ne használják a VPN-t. Ãgy egyetlen kapcsolat sem lesz blokkolva. + Rendszeralkalmazások kizárása + + None + All except browsers + All + + Felhasználói alkalmazások kizárása + + + Kizárt alkalmazások + Összes kijelölése + Összes kijelölésének törlése + Application icon + diff --git a/app/src/main/res/values-hu/strings_support.xml b/app/src/main/res/values-hu/strings_support.xml new file mode 100644 index 0000000..be3c01f --- /dev/null +++ b/app/src/main/res/values-hu/strings_support.xml @@ -0,0 +1,5 @@ + + + Támogatás + Legyél szponzor + \ No newline at end of file diff --git a/app/src/main/res/values-hu/strings_update.xml b/app/src/main/res/values-hu/strings_update.xml new file mode 100644 index 0000000..7d0c1cc --- /dev/null +++ b/app/src/main/res/values-hu/strings_update.xml @@ -0,0 +1,21 @@ + + + AdAway frissítés + + Frissítés elérhetÅ‘! + + + Naprakész vagy + Frissítés érhetÅ‘ el + AdAway frissítése + Frissítés most + %1$s / %2$s + Utolsó változtatások + Változásnapló + Fejlesztés támogatása + Adományozás + Támogató + + + Legutóbbi AdAway verzió letöltése… + diff --git a/app/src/main/res/values-hu/strings_welcome.xml b/app/src/main/res/values-hu/strings_welcome.xml new file mode 100644 index 0000000..43be991 --- /dev/null +++ b/app/src/main/res/values-hu/strings_welcome.xml @@ -0,0 +1,52 @@ + + + Üdv + A varázsló elsÅ‘ lépése + A varázsló második lépése + A varázsló utolsó lépése + + + Üdv az AdAway alkalmazásban! + Az AdAway két hirdetésblokkoló módot kínál. Válassza ki azt, amelyik tetszik: + + Root logo + Root alapú\nhirdetésblokkolás + Gyorsabb + Akkumulátor-barát + Root szükséges + + VPN logo + VPN alapú\nhirdetésblokkolás + Lassabb + Fut a háttérben + Kompatibilitás + + Rootolt Android szükséges + Vagy nem található a su bináris, vagy nem engedélyezte a root hozzáférést az AdAway számára.\n\nEz akkor fordulhat elÅ‘, ha az eszköt nem rendelkezik root jogosultságokkal. A készülék rootolásáról további információkat a wiki.lineageos.org vagy más Android weboldalon talál. + + ElÅ‘ny + Hátrány + + + Szinkronizálás kész + Hiba történt a szinkronizálás közben + + Szinkronizálás + Szinkronizálva! + Az AdAway letölti a hirdetési hálózatokat, hogy blokkolja az online forrásokat. A beállításokban késÅ‘bb testreszabhatja Å‘ket. + Szinkronizálás újrapróbálása + Nem sikerült a szinkronizálás: %1$s Újrapróbálkozás? + + + Támogatás + Támogass engem! + Ez egy ingyenes és nyílt forráskódú alkalmazás. A szabadidÅ‘mben fejlesztem, ezért ha tetszik a projekt, és megteheted, támogass: + Támogatás PayPal-on keresztül + Szereted a bugokat? Én se. + Telemetria engedélyezése összeomlási jelentések küldéséhez + + + Vissza + KövetkezÅ‘ + Befejezés + diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml new file mode 100644 index 0000000..b1300e4 --- /dev/null +++ b/app/src/main/res/values-in/strings.xml @@ -0,0 +1,258 @@ + + + + Keluar + Tutup + Ya + Tidak + Tambah + Batal + Simpan + Bantuan + + + Selamat Datang! + AdAway adalah perangkat lunak gratis dengan desain kode terbuka untuk memblokir iklan. AdAway menangkap alamat-alamat jaringan iklan untuk memblokirnya di perangkatmu.\nIngin tahu lebih? Lihat bantuan di bawah! + Tampilkan semua bantuan + Keterangan pembaharuan + Semua file hosts dari sumber yang ditentukan sudah didownload dan digabungkan dengan daftar anda dan dipasang menjadi satu file host dalam sistem anda. + Hidupkan pemblokir iklan + Matikan pemblokir iklan + Layanan perambah + Berjalan + Berhenti + Mulai atau hentikan web server pada localhost untuk menjawab permintaan untuk memblok hostnames + Hidupkan layanan perambah + Matikan layanan perambah + VPN + Berjalan + Berhenti + Mulai atau hentikan VPN untuk menyaring permintaan + Hidupkan VPN + Matikan VPN + + + Ubah Masukan + Terapkan + Sunting + Hapus + + + Mengimpor … + Cadangan sukses diimpor dari penyimpanan eksternal anda + Cadangan gagal diimpor. Apakah formatnya benar? Lihat logcat untuk detail lebih. + Mengekspor … + File backup \'%s\' berhasil di export ke penyimpanan eksternal + Gagal untuk mengeksport file backup \'%s\'. + + + Daftar hosts + File host adalah File sistem yang memetakan antara nama host dengan alamat IP. Itu adalah file teks biasa yang konfigurasinya ditangani oleh Adaway. Berikut beberapa baris pertamanya: + Membaca isi file host… + Buka file host + + + Memeriksa pembaruan + Cek pembaruan sumber %s + menerima sumber + Mengunduh sumber %s + membaca sumber %s + Mengurai %s sumber + Mensinkronasi peraturan database + Mengembalikan ke file hosts standar + file hosts kembali ke standar + Membuat host file standar + Sumber pembaruan tersedia + Berkas hosts terbaru tersedia + Tidak ada pembaruan + Tidak ada koneksi internet + Tidak ada koneksi internet yang tersedia + Sumber tidak tersedia + Tidak ada sumber host yang terjangkau! + Akses root ditolak + Ijinkan akses root dari aplikasi root anda + Terjadi kesalahan + Periksa logcat untuk lebih jelasnya + Dinyalakan + Berkas hosts terbaru dinyalakan + Dimatikan + File host bawaan dipasang + Terapkan sumber terbaru + Membuat file host baru + Menyalin file host baru + Memeriksa salinan file host + Berhasil memperbarui file host + Berhasil memperbarui konfigurasi VPN + Konfigurasi anda berubah. Anda perlu menerapkannya. + Terapkan + Menerapkan konfigurasi baru… + Gagal menerapkan konfigurasi baru + + + Symlink ke target file host tidak di temukan + Symlink dari target ke /system/etc/hosts tidak benar atau tidak ada! AdAway tidak akan bekerja jika hal itu tidak dibetulkan.\n\nApa anda ingin mencoba membuat symlink? + Symlink tidak ditemukan + Tidak ada cukup ruang di partisi!\nCobalah mengganti target file host di prefrensi menjadi /data/data/hosts. + Tidak cukup ruang + Berkas terunduh tidak dapat dibaca. + Berkas pribadi gagal + Mount ulang partisi sebagai read/write gagal! + remount gagal + Gagal menyalin file host + Penyalinan file host gagal! + Penyalinan gagal + Sumber host diterapan + Penerapan berhasil + Penerapan telah berhasil. Anda mungkin perlu melakukan reboot Android untuk perubahan berefek. Apakah Anda ingin reboot? (Untuk mencegah kehilangan data pastikan tidak ada aplikasi menggunakan sdcard saat ini!) + Symlink telah berhasil dibuat.\nIni mungkin membutuhkan memuat ulang Android untuk mendapatkan hasil dari perubahan.\n\nApakah anda ingin memuat ulang?\n(Untuk mencegah adanya kehilangan data, pastikan tidak ada aplikasi yang menggunakan kartu SD pada saat ini!) + Pembuatan symlink berhasil + Symlink tidak dapat di buat oleh Android.\nKebanyakan ini gagal karena \'fitur\' yang disebut S-ON pada ponsel HTC!\n\nSolusi untuk masalah ini adalah dengan masuk ke mode recovery lalu buat symlink dengan perintah \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nJika masih tidak mempan carilah di Internet cara untuk S-OFF ponselmu. + Pembuatan symlink gagal + Silahkan baca Help untuk informasi lebih lanjut. + Sebuah proksi APN terkonfigurasi pada Android mu!\nAdAway mungkin tidak berdungsi semestinya pada jaringan seperti 3G. Kamu bisa mematikan proksi pada APN terkonfigurasi (Pengaturan aplikasi: Jaringan & Internet -> Jaringan Mobile -> Lanjutan -> Nama Akses Poin) dan hapus nilai pada kolom proksi. + APN peladen pewali ditentukan! + Koneksi internet tidak berfungsi. + Tidak ada koneksi + Sedang mendownload… + Menerapkan perubahan… + Menerapkan daftar hitam dan putih + Mengakses dan menggabungkan file host + Menyusun file hosts + Menerapkan file host + Gagal menerapkan file host baru + Penerapan file host ke sistem anda gagal!\nCobalah untuk mengganti target file host di prefrensi ke /data/data/hosts. + Pemasangan gagal + Mohon cek aplikasi manajemen root Anda untuk memastikan akses root telah diberikan. + Anda mengembalikan ke file host bawaan.\nIni mungkin membutuhkan memuat ulang Android untuk mendapatkan hasil dari perubahan.\n\nApakah anda ingin memuat ulang?\n(Untuk mencegah adanya kehilangan data, pastikan tidak ada aplikasi yang menggunakan kartu SD pada saat ini!) + Pengembalian berhasil + Tidak bisa mengembalikan file host + Pengembalian gagal karena alasan yang tidak diketahui. + Pengembalian gagal + Tak satu pun dari sumber host yang Anda aktifkan bisa dijangkau! Apakah Anda terhubung dengan benar dengan internet? + Download gagal + Gagal membuat file hosts pribadi + Berkas pribadi tidak dapat dibuat. + Pembuatan berkas pribadi gagal + Kamu mengaktifkan mode systemless.\nlt perlu sekiranya untuk memulai ulang Android agar perubahan efektif.\n\nIngin memulai ulang?\n(Untuk mencegah kehilangan data pastikan tidak ada aplikasi yang menggunakan kartu SD saat ini!) + Aktivasi berhasil + Kamu mematikan mode systemless.\nlt perlu sekiranya untuk memulai ulang Android agar perubahan efektif.\n\nIngin memulai ulang?\n(Untuk mencegah kehilangan data pastikan tidak ada aplikasi yang menggunakan kartu SD saat ini!) + Berhasil menonaktifkan + Gagal mengaktifkan VPN pem-blok iklan + Gagal mematikan VPN pem-blok iklan + Mengaktifkan modul hosts Magisk + Aktifkan fitur systemless host dari Magisk Manager. Melalui pengaturan, aktifkan pilihan Systemless hosts lalu mulai ulang perangkatmu. + Menonaktifkan modul hosts Magisk + Matikan fitur systemless host dari Magisk Manager. Dari daftar modul, uninstall modul Systemless hosts lalu mulai ulang perangkatmu. + + + Masukan URL ke file hosts: + Ini bukan hostname yang benar! + Hostname tidak diformat dengan benar + Ini bukan IP yang benar! + IP tidak diformat dengan benar + Jangan pernah nyalakan ulang dan jangan tampilkan pertanyaan ini lain kali + Memuat… + + + Segarkan + Tambah + Bantuan + Impor cadangan + Ekspor cadangan + + + S-ON/S-OFF + FAQ + Masalah + + + Adware + Disini Anda dapat menemukan adware yang terpasang, aplikasi jelek yang tidak dapat diblok oleh AdAway. Aplikasi ini digunakan sebagai contoh, notifikasi Airpush yang muncul ketika aplikasi tidak berjalan ataupun mengganti ringtonemu. Satu-satunya penanggulangan yang tersedia adalah melepas aplikasi-aplikasi tersebut dengan mengklik pada daftar item. + Memindai… + Adware tidak ditemukan! + + + Ad blocker + Tidak terinstal pengedit teks + Tidak ada editor teks yang dapat ditemukan untuk membuka file host. Anda bisa menginstal Jota atau teks editor lain.\n\nApakah anda ingin menginstal Jota? + Tidak ada manager file yang terpasang + Tidak ada manajer file yang dapat ditemukan untuk membuka file. Anda bisa menginstal OI File Manager atau manajer file lain.\n\nApakah anda ingin menginstal OI File Manager? + + + Tcpdump + Tcpdump adalah alat untuk memonitor permintan DNS dan menyimpannya ke file. Anda bisa membuka aplikasi yang memunculkan iklan, dan selanjutnya menganalisai permintaan DNS. Server iklan bisa tisa di tambahkan ke daftar hitam anda. + Matikan pemantauan + Hidupkan pemantauan + Tampilkan hasil + Sortir domain + Bersihkan catatan + Tambahkan pada daftar hitam + Tambahkan pada daftar putih + Tambahkan pada daftar pengalihan + + Ubah nilai preferensi teks + Buka menu + Tutup menu + + + + Beranda + Sumber host + Daftar pribadi + Buka berkas hosts + Catatan permintaan DNS + Pindai terhadap adware + Pengaturan + Bantuan + + + + + Aktifitas DNS + Daftar pribadi + Pengaturan + + + Terpasang %1$s yang lalu + Pembaruan untuk %1$s + Pembaruan dibutuhkan untuk %1$s + Pembaruan terakhir %1$s yang lalu + Status pembaharuan tidak diketahui + Dimatikan + beberapa menit + + %d menit + + + %d jam + + + %d hari + + + %d bulan + + + + Host terkopi ke papan klip + + + memulai + Aktif + menghentikan + menunggu jaringan + menghubungkan + gagal menghubungkan + Jeda + berhenti + VPN Pem-blok iklan %1$s + Jeda + Lanjutkan + + + Izin AdAway + Izinkan untuk berinteraksi dengan AdAway + Kirim perintah ke AdAway + Izinkan untuk mengirim perintah ke AdAway, seperti mengaktifkan atau mematikan system-wide ad-blocking + + diff --git a/app/src/main/res/values-in/strings_app.xml b/app/src/main/res/values-in/strings_app.xml new file mode 100644 index 0000000..23843b5 --- /dev/null +++ b/app/src/main/res/values-in/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Ad blocker Open Source + logo AdAway + diff --git a/app/src/main/res/values-in/strings_errors.xml b/app/src/main/res/values-in/strings_errors.xml new file mode 100644 index 0000000..03a342f --- /dev/null +++ b/app/src/main/res/values-in/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Tidak ada koneksi internet + Tidak bisa menyambung koneksi ke internet. Tolong cek koneksi perangkat anda. + Gagal mengunduh sumber hosts + Tidak ada satupun sumber hosts anda dapat terjangkau. Tolong cek bahwa anda sudah benar terkoneksi ke internet. + + Gagal untuk membuat file private + Gagal membuat file private untuk membangun sumber hosts baru. Tolong cek ruang penyimpanan yang tersedia di perangkat anda. + Tidak cukup ruang + Tidak bisa menduplikasi file hosts ke partisi system anda. Tolong cek modul Magisk systemless diaktifkan dan mulai ulang. + Gagal untuk memasang file hosts baru + Tidak dapat menyalin file ke partisi /system, cek modul systemless Magisk, aktifkan, kemudian reboot. + Gagal mengembalikan file host + Gagal mengembalikan host ke aturan bawaan + + Gagal mengaktifkan VPN pem-blok iklan + Cek peraturan VPN untuk mengizinkan aplikasi memulai VPN + Gagal mematikan VPN pem-blok iklan + Cek peraturan VPN untuk menonaktifkan secara manual + diff --git a/app/src/main/res/values-in/strings_home.xml b/app/src/main/res/values-in/strings_home.xml new file mode 100644 index 0000000..b344be4 --- /dev/null +++ b/app/src/main/res/values-in/strings_home.xml @@ -0,0 +1,44 @@ + + + + + Diblokir + Diizinkan + Dialihkan + + + + %d sumber up-to-date + + + %d sumber usang + + Mengecek pembaruan host + Perbaharui daftar + + + Perlihatkan log DNS requests + + + Tampilkan bantuan\ndan tips + + + Buka GitHub Page + + + Dukung proyek + + + Proyek GitHub + Pengaturan + + + Buka laci navigasi + Jeda / lanjutkan pemblokiran iklan + Perbarui domain yang diblokir + Tampilkan domain yang diminta + + + Silahkan baca Help untuk informasi lebih lanjut. + + \ No newline at end of file diff --git a/app/src/main/res/values-in/strings_hosts.xml b/app/src/main/res/values-in/strings_hosts.xml new file mode 100644 index 0000000..800befd --- /dev/null +++ b/app/src/main/res/values-in/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Sumber host + + User list + Official AdAway host + Hosts StevenBlack Unified + Hosts Pete Lowe blocklist + + Tidak tersedia + %s hosts + + Tambah sumber + Ubah sumber + URL: (a https:// atau file:// sumber) + Alamat sumber daftar + diff --git a/app/src/main/res/values-in/strings_lists.xml b/app/src/main/res/values-in/strings_lists.xml new file mode 100644 index 0000000..1a50511 --- /dev/null +++ b/app/src/main/res/values-in/strings_lists.xml @@ -0,0 +1,24 @@ + + + Daftar pribadi + Tambah hosts + + Diblokir + Diizinkan + Dialihkan + + Filter host + Cari hostname… + Beralih sumber + + Tambahkan pada daftar hitam + Tambahkan pada daftar putih + Tambahkan pada daftar pengalihan + Sunting host daftar hitam + Sunting host daftar putih host + Kelola pengalihan + Hostname: + Alamat sumber daftar + (Karakter * dan ? diperbolehkan) + IP (IPv4 atau IPv6): + diff --git a/app/src/main/res/values-in/strings_log.xml b/app/src/main/res/values-in/strings_log.xml new file mode 100644 index 0000000..0383312 --- /dev/null +++ b/app/src/main/res/values-in/strings_log.xml @@ -0,0 +1,11 @@ + + + Tombol rekam log + Tekan rekam untuk memulai log, browsing atau gunakan aplikasi target, kemudian kembali atau refresh halaman ini + \n\nNonaktifkan ad-block dulu sebelum memuali log + + Urutkan sesuai abjad + Urutkan sesuai TLD + + Alihkan domain + diff --git a/app/src/main/res/values-in/strings_notification.xml b/app/src/main/res/values-in/strings_notification.xml new file mode 100644 index 0000000..52370e9 --- /dev/null +++ b/app/src/main/res/values-in/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Pembaruan + Notifikasi pembaruan + Sumber pembaruan tersedia + File host terbaru tersedia untuk di unduh + Pembaruan app tersedia + AdAway versi terbaru tersedia untuk di unduh. + + VPN + Notifikasi VPN berjalan + diff --git a/app/src/main/res/values-in/strings_prefs_backup_restore.xml b/app/src/main/res/values-in/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..76477c6 --- /dev/null +++ b/app/src/main/res/values-in/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Backup & pulihkan + Backup + Backup aturan blokir ke penyimpanan eksternal + Pulihkan + Pulihkan aturan blookir dari berkas backup + diff --git a/app/src/main/res/values-in/strings_prefs_main.xml b/app/src/main/res/values-in/strings_prefs_main.xml new file mode 100644 index 0000000..6abae13 --- /dev/null +++ b/app/src/main/res/values-in/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Pengaturan + + Umum + Gunakan tema gelap + + Terang + Gelap + Bawaan sistem + + Pembaruan otomatis + + Pemblokir iklan + Mode root + Mode vpn + Aktifkan IPv6 + Backup / memulihkan aturan blokir + + Debug + Nyalakan laporan crash + Ijinkan aplikasi untuk mengirim laporan error dan crash ke Sentry (sentry.io) + Tidak mendukung pada build ini + Nyalakan verbose logging + Anda perlu memulai kembali AdAway agar pengaturan ini berlaku. + diff --git a/app/src/main/res/values-in/strings_prefs_root.xml b/app/src/main/res/values-in/strings_prefs_root.xml new file mode 100644 index 0000000..fc28f10 --- /dev/null +++ b/app/src/main/res/values-in/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + pemblokir basis root + + Install hosts + Buka berkas hosts + Target file host + Sebelum mengganti pengaturan. Baca panduan untuk fungsi tersebut. + + /system/etc/hosts + /data/hosts + /data/data/hosts + Kustom target + + Kustom target + Sembunyikan pesan reboot + + Pengalihan + Masukkan kemana hosts akan dialihkan + Redireksi IPv4 + Redireksi IPv6 + Pengalihan salah + + Peladen Web lokal + Server web lokal mendengarkan alamat IP lokal untuk menjawab permintaan nama host yang diblokir. Ini dapat membantu dengan pembekuan aplikasi pada koneksi yang diblokir. + Aktifkan peladen web + Tes server web + Instal sertifikat self-signed + Instal sertifikat manual + Mulai dari Android 11 (R), aplikasi tidak bisa menginstall certificate authority (CA).\n\nBuka \"keamanaan\" pada setelan, \"Enkripsi & kredensial\" kemudian \"menginstal sertifikat\". Setelah itu, pilih \"Sertifikat CA\" dan pilih file sertifikat yang baru dibuat. + Buka \"Keamanan\" di setelan + Memeriksa… + Tidak berjalan + Berjalan tapi tidak terinstal + Berjalan dan terinstal + Mengganti iklan yang terblokir dengan ikon app + diff --git a/app/src/main/res/values-in/strings_prefs_update.xml b/app/src/main/res/values-in/strings_prefs_update.xml new file mode 100644 index 0000000..7a7cc98 --- /dev/null +++ b/app/src/main/res/values-in/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Pembaruan + Notifikasi dinonaktifkan + Notifikasi aplikasi tidak dapat ditampilkan, Tap untuk mengaktifkan. + + Update aplikasi + Periksa update tiap mulai + Periksa pembaruan setiap hari + menyertakan rilisan beta + + Update hosts + Periksa update tiap mulai + Periksa pembaruan setiap hari + Sinkronisasi saat update + Hanya singkronisasi pada koneksi tak dibatasi + diff --git a/app/src/main/res/values-in/strings_prefs_vpn.xml b/app/src/main/res/values-in/strings_prefs_vpn.xml new file mode 100644 index 0000000..f560b3c --- /dev/null +++ b/app/src/main/res/values-in/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Mode vpn + + Mengizinkan saat mulai + Memonitor konneksi + Cek keadaan koneksi berkala untuk restart koneksi VPN + + Aplikasi yang dikecualikan + Atur aplikasi yang tidak menggunakan VPN agar koneksi tidak terblokir + Kecualikan aplikasi sisttem + + None + All except browsers + All + + kecualikan aplikasi pengguna + + + Aplikasi yang dikecualikan + Pilih semua + Batal pilih semua + Ikon aplikasi + diff --git a/app/src/main/res/values-in/strings_source_edit.xml b/app/src/main/res/values-in/strings_source_edit.xml new file mode 100644 index 0000000..dcf0bb4 --- /dev/null +++ b/app/src/main/res/values-in/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Ubah sumber + Tambah sumber + + Label + Label dibutuhkan + Tipe + URL + File + Lokasi + https:// + Lokasi dibutuhkan + Tekan File untuk memilih sumber berkasnya + Lokasi salah + Daftar format + Blokir + Ijinkan + Perbolehkan pengalihan host + Memperbolehkan pengalihan host dapat menyebabkan masalah keamanan. Hanya gunakan pengaturan ini pada sumber yang terpercaya, karena ini dapat mengalihkan lalu lintas data sensitif ke server manapun. + diff --git a/app/src/main/res/values-in/strings_support.xml b/app/src/main/res/values-in/strings_support.xml new file mode 100644 index 0000000..bca0f3f --- /dev/null +++ b/app/src/main/res/values-in/strings_support.xml @@ -0,0 +1,5 @@ + + + Dukungan + Menjadi sponsor + diff --git a/app/src/main/res/values-in/strings_update.xml b/app/src/main/res/values-in/strings_update.xml new file mode 100644 index 0000000..ee1bc5b --- /dev/null +++ b/app/src/main/res/values-in/strings_update.xml @@ -0,0 +1,21 @@ + + + Pembaruan AdAway + + Pembaruan tersedia! + + + Kamu sudah up-to-date + Pembaruan tersedia + Memperbarui AdAway + Perbarui sekarang + %1$s / %2$s + Perubahan terakhir + Changelog + Dukung pengembangan + Donasi + Sponsor + + + Mengunduh AdAway versi terbaru… + diff --git a/app/src/main/res/values-in/strings_welcome.xml b/app/src/main/res/values-in/strings_welcome.xml new file mode 100644 index 0000000..241a07f --- /dev/null +++ b/app/src/main/res/values-in/strings_welcome.xml @@ -0,0 +1,54 @@ + + + Selamat datang + Langkah pertama + Langkah Kedua + Langkah ketiga + + + Selamat datang di AdAway! + AdAway menyediakan dua metode pemblokiran iklan. +Pilih salah satu yang kamu inginkan: + + Logo root + Pemblokiran iklan menggunakan root + Lebih cepat + Hemat baterai + Membutuhkan mode root + + logo VPN + Pemblokiran iklan menggunakan VPN + Lebih lambat + Berjalan di latar belakang + Kompatibilitas + + Dibutuhkan perangkat Android yang sudah di-root + Binary su tidak ditemukan atau anda tidak memberikan izin root untuk AdAway.\n\nIni dapat terjadi ketika perangkat anda tidak memiliki akses root. Anda dapat menemukan informasi mengenai cara root perangkat anda di wiki.lineageos.org atau webiste Android lainnya. + + Kelebihan + Kekurangan + + + Singkronisasi selesai + Kesalahan saat melakukan sinkronisasi + + Sedang menyinkronkan + Sudah tersinkron! + AdAway mengunduh jaringan iklan untuk memblokir dari sumber-sumber online. Anda dapat menyesuaikannya nanti di pengaturan. + Mengulang sinkorinisasi + Gagal saat sinkronisasi: %1$s Coba lagi? + dapat mengirimkan notifikasi tentang blok iklan dan pengaturan, juga notifikasi update aplikasi yang tersedia (beberapa kali per tahun). Aktifkan jika ingin tetap up-to-date + + + Dukungan + Dukung saya! + AdAway adalah aplikasi graris dan open-source yang dikembangkan pada waktu luang saya. Jika kamu menyukainya, terima kasih dukungannya: + Donasi di PayPal + Anda menyukai bug? Saya juga tidak. + Izinkan penggunaan telemetri untuk mengirimkan laporan kesalahan kepada saya + + + Kembali + Selanjutnya + Selesai + diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml new file mode 100644 index 0000000..9e45587 --- /dev/null +++ b/app/src/main/res/values-is/strings.xml @@ -0,0 +1,14 @@ + + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-is/strings_app.xml b/app/src/main/res/values-is/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-is/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-is/strings_errors.xml b/app/src/main/res/values-is/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-is/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-is/strings_home.xml b/app/src/main/res/values-is/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-is/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-is/strings_hosts.xml b/app/src/main/res/values-is/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-is/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-is/strings_lists.xml b/app/src/main/res/values-is/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-is/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-is/strings_log.xml b/app/src/main/res/values-is/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-is/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-is/strings_notification.xml b/app/src/main/res/values-is/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-is/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-is/strings_prefs_backup_restore.xml b/app/src/main/res/values-is/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-is/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-is/strings_prefs_main.xml b/app/src/main/res/values-is/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-is/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-is/strings_prefs_root.xml b/app/src/main/res/values-is/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-is/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-is/strings_prefs_update.xml b/app/src/main/res/values-is/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-is/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-is/strings_prefs_vpn.xml b/app/src/main/res/values-is/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-is/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-is/strings_support.xml b/app/src/main/res/values-is/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-is/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-is/strings_update.xml b/app/src/main/res/values-is/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-is/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-is/strings_welcome.xml b/app/src/main/res/values-is/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-is/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml new file mode 100644 index 0000000..1eafc0b --- /dev/null +++ b/app/src/main/res/values-it/strings.xml @@ -0,0 +1,267 @@ + + + + Esci + Chiudi + Sì + No + Aggiungi + Annulla + Salva + Aiuto + + + Benvenuto! + AdAway è un software gratuito e open-source progettato per bloccare pubblicità. Raccoglie gli indirizzi pubblicitari per bloccarli sul tuo dispositivo.\nVuoi saperne di più? Controlla la sezione di aiuto qui sotto! + Mostra più suggerimenti + Aggiorna stato + Tutti i file hosts vengono scaricati dalle sorgenti definite, uniti alle tue liste personali e installati come un unico file hosts nel sistema + Abilita blocco pubblicità + Disabilita blocco pubblicità + Web server + In esecuzione + Interrotto + Avvia o interrompe il web server su localhost per rispondere alle richieste degli hostname bloccati + Abilita il web server + Disabilita web server + VPN + In esecuzione + Interrotto + Avvia o interrompe la VPN per filtrare le richieste + Abilita VPN + Disabilita VPN + + + Modifica valore + Applica + Modifica + Elimina + + + Importazione… + Backup correttamente importato dalla SDcard + Importazione del backup non riuscita. Il formato è corretto? Controlla il log per maggiori dettagli + Esporto… + Backup correttamente esportato nel file \'%s\' nella memoria esterna. + È fallita l\'esportazione del file di backup \'%s\'. + + + Il file hosts + Il file hosts è un file di sistema che mappa gli hostnames in indirizzi IP. È un semplice file di testo la cui configurazione è gestita da AdAway. Ecco alcune righe: + Caricamento contenuto del file hosts… + Apri il file hosts + + + Controllo aggiornamenti in corso + Controllo aggiornamenti sorgente %s + Recupero delle sorgenti + Scarico sorgente %s + Leggo sorgente %s + Analizzo sorgente %s + Sincronizzazione del database delle regole + Ripristino in corso del file hosts predefinito + File hosts predefinito ripristinato + Creo file hosts standard + Aggiornamento sorgenti disponibile + File hosts più recenti disponibili + Nessuna sorgente da aggiornare + Nessuna connessione internet + Nessuna connessione internet disponibile + Sorgenti non disponibili + Nessuna sorgente hosts raggiungibile! + Permessi di root negati + Concedi i permessi di root dal root manager che utilizzi + Qualcosa è andato storto + Controlla il registro per i dettagli + Abilitato + File hosts più recente abilitato + Disabilitato + File host predefiniti installati + Applica sorgenti aggiornate + Creazione in corso del nuovo file hosts + Copio il nuovo file hosts + Controllo in corso della copia del file hosts + File hosts aggiornato con successo + Configurazione VPN aggiornata + Configurazione modificata. Ora devi applicarla + Applica + Applico nuova configurazione… + Applicazione nuova configurazione fallita + + + Symlink del file hosts di destinazione mancante + Il collegamento simbolico a /system/etc/hosts non esiste o non è corretto! AdAway non funzionerà se il collegamento non punta al file giusto.\n\nVuoi provare a creare un collegamento simbolico? + Collegamento simbolico mancante + Non c\'è abbastanza spazio nella partizione!\nProva a cambiare il percorso del file hosts in /data/data/hosts nelle preferenze. + Spazio non sufficiente + Il file scaricato non può essere letto + Creazione file privato fallita + Remount della partizione in lettura/scrittura fallito! + Remount fallito! + Impossibile copiare il file hosts + Copia del file host fallita! + Copia fallita + Sorgenti host applicate + Modifiche applicate! + Modifiche effettuate con successo.\nPotrebbe essere necessario riavviare Android affinché le modifiche abbiano effetto.\n\nVuoi riavviare?\n(Per evitare la perdita di dati assicurati che nessuna app utilizzi la SDcard al momento!) + Symlink è stato creato con successo.\nPotrebbe essere necessario riavviare Android affinché le modifiche abbiano effetto.\n\nVuoi riavviare?\n(Per evitare la perdita di dati assicurati che nessuna app utilizzi la SDcard al momento!) + Collegamento simbolico creato con successo + Il collegamento simbolico non può essere creato da Android.\nQuesto problema è dovuto quasi sicuramente a una \"caratteristica\" chiamata S-ON nei telefoni HTC!\n\nUna possibile soluzione è quella di avviare il telefono in modalità recovery e creare il collegamento simbolico con \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nSe questo non dovesse funzionare fai una ricerca su Internet su S-OFF e il tuo telefono + Creazione del collegamento simbolico fallita + Leggere l\'Aiuto per ulteriori informazioni + Un proxy APN è impostato sul tuo Android!\nAdAway non funzionerà in modo affidabile quando connesso a reti mobili come il 3G. Puoi disattivare il proxy andando nelle impostazioni del tuo APN (Nell\'app Impostazioni: Rete e Internet -> Rete mobile -> Avanzate -> Nomi punti di accesso) e rimuovendo il contenuto del campo proxy + Proxy APN impostato! + La connesione a internet non funziona + Nessuna connessione + Scarico… + Applico… + Applico Blacklist e Whitelist + Analizzo e unisco file hosts + Costruisco file hosts + Applico file hosts + Impossibile applicare il nuovo file host + L\'applicazione del file hosts è fallita!\nProva a cambiare il percorso del file hosts in /data/data/hosts nelle preferenze. + Modifiche non applicate! + Controlla il root manager per assicurarti che i permessi di root siano stati concessi + Sei tornato al file hosts predefinito.\nPotrebbe essere necessario riavviare Android affinché le modifiche abbiano effetto.\n\nVuoi riavviare?\n(Per evitare la perdita di dati assicurati che nessuna app utilizzi la scheda SD al momento!) + Ripristino effettuato! + Impossibile ripristinare il file hosts + Ripristino fallito per ragioni sconosciute + Ripristino fallito! + Nessuna delle sorgenti hosts che hai abilitato è raggiungibile! Sei connesso a internet? + Download fallito + Impossibile scrivere il nuovo file hosts privato + Il file privato non può essere creato + Creazione file privato fallita + Hai attivato la modalità systemless.\nPotrebbe essere necessario riavviare Android affinché le modifiche abbiano effetto.\n\nVuoi riavviare?\n(Per evitare perdite di dati assicurati che nessuna app utilizzi la scheda SD al momento!) + Attivazione completata + Hai disabilitato la modalità systemless.\nPotrebbe essere necessario riavviare Android per applicare i cambiamenti. .\n\nVuoi riavviare?\n(Per impedire perdita di dati assicurati che nessuna app al momento sta utilizzando la scheda SD!) + Disattivazione completata + Impossibile abilitare la VPN per il blocco pubblicità + Impossibile disabilitare la VPN per il blocco pubblicità + Abilito il modulo hosts di Magisk + Abilita la funzione hosts systemless da Magisk Manager. Dalle impostazioni, abilita l\'opzione Host systemless e poi riavvia il dispositivo + Disabilito il modulo hosts di Magisk + Disabilita la funzione host systemless da Magisk Manager. Dalla lista dei moduli, disinstalla il modulo Host systemless e poi riavvia il dispositivo + + + Inserisci URL al file hosts: + Questo non è un hostname valido! + Nome host non formattato correttamente + Questo non è un IP valido! + IP non formattato correttamente + Non riavviare e non mostrare più questo messaggio! + Caricamento… + + + Aggiorna + Aggiungi + Aiuto + Importa backup + Esporta backup + + + S-ON/S-OFF + FAQ + Problemi + + + Adware + Qui puoi troverai l\'adware installato, applicazioni malevole che non possono essere bloccate da AdAway. Queste applicazioni utilizzano, ad esempio, notifiche Airpush che appaiono anche quando l\'app non è in esecuzione o che modificano la tua suoneria. L\'unica contromisura disponibile è quella di disinstallare queste applicazioni cliccando sugli elementi dell\'elenco + Scansione in corso… + Nessun Adware trovato! + + + Blocca pubblicità + Nessun editor di testo installato + Nessun editor di testo trovato per aprire il file hosts. Puoi installare Jota o un altro editor di testo per rimediare.\n\nVuoi installare Jota? + Nessun file manager installato + Nessun file manager trovato per aprire i file. Puoi installare OI File Manager o altri file manager per rimediare.\n\n +Vuoi installare OI File Manager? + + + Tcpdump + Tcpdump è uno strumento per monitorare le richieste DNS e salvarle in un file di log. E\' possibile eseguirlo in background, aprire l\'applicazione che visualizza la pubblicità, e poi analizzare le richieste fatte grazie al file di log. Eventuali server pubblicitari possono essere poi aggiunti alla blacklist + Disabilita monitoraggio + Abilita monitoraggio + Mostra risultati + Ordinamento per dominio + Pulisci i log + Aggiungi voce a blacklist + Aggiungi voce alla whitelist + Aggiungi voce alla lista reindirizzamenti + + Modifica il valore di testo + Apri menù + Chiudi menù + + + + Home + Sorgenti host + Le tue liste + Apri file hosts + Log richieste DNS + Scansione Adware + Preferenze + Aiuto + + + + + Richieste DNS + Le tue liste + Preferenze + + + Installato %1$s fa + Aggiornato %1$s fa + Richiede aggiornamento da %1$s + Ultimo aggiornamento %1$s fa + Stato aggiornamento sconosciuto + Disabilitato + pochi minuti + + %d minuto + %d minuti + %d minuti + + + %d ora + %d ore + %d ore + + + %d giorno + %d giorni + %d giorni + + + %d mese + %d mesi + %d mesi + + + + Host copiati negli appunti + + + Avvio in corso + attivo + Interruzione in corso + In attesa di rete + In riconnessione + Errore di riconnessione + In pausa + Interrotto + VPN Ad-blocker %1$s + Pausa + Riprendi + + + Permessi di AdAway + Permetti di interagire con AdAway + Manda comandi a AdAway + Permetti l\'invio di comandi a AdAway come attivare o disattivare il blocco pubblicità a livello di sistema + + diff --git a/app/src/main/res/values-it/strings_app.xml b/app/src/main/res/values-it/strings_app.xml new file mode 100644 index 0000000..2b3d0ca --- /dev/null +++ b/app/src/main/res/values-it/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Blocco pubblicità Open Source + Logo di AdAway + diff --git a/app/src/main/res/values-it/strings_errors.xml b/app/src/main/res/values-it/strings_errors.xml new file mode 100644 index 0000000..6bdd8c4 --- /dev/null +++ b/app/src/main/res/values-it/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Nessuna connessione Internet + Impossibile stabilire una connessione Internet. Controlla la connessione del tuo dispositivo + Impossibile scaricare dalla sorgente hosts + Nessuna delle sorgenti hosts abilitate è raggiungibile. Assicurati di essere correttamente connesso ad Internet + + Impossibile creare file privato + Impossibile creare il file privato per assemblare la nuova sorgente hosts. Assicurati che ci sia spazio disponibile sul tuo dispositivo + Spazio non sufficiente + Impossibile copiare il file hosts nella partizione /system. Controlla se il modulo systemless di Magisk è attivo e riavvia il dispositivo + Impossibile installare il nuovo file hosts + Impossibile copiare il file hosts nella partizione /system. Controlla se il modulo systemless di Magisk è attivo e poi riavvia il dispositivo. + Impossibile ripristinare file hosts + Impossibile ripristinare la configurazione predefinita del file hosts + + Impossibile abilitare VPN per blocco pubblicità + Controlla le impostazioni VPN per autorizzare l\'app ad avviare la VPN + Impossibile disabilitare la VPN per il blocco pubblicità + Controlla le impostazioni VPN per disabilitarla manualmente + diff --git a/app/src/main/res/values-it/strings_home.xml b/app/src/main/res/values-it/strings_home.xml new file mode 100644 index 0000000..fba1ab4 --- /dev/null +++ b/app/src/main/res/values-it/strings_home.xml @@ -0,0 +1,48 @@ + + + + + Bloccati + Autorizzati + Reindirizzati + + + + %d sorgente aggiornata + %d sorgenti aggiornate + %d sorgenti aggiornate + + + %d sorgente obsoleta + %d sorgenti obsolete + %d sorgenti obsolete + + Controlla aggiornamenti host + Aggiorna gli hosts + + + Registro richieste DNS + + + Aiuto + + + GitHub + + + Supporto + + + Progetto GitHub + Preferenze + + + Apri menù di navigazione + Metti in pausa/riprendi blocco pubblicità + Aggiorna domini bloccati + Mostra domini richiesti + + + Leggi l\'aiuto per maggiori informazioni + + \ No newline at end of file diff --git a/app/src/main/res/values-it/strings_hosts.xml b/app/src/main/res/values-it/strings_hosts.xml new file mode 100644 index 0000000..9e65517 --- /dev/null +++ b/app/src/main/res/values-it/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Sorgenti hosts + + Lista utente + Hosts ufficiali AdAway + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + non disponibile + %s hosts + + Aggiungi sorgente + Modifica sorgente + URL: (una risorsa https:// o file://) + URL sorgente hosts + diff --git a/app/src/main/res/values-it/strings_lists.xml b/app/src/main/res/values-it/strings_lists.xml new file mode 100644 index 0000000..6b628c3 --- /dev/null +++ b/app/src/main/res/values-it/strings_lists.xml @@ -0,0 +1,24 @@ + + + Le tue liste + Aggiungi host + + Bloccati + Autorizzati + Reindirizzati + + Filtra hosts + Cerca hostname… + Attiva/disattiva sorgenti + + Aggiungi host alla blacklist + Aggiungi host alla whitelist + Aggiungi reindirizzamento host + Modifica host in blacklist + Modifica host in whitelist + Modifica reindirizzamento + Hostname: + URL sorgente hosts + (I caratteri jolly * e ? sono consentiti) + IP (IPv4 o IPv6): + diff --git a/app/src/main/res/values-it/strings_log.xml b/app/src/main/res/values-it/strings_log.xml new file mode 100644 index 0000000..f6fd6ec --- /dev/null +++ b/app/src/main/res/values-it/strings_log.xml @@ -0,0 +1,11 @@ + + + Attiva/disattiva registrazione log + Premi registra per avviare la raccolta delle richieste, naviga su internet o usa le app, quindi torna indietro o scorri per aggiornare i log. + \n\nLe richieste bloccate non verranno registrate. Se vuoi includerle, devi prima disabilitare il blocco pubblicità. + + Ordinamento alfabetico + Ordinamento per dominio di primo livello + + Reindirizza dominio + diff --git a/app/src/main/res/values-it/strings_notification.xml b/app/src/main/res/values-it/strings_notification.xml new file mode 100644 index 0000000..b35fb37 --- /dev/null +++ b/app/src/main/res/values-it/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Aggiornamenti + Notifica nuovo aggiornamento + Aggiornamento sorgenti disponibile + File hosts più recente disponibile + Aggiornamento dell\'app disponibile + Nuova versione di AdAway disponibile + + VPN + Notifica VPN in esecuzione + diff --git a/app/src/main/res/values-it/strings_prefs_backup_restore.xml b/app/src/main/res/values-it/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..57686f5 --- /dev/null +++ b/app/src/main/res/values-it/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Backup e ripristino + Backup + Salva le regole di blocco sullo spazio di archiviazione esterno + Ripristina + Ripristina le regole di blocco da un file di backup + diff --git a/app/src/main/res/values-it/strings_prefs_main.xml b/app/src/main/res/values-it/strings_prefs_main.xml new file mode 100644 index 0000000..8661950 --- /dev/null +++ b/app/src/main/res/values-it/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Preferenze + + Generale + Tema scuro + + Chiaro + Scuro + Predefinito + + Aggiornamenti automatici + + Blocco pubblicità + Blocco pubblicità basato su root + Blocco pubblicità basato su VPN + Abilita supporto IPv6 + Backup / ripristino regole di blocco + + Debug + Invia segnalazioni errori + Inviare errori a Sentry (sentry.io) + Non supportato in questa versione + Log dettagliato + Riavviare AdAway per applicare le modifiche + diff --git a/app/src/main/res/values-it/strings_prefs_root.xml b/app/src/main/res/values-it/strings_prefs_root.xml new file mode 100644 index 0000000..689f64e --- /dev/null +++ b/app/src/main/res/values-it/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Blocco pubblicità basato su root + + Installazione file hosts + Apri file hosts + Percorso file hosts + Leggi l\'Aiuto prima di usare questa funzione + + /system/etc/hosts + /data/hosts + /data/data/hosts + Destinazione personalizzata + + Percorso personalizzato + Nascondi la richiesta di riavvio + + Reindirizzamento + Specifica dove reindirizzare gli host bloccati + Reindirizzamento IPv4 + Reindirizzamento IPv6 + Reindirizzamento non valido + + Web server locale + Il web server locale rimane in ascolto sugli indirizzi IP locali per rispondere alle richieste degli hostname bloccati. Può aiutare con le app che danno problemi sulle connessioni bloccate. + Abilita web server + Test web server + Installa certificato autofirmato + Installazione manuale del certificato + A partire da Android 11 (R), le app non possono più installare automaticamente un\'autorità di certificazione (CA). \n\nVai alle impostazioni di Sicurezza, \"Crittografia e Credenziali\" e a \"Installa un certificato\". Quindi scegli \"Certificato CA\" e seleziona il file del certificato appena esportato. + Apri impostazioni di Sicurezza + Verifica in corso… + Non in esecuzione + In esecuzione ma certificato non installato + In esecuzione con certificato installato + Riempi lo spazio pubblicitario con l\'icona dell\'app + diff --git a/app/src/main/res/values-it/strings_prefs_update.xml b/app/src/main/res/values-it/strings_prefs_update.xml new file mode 100644 index 0000000..89eb58e --- /dev/null +++ b/app/src/main/res/values-it/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Aggiornamenti + Notifiche disabilitate + Le notifiche dell\'app non verranno mostrate. Tocca per abilitarle. + + Aggiornamenti dell\'app + Controlla all\'avvio + Controlla periodicamente + Includi versioni beta + + Aggiornamenti degli host + Controlla all\'avvio + Controlla periodicamente + Sincronizza all\'aggiornamento + Sincronizza solo su connessioni non a consumo + diff --git a/app/src/main/res/values-it/strings_prefs_vpn.xml b/app/src/main/res/values-it/strings_prefs_vpn.xml new file mode 100644 index 0000000..dfd4856 --- /dev/null +++ b/app/src/main/res/values-it/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Blocco pubblicità su VPN + + Abilita all\'avvio + Monitora connessione + Controlla periodicamente lo stato della rete per riavviare la VPN quando si disconnette. + + App escluse + Configura quali app non devono usare la VPN per non bloccare alcuna connessione + Escludi app di sistema + + Nessuna + Tutte eccetto i browser + Tutte + + Escludi app utente + + + App escluse + Seleziona tutte + Deseleziona tutte + Icona app + diff --git a/app/src/main/res/values-it/strings_source_edit.xml b/app/src/main/res/values-it/strings_source_edit.xml new file mode 100644 index 0000000..28be21d --- /dev/null +++ b/app/src/main/res/values-it/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Modifica sorgente + Aggiungi sorgente + + Etichetta + Etichetta obbligatoria + Tipo + URL + File + Posizione + https:// + Posizione obbligatoria + Premi File per selezionare il file della sorgente + Posizione non valida + Formato lista + Blocca + Autorizza + Applica host reindirizzati + Consentire gli host reindirizzati può causare problemi di sicurezza. Usa questa opzione solo con una sorgente affidabile, dal momento che potrebbe reindirizzare del traffico sensibile a qualunque server essa specifichi. + diff --git a/app/src/main/res/values-it/strings_support.xml b/app/src/main/res/values-it/strings_support.xml new file mode 100644 index 0000000..4a521d9 --- /dev/null +++ b/app/src/main/res/values-it/strings_support.xml @@ -0,0 +1,5 @@ + + + Supporto + Diventa uno sponsor + \ No newline at end of file diff --git a/app/src/main/res/values-it/strings_update.xml b/app/src/main/res/values-it/strings_update.xml new file mode 100644 index 0000000..a97edf6 --- /dev/null +++ b/app/src/main/res/values-it/strings_update.xml @@ -0,0 +1,22 @@ + + + Aggiornamento di AdAway + + Aggiornamento disponibile! + + + Sei aggiornato + Aggiornamento disponibile + Aggiornando AdAway + Aggiorna ora + %1$s/%2$s + Completato + Le ultime novità: + Registro modifiche + Supporta lo sviluppo + Fai una donazione + Sponsor + + + Download in corso dell\'ultima versione di AdAway… + diff --git a/app/src/main/res/values-it/strings_welcome.xml b/app/src/main/res/values-it/strings_welcome.xml new file mode 100644 index 0000000..df318f8 --- /dev/null +++ b/app/src/main/res/values-it/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Benvenuto + Procedura Guida primo passo + Procedura Guida secondo passo + Procedura Guida ultimo passo + + + Benvenuto in AdAway! + AdAway ha due modalità per bloccare le pubblicità. Scegli quella che preferisci: + + Logo root + Blocco pubblicità\ntramite root + Più veloce + Non ha impatto sulla batteria + Richiede il root + + Logo VPN + Blocco pubblicità\ntramite VPN + Più lento + Esecuzione in background + Compatibilità + + Richiesto Android con root + Non è stato trovato il binario SU o non hai concesso i permessi di root ad AdAway.\n\nPuò succedere quando il tuo dispositivo non ha i permessi di root.\nPuoi trovare maggiori informazioni su come abilitarli per il tuo dispositivo su wiki.lineageos.org o su altri siti web riguardanti Android. + + Pro + Contro + + + Sincronizzazione completata + Errore durante la sincronizzazione + + Sincronizzazione in corso + Sincronizzato! + AdAway scarica da sorgenti online le reti pubblicitarie da bloccare. Puoi personalizzarle dalle impostazioni + Riprova sincronizzazione + Sincronizzazione fallita: %1$s Vuoi riprovare adesso? + Può inviare notifiche per mostrare lo stato e i controlli del blocco pubblicità, e per segnalare la disponibilità di aggiornamenti dell\'app (poche volte all\'anno). Abilitale se vuoi rimanere aggiornato. + + + Supporto + Supportami! + AdAway è un\'app gratuita e open-source che sviluppo nel mio tempo libero. Se ti piace, sentiti libero di mostrare il tuo sostegno: + Dona tramite PayPal + Ti piacciono i bug? Neanche a me. + Abilita la telemetria per inviarmi le segnalazioni di errori + + + Indietro + Avanti + Fine + diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml new file mode 100644 index 0000000..de6cde6 --- /dev/null +++ b/app/src/main/res/values-iw/strings.xml @@ -0,0 +1,272 @@ + + + + יצי××” + סגירה + כן + ×œ× + הוספה + ביטול + שמירה + עזרה + + + ברוך הב×! + AdAway ×”×™× ×ª×•×›× ×ª קוד פתוח חינמית לחסימת פרסומות. התוכנה שולפת כתובות רשת של ×ž×¤×¨×¡×ž×™× ×›×“×™ ×œ×—×¡×•× ×ותן במכשיר שלך.\nרוצה לדעת עוד? היעזר בעזרה למטה! + הצג עזרה נוספת + מצב העדכון + כל קבצי המ××¨×—×™× ×ž×”×ž×§×•×¨×•×ª ×”×ž×•×’×“×¨×™× ×”×•×¨×“×•, מוזגו ×¢× ×”×¨×©×™×ž×•×ª שלך והותקנו כקובץ מ×רח יחיד במערכת שלך. + הפעל חסימת פרסומות + בטל חסימת פרסומות + שרת ×ינטרנט + פעיל + כבוי + הפעל ×ו עצור ×ת השרת המקומי כדי לענות על בקשות לשמות מ×רח חסומי×. + הפעל שרת ×ינטרנט + בטל שרת ×ינטרנט + VPN + פעיל + כבוי + הפעל ×ו הפסק VPN כדי לסנן בקשות. + VPN פעיל + VPN מושבת + + + ערוך רשומה + החל + ערוך + מחק + + + מייב×… + גיבוי ×™×•×‘× ×‘×”×¦×œ×—×” מה×חסון החיצוני + ×™×™×‘×•× ×”×’×™×‘×•×™ נכשל. ×”×× ×¤×•×¨×ž×˜ הגיבוי נכון? בדוק ×ת logcat ×œ×¤×¨×˜×™× × ×•×¡×¤×™×. + מייצ×… + הגיבוי ×™×•×¦× ×‘×”×¦×œ×—×” לקובץ \'%s\' ב×חסון החיצוני שלך. + ×™×™×¦×•× ×§×•×‘×¥ הגיבוי \'%s\' נכשל. + + + קובץ מ××¨×—×™× + קובץ המ××¨×—×™× ×”×•× ×§×•×‘×¥ מערכת הממפה שמות מ××¨×—×™× ×œ×›×ª×•×‘×•×ª IP. זהו קובץ טקסט רגיל שנוצר ומתוחזק על־ידי AdAway. להלן כמה שורות ר×שונות: + + + טוען תוכן קובץ מ×רחי×… + פתח קובץ מ××¨×—×™× + + + בדיקת ×¢×“×›×•× ×™× + בדיקת עדכון במקור %s + ×חזור מקורות + מוריד ×ת מקור %s + ×§×•×¨× ×ת מקור %s + מנתח ×ת מקור%s + מסנכרן חוקי מסד × ×ª×•× ×™× + מ×חזר לברירת מחדל ×ת קובץ המ××¨×—×™× + קובץ מ××¨×—×™× ×©×•×—×–×¨ לברירת מחדל + יוצר קובץ מ××¨×—×™× ×¨×’×™×œ + ×§×™×™× ×¢×™×“×›×•×Ÿ + קבצי מ××¨×—×™× ×—×“×©×™× ×–×ž×™× ×™× ×œ×”×•×¨×“×” + ×œ× × ×ž×¦×ו עדכוני מקורות + ×ין חיבור ל×ינטרנט + ×ין חיבור זמין ל×ינטרנט + מקורות ×œ× ×–×ž×™× ×™× + ×œ× ×”×•×©×’×• מקורות מ×רחי×! + ×ין גישת root + ×פשר גישת root מ×פליקציית ×”-root שלך + משהו ×œ× ×ª×§×™×Ÿ קרה + בדוק ב-logcat על מנת לקבל מידע נוסף + פעיל + קבצי מ××¨×—×™× ×—×“×©×™× ×¤×¢×™×œ×™× + ×œ× ×¤×¢×™×œ + קובץ מ××¨×—×™× ×‘×¨×™×¨×ª המחדל הותקן + החלת מקורות ××—×¨×•× ×™× + יצירת קובץ מ××¨×—×™× ×—×“×© + העתקת קובץ מ××¨×—×™× ×—×“×© + בדיקת העתק קובץ מ××¨×—×™× + קובץ מ××¨×—×™× ×¢×•×“×›×Ÿ בהצלחה + תצורת ×”Ö¾VPN עודכנה בהצלחה + התצורה שלך השתנתה. עליך להחיל ×ותה. + החל + מחיל תצורה חדשה… + החלת התצורה החדשה נכשלה. + + + ההפניה ליעד של קובץ המ××¨×—×™× ×—×¡×¨×”. + קישור המערכת שלך ×ל /system/etc/hosts ×ינו ×§×™×™× ×ו ×ינו נכון! AdAway ×œ× ×™×¤×¢×œ ×× ×œ× ×ª×‘×—×¨ ×ת הקובץ הנכון.\n\n×”×× ×‘×¨×¦×•× ×š לנסות ליצור קישור מערכת? + קישור סימבולי ×œ× ×§×™×™× + ×ין מספיק שטח ×יחסון בדיכרון!\nנסה לשנות בהעדפות התוכנה ×ת הגדרת היעד ל /data/data/hosts. + ×ין מספיק זיכרון + ×œ× × ×™×ª×Ÿ ×œ×§×¨×•× ×ž×”×§×•×‘×¥ שהתקבל + החלת קובץ פרטי נכשל + הענקת הרש×ות קרי××”/כתיבה נכשלו! + הענקת הרש×ות נכשלה + נכשל בהעתקת קובץ מ××¨×—×™× + העתקת קובץ מ××¨×—×™× × ×›×©×œ×” + העתקה נכשלה + עדכן מקורות מ××¨×—×™× + החלת ההגדרות הושלמה בהצלחה + החלת ×”×©×™× ×•×™×™× ×‘×•×¦×¢×” בהצלחה. ×ך יתכן שיהיה צורך להפעיל מחדש ×ת ×נדרו×יד כדי ×©×”×©×™× ×•×™×™× ×™×™×›× ×¡×• לתוקף.\n\n×”×× ×‘×¨×¦×•× ×š ל×תחל מחדש?\n(כדי למנוע ×ובדן × ×ª×•× ×™× ×•×•×“× ×©××£ ×פליקציה ×œ× ×ž×©×ª×ž×©×ª בכרטיס ×”- SD כרגע!) + הקישור הסימבולי נוצר בהצלחה.\nכדי להחיל ×ת ×”×©×™× ×•×™×™× ×™×™×ª×›×Ÿ שיש צורך בהפעלה מחדש.\n\nלהפעיל מחדש עכשיו?\n(כד××™ להמנע מ×יבוד מידע יש ×œ×•×•×“× ×©××£ ×פליקציה ×œ× ×ž×©×ª×ž×©×ª בכרטיס הזיכרון!) + קישור סימבולי נוצר בהצלחה + ×נדרו×יד ×œ× ×™×›×•×œ ×”×™×” ליצור ×ת Symlink.\n הכישלון בד״כ בעיקר בגלל \'פיצ\'ר\' ×©× ×§×¨× S-ON ×‘×˜×œ×¤×•× ×™× ×©×œ HTC! \n\n הפיתרון ×”×•× ×œ×תחל ×ת הטלפון שלך למצב שחזור וליצור ×©× ×ת ×”- symlink ×¢× \'ln -s /data/data/hosts /system/etc/hosts\'.\n\n ×× ×–×” ×œ× ×¢×•×‘×“ חפש ב×ינטרנט ובטלפון שלך ×ת: S-OFF. + יצירת קישור סימבולי נכשלה + ×§×¨× ×ת העזרה למידע נוסף. + פרוקסי APN מוגדר ב×נדרו×יד שלך!\n AdAway ×œ× ×™×¢×‘×•×“ ב×ופן ×מין ברשתות סלולריות כמו 3G. ×תה יכול להשבית ×ת ×”- proxy ×”×–×” על ידי מעבר ל- APN שבחרת. (בתפריט הגדרות רשת -> רשתות מובייל -> ×ž×ª×§×“× -> APN והסר ×ž×©× ×ת הערך בשדה proxy). + פרוקסי APN הוגדר! + החיבור ל×ינטרנט ×ינו פעיל + ×ין חיבור + מוריד… + מחיל… + החל רשימה שחורה ולבנה + מ×חד קבצי מ××¨×—×™× + בונה קובץ מ××¨×—×™× + מחיל קובץ מ××¨×—×™× + כשלון בהגדרת קובץ מ××¨×—×™× ×—×“×© + החלת קובץ מ××¨×—×™× ×‘×ž×¢×¨×›×ª נכשלה!\nנסה לשנות בהעדפות התוכנה ×ת הגדרת היעד ל /data/data/hosts. + החלת הגדרות נכשלה + ×× × ×‘×“×•×§ ×ת ×פליקציית ניהול ×”-root שלך כדי ×œ×•×•×“× ×©× ×™×ª× ×” גישה ל-root. + חזרת לקובץ המ××¨×—×™× ×”×ž×•×’×“×¨ כברירת מחדל.\nייתכן שיהיה צורך ל×תחל ×ת המכשיר כדי ×©×”×©×™× ×•×™×™× ×™×™×›× ×¡×• לתוקף. \n\n×”×× ×‘×¨×¦×•× ×š ל×תחל מחדש?\n(כדי למנוע ×ובדן נתוני×, ×•×“× ×©××£ ×פליקציה ×œ× ×ž×©×ª×ž×©×ª כרגע בכרטיס ×”â€Ö¾SD!) + החזרת ההגדרות הושלמה בהצלחה + ×œ× × ×™×ª×Ÿ להחזיר ×ת קובץ המ××¨×—×™× + שיחזור נכשל מסיבות ×œ× ×™×“×•×¢×•×ª. + שחזור נכשל! + ××£ ×חד ממקורות המ××¨×—×™× ×©×œ×š ×œ× ×”×•×©×’, בטוח שיש חיבור ל×ינטרנט? × × ×œ×‘×“×•×§ שוב + הורדה נכשלה + כישלון בכתיבת קובץ מ××¨×—×™× ×¤×¨×˜×™ חדש + ×œ× × ×™×ª×Ÿ ליצור קובץ פרטי. + יצירת קובץ פרטי נכשלה + הפעלת מצב ×œ×œ× ×ž×¢×¨×›×ª.\nיתכן שיהיה צורך ל×תחל ×ת המכשיר כדי ×©×”×©×™× ×•×™×™× ×™×™×›× ×¡×• לתוקף.\n\n×”×× ×‘×¨×¦×•× ×š ל×תחל מחדש?\n(כדי למנוע ×ובדן נתוני×, ×•×“× ×©××£ ×פליקציה ×œ× ×ž×©×ª×ž×©×ª בכרטיס ×”Ö¾SD כרגע!) + הופעל בהצלחה + השבתת ×ת מצב ×œ×œ× ×ž×¢×¨×›×ª.\nייתכן שיהיה צורך ל×תחל ×ת המכשיר כדי ×©×”×©×™× ×•×™×™× ×™×™×›× ×¡×• לתוקף.\n\n×”×× ×‘×¨×¦×•× ×š ל×תחל מחדש?\n(כדי למנוע ×ובדן נתוני×, ×•×“× ×©××£ ×פליקציה ×œ× ×ž×©×ª×ž×©×ª בכרטיס ×”Ö¾SD כרגע!) + כובה בהצלחה + הפעלת חסימת מודעות ב×מצעות VPN נכשלה. + השבתת חסימת מודעות ב×מצעות VPN נכשלה. + הפעלת מודול מ××¨×—×™× Magisk + ×פשר תכונת מ××¨×—×™× ×œ×œ× ×ž×¢×¨×›×ª מ־Magisk manager. מהגדרות ×”×פליקציה, הפעל ×ת ×”×פשרות Systemless hosts ו××– ×תחל ×ת המכשיר שלך. + כיבוי מודול מ××¨×—×™× Magisk + השבת תכונת מ××¨×—×™× ×œ×œ× ×ž×¢×¨×›×ª מ־Magisk manager. מרשימת המודולי×, הסר ×ת המודול Systemless hosts ו××– ×תחל ×ת המכשיר שלך. + + + הכנס כתובת לקובץ מ×רחי×: + ×©× ×”×©×¨×ª ×ינו חוקי! + ×©× ×”×©×¨×ª בתבנית ×œ× × ×›×•× ×” + כתובת ×” IP ××™× ×” חוקית! + כתובת IP בתבנית ×œ× × ×›×•× ×” + ×œ×¢×•×œ× ×ל תפעיל מחדש ו×ל תש×ל ×ותי ×–×ת שוב! + טוען… + + + רענן + הוסף + עזרה + ×™×™×‘× ×’×™×‘×•×™ + ×™×™×¦× ×’×™×‘×•×™ + + + S-ON/S-OFF + ש×לות ותשובות + תקלות + + + תוכנת ×¤×™×¨×¡×•× + ×›×ן תוכלו ×œ×ž×¦×•× ×ª×•×›× ×•×ª ×¤×¨×¡×•× ×ž×•×ª×§× ×•×ª ×•×™×™×©×•×ž×™× ×©×œ× × ×™×ª×Ÿ ×œ×—×¡×•× ×‘×”× ×¢×œÖ¾×™×“×™ AdAway. ×פליקציות ×לה משתמשות למשל בהתר×ות דחיפה שצצות ×’× ×›×שר ×”×פליקציה ××™× ×” פועלת וביכולתן ×פילו לשנות ×ת הצלצול שלכ×. ×מצעי הנגד היחידי הזמין ×”×•× ×”×¡×¨×ª התקנה של ×™×™×©×•×ž×™× ×לה על־ידי לחיצה על רשימת ×”×¤×¨×™×˜×™× ×”×œ×œ×•. + סורק… + ×œ× × ×ž×¦×ו תוכנות פרסו×! + + + ×—×¡×•× ×¤×¨×¡×•×ž×•×ª + ×œ× ×ž×•×ª×§×Ÿ עורך טקסט + ×œ× × ×ž×¦× ×¢×•×¨×š טקסט כל ×©×”×•× ×ž×•×ª×§×Ÿ עבור פתיחת קובץ מ×רחי×. ×תה יכול להתקין ×ת העורך Jota ×ו כל עורך טקסט ×חר כדי לפתוח ×ת הקובץ.\n\n×תה רוצה להתקין ×ת Jota כעת? + ×œ× ×ž×•×ª×§×Ÿ מנהל ×§×‘×¦×™× + ×œ× × ×ž×¦× ×ž× ×”×œ ×§×‘×¦×™× ×œ×¤×ª×™×—×ª קובץ ×–×”. תוכל להתקין ×ת OI File Manager ×ו כל מנהל ×§×‘×¦×™× ×חר כדי לפתור ×–×ת.\n\n×”×× ×תה רוצה להתקין ×ת OI File Manager כעת? + + + Tcpdump + Tcpdump ×”×•× ×›×œ×™ לניטור בקשות DNS ושמירה ×©×œ×”× ×‘×§×•×‘×¥ יומן. ×תה יכול להפעיל ×ותו ברקע, ולהפעיל ×™×™×©×•×ž×™× ×©×ž×¦×™×’×™× ×¤×¨×¡×•×ž×•×ª, ול×חר מכן להסתכל ביומן בקשות ×” DNS על ידי שימוש בקובץ היומן. וכך להוסיף שרתי פרסומות לרשימה השחורה שלך. + בטל ניטור + הפעל ניטור + הצג תוצ×ות + מיין דומיין + × ×§×” לוג + הוסף לרשימה שחורה + הוסף לרשימה לבנה + הוסף לרשימת הפניות + + ערוך ×ת ערך העדפת הטקסט + פתח תפריט + סגור תפריט + + + + בית + מקורות מ××¨×—×™× + הרשימות שלך + פתיחת קובץ מ××¨×—×™× + לוג בקשות DNS + סרוק תוכנות ×¤×™×¨×¡×•× + העדפות + עזרה + + + + + בקשות DNS + הרשימות שלך + העדפות + + + הותקנו לפני %1$s + עודכן לפני %1$s + נדרש עדכון עבור %1$s + עדכון ×חרון לפני %1$s + מצב עדכון ×œ× ×™×“×•×¢ + ×œ× ×¤×¢×™×œ + כמה דקות + + דקה %d + %d דקות + %d דקות + %d דקות + + + שעה %d + %d שעות + %d שעות + %d שעות + + + ×™×•× %d + %d ×™×ž×™× + %d ×™×ž×™× + %d ×™×ž×™× + + + חודש %d + %d ×—×•×“×©×™× + %d ×—×•×“×©×™× + %d×—×•×“×©×™× + + + + המ×רח הועתק ללוח + + + מפעיל + פעיל + עוצר + ממתין לרשת + מתחבר מחדש + שגי×ת התחברות מחדש + מושהה + נעצר + ×—×•×¡× ×¤×¨×¡×•×ž×•×ª VPN %1$s + השהה + קורות ×—×™×™× + + + הרש×ות AdAway + ×פשר ×ינטר×קציה ×¢× AdAway + שלח פקודות ×ל AdAway + ×פשר לשלוח פקודות ל-AdAway כמו הפעלה ×ו השבתה של חסימת מודעות בכל המערכת + + diff --git a/app/src/main/res/values-iw/strings_app.xml b/app/src/main/res/values-iw/strings_app.xml new file mode 100644 index 0000000..cc13250 --- /dev/null +++ b/app/src/main/res/values-iw/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + ×—×•×¡× ×¤×¨×¡×•×ž×•×ª ×¢× ×§×•×“ מקור פתוח + לוגו AdAway + diff --git a/app/src/main/res/values-iw/strings_errors.xml b/app/src/main/res/values-iw/strings_errors.xml new file mode 100644 index 0000000..f06e283 --- /dev/null +++ b/app/src/main/res/values-iw/strings_errors.xml @@ -0,0 +1,22 @@ + + + + ×ין חיבור ל×ינטרנט + ×œ× × ×™×ª×Ÿ ליצור חיבור ל×ינטרנט. ×× × ×‘×“×•×§ ×ת קישוריות המכשיר שלך. + הורדת מקור קובץ המ××¨×—×™× × ×›×©×œ×” + ×œ× × ×™×ª×Ÿ להגיע ל××£ ×חד ממקורות המ××¨×—×™× ×”×ž×•×¤×¢×œ×™× ×©×œ×š. ×× × ×‘×“×•×§ ש×תה מחובר כר×וי ל×ינטרנט. + + יצירת קובץ פרטי נכשלה + ×œ× × ×™×ª×Ÿ ×”×™×” ליצור קובץ פרטי לבניית מקור מ××¨×—×™× ×—×“×©. ×× × ×‘×“×•×§ ×ת שטח ×”×חסון הפנוי הזמין במכשיר שלך. + ×ין מספיק ×ž×§×•× ×חסון + ×œ× × ×™×ª×Ÿ להעתיק ×ת קובץ המ××¨×—×™× ×œ×ž×—×™×¦×ª המערכת שלך. ×× × ×‘×“×•×§ שהמודול ×œ×œ× ×ž×¢×¨×›×ª ב־Magisk מופעל ו××– ×תחל מחדש. + התקנת קובץ מ××¨×—×™× ×—×“×© נכשלה + ×œ× × ×™×ª×Ÿ להעתיק ×ת קובץ המ××¨×—×™× ×œ×ž×—×™×¦×ª המערכת. ×× × ×‘×“×•×§ ×× ×ž×•×“×•×œ Magisk systemless מופעל ו××– ל×תחל מחדש. + ביטול קובץ המ××¨×—×™× × ×›×©×œ + ×œ× × ×™×ª×Ÿ ×”×™×” לשחזר ×ת תצורת ×”×§×‘×¦×™× ×”×ž×•×’×“×¨×ª כברירת מחדל. + + הפעלת חסימת מודעות ב×מצעות VPN נכשלה. + ×× × ×‘×“×•×§ ×ת הגדרות ×”Ö¾VPN שלך כדי ל×שר ×œ×™×™×©×•× ×ת הפעלת ×”Ö¾VPN. + השבתת חסימת מודעות ב×מצעות VPN נכשלה. + × × ×‘×“×•×§ ×ת הגדרות ×”Ö¾VPN שלך כדי להשבית ×ותו ידנית. + diff --git a/app/src/main/res/values-iw/strings_home.xml b/app/src/main/res/values-iw/strings_home.xml new file mode 100644 index 0000000..1a55367 --- /dev/null +++ b/app/src/main/res/values-iw/strings_home.xml @@ -0,0 +1,50 @@ + + + + + ×—×¡×•× + מ×ופשר + מופנה + + + + %d up-to-date source + %d up-to-date sources + %d up-to-date sources + %d מקורות ×ž×¢×•×“×›× ×™× + + + %d outdated source + %d outdated sources + %d outdated sources + %d מקורות ×œ× ×ž×¢×•×“×›× ×™× + + בדוק ×חר עדכוני מ××¨×—×™× + עדכן מ××¨×—×™× + + + הצג יומן בקשות DNS + + + הצג טיפי×/עזרה + + + פתיחת דף GitHub + + + תמיכה בפרוייקט + + + פרויקט ×”Ö¾GitHub + העדפות + + + פתיחת מגירת הניווט + השהה/המשך ×—×•×¡× ×¤×¨×¡×•×ž×•×ª + עדכון ×“×•×ž×™×™× ×™× ×—×¡×•×ž×™× + הצגת ×“×•×ž×™×™× ×™× ×ž×‘×•×§×©×™× + + + ×§×¨× ×ת העזרה למידע נוסף. + + \ No newline at end of file diff --git a/app/src/main/res/values-iw/strings_hosts.xml b/app/src/main/res/values-iw/strings_hosts.xml new file mode 100644 index 0000000..81c3a18 --- /dev/null +++ b/app/src/main/res/values-iw/strings_hosts.xml @@ -0,0 +1,17 @@ + + + מקורות מ××¨×—×™× + + רשימת משתמש + מ××¨×—×™× ×¨×©×ž×™×™× ×©×œ AdAway + ×יחוד מ××¨×—×™× StevenBlack + Pete Lowe רשימת חסימת מ××¨×—×™× + + ×œ× ×–×ž×™×Ÿ + %s מ××¨×—×™× + + הוסף מקור + ערוך מקור + כתובת URL: (כתובת https:// ×ו file://) + כתובת URL למקור מ××¨×—×™× + diff --git a/app/src/main/res/values-iw/strings_lists.xml b/app/src/main/res/values-iw/strings_lists.xml new file mode 100644 index 0000000..0007bc5 --- /dev/null +++ b/app/src/main/res/values-iw/strings_lists.xml @@ -0,0 +1,24 @@ + + + הרשימות שלך + הוספת מ×רח + + ×—×¡×•× + מ×ופשר + מופנה + + סינון מ××¨×—×™× + חיפוש ×©× ×ž×רח… + החלפת מקורות + + הוסף מ×רח לרשימה שחורה + הוסף מ×רח לרשימה לבנה + הוסף הפניית מ×רח + ערוך מ×רח ברשימה שחורה + ערוך מ×רח ברשימה לבנה + ערוך הפנייה + ×©× ×©×¨×ª: + כתובת URL למקור מ××¨×—×™× + (×ª×•×•×™× ×›×œ×œ×™×™× * ו ? מותרי×) + IP (IPv4 ×ו IPv6): + diff --git a/app/src/main/res/values-iw/strings_log.xml b/app/src/main/res/values-iw/strings_log.xml new file mode 100644 index 0000000..b836f30 --- /dev/null +++ b/app/src/main/res/values-iw/strings_log.xml @@ -0,0 +1,11 @@ + + + החלפת הקלטת היומן + לחץ על הקלט כדי להתחיל ×‘×¨×™×©×•× ×‘×§×©×•×ª, לגלוש ב×ינטרנט ×ו להשתמש ביישומי×, ו××– לחזור ×חורה ×ו להחליק כדי לרענן ×ת היומני×. + \n\nבקשות חסומות ×œ× ×™×™×¨×©×ž×•. יש להשבית תחילה ×ת חסימת המודעות ×× ×‘×¨×¦×•× ×š ×œ×¨×©×•× ×’× ×ותן. + + מיון ×לפביתי + מיון דומיין ברמה העליונה + + הפניית דומיין + diff --git a/app/src/main/res/values-iw/strings_notification.xml b/app/src/main/res/values-iw/strings_notification.xml new file mode 100644 index 0000000..77bd403 --- /dev/null +++ b/app/src/main/res/values-iw/strings_notification.xml @@ -0,0 +1,13 @@ + + + + ×¢×“×›×•× ×™× + התר×ות עדכון חדשות + עדכוני מקורות ×–×ž×™× ×™× + קובץ hosts חדש יותר זמין להורדה + עדכון ×™×™×©×•× ×–×ž×™×Ÿ + גרסה חדשה של AdAway זמינה להורדה. + + VPN + התר×ות ריצת VPN + \ No newline at end of file diff --git a/app/src/main/res/values-iw/strings_prefs_backup_restore.xml b/app/src/main/res/values-iw/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..f35e0f5 --- /dev/null +++ b/app/src/main/res/values-iw/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + גיבוי &שיחזור + גיבוי + גיבוי ל×יחסון חיצוני ×ת חוקי החסימה שלך + שחזור + שחזור חוקי חסימה מקובץ גיבוי + diff --git a/app/src/main/res/values-iw/strings_prefs_main.xml b/app/src/main/res/values-iw/strings_prefs_main.xml new file mode 100644 index 0000000..b78f5e2 --- /dev/null +++ b/app/src/main/res/values-iw/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + העדפות + + כללי + ערכת ×¦×‘×¢×™× ×›×”×” + + בהיר + ×›×”×” + ברירת מחדל מערכת + + עדכון ×וטומטי + + ×—×•×¡× ×¤×¨×¡×•×ž×•×ª + ×—×•×¡× ×¤×¨×¡×•×ž×•×ª מבוסס גישת שורש + ×—×•×¡× ×¤×¨×¡×•×ž×•×ª מבוסס VPN + ×פשר תמיכת IPv6 + גיבוי / שחזור חוקי חסימה + + ניפוי שגי×ות + הפעל דוחות קריסה + ×פשר ל×פליקציה לשלוח שגי×ות ודוחות קריסה ל-Sentry (sentry.io). + ×œ× × ×ª×ž×š בבניה זו + הפעל לוג מפורט + יש להפעיל מחדש בכדי להגדיר + diff --git a/app/src/main/res/values-iw/strings_prefs_root.xml b/app/src/main/res/values-iw/strings_prefs_root.xml new file mode 100644 index 0000000..ab25c91 --- /dev/null +++ b/app/src/main/res/values-iw/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + ×—×•×¡× ×¤×¨×¡×•×ž×•×ª מבוסס גישת שורש + + התקנת מ××¨×—×™× + פתח קובץ מ××¨×—×™× + יעד קובץ מ××¨×—×™× + לפני שימושש בהגדרה זו, יש ×œ×§×¨×•× ×ודותיה + + /system/etc/hosts + /data/hosts + /data/data/hosts + יעד מות×× ×ישית + + ×ž×™×§×•× ×™×¢×“ מות×× ×ישית + הסתרת תיבת דו שיח ×ודות ×תחול ל×חר הגדרה + + הפניה + הגדר ל×ן להפנות מ××¨×—×™× ×—×¡×•×ž×™× + הפניית IPv4 + הפניית IPv6 + ניתוב מחדש ×œ× ×—×•×§×™ + + שרת מקומי + שרת ×”×ינטרנט המקומי מקשיב לכתובות IP מקומיות כדי לענות לבקשות של ×©× ×ž×רח חסו×. ×–×” עשוי לעזור בהקפ×ת ×פליקציות בחיבור חסו×. + הפעלת שרת Web + בדיקת שרת Web + התקן ×ישור בחתימה עצמית + התקנה ידנית של ×”×ישור + החל מ־Android 11 (R), ×”×™×™×©×•× ×œ× ×™×›×•×œ להתקין יותר ×וטומטית ×ת רשות ×”××™×©×•×¨×™× (CA).\n\nעבור ×ל הגדרות \"×בטחה\", \"הצפנה ו×ישורי×\" ו××– \"התקן ×ישור\". מש×, בחר \"×ישור CA\" ובחר ×ת קובץ ×”×ישור החדש שיוצ×. + פתיחת הגדרות \"×בטחה\" + בודק… + ×œ× ×¤×¢×™×œ + פועל ×ך ×”×ישור ×œ× ×”×•×ª×§×Ÿ + פועל וה×ישור הותקן + החלף שטח ריק של מודעות שנחסמו בסמל ×”×פליקציה + diff --git a/app/src/main/res/values-iw/strings_prefs_update.xml b/app/src/main/res/values-iw/strings_prefs_update.xml new file mode 100644 index 0000000..8a47231 --- /dev/null +++ b/app/src/main/res/values-iw/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + ×¢×“×›×•× ×™× + ההתר×ות מושבתות + הודעות ×™×™×©×•× ×œ× ×™×•×¤×™×¢×•. הקש כדי להפעיל ×ות×. + + עידכוני ×™×™×©×•× + בדיקת ×§×™×•× ×¢×“×›×•× ×™× ×‘×”×¤×¢×œ×” + בדיקת ×§×™×•× ×¢×“×›×•× ×™× ×ž×™×“×™ ×¤×¢× + כולל גרסת ×‘×˜× + + עדכוני מ××¨×—×™× + בדיקת ×¢×“×›×•× ×™× ×‘×”×¤×¢×œ×” + בדיקת ×§×™×•× ×¢×“×›×•× ×™× ×ž×™×“×™ ×¤×¢× + סנכרון בעת עדכון + סנכרון בעת שימוש ברשת ×œ× × ×ž×“×“×ª בלבד + diff --git a/app/src/main/res/values-iw/strings_prefs_vpn.xml b/app/src/main/res/values-iw/strings_prefs_vpn.xml new file mode 100644 index 0000000..740cb5a --- /dev/null +++ b/app/src/main/res/values-iw/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + ×—×•×¡× ×¤×¨×¡×•×ž×•×ª מבוסס VPN + + הפעלת בעת הפעלת המכשיר + צג חיבור + בדוק מעת לעת ×ת מצב הרשת כדי להפעיל מחדש ×ת ×”Ö¾VPN בעת ניתוקו. + + ×”×ª×¢×œ× ×ž×™×™×©×•×ž×™× + הגדר ×ילו ×™×™×©×•×ž×™× ×œ× ×™×•×›×œ×• להשתמש ב-VPN כדי ×©×œ× ×™×ª× ×ª×§×• ×—×™×‘×•×¨×™× + ×”×ª×¢×œ× ×ž×™×™×©×•×ž×™ מערכת + + ×œ×œ× + הכל למעט ×“×¤×“×¤× ×™× + הכל + + ×”×ª×¢×œ× ×ž×פליקציות משתמש + + + ×”×ª×¢×œ× ×ž×פליקציות + בחר הכל + הסר הכל + סמל ×™×™×©×•× + diff --git a/app/src/main/res/values-iw/strings_source_edit.xml b/app/src/main/res/values-iw/strings_source_edit.xml new file mode 100644 index 0000000..8bdc3fb --- /dev/null +++ b/app/src/main/res/values-iw/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + עריכת מקור + הוספת מקור + + תווית + נדרש תווית + סוג + כתובת ×תר + קובץ + ×ž×™×§×•× + https:// + ×ž×™×§×•× × ×“×¨×© + לחיצה על קובץ כדי לבחור קובץ מקור + ×ž×™×§×•× ×œ× ×—×•×§×™ + תבנית רשימה + חסימה + הרש××” + החלת מ××¨×—×™× ×©× ×•×ª×‘×• מחדש + מתן ×פשרות למ××¨×—×™× ×”×ž× ×•×ª×‘×™× ×ž×—×“×© עלולה ×œ×’×¨×•× ×œ×‘×¢×™×•×ª ×בטחה. יש להשתמש בהגדרות ×לו רק במקור מהימן מכיוון ×©×”×•× ×™×›×•×œ להפנות תנועה רגישה ל××™×–×” שרת ×©×”×•× ×¨×•×¦×”. + diff --git a/app/src/main/res/values-iw/strings_support.xml b/app/src/main/res/values-iw/strings_support.xml new file mode 100644 index 0000000..b036237 --- /dev/null +++ b/app/src/main/res/values-iw/strings_support.xml @@ -0,0 +1,5 @@ + + + תמיכה + הפוך להיות נותן חסות + \ No newline at end of file diff --git a/app/src/main/res/values-iw/strings_update.xml b/app/src/main/res/values-iw/strings_update.xml new file mode 100644 index 0000000..a86c740 --- /dev/null +++ b/app/src/main/res/values-iw/strings_update.xml @@ -0,0 +1,21 @@ + + + עדכון AdAway + + עדכון זמין! + + + זו הגרסה ×”×חרונה + עדכון זמין + מעדכן ×ת AdAway + עדכן כעת + %1$s / %2$s + ×©×™× ×•×™×™× ××—×¨×•× ×™× + רשימת ×©×™× ×•×™×™× + תמיכה בפיתוח + ×œ×ª×¨×•× + נותן חסות + + + הורדת גרסה ×חרונה של AdAway… + diff --git a/app/src/main/res/values-iw/strings_welcome.xml b/app/src/main/res/values-iw/strings_welcome.xml new file mode 100644 index 0000000..2a2365e --- /dev/null +++ b/app/src/main/res/values-iw/strings_welcome.xml @@ -0,0 +1,53 @@ + + + ברוך הב×! + ×שף הצעד הר×שון + ×שף הצעד השני + ×שף הצעד ×”×חרון + + + ×‘×¨×•×›×™× ×”×‘××™× ×ל AdAway! + AdAway מספק שתי שיטות חסימת פרסומות, × × ×œ×‘×—×•×¨ ×ת השיטה המועדפת עליכ×: + + לוגו גישת שורש + מבוסס גישת שורש\n×—×•×¡× ×¤×¨×¡×•×ž×•×ª + מהיר יותר + ידידותי לסוללה + נדרש גישת שורש + + לוגו VPN + מבוסס VPN\n×—×•×¡× ×¤×¨×¡×•×ž×•×ª + ×יטי יותר + פועל ברקע + מות×× + + גישת שורש ×נדרו×יד נדרשת + ×œ× ×פשרת הרש×ת Root ל־AdAway.\n\n×–×” יכול לקרות ×›×שר המכשיר שלך ×ינו בעל גישת Root. תוכל ×œ×ž×¦×•× ×ž×™×“×¢ על ×ופן ביצוע Root במכשיר שלך ב־wiki.lineageos.org ×ו ב×תרי דומי×. + + מקצועי + ×¢× + + + סנכרון ×”×•×©×œ× + שגי×ת בעת סינכרון + + מסנכרן + סונכרן! + AdAway מוריד רשתות של מודעות כדי ×œ×—×¡×•× ×ותן ממקורותיהן המקווני×. ×תה יכול להת××™× ×ותן מ×וחר יותר בהגדרות. + נסה לסנכרן בשנית + נכשל בסנכרון: %1$s לנסות כעת? + ×–×” יכול לשלוח הודעות כדי להציג סטטוס חסימת מודעות ושליטה, ולהודיע על עדכון ×™×™×©×•× ×–×ž×™×Ÿ (מספר ×¤×¢×ž×™× ×‘×©× ×”). יש להפעיל ××•×ª× ×× ×‘×¨×¦×•× ×š להיש×ר מעודכן. + + + תמיכה + תמוך בי! + AdAway ×”×•× ×™×™×©×•× ×—×™× ×ž×™ וקוד פתוח ש×× ×™ מפתח בזמני הפנוי. ×× ×”×™× ×š × ×”× ×” מזה, ×ל תהסס להר×ות ×ת תמיכתך: + תרומה ב×מצעות PayPal + ×תה ×והב ב××’×™×? גמ×× ×™ ל×. + הפעלת טלמטריה בכדי לשלוח לי דוחות קריסה + + + ×חורה + קדימה + ×¡×™×•× + diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml new file mode 100644 index 0000000..f5a3b99 --- /dev/null +++ b/app/src/main/res/values-ja/strings.xml @@ -0,0 +1,258 @@ + + + + 終了 + é–‰ã˜ã‚‹ + ã¯ã„ + ã„ã„㈠+ 追加 + キャンセル + ä¿å­˜ + ヘルプ + + + よã†ã“ãï¼ + AdAwayã¯ã€åºƒå‘Šã‚’ブロックã™ã‚‹ãŸã‚ã®ãƒ•リーã§ã‚ªãƒ¼ãƒ—ンソースã®ã‚½ãƒ•トウェアã§ã™ã€‚広告用ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’å–å¾—ã—ã¦ã€ã‚ãªãŸã®ãƒ‡ãƒã‚¤ã‚¹ä¸Šã§é®æ–­ã—ã¾ã™ã€‚\nã‚‚ã£ã¨çŸ¥ã‚ŠãŸã„ã§ã™ã‹ï¼Ÿ 以下ã®ãƒ˜ãƒ«ãƒ—ã‚’ãƒã‚§ãƒƒã‚¯ã—ã¦ãã ã•ã„ï¼ + 詳ã—ã„ヘルプを表示 + æœ€æ–°çŠ¶æ³ + 定義ã•れãŸã‚½ãƒ¼ã‚¹ã‹ã‚‰hostsファイルをダウンロードã—ã€ã‚·ã‚¹ãƒ†ãƒ ã®hostsファイルã«çµ±åˆã—ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ã¾ã™ + 広告ブロックを有効ã«ã™ã‚‹ + 広告ブロックを無効ã«ã™ã‚‹ + ウェブサーãƒãƒ¼ + 実行中 + åœæ­¢ä¸­ + ブロックã—ãŸãƒ›ã‚¹ãƒˆåã«è¿”ç­”ã™ã‚‹ãƒ­ãƒ¼ã‚«ãƒ«ãƒ›ã‚¹ãƒˆã®ã‚¦ã‚§ãƒ–サーãƒãƒ¼ã‚’é–‹å§‹/åœæ­¢ã—ã¾ã™ + Webサーãƒãƒ¼ã‚’有効ã«ã™ã‚‹ + Webサーãƒãƒ¼ã‚’無効ã«ã™ã‚‹ + VPN + 実行中 + åœæ­¢ä¸­ + VPNã«ã‚ˆã‚‹ãƒ•ィルタリングを開始/åœæ­¢ã—ã¾ã™ + VPN 有効 + VPN 無効 + + + 項目を編集ã™ã‚‹ + é©ç”¨ã™ã‚‹ + 編集 + 削除 + + + インãƒãƒ¼ãƒˆä¸­â€¦ + 外部ストレージã‹ã‚‰ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ãŒæ­£å¸¸ã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã•れã¾ã—ãŸã€‚ + ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã«å¤±æ•—ã—ã¾ã—ãŸã€‚ ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®å½¢å¼ã¯æ­£ã—ã„ã§ã™ã‹? 詳細ã¯ã€ logcat を確èªã—ã¦ãã ã•ã„。 + エクスãƒãƒ¼ãƒˆä¸­â€¦ + ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã¯ã€å¤–部ストレージ上㮠\'%s\' ã¸æ­£å¸¸ã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã•れã¾ã—ãŸã€‚ + ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—\'%s\'ã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã«å¤±æ•—ã—ã¾ã—ãŸã€‚ + + + hostsファイル + hostsファイルã¯ãƒ›ã‚¹ãƒˆåã‚’IPアドレスã«å¯¾å¿œã•ã›ã‚‹ã‚·ã‚¹ãƒ†ãƒ ãƒ•ァイルã§ã™ã€‚ AdAwayãŒå‡¦ç†ã™ã‚‹è¨­å®šãŒæ›¸ã‹ã‚ŒãŸãŸã ã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ァイルã§ã™ã€‚ 最åˆã®æ•°è¡Œã¯ã“ã‚“ãªæ„Ÿã˜ã§ã™ï¼š + hostsファイルã®å†…容を読ã¿è¾¼ã¿ä¸­â€¦ + hostsファイルを開ã + + + 更新を確èªä¸­ + %sã®æ›´æ–°ã‚’確èªä¸­ + ソースã®å–å¾— + %sをダウンロード中 + %sを読込中 + %sã‚’è§£æžä¸­ + ãƒ«ãƒ¼ãƒ«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’åŒæœŸ + デフォルトhostsãƒ•ã‚¡ã‚¤ãƒ«ã«æˆ»ã™ + デフォルトhostsファイルをリストアã—ã¾ã—㟠+ 標準hostsファイルを作æˆä¸­ + æ›´æ–°ãŒã‚りã¾ã™ + æ–°ã—ã„hostsファイルãŒã‚りã¾ã™ + ã‚½ãƒ¼ã‚¹ã®æ›´æ–°ã¯ã‚りã¾ã›ã‚“ + ãƒãƒƒãƒˆæŽ¥ç¶šãªã— + ãƒãƒƒãƒˆã«æŽ¥ç¶šã•れã¦ã„ã¾ã›ã‚“ + å–å¾—å…ˆãŒåˆ©ç”¨ã§ãã¾ã›ã‚“ + ã©ã®hosts å–å¾—å…ˆã«ã‚‚接続ã§ãã¾ã›ã‚“ï¼ + ãƒ«ãƒ¼ãƒˆã‚¢ã‚¯ã‚»ã‚¹ãŒæ‹’å¦ã•れã¾ã—㟠+ ルートアプリã‹ã‚‰ã®ãƒ«ãƒ¼ãƒˆ アクセスを許å¯ã™ã‚‹ + 何らã‹ã®ä¸å…·åˆãŒèµ·ãã¾ã—㟠+ 詳細㯠logcat ã‚’ãƒã‚§ãƒƒã‚¯ã—ã¦ãã ã•ã„ + 有効ã§ã™ + 最新㮠hosts ãƒ•ã‚¡ã‚¤ãƒ«ãŒæœ‰åйã«ãªã‚Šã¾ã—㟠+ 無効ã«ãªã£ã¦ã„ã¾ã™ + デフォルト㮠hosts ファイルãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•れã¾ã—㟠+ 最新ã®ã‚½ãƒ¼ã‚¹ã‚’é©ç”¨ + æ–°ã—ã„hostsファイルã®ä½œæˆ + æ–°ã—ã„hostsファイルをコピー + hostsファイルã®ã‚³ãƒ”ãƒ¼ã‚’ç¢ºèª + hostsãƒ•ã‚¡ã‚¤ãƒ«ã®æ›´æ–°ã«æˆåŠŸ + VPNæ§‹æˆã®æ›´æ–°ã«æˆåŠŸ + 設定ãŒå¤‰æ›´ã•れã¾ã—ãŸã€‚é©ç”¨ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ + é©ç”¨ã™ã‚‹ + æ–°ã—ã„設定をé©ç”¨ã—ã¦ã„ã¾ã™â€¦ + æ–°ã—ã„設定ã®é©ç”¨ã«å¤±æ•—ã—ã¾ã—㟠+ + + hostsファイルターゲットã¸ã®ã‚·ãƒ³ãƒœãƒªãƒƒã‚¯ãƒªãƒ³ã‚¯ãŒä¸æ˜Žã§ã™ + /system/etc/hostsã¸ã®ã‚·ãƒ³ãƒœãƒªãƒƒã‚¯ãƒªãƒ³ã‚¯ã¯å­˜åœ¨ã—ãªã„ã‹ä¸æ­£ã§ã™! AdAwayã¯æ­£ã—ã„ãƒ•ã‚¡ã‚¤ãƒ«ãŒæŒ‡å®šã•れã¦ã„ãªã„ã¨å‹•作ã—ã¾ã›ã‚“。\n\nシンボリックリンクを作æˆã—ã¾ã™ã‹ï¼Ÿ + シンボリックリンクãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ + ã“ã®ãƒ‘ーティションã«å分ãªå®¹é‡ãŒã‚りã¾ã›ã‚“!\n設定ã§å¯¾è±¡ã¨ã™ã‚‹ hosts ファイルを /data/data/hosts ã«å¤‰æ›´ã—ã¦ã¿ã¦ãã ã•ã„。 + 空ã容é‡ä¸è¶³ + ダウンロードã—ãŸãƒ•ァイルãŒèª­ã¿è¾¼ã‚ã¾ã›ã‚“ + プライベートファイル失敗 + パーティション㮠読ã¿/書ã ã§ã®å†ãƒžã‚¦ãƒ³ãƒˆã«å¤±æ•—ã—ã¾ã—ãŸï¼ + å†ãƒžã‚¦ãƒ³ãƒˆå¤±æ•— + hostsファイルã®ã‚³ãƒ”ーã«å¤±æ•— + hostsファイルã®ã‚³ãƒ”ãƒ¼å¤±æ•—ï¼ + コピー失敗 + hosts ã®ã‚½ãƒ¼ã‚¹ã‚’é©ç”¨ã—ã¾ã—㟠+ é©ç”¨ã—ã¾ã—㟠+ é©ç”¨ã«æˆåŠŸã—ã¾ã—ãŸã€‚\n実際ã«å¤‰æ›´ã•れるã«ã¯ Android ã®å†èµ·å‹•ãŒå¿…è¦ãªã“ã¨ãŒã‚りã¾ã™ã€‚\n\nå†èµ·å‹•ã—ã¾ã™ã‹ï¼Ÿ\n(ãƒ‡ãƒ¼ã‚¿ã®æå‚·ã‚’é˜²ããŸã‚ã€ç¾åœ¨ SDカードを使ã£ã¦ã„るアプリãŒç„¡ã„ã®ã‚’確èªã—ã¦ãã ã•ã„ï¼) + シンボリックリンク作æˆã«æˆåŠŸã—ã¾ã—ãŸã€‚\n実際ã«å¤‰æ›´ã•れるã«ã¯ Android ã®å†èµ·å‹•ãŒå¿…è¦ãªã“ã¨ãŒã‚りã¾ã™ã€‚\n\nå†èµ·å‹•ã—ã¾ã™ã‹ï¼Ÿ\n(ãƒ‡ãƒ¼ã‚¿ã®æå‚·ã‚’é˜²ããŸã‚ã€ç¾åœ¨ SDカードを使ã£ã¦ã„るアプリãŒç„¡ã„ã®ã‚’確èªã—ã¦ãã ã•ã„ï¼) + ã‚·ãƒ³ãƒœãƒªãƒƒã‚¯ãƒªãƒ³ã‚¯ä½œæˆæˆåŠŸ + Android ㌠シンボリックリンクを作æˆã§ãã¾ã›ã‚“。\nHTC 製端末ã«ã‚ã‚‹ S-ON ã¨ã„ã†ã€Œæ©Ÿèƒ½ã€ãŒåŽŸå› ã§ã™ã€‚\n\n解決ã™ã‚‹ã«ã¯ãƒªã‚«ãƒãƒªãƒ¢ãƒ¼ãƒ‰ã§èµ·å‹•ã—ã€ã‚³ãƒžãƒ³ãƒ‰ 「 ln -s /data/data/hosts /system/etc/hosts 〠ã§ã‚·ãƒ³ãƒœãƒªãƒƒã‚¯ãƒªãƒ³ã‚¯ã‚’作æˆã—ã¦ãã ã•ã„。\n\nãれã§ã‚‚動作ã—ãªã„å ´åˆ S-OFF ã«ã¤ã„ã¦æ¤œç´¢ã—ã¦ãã ã•ã„。 + シンボリックリンク作æˆå¤±æ•— + 詳ã—ãã¯ãƒ˜ãƒ«ãƒ—ã‚’ã”覧ãã ã•ã„ + ã”使用ã®ç«¯æœ«ã« APN プロキシãŒè¨­å®šã•れã¦ã„ã¾ã™! 3Gç­‰ã®ãƒ¢ãƒã‚¤ãƒ«ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã§ AdAway ãŒã†ã¾ã動作ã—ãªã„å ´åˆãŒã‚りã¾ã™ã€‚プロキシを無効ã«ã™ã‚‹ã«ã¯ã€é¸æŠžã•れã¦ã„ã‚‹ APN (設定アプリã‹ã‚‰: ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ → インターãƒãƒƒãƒˆ → モãƒã‚¤ãƒ«ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ → 詳細設定 → アクセスãƒã‚¤ãƒ³ãƒˆå) ã‚’é¸æŠžã—ã¦ã€ã€Œãƒ—ロキシã€ã®æ¬„を空白ã«ã—ã¦ãã ã•ã„。 + APNプロキシãŒã‚»ãƒƒãƒˆã•れã¾ã—ãŸï¼ + ãƒãƒƒãƒˆæŽ¥ç¶šãŒã‚りã¾ã›ã‚“ + 接続ãªã— + ダウンロード中… + é©ç”¨ä¸­â€¦ + ブラック/ホワイトリストをé©ç”¨ä¸­ + hostsファイルã®è§£æžï½¥çµ±åˆä¸­â€¦ + hostsファイルを構築中… + hostsファイルをé©ç”¨ä¸­ + æ–°ã—ã„hostsファイルã®é©ç”¨ã«å¤±æ•— + hostsファイルã®é©ç”¨ã«å¤±æ•—ã—ã¾ã—ãŸ!\n設定ã§å¯¾è±¡ã¨ã™ã‚‹ hosts ファイルを /data/data/hosts ã«å¤‰æ›´ã—ã¦ã¿ã¦ãã ã•ã„。 + é©ç”¨ã«å¤±æ•— + ルート管ç†ã‚¢ãƒ—リをãƒã‚§ãƒƒã‚¯ã—ã¦ã€ãƒ«ãƒ¼ãƒˆã‚¢ã‚¯ã‚»ã‚¹ãŒè¨±å¯ã•れã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。 + デフォルト㮠hosts ファイルã«å·®ã—戻ã—ã¾ã—ãŸã€‚\n実際ã«å¤‰æ›´ã•れるã«ã¯ Android ã®å†èµ·å‹•ãŒå¿…è¦ãªã“ã¨ãŒã‚りã¾ã™ã€‚\n\nå†èµ·å‹•ã—ã¾ã™ã‹ï¼Ÿ\n(ãƒ‡ãƒ¼ã‚¿ã®æå‚·ã‚’é˜²ããŸã‚ã€ç¾åœ¨ SDカードを使ã£ã¦ã„るアプリãŒç„¡ã„ã®ã‚’確èªã—ã¦ãã ã•ã„ï¼) + å…ƒã«æˆ»ã—ã¾ã—㟠+ hostsãƒ•ã‚¡ã‚¤ãƒ«ã‚’å…ƒã«æˆ»ã›ã¾ã›ã‚“ + 何らã‹ã®ç†ç”±ã«ã‚ˆã‚Šå…ƒã«æˆ»ã›ã¾ã›ã‚“ã§ã—㟠+ å…ƒã«æˆ»ã›ã¾ã›ã‚“ï¼ + ã©ã® hosts å–å¾—å…ˆã«ã‚‚接続ã§ãã¾ã›ã‚“ï¼ ã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆã«æŽ¥ç¶šã•れã¦ã„ã¾ã™ã‹ï¼Ÿ + ダウンロード失敗 + æ–°ã—ã„プライベートhostsãƒ•ã‚¡ã‚¤ãƒ«ã®æ›¸ãè¾¼ã¿ã«å¤±æ•—ã—ã¾ã—㟠+ プライベートファイルãŒä½œæˆã§ãã¾ã›ã‚“ + プライベートファイルã®ä½œæˆå¤±æ•— + システムレスモードを有効ã«ã—ã¾ã—ãŸã€‚\n実際ã«å¤‰æ›´ã•れるã«ã¯ Android ã®å†èµ·å‹•ãŒå¿…è¦ãªã“ã¨ãŒã‚りã¾ã™ã€‚\n\nå†èµ·å‹•ã—ã¾ã™ã‹ï¼Ÿ\n(ãƒ‡ãƒ¼ã‚¿ã®æå‚·ã‚’é˜²ããŸã‚ã€ç¾åœ¨ SDカードを使ã£ã¦ã„るアプリãŒç„¡ã„ã®ã‚’確èªã—ã¦ãã ã•ã„ï¼) + æœ‰åŠ¹åŒ–ã¯æˆåŠŸã§ã™ + システムレスモードを無効ã«ã—ã¾ã—ãŸã€‚\n実際ã«å¤‰æ›´ã•れるã«ã¯ Android ã®å†èµ·å‹•ãŒå¿…è¦ãªã“ã¨ãŒã‚りã¾ã™ã€‚\n\nå†èµ·å‹•ã—ã¾ã™ã‹ï¼Ÿ\n(ãƒ‡ãƒ¼ã‚¿ã®æå‚·ã‚’é˜²ããŸã‚ã€ç¾åœ¨ SDカードを使ã£ã¦ã„るアプリãŒç„¡ã„ã®ã‚’確èªã—ã¦ãã ã•ã„ï¼) + ç„¡åŠ¹åŒ–ã¯æˆåŠŸã§ã™ + VPNåºƒå‘Šãƒ–ãƒ­ãƒƒã‚¯ã®æœ‰åŠ¹åŒ–ã«å¤±æ•—ã—ã¾ã—㟠+ VPN広告ブロックã®ç„¡åŠ¹åŒ–ã«å¤±æ•—ã—ã¾ã—㟠+ Magisk ã® hosts ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã®æœ‰åŠ¹åŒ– + Magisk マãƒãƒ¼ã‚¸ãƒ£ãƒ¼ã‹ã‚‰ Systemless hosts 機能を有効ã«ã—ã¾ã™ã€‚設定ã‹ã‚‰ Systemless hosts オプションを有効ã«ã—ã¦ã‹ã‚‰ã€ãƒ‡ãƒã‚¤ã‚¹ã‚’å†èµ·å‹•ã—ã¾ã™ã€‚ + Magisk ã® hosts モジュールã®ç„¡åŠ¹åŒ– + Magisk マãƒãƒ¼ã‚¸ãƒ£ãƒ¼ ã‹ã‚‰ Systemless hosts 機能を無効ã«ã—ã¾ã™ã€‚モジュールリストã‹ã‚‰ã€ Systemless hosts モジュールをアンインストールã—ã¦ã‹ã‚‰ã€ãƒ‡ãƒã‚¤ã‚¹ã‚’å†èµ·å‹•ã—ã¾ã™ã€‚ + + + hostsファイルã®URLを入力: + æ­£ã—ã„ホストåã§ã¯ã‚りã¾ã›ã‚“ï¼ + ホストåãŒæ­£ã—ãã‚りã¾ã›ã‚“ + 䏿­£ãªIPã§ã™ï¼ + IPãŒæ­£ã—ãã‚りã¾ã›ã‚“ + å†èµ·å‹•ã›ãšã«ã€ã“ã®è³ªå•を二度ã¨è¡¨ç¤ºã—ãªã„ + 読ã¿è¾¼ã¿ä¸­â€¦ + + + æ›´æ–° + 追加 + ヘルプ + ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ + ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ + + + S-ON/S-OFF + FAQ + å•題 + + + アドウェア + ã“ã“ã§ã¯AdAway ã«ã‚ˆã£ã¦ãƒ–ロックã§ããªã„ã€ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«æ¸ˆã¿ã®æœ‰å®³ã‚¢ãƒ—リ (アドウェア) を一覧化ã—ã¦ã„ã¾ã™ã€‚ ã“れらã®ã‚¢ãƒ—リã¯ä¾‹ãˆã°ã€ãƒ—ッシュ通知を使用ã—ã¦ã‚¢ãƒ—リãŒå®Ÿè¡Œã•れã¦ã„ãªã„ã¨ãã«ã‚‚ãƒãƒƒãƒ—アップã—ãŸã‚Šã€ç€ä¿¡éŸ³ã‚’ç„¡æ–­ã§å¤‰æ›´ã—ãŸã‚Šã—ã¾ã™ã€‚ 対策ã¯ãƒªã‚¹ãƒˆé …目をタップã—ã¦ã€ã‚¢ãƒ—リをアンインストールã™ã‚‹ã“ã¨ã ã‘ã§ã™ã€‚ + スキャン中… + ã‚¢ãƒ‰ã‚¦ã‚§ã‚¢ã¯æ¤œå‡ºã•れã¾ã›ã‚“ã§ã—ãŸï¼ + + + åºƒå‘ŠæŽ’é™¤ï¼ + テキストエディタãŒã‚りã¾ã›ã‚“ + hostsファイルを開ããŸã‚ã®ãƒ†ã‚­ã‚¹ãƒˆã‚¨ãƒ‡ã‚£ã‚¿ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。Jotaãªã©ãƒ†ã‚­ã‚¹ãƒˆã‚¨ãƒ‡ã‚£ã‚¿ã‚’インストールã—ã¦ãã ã•ã„。\n\nJotaをインストールã—ã¾ã™ã‹ï¼Ÿ + ファイルマãƒãƒ¼ã‚¸ãƒ£ãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•れã¦ã„ã¾ã›ã‚“ + ファイルマãƒãƒ¼ã‚¸ãƒ£ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。OI File Managerã‚„Tetraãªã©ã‚’インストールã—ã¦ãã ã•ã„。\n\nOI File Managerをインストールã—ã¾ã™ã‹ï¼Ÿ + + + TCPダンプ + TCPダンプã¯DNSè¦æ±‚を監視ã—ã¦ãƒ­ã‚°ãƒ•ァイルã«ä¿å­˜ã™ã‚‹æ©Ÿèƒ½ã§ã™ã€‚ ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã§é–‹å§‹ã—ã¦ã€åºƒå‘Šã‚’表示ã™ã‚‹ã‚¢ãƒ—リを起動ã™ã‚‹ã¨ãƒ­ã‚°ãƒ•ァイルã§DNSè¦æ±‚を調ã¹ã‚‰ã‚Œã¾ã™ã€‚広告ã®ã‚µãƒ¼ãƒãƒ¼ã ã¨æ€ã‚れるもã®ã¯ãƒ–ラックリストã«è¿½åŠ å‡ºæ¥ã¾ã™ + 監視を無効ã«ã™ã‚‹ + 監視を有効ã«ã™ã‚‹ + çµæžœã‚’表示 + ãƒ‰ãƒ¡ã‚¤ãƒ³ã‚’ä¸¦ã¹æ›¿ãˆã‚‹ + ログを消去 + ブラックリストã«ã‚¨ãƒ³ãƒˆãƒªãƒ¼ã‚’追加ã™ã‚‹ + ホワイトリストã«ã‚¨ãƒ³ãƒˆãƒªãƒ¼ã‚’追加ã™ã‚‹ + リダイレクトリストã«ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹ + + テキスト設定値を編集ã™ã‚‹ + メニューを開ã + メニューを閉ã˜ã‚‹ + + + + ホーム + hosts å–å¾—å…ˆ + ã‚ãªãŸã®ãƒªã‚¹ãƒˆ + hostsファイルを開ã + DNS è¦æ±‚ã®ãƒ­ã‚° + アドウェアをスキャン + 設定 + ヘルプ + + + + + DNSリクエスト + ã‚ãªãŸã®ãƒªã‚¹ãƒˆ + 設定 + + + インストール済㿠%1$s + 最新 %1$s + æ›´æ–°ãŒå¿…è¦ %1$s + æœ€å¾Œã®æ›´æ–° %1$s + 更新ステータスãŒä¸æ˜Ž + 無効ã«ãªã£ã¦ã„ã¾ã™ + æ•°åˆ†å‰ + + %d 分 + + + %d 時間 + + + %d æ—¥ + + + %d ヶ月 + + + + ホストをクリップボードã«ã‚³ãƒ”ーã—ã¾ã—㟠+ + + é–‹å§‹ + 動作中 + åœæ­¢ + ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚’待機中 + å†æŽ¥ç¶š + å†æŽ¥ç¶šã‚¨ãƒ©ãƒ¼ + ä¸€æ™‚åœæ­¢ + åœæ­¢ + Ad-blocker VPN %1$s + ä¸€æ™‚åœæ­¢ + 復帰 + + + AdAway æ¨©é™ + AdAwayã¨ã®é€£æºã‚’許å¯ã™ã‚‹ + AdAwayã«ã‚³ãƒžãƒ³ãƒ‰ã‚’é€ä¿¡ + システムã®åºƒå‘Šãƒ–ロックを切り替ãˆã‚‹ç­‰ã®ã‚³ãƒžãƒ³ãƒ‰ã‚’AdAwayã¸é€ä¿¡ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚ + + diff --git a/app/src/main/res/values-ja/strings_app.xml b/app/src/main/res/values-ja/strings_app.xml new file mode 100644 index 0000000..2ce8555 --- /dev/null +++ b/app/src/main/res/values-ja/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Open Source ad blocker + AdAway ロゴ + diff --git a/app/src/main/res/values-ja/strings_errors.xml b/app/src/main/res/values-ja/strings_errors.xml new file mode 100644 index 0000000..21a2d6e --- /dev/null +++ b/app/src/main/res/values-ja/strings_errors.xml @@ -0,0 +1,22 @@ + + + + ãƒãƒƒãƒˆæŽ¥ç¶šãªã— + インターãƒãƒƒãƒˆã¸ã®æŽ¥ç¶šã‚’確立ã§ãã¾ã›ã‚“ã€‚ç«¯æœ«ã®æŽ¥ç¶šçŠ¶æ…‹ã‚’ç¢ºèªã—ã¦ãã ã•ã„。 + hostsソースã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã«å¤±æ•—ã—ã¾ã—㟠+ 有効ã«ã—ãŸhostsソースã«åˆ°é”ã§ãã¾ã›ã‚“。インターãƒãƒƒãƒˆã«æ­£ã—ãæŽ¥ç¶šã•れã¦ã„ã‚‹ã‹ç¢ºèªã—ã¦ãã ã•ã„。 + + プライベートファイルã®ä½œæˆã«å¤±æ•—ã—ã¾ã—㟠+ æ–°ã—ã„hostsソースを構築ã™ã‚‹ãŸã‚ã®ãƒ—ライベートファイルを作æˆã§ãã¾ã›ã‚“。端末ã®ç©ºã容é‡ã‚’確èªã—ã¦ãã ã•ã„。 + 空ã容é‡ä¸è¶³ + hostsファイルをシステムパーティションã«ã‚³ãƒ”ーã§ãã¾ã›ã‚“。Magiskã®ã‚·ã‚¹ãƒ†ãƒ ãƒ¬ã‚¹ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ãŒæœ‰åйã«ãªã£ã¦ã„ã‚‹ã‹ç¢ºèªã—ã€å†èµ·å‹•ã—ã¦ãã ã•ã„。 + æ–°ã—ã„hostsファイルã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã«å¤±æ•—ã—ã¾ã—㟠+ hostsファイルを/systemパーティションã«ã‚³ãƒ”ーã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。Magiskã®ã‚·ã‚¹ãƒ†ãƒ ãƒ¬ã‚¹ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ãŒæœ‰åйã«ãªã£ã¦ã„ã‚‹ã‹ç¢ºèªã—ã€å†èµ·å‹•ã—ã¦ãã ã•ã„。 + hostsファイルã®å¾©å…ƒã«å¤±æ•—ã—ã¾ã—㟠+ デフォルトã®hostsファイル構æˆã‚’復元ã§ãã¾ã›ã‚“。 + + VPNåºƒå‘Šãƒ–ãƒ­ãƒƒã‚¯ã®æœ‰åŠ¹åŒ–ã«å¤±æ•—ã—ã¾ã—㟠+ 端末ã®VPN設定を確èªã—ã¦ã€ã‚¢ãƒ—リã‹ã‚‰ã®VPNã®èµ·å‹•を許å¯ã—ã¦ãã ã•ã„。 + VPN広告ブロックã®ç„¡åŠ¹åŒ–ã«å¤±æ•—ã—ã¾ã—㟠+ 端末ã®VPN設定を確èªã—ã¦ã€æ‰‹å‹•ã§ç„¡åйã«ã—ã¦ãã ã•ã„。 + diff --git a/app/src/main/res/values-ja/strings_home.xml b/app/src/main/res/values-ja/strings_home.xml new file mode 100644 index 0000000..fba20ba --- /dev/null +++ b/app/src/main/res/values-ja/strings_home.xml @@ -0,0 +1,44 @@ + + + + + ç¦æ­¢ + è¨±å¯ + è»¢é€ + + + + %d 最新ソース + + + %d å¤ã„ソース + + hostsã®æ›´æ–°ã‚’ç¢ºèª + hostsã‚’æ›´æ–° + + + DNSリクエストログを表示 + + + ヘルプを表示 + + + GitHub ページを開ã + + + プロジェクト サãƒãƒ¼ãƒˆ + + + GitHub プロジェクト + 設定 + + + ナビゲーションドロワーを開ã + 広告ブロックã®ä¸€æ™‚åœæ­¢/å†é–‹ + ブロックã•れãŸãƒ‰ãƒ¡ã‚¤ãƒ³ã®æ›´æ–° + è¦æ±‚ã•れãŸãƒ‰ãƒ¡ã‚¤ãƒ³ã®è¡¨ç¤º + + + 詳ã—ãã¯ãƒ˜ãƒ«ãƒ—ã‚’ã”覧ãã ã•ã„ + + \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings_hosts.xml b/app/src/main/res/values-ja/strings_hosts.xml new file mode 100644 index 0000000..0bfa7e1 --- /dev/null +++ b/app/src/main/res/values-ja/strings_hosts.xml @@ -0,0 +1,17 @@ + + + hosts å–å¾—å…ˆ + + ユーザーリスト + AdAway official hosts + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + æ—¥æ™‚ä¸æ˜Ž + %s hosts + + ソースを追加 + ソースを編集 + URL: (https:// ã¾ãŸã¯ file:// ã®æƒ…å ±æº) + hosts ãŒç½®ã„ã¦ã‚ã‚‹ URL + diff --git a/app/src/main/res/values-ja/strings_lists.xml b/app/src/main/res/values-ja/strings_lists.xml new file mode 100644 index 0000000..2dc1dfa --- /dev/null +++ b/app/src/main/res/values-ja/strings_lists.xml @@ -0,0 +1,24 @@ + + + ã‚ãªãŸã®ãƒªã‚¹ãƒˆ + ホストを追加 + + ブロック + è¨±å¯ + è»¢é€ + + hostsã®ãƒ•ィルタリング + hostnameを検索… + ソースを切り替ãˆã‚‹ + + ホストをブラックリストã«è¿½åŠ ã™ã‚‹ + ホストをホワイトリストã«è¿½åŠ ã™ã‚‹ + ホストリダイレクトを追加 + ブラックリスト内ã®ãƒ›ã‚¹ãƒˆã‚’編集ã™ã‚‹ + ホワイトリスト内ã®ãƒ›ã‚¹ãƒˆã‚’編集ã™ã‚‹ + リダイレクト先を編集 + ホストå: + hosts ãŒç½®ã„ã¦ã‚ã‚‹ URL + (ワイルドカード文字 「*〠ãŠã‚ˆã³ 「?〠ãŒä½¿ç”¨ã§ãã¾ã™ï¼‰ + IP (IPv4 ã‹ IPv6): + diff --git a/app/src/main/res/values-ja/strings_log.xml b/app/src/main/res/values-ja/strings_log.xml new file mode 100644 index 0000000..28e3845 --- /dev/null +++ b/app/src/main/res/values-ja/strings_log.xml @@ -0,0 +1,11 @@ + + + ログå–得切替 + 記録ボタンを押ã—ã¦ãƒ­ã‚°ã®å–得を開始後ã€Web閲覧やアプリを使用ã—ã¦ã‹ã‚‰ã€å†åº¦ã“ã®ç”»é¢ã«æˆ»ã‚‹ã‹ã‚¹ãƒ¯ã‚¤ãƒ—ã™ã‚‹ã“ã¨ã§ãƒ­ã‚°ãŒæ›´æ–°ã•れã¾ã™ã€‚ + \n\nブロックã•れãŸDNSè¦æ±‚ã¯ãƒ­ã‚°ã«è¨˜éŒ²ã•れã¾ã›ã‚“。広告ブロックを解除ã—ã¦ã‹ã‚‰ãƒ­ã‚°ã‚’記録ã—ã¦ãã ã•ã„。 + + アルファベット順 + トップレベルドメイン順 + + ドメインをリダイレクトã™ã‚‹ + diff --git a/app/src/main/res/values-ja/strings_notification.xml b/app/src/main/res/values-ja/strings_notification.xml new file mode 100644 index 0000000..85849a9 --- /dev/null +++ b/app/src/main/res/values-ja/strings_notification.xml @@ -0,0 +1,13 @@ + + + + アップデート + æ–°ã—ã„アップデートã®é€šçŸ¥ + æ›´æ–°ãŒã‚りã¾ã™ + æ–°ã—ã„hostsファイルãŒãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰å¯èƒ½ã«ãªã‚Šã¾ã—㟠+ アプリを更新ã§ãã¾ã™ + AdAwayã®æ–°ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã§ãã¾ã™ + + VPN + VPN実行中ã®é€šçŸ¥ + \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings_prefs_backup_restore.xml b/app/src/main/res/values-ja/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..b822fe7 --- /dev/null +++ b/app/src/main/res/values-ja/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ— & リストア + ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ— + ブロックルールを外部ストレージã«ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ— + リストア + ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ファイルã‹ã‚‰ãƒ–ロックルールを復元 + diff --git a/app/src/main/res/values-ja/strings_prefs_main.xml b/app/src/main/res/values-ja/strings_prefs_main.xml new file mode 100644 index 0000000..9cb9739 --- /dev/null +++ b/app/src/main/res/values-ja/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + 設定 + + 一般 + ダークテーマ + + ライト + ダーク + システムã®ãƒ‡ãƒ•ォルト + + 自動更新 + + 広告ブロッキング + Root based ad blocker + VPN based ad blocker + IPv6 サãƒãƒ¼ãƒˆã®æœ‰åŠ¹åŒ– + ブロックルールã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—/リストア + + デãƒãƒƒã‚° + クラッシュレãƒãƒ¼ãƒˆã®é€ä¿¡ + Sentryã¸å ±å‘Šï¼ˆsentry.io) + ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã›ã‚“ + 徹底ã—ãŸãƒ­ã‚°åŽé›† + é©ç”¨ã™ã‚‹ã«ã¯ã‚¢ãƒ—リã®å†èµ·å‹•ãŒå¿…è¦ã§ã™ + diff --git a/app/src/main/res/values-ja/strings_prefs_root.xml b/app/src/main/res/values-ja/strings_prefs_root.xml new file mode 100644 index 0000000..a64d42a --- /dev/null +++ b/app/src/main/res/values-ja/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Root based ad blocker + + hostsインストール + hostsファイルを開ã + ターゲットhostsファイル + ã“ã®æ©Ÿèƒ½ã‚’使用ã™ã‚‹å‰ã«ã€ãƒ˜ãƒ«ãƒ—ã‚’ãŠèª­ã¿ãã ã•ã„ + + /system/etc/hosts + /data/hosts + /data/data/hosts + カスタムターゲット + + カスタムターゲットã®å ´æ‰€ + é©ç”¨å¾Œã®å†èµ·å‹•ダイアログを表示ã—ãªã„ + + リダイレクト + ブロックã•れãŸãƒ›ã‚¹ãƒˆã®ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆå…ˆã‚’定義ã—ã¾ã™ + IPv4リダイレクト + IPv6リダイレクト + 無効ãªãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆ + + ローカルWebサーãƒãƒ¼ + ローカルWebサーãƒãƒ¼ãŒãƒ–ロックã•れãŸãƒ›ã‚¹ãƒˆåã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ç­”ãˆã¾ã™ã€‚接続ãŒãƒ–ロックã•れãŸå½±éŸ¿ã«ã‚ˆã‚‹ã‚¢ãƒ—リã®ãƒ•リーズを防ãã“ã¨ãŒã§ãã¾ã™ã€‚ + Webサーãƒãƒ¼ã‚’有効ã«ã™ã‚‹ + Webサーãƒãƒ¼ã®ãƒ†ã‚¹ãƒˆ + 自己署å証明書ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ« + è¨¼æ˜Žæ›¸ã®æ‰‹å‹•インストール + Android 11 (R)以é™ã€ã‚¢ãƒ—リã‹ã‚‰èªè¨¼å±€ï¼ˆCA)ã®è‡ªå‹•インストールãŒã§ããªããªã‚Šã¾ã—ãŸã€‚\n\n\"セキュリティ\"設定ã®\"æš—å·åŒ–ã¨èªè¨¼æƒ…å ±\"ã‹ã‚‰\"証明書ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«\"ã‚’é¸æŠžã—ã¦ãã ã•ã„。ãã“ã‹ã‚‰\"CA証明書\"ã‚’é¸æŠžã—ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ãŸè¨¼æ˜Žæ›¸ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠžã—ã¦ãã ã•ã„。 + \"セキュリティ\"設定を開ã + 確èªä¸­â€¦ + 実行ã—ã¦ã„ã¾ã›ã‚“ + 実行中ã§ã™ãŒè¨¼æ˜Žæ›¸ãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•れã¦ã„ã¾ã›ã‚“ + 実行中ã§è¨¼æ˜Žæ›¸ãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•れã¦ã„ã¾ã™ + 空白ã«ãªã‚‹åºƒå‘Šã‚¹ãƒšãƒ¼ã‚¹ã‚’アプリアイコンã§ç½®ãæ›ãˆã‚‹ + diff --git a/app/src/main/res/values-ja/strings_prefs_update.xml b/app/src/main/res/values-ja/strings_prefs_update.xml new file mode 100644 index 0000000..2319aae --- /dev/null +++ b/app/src/main/res/values-ja/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + アップデート + 通知ãŒã‚ªãƒ•ã•れã¦ã„ã¾ã™ + アプリケーションã®é€šçŸ¥ã¯è¡¨ç¤ºã•れã¾ã›ã‚“。タップã—ã¦æœ‰åйã«ã™ã‚‹ã€‚ + + ã‚¢ãƒ—ãƒªã‚±ãƒ¼ã‚·ãƒ§ãƒ³ã®æ›´æ–° + 起動時ã«ã‚¢ãƒƒãƒ—デートを確èªã™ã‚‹ + 定期的ãªã‚¢ãƒƒãƒ—デートã®ç¢ºèª + ベータ版ã®ãƒªãƒªãƒ¼ã‚¹ã‚’å«ã‚ã‚‹ + + hostsã®æ›´æ–° + 起動時ã«ã‚¢ãƒƒãƒ—デートを確èªã™ã‚‹ + 定期的ãªã‚¢ãƒƒãƒ—デートã®ç¢ºèª + 更新時ã«åŒæœŸã™ã‚‹ + éžèª²é‡‘ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã§ã®ã¿åŒæœŸ + diff --git a/app/src/main/res/values-ja/strings_prefs_vpn.xml b/app/src/main/res/values-ja/strings_prefs_vpn.xml new file mode 100644 index 0000000..8d7c25d --- /dev/null +++ b/app/src/main/res/values-ja/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN based ad blocker + + èµ·å‹•æ™‚ã«æœ‰åйã«ã™ã‚‹ + 接続を監視ã™ã‚‹ + 定期的ã«ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®çŠ¶æ…‹ã‚’ç¢ºèªã—ã€åˆ‡æ–­æ™‚ã«VPNã‚’å†èµ·å‹•ã—ã¾ã™ + + 対象外ã®ã‚¢ãƒ—リケーション + VPNを使用ã—ãªã„アプリケーションを設定ã™ã‚‹ã¨ã€æŽ¥ç¶šãŒãƒ–ロックã•れãªããªã‚Šã¾ã™ + システムアプリを除外ã™ã‚‹ + + 除外ã—ãªã„ + ブラウザを除ãã™ã¹ã¦ + ã™ã¹ã¦ + + ユーザーアプリを除外ã™ã‚‹ + + + 対象外ã®ã‚¢ãƒ—リケーション + ã™ã¹ã¦é¸æŠž + ã™ã¹ã¦ã®é¸æŠžã‚’解除 + Application icon + diff --git a/app/src/main/res/values-ja/strings_source_edit.xml b/app/src/main/res/values-ja/strings_source_edit.xml new file mode 100644 index 0000000..48b30b8 --- /dev/null +++ b/app/src/main/res/values-ja/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + ソースを編集 + ソースを追加 + + ラベル + ラベルã¯å¿…é ˆã§ã™ + タイプ + URL + ファイル + 場所 + https:// + 場所ã¯å¿…é ˆã§ã™ + ファイルを押ã™ã¨ã‚½ãƒ¼ã‚¹ãƒ•ァイルã¨ã—ã¦é¸ã¹ã¾ã™ + 場所ãŒé–“é•ã£ã¦ã„ã¾ã™ + ãƒªã‚¹ãƒˆå½¢å¼ + ブロック + è¨±å¯ + リダイレクトホストã®é©ç”¨ + リダイレクトホストを許å¯ã™ã‚‹ã¨ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã®å•題を起ã“ã™å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚é‡è¦ãªãƒˆãƒ©ãƒ•ィックを他ã®ã‚µãƒ¼ãƒãƒ¼ã«è»¢é€ã—ã¦ã—ã¾ã†æã‚ŒãŒã‚ã‚‹ãŸã‚ã€ä¿¡é ¼ã§ãるソースã§ã®ã¿ã“ã®è¨­å®šã‚’使ã£ã¦ãã ã•ã„。 + diff --git a/app/src/main/res/values-ja/strings_support.xml b/app/src/main/res/values-ja/strings_support.xml new file mode 100644 index 0000000..8479178 --- /dev/null +++ b/app/src/main/res/values-ja/strings_support.xml @@ -0,0 +1,5 @@ + + + Support + スãƒãƒ³ã‚µãƒ¼ã«ãªã‚‹ + \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings_update.xml b/app/src/main/res/values-ja/strings_update.xml new file mode 100644 index 0000000..803860d --- /dev/null +++ b/app/src/main/res/values-ja/strings_update.xml @@ -0,0 +1,21 @@ + + + AdAway update + + アップデートã§ãã¾ã™! + + + 最新版ã§ã™ + æ›´æ–°ãŒã‚りã¾ã™ + AdAway 更新中 + 今ã™ãæ›´æ–° + %1$s / %2$s + 変更点: + 変更履歴: + é–‹ç™ºã®æ”¯æ´ + 寄付 + スãƒãƒ³ã‚µãƒ¼ + + + 最新ã®AdAwayをダウンロードã—ã¦ã„ã¾ã™â€¦ + diff --git a/app/src/main/res/values-ja/strings_welcome.xml b/app/src/main/res/values-ja/strings_welcome.xml new file mode 100644 index 0000000..805d452 --- /dev/null +++ b/app/src/main/res/values-ja/strings_welcome.xml @@ -0,0 +1,52 @@ + + + よã†ã“ã + 最åˆã®ã‚¦ã‚£ã‚¶ãƒ¼ãƒ‰ + 次ã®ã‚¦ã‚£ã‚¶ãƒ¼ãƒ‰ + 最後ã®ã‚¦ã‚£ã‚¶ãƒ¼ãƒ‰ + + + AdAwayã¸ã‚ˆã†ã“ã! + AdAwayã«ã¯2ã¤ã®åºƒå‘Šãƒ–ロック方法ãŒã‚りã¾ã™ã€‚好ããªæ–¹ã‚’é¸ã‚“ã§ãã ã•ã„。 + + Root logo + Root based\nad blocking + 高速 + ãƒãƒƒãƒ†ãƒªãƒ¼ã«å„ªã—ã„ + RootãŒå¿…è¦ + + VPN logo + VPN based\nad blocking + 低速 + ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã§å‹•作 + äº’æ›æ€§ãŒé«˜ã„ + + root化ã•れãŸAndroidãŒå¿…è¦ã§ã™ + suã®ãƒã‚¤ãƒŠãƒªãŒè¦‹ã¤ã‹ã‚‰ãªã‹ã£ãŸã‹ã€AdAwayã«root権é™ãŒè¨±å¯ã•れã¦ã„ãªã„ã‹ã®ã©ã¡ã‚‰ã‹ã§ã™ã€‚\n\nã“れã¯ã€ãŠä½¿ã„ã®ãƒ‡ãƒã‚¤ã‚¹ãŒroot化ã•れã¦ã„ãªã„å ´åˆã«ç™ºç”Ÿã™ã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚デãƒã‚¤ã‚¹ã‚’root化ã™ã‚‹æ–¹æ³•ã«ã¤ã„ã¦ã¯ã€wiki.lineageos.orgã‚„ãã®ä»–ã®Androidã®ã‚¦ã‚§ãƒ–サイトã§ç¢ºèªã§ãã¾ã™ã€‚ + + Pro + Con + + + Sync done + Error during sync + + åŒæœŸä¸­ + åŒæœŸã—ã¾ã—ãŸ! + AdAwayã¯ã€ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ã‚½ãƒ¼ã‚¹ã‹ã‚‰ãƒ–ロックã™ã‚‹åºƒå‘Šãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚’ダウンロードã—ã¾ã™ã€‚後ã‹ã‚‰è¨­å®šã§ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚ºã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ + Retry sync + åŒæœŸå¤±æ•—: %1$s リトライã—ã¾ã™ã‹? + + + Support + サãƒãƒ¼ãƒˆã—ã¦ã­! + ã“れã¯ç„¡æ–™ã®ã‚ªãƒ¼ãƒ—ンソースアプリã§ã™ã€‚ç§ã¯è‡ªç”±ãªæ™‚間を使ã£ã¦é–‹ç™ºã—ã¦ã„ã¾ã™ã€‚ã§ã™ã‹ã‚‰ã€ã‚‚ã—æ¥½ã—ã‚“ã§ã„ãŸã ã‘ãŸãªã‚‰é æ…®ãªãサãƒãƒ¼ãƒˆã—ã¦ãã ã•ã„。 + PayPalã§å¯„付ã™ã‚‹ + ãƒã‚°ã¯å«Œã„ã§ã™ã‚ˆã­ï¼Ÿç§ã‚‚ã§ã™ã€‚ + クラッシュレãƒãƒ¼ãƒˆã®åŽé›†ã¨å ±å‘Šã‚’有効ã«ã™ã‚‹ + + + 戻る + 次㸠+ 完了 + diff --git a/app/src/main/res/values-km/strings.xml b/app/src/main/res/values-km/strings.xml new file mode 100644 index 0000000..490f651 --- /dev/null +++ b/app/src/main/res/values-km/strings.xml @@ -0,0 +1,57 @@ + + + + ចាកចáŸáž‰ + បិទ + បាទ + ទ០+ បន្ážáŸ‚ម + បោះបង់ + រក្សាទុក + ជំនួយ + កែប្រែ + លុបចáŸáž‰ + + រកឃើញមានជំនាន់ážáŸ’មី + ពុំមានážáŸ†áž“រភ្ជាប់អ៊ិនធឺណែហ+ ពុំមានឃើញមានážáŸ†áž“រភ្ជាប់អ៊ិនធឺណែហ+ គ្មានប្រភពឯកសារម៉ាស៊ីនណាអាចទាក់ទងបាន + ážáŸ’រូវបានបញ្ចូល + ážáŸ’រូវបានបណ្ážáž¶áž…់ + ពុំមានប្រលោះទំនáŸážšáž‚្រប់គ្រាន់ + ចម្លងបរាជáŸáž™ + ស្នើរសុំជោគជáŸáž™ + សូមអាន \"ជំនួយ\" សម្រាប់ពáŸážáž˜áž¶áž“បន្ážáŸ‚ម + បានកំណážáŸ‹ APN ប្រូកស៊ី! + ការភ្ជាប់អ៊ិនធឺណែážáž‚ឺមិនដំនើរការ + គ្មានការážáž—្ជាប់ + កំពុងអនុវážáŸ’ážáž”ញ្ជីážáŸ’មៅ និង បញ្ជីស + កំពុងបង្កើážáž¯áž€ážŸáž¶ážš + កំពុងអនុវážáŸ’ážáž¯áž€ážŸáž¶ážš + ការអនុវážáŸ’ážáž”ានបរាជáŸáž™ + ážáŸ’រឡប់ដូចដើមជោគជáŸáž™ + ធ្វើឲ្យដូចដើមបរាជáŸáž™ + ទាញយកបរាជáŸáž™ + កំពុងផ្ទុកទិន្នáŸáž™â€¦ + + បន្ážáŸ‚ម + ជំនួយ + + S-ON/S-OFF + + អ្នកបំបិទការឃោសនា + ពុំមានកម្មវិធីគ្រប់គ្រងឯកសារážáŸ’រូវបានបញ្ចូល + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + ការកំណážáŸ‹ + ជំនួយ + + ការកំណážáŸ‹ + + diff --git a/app/src/main/res/values-km/strings_app.xml b/app/src/main/res/values-km/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-km/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-km/strings_errors.xml b/app/src/main/res/values-km/strings_errors.xml new file mode 100644 index 0000000..2fee285 --- /dev/null +++ b/app/src/main/res/values-km/strings_errors.xml @@ -0,0 +1,6 @@ + + + + ពុំមានážáŸ†áž“រភ្ជាប់អ៊ិនធឺណែហ+ ពុំមានប្រលោះទំនáŸážšáž‚្រប់គ្រាន់ + \ No newline at end of file diff --git a/app/src/main/res/values-km/strings_home.xml b/app/src/main/res/values-km/strings_home.xml new file mode 100644 index 0000000..1a68a36 --- /dev/null +++ b/app/src/main/res/values-km/strings_home.xml @@ -0,0 +1,9 @@ + + + + ការកំណážáŸ‹ + + + សូមអាន \"ជំនួយ\" សម្រាប់ពáŸážáž˜áž¶áž“បន្ážáŸ‚ម + + \ No newline at end of file diff --git a/app/src/main/res/values-km/strings_hosts.xml b/app/src/main/res/values-km/strings_hosts.xml new file mode 100644 index 0000000..033e676 --- /dev/null +++ b/app/src/main/res/values-km/strings_hosts.xml @@ -0,0 +1,6 @@ + + + Hosts sources + + មិនមានរកឃើញ + diff --git a/app/src/main/res/values-km/strings_lists.xml b/app/src/main/res/values-km/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-km/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-km/strings_log.xml b/app/src/main/res/values-km/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-km/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-km/strings_notification.xml b/app/src/main/res/values-km/strings_notification.xml new file mode 100644 index 0000000..b52dc27 --- /dev/null +++ b/app/src/main/res/values-km/strings_notification.xml @@ -0,0 +1,4 @@ + + + រកឃើញមានជំនាន់ážáŸ’មី + \ No newline at end of file diff --git a/app/src/main/res/values-km/strings_prefs_backup_restore.xml b/app/src/main/res/values-km/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-km/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-km/strings_prefs_main.xml b/app/src/main/res/values-km/strings_prefs_main.xml new file mode 100644 index 0000000..3483c2f --- /dev/null +++ b/app/src/main/res/values-km/strings_prefs_main.xml @@ -0,0 +1,6 @@ + + + ការកំណážáŸ‹ + + បំបាážáŸ‹áž€áŸ†áž áž»ážŸ + diff --git a/app/src/main/res/values-km/strings_prefs_root.xml b/app/src/main/res/values-km/strings_prefs_root.xml new file mode 100644 index 0000000..fd139d5 --- /dev/null +++ b/app/src/main/res/values-km/strings_prefs_root.xml @@ -0,0 +1,11 @@ + + + Open hosts file + គោលដៅឯកសារម៉ាស៊ីន + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-km/strings_prefs_update.xml b/app/src/main/res/values-km/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-km/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-km/strings_prefs_vpn.xml b/app/src/main/res/values-km/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-km/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-km/strings_support.xml b/app/src/main/res/values-km/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-km/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-km/strings_update.xml b/app/src/main/res/values-km/strings_update.xml new file mode 100644 index 0000000..f186884 --- /dev/null +++ b/app/src/main/res/values-km/strings_update.xml @@ -0,0 +1,4 @@ + + + រកឃើញមានជំនាន់ážáŸ’មី + diff --git a/app/src/main/res/values-km/strings_welcome.xml b/app/src/main/res/values-km/strings_welcome.xml new file mode 100644 index 0000000..27c8543 --- /dev/null +++ b/app/src/main/res/values-km/strings_welcome.xml @@ -0,0 +1,4 @@ + + + ážáž˜áŸ’រូវការ Root ទូរសáŸáž–្ធ + diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml new file mode 100644 index 0000000..6c66b86 --- /dev/null +++ b/app/src/main/res/values-ko/strings.xml @@ -0,0 +1,258 @@ + + + + 종료 + 닫기 + 예 + 아니오 + 추가 + 취소 + 저장 + ë„ì›€ë§ + + + 환ì˜í•©ë‹ˆë‹¤! + AdAway는 광고를 막기 위해 ê³ ì•ˆëœ ë¬´ë£Œ 오픈 소스 소프트웨어입니다. ì´ëŠ” ê´‘ê³ ë“¤ì˜ ë„¤íŠ¸ì›Œí¬ ì£¼ì†Œë¥¼ 찾아 ë‹¹ì‹ ì˜ ë””ë°”ì´ìФì—서 막습니다.\në” ì•Œê³  싶다면 ë°‘ì˜ ë„움ë§ì„ 확ì¸í•´ì£¼ì„¸ìš”! + ë„ì›€ë§ ë”보기 + ì—…ë°ì´íЏ ìƒíƒœ + 지정한 ì†ŒìŠ¤ì˜ ëª¨ë“  호스트 파ì¼ì´ ì‚¬ìš©ìž ëª©ë¡ê³¼ 다운로드 ë° ë³‘í•©ë˜ì—ˆê³  ì‹œìŠ¤í…œì— í•˜ë‚˜ì˜ í˜¸ìŠ¤íŠ¸ 파ì¼ë¡œ 설치ë˜ì—ˆìŠµë‹ˆë‹¤. + 광고차단 활성화 + 광고차단 비활성화 + 웹 서버 + 실행중 + ì¤‘ì§€ë¨ + ë¡œì»¬í˜¸ìŠ¤íŠ¸ì˜ ì›¹ì„œë²„ë¥¼ 시작 ë˜ëŠ” 중지하여 ì°¨ë‹¨ëœ í˜¸ìŠ¤íŠ¸ëª…ì˜ ìš”ì²­ì— ì‘답합니다. + 웹 서버 활성화 + 웹 서버 비활성화 + VPN + 실행중 + ì¤‘ì§€ë¨ + 필터를 요청하려면, VPNì„ ì‹œìž‘í•˜ê±°ë‚˜ 중단해야합니다. + VPN 활성화 + VPN 비활성화 + + + 항목 편집 + ì ìš© + 편집 + ì‚­ì œ + + + 가져오는 중… + ë°±ì—…ì´ ì„±ê³µì ìœ¼ë¡œ 외부 저장소ì—서부터 불러와졌습니다. + ë°±ì—…ì„ ë¶ˆëŸ¬ì˜¤ëŠ”ë° ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤. 해당 íŒŒì¼ í˜•ì‹ì´ 옳바릅니까? ìžì„¸í•œ ë‚´ìš©ì€ ë¡œê·¸ìº£ì„ í™•ì¸í•´ì£¼ì‹­ì‹œì˜¤. + 내보내는 중… + Backup successfully exported to file \'%s\' on your external storage. + 백업 íŒŒì¼ \'%s\'를 ë‚´ë³´ë‚´ì§€ 실패했어요. + + + 호스트 íŒŒì¼ + 호스트 파ì¼ì€ 호스트ì´ë¦„ì„ IP주소로 변환하는 파ì¼ìž…니다. AdAwayì—서 처리ë˜ëŠ” 간단한 í…스트 파ì¼ìž…니다. 파ì¼ì˜ ì‹œìž‘ì€ ë‹¤ìŒê³¼ 같습니다: + 호스트 íŒŒì¼ ì»¨í…츠 불러오는 중… + 호스트 íŒŒì¼ ì—´ê¸° + + + ì—…ë°ì´íЏ í™•ì¸ ì¤‘ + ì—…ë°ì´íŠ¸ë¥¼ 위한 %s 소스 í™•ì¸ ì¤‘ + 소스 검색 중 + 소스 다운로드 중 %s + 소스 ì½ëŠ” 중 %s + 소스 ë¶„ì„ ì¤‘ %s + 규칙 ë°ì´í„°ë² ì´ìФ ë™ê¸°í™” + 기본 호스트 파ì¼ë¡œ ë˜ëŒë¦¬ëŠ” 중 + 기본 호스트 파ì¼ë¡œ 복구 ë¨ + 표준 호스트 íŒŒì¼ ìƒì„± 중 + ì—…ë°ì´íЏ 가능 + 최신 호스트 íŒŒì¼ ì‚¬ìš© 가능 + 소스 ì—…ë°ì´íŠ¸ë¥¼ ì°¾ì„ ìˆ˜ ì—†ìŒ + ì¸í„°ë„· ì—°ê²° ì•ˆë¨ + 사용 가능한 ì¸í„°ë„· ì—°ê²°ì´ ì—†ìŒ + 사용할수없는 소스 + ì ‘ê·¼ 가능한 호스트 소스가 없습니다! + 루팅 ê¶Œí•œì´ ê±°ë¶€ë¨ + 루팅앱ì—서 루팅 ê¶Œí•œì„ í—ˆìš©í•˜ì‹­ì‹œì˜¤. + 뭔가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤ + ìžì„¸í•œ ë‚´ìš©ì€ ë¡œê·¸ìº£ì„ í™•ì¸í•´ì£¼ì„¸ìš”. + í™œì„±í™”ë¨ + 최신 호스트 파ì¼ì´ í™œì„±í™”ë¨ + ë¹„í™œì„±í™”ë¨ + 기본 호스트 파ì¼ë“¤ì´ 설치 ë¨ + 최근 소스 ì ìš© + 새 호스트 íŒŒì¼ ìƒì„± 중 + 새 호스트 íŒŒì¼ ë³µì‚¬ 중 + 복사 ëœ ìƒˆ 호스트 íŒŒì¼ í™•ì¸ ì¤‘ + 호스트 파ì¼ì´ 성공ì ìœ¼ë¡œ ì—…ë°ì´íЏ ë¨ + VPN êµ¬ì„±ì´ ì„±ê³µì ìœ¼ë¡œ ì—…ë°ì´íЏ ë¨ + ë³€ê²½ëœ ì„¤ì •ì„ ì €ìž¥í•˜ë ¤ë©´, ì ìš©ì„ 해야합니다. + ì ìš© + 새 설정 ì ìš© 중… + 새 설정 ì ìš©ì— 실패했습니다. + + + 호스트 íŒŒì¼ ëŒ€ìƒì— 대한 심ë§í¬ê°€ ëˆ„ë½ ë¨ + 대ìƒì—서 /system/etc/host으로 ì—°ê²°ë˜ëŠ” 심ë§í¬ê°€ 존재하지 않거나 올바르지 않습니다! 올바른 파ì¼ì„ 가르키지 ì•Šì„ ê²½ìš° AdAwayê°€ ìž‘ë™í•˜ì§€ 않습니다.\n\n심ë§í¬ ìƒì„±ì„ 시ë„하시겠습니까? + 심ë§í¬ê°€ 누ë½ë¨ + íŒŒí‹°ì…˜ì— ê³µê°„ì´ ë¶€ì¡±í•©ë‹ˆë‹¤!\n환경 설정ì—서 ëŒ€ìƒ í˜¸ìŠ¤íŠ¸ 파ì¼ì„ /data/data/hosts로 변경해보십시오. + 공간 부족 + 다운로드한 파ì¼ì„ ì½ì„ 수 없습니다. + ê°œì¸ íŒŒì¼ ì ìš© 실패 + ì½ê¸°/쓰기 가능한 파티션으로 ìž¬ìž¥ì°©ì— ì‹¤íŒ¨ë˜ì—ˆìŠµë‹ˆë‹¤! + 재장착 실패 + 호스트 íŒŒì¼ ë³µì‚¬ 실패 + 호스트 íŒŒì¼ ë³µì‚¬ì— ì‹¤íŒ¨í•˜ì˜€ìŠµë‹ˆë‹¤! + 복사 실패 + 호스트 소스 ì ìš©ë¨ + ì ìš© 성공 + 성공ì ìœ¼ë¡œ ì ìš©í•˜ì˜€ìŠµë‹ˆë‹¤.\n변경 ì‚¬í•­ì„ ì ìš©í•˜ë ¤ë©´ ìž¬ë¶€íŒ…ì´ í•„ìš”í•  수 있습니다.\n\n재부팅 하시겠습니까?\n(ë°ì´í„° ì†ì‹¤ 방지를 위해 현재 SD카드를 사용 ì¤‘ì¸ ì•±ì´ ì—†ëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤!) + 심ë§í¬ë¥¼ 성공ì ìœ¼ë¡œ ìƒì„±í•˜ì˜€ìŠµë‹ˆë‹¤.\n변경 ì‚¬í•­ì„ ì ìš©í•˜ë ¤ë©´ ìž¬ë¶€íŒ…ì´ í•„ìš”í•  수 있습니다.\n\n재부팅 하시겠습니까?\n(ë°ì´í„° ì†ì‹¤ 방지를 위해 현재 SD카드를 사용 ì¤‘ì¸ ì•±ì´ ì—†ëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤!) + 심ë§í¬ ìƒì„± 성공 + 안드로ì´ë“œê°€ 심ë§í¬ë¥¼ ìƒì„±í•˜ì§€ 못하였습니다.\nì´ê²ƒì€ 대부분 HTC ì „í™”ê¸°ì˜ S-ONì´ë¼ 불리는 \'기능\'ì´ ì›ì¸ìž…니다!\n\ní•´ê²°ì„ ìœ„í•´ 전화기를 복구 모드로 부팅한 후 \'ln -s /data/data/hosts /system/etc/hosts\'ì—서 심ë§í¬ë¥¼ ìƒì„±í•˜ì‹­ì‹œì˜¤.\n\nì´ ë°©ë²•ì´ ìž‘ë™í•˜ì§€ ì•Šì„ ê²½ìš° ì¸í„°ë„·ì—서 S-OFF ë° ì „í™”ê¸° ê¸°ì¢…ì„ ê²€ìƒ‰í•˜ì‹­ì‹œì˜¤. + 심ë§í¬ ìƒì„± 실패 + ë” ë§Žì€ ì •ë³´ëŠ” ë„움ë§ì„ 참조해주십시오. + 안드로ì´ë“œì— APN 프ë¡ì‹œê°€ 설정ë˜ì–´ 있습니다!\nAdAway는 3G와 ê°™ì€ ëª¨ë°”ì¼ ë„¤íŠ¸ì›Œí¬ ìƒì—서 안정ì ìœ¼ë¡œ ìž‘ë™í•˜ì§€ 않습니다. ì„ íƒí•œ APN (설정 앱ì—서: ë„¤íŠ¸ì›Œí¬ ë° ì¸í„°ë„· -> ëª¨ë°”ì¼ ë„¤íŠ¸ì›Œí¬ -> 고급 -> 액세스 í¬ì¸íЏ ì´ë¦„)으로 ì´ë™í•˜ì—¬ 해당 프ë¡ì‹œë¥¼ 비활성화하고 프ë¡ì‹œ ìž…ë ¥ëž€ì— ê°’ì„ ì œê±°í•  수 있습니다. + APN 프ë¡ì‹œê°€ 설정ë¨! + ì¸í„°ë„·ì— ì—°ê²°ë˜ì§€ì•Šì•„ ìž‘ë™í•˜ì§€ì•ŠìŠµë‹ˆë‹¤ + ì—°ê²° ëŠê¹€ + 다운로드 중… + ì ìš© 중… + 허용 ëª©ë¡ ë° ì°¨ë‹¨ ëª©ë¡ ì ìš© 중 + 호스트 íŒŒì¼ êµ¬ë¬¸ ë¶„ì„ ë° ë³‘í•© 중 + 호스트 íŒŒì¼ ìƒì„± 중 + 호스트 íŒŒì¼ ì ìš© 중 + 새 호스트 íŒŒì¼ ì ìš© 실패 + ì‹œìŠ¤í…œì— í˜¸ìŠ¤íŠ¸ íŒŒì¼ ì ìš©í•˜ëŠ”ë° ì‹¤íŒ¨í•˜ì˜€ìŠµë‹ˆë‹¤!\n환경 설정ì—서 ëŒ€ìƒ í˜¸ìŠ¤íŠ¸ 파ì¼ì„ /data/data/hosts(으)로 변경해보십시오. + ì ìš©ì— 실패함 + ë‹¹ì‹ ì˜ ë£¨íŒ… ê´€ë¦¬ìž ì•±ì„ í™•ì¸í•˜ì—¬ 루팅 ê¶Œí•œì´ í—ˆìš©ë˜ì–´ìžˆëŠ”ì§€ 확ì¸í•´ì£¼ì‹­ì‹œì˜¤. + 기본 호스트 파ì¼ë¡œ ë˜ëŒë¦¬ì…¨ìŠµë‹ˆë‹¤.\n변경 ì‚¬í•­ì„ ì ìš©í•˜ë ¤ë©´ ìž¬ë¶€íŒ…ì´ í•„ìš”í•  수 있습니다.\n\n재부팅 하시겠습니까?\n(ë°ì´í„° ì†ì‹¤ 방지를 위해 현재 SD카드를 사용 ì¤‘ì¸ ì•±ì´ ì—†ëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤!) + ë˜ëŒë¦¬ê¸° 성공 + 호스트 파ì¼ì„ ë˜ëŒë¦´ 수 ì—†ìŒ + 알 수 없는 ì´ìœ ë¡œ ë˜ëŒë¦¬ê¸°ì— 실패하였습니다. + ë˜ëŒë¦¬ê¸°ì— 실패함! + í™œì„±í™”ëœ í˜¸ìŠ¤íŠ¸ 소스 중 ì–´ëŠ í•˜ë‚˜ë„ ì—°ê²°í•  수 없습니다! ì¸í„°ë„·ì— 제대로 ì—°ê²°ë˜ì–´ 있습니까? + 다운로드 실패 + 새 ê°œì¸ í˜¸ìŠ¤íŠ¸ íŒŒì¼ ìž‘ì„± 실패 + ê°œì¸ íŒŒì¼ì„ ìƒì„±í•  수 없습니다. + ê°œì¸ íŒŒì¼ ìƒì„±ì— 실패함 + Systemless 모드를 활성화하였습니다.\n변경 ì‚¬í•­ì„ ì ìš©í•˜ë ¤ë©´ ìž¬ë¶€íŒ…ì´ í•„ìš”í•  수 있습니다.\n\n재부팅 하시겠습니까?\n(ë°ì´í„° ì†ì‹¤ 방지를 위해 현재 SD카드를 사용 ì¤‘ì¸ ì•±ì´ ì—†ëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤!) + 활성화 성공 + Systemless 모드를 비활성화하였습니다.\n변경 ì‚¬í•­ì„ ì ìš©í•˜ë ¤ë©´ ìž¬ë¶€íŒ…ì´ í•„ìš”í•  수 있습니다.\n\n재부팅 하시겠습니까?\n(ë°ì´í„° ì†ì‹¤ 방지를 위해 현재 SD카드를 사용 ì¤‘ì¸ ì•±ì´ ì—†ëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤!) + 비활성화 성공 + ê´‘ê³  차단 활성화 실패 + ê´‘ê³  차단 비활성화 실패 + 호스트 Magisk 모듈 활성화 + Magisk 매니저ì—서 시스템없는 호스트 ê¸°ëŠ¥ì„ í™œì„±í™”í•©ë‹ˆë‹¤. Magisk 설정ì—서 Systemless hosts를 활성화한 ë‹¤ìŒ ìž¬ë¶€íŒ…í•˜ì‹­ì‹œì˜¤. + 호스트 Magisk 모듈 비활성화 + Magisk 매니저ì—서 시스템없는 호스트 ê¸°ëŠ¥ì„ ë¹„í™œì„±í™”í•©ë‹ˆë‹¤. 모듈 목ë¡ì—서, Systemless hosts를 제거한 ë‹¤ìŒ ìž¬ë¶€íŒ…í•˜ì‹­ì‹œì˜¤. + + + 호스트 파ì¼ì— URL ìž…ë ¥: + ìž˜ëª»ëœ í˜¸ìŠ¤íŠ¸ëª…ìž…ë‹ˆë‹¤! + ë¶€ì ì ˆí•œ 형ì‹ì˜ 호스트명 + ì´ê²ƒì€ 올바른 IPê°€ 아닙니다! + ë¶€ì ì ˆí•œ 형ì‹ì˜ IP + 절대 재시작하지 ë§ê³  다시는 ì´ ì§ˆë¬¸ì„ í•˜ì§€ 마십시오! + 불러오는 중… + + + 새로 고침 + 추가 + ë„ì›€ë§ + 백업 불러오기 + 백업 저장하기 + + + S-ON/S-OFF + FAQ + 문제 + + + 애드웨어 + 여기서 AdAway로 차단ë˜ì§€ 않는 불량 애드웨어 ì•±ì„ ê²€ìƒ‰í•  수 있습니다. ì´ ì•±ë“¤ì€ ì•±ì´ ì‹¤í–‰ 중ì´ì§€ ì•Šì„ ë•Œë‚˜ 벨소리를 변경할 ë•Œë„ íŒì—… 형ì‹ìœ¼ë¡œ 나타나는 Alrpush ê°™ì€ ì•Œë¦¼ì„ ì‚¬ìš©í•©ë‹ˆë‹¤. 사용 가능한 유ì¼í•œ ëŒ€ì±…ì€ ëª©ë¡ ì•„ì´í…œì„ í´ë¦­í•˜ì—¬ 제거하는 것입니다. + 스캔중… + 애드웨어가 없습니다! + + + ê´‘ê³  차단기 + ì„¤ì¹˜ëœ í…스트 편집기가 ì—†ìŒ + 호스트 파ì¼ì„ 열기 위한 í…스트 편집기를 발견하지 못하였습니다. Jota ë˜ëŠ” 기타 í…스트 편집기를 설치하여 ì´ë¥¼ 처리할 수 있습니다.\n\nJota를 설치하시겠습니까? + íŒŒì¼ ê´€ë¦¬ìžê°€ 설치ë˜ì–´ìžˆì§€ ì•ŠìŒ + 파ì¼ì„ 열기 위한 íŒŒì¼ ê´€ë¦¬ìžë¥¼ 발견하지 못했습니다. OI íŒŒì¼ ê´€ë¦¬ìž ë˜ëŠ” 기타 íŒŒì¼ ê´€ë¦¬ìžë¥¼ 설치하여 ì´ë¥¼ 처리할 수 있습니다.\n\nOI íŒŒì¼ ê´€ë¦¬ìžë¥¼ 설치하시겠습니까? + + + Tcpdump + Tcpdump는 DNS ìš”ì²­ì„ ê°ì‹œí•˜ê³  로그 파ì¼ì— 저장하는 ë„구입니다. ë°°ê²½ì—서 시작할 수 있고, 광고를 표시하는 ì•±ì„ ì‹¤í–‰í•  수 있으며, 추후 로그 파ì¼ì„ ì´ìš©í•˜ì—¬ DNS ìš”ì²­ì„ ë¶„ì„í•  수 있습니다. 그런 ë‹¤ìŒ ì˜ì‹¬ìŠ¤ëŸ¬ìš´ ê´‘ê³  서버를 차단 목ë¡ì— 추가할 수 있습니다. + ê°ì‹œ 비활성화 + ê°ì‹œ 활성화 + ê²°ê³¼ 보기 + ë„ë©”ì¸ ì •ë ¬ + 로그 지우기 + ë¸”ëž™ë¦¬ìŠ¤íŠ¸ì— ì¶”ê°€ + í™”ì´íŠ¸ë¦¬ìŠ¤íŠ¸ì— ì¶”ê°€ + 리다ì´ë ‰íЏ ë¦¬ìŠ¤íŠ¸ì— ì¶”ê°€ + + í…스트 ê°’ 수정 + 메뉴 열기 + 메뉴 닫기 + + + + 홈 + 호스트 소스 + ì‚¬ìš©ìž ë¦¬ìŠ¤íŠ¸ + 호스트 íŒŒì¼ ì—´ê¸° + DNS 리퀘스트 로그 + 애드웨어 검색 + 환경 설정 + ë„ì›€ë§ + + + + + DNS 리퀘스트 + ì‚¬ìš©ìž ëª©ë¡ + 환경 설정 + + + %1$s ì „ì— ì„¤ì¹˜ ë¨ + %1$s ì „ì— ê°±ì‹  ë¨ + %1$sê°œì˜ ì—…ë°ì´íŠ¸ê°€ í•„ìš” + %1$sì¼ ì „ì— ì—…ë°ì´íЏ ë¨ + ì—…ë°ì´íЏ ìƒíƒœ í™•ì¸ ë¶ˆê°€ + ë¹„í™œì„±í™”ë¨ + 몇 ë¶„ + + %d ë¶„ + + + %d 시간 + + + %d ì¼ + + + %d 개월 + + + + í´ë¦½ë³´ë“œì— ë³µì‚¬ëœ í˜¸ìŠ¤íŠ¸ + + + 시작 중 + 활성화 + 중단 중 + ë„¤íŠ¸ì›Œí¬ ê¸°ë‹¤ë¦¬ëŠ” 중 + ìž¬ì ‘ì† ì¤‘ + ìž¬ì ‘ì† ì˜¤ë¥˜ + ì¼ì‹œì •ì§€ë¨ + ì¤‘ë‹¨ë¨ + ê´‘ê³  차단 VPN %1$s + ì¼ì‹œì •ì§€ + 탭하여 재개 + + + AdAwayì˜ í—ˆê°€ + Adaway와 ìƒí˜¸ìž‘용하ë„ë¡ í—ˆìš© + 시스템 ê´‘ê³  ì°¨ë‹¨ì„ í™œì„±í™”í•˜ê±°ë‚˜ 비활성화 + Adawayì— ì‹œìŠ¤í…œ ì „ì²´ ê´‘ê³  ì°¨ë‹¨ì„ í™œì„±í™”ë˜ëŠ” 비활성화와 ê°™ì€ ëª…ë ¹ì„ ë³´ë‚¼ìˆ˜ 있게 허용 + + diff --git a/app/src/main/res/values-ko/strings_app.xml b/app/src/main/res/values-ko/strings_app.xml new file mode 100644 index 0000000..0f0a38a --- /dev/null +++ b/app/src/main/res/values-ko/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + 오픈 소스 ê´‘ê³  차단기 + AdAway 로고 + diff --git a/app/src/main/res/values-ko/strings_errors.xml b/app/src/main/res/values-ko/strings_errors.xml new file mode 100644 index 0000000..f2f809e --- /dev/null +++ b/app/src/main/res/values-ko/strings_errors.xml @@ -0,0 +1,22 @@ + + + + ì¸í„°ë„· ì—°ê²° ì•ˆë¨ + ì¸í„°ë„· ì—°ê²°ì„ ì„¤ì •í•  수 없습니다. 장치 ì—°ê²°ì„ í™•ì¸í•˜ì‹­ì‹œì˜¤. + 호스트 소스 다운로드 실패 + í™œì„±í™”ëœ í˜¸ìŠ¤íŠ¸ ì†ŒìŠ¤ì— ì—°ê²°í•  수 없습니다. ì¸í„°ë„·ì— 제대로 ì—°ê²°ë˜ì–´ 있는지 확ì¸í•˜ì‹­ì‹œì˜¤. + + ê°œì¸ íŒŒì¼ ìƒì„± 실패 + 새 호스트 소스를 빌드하기 위한 ê°œì¸ íŒŒì¼ì„ ìƒì„±í•  수 없습니다. 장치ì—서 사용 가능한 ê³ ê°„ì„ í™•ì¸í•˜ì‹­ì‹œì˜¤. + 공간 부족 + 호스트 파ì¼ì´ 시스템 íŒŒí‹°ì…˜ì— ë³µì‚¬ í•  수 없습니다. Magisk 시스템 제외 ëª¨ë“ˆì´ ìž¬ë¶€íŒ… 후 활성화 ë˜ì–´ìžˆëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤. + 새 호스트 íŒŒì¼ ì„¤ì¹˜ 실패 + 호스트 파ì¼ì´ /system íŒŒí‹°ì…˜ì— ë³µì‚¬í•  수 없습니다. Magisk 시스템 제외 ëª¨ë“ˆì´ ìž¬ë¶€íŒ… 후 활성화 ë˜ì–´ìžˆëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤. + 호스트 íŒŒì¼ ë˜ëŒë¦¬ê¸° 실패 + 호스트 íŒŒì¼ êµ¬ì„±ì„ ê¸°ë³¸ê°’ìœ¼ë¡œ ë³µì›í•  수 없습니다. + + ê´‘ê³  차단 활성화 실패 + VPN ì„¤ì •ì„ í™•ì¸í•˜ì—¬ VPNì´ ì‹¤í–‰ë˜ë„ë¡ ê¶Œí•œì„ ë¶€ì—¬í•´ì£¼ì‹­ì‹œì˜¤. + ê´‘ê³  차단 비활성화 실패 + VPN ì„¤ì •ì„ ìˆ˜ë™ìœ¼ë¡œ 비활성화하려면 VPN ì„¤ì •ì„ í™•ì¸í•˜ì‹­ì‹œì˜¤. + diff --git a/app/src/main/res/values-ko/strings_home.xml b/app/src/main/res/values-ko/strings_home.xml new file mode 100644 index 0000000..8b4293c --- /dev/null +++ b/app/src/main/res/values-ko/strings_home.xml @@ -0,0 +1,44 @@ + + + + + 차단 ë¨ + 허용 ë¨ + 리다ì´ë ‰íЏ ë¨ + + + + %dê°œì˜ ê°±ì‹ ëœ ì†ŒìŠ¤ + + + %dê°œì˜ ì˜¤ëž˜ëœ ì†ŒìŠ¤ + + 호스트 ì—…ë°ì´íЏ í™•ì¸ + 호스트 ì—…ë°ì´íЏ + + + DNS 요청 ê¸°ë¡ ë³´ê¸° + + + ë„ì›€ë§ ë³´ê¸° + + + GitHub ì ‘ì† + + + ì§€ì›í•˜ê¸° + + + Github 프로ì íЏ + 환경 설정 + + + 네비게ì´ì…˜ ì„œëž ì—´ê¸° + ê´‘ê³  차단 ì¼ì‹œì •ì§€/재개 + ì°¨ë‹¨ëœ ë„ë©”ì¸ ì—…ë°ì´íЏ + ìš”ì²­ëœ ë„ë©”ì¸ ë³´ê¸° + + + ë” ë§Žì€ ì •ë³´ëŠ” ë„움ë§ì„ 참조해주세요. + + \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings_hosts.xml b/app/src/main/res/values-ko/strings_hosts.xml new file mode 100644 index 0000000..8369795 --- /dev/null +++ b/app/src/main/res/values-ko/strings_hosts.xml @@ -0,0 +1,17 @@ + + + 호스트 소스 + + ì‚¬ìš©ìž ë¦¬ìŠ¤íŠ¸ + AdAway ê³µì‹ í˜¸ìŠ¤íŠ¸ + StevenBlack 통합 호스트 + Pete Lowe 블ë½ë¦¬ìŠ¤íŠ¸ 호스트 + + 사용 불가 + %s 호스트 + + 소스 추가 + 소스 수정 + URL: (https://로 시작하거나 file://로 시작) + 호스트 소스 URL + diff --git a/app/src/main/res/values-ko/strings_lists.xml b/app/src/main/res/values-ko/strings_lists.xml new file mode 100644 index 0000000..d531a1a --- /dev/null +++ b/app/src/main/res/values-ko/strings_lists.xml @@ -0,0 +1,24 @@ + + + ì‚¬ìš©ìž ëª©ë¡ + 호스트 추가 + + 차단 ë¨ + 허용 ë¨ + 리다ì´ë ‰íЏ ë¨ + + 호스트 í•„í„° + 호스트 ì´ë¦„ 검색… + 소스 전환 + + ë¸”ëž™ë¦¬ìŠ¤íŠ¸ì— í˜¸ìŠ¤íŠ¸ 추가 + í™”ì´íŠ¸ë¦¬ìŠ¤íŠ¸ì— í˜¸ìŠ¤íŠ¸ 추가 + 리다ì´ë ‰íŠ¸ì— í˜¸ìŠ¤íŠ¸ 추가 + 블랙리스트 호스트 수정 + í™”ì´íŠ¸ë¦¬ìŠ¤íŠ¸ 호스트 수정 + 리다ì´ë ‰íЏ 수정 + 호스트명: + 호스트 소스 URL + (*ê³¼ ? 2ê°€ì§€ì˜ ì™€ì¼ë“œì¹´ë“œ 문ìžë“¤ì´ 허용ë©ë‹ˆë‹¤) + IP (IPv4 ë˜ëŠ” IPv6): + diff --git a/app/src/main/res/values-ko/strings_log.xml b/app/src/main/res/values-ko/strings_log.xml new file mode 100644 index 0000000..1b78f75 --- /dev/null +++ b/app/src/main/res/values-ko/strings_log.xml @@ -0,0 +1,11 @@ + + + 로그 ê¸°ë¡ ì „í™˜ + 기ë¡ì„ 눌러 요청 로그를 시작하고, ì›¹ì„ íƒìƒ‰í•˜ê±°ë‚˜ ì•±ì„ ì‚¬ìš©í•œ ë‹¤ìŒ ë’¤ë¡œ ëŒì•„가거나 스와ì´í”„하여 로그를 새로 고칩니다. + \n\nì°¨ë‹¨ëœ ìš”ì²­ì€ ë¡œê·¸ë¥¼ 남기지 않습니다. ì´ê²ƒë“¤ë„ 로그를 남기고 싶다면 먼저 ê´‘ê³ ì°¨ë‹¨ì„ ë¹„í™œì„±í™”í•˜ì‹­ì‹œì˜¤. + + 알파벳순 ì •ë ¬ + 레벨순 ì •ë ¬ + + ë„ë©”ì¸ ë¦¬ë‹¤ì´ë ‰íЏ + diff --git a/app/src/main/res/values-ko/strings_notification.xml b/app/src/main/res/values-ko/strings_notification.xml new file mode 100644 index 0000000..c40ef66 --- /dev/null +++ b/app/src/main/res/values-ko/strings_notification.xml @@ -0,0 +1,13 @@ + + + + ì—…ë°ì´íЏ + 새 ì—…ë°ì´íЏ 알림 + ì—…ë°ì´íЏ 가능 + 다운로드 가능한 새 호스트 파ì¼ì´ 있습니다. + 앱 ì—…ë°ì´íЏ 사용가능 + AdAwayì˜ ìƒˆë¡œìš´ ë²„ì „ì„ ë‹¤ìš´ë¡œë“œí•  수 있습니다. + + VPN + VPN 실행 알림 + \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings_prefs_backup_restore.xml b/app/src/main/res/values-ko/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..823c082 --- /dev/null +++ b/app/src/main/res/values-ko/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + 백업 ë° ë³µì› + 백업 + 차단 ê·œì¹™ì„ ì™¸ë¶€ ì €ìž¥ì†Œì— ë°±ì—…í•©ë‹ˆë‹¤ + ë³µì› + ë°±ì—…ëœ ì°¨ë‹¨ ê·œì¹™ì„ ë³µì›í•©ë‹ˆë‹¤ + diff --git a/app/src/main/res/values-ko/strings_prefs_main.xml b/app/src/main/res/values-ko/strings_prefs_main.xml new file mode 100644 index 0000000..f2ecf66 --- /dev/null +++ b/app/src/main/res/values-ko/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + 환경 설정 + + ì¼ë°˜ + 테마 + + ë°ìŒ + ì–´ë‘움 + 시스템 기본값 + + ìžë™ ì—…ë°ì´íЏ + + ê´‘ê³  차단 + 루팅 기반 ê´‘ê³  차단 + VPN 기반 ê´‘ê³  차단 + IPv6 ì§€ì› ì ìš© + 차단 규칙 백업 / ë³µì›í•˜ê¸° + + 디버깅 + ì¶©ëŒ ë³´ê³ ì„œ 전송 + Sentry (sentry.io)ì— ë³´ê³  + ì´ ë¹Œë“œì—서는 ì§€ì›ë˜ì§€ 않습니다 + ìƒì„¸ 로그 + ì ìš©í•˜ë ¤ë©´ 앱 ìž¬ì‹œìž‘ì´ í•„ìš”í•©ë‹ˆë‹¤ + diff --git a/app/src/main/res/values-ko/strings_prefs_root.xml b/app/src/main/res/values-ko/strings_prefs_root.xml new file mode 100644 index 0000000..f0cf641 --- /dev/null +++ b/app/src/main/res/values-ko/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + 루팅 기반 ê´‘ê³  차단 + + 호스트 설치 + 호스트 íŒŒì¼ ì—´ê¸° + ëŒ€ìƒ í˜¸ìŠ¤íŠ¸ íŒŒì¼ + ì´ ê¸°ëŠ¥ì„ ì‚¬ìš©í•˜ê¸° ì „ì— ë„움ë§ì„ ì½ìœ¼ì‹­ì‹œì˜¤ + + /system/etc/hosts + /data/hosts + /data/data/hosts + ì‚¬ìš©ìž ì§€ì • ëŒ€ìƒ + + ì‚¬ìš©ìž ì§€ì • ëŒ€ìƒ ìœ„ì¹˜ + ì ìš© 후 재부팅 대화ìƒìž 숨기기 + + 리다ì´ë ‰íЏ + ì°¨ë‹¨ëœ í˜¸ìŠ¤íŠ¸ë¥¼ 리다ì´ë ‰íŠ¸í•  위치 ì •ì˜ + IPv4 리다ì´ë ‰íЏ + IPv6 리다ì´ë ‰íЏ + ìž˜ëª»ëœ ë¦¬ë‹¤ì´ë ‰ì…˜ + + 로컬 웹 서버 + 로컬 웹 서버는 차단 ëœ í˜¸ìŠ¤íŠ¸ ì´ë¦„ì„ ìš”ì²­ì— ì‘답하기 위해 로컬 IP 주소를 수신합니다. ì°¨ë‹¨ëœ ì—°ê²°ë¡œ 앱 í”„ë¦¬ì§•ì„ ë§‰ì„ ìˆ˜ 있습니다. + 웹 서버 활성화 + 시험 웹 서버 + ìžì²´ ì„œëª…ëœ ì¸ì¦ì„œ 설치 + ìˆ˜ë™ ì„¤ì¹˜ ì¸ì¦ + Android 11 (R)부터 애플리케ì´ì…˜ì€ ìžë™ìœ¼ë¡œ ì¸ì¦ 기관 (CA)를 설치할 수 없습니다.\n\n\"보안\" 설정으로 ì´ë™í•œ ë‹¤ìŒ \" 암호화 ë° ì‚¬ìš©ìž ì¸ì¦ ì •ë³´\"ì—서 \"ì¸ì¦ì„œ 설치\"를 해주세요. 그리고 \"CA ì¸ì¦ì„œ\"를 ì„ íƒí•œ ë‹¤ìŒ ìµœê·¼ì— ë‚´ë³´ë‚¸ ì¸ì¦ì„œ 파ì¼ì„ ì„ íƒí•´ 주세요. + \"보안\" 설정 열기 + í™•ì¸ ì¤‘â€¦ + ì‹¤í–‰ì¤‘ì´ ì•„ë‹˜ + 실행 중ì´ì§€ë§Œ ì¸ì¦ì„œê°€ 설치ë˜ì§€ ì•ŠìŒ + 실행 중ì´ë©° ì¸ì¦ì„œê°€ 설치ë˜ì–´ ìžˆìŒ + 빈 ê´‘ê³  ê³µê°„ì„ ì•± ì•„ì´ì½˜ìœ¼ë¡œ 대체하기 + diff --git a/app/src/main/res/values-ko/strings_prefs_update.xml b/app/src/main/res/values-ko/strings_prefs_update.xml new file mode 100644 index 0000000..5fa06ee --- /dev/null +++ b/app/src/main/res/values-ko/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + ì—…ë°ì´íЏ + + 앱 ì—…ë°ì´íЏ + 시작 시 ì—…ë°ì´íЏ í™•ì¸ + 주기ì ìœ¼ë¡œ ì—…ë°ì´íЏ í™•ì¸ + 베타 릴리즈 í¬í•¨ + + 호스트 ì—…ë°ì´íЏ + 시작 시 ì—…ë°ì´íЏ í™•ì¸ + 주기ì ìœ¼ë¡œ ì—…ë°ì´íЏ í™•ì¸ + ì—…ë°ì´íЏ 시 ë™ê¸°í™” + 무제한 ë„¤íŠ¸ì›Œí¬ í™˜ê²½ì—서만 ë™ê¸°í™” + diff --git a/app/src/main/res/values-ko/strings_prefs_vpn.xml b/app/src/main/res/values-ko/strings_prefs_vpn.xml new file mode 100644 index 0000000..1c2b6d6 --- /dev/null +++ b/app/src/main/res/values-ko/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN 기반 ê´‘ê³  차단 + + 앱 실행시 활성화 + ì—°ê²° ê°ì‹œ + 주기ì ìœ¼ë¡œ ë„¤íŠ¸ì›Œí¬ ìƒíƒœë¥¼ 확ì¸í•˜ì—¬ ì—°ê²° ëŠê¹€ì‹œ VPNì„ ìž¬ì‹œìž‘í•˜ê¸° + + 앱 제외하기 + VPNì„ ì‚¬ìš©í•˜ì§€ 않아야 하는 ì•±ì„ ì„¤ì •í•˜ì—¬ ì—°ê²°ì´ ì°¨ë‹¨ë˜ì§€ 않ë„ë¡ í•˜ì‹­ì‹œì˜¤. + 시스템 앱 제외하기 + + ì—†ìŒ + 모든 브ë¼ìš°ì € 제외 + ì „ë¶€ + + ì‚¬ìš©ìž ì•± 제외하기 + + + 앱 제외하기 + ëª¨ë‘ ì„ íƒ + ëª¨ë‘ ì„ íƒ í•´ì œ + 앱 ì•„ì´ì½˜ + diff --git a/app/src/main/res/values-ko/strings_support.xml b/app/src/main/res/values-ko/strings_support.xml new file mode 100644 index 0000000..75c6a5f --- /dev/null +++ b/app/src/main/res/values-ko/strings_support.xml @@ -0,0 +1,5 @@ + + + ì§€ì› + 스í°ì„œê°€ ë˜ê¸° + \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings_update.xml b/app/src/main/res/values-ko/strings_update.xml new file mode 100644 index 0000000..fa1514e --- /dev/null +++ b/app/src/main/res/values-ko/strings_update.xml @@ -0,0 +1,21 @@ + + + AdAway ì—…ë°ì´íЏ + + ì—…ë°ì´íЏ 가능! + + + 최신 버전입니다 + ì—…ë°ì´íЏ 가능 + AdAway를 ì—…ë°ì´íЏ 중 + 지금 ì—…ë°ì´íŠ¸í•˜ê¸° + %1$s / %2$s + 마지막 변경: + 변경사항: + ë„와준 사람들 + 기부 + í›„ì› + + + 최신 AdAway ë²„ì „ì„ ë‹¤ìš´ë¡œë“œ 중… + diff --git a/app/src/main/res/values-ko/strings_welcome.xml b/app/src/main/res/values-ko/strings_welcome.xml new file mode 100644 index 0000000..86842dc --- /dev/null +++ b/app/src/main/res/values-ko/strings_welcome.xml @@ -0,0 +1,52 @@ + + + 환ì˜í•©ë‹ˆë‹¤ + 마법사 첫번째 설정 + 마법사 ë‘번째 설정 + 마법사 마지막 설정 + + + AdAwayì— ì˜¤ì‹  걸 환ì˜í•©ë‹ˆë‹¤! + AdAway는 ë‘ ê°€ì§€ ê´‘ê³  ì°¨ë‹¨ì„ ì œê³µí•˜ê³  있습니다. ì›í•˜ì‹œëŠ” ê¸°ëŠ¥ì„ ì„ íƒí•´ 주십시오: + + Root logo + 루팅 기반\nê´‘ê³  차단 + 빠름 + 저전력 + ë£¨íŒ…ì´ í•„ìš”í•¨ + + VPN logo + VPN 기반\nê´‘ê³  차단 + ëŠë¦¼ + 백그ë¼ìš´ë“œ 실행 + 호환성 + + 루팅 필수 + su ë°”ì´ë„ˆë¦¬ë¥¼ ì°¾ì„ ìˆ˜ 없거나 AdAwayì— ëŒ€í•œ 루팅 ê¶Œí•œì„ í—ˆìš©í•˜ì§€ ì•Šì€ ê²½ìš°.\n\nì´ ë¬¸ì œëŠ” 장치가 루팅ë˜ì§€ ì•Šì€ ê²½ìš°ì— ë°œìƒí•  수 있습니다. wiki.lineageos.org ë˜ëŠ” 다른 안드로ì´ë“œ 웹 사ì´íЏì—서 장치를 루팅하는 ë°©ë²•ì— ëŒ€í•œ 정보를 ì°¾ì„ ìˆ˜ 있습니다. + + Pro + Con + + + ë™ê¸°í™” 완료 + ë™ê¸°í™” ë„중 오류 + + ë™ê¸°í™” 중 + ë™ê¸°í™” ë¨! + AdAway는 온ë¼ì¸ 소스로 부터 차단하기 위해 ê´‘ê³  네트워í¬ë¥¼ 다운로드합니다. ë‚˜ì¤‘ì— ì„¤ì •ì—서 수정할 수 있습니다. + ë™ê¸°í™” ìž¬ì‹œë„ + ë™ê¸°í™” 실패 ë¨: %1$s 재시ë„하시겠습니까? + + + ì§€ì› + ì§€ì›í•´ì£¼ì„¸ìš”! + ì´ ì•±ì€ ë¬´ë£Œì´ë©´ì„œ 오픈 소스입니다. 저는 여가 ì‹œê°„ì— ê°œë°œí•˜ê³  있습니다. 만약 만족하신다면, ì—¬ëŸ¬ë¶„ì˜ ì§€ì›ì„ ìžìœ ë¡­ê²Œ 보내주세요: + PayPal로 기부하기 + 버그 좋아하시나요? ì „ 싫어합니다. + ì¶©ëŒ ë³´ê³ ì„œë¥¼ 전송하려면, ì›ê²© ë¶„ì„ì„ í™œì„±í™” 해야합니다. + + + 뒤로 + ë‹¤ìŒ + 완료 + diff --git a/app/src/main/res/values-ku/strings.xml b/app/src/main/res/values-ku/strings.xml new file mode 100644 index 0000000..68d11cc --- /dev/null +++ b/app/src/main/res/values-ku/strings.xml @@ -0,0 +1,20 @@ + + + + دەرچوون + بە + نا + ھەڵوەشاندن + دەستکاری + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-ku/strings_app.xml b/app/src/main/res/values-ku/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-ku/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-ku/strings_errors.xml b/app/src/main/res/values-ku/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ku/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ku/strings_home.xml b/app/src/main/res/values-ku/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-ku/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-ku/strings_hosts.xml b/app/src/main/res/values-ku/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-ku/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-ku/strings_lists.xml b/app/src/main/res/values-ku/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-ku/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-ku/strings_log.xml b/app/src/main/res/values-ku/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-ku/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-ku/strings_notification.xml b/app/src/main/res/values-ku/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ku/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ku/strings_prefs_backup_restore.xml b/app/src/main/res/values-ku/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ku/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ku/strings_prefs_main.xml b/app/src/main/res/values-ku/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-ku/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-ku/strings_prefs_root.xml b/app/src/main/res/values-ku/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-ku/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-ku/strings_prefs_update.xml b/app/src/main/res/values-ku/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ku/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ku/strings_prefs_vpn.xml b/app/src/main/res/values-ku/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-ku/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-ku/strings_support.xml b/app/src/main/res/values-ku/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ku/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ku/strings_update.xml b/app/src/main/res/values-ku/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ku/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ku/strings_welcome.xml b/app/src/main/res/values-ku/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-ku/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml new file mode 100644 index 0000000..ba7e7b1 --- /dev/null +++ b/app/src/main/res/values-lt/strings.xml @@ -0,0 +1,266 @@ + + + + IÅ¡eiti + Uždaryti + Taip + Ne + PridÄ—ti + AtÅ¡aukti + IÅ¡saugoti + Pagalba + + + Sveiki! + AdAway yra nemokama ir atviro kodo programinÄ— įranga sukurta blokuoti reklamas. Å i programa filtruoja reklamų tinklo adresus jÅ«sų įrenginyje, taip jas blokuodama. Norite sužinoti daugiau? Patikrinkite pagalbÄ… apaÄioje! + Parodyti daugiau pagalbos + Atnaujinti bÅ«senÄ… + Visi hosts failai atsiųsti ir apjungti su įdiegtu hosts failu. + Ä®jungti reklamų blokavimÄ… + IÅ¡jungti reklamų blokavimÄ… + Web tinklo serveris + Veikia + Sustabdytas + PradÄ—ti arba sustabdyti tinklo web serverį jÅ«sų vietiniame įrenginyje kuris atsako į blokuotų domenų užklausas. + Ä®jungti web serverį + IÅ¡jungti tinklo web serverį + VPN + Ä®jungta + Sustabdyta + Pradeti arba sustabdyti VPN kad pradÄ—tų filtruoti užklausas. + Ä®jungti VPN + IÅ¡jungti VPN + + + Redeguoti Ä®rašą + Pritaikyti + Redeguoti + IÅ¡trinti + + + Importuoju… + AtsarginÄ— kopija sÄ—kmingai importuota iÅ¡ jÅ«sų iÅ¡orinÄ—s atminties. + Nepavyko importuoti atsarginÄ—s kopijos. Ar jos formatas teisingas? Patikrinkite logcat failÄ… dÄ—l iÅ¡samesnių detalių. + Eksportuojama… + AtsarginÄ— kopija sÄ—kmingai eksportuota į failÄ… \'%s\' jÅ«sų iÅ¡orinÄ—je saugykloje. + Nepavyko eksportuoti atsarginÄ—s kopijos failÄ…%s + + + Hosts failas + Hosts failas yra sistemos failas kuris pritaiko domenus prie IP adresų. Tai yra paprastas teksto failas kurio konfiguracijÄ… tvarko ir naudoja AdAway. ÄŒia yra jos pirmos eilutÄ—s: + Kraunama hosts failo duomenys… + Atverti hosts failÄ… + + + Tikrinama ar yra atnaujinimų + Tikrinama %s Å¡altinį dÄ—l atnaujinimo + Gaunama Å¡altinius + AtsisiunÄiama Å¡altinį %s + Skaitoma Å¡altinį %s + NagrinÄ—jamas %s Å¡altinis + Sinchronizuojamų taisyklių duomenų bazÄ— + Atstatomas originalus hosts failas + Originalus hosts failas atkurtas + Kuriu standartinį hosts failÄ… + Pasiekiamas atnaujinimas + Pasiekiamas naujesnis host failas + Å altinio atnaujinimų nerasta. + NÄ—ra interneto + NeprisijungÄ™s prie interneto + Å altiniai nepasiekiami + Nepasiekiami hosts Å¡altiniai! + Root priÄ—jimas atmestas + Leisti root prieigÄ… iÅ¡ jÅ«sų root programos + Kažkas nesutapo + Patikrinkite logcat failÄ… dÄ—l iÅ¡samesnių detalių + Ä®jungta + Naujausias host failas ijungtas + IÅ¡jungta + Originalus hosts failas instaliuotas + Pritaikyti naujausius Å¡altinius + Kuriamas naujas hosts failas + Kopijuojamas naujas hosts failas + Tikrinama hosts failo kopija + Hosts failas sÄ—kmingai atnaujintas + VPN konfigÅ«racija sÄ—kmingai atnaujinta + JÅ«sų konfiguracija iÅ¡saugota. Jums reikia jÄ… pritaikyti. + Pritaikyti + Pritaikoma nauja konfigÅ«racija… + Nepavyko pritaikyti naujos konfigÅ«racijos. + + + TrÅ«ksta symlink nuorodos į hosts failÄ… + Symlink nuoroda /system/etc/hosts neteisinga! AdAway neveiks jei neteisingai nurodytas kelias.\n\nPabandyti sukurti teisingÄ… symlink nuorodÄ…? + NÄ—ra symlink + Particijoje neužtenka vietos!\nPabandykite pakeisti pasirenkamÄ… hosts failÄ… nustatymuose /data/data/hosts. + Nepakanka vietos + Nepavyksta nuskaityti atsiųsto failo. + Asmeninio failo klaida + Nepavyko skirsnio padaryti įraÅ¡omu! + Permantavimo klaida + Nepavyko nukopijuoti hosts failo + Hosts file kopijavimas nepavyko! + Kopijavimas nepavyko + Pritaikyti hosts Å¡altiniai + Pritaikymas sÄ—kmingas + Pritaikymas sÄ—kmingas.\nlt gali bÅ«ti kad reikÄ—s perkrauti jÅ«sų Android įrenginį kad pritaikyti naujus pakeitimus.n\nAr jÅ«s norite perkauti įrenginį?\n(Kad neprarastumÄ—te duomenų įsitikinkite kad programa naudoja SD kortelÄ™ Å¡io momentu!) + Symlink nuorodos sukÅ«rimas sÄ—kmingas.\nGali bÅ«ti kad reikÄ—s perkrauti jÅ«sų Android įrenginį kad pritaikyti naujus pakeitimus.n\nAr jÅ«s norite perkauti įrenginį?\n(Kad neprarastumÄ—te duomenų įsitikinkite kad programa naudoja SD kortelÄ™ Å¡iuo momentu!) + Symlink sukurtas + Symlink nuoroda jÅ«sų įrenginyje negalÄ—jo bÅ«ti sukurta.\nTaip įvyksta dÄ—l \'funkcijos\' pavadinimu S-ON HTC telefonuose!\n\nA Sprendimas yra įjungti jÅ«sų įrenginį į atsarginių kopijų rėžimÄ… recovery mode ir sukurti nuorodÄ… symlink, ten, naudojant \'In -s /data/data/hosts /system/etc/hosts\'.\n\n Jei nesuveiks jums reikÄ—s internete surasti S-OFF jÅ«sų įrenginiui. + Nepavyko sukurti symlink + DetalesnÄ™ informacijÄ… rasite skiltyje Pagalba + APN proxy serveris yra įjungtas jÅ«sų įrenginyje!\nAdAway neveiks patikimai kai naujomi mobilieji tinklai kaip 3G. JÅ«s galite deaktyvuoti jÅ«sų proxy pasirenkant jÅ«sų pasirinktÄ… APN (Nustatymuose: Tinklas & Internetas -> Mobilusis tinklas -> SudÄ—tingiau -> Prieigų TaÅ¡kų Pavadinimai) ir iÅ¡trinti adresÄ… iÅ¡ proxy laukelio. + APN proxy nustatytas! + Prisijungti pire interneto nepavyko. + NÄ—ra Interneto + AtsisiunÄiama… + Pritaikoma… + Pritaikomas Juodasis ir Baltasis sÄ…raÅ¡as. + NagrinÄ—jamas ir suliejamas host faias + Tvarkomas host failas + Pritaikomas host failas + Nepavyko pritakyti naujam hosts failui. + Nepavyko pritaikyti hosts failo!\nPabandykite pakeisti paskirties vietÄ… nustatymuose į /data/data/hosts. + Pritaikymas nepavyko + PraÅ¡ome patikrinti jÅ«sų root prieigos tvarkymo programÄ—lÄ™, įsitikinkite kad leista root prieiga. + JÅ«s atstatÄ—te originalų hosts failÄ….\nlt gali bÅ«ti kad reikÄ—s perkrauti jÅ«sų Android įrenginį kad pritaikyti naujus pakeitimus.n\nAr jÅ«s norite perkauti įrenginį?\n(Kad nesukurti duomenų praradimo įsitikinkite kad programa naudoja SD kortelÄ™ Å¡io momentu!) + AtkÅ«rimas sÄ—kmingas + Hosts failo atstatymas negalimas + Nepavyko atstatyti dÄ—l nežinomų priežasÄių. + AtkÅ«rimas nepavyko! + Nepasiekiamas nei vienas iÅ¡ pasirinktų hosts Å¡altinių! Ar tikrai prisijungÄ—te prie interneto? + Atsisiuntimas nepavyko + NÄ—ra prieigos koreguoti naujo privataus hosts failo + Nepavyko sukurti asmeninio failo. + Nepavyko sukurti asmeninio failo + JÅ«s įjungÄ—te ne sisteminį rėžimÄ….\nGali bÅ«ti kad reikÄ—s perkrauti jÅ«sų Android įrenginį kad pritaikyti naujus pakeitimus.n\nAr jÅ«s norite perkauti įrenginį?\n(Kad neprarastumÄ—te duomenų įsitikinkite kad programa naudoja SD kortelÄ™ Å¡iuo momentu!) + Pavyko įjungti + JÅ«s iÅ¡jungÄ—te ne sisteminį rėžimÄ….\nGali bÅ«ti kad reikÄ—s perkrauti jÅ«sų Android įrenginį kad pritaikyti naujus pakeitimus.n\nAr jÅ«s norite perkauti įrenginį?\n(Kad neprarastumÄ—te duomenų įsitikinkite kad programa naudoja SD kortelÄ™ Å¡iuo momentu!) + Pavyko iÅ¡jungti + Nepavyko įjungti VPN reklamų blokavimo. + Nepavyko iÅ¡jungti VPN reklamų blokavimo. + Ä®jungiamas hosts Magisk modulis + Ä®jungkite ne sisteminÄ™ hosts funkcijÄ… iÅ¡ Magisk tvarkytuvo. Jo nustatymuose įjungkite Ne sisteminiai hosts Å¡altiniai funkcijÄ… ir perkraukite jÅ«sų įrenginį. + IÅ¡jungiamas hosts Magisk modulis + IÅ¡jungti ne sisteminių Å¡altinių hosts Å¡altinių funkcijÄ… Magisk tvarkytuve. IÅ¡ modulių saraÅ¡o, iÅ¡trinkite Ne sisteminiai hosts Å¡altiniai modulį ir perkraukite jÅ«sų įrenginį. + + + Ä®terpti URL į hosts failÄ…: + Neteisingas host vardas! + Neteisingas host vardo formatas + Neteisingas IP + Neteisingas IP formatas + Niekada neperkrauti ir neberodyti Å¡io klausimo! + Kraunama… + + + Atnaujinti + PridÄ—ti + Pagalba + Imporuoti atsarginÄ™ kopijÄ… + Eksportuoti atsarginÄ™ kopijÄ… + + + S-ON/S-OFF + DUK + Problemos + + + Adware Reklamų virusas + ÄŒia jÅ«s galite rasti blogas programas kurios negali bÅ«ti užblokuotos AdAway programoje. Å ios programos naudoja Airpush pranÄ—Å¡imus, kurie iššoka net jei ir programa iÅ¡jungta, gali net pakeisti skambuÄio tonÄ…. Vienintelis bÅ«das to iÅ¡vengti - IÅ¡trinti Å¡ias programas paspaudžiant ant programų saraÅ¡o. + Skanuojama… + Nerasta Adware Reklamų virusų. + + + Reklamos blokavimas + Neradau teksto redagavimo programos + Neturite jokios teksto redagavimo programos, su kuria galÄ—tume atidaryti host failÄ….\n\nÄ®diegti Jota? + NÄ—ra failų tvarkyklÄ—s + Neturite failų tvarkymo programos, su kuria galÄ—tume atidaryti failus. Galite įdiegti OI Failų TvarkyklÄ™\n\nÄ®diegti Dabar? + + + Tcpdump + Tcpdump tai įrankis DNS užklausų stebÄ—jimui ir iįsaugoimui log faile. Galite paleisti fone, įjungti programÄ…, kuri rodo reklamÄ… ir po to analizuoti DNS užklausas log faile. Reklamos serverį galÄ—site pridÄ—ti į juodÄ…jį sÄ…rašą. + IÅ¡jungti sekimÄ… + įjungti sekimÄ… + Parodyti rezultatus + RÅ«siuoti domenus + IÅ¡valyti surinktÄ… informacijÄ… + Ä®dÄ—ti įėjima į juodÄ… sÄ…rašą + Ä®dÄ—ti įėjimÄ… į baltajį sÄ…rašą + Ä®dÄ—ti įėjima į nukreipimo sÄ…rašą + + Redaguoti teksto pasirinkimo vertÄ™ + Atverti meniu + Uždaryti meniu + + + + Namai + Hosts Å¡altiniai + JÅ«sų saraÅ¡ai + Atverti hosts failÄ… + Rinkti DNS užklausas + Skanuoti dÄ—l reklamų virusų + Nustatymai + Pagalba + + + + + DNS užklausos + JÅ«sų saraÅ¡ai + Nustatymai + + + Instaliuotos nuo %1$s + GaliojanÄios iki %1$s + Reikia atnaujinimo dÄ—l %1$s + Paskutinis atnaujinimas %1$s + Nežinomas atnaujinimo statusas + kelios minutÄ—s + + %d minutÄ— + %d minutÄ—s + %d minutÄ—s + %d minutÄ—s + + + %d valanda + %d valandos + %d valandos + %d valandos + + + %d diena + %d dienos + %d dienos + %d dienos + + + %d mÄ—nesis + %d mÄ—nesiai + %d mÄ—nesiai + %d mÄ—nesiai + + + + Pradedama + aktyvus + stabdoma + laukiama tinklo + prisijungiama iÅ¡ naujo + prisijungimo klaida + pauzÄ— + sustabdyta + Reklamų-blokavimo VPN %1$s + PauzÄ— + TÄ™sti + + + AdAway leidimai + Leisti bendrauti su AdAway + Siųsti komandas AdAway + Leisti siųsti komandas AdAway, pvz., Ä®jungti arba iÅ¡jungti sistemos reklamų blokavimÄ… + + diff --git a/app/src/main/res/values-lt/strings_app.xml b/app/src/main/res/values-lt/strings_app.xml new file mode 100644 index 0000000..848d561 --- /dev/null +++ b/app/src/main/res/values-lt/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Atviro Kodo reklamų blokatorius + AdAway logotipas + diff --git a/app/src/main/res/values-lt/strings_errors.xml b/app/src/main/res/values-lt/strings_errors.xml new file mode 100644 index 0000000..bae60a3 --- /dev/null +++ b/app/src/main/res/values-lt/strings_errors.xml @@ -0,0 +1,22 @@ + + + + NÄ—ra interneto + Negalimas sujingimas internetu. PraÅ¡ome patkikrinti įrenginio sujungimÄ…. + Nepavyko atsisiųsti hosts failo + Nei vienas jÅ«sų įjungtas domeno Å¡altinis yra pasiekiamas. PraÅ¡ome patikrinti ar esate gerai prisijungÄ™ prie interneto. + + Nepavyko sukurti privataus failo + Nepavyko sukurti privataus failo kad sukurti naujo domeno Å¡altinio. PraÅ¡ome patikrintai ar yra laisvos vietos jÅ«sų įrenginyje. + Nepakanka vietos + Nepavyko nukopijuoti domeno failo į jÅ«sų sistemos particijos skirsnį. PraÅ¡ome patikrinti ar Magisk ne sisteminis modulis įjungtas, tada perkraukite įrenginį + Nepavyko instaliuoti naujo hosts domeno failo. + Nepavyko nukopijuoti domeno failo į jÅ«sų /system particijos skirsnį. PraÅ¡ome patikrinti ar Magisk ne sisteminis modulis įjungtas, tada perkraukite įrenginį. + Nepavyko atkurti praÄ—jusio hosts domeno failo + Nepavyko atkrurti originalaus hosts domeno failo konfiguracijos + + Nepavyko įjungti VPN reklamų blokavimo. + PraÅ¡ome patikrinti jÅ«sų VPN nustatymus kurie atsakingi už aplikacijos VPN paleidimÄ…. + Nepavyko iÅ¡jungti VPN reklamų blokavimo. + PraÅ¡ome patikrinti jÅ«sų VPN nustatymus kad juos iÅ¡jungti rankiniu bÅ«du. + diff --git a/app/src/main/res/values-lt/strings_home.xml b/app/src/main/res/values-lt/strings_home.xml new file mode 100644 index 0000000..95f2aca --- /dev/null +++ b/app/src/main/res/values-lt/strings_home.xml @@ -0,0 +1,44 @@ + + + + + Užblokuotos + Leistos + Nukreiptos + + + + %d galiojantis kodas + %d galiojantys kodai + %d galiojantys kodai + %d galiojantys kodai + + + %d nebegaliojantis kodas + %d nebeagliojantys kodai + %d nebeagliojantys kodai + %d nebeagliojantys kodai + + + + Rodyti pagalbÄ… + + + Atverti GitHub svetainÄ™ + + + Palaikyti projektÄ… + + + Nustatymai + + + Atverti navigacijos stalÄių + Stabdyti/tÄ™sti reklamų blokavimÄ… + Atnaujinti užblokuotus domenus + Rodyti užklaustus domenus + + + DetalesnÄ™ informacijÄ… rasite skiltyje Pagalba + + diff --git a/app/src/main/res/values-lt/strings_hosts.xml b/app/src/main/res/values-lt/strings_hosts.xml new file mode 100644 index 0000000..cb2a9bf --- /dev/null +++ b/app/src/main/res/values-lt/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Host domenų Å¡altiniai + + Vartotojų sÄ…raÅ¡as + AdAway oficialÅ«s domenai + StevenBlack Unified sujungti domenai + Pete Lowe blokavimo domenai + + nepasiekiama + %s hosts domenų sÄ…raÅ¡ai + + Ä®dÄ—ti Å¡altinį + Redaguoti Å¡altinį + URL: (https:// arba file:// iÅ¡teklius) + Domeno iÅ¡teklio URL + diff --git a/app/src/main/res/values-lt/strings_lists.xml b/app/src/main/res/values-lt/strings_lists.xml new file mode 100644 index 0000000..9283877 --- /dev/null +++ b/app/src/main/res/values-lt/strings_lists.xml @@ -0,0 +1,23 @@ + + + Your lists + + Užblokuotos + Leistos + Nukreiptos + + Filtruoti domenenai hosts + IeÅ¡koti domeno… + Pakeisti Å¡altinius + + Ä®traukti į juodÄ… sÄ…rašą + Ä®traukti į baltÄ… sÄ…rašą + Ä®dÄ—ti domeno nukreipimÄ… + Redaguoti juodai pažymÄ—tÄ… domenÄ… + Redaguoti baltai pažymÄ—tÄ… domenÄ… + Redaguoti nukreipimÄ… + Host domeno vardas: + Domeno iÅ¡teklio URL + (Charakteriai * ir ? leidžiami) + IP (IPv4 ar IPv6): + diff --git a/app/src/main/res/values-lt/strings_log.xml b/app/src/main/res/values-lt/strings_log.xml new file mode 100644 index 0000000..15008e6 --- /dev/null +++ b/app/src/main/res/values-lt/strings_log.xml @@ -0,0 +1,8 @@ + + + + Alfabetinis rūšiavimas + VirÅ¡utinio lygio domeno rūšiavimas + + Nukreipti domenÄ… + diff --git a/app/src/main/res/values-lt/strings_notification.xml b/app/src/main/res/values-lt/strings_notification.xml new file mode 100644 index 0000000..38120ba --- /dev/null +++ b/app/src/main/res/values-lt/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Atnaujinimai + Naujų atnaujinimų praneÅ¡imai + Å altinio atnaujinimas galimas + Naujesni domeno failai su galimybe atsisiÅ«sti + Programos ataujinimas galimas + Nauja AdAway versija yra galima atsisiuntimui. + + VPN + VPN paleisti praneÅ¡imai + \ No newline at end of file diff --git a/app/src/main/res/values-lt/strings_prefs_backup_restore.xml b/app/src/main/res/values-lt/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..5209ae4 --- /dev/null +++ b/app/src/main/res/values-lt/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Padaryti atsarginÄ™ kopijÄ…; atkurti + AtsarginÄ— kopija + Sukurti atsarginÄ™ kopijÄ… į blokavimo taisyklių į iÅ¡orinÄ™ duomenų laikmenÄ… + Atkurti + Atkrurti jÅ«sų blokavimo taisykles iÅ¡ atsarginÄ—s kopijos + diff --git a/app/src/main/res/values-lt/strings_prefs_main.xml b/app/src/main/res/values-lt/strings_prefs_main.xml new file mode 100644 index 0000000..a9a8253 --- /dev/null +++ b/app/src/main/res/values-lt/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Nustatymai + + Bendri + Tamsi tema + + Å viesi + Tamsi + Sistemos pasirinkta + + Automatiniai naujinimai + + Reklamų blokavimas + Root pagrįstas\nad blokavimas + VPN pagrįstas reklamų blokavimas + Ä®jungti IPv6 + Padaryti atsarginÄ™ kopijÄ… / atkurti blokavimo taisykles + + Derinti + SiÅ«sti klaidų įraÅ¡us + Pateikti sargybai (sentry.io) + Nepalaikoma Å¡ios programos versijoje + Platus įrašų saugojimas + Reikia paleisti iÅ¡ naujo AdAway, kad veiktų nustatymai. + diff --git a/app/src/main/res/values-lt/strings_prefs_root.xml b/app/src/main/res/values-lt/strings_prefs_root.xml new file mode 100644 index 0000000..c54ffea --- /dev/null +++ b/app/src/main/res/values-lt/strings_prefs_root.xml @@ -0,0 +1,36 @@ + + + Root pagrįstas\nad blokavimas + + Domeno instaliacija + Atidaryti host faila + Nukreipti host failÄ… + PrieÅ¡ keiÄiant šį nustatymÄ…, perskaitykite PagalbÄ… apie funkcionalumÄ…. + + /system/etc/hosts + /data/hosts + /data/data/hosts + Pasirinktinis nukreipimas + + Pasirinktinis nukreipimas + Slepti perkrovimo užklausÄ… + + Nukreipimas + Pasirinkti kur nukreipti užblokuotus hosts domenus + IPv4 nukreipimas + IPv6 nukreipimas + + Vietinis serveris + Lokalus web serveris klauso lokalių IP adresų ir blokuoja domenų adresų užklausas. Tai gali padÄ—ti su programos strigimu su blokuotu sujungimu. + Ä®jungti web serverį + Testuoti web serverį + Instaliuoti savo pažymÄ—tus sertifikatus + Sertifikato instrukcijos instaliavimas + Pradedant nuo Android 11 (R), programa nebegali automatiÅ¡kai instaliuoti autorizacijos sertifikato (CA).n\n\ Eikite į \"Saugos\" nustatymus, \"Å ifravimas ir Identifikacija\" tada \"Instaliuoti serfifikatÄ…\". Nuo ten, pasirinkti \"CA sertifikatas\" ir naujai eksportuotÄ… sertifikato failÄ…. + Atverty \"Saugos\" nustatymus + Tikrinama… + Neveikia + Veikia bet serfikatas neįdiegtas + Veikia, serifikatas instaliuotas + Pakeisti tuÅ¡Äios reklamos vietÄ… su programÄ—les ikona + diff --git a/app/src/main/res/values-lt/strings_prefs_update.xml b/app/src/main/res/values-lt/strings_prefs_update.xml new file mode 100644 index 0000000..a6820f5 --- /dev/null +++ b/app/src/main/res/values-lt/strings_prefs_update.xml @@ -0,0 +1,12 @@ + + + Atnaujinimai + + Programos atnaujinimai + PeriodiÅ¡kai ieÅ¡koti atnaujinimų + + Domeno hosts atnaujinimai + PeriodiÅ¡kai ieÅ¡koti atnaujinimų + Sinchronizuoti atnaujinimo metu + Sinchronizuoti tik neribotu tinklu + diff --git a/app/src/main/res/values-lt/strings_prefs_vpn.xml b/app/src/main/res/values-lt/strings_prefs_vpn.xml new file mode 100644 index 0000000..a86680c --- /dev/null +++ b/app/src/main/res/values-lt/strings_prefs_vpn.xml @@ -0,0 +1,22 @@ + + + VPN pagrįstas reklamų blokavimas + + Ä®jungti įjungimo metu + + IÅ¡skirtos aplikacijos + SukonfigÅ«ruoti kurios aplikacijos nenaudos VPN kad sujungimai nebÅ«tų blokuojami. + IÅ¡skirti sistemos aplikacijos + + Nei viena + Visos iÅ¡skyrus narÅ¡ykles + Visos + + IÅ¡skirti vartotojo aplikacijas + + + IÅ¡skirtos programos + Pasirinkti visas + Nebepasirinkti visų + Programos ikona + diff --git a/app/src/main/res/values-lt/strings_support.xml b/app/src/main/res/values-lt/strings_support.xml new file mode 100644 index 0000000..78eaff1 --- /dev/null +++ b/app/src/main/res/values-lt/strings_support.xml @@ -0,0 +1,5 @@ + + + Palaikymas + Tapkite sponsoriumi + \ No newline at end of file diff --git a/app/src/main/res/values-lt/strings_update.xml b/app/src/main/res/values-lt/strings_update.xml new file mode 100644 index 0000000..e2f0ec4 --- /dev/null +++ b/app/src/main/res/values-lt/strings_update.xml @@ -0,0 +1,18 @@ + + + AdAway atnaujinimas + + Atnaujinimas galimas! + + + JÅ«s turite naujausiÄ… versijÄ… + Galimas atnaujinimas + Atnaujiname AdAway + Atnaujinti dabar + %1$s / %2$s + Paskutiniai pakeitimai: + Pakeitimų įraÅ¡ai: + + + AtsisunÄiame naujausiÄ… AdAway versiją… + diff --git a/app/src/main/res/values-lt/strings_welcome.xml b/app/src/main/res/values-lt/strings_welcome.xml new file mode 100644 index 0000000..0933baa --- /dev/null +++ b/app/src/main/res/values-lt/strings_welcome.xml @@ -0,0 +1,52 @@ + + + Sveiki + Pirmas žingsnis + Antras žingsnis + Paskutinis žingsnis + + + Sveiki, Äia AdAway! + AdAway teikia du reklamų blokavimo metodus. Pasirinkite norimÄ…: + + Root logotipas + Root pagrįstas\nad blokavimas + Greitesnis + DraugiÅ¡kas baterijai + Root privalomas + + VPN logotipas + VPN pagrįstas\nad blokavimas + LÄ—tesnis + Veikti fone + Suderinamumas + + Root Android prieiga bÅ«tina! + Arba su binary nerasta arba jÅ«s neleidote root leidimo AdAway.\n\nTai gali atsitikti kai jÅ«sų įrenginys neturi root prieigos. Galite rasti daugiau informacijos kaip gauti root prieigÄ… wiki.lineageos.org ar kituose Android puslapiuose + + Pro + Negatyvai + + + Sinchronizavimas baigtas + Klaidos sinchronizavimo metu + + Sinchronizavimas + Susinchronizuota! + AdAway atsiunÄia reklamų adresus kad juos užblokuotų iÅ¡ tinklo. JÅ«s galite juos pasirinkti veliau nustatymuose. + Bandyti sinchronizuoti iÅ¡ naujo + Sinchronizacija nepavyko %1$s Bandyti iÅ¡ naujo? + + + Palaikymas + Palaikyk mane! + Tai yra nemokama atviro kodo programa. AÅ¡ jÄ… sukÅ«riau mano laisvu laiku. Jeigu jums ji patinka, galite mane palaikyti: + Donuoti per PayPal + Ar jums patinka klaidos? Man irgi ne. + Ä®jungti telemetijÄ… kad man atsiÅ«stu užstrigusios programos įraÅ¡us + + + Atgal + Kitas + Pabaiga + diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml new file mode 100644 index 0000000..c069e4d --- /dev/null +++ b/app/src/main/res/values-ml/strings.xml @@ -0,0 +1,196 @@ + + + + à´ªàµà´±à´¤àµà´¤àµ‡à´•ൠഉളàµà´³ വഴി + അവസാനിപàµà´ªà´¿à´•àµà´•àµà´• + ആണൠ+ à´…à´²àµà´² + ചേർകàµà´•àµà´• + ഉപേകàµà´·à´¿à´•àµà´•àµà´• + സൂകàµà´·à´¿à´•àµà´•àµà´• + സഹായം + + + à´¸àµà´µà´¾à´—തം + പരസàµà´¯à´‚ചെയàµà´¯àµ½ തടയàµà´¨àµà´¨à´¤à´¿à´¨àµà´³àµà´³ ഒരൠസൗജനàµà´¯ ,à´“à´ªàµà´ªàµº സോഴàµâ€Œà´¸àµ സോഫàµà´±àµà´±àµà´µàµ†à´¯àµ¼ ഡിസൈനാണൠAdAway.നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿àµ½ പരസàµà´¯à´™àµà´™àµ¾ തടയàµà´¨àµà´¨à´¤à´¿à´¨àµ ഇതൠപരസàµà´¯ നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•ൠവിലാസങàµà´™àµ¾ നേടàµà´¨àµà´¨àµ.കൂടàµà´¤àµ½ അറിയണോ?à´šàµà´µà´Ÿàµ†à´¯àµà´³àµà´³ സഹായം പരിശോധികàµà´•àµà´•! + കൂടàµà´¤àµ½ സഹായം കാണികàµà´•àµà´• + നില മെചàµà´šà´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´• + നിർവചികàµà´•à´ªàµà´ªàµ†à´Ÿàµà´Ÿ ഉറവിടങàµà´™à´³à´¿àµ½ നിനàµà´¨àµà´³àµà´³ à´Žà´²àµà´²à´¾ ഹോസàµà´±àµà´±àµ ഫയലàµà´•à´³àµà´‚ ഡൗൺലോഡàµâ€Œ ചെയàµâ€Œà´¤àµ,നിങàµà´™à´³àµà´Ÿàµ† à´¸àµà´µà´¨àµà´¤à´‚ ലിസàµà´±àµà´±àµà´•à´³àµà´®à´¾à´¯à´¿ ലയിപàµà´ªà´¿à´šàµà´šàµ നിങàµà´™à´³àµà´Ÿàµ† സിസàµà´±àµà´±à´¤àµà´¤à´¿àµ½ ഒരൠഹോസàµà´±àµà´±àµ ഫയലായി ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¤àµ + പരസàµà´¯-തടയൽ à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•àµà´• + പരസàµà´¯-തടയൽ à´…à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•àµà´• + വെബൠസെർവർ + à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´¨àµà´¨àµ + നിർതàµà´¤à´²à´¾à´•àµà´•à´ªàµà´ªàµ†à´Ÿàµà´Ÿàµ + വെബൠസെർവർ à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•àµà´• + വെബൠസെർവർ à´…à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•àµà´• + + ചേർതàµà´¤à´¤àµ തിരàµà´¤àµà´¤àµà´• + à´ªàµà´°à´¯àµ‹à´—à´¿à´•àµà´•àµà´• + തിരàµà´¤àµà´¤àµà´• + നീകàµà´•à´‚ ചെയàµà´¯àµà´• + + + ഇറകàµà´•àµà´®à´¤à´¿ ചെയàµà´¯àµà´¨àµà´¨àµâ€¦ + നിങàµà´™à´³àµà´Ÿàµ† ബാഹàµà´¯ സംഭരണതàµà´¤à´¿àµ½ നിനàµà´¨àµ ബാകàµà´•à´ªàµà´ªàµ വിജയകരമായി ഇറകàµà´•àµà´®à´¤à´¿ ചെയàµà´¤àµ. + ബാകàµà´•à´ªàµà´ªàµ ഇറകàµà´•àµà´®à´¤à´¿ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ.അതിനàµà´±àµ† ഫോർമാറàµà´±àµ ശരിയാണോ?കൂടàµà´¤àµ½ വിവരങàµà´™àµ¾à´•àµà´•ൠലോഗàµà´•ാറàµà´±àµ പരിശോധികàµà´•àµà´•. + കയറàµà´±àµà´®à´¤à´¿ ചെയàµà´¯àµà´¨àµà´¨àµ + + ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഫയൽ + ഹോസàµà´±àµà´±àµà´¨à´¾à´®à´™àµà´™àµ¾ IP വിലാസങàµà´™à´³à´¿à´²àµ‡à´•àµà´•ൠമാപàµà´ªàµ ചെയàµà´¯àµà´¨àµà´¨ ഒരൠസിസàµà´±àµà´±à´‚ ഫയലാണൠഹോസàµà´±àµà´±àµà´¸àµ ഫയൽ.AdAway കോൺഫിഗറേഷൻ കൈകാരàµà´¯à´‚ ചെയàµà´¯àµà´¨àµà´¨ ഒരൠപàµà´²àµ†à´¯à´¿àµ» ടെകàµà´¸àµà´±àµà´±àµ ഫയലാണിതàµ.അതിനàµà´±àµ† ആദàµà´¯ വരികൾ ഇതാ: + ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഫയൽ ഉളàµà´³à´Ÿà´•àµà´•à´‚ ലോഡàµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨àµâ€¦ + ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഫയൽ à´¤àµà´±à´•àµà´•àµà´• + + à´¸àµà´±àµà´±à´¾àµ»à´¡àµ‡àµ¼à´¡àµ ഹോസàµà´±àµà´±àµ ഫയൽ സൃഷàµà´Ÿà´¿à´•àµà´•àµà´¨àµà´¨àµ + നവീകരണം ലഭàµà´¯à´®à´¾à´£àµ + à´ªàµà´¤à´¿à´¯ ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഫയലàµà´•ൾ ലഭàµà´¯à´®à´¾à´£àµ + ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ കണകàµà´·à´¨à´¿à´²àµà´² + ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ കണകàµà´·à´¨àµŠà´¨àµà´¨àµà´‚ ലഭàµà´¯à´®à´²àµà´² + ലഭàµà´¯à´®à´²àµà´²à´¾à´¤àµà´¤ ഉറവിടങàµà´™àµ¾ + ഹോസàµà´±àµà´±àµ ഉറവിടങàµà´™à´³àµŠà´¨àµà´¨àµà´‚ à´Žà´¤àµà´¤à´¿à´šàµà´šàµ‡à´°à´¾à´¨à´¾à´µà´¿à´²àµà´² ! + റൂടàµà´Ÿàµ ആകàµâ€Œà´¸à´¸àµà´¸àµ നിരസിചàµà´šàµ + നിങàµà´™à´³àµà´Ÿàµ† റൂടàµà´Ÿàµ à´…à´ªàµà´²à´¿à´•àµà´•േഷനിൽ നിനàµà´¨àµ റൂടàµà´Ÿàµ ആകàµâ€Œà´¸à´¸àµà´¸àµ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´• + à´Žà´¨àµà´¤àµ‹ à´•àµà´´à´ªàµà´ªà´‚ സംഭവിചàµà´šàµ + കൂടàµà´¤àµ½ വിവരങàµà´™àµ¾à´•àµà´•ൠലോഗàµà´•ാറàµà´±àµ പരിശോധികàµà´•àµà´• + à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´®à´¾à´•àµà´•à´¿ + à´à´±àµà´±à´µàµà´‚ à´ªàµà´¤à´¿à´¯ ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഫയലàµà´•ൾ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´®à´¾à´•àµà´•à´¿ + à´…à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•à´¿ + à´¸àµà´¥à´¿à´°à´¸àµà´¥à´¿à´¤à´¿ ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഫയൽ ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¤àµ + à´ªàµà´°à´¯àµ‹à´—à´¿à´•àµà´•àµà´• + നിങàµà´™à´³àµà´Ÿàµ† ടാർഗെറàµà´±à´¿àµ½ നിനàµà´¨àµ / സിസàµà´±àµà´±à´‚ / etc / ഹോസàµà´±àµà´±àµà´•ളിലേകàµà´•àµà´³àµà´³ സിംലിങàµà´•ൠനിലവിലിലàµà´² à´…à´²àµà´²àµ†à´™àµà´•ിൽ തെറàµà´±à´¾à´£àµ ! ശരിയായ ഫയലിലേകàµà´•ൠപോയിനàµà´±àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨à´¿à´²àµà´²àµ†à´™àµà´•ിൽ AdAway à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•à´¿à´²àµà´².\n\nഒരൠസിംലിങàµà´•ൠസൃഷàµà´Ÿà´¿à´•àµà´•ാൻ à´¶àµà´°à´®à´¿à´•àµà´•ണോ? + സിംലിങàµà´•ൠകാണàµà´¨àµà´¨à´¿à´²àµà´² + പാർടàµà´Ÿàµ€à´·à´¨à´¿àµ½ മതിയായ ഇടമിലàµà´².\nടാർ‌ഗെറàµà´±àµ ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഫയൽ‌ / data / data / hosts നൠമàµàµ»à´—ണന മാറàµà´±à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´•. + മതിയായ à´¸àµà´¥à´²à´®à´¿à´²àµà´² + ഡൗൺലോഡàµà´šàµ†à´¯àµâ€Œà´¤ ഫയൽ വായികàµà´•ാൻ à´•à´´à´¿à´žàµà´žà´¿à´²àµà´². + à´¸àµà´µà´•ാരàµà´¯ ഫയൽ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ + പാർടàµà´Ÿàµ€à´·àµ» read / write ആയി റീമൗണàµà´Ÿàµ ചെയàµà´¯àµà´¨àµà´¨à´¤àµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ + റീമൗണàµà´Ÿàµ പരാജയപെടàµà´Ÿàµ + ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഫയൽ പകർതàµà´¤àµà´¨àµà´¨à´¤àµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ + പകർപàµà´ªàµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ + à´ªàµà´°à´¯àµ‹à´—à´¿à´šàµà´š ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഉറവിടങàµà´™àµ¾ + à´ªàµà´°à´¯àµ‹à´—à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ വിജയകരമാണൠ+ à´ªàµà´°à´¯àµ‹à´—à´¿à´šàµà´šà´¿à´°àµà´¨àµà´¨à´¤àµ വിജയകരമായിരàµà´¨àµà´¨àµ.\nമാറàµà´±à´™àµà´™àµ¾ à´ªàµà´°à´¾à´¬à´²àµà´¯à´¤àµà´¤à´¿àµ½ വരാൻ ആൻഡàµà´°àµ‹à´¯à´¿à´¡àµ റീബൂടàµà´Ÿàµ ചെയàµà´¯àµ‡à´£àµà´Ÿà´¤àµ ആവശàµà´¯à´®à´¾à´¯à´¿ വനàµà´¨àµ‡à´•àµà´•ാം.\n\nനിങàµà´™àµ¾à´•àµà´•ൠറീബൂടàµà´Ÿàµ ചെയàµà´¯à´£àµ‹?(ഡാറàµà´± നഷàµâ€Œà´Ÿà´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨à´¤àµ തടയാൻ ഇപàµà´ªàµ‹àµ¾ ഒരൠഅപàµà´²à´¿à´•àµà´•േഷനàµà´‚ à´Žà´¸àµà´¡à´¿. കാർഡൠഉപയോഗികàµà´•àµà´¨àµà´¨à´¿à´²àµà´²àµ†à´¨àµà´¨àµ ഉറപàµà´ªà´¾à´•àµà´•àµà´•!) + സിം‌ലിങàµà´•ൠവിജയകരമായി സൃഷàµâ€Œà´Ÿà´¿à´šàµà´šàµ.\nമാറàµà´±à´™àµà´™àµ¾ à´ªàµà´°à´¾à´¬à´²àµà´¯à´¤àµà´¤à´¿àµ½ വരാൻ ആൻഡàµà´°àµ‹à´¯à´¿à´¡àµ റീബൂടàµà´Ÿàµ ചെയàµà´¯àµ‡à´£àµà´Ÿà´¤àµ ആവശàµà´¯à´®à´¾à´¯à´¿ വനàµà´¨àµ‡à´•àµà´•ാം.\n\nനിങàµà´™àµ¾à´•àµà´•ൠറീബൂടàµà´Ÿàµ ചെയàµà´¯à´£àµ‹?(ഡാറàµà´± നഷàµâ€Œà´Ÿà´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨à´¤àµ തടയാൻ ഇപàµà´ªàµ‹àµ¾ ഒരൠഅപàµà´²à´¿à´•àµà´•േഷനàµà´‚ à´Žà´¸àµà´¡à´¿. കാർഡൠഉപയോഗികàµà´•àµà´¨àµà´¨à´¿à´²àµà´²àµ†à´¨àµà´¨àµ ഉറപàµà´ªà´¾à´•àµà´•àµà´•!) + സിംലിങàµà´•ൠസൃഷàµà´Ÿà´¿à´•àµà´•ൽ വിജയിചàµà´šàµ + ആൻഡàµà´°àµ‹à´¯àµâ€Œà´¡à´¿à´¨àµ സിംലിങàµà´•ൠസൃഷàµà´Ÿà´¿à´•àµà´•ാൻ à´•à´´à´¿à´žàµà´žà´¿à´²àµà´².à´Žà´šàµà´šàµà´Ÿà´¿à´¸à´¿ ഫോണàµà´•ളിലെ à´Žà´¸àµ-ഓൺ à´Žà´¨àµà´¨ സവിശേഷത കാരണം ഇതൠപരാജയപàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ!.നിങàµà´™à´³àµà´Ÿàµ† ഫോൺ റികàµà´•വറി മോഡിലേകàµà´•ൠബൂടàµà´Ÿàµ ചെയàµà´¤àµ \'ln -s / data / data / host / system / etc / host\' ഉപയോഗിചàµà´šàµ സിംലിങàµà´•ൠസൃഷàµà´Ÿà´¿à´•àµà´•àµà´• à´Žà´¨àµà´¨à´¤à´¾à´£àµ ഒരൠപരിഹാരം.ഇതൠപàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´²àµ†à´™àµà´•ിൽ à´Žà´¸àµ-à´“à´«à´¿à´¨àµà´‚ നിങàµà´™à´³àµà´Ÿàµ† ഫോണിനàµà´®à´¾à´¯à´¿ ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±à´¿àµ½ തിരയàµà´•. + സിംലിങàµà´•ൠസൃഷàµà´Ÿà´¿à´•àµà´•ൽ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ + കൂടàµà´¤àµ½ വിവരങàµà´™àµ¾à´•àµà´•ൠസഹായം വായികàµà´•àµà´•. + നിങàµà´™à´³àµà´Ÿàµ† ആൻഡàµà´°àµ‹à´¯à´¿à´¡à´¿àµ½ ഒരൠAPN à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സജàµà´œà´®à´¾à´•àµà´•à´¿!3 ജി പോലàµà´³àµà´³ മൊബൈൽ നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµà´•ളിൽ ആയിരികàµà´•àµà´®àµà´ªàµ‹àµ¾ AdAway വിശàµà´µà´¸à´¨àµ€à´¯à´®à´¾à´¯à´¿ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•à´¿à´²àµà´².നിങàµà´™àµ¾ തിരഞàµà´žàµ†à´Ÿàµà´¤àµà´¤ APN- ലേകàµà´•ൠപോയി (From the Settings app: Network & Internet -> Mobile network -> Advanced -> Access Point Names) à´† à´ªàµà´°àµ‹à´•àµà´¸à´¿ നിർജàµà´œàµ€à´µà´®à´¾à´•àµà´•à´¿ à´ªàµà´°àµ‹à´•àµà´¸à´¿ ഫീൽഡിലെ മൂലàµà´¯à´‚ നീകàµà´•ംചെയàµà´¯à´¾à´‚. + APN à´ªàµà´°àµ‹à´•àµà´¸à´¿ നേരെയാകàµà´•à´¿! + ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ കണകàµà´·àµ» à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². + ബനàµà´§à´®à´¿à´²àµà´² + ഡൗൺലോഡàµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨àµâ€¦ + à´ªàµà´°à´¯àµ‹à´—à´¿à´•àµà´•àµà´¨àµà´¨àµâ€¦ + à´¬àµà´²à´¾à´•àµà´•ൠലിസàµà´±àµà´±àµà´‚ വൈറàµà´±àµâ€Œà´²à´¿à´¸àµà´±àµà´±àµà´‚ à´ªàµà´°à´¯àµ‹à´—à´¿à´•àµà´•àµà´¨àµà´¨àµ + ഹോസàµà´±àµà´±àµ ഫയലàµà´•ൾ വിശകലനം ചെയàµà´¯àµà´•à´¯àµà´‚ ലയിപàµà´ªà´¿à´•àµà´•àµà´•à´¯àµà´‚ ചെയàµà´¯àµà´¨àµà´¨àµ + ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഫയൽ നിർമàµà´®à´¿à´•àµà´•àµà´¨àµà´¨àµ + ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഫയൽ à´ªàµà´°à´¯àµ‹à´—à´¿à´•àµà´•àµà´¨àµà´¨àµ + നിങàµà´™à´³àµà´Ÿàµ† സിസàµà´±àµà´±à´¤àµà´¤à´¿à´²àµ‡à´•àµà´•ൠഹോസàµà´±àµà´±àµà´¸àµ ഫയൽ à´ªàµà´°à´¯àµ‹à´—à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ!ടാർ‌ഗെറàµà´±àµ ഹോസàµà´±àµà´±àµà´•ൾ‌ ഫയൽ‌ / data / data / hosts à´®àµàµ»â€Œà´—ണനയായി മാറàµà´±à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´•. + à´ªàµà´°à´¯àµ‹à´—à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ + റൂടàµà´Ÿàµ ആകàµâ€Œà´¸à´¸àµ à´…à´¨àµà´µà´¦à´¿à´šàµà´šàµà´µàµ†à´¨àµà´¨àµ ഉറപàµà´ªà´¾à´•àµà´•ാൻ ദയവായി നിങàµà´™à´³àµà´Ÿàµ† റൂടàµà´Ÿàµ മാനേജàµà´®àµ†à´¨àµà´±àµ à´…à´ªàµà´²à´¿à´•àµà´•േഷൻ പരിശോധികàµà´•àµà´•. + നിങàµà´™àµ¾ à´¸àµà´¥à´¿à´°à´¸àµà´¥à´¿à´¤à´¿ ഹോസàµà´±àµà´±àµ ഫയൽ പഴയപടിയാകàµà´•à´¿.മാറàµà´±à´™àµà´™àµ¾ à´ªàµà´°à´¾à´¬à´²àµà´¯à´¤àµà´¤à´¿àµ½ വരാൻ ആൻഡàµà´°àµ‹à´¯à´¿à´¡àµ റീബൂടàµà´Ÿàµ ചെയàµà´¯àµ‡à´£àµà´Ÿà´¤àµ ആവശàµà´¯à´®à´¾à´¯à´¿ വനàµà´¨àµ‡à´•àµà´•ാം.നിങàµà´™àµ¾à´•àµà´•ൠറീബൂടàµà´Ÿàµ ചെയàµà´¯à´£àµ‹?(ഡാറàµà´± നഷàµâ€Œà´Ÿà´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨à´¤àµ തടയാൻ ഇപàµà´ªàµ‹àµ¾ ഒരൠഅപàµà´²à´¿à´•àµà´•േഷനàµà´‚ à´Žà´¸àµà´¡à´¿ കാർഡൠഉപയോഗികàµà´•àµà´¨àµà´¨à´¿à´²àµà´²àµ†à´¨àµà´¨àµ ഉറപàµà´ªà´¾à´•àµà´•àµà´•!) + പഴയപടിയാകàµà´•àµà´¨àµà´¨àµ പഴയപടിയാകàµà´•àµà´¨àµà´¨à´¤à´¿àµ½ വിജയിചàµà´šàµ   + à´…à´œàµà´žà´¾à´¤à´®à´¾à´¯ കാരണങàµà´™à´³à´¾àµ½ പഴയപടിയാകàµà´•ൽ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ. + പഴയപടിയാകàµà´•ൽ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ! + നിങàµà´™à´³àµà´Ÿàµ† à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•à´¿à´¯ ഹോസàµà´±àµà´±àµ ഉറവിടങàµà´™à´³àµŠà´¨àµà´¨àµà´‚ à´Žà´¤àµà´¤à´¿à´šàµà´šàµ‡à´°à´¾à´¨à´¾à´•à´¿à´²àµà´²!നിങàµà´™àµ¾ ശരിയായി ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµà´®à´¾à´¯à´¿ ബനàµà´§à´¿à´ªàµà´ªà´¿à´šàµà´šà´¿à´Ÿàµà´Ÿàµà´£àµà´Ÿàµ‹? + ഡൗൺലോഡൠപരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ + à´¸àµà´µà´•ാരàµà´¯ ഫയൽ സൃഷàµà´Ÿà´¿à´•àµà´•ാൻ കഴിയിലàµà´². + à´¸àµà´µà´•ാരàµà´¯ ഫയൽ സൃഷàµâ€Œà´Ÿà´¿à´•àµà´•ൽ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ + നിങàµà´™àµ¾ സിസàµà´±àµà´±à´®à´¿à´²àµà´²à´¾à´¤àµà´¤ മോഡൠപàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´®à´¾à´•àµà´•à´¿..മാറàµà´±à´™àµà´™àµ¾ à´ªàµà´°à´¾à´¬à´²àµà´¯à´¤àµà´¤à´¿àµ½ വരാൻ ആൻഡàµà´°àµ‹à´¯à´¿à´¡àµ റീബൂടàµà´Ÿàµ ചെയàµà´¯àµ‡à´£àµà´Ÿà´¤àµ ആവശàµà´¯à´®à´¾à´¯à´¿ വനàµà´¨àµ‡à´•àµà´•ാം.നിങàµà´™àµ¾à´•àµà´•ൠറീബൂടàµà´Ÿàµ ചെയàµà´¯à´£àµ‹?(ഡാറàµà´± നഷàµâ€Œà´Ÿà´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨à´¤àµ തടയാൻ ഇപàµà´ªàµ‹àµ¾ ഒരൠഅപàµà´²à´¿à´•àµà´•േഷനàµà´‚ à´Žà´¸àµà´¡à´¿ കാർഡൠഉപയോഗികàµà´•àµà´¨àµà´¨à´¿à´²àµà´²àµ†à´¨àµà´¨àµ ഉറപàµà´ªà´¾à´•àµà´•àµà´•!) + à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´‚മാകàµà´•àµà´¨àµà´¨à´¤à´¿àµ½ വിജയിചàµà´šàµ + നിങàµà´™àµ¾ സിസàµà´±àµà´±à´®à´¿à´²àµà´²à´¾à´¤àµà´¤ മോഡൠഅപàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•à´¿.മാറàµà´±à´™àµà´™àµ¾ à´ªàµà´°à´¾à´¬à´²àµà´¯à´¤àµà´¤à´¿àµ½ വരാൻ ആൻഡàµà´°àµ‹à´¯à´¿à´¡àµ റീബൂടàµà´Ÿàµ ചെയàµà´¯àµ‡à´£àµà´Ÿà´¤àµ ആവശàµà´¯à´®à´¾à´¯à´¿ വനàµà´¨àµ‡à´•àµà´•ാം.നിങàµà´™àµ¾à´•àµà´•ൠറീബൂടàµà´Ÿàµ ചെയàµà´¯à´£àµ‹?(ഡാറàµà´± നഷàµâ€Œà´Ÿà´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨à´¤àµ തടയാൻ ഇപàµà´ªàµ‹àµ¾ ഒരൠഅപàµà´²à´¿à´•àµà´•േഷനàµà´‚ à´Žà´¸àµà´¡à´¿ കാർഡൠഉപയോഗികàµà´•àµà´¨àµà´¨à´¿à´²àµà´²àµ†à´¨àµà´¨àµ ഉറപàµà´ªà´¾à´•àµà´•àµà´•!) + à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´•àµà´•àµà´¨àµà´¨à´¤à´¿àµ½ വിജയിചàµà´šàµ + ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† മാജിസàµà´•ൠമൊഡàµà´¯àµ‚ൾ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´®à´¾à´•àµà´•àµà´¨àµà´¨àµ + മാജിസàµà´•ൠമാനേജറിൽ നിനàµà´¨àµ സിസàµà´±àµà´±à´®à´¿à´²àµà´²à´¾à´¤àµà´¤ ഹോസàµà´±àµà´±àµ സവിശേഷത à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•àµà´•.അതിനàµà´±àµ† à´•àµà´°à´®àµ€à´•രണങàµà´™à´³à´¿àµ½ നിനàµà´¨àµ, സിസàµà´±àµà´±à´‚ലെസàµà´¸àµ ഹോസàµà´±àµà´±àµà´•ൾ à´“à´ªàµà´·àµ» à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•à´¿ നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം റീബൂടàµà´Ÿàµ ചെയàµà´¯àµà´•. + ഹോസàµà´±àµà´±àµà´•ൾ മാജിസàµà´•ൠമൊഡàµà´¯àµ‚ൾ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´•àµà´•àµà´¨àµà´¨àµ + മാജിസàµà´•ൠമാനേജറിൽ നിനàµà´¨àµ സിസàµà´±àµà´±à´®à´¿à´²àµà´²à´¾à´¤àµà´¤ ഹോസàµà´±àµà´±àµ സവിശേഷത à´…à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•àµà´•.മൊഡàµà´¯àµ‚ൾ ലിസàµà´±àµà´±à´¿àµ½ നിനàµà´¨àµ,സിസàµà´±àµà´±à´‚ലെസàµà´¸àµ ഹോസàµà´±àµà´±àµ മൊഡàµà´¯àµ‚ൾ അൺഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¤àµ നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം റീബൂടàµà´Ÿàµ ചെയàµà´¯àµà´•. + + + ഹോസàµà´±àµà´±àµ ഫയലിലേകàµà´•ൠURL ഇൻപàµà´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´•: + ഇതൊരൠസാധàµà´µà´¾à´¯ ഹോസàµà´±àµà´±àµà´¨à´¾à´®à´®à´²àµà´²! + à´…à´¨àµà´šà´¿à´¤à´®à´¾à´¯à´¿ ഫോർമാറàµà´±àµà´šàµ†à´¯àµâ€Œà´¤ ഹോസàµà´±àµà´±àµà´¨à´¾à´®à´‚ + ഇതൊരൠസാധàµà´µà´¾à´¯ IP à´…à´²àµà´²! + à´…à´¨àµà´šà´¿à´¤à´®à´¾à´¯à´¿ ഫോർമാറàµà´±àµà´šàµ†à´¯àµâ€Œà´¤ IP + à´’à´°à´¿à´•àµà´•à´²àµà´‚ റീബൂടàµà´Ÿàµ ചെയàµà´¯à´°àµà´¤àµ, à´…à´Ÿàµà´¤àµà´¤ തവണ à´ˆ ചോദàµà´¯à´‚ കാണികàµà´•à´°àµà´¤àµ! + ലോഡിംഗàµâ€¦ + + + à´ªàµà´¤àµà´•àµà´•àµà´• + ചേർകàµà´•àµà´• + സഹായം + ബാകàµà´•à´ªàµà´ªàµ ഇമàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµà´šàµ†à´¯àµà´¯àµà´• + ബാകàµà´•à´ªàµà´ªàµ à´Žà´•àµà´¸àµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´• + + + à´Žà´¸àµ-ഓൺ / à´Žà´¸àµ-ഓഫൠ+ പതിവàµà´šàµ‡à´¾à´¦àµà´¯à´™àµà´™àµ¾ + à´ªàµà´°à´¶àµà´¨à´™àµà´™àµ¾ + + + ആഡൠവെയർ + ഇവിടെ നിങàµà´™àµ¾à´•àµà´•ൠഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¤ ആഡàµà´µàµ†à´¯àµ¼ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¾à´‚,AdAway- നൠതടയാൻ കഴിയാതàµà´¤ മോശം à´…à´ªàµà´²à´¿à´•àµà´•േഷനàµà´•ൾ.à´…à´ªàµà´²à´¿à´•àµà´•േഷൻ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•ാതàµà´¤à´ªàµà´ªàµ‹à´´àµà´‚ നിങàµà´™à´³àµà´Ÿàµ† റിംഗàµâ€Œà´Ÿàµ‹àµº മാറàµà´±àµà´®àµà´ªàµ‹à´´àµà´‚ പോപàµà´ªàµ à´…à´ªàµà´ªàµ ചെയàµà´¯àµà´¨àµà´¨ എയർപàµà´·àµ അറിയിപàµà´ªàµà´•ൾ à´ˆ à´…à´ªàµà´²à´¿à´•àµà´•േഷനàµà´•ൾ ഉപയോഗികàµà´•àµà´¨àµà´¨àµ.ലിസàµà´±àµà´±àµ ഇനങàµà´™à´³à´¿àµ½ à´•àµà´²à´¿à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤àµ à´† à´…à´ªàµà´²à´¿à´•àµà´•േഷനàµà´•ൾ അൺഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¯àµà´• à´Žà´¨àµà´¨à´¤à´¾à´£àµ ലഭàµà´¯à´®à´¾à´¯ ഒരേയൊരൠപàµà´°à´¤à´¿à´µà´¾à´¦à´‚. + à´¸àµà´•ാൻ ചെയàµà´¯àµà´¨àµà´¨àµâ€¦ + ആഡൠവെയർ à´’à´¨àµà´¨àµà´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´²! + + + Ad blocker + ടെകàµà´¸àµà´±àµà´±àµ à´Žà´¡à´¿à´±àµà´±à´±àµŠà´¨àµà´¨àµà´‚ ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¤à´¿à´Ÿàµà´Ÿà´¿à´²àµà´² + ഹോസàµà´±àµà´±àµ ഫയൽ à´¤àµà´±à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ ടെകàµà´¸àµà´±àµà´±àµ à´Žà´¡à´¿à´±àµà´±à´±àµŠà´¨àµà´¨àµà´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¾àµ» à´•à´´à´¿à´žàµà´žà´¿à´²àµà´².ഇതൠകൈകാരàµà´¯à´‚ ചെയàµà´¯à´¾àµ» നിങàµà´™àµ¾à´•àµà´•ൠജോറàµà´± à´…à´²àµà´²àµ†à´™àµà´•ിൽ മറàµà´±àµ ടെകàµà´¸àµà´±àµà´±àµ à´Žà´¡à´¿à´±àµà´±à´±àµà´•ൾ ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´¾àµ» à´•à´´à´¿à´¯àµà´‚.\n\nനിങàµà´™àµ¾à´•àµà´•ൠജോറàµà´± ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´£àµ‹? + ഫയൽ മാനേജറൊനàµà´¨àµà´‚ ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¤à´¿à´Ÿàµà´Ÿà´¿à´²àµà´² + ഫയലàµà´•ൾ à´¤àµà´±à´•àµà´•ാൻ ഒരൠഫയൽ മാനേജറàµà´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¾à´¨à´¾à´¯à´¿à´²àµà´².ഇതൠകൈകാരàµà´¯à´‚ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ നിങàµà´™àµ¾à´•àµà´•ൠOI ഫയൽ മാനേജർ à´…à´²àµà´²àµ†à´™àµà´•ിൽ മറàµà´±àµ ഫയൽ മാനേജർമാർ ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´¾àµ» à´•à´´à´¿à´¯àµà´‚.\n\nOI ഫയൽ മാനേജർ ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´¾àµ» നിങàµà´™àµ¾ ആഗàµà´°à´¹à´¿à´•àµà´•àµà´¨àµà´¨àµà´£àµà´Ÿàµ‹? + + + Tcpdump + DNS à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨à´•ൾ നിരീകàµà´·à´¿à´•àµà´•ാനàµà´‚ à´…à´µ ഒരൠലോഗൠഫയലിൽ സംരകàµà´·à´¿à´•àµà´•ാനàµà´‚ ഉളàµà´³ ഉപകരണമാണൠTcpdump.നിങàµà´™àµ¾à´•àµà´•ൠഇതൠപശàµà´šà´¾à´¤àµà´¤à´²à´¤àµà´¤à´¿àµ½ ആരംഭികàµà´•ാൻ à´•à´´à´¿à´¯àµà´‚,പരസàµà´¯à´™àµà´™àµ¾ à´ªàµà´°à´¦àµ¼à´¶à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨ à´…à´ªàµà´²à´¿à´•àµà´•േഷനàµà´•ൾ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´•,അതിനàµà´¶àµ‡à´·à´‚ ലോഗൠഫയൽ ഉപയോഗിചàµà´šàµ DNS à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨à´•ൾ വിശകലനം ചെയàµà´¯àµà´•.സാധàµà´¯à´®à´¾à´¯ പരസàµà´¯ സെർവർ നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´²à´¾à´•àµà´•ൠലിസàµà´±àµà´±à´¿àµ½ ചേർകàµà´•ാൻ à´•à´´à´¿à´¯àµà´‚. + നിരീകàµà´·à´£à´‚ à´…à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•àµà´• + നിരീകàµà´·à´£à´‚ à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•àµà´• + ഫലങàµà´™àµ¾ കാണികàµà´•àµà´• + ഡൊമെയàµâ€Œà´¨àµà´•ൾ à´…à´Ÿàµà´•àµà´•àµà´• + ലോഗൠമായàµâ€Œà´•àµà´•àµà´• + à´¬àµà´²à´¾à´•àµà´•ൠലിസàµà´±àµà´±à´¿à´²àµ‡à´•ൠഎൻടàµà´°à´¿ ചേർകàµà´•àµà´• + വൈറàµà´±àµ ലിസàµà´±àµà´±à´¿à´²àµ‡à´•àµà´•ൠഎൻ‌ടàµà´°à´¿ ചേർകàµà´•àµà´• + റീഡയറകàµâ€Œà´Ÿàµ ലിസàµà´±àµà´±à´¿à´²àµ‡à´•àµà´•ൠഎൻടàµà´°à´¿ ചേർകàµà´•àµà´• + + വാചക à´®àµàµ»à´—ണന മൂലàµà´¯à´‚ à´Žà´¡à´¿à´±àµà´±àµà´šàµ†à´¯àµà´¯àµà´• + മെനൠതàµà´±à´•àµà´•àµà´• + മെനൠഅടയàµâ€Œà´•àµà´•àµà´• + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + + + + DNS à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨à´•ൾ + നിങàµà´™à´³àµà´Ÿàµ† ലിസàµà´±àµà´±àµà´•ൾ + à´®àµàµ»â€Œà´—ണനകൾ + + %1$sഇതിനകം കാലികമാണൠ+ %1$s നൠഅപàµâ€Œà´¡àµ‡à´±àµà´±àµ ആവശàµà´¯à´®à´¾à´£àµ + അവസാന à´…à´ªàµâ€Œà´¡àµ‡à´±àµà´±àµ %1$s à´®àµà´®àµà´ªàµ + à´…à´œàµà´žà´¾à´¤ à´…à´ªàµâ€Œà´¡àµ‡à´±àµà´±àµ നില + + %dമിനിറàµà´±àµ + %d മിനിറàµà´±àµ + + + %dമണികàµà´•ൂറàµà´•ൾ + %dമണികàµà´•ൂറàµà´•ൾ + + + %dദിവസങàµà´™àµ¾ + %dദിവസങàµà´™àµ¾ + + + %dമാസങàµà´™àµ¾ + %dമാസങàµà´™àµ¾Â  + + + diff --git a/app/src/main/res/values-ml/strings_app.xml b/app/src/main/res/values-ml/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-ml/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-ml/strings_errors.xml b/app/src/main/res/values-ml/strings_errors.xml new file mode 100644 index 0000000..4bda602 --- /dev/null +++ b/app/src/main/res/values-ml/strings_errors.xml @@ -0,0 +1,6 @@ + + + + ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ കണകàµà´·à´¨à´¿à´²àµà´² + മതിയായ à´¸àµà´¥à´²à´®à´¿à´²àµà´² + \ No newline at end of file diff --git a/app/src/main/res/values-ml/strings_home.xml b/app/src/main/res/values-ml/strings_home.xml new file mode 100644 index 0000000..2368bfe --- /dev/null +++ b/app/src/main/res/values-ml/strings_home.xml @@ -0,0 +1,19 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + à´®àµàµ»â€Œà´—ണനകൾ + + + കൂടàµà´¤àµ½ വിവരങàµà´™àµ¾à´•àµà´•ൠസഹായം വായികàµà´•àµà´•. + + \ No newline at end of file diff --git a/app/src/main/res/values-ml/strings_hosts.xml b/app/src/main/res/values-ml/strings_hosts.xml new file mode 100644 index 0000000..c53891b --- /dev/null +++ b/app/src/main/res/values-ml/strings_hosts.xml @@ -0,0 +1,11 @@ + + + ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഉറവിടങàµà´™àµ¾ + + ലഭàµà´¯à´®à´²àµà´² + + ഉറവിടം ചേർകàµà´•àµà´• + ഉറവിടം à´Žà´¡à´¿à´±àµà´±àµà´šàµ†à´¯àµà´¯àµà´• + URL: (a https:// or file:// resource) + ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഉറവിടമായ URL + diff --git a/app/src/main/res/values-ml/strings_lists.xml b/app/src/main/res/values-ml/strings_lists.xml new file mode 100644 index 0000000..dea986a --- /dev/null +++ b/app/src/main/res/values-ml/strings_lists.xml @@ -0,0 +1,15 @@ + + + നിങàµà´™à´³àµà´Ÿàµ† ലിസàµà´±àµà´±àµà´•ൾ + + ഹോസàµà´±àµà´±àµ à´¬àµà´²à´¾à´•àµà´•ൠലിസàµà´±àµà´±à´¿à´²àµ‡à´•ൠചേർകàµà´•àµà´• + ഹോസàµà´±àµà´±àµ à´¬àµà´²à´¾à´•àµà´•àµâ€Œà´²à´¿à´¸àµà´±àµà´±à´¿à´²àµ‡à´•ൠചേർകàµà´•àµà´• + ഹോസàµà´±àµà´±àµ à´µàµà´¯à´¤à´¿à´šà´²à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´²àµ†à´•ൠചേർകàµà´•àµà´• + à´¬àµà´²à´¾à´•àµà´•ൠലിസàµà´±àµà´±àµ ചെയàµà´¤ ഹോസàµà´±àµà´±àµà´•ൾ തിരàµà´¤àµà´¤àµà´• + വൈറàµà´±àµ ലിസàµà´±àµà´±àµ ചെയàµà´¤ ഹോസàµà´±àµà´±àµà´•ൾ തിരàµà´¤àµà´¤àµà´• + à´µàµà´¯à´¤à´¿à´šà´²à´¨à´‚ തിരàµà´¤àµà´¤àµà´• + ഹോസàµà´±àµà´±àµà´¨à´¾à´®à´‚ + ഹോസàµà´±àµà´±àµà´•à´³àµà´Ÿàµ† ഉറവിടമായ URL + (വൈൽഡàµà´•ാർഡൠപàµà´°à´¤àµ€à´•à´™àµà´™àµ¾ * ഉം ? à´…à´¨àµà´µà´¦à´¨àµ€à´¯à´®à´¾à´£àµ) + IP (IPv4 or IPv6): + diff --git a/app/src/main/res/values-ml/strings_log.xml b/app/src/main/res/values-ml/strings_log.xml new file mode 100644 index 0000000..4efb3de --- /dev/null +++ b/app/src/main/res/values-ml/strings_log.xml @@ -0,0 +1,8 @@ + + + + à´…à´•àµà´·à´°à´®à´¾à´²à´¾à´•àµà´°à´®à´¤àµà´¤à´¿àµ½ + ടോപàµà´ªàµ ലെവൽ ഡൊമെയàµàµ» à´…à´Ÿàµà´•àµà´•ൽ + + ഡൊമെയàµàµ» റീഡയറകàµà´Ÿàµ ചെയàµà´¯àµà´• + diff --git a/app/src/main/res/values-ml/strings_notification.xml b/app/src/main/res/values-ml/strings_notification.xml new file mode 100644 index 0000000..478e5cd --- /dev/null +++ b/app/src/main/res/values-ml/strings_notification.xml @@ -0,0 +1,6 @@ + + + + നവീകരങàµà´™àµ¾ + നവീകരണം ലഭàµà´¯à´®à´¾à´£àµ + \ No newline at end of file diff --git a/app/src/main/res/values-ml/strings_prefs_backup_restore.xml b/app/src/main/res/values-ml/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ml/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ml/strings_prefs_main.xml b/app/src/main/res/values-ml/strings_prefs_main.xml new file mode 100644 index 0000000..60d255b --- /dev/null +++ b/app/src/main/res/values-ml/strings_prefs_main.xml @@ -0,0 +1,7 @@ + + + à´®àµàµ»â€Œà´—ണനകൾ + റൂടàµà´Ÿàµ à´…à´Ÿà´¿à´¸àµà´¥à´¾à´¨à´®à´¾à´•àµà´•à´¿à´¯àµà´³àµà´³ പരസàµà´¯ à´¬àµà´²àµ‹à´•àµà´•ർ + + ഡീബഗൠചെയàµà´¯àµà´• + diff --git a/app/src/main/res/values-ml/strings_prefs_root.xml b/app/src/main/res/values-ml/strings_prefs_root.xml new file mode 100644 index 0000000..c1e1da4 --- /dev/null +++ b/app/src/main/res/values-ml/strings_prefs_root.xml @@ -0,0 +1,26 @@ + + + റൂടàµà´Ÿàµ à´…à´Ÿà´¿à´¸àµà´¥à´¾à´¨à´®à´¾à´•àµà´•à´¿à´¯àµà´³àµà´³ പരസàµà´¯ à´¬àµà´²àµ‹à´•àµà´•ർ + + hosts ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¨àµà´¨àµ + Open hosts file + ടാർഗെറàµà´±àµ ഹോസàµà´±àµà´±à´¸àµ ഫയൽ + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + + റീഡയറകàµà´·àµ» + റീഡയറകàµà´·àµ» IPv4 + റീഡയറകàµà´·àµ» IPv6 + + à´ªàµà´°à´¾à´¦àµ‡à´¶à´¿à´• വെബàµâ€Œà´¸àµ¼à´µàµ¼ + വെബൠസെർവർ à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•àµà´• + വെബൠസെർവർ പരിശോധികàµà´•àµà´• + സർ‌ടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ മാനàµà´µàµ½â€Œ ഇൻ‌സàµà´±àµà´±à´¾àµ¾â€Œ + à´¸àµà´°à´•àµà´·à´¾ à´•àµà´°à´®àµ€à´•രണങàµà´™àµ¾ à´¤àµà´±à´•àµà´•àµà´• + പരിശോധികàµà´•àµà´¨àµà´¨àµ + à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´² + diff --git a/app/src/main/res/values-ml/strings_prefs_update.xml b/app/src/main/res/values-ml/strings_prefs_update.xml new file mode 100644 index 0000000..ab9a3aa --- /dev/null +++ b/app/src/main/res/values-ml/strings_prefs_update.xml @@ -0,0 +1,4 @@ + + + നവീകരങàµà´™àµ¾ + diff --git a/app/src/main/res/values-ml/strings_prefs_vpn.xml b/app/src/main/res/values-ml/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-ml/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-ml/strings_support.xml b/app/src/main/res/values-ml/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ml/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ml/strings_update.xml b/app/src/main/res/values-ml/strings_update.xml new file mode 100644 index 0000000..8ade0ed --- /dev/null +++ b/app/src/main/res/values-ml/strings_update.xml @@ -0,0 +1,4 @@ + + + നവീകരണം ലഭàµà´¯à´®à´¾à´£àµ + diff --git a/app/src/main/res/values-ml/strings_welcome.xml b/app/src/main/res/values-ml/strings_welcome.xml new file mode 100644 index 0000000..b6e6a42 --- /dev/null +++ b/app/src/main/res/values-ml/strings_welcome.xml @@ -0,0 +1,4 @@ + + + റൂടàµà´Ÿàµ ചെയàµà´¤ ആൻഡàµà´°àµ‹à´¯à´¿à´¡àµ ആവശàµà´¯à´®à´¾à´£àµ + diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml new file mode 100644 index 0000000..9e45587 --- /dev/null +++ b/app/src/main/res/values-ms/strings.xml @@ -0,0 +1,14 @@ + + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-ms/strings_app.xml b/app/src/main/res/values-ms/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-ms/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-ms/strings_errors.xml b/app/src/main/res/values-ms/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ms/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ms/strings_home.xml b/app/src/main/res/values-ms/strings_home.xml new file mode 100644 index 0000000..a530b93 --- /dev/null +++ b/app/src/main/res/values-ms/strings_home.xml @@ -0,0 +1,6 @@ + + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-ms/strings_hosts.xml b/app/src/main/res/values-ms/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-ms/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-ms/strings_lists.xml b/app/src/main/res/values-ms/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-ms/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-ms/strings_log.xml b/app/src/main/res/values-ms/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-ms/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-ms/strings_notification.xml b/app/src/main/res/values-ms/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ms/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ms/strings_prefs_backup_restore.xml b/app/src/main/res/values-ms/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ms/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ms/strings_prefs_main.xml b/app/src/main/res/values-ms/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-ms/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-ms/strings_prefs_root.xml b/app/src/main/res/values-ms/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-ms/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-ms/strings_prefs_update.xml b/app/src/main/res/values-ms/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ms/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ms/strings_prefs_vpn.xml b/app/src/main/res/values-ms/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-ms/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-ms/strings_support.xml b/app/src/main/res/values-ms/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ms/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ms/strings_update.xml b/app/src/main/res/values-ms/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ms/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ms/strings_welcome.xml b/app/src/main/res/values-ms/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-ms/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml new file mode 100644 index 0000000..9e45587 --- /dev/null +++ b/app/src/main/res/values-my/strings.xml @@ -0,0 +1,14 @@ + + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-my/strings_app.xml b/app/src/main/res/values-my/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-my/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-my/strings_errors.xml b/app/src/main/res/values-my/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-my/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-my/strings_home.xml b/app/src/main/res/values-my/strings_home.xml new file mode 100644 index 0000000..a530b93 --- /dev/null +++ b/app/src/main/res/values-my/strings_home.xml @@ -0,0 +1,6 @@ + + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-my/strings_hosts.xml b/app/src/main/res/values-my/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-my/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-my/strings_lists.xml b/app/src/main/res/values-my/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-my/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-my/strings_log.xml b/app/src/main/res/values-my/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-my/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-my/strings_notification.xml b/app/src/main/res/values-my/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-my/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-my/strings_prefs_backup_restore.xml b/app/src/main/res/values-my/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-my/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-my/strings_prefs_main.xml b/app/src/main/res/values-my/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-my/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-my/strings_prefs_root.xml b/app/src/main/res/values-my/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-my/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-my/strings_prefs_update.xml b/app/src/main/res/values-my/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-my/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-my/strings_prefs_vpn.xml b/app/src/main/res/values-my/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-my/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-my/strings_support.xml b/app/src/main/res/values-my/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-my/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-my/strings_update.xml b/app/src/main/res/values-my/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-my/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-my/strings_welcome.xml b/app/src/main/res/values-my/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-my/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml new file mode 100644 index 0000000..5b2104a --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -0,0 +1,109 @@ + + + + Avslutt + Lukk + Ja + Nei + Legg til + Lukk + Lagre + Hjelp + + + Velkommen! + Vis mere hjelp + Oppdater statusen + Alle vertsfiler fra de valgte kildene blir lastet ned, slÃ¥tt sammen med dine egne lister, og installert som én vertsfil pÃ¥ systemet ditt. + Kjører + Stoppet + + Rediger oppføring + Rediger + Slett + + + Importerer … + Eksporterer … + Lager standard-vertsfilen + Nyere vertsfiler er tilgjengelig + Ingen internettilkobling + Ingen internettilkobling er tilgjengelig + Utilgjengelige kilder + Ingen vertsfiler kan bli nÃ¥dd! + Skrudd pÃ¥ + De nyeste vertsfilene er skrudd pÃ¥ + Skrudd av + Symlinken fra mÃ¥let ditt til /system/etc/hosts finnes ikke eller er feil! AdAway vil ikke virke dersom den ikke peker mot den riktige filen.\n\nVil du forsøke Ã¥ lage en symlink? + Symlinken mangler + Ikke nok plass pÃ¥ partisjonen!\nPrøv Ã¥ skifte mÃ¥lvertsfilen i innstillingene til /data/data/hosts. + Ikke nok plass + Den nedlastede filen kunne ikke bli lest inn. + Feil med privat fil + Gjenmontering av partisjonen som les+skriv mislyktes! + Gjenmontering mislyktes + Kopiering av vertsfilen mislyktes! + Kopiering mislyktes + Benyttelsen var vellykket + Symlink-opprettelsen var vellykket + Symlink-opprettelsen mislyktes + Se i Hjelp for mere informasjon. + APN-mellomtjeneren ble valgt! + TIlkoblingen til internettet virker ikke. + Ingen tilkobling + Laster ned … + Benytter … + Benytter svartelisten og hvitelisten + Parser og slÃ¥r sammen vertsfilene + Bygger vertsfilen + Benytter vertsfilen + Ã… fÃ¥ systemet ditt til Ã¥ benytte vertsfilen mislyktes!\nPrøv Ã¥ skifte mÃ¥lvertsfilen i innstillingene til /data/data/hosts. + Benyttelse mislyktes + Tilbakestillingen var vellykket + Tilbakestillingen mislyktes av ukjente grunner. + Tilbakestillingen mislyktes! + Ingen av dine vertsfiler kan bli koblet til! Er du riktig tilkoblet til internettet? + Nedlastningen mislyktes + Privatfilen kan ikke bli opprettet. + Privatfil-opprettelsen mislyktes + PÃ¥skruingen var vellykket + Avskruingen var vellykket + + Inndata-URLen til vertsfilen: + Dette er ikke et gyldig vertsnavn! + Ugyldig formattert vertsnavn + Dette er ikke gyldig IP! + Ugyldig formattert IP + Laster inn … + + + Oppfrisk + Legg til + Hjelp + + S-ON/S-OFF + FAQ + Problemer + + + Reklameblokkerer + Ingen tekstredigerere er installert + Ingen tekstredigerer som kunne Ã¥pne vertsfilen kunne bli funnet. Du kan installere Jota eller andre tekstredigerere for Ã¥ hÃ¥ndtere dette.\n\nVil du installere Jota? + Ingen filbehandlere er installert + Ingen filbehandler som kunne Ã¥pne filer kunne bli funnet. Du kan installere OI File Manager eller andre tekstredigerere for Ã¥ hÃ¥ndtere dette.\n\nVil du installere OI File Manager? + + Tcpdump er et verktøy for Ã¥ overvÃ¥ke DNS-forespørsler og lagre dem i en loggfil. Du kan starte den i bakgrunnen, kjøre apper som viser reklamer, og etterpÃ¥ analysere DNS-forespørslene ved hjelp av loggfilen. Mulige reklametjenere kan deretter bli lagt til i svartelisten din. + + + Home + Vertsfilkilder + Your lists + Ã…pne vertsfilen + Log DNS requests + Scan for adware + Preferanser + Hjelp + + Preferanser + + diff --git a/app/src/main/res/values-nb-rNO/strings_app.xml b/app/src/main/res/values-nb-rNO/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-nb-rNO/strings_errors.xml b/app/src/main/res/values-nb-rNO/strings_errors.xml new file mode 100644 index 0000000..4b99e25 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_errors.xml @@ -0,0 +1,6 @@ + + + + Ingen internettilkobling + Ikke nok plass + \ No newline at end of file diff --git a/app/src/main/res/values-nb-rNO/strings_home.xml b/app/src/main/res/values-nb-rNO/strings_home.xml new file mode 100644 index 0000000..eb55407 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_home.xml @@ -0,0 +1,19 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferanser + + + Se i Hjelp for mere informasjon. + + \ No newline at end of file diff --git a/app/src/main/res/values-nb-rNO/strings_hosts.xml b/app/src/main/res/values-nb-rNO/strings_hosts.xml new file mode 100644 index 0000000..004c241 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_hosts.xml @@ -0,0 +1,6 @@ + + + Vertsfilkilder + + ikke tilgjengelig + diff --git a/app/src/main/res/values-nb-rNO/strings_lists.xml b/app/src/main/res/values-nb-rNO/strings_lists.xml new file mode 100644 index 0000000..13a0402 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_lists.xml @@ -0,0 +1,6 @@ + + + Your lists + Vertsnavn: + IP (IPv6 eller IPv4): + diff --git a/app/src/main/res/values-nb-rNO/strings_log.xml b/app/src/main/res/values-nb-rNO/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-nb-rNO/strings_notification.xml b/app/src/main/res/values-nb-rNO/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-nb-rNO/strings_prefs_backup_restore.xml b/app/src/main/res/values-nb-rNO/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-nb-rNO/strings_prefs_main.xml b/app/src/main/res/values-nb-rNO/strings_prefs_main.xml new file mode 100644 index 0000000..fceee36 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_prefs_main.xml @@ -0,0 +1,6 @@ + + + Preferanser + + Avlusing + diff --git a/app/src/main/res/values-nb-rNO/strings_prefs_root.xml b/app/src/main/res/values-nb-rNO/strings_prefs_root.xml new file mode 100644 index 0000000..b85af8b --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_prefs_root.xml @@ -0,0 +1,13 @@ + + + Ã…pne vertsfilen + MÃ¥lpunktsvertsfilen + + /system/etc/hosts + /data/hosts + /data/data/hosts + Tilpasset mÃ¥lpunkt + + + Omdirigering + diff --git a/app/src/main/res/values-nb-rNO/strings_prefs_update.xml b/app/src/main/res/values-nb-rNO/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-nb-rNO/strings_prefs_vpn.xml b/app/src/main/res/values-nb-rNO/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-nb-rNO/strings_support.xml b/app/src/main/res/values-nb-rNO/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-nb-rNO/strings_update.xml b/app/src/main/res/values-nb-rNO/strings_update.xml new file mode 100644 index 0000000..dd21545 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_update.xml @@ -0,0 +1,4 @@ + + + Oppdatering tilgjengelig + diff --git a/app/src/main/res/values-nb-rNO/strings_welcome.xml b/app/src/main/res/values-nb-rNO/strings_welcome.xml new file mode 100644 index 0000000..dde7a13 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings_welcome.xml @@ -0,0 +1,4 @@ + + + En rootet Android er pÃ¥krevd + diff --git a/app/src/main/res/values-ne/strings.xml b/app/src/main/res/values-ne/strings.xml new file mode 100644 index 0000000..9e45587 --- /dev/null +++ b/app/src/main/res/values-ne/strings.xml @@ -0,0 +1,14 @@ + + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-ne/strings_app.xml b/app/src/main/res/values-ne/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-ne/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-ne/strings_errors.xml b/app/src/main/res/values-ne/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ne/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ne/strings_home.xml b/app/src/main/res/values-ne/strings_home.xml new file mode 100644 index 0000000..a530b93 --- /dev/null +++ b/app/src/main/res/values-ne/strings_home.xml @@ -0,0 +1,6 @@ + + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-ne/strings_hosts.xml b/app/src/main/res/values-ne/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-ne/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-ne/strings_lists.xml b/app/src/main/res/values-ne/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-ne/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-ne/strings_log.xml b/app/src/main/res/values-ne/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-ne/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-ne/strings_notification.xml b/app/src/main/res/values-ne/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ne/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ne/strings_prefs_backup_restore.xml b/app/src/main/res/values-ne/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ne/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ne/strings_prefs_main.xml b/app/src/main/res/values-ne/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-ne/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-ne/strings_prefs_root.xml b/app/src/main/res/values-ne/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-ne/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-ne/strings_prefs_update.xml b/app/src/main/res/values-ne/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ne/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ne/strings_prefs_vpn.xml b/app/src/main/res/values-ne/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-ne/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-ne/strings_support.xml b/app/src/main/res/values-ne/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ne/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ne/strings_update.xml b/app/src/main/res/values-ne/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ne/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ne/strings_welcome.xml b/app/src/main/res/values-ne/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-ne/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml new file mode 100644 index 0000000..542543d --- /dev/null +++ b/app/src/main/res/values-night/colors.xml @@ -0,0 +1,10 @@ + + + + #B71C1C + #e53935 + #ffffff + #EF9A9A + #80CBC4 + #9FA8DA + diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..413ae88 --- /dev/null +++ b/app/src/main/res/values-night/styles.xml @@ -0,0 +1,6 @@ + + + + diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml new file mode 100644 index 0000000..ccbf924 --- /dev/null +++ b/app/src/main/res/values-nl/strings.xml @@ -0,0 +1,272 @@ + + + + Afsluiten + Sluiten + Ja + Nee + Toevoegen + Annuleren + Bewaren + Help + + + Welkom! + AdAway is vrije software, ontworpen om advertenties te blokkeren. Het haalt de adressen van reclamenetwerken en blokkeert deze op uw apparaat.\nWilt u meer weten? Bekijk de hulpsectie hieronder. + Meer help tonen + Status bijwerken + Alle hosts-bestanden van de gedefinieerde bronnen worden gedownload, samengevoegd met uw eigen lijsten en als één hosts-bestand op uw systeem geïnstalleerd. + Advertentieblokkering inschakelen + Advertentieblokkering uitschakelen + Webserver + Actief + Gestopt + Start of stop de webserver op localhost om verzoeken aan geblokkeerde hostnamen te beantwoorden. + Webserver inschakelen + Webserver uitschakelen + VPN + Actief + Gestopt + Start of stop de VPN die verzoeken filtert. + VPN gebruiken + Geen VPN gebruiken + + + Invoer bewerken + Toepassen + Bewerken + Verwijder + + + Bezig met importeren… + De back-up is geïmporteerd van uw externe opslag. + Het importeren is mislukt. Is het formaat juist? Bekijk de logcat voor meer informatie. + Bezig met exporteren… + De back-up is succesvol geëxporteerd naar \'%s\' op uw externe opslag. + Het exporteren van backup file \'%s\' is mislukt. + + + Het hosts-bestand + Het hosts-bestand is een systeembestand dat ip-adressen toewijst aan hostnamen. Het is een tekstbestand waarvan de configuratie door AdAway wordt afgehandeld. Hier zijn de eerste regels: + Bezig met laden van inhoud van hosts-bestand… + Hosts-bestand openen + + + Bezig met controleren op updates + Controleer %s bron om te updaten + Bezig met ophalen van bronnen + Bezig met ophalen van bron \'%s\' + Lezen bron %s + Verwerken %s bron + Database synchroniseren + Bezig met terugzetten van standaard hosts-bestand + Het standaard hosts-bestand is teruggezet + Bezig met aanmaken van nieuw hosts-bestand + Er is een bronupdate beschikbaar + Er zijn nieuwere hosts-bestanden beschikbaar. + Geen bronupdates gevonden + Geen internetverbinding + Geen internetverbinding beschikbaar + Bronnen zijn niet beschikbaar + Er zijn geen hosts-bronnen bereikbaar! + Root toegang geweigerd + Root toegang toestaan + Er ging iets mis + Bekijk de logcat voor details + Ingeschakeld + Nieuwste hosts-bestanden ingeschakeld + Uitgeschakeld + Standaard hosts-bestand geïnstalleerd + Nieuwste bronnen toepassen + Bezig met aanmaken van nieuw hosts-bestand + Bezig met kopiëren van nieuw hosts-bestand + Bezig met controleren van hosts-kopie + Het hosts-bestand is bijgewerkt + VPN configuratie succesvol bijgewerkt + Je configuratie is gewijzigd. Je moet het toepassen. + Toepassen + Toepassen van nieuwe configuratie… + Toepassen van nieuwe configuratie is mislukt. + + + De symlink naar het hosts-bestand ontbreekt + Symlink van de gekozen locatie naar /system/etc/hosts bestaat niet, of verwijst niet naar het juiste bestand! AdAway werkt niet als de symlink niet naar het juiste bestand verwijst. Wilt u proberen een symlink te maken? + Symlink ontbreekt + Onvoldoende ruimte op de systeempartitie! +Verander de locatie van het hosts-bestand naar /data/data/hosts in de voorkeuren. + Onvoldoende ruimte + Gedownload bestand kan niet worden gelezen. + Privébestandsfout + Het opnieuw koppelen van de partitie als lezen/schrijven is mislukt! + Opnieuw koppelen mislukt + Het hosts-bestand kan niet worden gekopieerd + Kopiëren van hosts-bestand is mislukt! + Kopiëren mislukt + Hosts-bronnen toegepast + Toepassen voltooid + Toepassen voltooid. +Android moet mogelijk worden herstart om de wijzigingen door te voeren. + +Wilt u herstarten? +(Om gegevensverlies te voorkomen moet u zorgen dat geen enkele app op dit moment de SD-kaart gebruikt!) + Symlink aangemaakt. +Android moet mogelijk worden herstart om de wijzigingen door te voeren. + +Wilt u herstarten? +(Om gegevensverlies te voorkomen moet u zorgen dat geen enkele app op dit moment de SD-kaart gebruikt!) + Symlink aangemaakt + De symlink kon niet door Android worden aangemaakt. Dit mislukt meestal door een \'feature\' genaamd S-ON op HTC telefoons! Een oplossing is uw telefoon in recoverymodus opstarten en hier de symlink aanmaken met \'ln -s /data/data/hosts /system/etc/hosts\'. Als dit niet werkt, zoek dan op internet naar S-OFF en uw telefoon. + Symlink aanmaken mislukt + Bekijk de hulpsectie voor meer informatie. + Een APN proxy is ingesteld op jouw Android! AdAway zal niet betrouwbaar werken als er gebruik gemaakt wordt van mobiele netwerken zoals 3G/4G. Je kan je proxy uitschakelen door naar je geselecteerde APN te gaan. (Op Android 4: draadloos en netwerken -> meer… -> Mobiele netwerken -> namen toegangspunten) en de waarde in het proxy veld te verwijderen. + APN-proxy ingesteld! + De internetverbinding werkt niet. + Geen verbinding + Downloaden… + Toepassen… + Black en whitelist toepassen + Lezen en samenvoegen van hosts-bestanden + Hosts-bestand opbouwen + Hosts-bestand plaatsen + Het nieuwe hosts-bestand kan niet worden toegepast. + Het plaatsen van het hosts-bestand is mislukt!\nVerander de locatie van het hosts-bestand naar /data/data/hosts in de voorkeuren. + Hosts-bestand plaatsen mislukt + Controleer uw Root app om zeker te zijn dat Root toegang is toegestaan. + U hebt het standaard hosts bestand teruggezet. Het kan nodig zijn om Android te herstarten om de wijzigingen effect te laten hebben. Wilt u herstarten? (Om data verlies te voorkomen moet u zorgen dat geen enkele applicatie op dit moment de sdkaart gebruikt) + Terugzetten voltooid + Het hosts-bestand kan niet worden teruggezet + Terugzetten is door onbekende redenen mislukt. + Terugzetten mislukt! + Geen van uw geselecteerde hosts-bronnen zijn bereikbaar! Bent u verbonden met het internet? + Downloaden mislukt + Het nieuwe privéhosts-bestand kan niet worden toegepast + Privébestanden kunnen niet worden aangemaakt. + Aanmaken privébestand mislukt + U heeft de systeemloze modus ingeschakeld. Het kan nodig zijn om Android opnieuw op te starten om de wijzigingen effect te laten hebben. Wilt u nu opnieuw opstarten? (Om dataverlies te voorkomen, moet u zorgen dat geen enkele app op dit moment de SD-kaart gebruikt.) + + Inschakelen gelukt + U heeft systemless mode uitgeschakeld. Het kan nodig zijn om Android opnieuw op te starten om de wijzigingen effect te laten hebben. Wilt u nu herstarten? (Om dataverlies te voorkomen, moet u zorgen dat geen enkele app op dit moment de SD-kaart gebruikt.) + Uitschakelen gelukt + De VPN kan niet worden ingeschakeld. + De VPN kan niet worden uitgeschakeld. + Activeer Magisk module + Activeer systemless hosts van Magisk manager. Activeer in de instellingen Systemless hosts optie en start de telefoon opnieuw op. + De-activeer Magisk module + De-activeer systemless hosts van Magisk manager. De-installeer uit de module lijstSystemless hosts en start de telefoon opnieuw op. + + + Voer URL naar het hosts-bestand in: + Dit is geen correcte hostnaam! + Host-naam onjuist geformatteerd + Dit is geen correct IP-adres! + IP-adres is verkeerd opgemaakt + Herstart nooit en laat deze vraag niet meer zien. + Bezig met laden… + + + Verversen + Toevoegen + Help + Back-up importeren + Back-up exporteren + + + S-ON/S-OFF + VGV + Problemen + + + Adware + Hier kunt u scannen naar slechte Adware applicaties, welke niet door AdAway geblokkeerd kunnen worden. Deze applicaties gebruiken bijvoorbeeld Airpush notificaties, welke zelfs opkomen als de applicatie niet draait, of veranderen zelfs uw ringtone. De enige beschikbare oplossing is deze applicaties te deïnstalleren door op de lijst elementen te klikken! + Scannen… + Geen slechte Adware apps gevonden! + + + Adblocker + Geen tekstverwerker geïnstalleerd + Geen tekstverwerker gevonden om het hosts-bestand mee te openen. U kunt Jota of een andere tekstverwerker installeren om dit te verhelpen.\n\nWilt u Jota installeren? + Geen bestandsbeheerder aangetroffen + Geen bestandsbeheerder gevonden om bestanden te openen. U kunt OI Bestandsbeheer of een andere bestandsbeheerder installeren om dit af te handelen.\n\nWilt u OI Bestandsbeheer installeren? + + + Tcpdump + Tcpdump is een hulpmiddel om DNS-verzoeken te bekijken en deze op te slaan in een logbestand. U kunt het in de achtergrond starten, een app met reclames gebruiken, en achteraf de DNS-verzoeken analyseren middels het logbestand. Mogelijke reclameservers kunnen dan aan uw zwarte lijst worden toegevoegd. + Monitoring uitschakelen + Monitoring inschakelen + Laat resultaat zien + Sorteer domeinen + Wis log + Host toevoegen aan blacklist + Host toevoegen aan whitelist + Hostdoorschakeling toevoegen + + Wijzig tekst voorkeurswaarde + Menu openen + Menu sluiten + + + + Startpagina + Hosts-bronnen + Mijn lijsten + Hosts-bestand openen + Log DNS verzoeken + Scan op Adware + Voorkeuren + Help + + + + + DNS verzoeken + Mijn lijsten + Voorkeuren + + + %1$s geleden toegepast + Up-to-date van %1$s + Update nodig van%1$s + Laatste update %1$s geleden + Onbekende update status + Uitgeschakeld + enkele minuten + + %d minuten + %d minuten + + + %duren + %duren + + + %d dagen + %d dagen + + + %dmaanden + %dmaanden + + + + Host gekopieerd naar het klembord. + + + bezig met starten + actief + bezig met stoppen + wachten op een netwerk + bezig met herverbinden + fout tijdens herverbinden + onderbroken + gestopt + Advertentieblokkering-VPN %1$s + Onderbreken + Hervat + + + AdAway rechten + Toestaan om samen te werken met AdAway + Zend opdrachten naar AdAway + Toestaan om opdrachten te verzenden naar AdAway zoals het aan- of uitzetten van de advertentieblokkering + + diff --git a/app/src/main/res/values-nl/strings_app.xml b/app/src/main/res/values-nl/strings_app.xml new file mode 100644 index 0000000..f0edac1 --- /dev/null +++ b/app/src/main/res/values-nl/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Open source advertentieblokkeerder + AdAway logo + diff --git a/app/src/main/res/values-nl/strings_errors.xml b/app/src/main/res/values-nl/strings_errors.xml new file mode 100644 index 0000000..5e48de2 --- /dev/null +++ b/app/src/main/res/values-nl/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Geen internetverbinding + Er kan geen verbinding worden gemaakt met het internet. Controleer uw internetverbinding. + De hosts-bron kan niet worden opgehaald + Geen van de geselecteerde hosts-bronnen zijn bereikbaar. Controleer uw internetverbinding. + + Het privébestand kan niet worden aangemaakt + Het privébestand, dat nodig is voor de nieuwe hosts-bron, kan niet worden aangemaakt. Controleer of u beschikt over voldoende schijfruimte. + Onvoldoende ruimte + Het hosts-bestand kan niet worden gekopieerd naar de systeempartitie. Controleer of de systeemloze module van Magisk is geactiveerd en herstart uw apparaat. + Het nieuwe hosts-bestand kan niet worden toegepast + Het hosts-bestand kan niet worden gekopieerd naar de /system-partitie. Controleer of de systeemloze module van Magisk is geactiveerd en herstart uw apparaat. + Het hosts-bestand kan niet worden teruggezet + Het standaard hosts-bestand kan niet worden teruggezet. + + De VPN kan niet worden ingeschakeld. + Controleer uw VPN-instellingen en geef toestemming om de VPN applicatie te mogen starten. + De VPN kan niet worden uitgeschakeld. + Controleer uw VPN-instellingen en schakel deze handmatig uit. + diff --git a/app/src/main/res/values-nl/strings_home.xml b/app/src/main/res/values-nl/strings_home.xml new file mode 100644 index 0000000..3bb1762 --- /dev/null +++ b/app/src/main/res/values-nl/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Geblokkeerd + Toegestaan + Doorverwezen + + + + %d up-to-date bron + %d up-to-date bronnen + + + %d verouderde bron + %d verouderde bronnen + + Controleer op host updates + Hosts bijwerken + + + Toon DNS request log + + + Toon help\nand tips + + + GitHub-pagina openen + + + Project steunen + + + GitHub project + Instellingen + + + Navigatiemenu openen + Advertentieblokkering onderbreken/hervatten + Geblokkeerde domeinen bijwerken + Domeinaanvragen tonen + + + Bekijk de hulpsectie voor meer informatie. + + diff --git a/app/src/main/res/values-nl/strings_hosts.xml b/app/src/main/res/values-nl/strings_hosts.xml new file mode 100644 index 0000000..b786f5d --- /dev/null +++ b/app/src/main/res/values-nl/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Hosts-bronnen + + Gebruikerslijst + AdAway official hosts + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + niet beschikbaar + %s hosts + + Bron toevoegen + Bron aanpassen + URL: (een bron beginnend met https:// of file://) + De url van de hosts-bron + diff --git a/app/src/main/res/values-nl/strings_lists.xml b/app/src/main/res/values-nl/strings_lists.xml new file mode 100644 index 0000000..94442de --- /dev/null +++ b/app/src/main/res/values-nl/strings_lists.xml @@ -0,0 +1,24 @@ + + + Mijn lijsten + Host toevoegen + + Geblokkeerd + Toegestaan + Doorverwezen + + Hosts filteren + Zoek hostnaam… + Wissel van bronnen + + Host toevoegen aan zwarte lijst + Host toevoegen aan witte lijst + Hostdoorschakeling toevoegen + Host op zwarte lijst bewerken + Host op witte lijst bewerken + Doorverwijzing bewerken + Hostnaam: + De url van de hosts-bron + (jokertekens * en ? zijn toegestaan) + IP-adres (IPv4 of IPv6): + diff --git a/app/src/main/res/values-nl/strings_log.xml b/app/src/main/res/values-nl/strings_log.xml new file mode 100644 index 0000000..a889068 --- /dev/null +++ b/app/src/main/res/values-nl/strings_log.xml @@ -0,0 +1,11 @@ + + + Schakelaar Log opslaan + Druk op \"record\" om de aanvragen te loggen, surf het web of gebruik apps, kom dan terug of swipe om de logs te vernieuwen. + \n\nBlocked aanvragen worden niet gelogd. Schakel advertentieblokkering eerst uit als je deze ook wilt gaan loggen. + + Sorteer alfabetisch + Bovenste niveau domein sortering + + Doorverwijzingsdomein + diff --git a/app/src/main/res/values-nl/strings_notification.xml b/app/src/main/res/values-nl/strings_notification.xml new file mode 100644 index 0000000..7914ce5 --- /dev/null +++ b/app/src/main/res/values-nl/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Updates + Updatemeldingen + Er is een bronupdate beschikbaar + Er zijn nieuwere hosts-bestanden beschikbaar. + Er is een app-update beschikbaar + Er is een nieuwe versie van AdAway beschikbaar. + + VPN + VPN-meldingen + \ No newline at end of file diff --git a/app/src/main/res/values-nl/strings_prefs_backup_restore.xml b/app/src/main/res/values-nl/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..d8447f9 --- /dev/null +++ b/app/src/main/res/values-nl/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Backup & restore + Backup + Backup je blokkeerregels naar een externe locatie + Restore + Restore je blokkeerregels vanuit een backup bestand + diff --git a/app/src/main/res/values-nl/strings_prefs_main.xml b/app/src/main/res/values-nl/strings_prefs_main.xml new file mode 100644 index 0000000..4fff27a --- /dev/null +++ b/app/src/main/res/values-nl/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Instellingen + + Algemeen + Donker thema + + Licht + Donker + Systeem default + + Automatisch bijwerken + + Advertentieblokkering + Advertentieblokkeerder voor geroote apparaten + Advertentieblokkering op basis van VPN + IPv6-ondersteuning inschakelen + Backup/herstel blokkaderegels + + Foutopsporing + Crashverslagen versturen + Melden aan Sentry (sentry.io) + Niet ondersteund in deze bouwversie + Uitgebreid logboek + Herstart de app om toe te passen + diff --git a/app/src/main/res/values-nl/strings_prefs_root.xml b/app/src/main/res/values-nl/strings_prefs_root.xml new file mode 100644 index 0000000..34af218 --- /dev/null +++ b/app/src/main/res/values-nl/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Advertentieblokkeerder voor geroote apparaten + + Host installeren + Hosts-bestand openen + Locatie van hosts-bestand + Lees Help voordat je deze functie gebruikt + + /system/etc/hosts + /data/hosts + /data/data/hosts + Aangepaste locatie + + Aangepaste doellocatie + Verberg herstart dialoogscherm + + Doorverwijzing + Bepaal waar de geblokkeerde hosts naar moeten worden omgeleid + IPv4 doorverwijzing + IPv6 doorverwijzing + Ongeldige doorverwijzing + + Lokale webserver + De lokale webserver luistert naar lokale ip-adressen om aanvragen van geblokkeerde hostnamen te beantwoorden. indien de connectie blokkeert kan app freezing helpen. + Webserver inschakelen + Test webserver + Installeer zelf ondertekend certificaat + Installeer certificaten handmatig + Vanaf Android 11 (R), applicaties kunnen niet meer automatisch geautoriseerde certificaten (CA) installeren.\n\nGa naar \"Beveiliging\" in settings, \"Encrypty & credentials\" en dan \"Installeer een certificaat\". Vanaf daar kies voor \"CA certificaat\" en selecteer het nieuwe geëxporteerde certificaat bestand. + Open \"Beveiliging\" in settings + Controleer… + Niet actief + Actief maar certificaat is niet geinstalleerd + Actief en certificaat is geinstalleerd + Vervang lege advertentieruimte met app incon + diff --git a/app/src/main/res/values-nl/strings_prefs_update.xml b/app/src/main/res/values-nl/strings_prefs_update.xml new file mode 100644 index 0000000..2107464 --- /dev/null +++ b/app/src/main/res/values-nl/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Updates + Notificaties zijn uitgeschakeld + Applicatie notificaties zijn niet zichtbaar. Tik om in te schakelen. + + App-updates + Controleer voor updates tijdens opstarten + Regelmatig controleren op updates + Inclusief beta releases + + Hosts-updates + Controleer voor updates tijdens opstarten + Regelmatig controleren op updates + Synchroniseren na updates + Alleen synchroniseren via Wi-Fi + diff --git a/app/src/main/res/values-nl/strings_prefs_vpn.xml b/app/src/main/res/values-nl/strings_prefs_vpn.xml new file mode 100644 index 0000000..2a9a010 --- /dev/null +++ b/app/src/main/res/values-nl/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Advertentieblokkering op basis van VPN + + Inschakelen bij opstarten + Controleer verbinding + Controleer periodiek de netwerkstatus om VPN te herstarten bij disconnectie + + Uitgesloten applicaties + Geef aan welke applicaties niet VPN mogen gebruiken zodat er geen connecties zullen worden geblokkeerd. + Uitgesloten systeem applicaties + + None + All except browsers + All + + Uitgesloten gebruiker applicaties + + + Uitgesloten applicaties + Selecteer alles + Deselecteer alles + Applicatie icon + diff --git a/app/src/main/res/values-nl/strings_source_edit.xml b/app/src/main/res/values-nl/strings_source_edit.xml new file mode 100644 index 0000000..a00c441 --- /dev/null +++ b/app/src/main/res/values-nl/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Bron aanpassen + Bron toevoegen + + Label + Label verplicht + Type + URL + Bestand + Locatie + https:// + Locatie verplicht + Druk op bestand om het bronbestand te selecteren + Ongeldige locatie + Lijst format + Blokkeer + Toestaan + Doorverwezen hosts toepassen + Het toestaan van doorverwezen hosts kan beveiligingsproblemen veroorzaken. Gebruik deze instelling alleen bij een vertrouwde bron want het kan gevoelig verkeer doorsturen naar elke willekeurige server. + diff --git a/app/src/main/res/values-nl/strings_support.xml b/app/src/main/res/values-nl/strings_support.xml new file mode 100644 index 0000000..77ef4bb --- /dev/null +++ b/app/src/main/res/values-nl/strings_support.xml @@ -0,0 +1,5 @@ + + + Ondersteuning + Wordt sponsor + \ No newline at end of file diff --git a/app/src/main/res/values-nl/strings_update.xml b/app/src/main/res/values-nl/strings_update.xml new file mode 100644 index 0000000..0386ad4 --- /dev/null +++ b/app/src/main/res/values-nl/strings_update.xml @@ -0,0 +1,21 @@ + + + AdAway update + + Update beschikbaar! + + + Je bent up-to-date + Er is een update beschikbaar + Updating AdAway + Update nu + %1$s / %2$s + Laatste wijzigingen + Wijzigingslog + Steun de ontwikkeling + Doneren + Sponsor + + + Downloading nieuwste AdAway versie… + diff --git a/app/src/main/res/values-nl/strings_welcome.xml b/app/src/main/res/values-nl/strings_welcome.xml new file mode 100644 index 0000000..ebda2e3 --- /dev/null +++ b/app/src/main/res/values-nl/strings_welcome.xml @@ -0,0 +1,54 @@ + + + Welkom + Wizard 1e stap + Wizard 2e stap + Wizard 3e stap + + + Welkom bij AdAway! + AdAway biedt twee blokkeermethoden aan. Kies de gewenste methode: + + Rootlogo + Blokkering op basis van root + Sneller + Bespaart accu + Root vereist + + VPN-logo + Blokkering op basis van VPN + Langzamer + Actief op de achtergrond + Comptabiliteit + + Geroote Android vereist + De su-binary is niet aangetroffen of u heeft AdAway geen roottoegang verleend.\n\nDit komt voor als uw apparaat niet geroot is. Informatie over het rooten van uw apparaat vindt u op wiki.lineageos.org of andere Android-websites. + + Voordeel + Nadeel + + + Synchroniseren voltooid + Fout tijdens synchronisatie + + Bezig met synchroniseren + Gesynchroniseerd! + AdAway haalt reclamenetwerken op uit online-bronnen. U kunt deze later aanpassen in de instellingen. + Opnieuw proberen + 81%match +Het synchroniseren is mislukt: %1$s Wilt u het opnieuw proberen? + Het kan notificaties sturen om de blokkeerstatus te laten zien en te controleren, je op de hoogte stellen van een bestaande app update (een paar per jaar). Schakel in als je up-to-date wilt blijven. + + + Ondersteuning + Ondersteun mij! + AdAway is een gratis en open-source app dat ik ontwikkel in mijn vrije tijd. Als je het dus leuk vindt, voel je vrij om je support te laten zien: + Doneren via PayPal + Houdt u van bugs? Nee, ik ook niet. + Schakel telemetrie in om crashverslagen te sturen + + + Vorige + Volgende + Afronden + diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml new file mode 100644 index 0000000..34f3724 --- /dev/null +++ b/app/src/main/res/values-no/strings.xml @@ -0,0 +1,24 @@ + + + + Lukk + Lukk + Ja + Nei + Legg til + Avbryt + Lagre + Alle vertsfiler fra valgte kilder er nedlastet, legg dem sammen med din egen liste og installer som en vertsfil. + Legg til + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-no/strings_app.xml b/app/src/main/res/values-no/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-no/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-no/strings_errors.xml b/app/src/main/res/values-no/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-no/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-no/strings_home.xml b/app/src/main/res/values-no/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-no/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-no/strings_hosts.xml b/app/src/main/res/values-no/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-no/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-no/strings_lists.xml b/app/src/main/res/values-no/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-no/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-no/strings_log.xml b/app/src/main/res/values-no/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-no/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-no/strings_notification.xml b/app/src/main/res/values-no/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-no/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-no/strings_prefs_backup_restore.xml b/app/src/main/res/values-no/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-no/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-no/strings_prefs_main.xml b/app/src/main/res/values-no/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-no/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-no/strings_prefs_root.xml b/app/src/main/res/values-no/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-no/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-no/strings_prefs_update.xml b/app/src/main/res/values-no/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-no/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-no/strings_prefs_vpn.xml b/app/src/main/res/values-no/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-no/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-no/strings_support.xml b/app/src/main/res/values-no/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-no/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-no/strings_update.xml b/app/src/main/res/values-no/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-no/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-no/strings_welcome.xml b/app/src/main/res/values-no/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-no/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml new file mode 100644 index 0000000..9e45587 --- /dev/null +++ b/app/src/main/res/values-pa/strings.xml @@ -0,0 +1,14 @@ + + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-pa/strings_app.xml b/app/src/main/res/values-pa/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-pa/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-pa/strings_errors.xml b/app/src/main/res/values-pa/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-pa/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-pa/strings_home.xml b/app/src/main/res/values-pa/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-pa/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-pa/strings_hosts.xml b/app/src/main/res/values-pa/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-pa/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-pa/strings_lists.xml b/app/src/main/res/values-pa/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-pa/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-pa/strings_log.xml b/app/src/main/res/values-pa/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-pa/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-pa/strings_notification.xml b/app/src/main/res/values-pa/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-pa/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-pa/strings_prefs_backup_restore.xml b/app/src/main/res/values-pa/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-pa/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-pa/strings_prefs_main.xml b/app/src/main/res/values-pa/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-pa/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-pa/strings_prefs_root.xml b/app/src/main/res/values-pa/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-pa/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-pa/strings_prefs_update.xml b/app/src/main/res/values-pa/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-pa/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-pa/strings_prefs_vpn.xml b/app/src/main/res/values-pa/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-pa/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-pa/strings_support.xml b/app/src/main/res/values-pa/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-pa/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-pa/strings_update.xml b/app/src/main/res/values-pa/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-pa/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-pa/strings_welcome.xml b/app/src/main/res/values-pa/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-pa/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml new file mode 100644 index 0000000..669971a --- /dev/null +++ b/app/src/main/res/values-pl/strings.xml @@ -0,0 +1,270 @@ + + + + WyjÅ›cie + Zamknij + Tak + Nie + Dodaj + Anuluj + Zapisz + Pomoc + + + Witamy! + AdAway to darmowy i otwarty program do blokowania reklam. Pobiera adresy sieci reklamowych, aby zablokować je na urzÄ…dzeniu.\nChcesz wiedzieć wiÄ™cej? Sprawdź pomoc poniżej! + Pokaż wiÄ™cej pomocy + Stan aktualizacji + Wszystkie pliki ze zdefiniowanych źródeÅ‚ zostanÄ… pobrane, połączone z twojÄ… listÄ… i dodane do pliku hosts. + Włącz blokowanie reklam + Wyłącz blokowanie reklam + Serwer internetowy + Uruchomiony + Zatrzymany + Uruchom lub zatrzymaj webserver na localhost, aby odpowiedzieć na proÅ›by o zablokowanie nazwy hostów. + Włącz serwer www + Wyłącz serwer www + VPN + Uruchomiony + Zatrzymany + Uruchom lub zatrzymaj VPN, aby filtrować żądania. + Włącz VPN + Wyłącz VPN + + + Edytuj wpis + Zastosuj + Edytuj + UsuÅ„ + + + Importowanie… + Kopia zapasowa zostaÅ‚a pomyÅ›lnie zaimportowana z pamiÄ™ci zewnÄ™trznej. + Nie udaÅ‚o siÄ™ zaimportować kopii zapasowej. Czy jego format jest poprawny? Sprawdź logat, aby uzyskać wiÄ™cej szczegółów. + Eksportowanie… + Kopia zapasowa zostaÅ‚a pomyÅ›lnie wyeksportowana do pliku \'%s\' w pamiÄ™ci zewnÄ™trznej. + Nie udaÅ‚o siÄ™ wyeksportować pliku kopii zapasowej \'%s\'. + + + Plik hosts + Plik hosts jest plikiem systemowym, który mapuje nazwy hostów na adresy IP. Jest to plik tekstowy, którego konfiguracja jest obsÅ‚ugiwana przez AdAway. Oto kilka pierwszych linii: + Åadowanie zawartoÅ›ci pliku hosts… + Otwórz plik hosts + + + Sprawdzanie aktualizacji + Sprawdzam %s źródÅ‚o aktualizacji + Pobieranie źródeÅ‚ + Pobieranie źródÅ‚a %s + Czytanie źródÅ‚a %s + Parsowanie źródÅ‚a %s + Synchronizacja reguÅ‚ bazy danych + Przywracanie domyÅ›lnego pliku hosts + Przywrócono domyÅ›lny plik hosts + Tworzenie standardowego pliku hosts + Aktualizacja jest dostÄ™pna + Nowe pliki hostów sÄ… dostÄ™pne + Nie znaleziono aktualizacji źródeÅ‚ + Brak połączenia z Internetem + Połączenie z Internetem niedostÄ™pne + ŹródÅ‚a niedostÄ™pne + Wszystkie źródÅ‚a sÄ… nieosiÄ…galne! + Odmowa dostÄ™pu do root + Zezwól na dostÄ™p root z aplikacji root + CoÅ› poszÅ‚o nie tak + Sprawdź kod logcat, aby uzyskać wiÄ™cej informacji + Włączone + Najnowsze pliki hostów zostaÅ‚y włączone + Wyłączone + DomyÅ›lny plik hosts zostaÅ‚ zainstalowany + Stosowanie najnowszych źródeÅ‚ + Tworzenie nowego pliku hostów + Kopiowanie nowego pliku hostów + Sprawdzanie kopii pliku hostów + Plik hosts zostaÅ‚ pomyÅ›lnie zaktualizowany + Konfiguracja VPN zostaÅ‚a zaktualizowana + Twoja konfiguracja zostaÅ‚a zmieniona. Musisz jÄ… zastosować. + Zastosuj + Zastosowanie nowej konfiguracji… + Nie można zastosować nowej konfiguracji. + + + Brak dowiÄ…zania symbolicznego do docelowego pliku hosts + Symlink z Twojego celu do /system/etc/hosts nie istnieje lub nie jest poprawny! AdAway nie bÄ™dzie dziaÅ‚ać jeÅ›li nie jest wskazany poprawny plik.\n\n Czy chcesz spróbować stworzyć symlink? + Brak symlinka + Za maÅ‚o miejsca na partycji!\nSpróbuj zmienić docelowy plik hosts w ustawieniach do /data/data/hosts. + Zbyt maÅ‚o miejsca + Pobrany plik nie może zostać odczytany. + Błąd pliku osobistego + Zamontowanie partycji do odczytu/zapisu nieudane! + Montowanie nieudane + Nie można skopiować pliku hostów + Kopiowanie pliku hosts nieudane! + Nieudane kopiowanie + Zastosowane źródÅ‚a hostów + Zastosowano pomyÅ›lnie + ZgÅ‚oszenie powiodÅ‚o siÄ™.\nMoże być konieczne ponowne uruchomienie Androida, aby zmiany zaczęły obowiÄ…zywać.\n\nCzy chcesz zrestartować system?\n(Aby zapobiec utracie danych, upewnij siÄ™, że żadna aplikacja nie używa karty SD!) + Symlink zostaÅ‚ utworzony pomyÅ›lnie.\nMoże być konieczne ponowne uruchomienie Androida, aby zmiany zaczęły obowiÄ…zywać.\n\nCzy chcesz zrestartować system?\n(Aby zapobiec utracie danych, upewnij siÄ™, że żadna aplikacja nie używa karty SD!) + Symlink utworzony prawidÅ‚owo + Symlink nie mógÅ‚ być utworzony przez system Android.\nBłąd ten wystÄ™puje głównie na telefonach HTC z \'funkcjÄ…\' zwanÄ… S-ON!\n\nRozwiÄ…zaniem jest uruchomienie w trybie recovery i rÄ™czne utworzenie symlinka komendÄ… \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nJeżeli to nie pomaga poszukaj w Internecie informacji o S-OFF i Twoim telefonie. + Symlink nie zostaÅ‚ utworzony + ProszÄ™ przeczytać Pomoc, aby uzyskać wiÄ™cej informacji. + Serwer proxy APN jest ustawiony na twoim Androidzie!\nAdAway nie bÄ™dzie dziaÅ‚ać niezawodnie w sieciach komórkowych takich jak 3G. Możesz wyłączyć ten serwer proxy, przechodzÄ…c do wybranego APN (z poziomu aplikacji Ustawienia: Sieć i Internet -> Sieć komórkowa -> Zaawansowane -> Punkty dostÄ™pu) i usuÅ„ wartość z pola proxy. + Ustawione proxy APN! + Połączenie z SieciÄ… jest niedostÄ™pne. + Brak połączenia + Pobieranie… + Stosowanie… + Stosowanie Czarnej i BiaÅ‚ej listy + Analizowanie i łączenie plików hosts + Budowanie pliku hosts + Stosowanie pliku hosts + Nie można zastosować nowego pliku hostów. + Stosowanie pliku hosts zakoÅ„czone niepowodzeniem!\nSpróbuj zmienić w ustawieniach plik docelowy hosts na /data/data/hosts. + Zastosowanie nieudane + Sprawdź aplikacjÄ™ zarzÄ…dzania rootem, aby upewnić siÄ™, że przyznano dostÄ™p root. + PowróciÅ‚eÅ› do domyÅ›lnego pliku hosts.\nMoże być konieczne ponowne uruchomienie Androida, aby zmiany zaczęły obowiÄ…zywać.\n\nCzy chcesz zrestartować system?\n(Aby zapobiec utracie danych, upewnij siÄ™, że żadna aplikacja nie używa karty SD!) + Przywracanie wykonane prawidÅ‚owo + Nie można przywrócić pliku hostów + Przywracanie zakoÅ„czone niepowodzeniem z nieznanych przyczyn. + Przywracanie nieudane! + Wszystkie włączone źródÅ‚a sÄ… nieosiÄ…galne! Czy na pewno masz połączenie z Internetem? + Pobieranie nieudane + Nie można zapisać nowego pliku hostów prywatnych + Plik osobisty nie zostaÅ‚ utworzony. + Tworzenie pliku osobistego nieudane + WłączyÅ‚eÅ› tryb bez systemu.\nMoże być konieczne ponowne uruchomienie Androida, aby zmiany zaczęły obowiÄ…zywać.\n\nCzy chcesz zrestartować system?\n(Aby zapobiec utracie danych, upewnij siÄ™, że żadna aplikacja nie używa karty SD!) + PomyÅ›lnie włączono + WyłączyÅ‚eÅ› tryb bez systemu.\nMoże być konieczne ponowne uruchomienie Androida, aby zmiany zaczęły obowiÄ…zywać.\n\nCzy chcesz zrestartować system?\n(Aby zapobiec utracie danych, upewnij siÄ™, że żadna aplikacja nie używa karty SD!) + Wyłączono poprawnie + Nie można włączyć blokowania reklam VPN. + Nie można wyłączyć blokowania reklam VPN. + Włączanie moduÅ‚u Magisk dla hostów + Włącz funkcjÄ™ hostów bezsystemowych w menedżerze Magisk. W ustawieniach włącz opcjÄ™ Hosty bez systemu, a nastÄ™pnie uruchom ponownie urzÄ…dzenie. + Wyłączanie moduÅ‚u Magisk hostów + Wyłącz funkcjÄ™ bezsystemowych hostów w menedżerze Magisk. Z listy modułów odinstaluj moduÅ‚ Hosty bez systemu, a nastÄ™pnie uruchom ponownie urzÄ…dzenie. + + + Dopisz adres URL do pliku hosts: + To jest nieprawidÅ‚owa nazwa hosta! + Niepoprawna nazwa hosta + To nie jest prawidÅ‚owy adres IP! + Niepoprawny adres IP + Nigdy nie restartuj i nie pokazuj tego pytania ponownie! + Åadowanie… + + + OdÅ›wież + Dodaj + Pomoc + Importuj kopiÄ™ zapasowÄ… + Eksportuj kopiÄ™ zapasowÄ… + + + S-ON/S-OFF + FAQ + Problemy + + + Adware + Tutaj możesz znaleźć zainstalowane adware, zÅ‚e aplikacje, które nie mogÄ… być blokowane przez AdAway. Te aplikacje używajÄ… na przykÅ‚ad powiadomieÅ„ Airpush, które pojawiajÄ… siÄ™ nawet wtedy, gdy aplikacja nie dziaÅ‚a lub nawet zmienia dzwonek. Jedynym dostÄ™pnym Å›rodkiem zaradczym jest odinstalowanie tych aplikacji, klikajÄ…c elementy listy. + Skanowanie… + Nie znaleziono adware! + + + Bloker reklam + Brak zainstalowanego edytora tekstu + Nie odnaleziono edytora tekstu aby otworzyć plik hosts. Możesz zainstalować edytor Jota lub inny edytor tekstu żeby tego dokonać./n/nCzy chcesz zainstalować Jota? + Brak zainstalowanego menedżera plików + Nie znaleziono menadżera plików aby otworzyć plik. Możesz zainstalować OI File Manager lub inne menadżery plików.\n\nCzy chcesz zainstalować OI File Manager? + + + Tcpdump + Tcpdump jest narzÄ™dziem do monitorowania żądaÅ„ DNS i zapisywania ich w pliku dziennika. Możesz go uruchomić w tle, uruchomić aplikacjÄ™, która wyÅ›wietla reklamy, a nastÄ™pnie przeanalizować zapisany dziennik żądaÅ„ DNS. Ewentualny serwer reklam można nastÄ™pnie dodać do twojej Czarnej listy. + Wyłącz monitorowanie + Włącz monitorowanie + Pokaż wyniki + Sortuj domeny + Wyczyść dziennik + Dodaj wpis do czarnej listy + Dodaj wpis do biaÅ‚ej listy + Dodaj wpis do listy przekierowaÅ„ + + Edytuj wartość preferencji tekstu + Otwórz menu + Zamknij menu + + + + Ekran główny + ŹródÅ‚a hostów + Twoje listy + Otwórz plik hosts + Rejestruj żądania DNS + Skanuj w poszukiwaniu Adware + Ustawienia + Pomoc + + + + + Żądania DNS + Twoje listy + Ustawienia + + + Zainstalowano %1$s temu + Aktualne dla %1$s + Potrzebujesz aktualizacji dla %1$s + Ostatnia aktualizacja %1$s temu + Nieznany status aktualizacji + Wyłączone + kilka minut + + %d minuta + %d minuty + %d minut + %d minut + + + %d godzina + %d godziny + %d godzin + %d godzin + + + %d dzieÅ„ + %d dni + %d dni + %d dni + + + %d miesiÄ…c + %d miesiÄ…ce + %d miesiÄ™cy + %d miesiÄ™cy + + + + Host skopiowany do schowka + + + uruchamianie + aktywny + zatrzymanie + czekam na sieć + ponowne łączenie + błąd ponownego łączenia + Wstrzymany + Zatrzymany + Blokowanie reklam VPN %1$s + Wstrzymaj + Wznów + + + AdAway uprawnienia + Pozwól na interakcjÄ™ z AdAway + WyÅ›lij polecenia do AdAway + Zezwalaj na wysyÅ‚anie poleceÅ„ do AdAway, takich jak włączanie lub wyłączanie blokowania reklam w caÅ‚ym systemie + + diff --git a/app/src/main/res/values-pl/strings_app.xml b/app/src/main/res/values-pl/strings_app.xml new file mode 100644 index 0000000..52282d8 --- /dev/null +++ b/app/src/main/res/values-pl/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Bloker reklam typu open source + Logo AdAway + diff --git a/app/src/main/res/values-pl/strings_errors.xml b/app/src/main/res/values-pl/strings_errors.xml new file mode 100644 index 0000000..443ca4e --- /dev/null +++ b/app/src/main/res/values-pl/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Brak połączenia z Internetem + Nie można nawiÄ…zać połączenia z Internetem. Sprawdź podłączenie urzÄ…dzenia do sieci. + Nie można pobrać źródÅ‚a hostów + Å»adne z włączonych źródeÅ‚ hostów nie jest osiÄ…galne. Sprawdź, czy masz prawidÅ‚owe połączenie z Internetem. + + Nie udaÅ‚o siÄ™ utworzyć prywatnego pliku + Nie można utworzyć prywatnego pliku, aby zbudować nowe źródÅ‚o hostów. Sprawdź wolne miejsce dostÄ™pne w urzÄ…dzeniu. + Zbyt maÅ‚o miejsca + Nie można skopiować pliku hosts na partycjÄ™ systemowÄ…. Sprawdź, czy moduÅ‚ systemowy Magisk jest włączony, a nastÄ™pnie uruchom ponownie. + Nie udaÅ‚o siÄ™ zainstalować nowego pliku hosts + Nie można skopiować pliku hosts do /system partycji. ProszÄ™ sprawdzić czy moduÅ‚ Magisk niesystematyczny jest włączony, a nastÄ™pnie uruchom ponownie + Nie udaÅ‚o siÄ™ przywrócić pliku hostów + Nie można przywrócić domyÅ›lnej konfiguracji pliku hosts. + + Nie można włączyć blokowania reklam VPN. + Sprawdź ustawienia VPN, aby autoryzować aplikacjÄ™ VPN do uruchomienia. + Nie można wyłączyć blokowania reklam VPN. + Sprawdź ustawienia VPN, aby wyłączyć je rÄ™cznie. + diff --git a/app/src/main/res/values-pl/strings_home.xml b/app/src/main/res/values-pl/strings_home.xml new file mode 100644 index 0000000..318793d --- /dev/null +++ b/app/src/main/res/values-pl/strings_home.xml @@ -0,0 +1,50 @@ + + + + + Zablokowane + Dozwolone + Przekierowany + + + + %d aktualne źródÅ‚o + %d aktualne źródÅ‚a + %d aktualnych źródeÅ‚ + %d aktualne źródÅ‚a + + + %d nieaktualne źródÅ‚o + %d nieaktualne źródÅ‚a + %d nieaktualnych źródeÅ‚ + %d nieaktualnych źródeÅ‚ + + Sprawdź aktualizacje hostów + Zaktualizuj hosty + + + Pokaż dziennik żądaÅ„ DNS + + + Pokaż pomoc\i wskazówki + + + Otwórz stronÄ™ GitHub + + + Wsparcie projektu + + + Projekt GitHub + Ustawienia + + + Otwórz szufladÄ™ nawigacji + Wstrzymaj/wznów blokowanie reklam + Zaktualizuj zablokowane domeny + Pokaż żądane domeny + + + ProszÄ™ przeczytać Pomoc, aby uzyskać wiÄ™cej informacji. + + \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings_hosts.xml b/app/src/main/res/values-pl/strings_hosts.xml new file mode 100644 index 0000000..f3f4eb2 --- /dev/null +++ b/app/src/main/res/values-pl/strings_hosts.xml @@ -0,0 +1,17 @@ + + + ŹródÅ‚a hostów + + Lista użytkownika + Oficjalny plik hostów AdAway + Plik hostów StevenBlack Unified + Plik listy bloków hostów Pete Lowe + + niedostÄ™pny(e) + %s hostów + + Dodaj źródÅ‚o + Edytuj źródÅ‚o + Adres URL: (https:// lub plik:// zasób) + Adres URL źródÅ‚a hostów + diff --git a/app/src/main/res/values-pl/strings_lists.xml b/app/src/main/res/values-pl/strings_lists.xml new file mode 100644 index 0000000..91bf942 --- /dev/null +++ b/app/src/main/res/values-pl/strings_lists.xml @@ -0,0 +1,24 @@ + + + Twoje listy + Dodaj hosta + + Zablokowany + Dozwolone + Przekierowany + + Filtruj hosty + Wyszukaj nazwÄ™ hosta… + Przełącz źródÅ‚a + + Dodaj host do czarnej listy + Dodaj host do biaÅ‚ej listy + Dodaj przekierowanie hosta + Edycja hostów umieszczonych na czarnej liÅ›cie + Edycja hostów umieszczonych na biaÅ‚ej liÅ›cie + Edytuj przekierowanie + Nazwa hosta: + Adres URL źródÅ‚a hostów + (Znaki wieloznaczne * i ? sÄ… dozwolone) + IP (IPv4 lub IPv6): + diff --git a/app/src/main/res/values-pl/strings_log.xml b/app/src/main/res/values-pl/strings_log.xml new file mode 100644 index 0000000..6e053b4 --- /dev/null +++ b/app/src/main/res/values-pl/strings_log.xml @@ -0,0 +1,11 @@ + + + Przełącz rejestrowanie dziennika + NaciÅ›nij rekord, aby rozpocząć rejestrowanie żądaÅ„, przeglÄ…daj Internet lub korzystaj z aplikacji, a nastÄ™pnie wróć lub przesuÅ„ palcem, aby odÅ›wieżyć dzienniki. + \n\nZablokowane żądania nie bÄ™dÄ… rejestrowane. Najpierw wyłącz blokowanie reklam, jeÅ›li chcesz je również rejestrować. + + Sortuj alfabetycznie + Sortuj rosnÄ…co + + Przekieruj domenÄ™ + diff --git a/app/src/main/res/values-pl/strings_notification.xml b/app/src/main/res/values-pl/strings_notification.xml new file mode 100644 index 0000000..65e6288 --- /dev/null +++ b/app/src/main/res/values-pl/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Aktualizacje + Powiadomienia o nowych aktualizacjach + Aktualizacja jest dostÄ™pna + Nowsze pliki hostów sÄ… dostÄ™pne do pobrania. + DostÄ™pna aktualizacja aplikacji + Nowa wersja AdAway jest dostÄ™pna do pobrania. + + VPN + Powiadomienia o uruchomieniu sieci VPN + \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings_prefs_backup_restore.xml b/app/src/main/res/values-pl/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..ca85503 --- /dev/null +++ b/app/src/main/res/values-pl/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Przywracania kopii zapasowej & + Kopia zapasowa + Utwórz kopiÄ™ zapasowÄ… w pamiÄ™ci zewnÄ™trznej reguÅ‚ blokowania + Przywróć + Przywracanie reguÅ‚ bloku z pliku kopii zapasowej + diff --git a/app/src/main/res/values-pl/strings_prefs_main.xml b/app/src/main/res/values-pl/strings_prefs_main.xml new file mode 100644 index 0000000..e49c9eb --- /dev/null +++ b/app/src/main/res/values-pl/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Ustawienia + + Ogólne + WyglÄ…d motywu + + Jasny + Ciemny + DomyÅ›lne ustawienie systemowe + + Aktualizacje automatyczne + + Blokowanie reklam + Blokowanie reklam oparte na Root + Blokowanie reklam oparte na VPN + Włącz obsÅ‚ugÄ™ IPv6 + Kopia zapasowa / przywracanie zasad blokowania + + Debugowanie + WysyÅ‚aj raporty o awariach + ZgÅ‚oÅ› raport do Sentry (sentry.io) + NieobsÅ‚ugiwany w tej wersji + PeÅ‚ne rejestrowanie + Aby zastosować, konieczne jest ponowne uruchomienie aplikacji + diff --git a/app/src/main/res/values-pl/strings_prefs_root.xml b/app/src/main/res/values-pl/strings_prefs_root.xml new file mode 100644 index 0000000..9889758 --- /dev/null +++ b/app/src/main/res/values-pl/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Blokowanie reklam oparte na Root + + Instalacja Hosts + Otwórz plik hosts + Docelowy plik hosts + Zanim zmienisz to ustawienie, przeczytaj pomoc dotyczÄ…cÄ… tej funkcjonalnoÅ›ci. + + /system/etc/hosts + /data/hosts + /data/data/hosts + Niestandardowy plik docelowy + + Niestandardowy plik docelowy + Ukryj komunikat o restarcie + + Przekierowanie + OkreÅ›l, gdzie przekierować blokowanie hosts + Przekierowanie IPv4 + Przekierowanie IPv6 + NieprawidÅ‚owe przekierowanie + + Lokalny serwer www + Lokalny serwer WWW nasÅ‚uchuje na lokalnych adresach IP, aby odpowiedzieć na zablokowane żądania nazwy hosta. Może to pomóc w zawieszaniu siÄ™ aplikacji przy zablokowanym połączeniu. + Włącz serwer www + Przetestuj serwer WWW + Zainstaluj samopodpisany certyfikat + Instalacja rÄ™czna certyfikatu + PoczÄ…wszy od wersji Android 11 (R), aplikacja nie może już automatycznie instalować urzÄ™du certyfikacji (CA).\n\ nPrzejdź do ustawieÅ„ \"Zabezpieczenia\", \"Szyfrowanie i poÅ›wiadczenia\", a nastÄ™pnie \"Zainstaluj certyfikat\". StamtÄ…d wybierz \"Certyfikat CA\" i wybierz nowo wyeksportowany plik certyfikatu. + Otwórz ustawienia \"Zabezpieczenia\" + Sprawdzanie… + Nie uruchomiony + Uruchomiony, ale certyfikat nie zostaÅ‚ zainstalowany + Uruchamianie i instalowanie certyfikatu + ZastÄ…p puste miejsce reklamowe ikonÄ… aplikacji + diff --git a/app/src/main/res/values-pl/strings_prefs_update.xml b/app/src/main/res/values-pl/strings_prefs_update.xml new file mode 100644 index 0000000..0982568 --- /dev/null +++ b/app/src/main/res/values-pl/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Aktualizacje + Powiadomienia wyłączone + Powiadomienia nie pojawiÄ… siÄ™. Kliknij, aby włączyć je. + + Aktualizacje aplikacji + Sprawdź aktualizacjÄ™ podczas uruch + Szukaj codzieÅ„.. aktualizacji + UwzglÄ™dnij wersje beta + + Aktualizacje hostów + Sprawdź aktualizacjÄ™ na starcie + Szukaj aktualizacji co jakiÅ› czas + Synchronizuj podczas aktualizacji + Synchronizuj tylko w bezpÅ‚atnej sieci + diff --git a/app/src/main/res/values-pl/strings_prefs_vpn.xml b/app/src/main/res/values-pl/strings_prefs_vpn.xml new file mode 100644 index 0000000..333051c --- /dev/null +++ b/app/src/main/res/values-pl/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Blokowanie reklam oparte na VPN + + Włącz podczas uruchamiania + Monitoruj połączenie + Okresowo sprawdzaj stan sieci, aby ponownie uruchomić VPN po rozłączeniu. + + Wykluczone aplikacje + Skonfiguruj, które aplikacje nie powinny korzystać z VPN, aby żadne połączenia nie byÅ‚y blokowane. + Wyklucz aplikacje systemowe + + Å»adne + Wszystkie oprócz przeglÄ…darek + Wszystkie + + Wyklucz aplikacje użytkownika + + + Wykluczone aplikacje + Zaznacz wszystkie + Odznacz wszystkie + Ikona aplikacji + diff --git a/app/src/main/res/values-pl/strings_source_edit.xml b/app/src/main/res/values-pl/strings_source_edit.xml new file mode 100644 index 0000000..cd50060 --- /dev/null +++ b/app/src/main/res/values-pl/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Edytuj źródÅ‚o + Dodaj źródÅ‚o + + Etykieta + Wymagana etykieta + Typ + URL + Plik + Lokalizacja + https:// + Wymagana lokalizacja + Kliknij Plik, aby wybrać źródÅ‚o + NieprawidÅ‚owa lokalizacja + Format listy + Zablokuj + Zezwól + Zastosuj przekierowane hosty + Zezwalanie na przekierowanie hostów może powodować problemy z bezpieczeÅ„stwem. Używaj tego ustawienia tylko na zaufanym źródle, ponieważ może ono przekierować wrażliwy ruch na dowolny serwer. + diff --git a/app/src/main/res/values-pl/strings_support.xml b/app/src/main/res/values-pl/strings_support.xml new file mode 100644 index 0000000..e9fcd5b --- /dev/null +++ b/app/src/main/res/values-pl/strings_support.xml @@ -0,0 +1,5 @@ + + + Wsparcie + ZostaÅ„ sponsorem + \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings_update.xml b/app/src/main/res/values-pl/strings_update.xml new file mode 100644 index 0000000..a6db007 --- /dev/null +++ b/app/src/main/res/values-pl/strings_update.xml @@ -0,0 +1,21 @@ + + + Aktualizacja AdAway + + DostÄ™pna aktualizacja! + + + JesteÅ› na bieżąco + Aktualizacja jest dostÄ™pna + Aktualizowanie AdAway + Aktualizuj teraz + %1$s / %2$s + Ostatnie zmiany + Lista zmian + Wspieraj rozwój + Dotacja + Sponsor + + + Pobieram najnowszÄ… wersjÄ™ AdAway… + diff --git a/app/src/main/res/values-pl/strings_welcome.xml b/app/src/main/res/values-pl/strings_welcome.xml new file mode 100644 index 0000000..28c2485 --- /dev/null +++ b/app/src/main/res/values-pl/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Zapraszamy + Kreator pierwszy krok + Drugi krok kreatora + Ostatni krok kreatora + + + Witamy w AdAway! + AdAway zapewnia dwie metody blokowania reklam. Wybierz tÄ™, którÄ… lubisz: + + Logo Root + Blokowanie bazowane na Root + Szybciej + Przyjazny dla baterii + Wymagany root + + Logo VPN + Blokowanie przez VPN + Wolniej + Uruchom w tle + Zgodność + + Wymagany jest zrootowany Android + Nie można znaleźć pliku binarnego su lub nie zezwolono na uprawnienia roota dla AdAway.\n\nMoże to siÄ™ zdarzyć, gdy urzÄ…dzenie nie jest zrootowane. Informacje na temat rootowania urzÄ…dzenia można znaleźć na wiki.lineageos.org lub innych stronach o systemie Android. + + Plusy + Minusy + + + Synchronizacja zakoÅ„czona + Błąd podczas synchronizacji + + Synchronizacja + Zsynchronizowany! + AdAway pobiera sieci reklamowe w celu blokowania ze źródeÅ‚ internetowych. Możesz je później dostosować w ustawieniach. + Ponów synchronizacjÄ™ + Błąd synchronizacji: %1$s Powtórzyć? + Może wyÅ›wietlać powiadomienia o statusie AdAway i jego ustawieniach oraz informować o dostÄ™pnych aktualizacjach aplikacji (kilka w ciÄ…gu roku). Włącz, aby być na bieżąco. + + + Wsparcie + Wesprzyj mnie! + AdAway jest darmowÄ… aplikacjÄ… open-source, którÄ… rozwijam w wolnym czasie. JeÅ›li podoba Ci siÄ™, pomyÅ›l nad wsparciem projektu: + Darowizna na PayPal + Lubisz błędy? Ja też nie. + Włącz telemetriÄ™, aby wysyÅ‚ać mi raporty o awariach + + + Wstecz + Dalej + ZakoÅ„cz + diff --git a/app/src/main/res/values-ps/strings.xml b/app/src/main/res/values-ps/strings.xml new file mode 100644 index 0000000..55028e2 --- /dev/null +++ b/app/src/main/res/values-ps/strings.xml @@ -0,0 +1,211 @@ + + + + وتون + بندول + هو + نه + زیاتول + ړنګونه + ساتل + مرسته + + + ÚšÙ‡ راغلاست! + Ø§Ú‰Ø§ÙˆÛ Ø¯ Ø§Ø²Ø§Ø¯Û Ø³Ø±Ú†ÙŠÙ†Û ÛŒÙˆ وړیا ساوتری دی کوم Ú†Û Ø§Ù†Ú«Ø±ÙˆØ²ÙŠ تړي. دا د انګروزي شبکو Ù¾ØªÛ Ø§Ø®Ù„ÙŠ ترڅو Ø³ØªØ§Ø³Û Ù¾Ù‡ وزله ÙŠÛ ÙˆØªÚ“ÙŠ.n\نور معلومات غواړئ؟ د Ù…Ø±Ø³ØªÛ Ù„Ù¾Ø§Ø±Ù‡ Ù„Ø§Ù†Ø¯Û ÙˆÚ«ÙˆØ±Ø¦! + د Ù†ÙˆØ±Û Ù…Ø±Ø³ØªÛ ÚšÙˆØ¯Ù„ + د انګروزيو تړل سالول + د انګروزيو تړل بندول + ګورت پالنګر + ÚØºÙ„ÙŠ + ØªÙ…ÛØ¯Ù„ÛŒ + د تړل شويو hostnames غوښتنو ته Úواب ورکولو لپاره په localhost Ø¨Ø§Ù†Ø¯Û Ø¯ ګورت پالنګر پیلول او یا تمول + ګورت پالنګر سالول + ګورت پالنګر بندول + اوڅاریز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„ VPN + ÚØºÙ„ÙŠ + ØªÙ…ÛØ¯Ù„ÛŒ + د غوښتنو چاڼولو لپاره د اوڅاريز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„ پیلول او یا تمول + اوڅاریز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„ سالول + اوڅاریز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„ بندول + + + د ننوت سمون + كارونګ + سمون + ړنګول + + + راوړل… + شاتړ په بريالي توګه له Ø¨Ù‡Ø±Ù†Û Ø²ÛØ±Ù…Û Ø±Ø§ÙˆÚ“Ù„ شو. + د شاتړ راوړنه Ù†Ø§Ø¨Ø±ÙŠØ§Ù„Û Ø´ÙˆÙ‡. آیا Ø¯Ø¯Û Ø¨Ú¼Ù‡ سمه ده؟ د نورو معلوماتو لپاره logcat وګورئ. + وړل… + + hosts دوتنه + د hosts Ø¯ÙˆØªÙ†Û Ù…Ù†Úپانګه Ù„Ûښل… + د hosts دوتنه Ù¾Ø±Ø§Ù†ÛŒÚØ¦ + + + اوسمهالیز لپاره ګورو + Ø³Ø±Ú†ÙŠÙ†Û Ù¾Ù„Ù¼Ù„ + سرچينه رالÛÚšÙ„ %s + د hosts ØªÙ„ÙˆØ§Ù„Û Ø¯ÙˆØªÙ†Û ØªÙ‡ راګرÚول + د hosts تلواله دوتنه Ø¨ÛŒØ§Ø²ÛØ±Ù…Ù‡ شوه + د hosts کره دوتنه پنÚول + د Ø³Ø±Ú†ÙŠÙ†Û Ø§ÙˆØ³Ù…Ù‡Ø§Ù„ÙŠØ² شته + نوي hosts Ø¯ÙˆØªÙ†Û Ø´ØªÙ‡ + Ù‡ÛÚ… Ø³Ø±Ú†ÙŠÙ†Û Ø§ÙˆØ³Ù…Ù‡Ø§Ù„ÙŠØ² Ùˆ نه موندل شو + انټرنÛÙ¼ پیوستون نشته + انټرنÛÙ¼ پیوستون شتون نه لري + Ø³Ø±Ú†ÙŠÙ†Û Ù†Ø´ØªÙ‡ + Ù‡ÛÚ… hosts Ø³Ø±Ú†ÙŠÙ†Û ØªÙ‡ Ù„Ø§Ø³Ø±Ø³Û Ù†Ø´ØªÙ‡! + وليز Ù„Ø§Ø³Ø±Ø³Û ÙˆØ± نه Ú©Ú“Ù„ شو + د خپل ÙˆÙ„Û Ú©Ø§Ø±ÙŠØ§Ù„ نه د وليز لاسرسي پرÛÚšÙ„ÛŒ ورکړئ + یو Ú…Ù‡ ناسم وشول + د Ù†ÙˆØ±Û Ø³Ù¾Ú“Ù†Û Ù„Ù¾Ø§Ø±Ù‡ logcat وګورئ + سالول شوی + نوي hosts Ø¯ÙˆØªÙ†Û Ø³Ø§Ù„ÙˆÙ„ شوي + بند شوی + د hosts تلواله دوتنه ولګول شوه + ترټولو ÙˆØ±ÙˆØ³ØªÛ Ø³Ø±Ú†ÙŠÙ†Û Ú©Ø§Ø±ÙˆÙ†Ú« + يوه Ù†ÙˆÛ hosts دوتنه پنÚول + يوه Ù†ÙˆÛ hosts دوتنه Ù„Ù…ÛØ³Ù„ + د hosts Ø¯ÙˆØªÙ†Û Ù„Ù…ÛØ³Ù‡ کتل + hosts دوتنه په بريالي توګه اوسمهاله شوه + د اوڅاریز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„ سازونه په بريالي توګه اوسمهاله شو + Ø³ØªØ§Ø³Û Ø³Ø§Ø²ÙˆÙ†Û Ø¨Ø¯Ù„ÙˆÙ† وموند. ØªØ§Ø³Û Ø§Ú“ ÛŒØ§Ø³ØªÛ Ú†Û Ú©Ø§Ø±ÙˆÙ†Ú«Ù‡ ÙŠÛ Ú©Ú“Ø¦. + كارونګ + د Ù†ÙˆÛ Ø³Ø§Ø²ÙˆÙ†Û Ú©Ø§Ø±ÙˆÙ†Ú«â€¦ + د Ù†ÙˆÛ Ø³Ø§Ø²ÙˆÙ†Û Ù¾Ø± کارونګه کولو Ú©ÚšÛ Ù†Ø§Ø¨Ø±ÛŒØ§Ù„Û Ø´Ùˆ. + + symlink Ø¨Û Ø¯Ø±Ú©Ù‡ دی + تشه بس نه ده + رالÛÚšÙ„ Ø´ÙˆÛ Ø¯ÙˆØªÙ†Ù‡ لوستل Ú©ÛÚ–ÙŠ نه. + ÚØ§Ù†ÙŠ Ø¯ÙˆØªÙ†Ù‡ Ù†Ø§Ø¨Ø±ÙŠØ§Ù„Û Ø´ÙˆÙ‡ + د ÙˆÛØ´ Ø¨ÛŒØ§ÚØ§Ù†ÚšÙ„ول د لوستنÛ/Ù„ÙŠÚ©Ù†Û Ù¾Ù‡ توګه نابريالی شو! + Ø¨ÛŒØ§ÚØ§Ù†ÚšÙ„ون نابريالی شو + د hosts Ø¯ÙˆØªÙ†Û Ù„Ù…ÛØ³Ù„ نابريالي شو + د hosts Ø¯ÙˆØªÙ†Û Ù„Ù…ÛØ³Ù„ نابريالي شو! + Ù„Ù…ÛØ³Ù„ نابريالي شو + کارونګه Ø´ÙˆÛ hosts Ø³Ø±Ú†ÙŠÙ†Û + کارونګ بریالی شو + کارونګ بریالی شو.n\د بدلونونو د Ø§ØºÛØ²Ù…Ù† Ú©ÛØ¯Ùˆ لپاره ښايي Ú†Û Ø¯ انډروÛÚ‰ بیاپيلون اړین وي.n\n\آیا ØªØ§Ø³Û Ø¨ÛŒØ§Ù¾ÙŠÙ„ÙˆÙ„ غواړئ؟n\(د اومتوک د لاسه ورکولو د مخنيوي لپاره دا باوري کړئ Ú†Û Ø¯Ù… Ú«Ú“Û Ù‡ÛÚ… کاريال له یاد Ù¾Ø§Ú¼Û (SD کارټ) څخه ګټه نه اخلي!) + symlink په Ø¨Ø±ÙŠØ§Ù„Û ØªÙˆÚ«Ù‡ وپنÚول شو.n\د بدلونونو د Ø§ØºÛØ²Ù…Ù† Ú©ÛØ¯Ùˆ لپاره ښايي Ú†Û Ø¯ انډروÛÚ‰ بیاپيلون اړین وي.n\n\آیا ØªØ§Ø³Û Ø¨ÛŒØ§Ù¾ÙŠÙ„ÙˆÙ„ غواړئ؟n\(د اومتوک د لاسه ورکولو د مخنيوي لپاره دا باوري کړئ Ú†Û Ø¯Ù… Ú«Ú“Û Ù‡ÛÚ… کاريال له یاد Ù¾Ø§Ú¼Û (SD کارټ) څخه ګټه نه اخلي!) + د symlink پنÚونه Ø¨Ø±ÙŠØ§Ù„Û Ø´ÙˆÙ‡ + د symlink پنÚونه Ù†Ø§Ø¨Ø±ÙŠØ§Ù„Û Ø´ÙˆÙ‡ + مهرباني وکړئ، د لا نورو معلوماتو لپاره مرسته ولولئ. + يو رسي Ù¼Ú©ÙŠ نوم APN ګوډاګى Ø³ØªØ§Ø³Û Ù¾Ø± انډروÛÚ‰ Ø¨Ø§Ù†Ø¯Û Ø§Ù…Ø³ØªÙ„ شوی دی!n/Ø§Ú‰Ø§ÙˆÛ Ø¨Ù‡ پر ګرÚند شبکه لکه، 3جي، Ø¨Ø§Ù†Ø¯Û Ø¨Ø§ÙˆØ±ÙŠ کار Ùˆ نه Ú©Ú“ÙŠ. ØªØ§Ø³Û Ú©ÙˆÙ„Ø§ÛŒ شئ Ú†Û Ù‡ØºÙ‡ ګوډاګی ناچارند کړئ د خپل ټاکلي رسي Ù¼Ú©ÙŠ نوم ته په تګ سره (د امستنو کاريال نه: Network & Internet -> Mobile network -> Advanced -> Access Point Names) او بیا د ګوډاګي ډګر نه ارزښت Ù„ÛØ±Û کړئ. + رسي Ù¼Ú©ÙŠ نوم ګوډاګی امستل شو! + انټرنÛÙ¼ پيوستون کار نه کوي. + پیوستون نشته + رالÛښل… + كارونګ… + د تورلړ او سپینلړ کارونګ + د hosts Ø¯ÙˆØªÙ†Û ØªØ¬Ø²ÛŒÙ‡ کول او سره Ù†Ù†ÙˆÛØ³ØªÙ„ + د hosts Ø¯ÙˆØªÙ†Û Ø¬ÙˆÚ“ÙˆÙ„ + د hosts Ø¯ÙˆØªÙ†Û Ú©Ø§Ø±ÙˆÙ†Ú« + د نوي hosts Ø¯ÙˆØªÙ†Û Ù¾Ù‡ کارونګ Ú©Û Ù†Ø§Ø¨Ø±ÛŒØ§Ù„ÛŒ شو. + Ø³ØªØ§Ø³Û Ù¾Ø± غونډال Ú©ÚšÛ Ø¯ hosts Ø¯ÙˆØªÙ†Û Ú©Ø§Ø±ÙˆÙ†Ú« نابریالي شو!n\په غورتياوو Ú©ÚšÛ Ø¯ Ù…ÙˆØ®Û Ø¯ hosts Ø¯ÙˆØªÙ†Û Ø¨Ø¯Ù„ÙˆÙ„Ùˆ Ù‡Ú…Ù‡ وکړئ. + کارونګ نابریالي شو + ØªØ§Ø³Û Ø¯ hosts ØªÙ„ÙˆØ§Ù„Û Ø¯ÙˆØªÙ†Û ØªÙ‡ راوګرÚÛØ¯Ù„ئ.n\د بدلونونو د Ø§ØºÛØ²Ù…Ù† Ú©ÛØ¯Ùˆ لپاره ښايي Ú†Û Ø¯ انډروÛÚ‰ بیاپيلون اړین وي.n\n\آیا ØªØ§Ø³Û Ø¨ÛŒØ§Ù¾ÙŠÙ„ÙˆÙ„ غواړئ؟n\(د اومتوک د لاسه ورکولو د مخنيوي لپاره دا باوري کړئ Ú†Û Ø¯Ù… Ú«Ú“Û Ù‡ÛÚ… کاريال له یاد Ù¾Ø§Ú¼Û (SD کارټ) څخه ګټه نه اخلي!) + راګرÚول بریالي شو + راګرÚول نابریالي شو! + رالÛÚšÙ„ نابريالي شو + د نوي hosts Ø¯ÙˆØªÙ†Û Ù¾Ù‡ ليکنه Ú©ÚšÛ Ù†Ø§Ø¨Ø±ÙŠØ§Ù„ÛŒ شو + ÚØ§Ù†ÙŠ Ø¯ÙˆØªÙ†Ù‡ پنÚول Ú©ÛØ¯Ø§ÛŒ نه شي. + د ÚØ§Ù†ÙŠ Ø¯ÙˆØªÙ†Û Ù¾Ù†Úونه Ù†Ø§Ø¨Ø±ÙŠØ§Ù„Û Ø´ÙˆÙ‡ + ØªØ§Ø³Û Ø¨Û ØºÙˆÙ†Ú‰Ø§Ù„Ù‡ اکر سال Ú©Ú“.n\د بدلونونو د Ø§ØºÛØ²Ù…Ù† Ú©ÛØ¯Ùˆ لپاره ښايي Ú†Û Ø¯ انډروÛÚ‰ بیاپيلون اړین وي.n\n\آیا ØªØ§Ø³Û Ø¨ÛŒØ§Ù¾ÙŠÙ„ÙˆÙ„ غواړئ؟n\(د اومتوک د لاسه ورکولو د مخنيوي لپاره دا باوري کړئ Ú†Û Ø¯Ù… Ú«Ú“Û Ù‡ÛÚ… کاريال له یاد Ù¾Ø§Ú¼Û (SD کارټ) څخه ګټه نه اخلي!) + سالول بريالي شو + ØªØ§Ø³Û Ø¨Û ØºÙˆÙ†Ú‰Ø§Ù„Ù‡ اکر بند Ú©Ú“.n\د بدلونونو د Ø§ØºÛØ²Ù…Ù† Ú©ÛØ¯Ùˆ لپاره ښايي Ú†Û Ø¯ انډروÛÚ‰ بیاپيلون اړین وي.n\n\آیا ØªØ§Ø³Û Ø¨ÛŒØ§Ù¾ÙŠÙ„ÙˆÙ„ غواړئ؟n\(د اومتوک د لاسه ورکولو د مخنيوي لپاره دا باوري کړئ Ú†Û Ø¯Ù… Ú«Ú“Û Ù‡ÛÚ… کاريال له یاد Ù¾Ø§Ú¼Û (SD کارټ) څخه ګټه نه اخلي!) + بندول بريالي شو + د اوڅاريز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„ انګروزي تړنه سالول نابريالي شو. + د اوڅاريز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„ انګروزي تړنه بندول نابريالي شو. + د hosts Magisk رغبÛÙ„Ú«Ù‡ سالول + له Magisk سمبالګر نه د Ø¨Û ØºÙˆÙ†Ú‰Ø§Ù„Ù‡ hosts ÚØ§Ù†Ú«Ú“نه سال کړئ. Ø¯Ø¯Û Ø¯ امستنو نه د Systemless hosts غوراوى سال کړئ او خپله وزله بیاپيل کړئ. + د hosts Magisk رغبÛÙ„Ú«Ù‡ بندول + له Magisk سمبالګر نه د Ø¨Û ØºÙˆÙ†Ú‰Ø§Ù„Ù‡ hosts ÚØ§Ù†Ú«Ú“نه بنده کړئ. د رغبÛÙ„Ú«Ù‡ Ù„Ú“ نه د Systemless hosts رغبÛÙ„Ú«Ù‡ Ù„ÛØ±Û کړئ او خپله وزله بیاپيل کړئ. + + دا یو سم hostname نه دی!†+ ناسم بڼول شوی hostname + دا یوه سمه انټرنÛÙ¼ باندره (IP) نه ده! + ناسمه بڼول Ø´ÙˆÛ Ø§Ù†Ù¼Ø±Ù†ÛÙ¼ باندره + Ù„Ûښل… + + + تاندول + زیاتول + مرسته + شاتړ راوړنه + شاتړ وړنه + + بيابيا ÙƒÛØ¯ÙˆÙ†ÙƒÛ Ù¾ÙˆÚšØªÙ†Û + Ø³ØªÙˆÙ†Ø²Û + + + انګروزيز ساوتری + ÚÛØ±Ù„… + Ù‡ÛÚ… انګروزیز ساوتری Ùˆ نه موندل شو + + + انګروزی تړونکی + د متن بیاسمونګر نه دی لګول شوی + دوتنه سمبالګر نه دی لګول شوی + + tcpdump + څارنه بندول + څارنه سالول + پایلو ښودل + شپولو اڼل + خبرال پاکول + تور Ù„Ú“ Ú©ÚšÛ Ø¯ ننوت زیاتول + سپين Ù„Ú“ Ú©ÚšÛ Ø¯ ننوت زیاتول + ØºÙˆØ±Ù†Û Ù¾Ø±Ø§Ù†ÙŠÚØ¦ + ØºÙˆØ±Ù†Û Ø¨Ù†Ø¯Ù‡ کړئ + + + + کوربه Ø³Ø±Ú†ÙŠÙ†Û + Ø³ØªØ§Ø³Û Ù„Ú“ÙˆÙ†Ù‡ + د کوربانه دوتنه Ù¾Ø±Ø§Ù†ÛŒÚØ¦ + ØºÙˆØ±ØªÙŠØ§ÙˆÛ + مرسته + + Ø³ØªØ§Ø³Û Ù„Ú“ÙˆÙ†Ù‡ + ØºÙˆØ±ØªÙŠØ§ÙˆÛ + + + ولګول شو %1$s Ù…Ø®Ú©Û + + %dÙ¾ÛÙ„ + %dÙ¾Ûله + + + %dساعت + %dساعته + + + %dÙˆØ±Ú + %dورÚÛ + + + %dمیاشت + %dÙ…ÛŒØ§Ø´ØªÛ + + + + Ù¾ÙŠÙ„ÛØ¯Ù„ + چارنده + ØªÙ…ÛØ¯Ù„ + Ø´Ø¨Ú©Û ØªÙ‡ په ÚØ§Ø± شئ + بياپيوستل + بياپيوستلو Ú©ÚšÛ ØªÛØ±ÙˆØªÙ†Ù‡ + ÚÙ†Ú‰ÛØ¯Ù„ÛŒ + ØªÙ…ÛØ¯Ù„ÛŒ + انګروزی تړونکی اوڅاريز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„%1$s + Úنډول + بیاروانولو لپاره ووهئ + + + د غونډال انګروزي تړل سالول او بندول + + diff --git a/app/src/main/res/values-ps/strings_app.xml b/app/src/main/res/values-ps/strings_app.xml new file mode 100644 index 0000000..630c2b3 --- /dev/null +++ b/app/src/main/res/values-ps/strings_app.xml @@ -0,0 +1,5 @@ + + + Ø§Ú‰Ø§ÙˆÛ + د Ø§Ø²Ø§Ø¯Û Ø³Ø±Ú†ÙŠÙ†Û Ø§Ù†Ú«Ø±ÙˆØ²ÛŒ تړونکی + diff --git a/app/src/main/res/values-ps/strings_errors.xml b/app/src/main/res/values-ps/strings_errors.xml new file mode 100644 index 0000000..bb14ff2 --- /dev/null +++ b/app/src/main/res/values-ps/strings_errors.xml @@ -0,0 +1,9 @@ + + + + انټرنÛÙ¼ پیوستون نشته + تشه بس نه ده + + د اوڅاريز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„ انګروزي تړنه سالول نابريالي شو. + د اوڅاريز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„ انګروزي تړنه بندول نابريالي شو. + \ No newline at end of file diff --git a/app/src/main/res/values-ps/strings_home.xml b/app/src/main/res/values-ps/strings_home.xml new file mode 100644 index 0000000..24094e1 --- /dev/null +++ b/app/src/main/res/values-ps/strings_home.xml @@ -0,0 +1,15 @@ + + + + + تړلی + پرÛÚšÙ„ÛŒ + + مرسته ښودل + + ØºÙˆØ±ØªÙŠØ§ÙˆÛ + + + مهرباني وکړئ، د لا نورو معلوماتو لپاره مرسته ولولئ. + + \ No newline at end of file diff --git a/app/src/main/res/values-ps/strings_hosts.xml b/app/src/main/res/values-ps/strings_hosts.xml new file mode 100644 index 0000000..dc2ea3a --- /dev/null +++ b/app/src/main/res/values-ps/strings_hosts.xml @@ -0,0 +1,11 @@ + + + Hosts Ø³Ø±Ú†ÙŠÙ†Û + + شتون نه لري + + سرچينه زیاتول + Ø³Ø±Ú†ÙŠÙ†Û Ø³Ù…ÙˆÙ† + URL: (یو https:// اویا file:// سرچينه) + د hosts Ø³Ø±Ú†ÙŠÙ†Û Ù¾ØªÙ‡ + diff --git a/app/src/main/res/values-ps/strings_lists.xml b/app/src/main/res/values-ps/strings_lists.xml new file mode 100644 index 0000000..96de9ff --- /dev/null +++ b/app/src/main/res/values-ps/strings_lists.xml @@ -0,0 +1,8 @@ + + + Ø³ØªØ§Ø³Û Ù„Ú“ÙˆÙ†Ù‡ + + تړلی + پرÛÚšÙ„ÛŒ + د کوربانه سرچيني URL + diff --git a/app/src/main/res/values-ps/strings_log.xml b/app/src/main/res/values-ps/strings_log.xml new file mode 100644 index 0000000..4e144bd --- /dev/null +++ b/app/src/main/res/values-ps/strings_log.xml @@ -0,0 +1,6 @@ + + + + آبڅیز اڼل + + diff --git a/app/src/main/res/values-ps/strings_notification.xml b/app/src/main/res/values-ps/strings_notification.xml new file mode 100644 index 0000000..5b5faeb --- /dev/null +++ b/app/src/main/res/values-ps/strings_notification.xml @@ -0,0 +1,6 @@ + + + د Ø³Ø±Ú†ÙŠÙ†Û Ø§ÙˆØ³Ù…Ù‡Ø§Ù„ÙŠØ² شته + + اوڅاریز ÚØ§Ù†ÙŠ Ø¬Ø§Ù„ (VPN) + \ No newline at end of file diff --git a/app/src/main/res/values-ps/strings_prefs_backup_restore.xml b/app/src/main/res/values-ps/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ps/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ps/strings_prefs_main.xml b/app/src/main/res/values-ps/strings_prefs_main.xml new file mode 100644 index 0000000..0ce2028 --- /dev/null +++ b/app/src/main/res/values-ps/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + ØºÙˆØ±ØªÙŠØ§ÙˆÛ + diff --git a/app/src/main/res/values-ps/strings_prefs_root.xml b/app/src/main/res/values-ps/strings_prefs_root.xml new file mode 100644 index 0000000..357dcf5 --- /dev/null +++ b/app/src/main/res/values-ps/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + + hosts لګول + د hosts دوتنه Ù¾Ø±Ø§Ù†ÛŒÚØ¦ + + ÚØ§ÙŠÙŠ Ú«ÙˆØ±Øª پالنګر + ګورت پالنګر سالول + نه ÚØºÙ„ÙŠ + diff --git a/app/src/main/res/values-ps/strings_prefs_update.xml b/app/src/main/res/values-ps/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ps/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ps/strings_prefs_vpn.xml b/app/src/main/res/values-ps/strings_prefs_vpn.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ps/strings_prefs_vpn.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ps/strings_support.xml b/app/src/main/res/values-ps/strings_support.xml new file mode 100644 index 0000000..04bfad6 --- /dev/null +++ b/app/src/main/res/values-ps/strings_support.xml @@ -0,0 +1,4 @@ + + + ملاتړ + \ No newline at end of file diff --git a/app/src/main/res/values-ps/strings_update.xml b/app/src/main/res/values-ps/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ps/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ps/strings_welcome.xml b/app/src/main/res/values-ps/strings_welcome.xml new file mode 100644 index 0000000..f45eab6 --- /dev/null +++ b/app/src/main/res/values-ps/strings_welcome.xml @@ -0,0 +1,14 @@ + + + ÚšÙ‡ راغلاست + + Ø§Ú‰Ø§ÙˆÛ ØªÙ‡ ÚšÙ‡ راغلاست! + ÙˆÙ„Û Ù†ÚšØ§Ù† + لاګړندى + + ملاتړ + + شا + بل + پاينه + diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000..2cc77ea --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,266 @@ + + + + Sair + Fechar + Sim + Não + Adicionar + Cancelar + Salvar + Ajuda + + + Bem-vindo! + O AdAway é um projeto de software livre e Open-Source para bloquear publicidade. Ele baixa endereços de rede de anúncios e configura o dispositivo para bloqueá-los.\nQuer saber mais? Veja a ajuda abaixo! + Mostrar mais ajuda + Atualizar status + Todos os arquivos hosts das fontes selecionadas já estão baixados, mesclados com suas listas personalizadas e instalados como um único arquivo hosts no seu sistema. + Ativar bloqueio de anúncios + Desativar bloqueio de anúncios + Servidor web + Em execução + Parado + Iniciar ou interromper servidor web no host local para responder solicitações de nomes de hosts bloqueados. + Ativar servidor web + Desativar servidor web + VPN + Em execução + Parado + Inicie ou pare o VPN para filtrar solicitações. + Ativar VPN + Desativar VPN + + + Editar Entrada + Aplicar + Editar + Excluir + + + Importando… + Backup importado com sucesso do seu armazenamento externo. + Falha ao importar backup. Seu formato está correto? Verifique o logcat para mais detalhes. + Exportando… + Backup exportado com sucesso para o arquivo \'%s\' em seu armazenamento externo. + Falha ao exportar arquivo de backup \'%s\'. + + + O arquivo de hosts + O arquivo hosts é um arquivo de sistema que mapeia nomes de host para endereços IP. É um arquivo de texto simples cuja configuração é gerenciada pela AdAway. Aqui estão suas poucas primeiras linhas: + Carregando o conteúdo do arquivo hosts… + Abrir arquivo hosts + + + Buscando atualização + Verificando atualização de fonte: %s + Obtendo fontes + Baixando fontes %s + Fonte de leitura %s + Fonte %s em análise + Sincronizando o banco de dados de regras + Revertendo para o arquivo de hosts padrão + Arquivo de hosts padrão restaurado + Criando arquivo hosts padrão + Atualização da fonte disponível + Hosts mais recentes disponíveis + Nenhuma atualização de fonte encontrada + Sem conexão à Internet + Nenhuma conexão à Internet disponível + Fontes indisponíveis + Nenhuma fonte de host está acessível! + Acesso root negado + Permitir acesso root do seu aplicativo de root + Algo deu errado + Verifique o logcat para mais detalhes + Ativado + Arquivos hosts mais recentes ativados + Desativado + Arquivo hosts padrão instalado + Aplicar as fontes mais recentes + Criando um novo arquivo de hosts + Copiando um novo arquivo de hosts + Verificando a cópia do arquivo de hosts + Arquivo de hosts atualizado com sucesso + Configuração da VPN atualizada com sucesso + Sua configuração foi alterada. Você precisa aplicá-la. + Aplicar + Aplicando nova configuração… + Falha ao aplicar nova configuração + + + O symlink para o destino do arquivo hosts está ausente + O link simbólico do seu destino para /system/etc/hosts não existe ou está incorreto! O AdAway não funcionará se ele não estiver direcionado ao arquivo certo.\n\nTentar criar um link simbólico? + Link simbólico ausente + Espaço insuficiente na partição!\nTente alterar o destino do arquivo hosts nas preferências para /data/data/hosts. + Espaço insuficiente + O arquivo baixado não pode ser lido. + Falha no arquivo privado + Falha ao remontar a partição como leitura/escrita! + Falha ao remontar + Falha ao copiar o arquivo hosts + Falha na cópia do arquivo hosts! + Falha ao copiar + Fontes de hosts aplicadas + Sucesso ao aplicar + A aplicação foi bem sucedida.\nPode ser necessário reiniciar o Android para as alterações fazerem efeito.\n\nDeseja reiniciar agora?\n(Para evitar perda de dados certifique-se de que nenhum app está usando o cartão SD no momento!) + O link simbólico foi criado com sucesso. Pode ser necessário reiniciar o Android para que as alterações entrem em vigor. Deseja reiniciar? (para evitar a perda de dados, certifique-se de que nenhum aplicativo está usando o cartão SD no momento!) + Sucesso ao criar link simbólico + O link simbólico não pôde ser criado pelo Android.\nIsso falha principalmente devido a um \'recurso\' chamado S-ON nos telefones HTC!\n\nUma solução é inicializar seu telefone no modo de recuperação e criar o link simbólico com \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nSe isso não funcionar, procure na Internet por S-OFF e seu telefone. + Falha ao criar link simbólico + Consulte a Ajuda para mais informações. + Um proxy APN está definido no seu Android!\nO AdAway não funcionará de forma confiável quando estiver em redes móveis como o 3G. Você pode desativar esse proxy acessando o APN selecionado (no aplicativo Configurações: Rede & Internet -> Rede móvel -> Avançado -> Nomes de pontos de acesso) e remova o valor no campo de proxy. + APN proxy definida! + A conexão à Internet não está funcionando. + Sem Conexão + Baixando… + Aplicando… + Aplicando Lista Negra e Lista Branca + Analisando e mesclando arquivos hosts + Compilando arquivo hosts + Aplicando arquivo hosts + Falha ao aplicar o novo arquivo de hosts. + Falha ao aplicar arquivo hosts no seu sistema!\nTente alterar o destino do arquivo hosts nas preferências para /data/data/hosts. + Falha ao aplicar + Por favor, verifique o seu aplicativo de gerenciamento de root para garantir que o acesso root tenha sido concedido. + Você reverteu para o arquivo de hosts padrão. Pode ser necessário reinicializar o Android para que as alterações entrem em vigor. Deseja reinicializar? (Para evitar a perda de dados, verifique se nenhum aplicativo usa o cartão SD no momento !) + Revertido com sucesso + Não foi possível reverter o arquivo hosts + Falha ao reverter devido a razões desconhecidas. + Falha ao reverter! + Nenhuma de suas fontes de hosts ativadas está acessível! Você está conectado devidamente à Internet? + Falha ao baixar + Falha ao gravar o novo arquivo de hosts privados + O arquivo privado não pode ser criado. + Falha ao criar arquivo privado + Você ativou o modo sem sistema. Pode ser necessário reinicializar o Android para que as alterações entrem em vigor. Deseja reinicializar? (Para evitar a perda de dados, certifique-se de que nenhum aplicativo use o cartão SD no momento!) + Ativado com sucesso + Você desativou o modo sem sistema. Pode ser necessário reiniciar o Android para que as alterações entrem em vigor. Deseja reiniciar? (Para evitar a perda de dados, certifique-se de que nenhum aplicativo use o cartão SD no momento!) + Desativado com sucesso + Falha ao ativar o bloqueio de anúncios VPN. + Falha ao desativar o bloqueio de anúncios VPN. + Ativando módulo Magisk de hosts + Habilite o recurso hosts sem sistema do gerenciador Magisk. Nas configurações, ative a opção Hosts sem sistema e reinicie o dispositivo. + Desativando módulo Magisk de hosts + Desative o recurso de hosts sem sistema do gerenciador Magisk. Na lista de módulos, desinstale o módulo Hosts sem sistema e reinicie o dispositivo. + + + URL de entrada para arquivo hosts: + Este não é um nome de host válido! + Nome de host incorretamente formatado + Este não é um IP válido! + IP incorretamente formatado + Nunca reinicie e não mostre esta pergunta na próxima vez! + Carregando… + + + Atualizar + Adicionar + Ajuda + Importar backup + Exportar backup + + + S-ON/S-OFF + FAQ + Problemas + + + Adware + Aqui você pode encontrar adwares instalados, aplicativos ruins que não podem ser bloqueados pelo AdAway. Esses aplicativos usam, por exemplo, notificações do Airpush que aparecem mesmo quando o aplicativo não está em execução ou até mesmo mudam seu toque. A única contramedida disponível é desinstalar esses aplicativos clicando nos itens da lista. + Escaneando… + Nenhum Adware foi encontrado! + + + Bloqueador de anúncios + Nenhum editor de texto instalado + Nenhum editor de texto pode ser encontrado para abrir o arquivo hosts. Você pode instalar Jota ou outros editores de texto para contornar isto.\n\nInstalar Jota? + Nenhum gerenciador de arquivos instalado + Nenhum gerenciador de arquivos pode ser encontrado para abrir arquivos. Você pode instalar OI Gerenciador de Arquivos ou outros gerenciadores de arquivos para contornar isto.\n\nInstalar OI Gerenciador de Arquivos? + + + Despejo TCP + Tcpdump é uma ferramenta para monitorar solicitações de DNS e salvá-las em um arquivo de registro. Você pode iniciá-la em segundo plano, executar apps que mostram anúncios, e logo após analisar as solicitações de DNS usando arquivo de registro. O possivel servidor de anúncios pode ser então adicionado na sua lista negra. + Desativar monitoramento + Ativar monitoramento + Mostrar resultados + Classificar domínios + Limpar registro + Adicionar entrada à lista negra + Adicionar entrada à lista branca + Adicionar entrada à lista de redirecionamento + + Edite o valor em texto preferido + Abrir menu + Fechar menu + + + + Início + Fontes de hosts + Suas listas + Abrir arquivo hosts + Registrar solicitações de DNS + Procurar por adware + Preferências + Ajuda + + + + + Pedidos DNS + Suas listas + Preferências + + + Instalado há %1$s + Atualizado há %1$s + Atualização necessária para %1$s + Última atualização há %1$s + Status de atualização desconhecido + Desativado + poucos minutos + + %d minuto + %d minutos + %d minutos + + + %d hora + %d horas + %d horas + + + %d dia + %d dias + %d dias + + + %d mês + %d meses + %d meses + + + + Host copiado para área da transferência + + + iniciando + ativo + parando + esperando pela rede + reconectando + erro de reconexão + pausado + parado + VPN bloqueadora de anúncios %1$s + Pausar + Retomar + + + Permissões do AdAway + Permitir a interação com o AdAway + Mandar comandos ao AdAway + Permitir o envio de comandos para o AdAway, como habilitar ou desabilitar o bloqueio de anúncios em todo o sistema + + diff --git a/app/src/main/res/values-pt-rBR/strings_app.xml b/app/src/main/res/values-pt-rBR/strings_app.xml new file mode 100644 index 0000000..b4415bb --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Bloqueador de anúncios de código aberto + Logo AdAway + diff --git a/app/src/main/res/values-pt-rBR/strings_errors.xml b/app/src/main/res/values-pt-rBR/strings_errors.xml new file mode 100644 index 0000000..b72c534 --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Sem conexão com a Internet + Não foi possível estabelecer uma conexão com a Internet. Por favor, verifique a conectividade do seu dispositivo. + Falha ao baixar a fonte dos hosts + Nenhuma das fontes de hosts ativadas está acessível. Por favor verifique se você está conectado corretamente à Internet. + + Falha ao criar arquivo privado + Não foi possível criar um arquivo privado para criar uma nova fonte de hosts. Verifique o espaço livre disponível no seu dispositivo. + Espaço insuficiente + Não foi possível copiar o arquivo hosts para partição do sistema. Por favor, verifique se o módulo sem sistema Magisk está ativado e reinicie. + Falha ao instalar o novo arquivo de hosts + Não foi possível copiar o arquivo hosts para a partição do sistema. Verifique se o módulo systemless do Magisk está habilitado e reinicie. + Falha ao reverter o arquivo hosts + Não foi possível restaurar a configuração do arquivo de hosts padrão. + + Falha ao ativar o bloqueio de anúncios VPN. + Verifique suas configurações de VPN para autorizar o aplicativo VPN a iniciar. + Falha ao desativar o bloqueio de anúncios VPN. + Por favor, verifique suas configurações de VPN para desativá-lo manualmente. + diff --git a/app/src/main/res/values-pt-rBR/strings_home.xml b/app/src/main/res/values-pt-rBR/strings_home.xml new file mode 100644 index 0000000..c3fa0aa --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Bloqueado + Permitido + Redirecionado + + + + %d up-to-date source + %d fontes atualizadas + + + %d outdated source + %d fontes desatualizadas + + Checar por atualizações de hosts + Atualizar hosts + + + Mostrar registro de solicitação de DNS + + + Mostrar ajuda\ne dicas + + + Abrir página do GitHub + + + Apoie o projeto + + + Projeto GitHub + Preferências + + + Abrir gaveta de navegação + Pausar/retomar ad bloqueador + Atualizar domínios bloqueados + Mostrar solicitações de domínios + + + Consulte a Ajuda para mais informações. + + \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings_hosts.xml b/app/src/main/res/values-pt-rBR/strings_hosts.xml new file mode 100644 index 0000000..b7aa779 --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Fontes de hosts + + Lista do usuário + Hosts oficiais do AdAway + Hosts StevenBlack Unificados + Lista negra de Pete Lowe + + não disponível + %s hosts + + Adicionar fonte + Editar fonte + URL: (https:// ou file:// recursos) + A URL da fonte de hosts + diff --git a/app/src/main/res/values-pt-rBR/strings_lists.xml b/app/src/main/res/values-pt-rBR/strings_lists.xml new file mode 100644 index 0000000..e85442a --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_lists.xml @@ -0,0 +1,24 @@ + + + Suas listas + Adicionar host + + Bloqueado + Permitido + Redirecionado + + Filtrar hosts + Pesquisar nome do host… + Alternar fontes + + Adicionar host à lista negra + Adicionar host à lista branca + Adicionar redirecionamento de host + Editar host da lista negra + Editar host da lista branca + Editar redirecionamento + Nome do host: + A URL da fonte de hosts + (Caracteres curinga * e ? são permitidos) + IP (IPv4 ou IPv6): + diff --git a/app/src/main/res/values-pt-rBR/strings_log.xml b/app/src/main/res/values-pt-rBR/strings_log.xml new file mode 100644 index 0000000..05c4907 --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_log.xml @@ -0,0 +1,11 @@ + + + Ativar gravação do registro + Aperte gravar para começar a registrar solicitações, navegue a Web ou use aplicativos, então retorne ou deslize para atualizar os registros. + \n\nSolicitações bloqueadas não vão ser registradas. Desative o bloqueio de anúncios se quiser registrá-las também. + + Ordem alfabética + Ordem de nível de domínio + + Redirecionamento de domínio + diff --git a/app/src/main/res/values-pt-rBR/strings_notification.xml b/app/src/main/res/values-pt-rBR/strings_notification.xml new file mode 100644 index 0000000..71427f2 --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Atualizações + Novas notificações de atualização + Atualização da fonte disponível + Novos arquivos hosts disponíveis para download. + Atualização de aplicativo disponível + Uma nova versão do AdAway está disponível para download. + + VPN + Notificações de execução de VPN + \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings_prefs_backup_restore.xml b/app/src/main/res/values-pt-rBR/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..2920e78 --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Backup & restaurar + Backup + Backup para armazenamento externo suas regras de bloqueio + Restaurar + Restaure suas regras de bloqueio do arquivo de backup + diff --git a/app/src/main/res/values-pt-rBR/strings_prefs_main.xml b/app/src/main/res/values-pt-rBR/strings_prefs_main.xml new file mode 100644 index 0000000..f8933b9 --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Preferências + + Geral + Ativar tema escuro + + Claro + Escuro + Padrão do sistema + + Atualizações automáticas + + Ad bloqueador + Bloqueador de anúncios baseado em Root + Bloqueador de anúncios baseado em VPN + Ativar IPv6 + Backup / restaure regras de bloqueio + + Depuração + Ativar relatório de erros + Permitir ao aplicativo enviar relatórios de erros e crashes para o Sentry (sentry.io). + Não suportado nesta compilação + Habilitar log detalhado + Você precisa reiniciar o AdAway para esta configuração ter efeito. + diff --git a/app/src/main/res/values-pt-rBR/strings_prefs_root.xml b/app/src/main/res/values-pt-rBR/strings_prefs_root.xml new file mode 100644 index 0000000..da13062 --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Bloqueador de anúncios baseado em Root + + Instalar Hosts + Abrir arquivo hosts + Destino do arquivo hosts + Antes de alterar esta definição, consulte a Ajuda sobre esta funcionalidade. + + /system/etc/hosts + /data/hosts + /data/data/hosts + Destino personalizado + + Destino personalizado + Ocultar diálogo de reinicialização + + Redirecionamento + Definir para onde redirecionar hosts bloqueados + Redirecionamento de IPv4 + Redirecionamento de IPv6 + Redirecionamento inválido + + Servidor Web Local + O servidor da Web local escutam os endereços IP locais para responder a solicitações de nome de host bloqueadas. Pode ajudar com o congelamento de aplicativos na conexão bloqueada. + Ativar servidor web + Testar servidor web + Instalar certificado autoassinado + Instalação manual do certificado + A partir do Android 11 (R), o aplicativo não pode mais instalar automaticamente a autoridade de certificação (CA).\n\nVá para as configurações de \"Segurança\", \"Criptografia e credenciais\" e, em seguida, \"Instalar um certificado\". A partir daí, escolha \"certificado CA\" e selecione o arquivo de certificado recém-exportado. + Abra as configurações de \"Segurança\" + Checando… + Não executando + Em execução, mas o certificado não foi instalado + Em execução e certificado instalado + Substituir espaço em branco do anúncio pelo ícone do aplicativo + diff --git a/app/src/main/res/values-pt-rBR/strings_prefs_update.xml b/app/src/main/res/values-pt-rBR/strings_prefs_update.xml new file mode 100644 index 0000000..a62cc03 --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Atualizações + As notificações estão desativadas + As notificações de aplicativos não serão exibidas. Toque para ativá-las. + + Atualizações do aplicativo + Verificar se há atualizações na inicialização + Verificar por atualizações diariamente + Incluir versões beta + + Atualizações de hosts + Verificar se há atualizações na inicialização + Verificar por atualizações diariamente + Sincronizar na atualização + Sincronizar apenas em rede sem limites + diff --git a/app/src/main/res/values-pt-rBR/strings_prefs_vpn.xml b/app/src/main/res/values-pt-rBR/strings_prefs_vpn.xml new file mode 100644 index 0000000..1c4f14b --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Bloqueador de anúncios baseado em VPN + + Ativar na inicialização + Monitore a conexão + Verifique periodicamente o estado da rede para reiniciar a VPN em caso de desconexão. + + Aplicativos excluídos + Configure quais aplicativos não devem usar a VPN para que nenhuma conexão seja bloqueada. + Excluir aplicativos do sistema + + Nenhum + Todos, exceto navegadores + Todos + + Excluir aplicativos do usuário + + + Aplicativos excluídos + Selecionar tudo + Remover todos + Ãcone do aplicativo + diff --git a/app/src/main/res/values-pt-rBR/strings_source_edit.xml b/app/src/main/res/values-pt-rBR/strings_source_edit.xml new file mode 100644 index 0000000..ca5021c --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Editar fonte + Adicionar fonte + + Etiqueta + Etiqueta necessária + Tipo + URL + Arquivo + Localização + https:// + Localização necessária + Toque em Arquivo para selecionar arquivo fonte + Localização inválida + Formato da lista + Bloquear + Permitir + Aplicar hosts redirecionados + Permitir hosts redirecionados poderá causar problemas de segurança. Usa esta definição apenas em fontes confiáveis, pois estas poderão redirecionar tráfego sensível para qualquer servidor que queiram. + diff --git a/app/src/main/res/values-pt-rBR/strings_support.xml b/app/src/main/res/values-pt-rBR/strings_support.xml new file mode 100644 index 0000000..4c9a07d --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_support.xml @@ -0,0 +1,5 @@ + + + Suporte + Seja um patrocinador + \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings_update.xml b/app/src/main/res/values-pt-rBR/strings_update.xml new file mode 100644 index 0000000..69e3edc --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_update.xml @@ -0,0 +1,21 @@ + + + Atualização do AdAway + + Atualização disponível! + + + Você esta atualizado + Atualização disponível + Atualizando AdAway + Atualizar agora + %1$s / %2$s + Últimas modificações + Registro de mudanças + Apoiar o desenvolvimento + Doar + Patrocinador + + + Baixando a última versão do AdAway + diff --git a/app/src/main/res/values-pt-rBR/strings_welcome.xml b/app/src/main/res/values-pt-rBR/strings_welcome.xml new file mode 100644 index 0000000..399e66d --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Bem-vindo + Primeira etapa do assistente + Segunda etapa do assistente + Última etapa do assistente + + + Bem-vindo ao AdAway! + O AdAway fornece dois métodos de bloqueio de anúncios. Escolha o que você gosta: + + Root logo + Bloqueio baseado\nem root + Mais rápido + Economiza bateria + Requer acesso root + + VPN logo + Bloqueio baseado\nem VPN + Mais lento + Executado em segundo plano + Maior compatibilidade + + É obrigatório o acesso root + Não foi possível encontrar o binário su ou você não permitiu a permissão root do AdAway.\n\nIsso pode acontecer quando o dispositivo não está rooteado. Você pode encontrar informações sobre como fazer root no seu dispositivo em wiki.lineageos.org ou em outros sites Android. + + Pró + Contra + + + Sincronização concluída + Erro durante a sincronização + + Sincronizando + Sincronizado + O AdAway baixa redes de anúncios para bloquear de fontes on-line. Você pode personalizá-los posteriormente nas configurações. + Repetir sincronização + Falha ao sincronizar: %1$s Repetir agora? + Ele pode enviar notificações para exibir o status e o controle do bloqueio de anúncios e para notificar sobre atualizações disponíveis do aplicativo (algumas por ano). Ative-as se quiser se manter atualizado. + + + Suporte + Ajude-me! + O AdAway é um aplicativo gratuito e de código aberto que desenvolvo em meu tempo livre. Se você gostar dele, fique à vontade para mostrar seu apoio: + Doar pelo PayPal + Você gosta de bugs? Nem eu. + Ativar telemetria para me enviar relatórios de falhas + + + Voltar + Próximo + Terminar + diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml new file mode 100644 index 0000000..7feb0fd --- /dev/null +++ b/app/src/main/res/values-pt/strings.xml @@ -0,0 +1,267 @@ + + + + Sair + Fechar + Sim + Não + Adicionar + Cancelar + Guardar + Ajuda + + + Bem-vindo! + O AdAway é um projeto de programa de código aberto e gratuito que bloqueia publicidade. Este procura endereços de redes de anúncios para os bloquear no seu dispositivo.\nQuer saber mais? Consulte a ajuda abaixo! + Mostrar mais ajuda + Estado da atualização + Todos os ficheiros de hospedeiros das fontes definidas foram transferidos, unidos com as suas próprias listas e instalados como um único ficheiro de hospedeiros no seu sistema. + Ativar bloqueio de anúncios + Desativar bloqueio de anúncios + Servidor da Web + Em execução + Parado + Ligar ou desligar um servidor da Web no hospedeiro local para responder a pedidos de nomes de hospedeiro bloqueados. + Ativar servidor da Web + Desativar servidor da Web + VPN + Em funcionamento + Parado + Iniciar ou parar a VPN para filtrar os pedidos. + Ativar VPN + Desativar VPN + + + Editar entrada + Aplicar + Editar + Eliminar + + + A importar… + Cópia de segurança importada com sucesso do armazenamento externo. + A importação da cópia de segurança falhou. O formato é o correto? Verifique o logcat para mais informações. + A exportar… + Backup sucessivamente exportado para o ficheiro %sno seu armazenamento interno. + Falha ao exportar o arquivo de backup %s. + + + O ficheiro \'\'hosts\'\' + O ficheiro \'\'hosts\'\' é um ficheiro do sistema que mapeia os nomes de hospedeiro para os endereços de IP. É um ficheiro de texto simples cuja configuração é gerida pela AdAway. Aqui tem as suas poucas primeiras linhas: + A carregar o conteúdo do ficheiro \'\'hosts\'\'… + Abrir o ficheiro \'\'hosts\'\' + + + A procurar atualização + A verificar %s fonte por atualizações + A obter fontes + A baixar a fonte %s + A ler a fonte %s + A analisar a fonte %s + A sincronizar a database de regras + A reverter para o ficheiro hosts padrão + Ficheiro hosts padrão restaurado + A criar um ficheiro de hosts padrão + Atualização disponível + Novos ficheiros de hosts disponíveis + Nenhuma atualização das fontes encontradas + Sem ligação à internet + Sem ligação à internet disponível + Fontes indisponíveis + Impossível aceder às fontes de hosts! + Acesso root negado + Permitir acesso root na sua aplicação de root + Algo correu mal + Verifique logcat para mais detalhes + Ativado + Os ficheiros de hosts mais recentes estão ativos + Desativado + Instalado o ficheiro de hosts padrão. + Aplicar últimas fontes. + A criar um ficheiro hosts novo + A copiar o novo ficheiro hosts + A verificar o ficheiro hosts copiado + Ficheiro hosts atualizado com sucesso + Configuração da VPN atualizada com sucesso + As suas configurações foram alteradas. +É necessário aplicá-las. + Aplicar + A aplicar nova configuração… + Falha ao aplicar nova configuração + + + O symlink do destino ficheiro hosts está em falta. + Uma ligação simbólica do seu destino para /system/etc/hosts não existe ou está incorreta! O AdAway não funcionará se não estiver a apontar para o ficheiro correto.\n\nPretende tentar criar uma ligação simbólica? + Ligação simbólica em falta + Não existe espaço suficiente na partição!\nExperimente alterar o ficheiro de hosts de destino nas preferências para /data/data/hosts. + Espaço insuficiente + Impossível ler o ficheiro descarregado. + Falha no ficheiro privado + Falha ao remontar a partição em modo leitura/escrita! + Falha ao remontar + Falha ao copiar o ficheiro hosts + Falha ao copiar o ficheiro de hosts! + Falha ao copiar + As fontes de hosts foram aplicadas + Aplicado com sucesso + Aplicado com sucesso.\nPoderá ser necessário reiniciar o Android para as alterações surtirem efeito.\n\nPretende reiniciar?\n(Para prevenir a perda de dados, certifique-se de que nenhuma aplicação está a utilizar o cartão SD neste momento!) + A ligação simbólica foi criada com sucesso.\nPoderá ser necessário reiniciar o Android para que as alterações surtem efeito.\n\nPretende reiniciar?\n(Para prevenir a perda de dados, certifique-se de que nenhuma aplicação está a utilizar o cartão SD neste momento!) + Ligação simbólica criada com sucesso + O link simbólico não pôde ser criado pelo Android.\nIsso acontece principalmente devido a um \'recurso\' chamado S-ON nos telefones HTC!\n\nUma solução é inicializar o telemóvel no modo de recuperação e criar o link simbólico com \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nSe isso não funcionar, procure na Internet por S-OFF e o seu telemóvel. + Falha ao criar a ligação simbólica + Para mais informações, por favor, leia a ajuda. + Está definido no seu Android um proxy APN!\nO AdAway não funcionará de forma confiável quando estiver em redes móveis como o 3G. Pode desativar este proxy acedendo ao APN selecionado (na aplicação Definições: Rede & Internet -> Rede móvel -> Avançado -> Nomes de pontos de acesso) e remova o valor no campo de proxy. + Proxy de APN definido! + A ligação à internet não está a funcionar. + Sem ligação + A descarregar… + A aplicar… + A aplicar listas negra e branca + A analisar e fundir os ficheiros de hosts + A construir o ficheiro de hosts + A aplicar o ficheiro de hosts + Falha ao aplicar o novo ficheiro hosts + Falha ao aplicar o ficheiro de hosts no sistema!\nExperimente alterar o ficheiro de hosts de destino nas preferências para /data/data/hosts. + Falha ao aplicar + Por favor verifique a sua app de gestão root para certificar-se que o acesso root foi concedido. + Reverteu o ficheiro de hosts predefinido.\nPoderá ser necessário reiniciar o Android para que as alterações surtem efeito.\n\nPretende reiniciar?\n(Para prevenir a perda de dados, certifique-se de que nenhuma aplicação está a utilizar o cartão SD neste momento!) + Revertido com sucesso + Incapaz de reverter o ficheiro hosts + Falha ao reverter por motivos desconhecidos. + Falha ao reverter! + Nenhuma das suas fontes de hosts ativadas está alcançável! Está corretamente ligado à internet? + Falha ao descarregar + Falha para escrever novo ficheiro hosts o privado. + Impossível criar ficheiro privado. + Falha ao criar ficheiro privado + Ativou o modo \"systemless\".\nPoderá ser necessário reiniciar o Android para que as alterações surtemefeito.\n\nPretende reiniciar?\n(Para impedir a perda de dados, certifique-se de que nenhuma aplicação esteja a utilizar o cartão SD neste momento!) + Ativação bem-sucedida + Desativou o modo \"systemless\".\nPoderá ser necessário reiniciar o Android para que as alterações surtam efeito.\n\nPretende reiniciar?\n(Para impedir a perda de dados, certifique-se de que nenhuma aplicação esteja a utilizar o cartão de memória neste momento!) + Desativação bem-sucedida + Falha para habilitar vpn bloquadora de anúncios. + Falha ao desativar o bloqueio de anúncios vpn. + Ativar systemless hosts + Ativar opção systemless hosts a partir do gestor Magisk. Nas definições do Magisk, ativar a opção Systemless hosts e de seguida reinicie o dispositivo. + Desativar módulo hosts do Magisk + Desativar opção systemless hosts no Magisk manager. Na lista de módulos, desinstalar o módulo Systemless hosts e de seguida reiniciar o dispositivo. + + + Introduza um URL para o ficheiro de hosts: + Este hostname não é válido! + Hostname incorretamente formatado + Este IP não é válido! + IP incorretamente formatado + Nunca reiniciar e não mostrar de novo esta mensagem. + A carregar… + + + Atualizar + Adicionar + Ajuda + Importar cópia de segurança + Exportar cópia de segurança + + + S-ON/S-OFF + Perguntas frequentes + Problemas + + + Adware + Aqui pode encontrar adwares instalados, aplicações indesejadas que não podem ser bloqueadas pelo AdAway. Estas aplicações usam, por exemplo, notificações do Airpush que aparecem mesmo quando a aplicação não está em execução e até podem alterar o seu toque de chamada. A única contramedida disponível é desinstalar essas aplicações clicando nos itens da lista. + A pesquisar… + Não foi encontrado o Adware! + + + Bloqueador de anúncios + Nenhum editor de texto instalado + Não foi encontrado nenhum editor de texto para abrir o ficheiro de hosts. Pode instalar o Jota ou outros editores de texto para solucionar isto.\n\nPretende instalar o Jota? + Nenhum gestor de ficheiros instalado + Não foi encontrado nenhum gestor de ficheiros para abrir ficheiros. Pode instalar o OI File Manager ou outros gestores de ficheiros para solucionar isto.\n\nPretende instalar o OI File Manager? + + + Tcpdump + Tcpdump é uma ferramenta para monitorizar os pedidos de DNS e guardá-los num ficheiro de registo. Pode iniciá-la em segundo plano, executar aplicações que exibem anúncios, e posteriormente analisar os pedidos de DNS utilizando o ficheiro de registo. Depois poderão ser adicionados à lista negra possíveis servidores de anúncios. + Desativar monitorização + Ativar monitorização + Mostrar resultados + Ordenar domínios + Limpar registo + Adicionar entrada à lista negra + Adicionar entrada à lista branca + Adicionar entrada à lista de redirecionamentos + + Editar valor da preferência do texto + Abrir menu + Fechar menu + + + + Início + Fontes de hosts + As suas listas + Abrir ficheiro de hosts + Registar pedidos de DNS + Procurar adware + Preferências + Ajuda + + + + + Pedidos de DNS + As suas listas + Preferências + + + Instalado à%1$satrás +  Atualizado para %1$s + Precisa de atualização para %1$s + Última atualização há %1$s + Estado de atualização desconhecido + Desativado + alguns minutos + + %d minuto + %d minutos + %d minutos + + + %d hora + %d horas + %d horas + + + %d dia + %d dias + %d dias + + + %d mês + %d meses + %d meses + + + + Host copiado para a área de transferências + + + A começar + Ativo + a parar + espere por internet + a reconnectar + Erro de conexão + pausado + parado + Vpn bloqueadora de anúncios%1$s + pausar + continuar + + + Permissions do AdAway. + Permitir a interação com o AdAway. + Enviar comandos para o AdAway + Permitir mandar comandos para o AdAway como habilitar or desabilitar o o bloqueio de anúncios no sistema + + diff --git a/app/src/main/res/values-pt/strings_app.xml b/app/src/main/res/values-pt/strings_app.xml new file mode 100644 index 0000000..610f42f --- /dev/null +++ b/app/src/main/res/values-pt/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Bloqueador de anúncios de código aberto + Logótipo do AdAway + diff --git a/app/src/main/res/values-pt/strings_errors.xml b/app/src/main/res/values-pt/strings_errors.xml new file mode 100644 index 0000000..f087011 --- /dev/null +++ b/app/src/main/res/values-pt/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Sem ligação à Internet + Incapaz de estabelecer ligação à Internet. Verifique a conexão do seu dispositivo. + Falha no descarregamento da fonte de hosts + Nenhuma das fontes de hosts ativadas está acessível. Verifique se está corretamente conectado à Internet. + + Falha ao criar ficheiro privado + Não foi possível criar um ficheiro privado para construir uma nova fonte de hosts. Verifique o espaço livre disponível no seu dispositivo. + Espaço insuficiente + Incapaz de copiar o ficheiro hosts para a partição de sistema. Verifique se o módulo fora de sistema do Magisk está ativado e reinicie. + Falha ao instalar um novo ficheiro hosts + Incapaz de copiar o ficheiro hosts para a partição /system. Verifique se o módulo fora de sistema do Magisk está ativado e reinicie. + Falha ao reverter o ficheiro hosts + Incapaz de restaurar a configuração predefinida do ficheiro hosts. + + Falha ao ativar VPN de bloqueio de anúncios. + Verifique a configuração da sua VPN para autorizar a VPN da aplicação a iniciar. + Falha ao desativar VPN de bloqueio de anúncios. + Verifique a configuração da sua VPN para a desativar manualmente. + diff --git a/app/src/main/res/values-pt/strings_home.xml b/app/src/main/res/values-pt/strings_home.xml new file mode 100644 index 0000000..41e9a01 --- /dev/null +++ b/app/src/main/res/values-pt/strings_home.xml @@ -0,0 +1,48 @@ + + + + + Bloqueado + Permitido + Redirecionado + + + + %d fonte atualizada + %d fontes atualizadas + %d fontes atualizadas + + + %d fonte desatualizada + %d fontes desatualizadas + %d fontes desatualizadas + + Verificar atualizações junto dos hospedeiros + Atualizar hospedeiros + + + Mostrar registo de pedidos DNS + + + Mostrar ajuda/e dicas + + + Abrir página do GitHub + + + Apoiar o projeto + + + Projeto no GitHub + Preferências + + + Abrir painel de navegação + Parar/retomar bloqueio de publicidade + Atualizar domínios bloqueados + Mostrar domínios pedidos + + + Para mais informação, por favor, leia a Ajuda. + + \ No newline at end of file diff --git a/app/src/main/res/values-pt/strings_hosts.xml b/app/src/main/res/values-pt/strings_hosts.xml new file mode 100644 index 0000000..a8bc538 --- /dev/null +++ b/app/src/main/res/values-pt/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Fontes de hosts + + Lista do utilizador + Hosts oficiais do AdAway + Hosts unificados de StevenBlack + Hosts de listas de bloqueio de Pete Lowe + + não disponível + %s hosts + + Adicionar fonte + Editar fonte + URL: (um recurso https:// ou file://) + O URL fonte de hosts + diff --git a/app/src/main/res/values-pt/strings_lists.xml b/app/src/main/res/values-pt/strings_lists.xml new file mode 100644 index 0000000..e6861e3 --- /dev/null +++ b/app/src/main/res/values-pt/strings_lists.xml @@ -0,0 +1,24 @@ + + + As suas listas + Adicionar host + + Bloqueado + Permitido + Redirecionado + + Filtrar hosts + Pesquisar nome do host… + Alternar fontes + + Adicionar host à lista negra + Adicionar host à lista branca + Adicionar redirecionamento de host + Editar lista negra de hosts + Editar lista branca de hosts + Editar redirecionamento + Hostname: + O URL fonte de hosts + (São permitidos carateres de substituição * e ?) + IP (IPv4 ou IPv6): + diff --git a/app/src/main/res/values-pt/strings_log.xml b/app/src/main/res/values-pt/strings_log.xml new file mode 100644 index 0000000..1b2f3b6 --- /dev/null +++ b/app/src/main/res/values-pt/strings_log.xml @@ -0,0 +1,11 @@ + + + Ativar gravação de registo + Pressione \"Gravar\" para começar a registar os pedidos, explorar a Web ou utilize aplicações, e depois volte ou deslize para atualizar os registos. + \n\nOs pedidos bloqueados não serão registados. Desative primeiro o bloqueio de anúncios se também os quiser registar. + + Ordenar alfabeticamente + Ordenação de domínio de nível superior + + Domínio de redirecionamento + diff --git a/app/src/main/res/values-pt/strings_notification.xml b/app/src/main/res/values-pt/strings_notification.xml new file mode 100644 index 0000000..39c6a29 --- /dev/null +++ b/app/src/main/res/values-pt/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Atualizações + Notificações de nova atualização + Atualização disponível + Novos ficheiros de hosts disponíveis para descarregamento + Atualização da aplicação disponível + Uma versão nova do AdAway está disponível para descarregamento. + + VPN + Notificações recorrentes da VPN + diff --git a/app/src/main/res/values-pt/strings_prefs_backup_restore.xml b/app/src/main/res/values-pt/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..425f0f4 --- /dev/null +++ b/app/src/main/res/values-pt/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Backup e restauro + Backup + Fazer backup para armazenamento externo das regras de bloqueio + Restaurar + Restaurar regras de bloqueio do ficheiro de backup + diff --git a/app/src/main/res/values-pt/strings_prefs_main.xml b/app/src/main/res/values-pt/strings_prefs_main.xml new file mode 100644 index 0000000..39a1901 --- /dev/null +++ b/app/src/main/res/values-pt/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Preferências + + Geral + Tema escuro + + Claro + Escuro + Pré-definição do sistema + + Atualizações automáticas + + Bloqueio de anúncios + Bloqueador de anúncios baseado em acesso root + Bloqueador de anúncios baseado em VPN + Ativar IPv6 + Guardar cópia de segurança / restaurar regras de bloqueio + + Depuração + Enviar relatórios de quebras + Enviar relatórios para o Sentry (sentry.io) + Não suportado nesta compilação + Registo verboso + Reinício da aplicação necessário para entrada em efeito + diff --git a/app/src/main/res/values-pt/strings_prefs_root.xml b/app/src/main/res/values-pt/strings_prefs_root.xml new file mode 100644 index 0000000..be4d95e --- /dev/null +++ b/app/src/main/res/values-pt/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Bloqueador de anúncios baseado em acesso root + + Instalar hosts + Abrir ficheiro de hosts + Ficheiro de hosts de destino + Lê a Ajuda antes de usar esta funcionalidade + + /system/etc/hosts + /data/hosts + /data/data/hosts + Destino personalizado + + Localização do destino personalizado + Ocultar diálogo de reinício após aplicação + + Redirecionamento + Definir para onde redirecionar hosts bloqueados + Configurar redirecionamento de IPv4 + Configurar redirecionamento de IPv6 + Redirecionamento inválido + + Servidor web local + O servidor web local escuta os endereços IP locais para responder a pedidos de hostnames bloqueados. Isto poderá ajudar com o congelamento de aplicações com conexões bloqueadas. + Ativar servidor web + Testar servidor web + Instalar certificado auto-assinado + Instalação manual de certificado + A partir do Android 11 (R), a aplicação não pode instalar automaticamente a autoridade de certificação (CA).\n\nVai às configurações de \"Segurança\", \"Encriptação e credenciais\" e, de seguida, \"Instalar um certificado\". A partir daí, escolhe \"Certificado CA\" e seleciona o ficheiro de certificado recém-exportado. + Abre as configurações de \"Segurança\" + A verificar… + Não está em execução + Em execução, mas o certificado não está instalado + Em execução, com certificado instalado + Substituir espaço vazio do anúncio pelo ícone da aplicação + diff --git a/app/src/main/res/values-pt/strings_prefs_update.xml b/app/src/main/res/values-pt/strings_prefs_update.xml new file mode 100644 index 0000000..f76c0f8 --- /dev/null +++ b/app/src/main/res/values-pt/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Atualizações + As notificações estão desativadas + As notificações da aplicação não serão exibidas. Toca aqui para ativá-las. + + Atualizações da aplicação + Verificar atualizações ao iniciar + Verificar atualizações diariamente + Incluir versões beta + + Atualização de hosts + Verificar atualizações ao iniciar + Verificar atualizações periodicamente + Sincronizar ao atualizar + Sincronizar apenas em redes sem limites de tráfego + diff --git a/app/src/main/res/values-pt/strings_prefs_vpn.xml b/app/src/main/res/values-pt/strings_prefs_vpn.xml new file mode 100644 index 0000000..c3d0a01 --- /dev/null +++ b/app/src/main/res/values-pt/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Bloqueador de anúncios baseado em VPN + + Ativar ao iniciar + Monitorizar conexão + Verificar periodicamente o estado da rede para reiniciar a VPN em cao de desconexão. + + Aplicações excluídas + Configurar quais aplicações não deverão usar a VPN para que nenhuma conexão seja bloqueada. + Excluir aplicações de sistema + + Nenhuma + Todas, exceto navegadores + Todas + + Excluir aplicações de utilizador + + + Aplicações excluídas + Selecionar tudo + De-selecionar tudo + Ãcone da aplicação + diff --git a/app/src/main/res/values-pt/strings_source_edit.xml b/app/src/main/res/values-pt/strings_source_edit.xml new file mode 100644 index 0000000..887b949 --- /dev/null +++ b/app/src/main/res/values-pt/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Editar fonte + Adicionar fonte + + Etiqueta + Etiqueta necessária + Tipo + URL + Ficheiro + Localização + https:// + Localização necessária + Carrega em Ficheiro para selecionar o ficheiro fonte + Localização inválida + Formato da lista + Bloquear + Permitir + Aplicar hosts redirecionados + Permitir hosts redirecionados poderá causar problemas de segurança. Usa esta definição apenas em fontes confiáveis, pois estas poderão redirecionar tráfego sensível para qualquer servidor que queiram. + diff --git a/app/src/main/res/values-pt/strings_support.xml b/app/src/main/res/values-pt/strings_support.xml new file mode 100644 index 0000000..f07a5ae --- /dev/null +++ b/app/src/main/res/values-pt/strings_support.xml @@ -0,0 +1,5 @@ + + + Suporte + Torne-se patrocinador + \ No newline at end of file diff --git a/app/src/main/res/values-pt/strings_update.xml b/app/src/main/res/values-pt/strings_update.xml new file mode 100644 index 0000000..75922fb --- /dev/null +++ b/app/src/main/res/values-pt/strings_update.xml @@ -0,0 +1,21 @@ + + + Atualização do AdAway + + Atualização disponível! + + + Está actualizado + Atualização disponível + Atualizando o AdAway + Atualizar agora + %1$s / %2$s + Últimas alterações + Novidades + Apoie o desenvolvimento + Doar + Patrocinador + + + Descarregando a última versão do AdAway + diff --git a/app/src/main/res/values-pt/strings_welcome.xml b/app/src/main/res/values-pt/strings_welcome.xml new file mode 100644 index 0000000..b2adc6c --- /dev/null +++ b/app/src/main/res/values-pt/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Bem-vindo! + Primeira etapa do assistente + Segunda etapa do assistente + Última etapa do assistente + + + Bem-vindo ao AdAway! + O AdAway oferece dois métodos de bloqueio de anúncios. Escolha o que gostar: + + Logótipo raiz + Bloqueio baseado\nem raiz + Mais rápido + Poupa bateria + Requer acesso raiz + + Logótipo VPN + Bloqueio baseado\nem VPN + Mais lento + Funciona em segundo plano + Compatibilidade + + É necessário um sistema Android com acesso à raiz + Ou o binário SU não foi encontrado ou não concedeste permissão de root ao AdAway.\n\nIsto pode acontecer quando o dispositivo não tem acesso root.\nPodes encontrar informação sobre como obter acesso root no dispositivo em wiki.lineageos.org ou noutros websites sobre Android. + + Prós + Contra + + + Sincronização concluída + Erro durante sincronização + + A sincronizar + Sincronizado! + O AdAway transfere redes de anúncios para bloquear das fontes \'\'on-line\'\'. Pode personalizá-las mais tarde nas definições. + Tentar sincronização novamente + Falha ao sincronizar: %1$s Tentar novamente? + Pode enviar notificações para exibir o estado e o controle do bloqueio de anúncios e notificar sobre atualizações disponíveis para a aplicação (algumas por ano). Ativa-as se quiseres manter-te atualizado(a). + + + Apoio + Apoie-me! + O AdAway é uma aplicação de código aberto e gratuito que eu desenvolvo no meu tempo livre. Se aprecia a aplicação, fique à vontade para mostrar o seu apoio: + Doar com PayPal + Gostas de erros? Eu também não. + Ative a telemetria para enviar-me os relatórios de erros. + + + Anterior + Seguinte + Terminar + diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml new file mode 100644 index 0000000..851d39e --- /dev/null +++ b/app/src/main/res/values-ro/strings.xml @@ -0,0 +1,266 @@ + + + + IeÈ™ire + ÃŽnchide + Da + Nu + Adaugă + Anulează + Salvează + Ajutor + + + Bine aÈ›i venit! + AdAway este un software gratuit cu sursă deschisă proiectat pentru blocarea anunÈ›urilor. Acesta preia adresele reclamelor pentru a le restricÈ›iona pe dispozitivul tău.\nVrei să aflii mai multe? Vezi secÈ›iunea de ajutor de mai jos! + AfiÈ™ează mai multe sfaturi + Starea actualizărilor + Toate fiÈ™ierele \"host\" din sursa definită vor fi descărcate, combinate cu lista personală È™i apoi instalate ca un fiÈ™ier \"hosts\" unitar. + Activare blocare reclame + Dezactivare blocare reclame + Server web + Pornit + Oprit + Pornire sau oprire server web local pentru a răspunde cererilor pe domeniile restricÈ›ionate. + Activează server web + Dezactivează server web + VPN + Rulează + Oprit + Pornire sau oprire VPN pentru filtrare cereri. + Pornire VPN + Oprire VPN + + + Editare intrare + Aplică + Editare + Ștergere + + + Importă… + Copie de rezervă importată cu succes din stocarea externă. + Imposibil de importat copia de rezervă. AÈ›i verificat corectitudinea formatului? Analizează logcat-ul pentru mai multe detalii. + Exportă… + Exportul s-a realizat cu succes, fiÈ™ierul %s a fost scris în memoria externă. + Exportul a eÈ™uat, fiÈ™ierul %s nu a fost scris. + + + FiÈ™ierul \'hosts\' + FiÈ™ierul hosts este un fiÈ™ier de sistem care mapează numele serverelor la adrese IP. Este pur È™i simplu un fiÈ™ier text a cărui configuraÈ›ie este gestionată de către AdAway. Iată câteva linii din începutul fiÈ™ierului: + ÃŽncărcare conÈ›inut din fiÈ™ierul hosts… + Deschidere fiÈ™ier hosts + + + Verificare pentru actualizări + Verificare sursă %s pentru actualizări + Se citesc surse + Descărcare sursă %s + Se citeÈ™te sursa %s + Analizare sursă %s + Sincronizare bază de date cu reguli + Restaurare valori implicite pentru fiÈ™ierul hosts + Valorile implicite pentru fiÈ™ierul hosts au fost restaurate + Sistemul creaza fisiere \"hosts\" standard. + Sursă actualizată disponibilă + Noi fisiere \"host\" sunt disponibile + Nu au fost găsite actualizări pentru surse + Nu există conexiune internet + Nu este disponibilă o conexiune internet + Surse indisponibile + N-au fost gasite surse pentru fisierele \"hosts\" + Acces root refuzat + PermiteÈ›i mai întâi accesul root din aplicaÈ›ia de rooting + Ceva nu a funcÈ›ionat corespunzător + AnalizaÈ›i logcat pentru mai multe detalii + Activat + Cele mai noi versiuni ale fisierelor \"host\" au fost activate + Dezactivat + FiÈ™ier implicit de hosts instalat + AplicaÈ›i ultimele actualizări ale surselor + Creare fiÈ™ier hosts nou + Copiere fiÈ™ier hosts nou + Verificare copie fiÈ™ier hosts + FiÈ™ierul hosts a fost actualizat cu succes + ConfiguraÈ›ia VPN a fost actualizată cu succes + ConfiguraÈ›ia a fost modificată. Modificările necesită aplicare. + Aplică + Aplicare configuraÈ›ie nouă… + Imposibil de aplicat noua configuraÈ›ie. + + + Legătura simbolică către fiÈ™ierul hosts lipseÈ™te + Legătura simbolică de la È›inta dumneavoastră către /system/etc/hosts nu există sau este incorectă! AdAway nu va funcÈ›iona dacă nu este direcÈ›ionat către fiÈ™ierul corect.\n\nVreÈ›i să încercaÈ›i să creaÈ›i o nouă legătură simbolică? + Legătura simbolică lipseÈ™te + SpaÈ›iu insuficient pe partiÈ›ie! \nÃŽncercaÈ›i să schimbaÈ›i din setări fiÈ™ierul hosts către /data/data/hosts. + SpaÈ›iu insuficient + FiÈ™ierul descărcat nu poate fi citit + Lansare nereusita a fisierul cu atribute speciale (private) + Reactivarea partiÈ›iei pentru citire/scriere nereuÈ™ită! + Remontare partiÈ›ie nereuÈ™ită + Imposibil de copiat fiÈ™ierul hosts + Copierea fiÈ™ierelor \"hosts\" nereuÈ™ită! + Copiere nereuÈ™ită + Surse aplicate pe hosts + Aplicare reuÈ™ită + Aplicarea modificărilor nu a reuÈ™it.\nPoate fi necesară repornirea Android pentru ca modificările să aibă efect.\n\nContinuaÈ›i cu repornirea?\n(Pentru a preveni pierderi de date asiguraÈ›i-vă că nicio aplicaÈ›ie nu utilizează stocarea SD în prezent!) + Legătura simbolică a fost creată cu succes.\nPoate fi necesară repornirea Android pentru ca modificările să aibă efect.\n\nContinuaÈ›i cu repornirea?\n(Pentru a preveni pierderi de date asiguraÈ›i-vă că nicio aplicaÈ›ie nu utilizează stocarea SD în prezent!) + Legătura simbolică a fost creată cu succes + Legătura simbolică nu a putut fi creată de către Android.\nAcest lucru se întâmplă de obicei datorită \'funcÈ›iei\' S-ON pe dispozitivele HTC!\n\nO soluÈ›ie ar putea fi repornirea în modul de recuperare È™i realizarea arborelui legăturii simbolice de acolo prin \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nDacă nici această soluÈ›ie nu funcÈ›ionează căutaÈ›i pe Internet despre S-OFF pentru dispozitivul curent. + Crearea legăturii simbolice a eÈ™uat + CiteÈ™te secÈ›iunea \"Ajutor\" pentru mai multe informaÈ›ii. + Un proxy de la furnizorul mobil de tip APN este activat pe Android!nAdAway nu va funcÈ›iona corespunzător când se află pe reÈ›ele de date mobile 3G/4G/5G. PoÈ›i dezactiva acel proxy din lista de APN (AplicaÈ›ia de Setări: Conexiuni & Internet -> ReÈ›ele Mobile -> Avansat->Nume puncte de acces) prin È™tergea valorii introduse în câmpul de proxy. + Punctul de acces APN proxy a fost setat! + Conexiunea la Internet nu funcÈ›ionează. + Nu există conexiune! + Descărcare… + Aplicare modificări… + Sistemul aplică atributele listelor permise È™i restricÈ›ionate + Analizează È™i combină nodurile în fiÈ™ierul hosts + Sistemul generează fiÈ™ierul hosts + Sistemul aplică fiÈ™ierul hosts + Imposibil de aplicat noul fiÈ™ier hosts. + Aplicarea fiÈ™ierului hosts pe sistemul dumneavoastră a eÈ™uat!\nÃŽncercaÈ›i să schimbaÈ›i fiÈ™ierul hosts È›intă din preferinÈ›e în /data/data/hosts. + Aplicare nereuÈ™ită + Verifică te rog aplicaÈ›ia de rooting pentru asigurarea faptului că accesul este permis acestei aplicaÈ›ii. + A fost restaurat foÈ™ierul hosts iniÈ›ial.\nPoate fi necesară repornirea Android pentru ca modificările să aibă efect.\n\nContinuaÈ›i cu repornirea?\n(Pentru a preveni pierderi de date asiguraÈ›i-vă că nicio aplicaÈ›ie nu utilizează stocarea SD în prezent!) + Restaurare reuÈ™ită + Imposibil de restaurat fiÈ™ierul hosts la starea precedentă + Restaurare nereuÈ™ită din cauze necunoscute. + Restaurare nereuÈ™ită! + Nici una din sursele active pentru fisierele \"hosts\" nu pot fi accesate! Exista conexiune internet? + Descărcare nereuÈ™ită + Imposibil de scris noul fiÈ™ier hosts cu atribut privat + Fisierul cu atribute speciale nu poate fi creat + Incercare nereusita de creeare a fisierului cu atribute speciale. + AÈ›i activat modul systemless.\nPoate fi necesară repornirea Android pentru ca modificările să aibă efect.\n\nContinuaÈ›i cu repornirea?\n(Pentru a preveni pierderi de date asiguraÈ›i-vă că nicio aplicaÈ›ie nu utilizează stocarea SD în prezent!) + Activarea a fost reuÈ™ită + AÈ›i dezactivat modul systemless.\nPoate fi necesară repornirea Android pentru ca modificările să aibă efect.\n\nContinuaÈ›i cu repornirea?\n(Pentru a preveni pierderi de date asiguraÈ›i-vă că nicio aplicaÈ›ie nu utilizează stocarea SD în prezent!) + Dezactivarea a fost reuÈ™ită + Imposibil de activat VPN pentru îndepărtarea reclamelor. + Imposibil de dezactivat VPN pentru îndepărtarea reclamelor. + Activare modul Magisk pentru hosts + ActivaÈ›i funcÈ›ia de hosting fără suport de sistem din Magisk manager. Din setările managerului, activaÈ›i Systemless hosts apoi reporniÈ›i dispozitivul. + Dezactivare modul Magisk pentru hosts + DezactivaÈ›i funcÈ›ia de hosting fără suport de sistem din Magisk manager. Din lista de module a managerului, dezinstalaÈ›i modulul Systemless hosts apoi reporniÈ›i dispozitivul. + + + Adăugare adresă (URL) la fiÈ™ierul \'hosts\': + Nume invalid pentru fisierul \"host\" + Hostname formatat incorect + IP incorect! + IP formatat incorect + Nu reporni È™i nu mă mai întreba data viitoare! + Se încarcă… + + + Regenerare + Adaugă + Ajutor + Importare fiÈ™ier de rezervă + Exportare fiÈ™ier de rezervă + + + S-ON/S-OFF + Listă cu întrebări frecvente + Probleme + + + AplicaÈ›ie cu reclame + Aici se regăsesc aplicaÈ›iile ce conÈ›in reclame, aplicaÈ›ii pe care AdAway nu le poate bloca. Aceste aplicaÈ›ii pot de exemplu să trimită notificări chiar dacă aplicaÈ›ia nu rulează sau pot chiar modifica tonul de apel. Singura măsură împotriva acestora este dezinstalarea prin atingerea lor în această listă. + Scanare… + Niciun Adware găsit! + + + Program care blocheaza reclame + Nu există instalat un editor text + Niciun editor de text nu a fost găsit pentru a deschide fiÈ™ierul hosts. PuteÈ›i instala Jota sau alte editoare text pentru a face asta.\n\nVreÈ›i să instalaÈ›i Jota? + Nu exista un manager de fisiere instalat in sistem + Nici un manager de fiÈ™iere nu a putut fi găsit pentru a deschide fiÈ™iere. PuteÈ›i sa instalaÈ›i OI File Manager sau alÈ›i manageri de fiÈ™iere pentru a face asta.\n\nVreÈ›i să instalaÈ›i OI File Manager? + + + Dumping din TCP + Tcpdump este un utilitar care monitorizeaza si salveaza cererile DNS intr-un fisier dedicat (log). Pentru a-l folosi, lanseaza utilitarul in \"background\", lanseaza aplicatiile care contin reclame, dupa care poti analiza cererile DNS folosing fisierul generat. + Dezactivare monitorizare + Activare monitorizare + AfiÈ™are rezultate + Sortare domenii + Șterge log-uri + Adăugare intrare în lista neagră + Adăugare intrare în lista albă + Adăugare înregistrare pe lista de redirecÈ›ionare + + Editare valori text din fiÈ™ierul de preferinÈ›e + DeschideÈ›i meniul + ÃŽnchideÈ›i meniul + + + + Home + Sursele (hosts) + Listele dvs. + Deschide fiÈ™ierul \'hosts\' + Log DNS requests + Scan for adware + PreferinÈ›e + Ajutor + + + + + Solicitări pe DNS + Listele dvs. + PreferinÈ›e + + + Instalat de %1$s + Actualizat de %1$s + Actualizare necesară de acum %1$s + Actualizat acum %1$s + Status de actualizare necunoscut + Dezactivat + câteva minute + + %d minut + %d minute + %d minute + + + %d oră + %d ore + %d ore + + + %d zi + %d zile + %d zile + + + %d lună + %d luni + %d luni + + + + Adresă copiată + + + se activează + activ + se opreÈ™te + se aÈ™teaptă reÈ›eaua + reconectare + eroare la reconectare + în pauză + oprit + VPN %1$s cu blocare de anunÈ›uri + Pauză + AtingeÈ›i pentru continuare + + + Permisiuni AdAway + Permite interacÈ›iune cu AdAway + Activare sau dezactivare sistem de blocare al reclamelor + Permite trimiterea comenzilor către AdAway, precum activarea/dezactivarea protecÈ›iei globale AdAway. + + diff --git a/app/src/main/res/values-ro/strings_app.xml b/app/src/main/res/values-ro/strings_app.xml new file mode 100644 index 0000000..a270b18 --- /dev/null +++ b/app/src/main/res/values-ro/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Software cu sursă deschisă pentru blocarea reclamelor + Logo AdAway + diff --git a/app/src/main/res/values-ro/strings_errors.xml b/app/src/main/res/values-ro/strings_errors.xml new file mode 100644 index 0000000..2b942e9 --- /dev/null +++ b/app/src/main/res/values-ro/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Nu există conexiune la internet + Imposibil de conectat la internet. VerificaÈ›i conexiunea dispozitivului. + Imposibil de descărcat sursele hosts + Nici una din sursele active pentru fisierele \"hosts\" nu pot fi accesate! Exista conexiune internet? + + Imposibil de creat fiÈ™ierul hosts + Imposibil de creat fiÈ™ierul hosts privat pentru generarea unei noi surse. Verifică dacă există spaÈ›iu de stocare disponibil pe dispozitiv. + SpaÈ›iu insuficient + Imposibil de copiat fiÈ™ierul hosts pe partiÈ›ia de sistem. Verifică dacă modulul Magisk systemless este activ apoi reporneÈ™te dispozitivul. + Imposibil de instalat noul fiÈ™ier hosts. + Imposibil de copiat fiÈ™ierul hosts pe partiÈ›ia de sistem. Verifică dacă modulul Magisk systemless este activ apoi reporneÈ™te dispozitivul. + Imposibil de restaurat fiÈ™ierul hosts la starea precedentă + Imposibil de restaurat fiÈ™ierul hosts la starea iniÈ›ială + + Imposibil de activat VPN pentru îndepărtare reclame. + Verifică setările VPN È™i permite accesul aplicaÈ›iei pentru a porni serverul VPN. + Imposibil de dezactivat VPN pentru îndepărtare reclame. + Verifică setările pentru VPN È™i dezactivează-l manual. + diff --git a/app/src/main/res/values-ro/strings_home.xml b/app/src/main/res/values-ro/strings_home.xml new file mode 100644 index 0000000..e8baa5e --- /dev/null +++ b/app/src/main/res/values-ro/strings_home.xml @@ -0,0 +1,42 @@ + + + + + Blocate + Permise + RedirecÈ›ionate + + + + %d sursă la zi + %d surse la zi + %d surse la zi + + + %d sursă învechită + %d surse învechite + %d surse învechite + + + + Arată ajutor + + + Deschide pagina GitHub + + + SusÈ›ine proiectul + + + Setări + + + Deschide meniul cu aplicaÈ›ii + Pauză/reluare blocare anunÈ›uri + Actualizează domeniile blocate + AfiÈ™ează cererile domeniilor + + + CiteÈ™te secÈ›iunea de Ajutor pentru mai multe informaÈ›ii! + + diff --git a/app/src/main/res/values-ro/strings_hosts.xml b/app/src/main/res/values-ro/strings_hosts.xml new file mode 100644 index 0000000..949708c --- /dev/null +++ b/app/src/main/res/values-ro/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Sursele (hosts) + + Listă personală + AdAway - surse oficiale + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + Indisponibil + %s surse + + Adăugare sursă + Editare sursă + URL: (sursă https:// sau file://) + Sursa pt fisier \'host\' + diff --git a/app/src/main/res/values-ro/strings_lists.xml b/app/src/main/res/values-ro/strings_lists.xml new file mode 100644 index 0000000..6279321 --- /dev/null +++ b/app/src/main/res/values-ro/strings_lists.xml @@ -0,0 +1,23 @@ + + + Liste personale + + Blocate + Permise + RedirecÈ›ionate + + Filtrare domenii + Căutare nume domeniu… + Comutare surse + + Adăugare domeniu în lista neagră + Adăugare domeniu în lista albă + Adăugare redirecÈ›ionare + Editare domeniu blocat + Editare domeniu permis + Editare redirecÈ›ionare + Nume domeniu: + URL domeniu + (Sunt permise caracterele generice * È™i ?) + Adresă IP (IPv4 sau IPv6): + diff --git a/app/src/main/res/values-ro/strings_log.xml b/app/src/main/res/values-ro/strings_log.xml new file mode 100644 index 0000000..13eebc8 --- /dev/null +++ b/app/src/main/res/values-ro/strings_log.xml @@ -0,0 +1,8 @@ + + + + Sortare alfabetică + Sortare domeniu pe nivel superior + + RedirecÈ›ionare domeniu + diff --git a/app/src/main/res/values-ro/strings_notification.xml b/app/src/main/res/values-ro/strings_notification.xml new file mode 100644 index 0000000..b21a528 --- /dev/null +++ b/app/src/main/res/values-ro/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Actualizări + Notificări pentru actualizări noi + Sursele au actualizări disponibile + Sunt disponibile fiÈ™iere noi hosts pentru descărcare. + Este disponibilă o actualizare aplicaÈ›iei + O nouă versiune AdAway este disponibilă pentru descărcare. + + VPN + Notificări în timpul rulării VPN + \ No newline at end of file diff --git a/app/src/main/res/values-ro/strings_prefs_backup_restore.xml b/app/src/main/res/values-ro/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..596e6f4 --- /dev/null +++ b/app/src/main/res/values-ro/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Salvare & restabilire + Salvare + Salvează pe memoria externă regulile de blocare + Restabilire + Restaurare reguli de blocare din fiÈ™ier + diff --git a/app/src/main/res/values-ro/strings_prefs_main.xml b/app/src/main/res/values-ro/strings_prefs_main.xml new file mode 100644 index 0000000..5700f07 --- /dev/null +++ b/app/src/main/res/values-ro/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Setări + + Generale + Temă întunecată + + Luminoasă + ÃŽntunecată + Valoare implicită sistem + + Actualizări automate + + Blocarea reclamelor + Blocarea prin root a reclamelor + Blocarea prin server VPN a reclamelor + Activare suport IPv6 + Salvare / restabilire copie de rezervă pentru regulile de blocare + + Depanare + Trimitere raport erori + Raportează către Sentry (sentry.io) + Nesuportat în această versiune + Depanare cu jurnal în timp real + Este necesară repornirea aplicaÈ›iei pentru aplicare + diff --git a/app/src/main/res/values-ro/strings_prefs_root.xml b/app/src/main/res/values-ro/strings_prefs_root.xml new file mode 100644 index 0000000..5d106a9 --- /dev/null +++ b/app/src/main/res/values-ro/strings_prefs_root.xml @@ -0,0 +1,36 @@ + + + Blocarea prin root\na reclamelor + + Instalare hosts + Deschide fiÈ™ierul hosts + LocaÈ›ia fiÈ™ierului hosts + CitiÈ›i sfaturile de ajutor înainte de a utiliza funcÈ›ia + + /system/etc/hosts + /data/hosts + /data/data/hosts + LocaÈ›ie personalizată + + LocaÈ›ie personalizată hosts + Ascunde dialogul de repornire după aplicare + + RedirecÈ›ionare + Definire domeniu de redirecÈ›ionare pentru domeniile blocate din hosts + RedirecÈ›ionare IPv4 + RedirecÈ›ionare IPv6 + + Server web local + Serverul web local ascultă pe adresa IP locală pentru a răspunde cererilor făcute de către domeniile blocate. Poate fi de ajutor dacă aplicaÈ›ia nu funcÈ›ionează fără conexiune. + Activare server web + Testare server web + Instalare certificat subsemnat + Instalare manuală certificat + ÃŽncepând cu versiunea 11 a Android (R), nu se mai pot instala automat certificate de autoritate (CA).\n\nAccesaÈ›i setarea \"Securitate\", \"Criptare È™i date de conectare\" apoi \"InstalaÈ›i de pe stocare\". AlegeÈ›i \"Certificat CA\" È™i instalaÈ›i certificatul exportat de aplicaÈ›ie. + AccesaÈ›i setarea \"Securitate\" (Security)
    + Verificare… + Nu rulează + Rulează fără certificat instalat + Rulează cu certificat instalat + Înlocuiește spațiul liber destinat reclamelor cu pictograma aplicației +
    diff --git a/app/src/main/res/values-ro/strings_prefs_update.xml b/app/src/main/res/values-ro/strings_prefs_update.xml new file mode 100644 index 0000000..0df5a9d --- /dev/null +++ b/app/src/main/res/values-ro/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + Actualizări + + Actualizări aplicaÈ›ie + Verificare actualizări la pornire + Verificare periodică + Include versiuni in stadiul \"beta\" + + Actualizări fiÈ™ier hosts + Verificare actualizări la pornire + Verificare periodică + Sincronizare la actualizare + Sincronizare doar pe reÈ›ea necontorizată + diff --git a/app/src/main/res/values-ro/strings_prefs_vpn.xml b/app/src/main/res/values-ro/strings_prefs_vpn.xml new file mode 100644 index 0000000..9eac5df --- /dev/null +++ b/app/src/main/res/values-ro/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Blocarea prin server VPN a reclamelor + + Activare la pornire + Monitorizare conexiune + Verificare periodică a stării internetului pentru repornirea VPN la deconectare + + AplicaÈ›ii excluse + AlegeÈ›i aplicaÈ›iile care nu ar trebui să fie blocate de către VPN deci conexiunea lor va rămâne nerestricÈ›ionată + Excludere aplicaÈ›ii de sistem + + Niciuna + Toate cu excepÈ›ia navigatoarelor web + Toate + + Excludere aplicaÈ›ii instalate de utilizator + + + AplicaÈ›ii excluse + Selectare toate + Anulare selecÈ›ie + Pictograma aplicaÈ›iei + diff --git a/app/src/main/res/values-ro/strings_support.xml b/app/src/main/res/values-ro/strings_support.xml new file mode 100644 index 0000000..efbdf53 --- /dev/null +++ b/app/src/main/res/values-ro/strings_support.xml @@ -0,0 +1,5 @@ + + + Suport + Devino sponsor + \ No newline at end of file diff --git a/app/src/main/res/values-ro/strings_update.xml b/app/src/main/res/values-ro/strings_update.xml new file mode 100644 index 0000000..16405f8 --- /dev/null +++ b/app/src/main/res/values-ro/strings_update.xml @@ -0,0 +1,18 @@ + + + Actualizare AdAway + + Actualizare disponibilă! + + + AveÈ›i ultimele actualizări + Actualizare disponibilă + AdAway se actualizează + Actualizează acum + %1$s / %2$s + Modificări recente: + Modificări: + + + Se descarcă ultima versiune a AdAway… + diff --git a/app/src/main/res/values-ro/strings_welcome.xml b/app/src/main/res/values-ro/strings_welcome.xml new file mode 100644 index 0000000..5ddcfc9 --- /dev/null +++ b/app/src/main/res/values-ro/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Bun venit + Configurator - primul pas + Configurator - Pasul 2 + Configurator - utlimul pas + + + Bun venit la AdAway! + AdAway dispune de două metode pentru a bloca reclamele. Alege-o pe cea potrivită: + + Logo rooting + Blocarea prin root\na reclamelor + Rapidă + Consum redus al bateriei + Acces root necesar + + Logo VPN + Blocarea prin server VPN\na reclamelor + Lentă + Rulează în fundal + Compatibilitate + + Necesită acces root pe Android + Este posibil ca fiÈ™ierul binar SU să nu fie găsit sau nu ai acordat permisiunea de acces root pentru AdAway.\n\nAcest lucru se poate întâmpla dacă dispozitivul tău nu este root-at. PoÈ›i afla mai multe informaÈ›ii despre cum să obÈ›ii acces root pe dispozitivul tău pe wiki.lineageos.org sau alte site-uri despre Android. + + Pro + Contra + + + Sincronizare finalizată + Eroare în timpul sincronizării + + Sincronizare + Sincronizat! + AdAway descarcă conÈ›inut online din serverele cu reclame pentru a le restricÈ›iona. PoÈ›i alege ulterior conÈ›inutul blocat din setări. + Reîncearcă sincronizarea + Imposibil de sincronizat: %1$s ReîncercaÈ›i acum? + + + Suport + SusÈ›ine-mă! + Este un program cu sursă deschisă. ÃŽl programez în timpul meu liber. +Dacă È›i-a plăcut, îți poÈ›i arăta recunoÈ™tinÈ›a astfel: + Donează pe PayPal + ÃŽÈ›i plac erorile? Nici mie. + Activare serviciu de urmărire pentru trimiterea de rapoarte cu erori. + + + ÃŽnapoi + Următorul + Finalizare + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml new file mode 100644 index 0000000..dcd01b3 --- /dev/null +++ b/app/src/main/res/values-ru/strings.xml @@ -0,0 +1,290 @@ + + + + Выйти + Закрыть + Да + Ðет + Добавить + Отменить + Сохранить + Помощь + + + Добро пожаловать! + AdAway — Ñто беÑплатное приложение Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом Ð´Ð»Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ рекламы. Оно Ñобирает адреÑа из рекламной Ñети и блокирует их на вашем уÑтройÑтве.\nХотите узнать больше? Читайте Ñправку! + РаÑÑˆÐ¸Ñ€ÐµÐ½Ð½Ð°Ñ Ñправка + Обновить ÑÑ‚Ð°Ñ‚ÑƒÑ + Ð’Ñе ÑпиÑки хоÑтов загружаютÑÑ Ð¸Ð· определенных иÑточников, объединÑÑŽÑ‚ÑÑ Ñ Ð²Ð°ÑˆÐ¸Ð¼Ð¸ ÑобÑтвенными ÑпиÑками и уÑтанавливаютÑÑ Ð² вашу ÑиÑтему в виде единого файла hosts. + Вкл. блокировку рекламы + Откл. блокировку рекламы + Веб-Ñервер + Работает + ОÑтановлено + ЗапуÑк или оÑтановка веб-Ñервера в локальной ÑиÑтеме Ð´Ð»Ñ Ð¾Ñ‚Ð²ÐµÑ‚Ð¾Ð² на запроÑÑ‹ на заблокированные хоÑты. + Включить веб-Ñервер + Отключить веб-Ñервер + VPN + Работает + ОÑтановлено + ЗапуÑтить или оÑтановить VPN Ð´Ð»Ñ Ñ„Ð¸Ð»ÑŒÑ‚Ñ€Ð°Ñ†Ð¸Ð¸ запроÑов. + Включить VPN + Отключить VPN + + + Редактировать запиÑÑŒ + Применить + Изменить + Удалить + + + Импорт… + Ð ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ ÑƒÑпешно импортирована из вашего внешнего хранилища. + Ðе удалоÑÑŒ импортировать резервную копию. Возможно, её формат не верен? Проверьте logcat Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð½Ð¾Ñтей. + ЭкÑпорт… + Ð ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ ÑƒÑпешно ÑкÑпортирована в файл \'%s\' в вашем внешнем хранилище. + Ðе удалоÑÑŒ ÑкÑпортировать файл резервной копии \'%s\'. + + + Файл hosts + Файл hosts — Ñто ÑиÑтемный файл, ÑопоÑтавлÑющий имена узлов Ñ IP-адреÑами. Это обычный текÑтовый файл, Ñодержимое которого обрабатываетÑÑ Ð² AdAway. Вот неÑколько его первых Ñтрок: + ЗагружаетÑÑ Ñодержимое файла hosts… + Открыть файл hosts + + + Проверка обновлений + ПроверÑем %s на наличие обновлений + Получение иÑточников + Загрузка иÑточника %s + Чтение иÑточник %s + Обработка иÑточника %s + Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» базы данных + ВоÑÑтановление Ñтандартного файла hosts + Стандартный файл hosts воÑÑтановлен + Создание Ñтандартного файла hosts + ДоÑтупно обновление иÑточников + ДоÑтупны более новые ÑпиÑки хоÑтов + ÐžÐ±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸Ñточников не найдены + Подключение к Интернету отÑутÑтвует + Ðет доÑтупного Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº интернету + ÐедоÑтупные иÑточники + Ðет доÑтупных иÑточников хоÑтов! + ДоÑтуп root был отклонён + Разрешите root-доÑтуп из вашего Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ root + Что-то пошло не так + Смотрите logcat Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð½Ð¾Ñтей + Подключено + ИÑпользуютÑÑ Ñвежие ÑпиÑки + Отключено + УÑтановлен Ñтандартный файл hosts + Применить Ñвежие иÑточники + Создание нового файла hosts + Копирование нового файла hosts + Проверка копии файла hosts + Файл hosts уÑпешно обновлён + ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ VPN уÑпешно обновлена + ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð°. Вам нужно применить её. + Применить + Применение новой конфигурации… + Ðе удалоÑÑŒ применить новую конфигурацию. + + + СимволичеÑÐºÐ°Ñ ÑÑылка на целевой файл hosts отÑутÑтвует + СимволичеÑÐºÐ°Ñ ÑÑылка на ваш /system/etc/hosts не ÑущеÑтвует или неверна! AdAway не будет работать, еÑли не указать правильный файл.\n\nÐ’Ñ‹ хотите попробовать Ñоздать ÑимволичеÑкую ÑÑылку? + СимволичеÑÐºÐ°Ñ ÑÑылка отÑутÑтвует + Ðе хватает меÑта на диÑковом разделе!\nПопробуйте заменить путь к файлу hosts в наÑтройках на /data/data/hosts. + ÐедоÑтаточно меÑта + Ðе получаетÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚ÑŒ загруженный файл + Сбой личного файла + Ðе получилоÑÑŒ перемонтировать раздел в режим чтениÑ/запиÑи! + Перемонтирование не удалоÑÑŒ + Ðе удалоÑÑŒ Ñкопировать файл hosts + Копирование файлов hosts не удалоÑÑŒ + Копирование не удалоÑÑŒ + Применены иÑточники хоÑтов + Применение прошло уÑпешно + Применение прошло уÑпешно. +Возможно, потребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ñ‚ÑŒ Android, чтобы Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²Ñтупили в Ñилу. + +Ð’Ñ‹ хотите перегрузить Android? +(Ð”Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñ‚ÐµÑ€Ð¸ данных убедитеÑÑŒ, что никакие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² данный момент не иÑпользуют карту памÑти!) + СÑылка Ñоздана уÑпешно. +Возможно, потребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ñ‚ÑŒ Android, чтобы Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²Ñтупили в Ñилу. + +Ð’Ñ‹ хотите перегрузить Android? +(Ð”Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñ‚ÐµÑ€Ð¸ данных убедитеÑÑŒ, что никакие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² данный момент не иÑпользуют карту памÑти!) + СимволичеÑÐºÐ°Ñ ÑÑылка Ñоздана уÑпешно + Android не Ñмог Ñоздать ÑимволичеÑкую ÑÑылку.\nВозможно, Ñто из-за \'функции\' телефонов HTC, называемой S-ON!\n\nРешение ÑоÑтоит в том, чтобы загрузить телефон в режим воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸ Ñоздать там ÑимволичеÑкую ÑÑылку при помощи \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nЕÑли Ñто не поможет, то надо иÑкать информацию в интернете по S-OFF и вашему телефону. + Ðе удалоÑÑŒ Ñоздать ÑимволичеÑкую ÑÑылку + ПожалуйÑта, прочтите Справку, чтобы узнать больше. + Ð’ наÑтройках APN вашего Android указан прокÑи-Ñервер!\nAdAway не будет работать надежно в мобильных ÑетÑÑ…, таких как 3G. Ð’Ñ‹ можете отключить Ñтот Ñервер прокÑи в наÑтройках иÑпользуемой APN (из Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÐаÑтройки: Сеть и Интернет -> ÐœÐ¾Ð±Ð¸Ð»ÑŒÐ½Ð°Ñ Ñеть -> Дополнительно -> Точки доÑтупа APN) и удалить значение в поле прокÑи. + ИÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÐµÐ¼Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° доÑтупа работает через прокÑи-Ñервер! + Подключение к Интернету не работает + Ðет Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ + Загрузка… + Применение… + Применить Чёрный и Белый ÑпиÑки + Разбор и объединение файлов Ñо ÑпиÑками хоÑтов + ПоÑтроение файла hosts + Применение файла hosts + Ðе удалоÑÑŒ применить новый файл hosts. + Ðе удалоÑÑŒ применить файл hosts на вашей ÑиÑтеме!\nПопробуйте изменить путь к файлу hosts в наÑтройках на /data/data/hosts. + Ðе удалоÑÑŒ + ПожалуйÑта, проверьте ваше приложение Ð´Ð»Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ root-доÑтупом, чтобы убедитьÑÑ, что root-доÑтуп был предоÑтавлен. + Ð’Ñ‹ вернулиÑÑŒ к файлу hosts по умолчанию. +Возможно, потребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ñ‚ÑŒ Android, чтобы Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²Ñтупили в Ñилу. + +Ð’Ñ‹ хотите перегрузить Android? +(Ð”Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñ‚ÐµÑ€Ð¸ данных убедитеÑÑŒ, что никакие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² данный момент не иÑпользуют карту памÑти!) + Возврат произошёл уÑпешно + Ðе удалоÑÑŒ воÑÑтановить файл hosts + ВоÑÑтановление не удалоÑÑŒ по неизвеÑтным причинам. + ВоÑÑтановление не удалоÑÑŒ! + Ðи один из ваших активных иÑточников хоÑтов недоÑтупен! Ð’Ñ‹ правильно подключены к интернету? + Загрузка не удалаÑÑŒ + Ðе удалоÑÑŒ запиÑать новый личный файл hosts + Личный файл не может быть Ñоздан. + Ðе удалоÑÑŒ Ñоздать личный файл + Ð’Ñ‹ активировали беÑÑиÑтемный режим. +Возможно, потребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ°, чтобы Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²Ñтупили в Ñилу. + +Ð’Ñ‹ хотите перезагрузить ÑиÑтему? +(Ð”Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñ‚ÐµÑ€Ð¸ данных убедитеÑÑŒ, что никакие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² данный момент не иÑпользуют карту памÑти!) + ÐÐºÑ‚Ð¸Ð²Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¾ÑˆÐ»Ð° уÑпешно + Ð’Ñ‹ отключили беÑÑиÑтемный режим. +Возможно, потребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ°, чтобы Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²Ñтупили в Ñилу. + +Ð’Ñ‹ хотите перезагрузить ÑиÑтему? +(Ð”Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñ‚ÐµÑ€Ð¸ данных убедитеÑÑŒ, что никакие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² данный момент не иÑпользуют карту памÑти!) + УÑпешно отключено + Ðе удалоÑÑŒ включить VPN блокировку рекламы. + Ðе удалоÑÑŒ отключить VPN блокировку рекламы. + Включить модуль хоÑтов Magisk + Включить функцию беÑÑиÑтемных хоÑтов из Magisk. Ð’ его наÑтройках включите параметр БеÑÑиÑтемный hosts, затем перезапуÑтите ваше уÑтройÑтво. + Отключить модуль хоÑтов Magisk + Выключить функцию беÑÑиÑтемных хоÑтов из Magisk. Из ÑпиÑка модулей удалите модуль БеÑÑиÑтемный hosts, затем перезапуÑтите ваше уÑтройÑтво. + + + Ð’Ñтавьте URL-Ð°Ð´Ñ€ÐµÑ Ð² файл hosts: + Это недопуÑтимое Ð¸Ð¼Ñ Ñ…Ð¾Ñта! + Ðеправильно отформатированное Ð¸Ð¼Ñ Ñ…Ð¾Ñта + Это недопуÑтимый IP-адреÑ! + Ðеправильно отформатированный IP-Ð°Ð´Ñ€ÐµÑ + Ðикогда не перезагружать и не показывать Ñтот Ð²Ð¾Ð¿Ñ€Ð¾Ñ Ð² дальнейшем! + Загрузка… + + + Обновить + Добавить + Помощь + Импортировать резервную копию + ЭкÑпортировать резервную копию + + + S-ON/S-OFF + FAQ + Проблемы + + + ÐŸÑ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¾Ð¹ + ПоиÑк приложений Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¾Ð¹, называемые Adware, и которые AdAway не может заблокировать. Эти Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸Ñпользуют, например, ÑиÑтему уведомлений Airpush, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°ÐµÑ‚ рекламу даже тогда, когда приложение не работает, или даже может изменить мелодию вашего звонка. ИзбавитьÑÑ Ð¾Ñ‚ такой рекламы можно только удалив приложениÑ, указанные в результатах ÑканированиÑ, путём Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ Ð½Ð° Ñлементы ÑпиÑка. + Сканирование… + ÐŸÑ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¾Ð¹ не найдены! + + + Блокировщик рекламы + ТекÑтовый редактор не уÑтановлен + Ðе найден текÑтовый редактор Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° hosts. Ð’Ñ‹ можете уÑтановить редактор Jota или другой текÑтовый редактор, чтобы Ñто иÑправить.\n\nÐ’Ñ‹ хотите уÑтановить редактор Jota? + Файловый менеджер не уÑтановлен + Ðет файлового менеджера Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð°. Ð’Ñ‹ можете уÑтановить OI File Manager или другой файловый менеджер, чтобы Ñто иÑправить.\n\nÐ’Ñ‹ хотите уÑтановить OI File Manager? + + + Tcpdump + Tcpdump — Ñто инÑтрумент Ð´Ð»Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ð° запроÑов DNS и их ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð² файле журнала. ЗапуÑтите Tcpdump, он будет работать в фоновом режиме до перезагрузки уÑтройÑтва — запуÑтите приложение, в котором на Ñкране показываетÑÑ Ñ€ÐµÐºÐ»Ð°Ð¼Ð° — проанализируйте запроÑÑ‹ DNS, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ñ„Ð°Ð¹Ð» журнала. Ðайденные в нём подозрительные Ñерверы, возможные иÑточники рекламы, могут быть внеÑены в чёрный ÑпиÑок. + Откл. мониторинг + Вкл. мониторинг + Результаты + Сортировать домены + ОчиÑтить журнал + Добавить запиÑÑŒ в Чёрный ÑпиÑок + Добавить запиÑÑŒ в Белый ÑпиÑок + Добавить запиÑÑŒ в ÑпиÑок Перенаправлений + + Править значение текÑтового Ð¿Ñ€ÐµÐ´Ð¿Ð¾Ñ‡Ñ‚ÐµÐ½Ð¸Ñ + Открыть меню + Закрыть меню + + + + Ð“Ð»Ð°Ð²Ð½Ð°Ñ + ИÑточники хоÑтов + Ваши ÑпиÑки + Открыть файл hosts + Журнал DNS-запроÑов + Сканирование на наличие приложений Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¾Ð¹ + ÐаÑтройки + Помощь + + + + + ЗапроÑÑ‹ DNS + Ваши ÑпиÑки + ÐаÑтройки + + + УÑтановлено %1$s назад + Ðктуально %1$s + ТребуетÑÑ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ðµ %1$s + ПоÑледнее обновление %1$s назад + ÐеизвеÑтный ÑÑ‚Ð°Ñ‚ÑƒÑ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ + Отключено + неÑколько минут + + %d минута + %d минуты + %d минут + %d минут + + + %d Ñ‡Ð°Ñ + %d чаÑа + %d чаÑов + %d чаÑов + + + %d день + %d Ð´Ð½Ñ + %d дней + %d дней + + + %d меÑÑц + %d меÑÑца + %d меÑÑцев + %d меÑÑцев + + + + ХоÑÑ‚ Ñкопирован в буфер обмена + + + начинаетÑÑ + активно + оÑтановлено + ожидание Ñети + переподключение + ошибка Ð¿ÐµÑ€ÐµÐ¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ + приоÑтановлено + оÑтановлено + Блокировщик рекламы VPN %1$s + ПриоÑтановить + Продолжить + + + Ð Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ AdAway + Разрешить взаимодейÑтвие Ñ AdAway + Отправить команды в AdAway + Разрешить AdAway отправлÑть такие команды, как включение или отключение общеÑиÑтемной блокировки рекламы. + + diff --git a/app/src/main/res/values-ru/strings_app.xml b/app/src/main/res/values-ru/strings_app.xml new file mode 100644 index 0000000..b05f0e6 --- /dev/null +++ b/app/src/main/res/values-ru/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Блокировщик рекламы Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом + Логотип AdAway + diff --git a/app/src/main/res/values-ru/strings_errors.xml b/app/src/main/res/values-ru/strings_errors.xml new file mode 100644 index 0000000..cb657b9 --- /dev/null +++ b/app/src/main/res/values-ru/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Подключение к Интернету отÑутÑтвует + Ðевозможно уÑтановить Ñоединение Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð½ÐµÑ‚Ð¾Ð¼. ПожалуйÑта, проверьте подключение вашего уÑтройÑтва. + Ðе удалоÑÑŒ загрузить иÑточники хоÑта + Ðи один из ваших включенных иÑточников хоÑтов недоÑтупен. ПожалуйÑта, проверьте подключение к интернету. + + Ðе удалоÑÑŒ Ñоздать личный файл + Ðевозможно Ñоздать личный файл Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ иÑточника. ПожалуйÑта, проверьте Ñвободное меÑто на вашем уÑтройÑтве. + Ðе хватает меÑта + Ðевозможно Ñкопировать файл hosts в ÑиÑтемный раздел. УбедитеÑÑŒ, что беÑÑиÑтемный модуль Magisk включен, затем перезагрузите Ñмартфон. + Ðе удалоÑÑŒ уÑтановить новый файл hosts + Ðе удалоÑÑŒ Ñкопировать файл hosts в раздел /system. ПожалуйÑта, проверьте включен ли беÑÑиÑтемный модуль Magisk, а затем перезагрузитеÑÑŒ. + Ðе удалоÑÑŒ воÑÑтановить файл hosts + Ðевозможно воÑÑтановить конфигурацию файла host по умолчанию. + + Ðе удалоÑÑŒ включить VPN блокировку рекламы. + ПожалуйÑта, проверьте наÑтройки VPN, чтобы авторизовать приложение VPN Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑка. + Ðе удалоÑÑŒ отключить VPN блокировку рекламы. + ПожалуйÑта, проверьте наÑтройки VPN, чтобы отключить его вручную. + diff --git a/app/src/main/res/values-ru/strings_home.xml b/app/src/main/res/values-ru/strings_home.xml new file mode 100644 index 0000000..30c61d3 --- /dev/null +++ b/app/src/main/res/values-ru/strings_home.xml @@ -0,0 +1,50 @@ + + + + + Блокировано + Разрешено + Перенаправлено + + + + %d обновлённый иÑточник + %d обновлённых иÑточника + %d обновлённых иÑточников + %d обновлённых иÑточников + + + %d уÑтаревший иÑточник + %d уÑтаревших иÑточника + %d уÑтаревших иÑточников + %d уÑтаревших иÑточников + + Проверить Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ…Ð¾Ñтов + Обновить хоÑты + + + Показать журнал запроÑов DNS + + + Показать Ñправку\nи Ñоветы + + + Открыть Ñтраницу GitHub + + + Поддержать проект + + + Проект на GitHub + ÐаÑтройки + + + Открыть боковое меню + ПриоÑтановить/продолжить блокировку рекламы + Обновить заблокированные домены + Показать запрошенные домены + + + ПожалуйÑта, прочтите Справку, чтобы узнать больше. + + \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings_hosts.xml b/app/src/main/res/values-ru/strings_hosts.xml new file mode 100644 index 0000000..d51e37d --- /dev/null +++ b/app/src/main/res/values-ru/strings_hosts.xml @@ -0,0 +1,17 @@ + + + ИÑточники хоÑтов + + СпиÑок пользоватей + Официальные ÑпиÑки от AdAway + Единые ÑпиÑки от StevenBlack + СпиÑки блокировки от Pete Lowe + + недоÑтупен + %s ÑпиÑки + + Добавить иÑточник + Редактировать иÑточник + URL: (реÑÑƒÑ€Ñ https:// или file://) + URL-Ð°Ð´Ñ€ÐµÑ Ð¸Ñточника хоÑтов + diff --git a/app/src/main/res/values-ru/strings_lists.xml b/app/src/main/res/values-ru/strings_lists.xml new file mode 100644 index 0000000..78dc714 --- /dev/null +++ b/app/src/main/res/values-ru/strings_lists.xml @@ -0,0 +1,24 @@ + + + Ваши ÑпиÑки + Добавить хоÑÑ‚ + + Блокировано + Разрешено + Перенаправлено + + Фильтровать хоÑты + ПоиÑк имени хоÑта… + Переключить иÑточники + + Добавить хоÑÑ‚ в Чёрный ÑпиÑок + Добавить хоÑÑ‚ в Белый ÑпиÑок + Добавить перенаправление хоÑта + Редактировать хоÑÑ‚ Чёрного ÑпиÑка + Редактировать хоÑÑ‚ Белого ÑпиÑка + Редактировать перенаправление + Ð˜Ð¼Ñ Ð¸Ñточника: + URL-Ð°Ð´Ñ€ÐµÑ Ð¸Ñточника хоÑтов + (ДопуÑкаютÑÑ Ð¿Ð¾Ð´Ñтановочные Ñимволы * и ?) + IP (IPv4 или IPv6): + diff --git a/app/src/main/res/values-ru/strings_log.xml b/app/src/main/res/values-ru/strings_log.xml new file mode 100644 index 0000000..6762f23 --- /dev/null +++ b/app/src/main/res/values-ru/strings_log.xml @@ -0,0 +1,11 @@ + + + Переключить запиÑÑŒ журнала + Ðажмите кнопку запиÑи, чтобы начать логирование запроÑов, поищите что-нибудь в интернете или воÑпользуйтеÑÑŒ другими приложениÑми, а затем вернитеÑÑŒ назад или потÑните вниз, чтобы обновить логи. + \n\nBlocked запроÑÑ‹ не будут логированы. Сначала отключите блокировку рекламы, еÑли вы также хотите их логировать. + + Сортировка по алфавиту + Сортировка по наивыÑшему уровню домена + + Перенаправить домен + diff --git a/app/src/main/res/values-ru/strings_notification.xml b/app/src/main/res/values-ru/strings_notification.xml new file mode 100644 index 0000000..22c4637 --- /dev/null +++ b/app/src/main/res/values-ru/strings_notification.xml @@ -0,0 +1,13 @@ + + + + ÐžÐ±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ + Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾Ð± обновлении + ДоÑтупно обновление + ДоÑтупны более новые ÑпиÑки хоÑтов Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸. + ДоÑтупно обновление Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + ÐÐ¾Ð²Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ AdAway доÑтупна Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸. + + VPN + Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ работе VPN + \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings_prefs_backup_restore.xml b/app/src/main/res/values-ru/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..f3cf048 --- /dev/null +++ b/app/src/main/res/values-ru/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Ð ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ Ð¸ воÑÑтановление + Ð ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ + Сохранить резервную копию ваших правил блокировки на внешний ноÑитель + ВоÑÑтановление + ВоÑÑтановить ваши правила блокировки из файла резервной копии + diff --git a/app/src/main/res/values-ru/strings_prefs_main.xml b/app/src/main/res/values-ru/strings_prefs_main.xml new file mode 100644 index 0000000..0654e90 --- /dev/null +++ b/app/src/main/res/values-ru/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + ÐаÑтройки + + Главные + Выбрать тему + + Ð¡Ð²ÐµÑ‚Ð»Ð°Ñ + Ð¢ÐµÐ¼Ð½Ð°Ñ + Ðа оÑнове ÑиÑтемной + + ÐвтоматичеÑкие Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ + + Блокировка рекламы + Блокировщик рекламы на оÑнове root + Блокировщик рекламы на оÑнове VPN + Включить поддержку IPv6 + Ð ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ / воÑÑтановление правил блокировки + + Режим отладки + ОтправлÑть отчёты об ошибках + ОтправлÑть в Sentry (sentry.io) + Ðе поддерживаетÑÑ Ð² Ñтой Ñборке + Подробный журнал отладки + Ð”Ð»Ñ Ð¿Ñ€Ð¸Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ‚Ñ€ÐµÐ±ÑƒÐµÑ‚ÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿ÑƒÑк Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + diff --git a/app/src/main/res/values-ru/strings_prefs_root.xml b/app/src/main/res/values-ru/strings_prefs_root.xml new file mode 100644 index 0000000..2553ce1 --- /dev/null +++ b/app/src/main/res/values-ru/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Блокировщик рекламы на оÑнове root + + УÑтановка хоÑтов + Открыть файл hosts + Путь к файлу hosts + Прочитайте Справку перед иÑпользованием Ñтой функции + + /system/etc/hosts + /data/hosts + /data/data/hosts + ПользовательÑкие наÑтройки + + ПользовательÑкое целевое раÑположение + Скрыть диалог перезагрузки поÑле Ð¿Ñ€Ð¸Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ + + ПереадреÑÐ°Ñ†Ð¸Ñ + Определить куда переадреÑовывать заблокированные хоÑты + Перенаправление IPv4 + Перенаправление IPv6 + Ðеверное перенаправление + + Локальный веб-Ñервер + Локальный веб-Ñервер проÑлушивает локальные IP адреÑа и отвечает на запроÑÑ‹ к заблокированным хоÑтам. Это поможет избегать завиÑаний при блокировке подключений. + Включить веб-Ñервер + Проверить веб-Ñервер + УÑтановить ÑамоподпиÑанный Ñертификат + УÑтановка Ñертификата вручную + ÐÐ°Ñ‡Ð¸Ð½Ð°Ñ Ñ Android 11 (R), приложение больше не может автоматичеÑки уÑтанавливать центр Ñертификации (CA).\n\nПерейдите в наÑтройки \"БезопаÑноÑть\", \"Шифрование личных данных\", затем \"УÑтановить Ñертификат\". Оттуда выберите \"Сертификат CA\" и выберите только что ÑкÑпортированный файл Ñертификата. + Откройте наÑтройки безопаÑноÑти + Проверка… + Ðе запущен + Запущен, но Ñертификат не уÑтановлен + Запущен и Ñертификат уÑтановлен + Заменить пуÑтое меÑто от рекламы логотипом Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + diff --git a/app/src/main/res/values-ru/strings_prefs_update.xml b/app/src/main/res/values-ru/strings_prefs_update.xml new file mode 100644 index 0000000..391914e --- /dev/null +++ b/app/src/main/res/values-ru/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + ÐžÐ±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ + Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ñ‹ + Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ð¹ не будут отображатьÑÑ. Ðажмите, чтобы включить их. + + ÐžÐ±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + ПроверÑть Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ запуÑке + ПериодичеÑÐºÐ°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° обновлений + Ð’ÐºÐ»ÑŽÑ‡Ð°Ñ Ð±ÐµÑ‚Ð°-верÑии + + ÐžÐ±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ…Ð¾Ñтов + ПроверÑть Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ запуÑке + ПериодичеÑÐºÐ°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° обновлений + Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸ обновлении + Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ в нетарифицируемой Ñети + diff --git a/app/src/main/res/values-ru/strings_prefs_vpn.xml b/app/src/main/res/values-ru/strings_prefs_vpn.xml new file mode 100644 index 0000000..822f81d --- /dev/null +++ b/app/src/main/res/values-ru/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Блокировщик рекламы на оÑнове VPN + + Включить при запуÑке + Проверка ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ + ПериодичеÑки проверÑйте ÑоÑтоÑние Ñети, чтобы перезапуÑтить VPN при отключении. + + ИÑключённые Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + ÐаÑтройте, какие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ должны иÑпользовать VPN, чтобы никакие ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð½Ðµ блокировалиÑÑŒ. + ИÑключить ÑиÑтемные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + + Ðикакие + Ð’Ñе, кроме браузеров + Ð’Ñе + + ИÑключить пользовательÑкие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + + + ИÑключённые Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + Выбрать вÑе + Отменить выбрать вÑе + Значок Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + diff --git a/app/src/main/res/values-ru/strings_source_edit.xml b/app/src/main/res/values-ru/strings_source_edit.xml new file mode 100644 index 0000000..d6d4029 --- /dev/null +++ b/app/src/main/res/values-ru/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Редактировать иÑточник + Добавить иÑточник + + Метка + ТребуетÑÑ Ð¼ÐµÑ‚ÐºÐ° + Тип + URL + Файл + МеÑтоположение + https:// + ТребуетÑÑ Ð´Ð¾Ñтуп к МеÑтоположению + Ðажмите Файл, чтобы выбрать иÑходный файл + Ðеверное меÑтоположение + Формат ÑпиÑка + Блокировать + Разрешить + Применить перенаправленные хоÑты + Разрешение Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñ…Ð¾Ñтов может вызвать проблемы Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°ÑноÑтью. ИÑпользуйте Ñти наÑтройки только Ð´Ð»Ñ Ð½Ð°Ð´ÐµÐ¶Ð½Ð¾Ð³Ð¾ иÑточника, поÑкольку он может перенаправить некоторый конфиденциальный трафик на любой Ñервер, который ему нужен. + diff --git a/app/src/main/res/values-ru/strings_support.xml b/app/src/main/res/values-ru/strings_support.xml new file mode 100644 index 0000000..ef64378 --- /dev/null +++ b/app/src/main/res/values-ru/strings_support.xml @@ -0,0 +1,5 @@ + + + Поддержать + Стать ÑпонÑором + \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings_update.xml b/app/src/main/res/values-ru/strings_update.xml new file mode 100644 index 0000000..5a431a4 --- /dev/null +++ b/app/src/main/res/values-ru/strings_update.xml @@ -0,0 +1,21 @@ + + + Обновление AdAway + + ДоÑтупно обновление! + + + У Ð²Ð°Ñ Ð°ÐºÑ‚ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ + ДоÑтупно обновление + Обновление AdAway + Обновить ÑÐµÐ¹Ñ‡Ð°Ñ + %1$s / %2$s + ПоÑледние Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ + СпиÑок изменений + Поддержать разработку + Пожертвовать + СпонÑор + + + Скачивание поÑледней верÑии AdAway… + diff --git a/app/src/main/res/values-ru/strings_welcome.xml b/app/src/main/res/values-ru/strings_welcome.xml new file mode 100644 index 0000000..6f3542b --- /dev/null +++ b/app/src/main/res/values-ru/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Добро пожаловать + Первый шаг + Второй шаг + ПоÑледний шаг + + + Добро пожаловать в AdAway! + AdAway предоÑтавлÑет два метода блокировки рекламы. Выберите тот, который вам подходит: + + Логотип root + Root\nблокировка рекламы + БыÑтрее + Экономит батарею + ТребуютÑÑ Ñ€ÑƒÑ‚ права + + Логотип VPN + VPN\nблокировка рекламы + Медленнее + Работает в фоне + СовмеÑтимый + + ТребуетÑÑ Android Ñ Root-правами + Либо двоичный файл su не найден, либо вы не предоÑтавили AdAway права root.\n\nЭто может ÑлучитьÑÑ Ñ‚Ð¾Ð³Ð´Ð°, когда ваше уÑтройÑтво не имеет root-прав. Ð’Ñ‹ можете найти информацию о том, как получить root права на ваше уÑтройÑтво, на wiki.lineageos.org или других Ñайтах Android. + + ПлюÑÑ‹ + МинуÑÑ‹ + + + Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð° + Ошибка при Ñинхронизации + + Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ + Синхронизировано! + AdAway загружает ÑпиÑки блокировки из онлайн-иÑточников. Ð’Ñ‹ можете изменить их позже в наÑтройках. + Повторить Ñинхронизацию + Ошибка Ñинхронизации: %1$s Повторить ÑейчаÑ? + Это поможет отправлÑть ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ÑтатуÑа блокировки рекламы и управлениÑ, а также уведомит, когда будет доÑтупно обновление Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (неÑколько раз в год). Включите, еÑли хотите быть в курÑе Ñобытий. + + + Поддержать + Поддержать менÑ! + AdAway — Ñто беÑплатное приложение Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом, которое Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð°Ñ‚Ñ‹Ð²Ð°ÑŽ в Ñвободное времÑ. ЕÑли она вам нравитÑÑ, не ÑтеÑнÑйтеÑÑŒ оказать Ñвою поддержку: + Пожертвовать на PayPal + Вам не нравÑÑ‚ÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ¸? Мне тоже. + Включить телеметрию Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸ мне отчетов о ÑбоÑÑ… + + + Ðазад + Далее + Закончить + diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml new file mode 100644 index 0000000..9e45587 --- /dev/null +++ b/app/src/main/res/values-si/strings.xml @@ -0,0 +1,14 @@ + + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-si/strings_app.xml b/app/src/main/res/values-si/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-si/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-si/strings_errors.xml b/app/src/main/res/values-si/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-si/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-si/strings_home.xml b/app/src/main/res/values-si/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-si/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-si/strings_hosts.xml b/app/src/main/res/values-si/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-si/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-si/strings_lists.xml b/app/src/main/res/values-si/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-si/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-si/strings_log.xml b/app/src/main/res/values-si/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-si/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-si/strings_notification.xml b/app/src/main/res/values-si/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-si/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-si/strings_prefs_backup_restore.xml b/app/src/main/res/values-si/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-si/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-si/strings_prefs_main.xml b/app/src/main/res/values-si/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-si/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-si/strings_prefs_root.xml b/app/src/main/res/values-si/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-si/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-si/strings_prefs_update.xml b/app/src/main/res/values-si/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-si/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-si/strings_prefs_vpn.xml b/app/src/main/res/values-si/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-si/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-si/strings_support.xml b/app/src/main/res/values-si/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-si/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-si/strings_update.xml b/app/src/main/res/values-si/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-si/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-si/strings_welcome.xml b/app/src/main/res/values-si/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-si/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml new file mode 100644 index 0000000..f80c1a4 --- /dev/null +++ b/app/src/main/res/values-sk/strings.xml @@ -0,0 +1,270 @@ + + + + UkonÄiÅ¥ + ZavrieÅ¥ + Ãno + Nie + PridaÅ¥ + ZruÅ¡iÅ¥ + UložiÅ¥ + Pomoc + + + Vitajte! + AdAway je bezplatný, open sourceový softvér navrhnutý na blokovanie reklamy. Získava adresy reklamných sietí a blokuje ich na vaÅ¡om zariadení.\nChcete vedieÅ¥ viac? Pozrite si pomocníka nižšie! + ZobraziÅ¥ ÄalÅ¡iu pomoc + AktualizovaÅ¥ status + VÅ¡etky hosts súbory z vybraných zdrojov budú stiahnuté, zlúÄené s vaÅ¡imi zoznamami a nainÅ¡talované ako jeden hosts súbor do vášho systému. + PovoliÅ¥ blokovanie reklám + ZakázaÅ¥ blokovanie reklám + Web server + Spustený + Zastavený + SpustiÅ¥ alebo zastaviÅ¥ webserver na zariadení pre odpovedanie na požiadavky blokovaných adries. + PovoliÅ¥ web server + ZakázaÅ¥ web server + VPN + Spustené + Zastavené + SpustiÅ¥ alebo zastaviÅ¥ VPN na filtrovanie požiadaviek. + PovoliÅ¥ VPN + ZakázaÅ¥ VPN + + + UpraviÅ¥ položku + AplikovaÅ¥ + UpraviÅ¥ + VymazaÅ¥ + + + Importovanie… + Záloha úspeÅ¡ne importovaná z vášho externého úložiska. + Nepodarilo sa importovaÅ¥ zálohu. Je jeho formát správny? ÄŽalÅ¡ie podrobnosti nájdete v protokole logcat. + Exportovanie… + Záloha bola úspeÅ¡ne exportovaná do súboru \'%s\' na externom úložisku. + Nepodarilo sa exportovaÅ¥ súbor zálohy \'%s\'. + + + Hosts súbor + Súbor hosts je systémový súbor, ktorý mapuje názvy hostiteľov k IP adresám. Je to jednoduchý textový súbor, ktorého konfiguráciu spracováva AdAway. Tu je zopár jeho prvých riadkov: + NaÄítavanie obsahu hosts súboru… + OtvoriÅ¥ hosts súbor + + + Kontrola aktualizácií + Kontroluje sa aktualizácia pre zdroj %s + Získavanie zdrojov + SÅ¥ahovanie zdroja %s + Čítanie zdroja %s + Analyzuje sa zdroj %s + Synchronizácia databázy pravidiel + Obnovuje sa pôvodný súbor hosts + Pôvodný súbor hosts obnovený + Vytváranie Å¡tandardného hosts súboru + Aktualizácia dostupná + Sú dostupné novÅ¡ie hosts súbory + Neboli nájdené žiadne aktualizácie pre zdroj + Bez internetového pripojenia + Internetové pripojenie nie je dostupné + Nedostupné zdroje + Nie sú dostupné žiadne hosts zdroje! + Prístup ROOT bol odmietnutý + Povoľte prístup ROOT z aplikácie urÄenej na správu prístupu ROOT + NieÄo sa pokazilo + Pre viac informácií skontrolujte logcat + Povolené + Máte najnovÅ¡ie hosts súbory + Zakázané + Predvolený súbor host nainÅ¡talovaný + PoužiÅ¥ najnovÅ¡ie zdroje + Vytváranie nového súboru hosts + Kopírovanie nového súboru hosts + Kontrola kópie súboru hosts + Súbor hosts úspeÅ¡ne aktualizovaný + Nastavenie VPN úspeÅ¡ne aktualizované + Konfigurácia sa zmenila. Musíte ju aplikovaÅ¥. + AplikovaÅ¥ + Aplikuje sa nová konfigurácia… + Nepodarilo sa aplikovaÅ¥ novú konfiguráciu + + + Chýba symbolický odkaz na cieľový súbor hosts + Odkaz z vášho cieľa do /system/etc/hosts neexistuje alebo je nesprávny! AdAway nebude fungovaÅ¥, pokiaľ odkaz nebude smerovaÅ¥ na správny súbor.\n\nChcete sa pokúsiÅ¥ vytvoriÅ¥ odkaz? + Odkaz chýba + Nedostatok miesta na partícii!\nSkúste zmeniÅ¥ umiestnenie hosts súboru v nastaveniach na /data/data/hosts. + Nedostatok miesta + Stiahnutý súbor sa nedá ÄítaÅ¥ + Chyba v súkromnom súbore + Znovupripojenie partície na Äítanie aj zápis zlyhalo! + Znovupripojenie zlyhalo + Nepodarilo sa skopírovaÅ¥ súbor hosts + Kopírovanie hosts súboru zlyhalo! + Kopírovanie zlyhalo + Zdroje hosts aplikované + Aplikovanie úspeÅ¡né + Aplikovanie bolo úspeÅ¡né.\nPre aplikovanie zmien budete musieÅ¥ reÅ¡tartovaÅ¥ zariadenie.\n\nChcete reÅ¡tartovaÅ¥?\n(Aby ste prediÅ¡li strate dát, uistite sa, že žiadna aplikácie práve teraz nepoužíva SD kartu!) + Symbolický odkaz bol úspeÅ¡ne vytvorený.\nPre aplikovanie zmien budete musieÅ¥ reÅ¡tartovaÅ¥ zariadenie.\n\nChcete reÅ¡tartovaÅ¥?\n(Aby ste prediÅ¡li strate dát, uistite sa, že žiadna aplikácie práve teraz nepoužíva SD kartu!) + Vytvorenie odkazu úspeÅ¡né + Symbolický odkaz nemohol byÅ¥ vytvorený Androidom.\nTúto chybu zväÄÅ¡a spôsobuje \"funkcia S-ON na telefónoch HTC!\"\n\nRieÅ¡ením je spustiÅ¥ telefón do režimu recovery a vytvoriÅ¥ symbolický odkaz tam pomocou \"n -s /data/data/hosts /system/etc/hosts\".\n\nAk to nepomôže, vyhľadajte na internete informácie o S-OFF pre váš telefón. + Vytvorenie odkazu zlyhalo + Prosím, pre viac informácií si preÄítajte Pomoc. + Na zariadení je nastavené APN proxy!\nAdAway nebude správne fungovaÅ¥ na mobilných sieÅ¥ach, napr. 3G. Proxy môžete deaktivovaÅ¥ v nastaveniach APN (Nastavenia -> Bezdrôtové pripojenia a siete -> Viac… -> Mobilné siete -> Názvy prístupových bodov) a vymazaním hodnoty Server proxy. + Nastavené APN proxy! + Pripojenie k internetu nefunguje. + Bez pripojenia + SÅ¥ahovanie… + Aplikovanie… + Aplikovanie Äiernej a bielej listiny + Analyzovanie a zluÄovanie hosts súborov + Vytváranie hosts súboru + Aplikovanie hosts súboru + Nepodarilo sa aplikovaÅ¥ nový súbor hosts. + Aplikovanie hosts súboru do vaÅ¡eho systému zlyhalo!\nSkúste zmeniÅ¥ umiestnenie hosts súboru v nastaveniach na /data/data/hosts. + Aplikovanie zlyhalo + Prosím, skontrolujte aplikáciu pre správu prístupu ROOT, aby ste sa uistili, že ste získali ROOT prístup + Obnovili ste súbor hosts na pôvodný.\nPre aplikovanie zmien budete musieÅ¥ reÅ¡tartovaÅ¥ zariadenie.\n\nChcete reÅ¡tartovaÅ¥?\n(Aby ste prediÅ¡li strate dát, uistite sa, že žiadna aplikácie práve teraz nepoužíva SD kartu!) + Obnovenie úspeÅ¡né + Súbor hosts sa nedá obnoviÅ¥ + Obnovenie zlyhalo z neznámeho dôvodu. + Obnovenie zlyhalo! + Žiadny z vaÅ¡ich povolených hosts zdrojov nie je dostupný! Ste správne pripojený k internetu? + SÅ¥ahovanie zlyhalo + Nepodarilo sa zapísaÅ¥ nový súkromný súbor hosts + Súkromný súbor nemožno vytvoriÅ¥. + Vytváranie súboru zlyhalo + Povolili ste bezsystémový režim.\nPre aplikovanie zmien budete musieÅ¥ reÅ¡tartovaÅ¥ zariadenie.\n\nChcete reÅ¡tartovaÅ¥?\n(Aby ste prediÅ¡li strate dát, uistite sa, že žiadna aplikácie práve teraz nepoužíva SD + ÚspeÅ¡ne povolené + Zakázali ste bezsystémový režim.\nPre aplikovanie zmien budete musieÅ¥ reÅ¡tartovaÅ¥ zariadenie.\n\nChcete reÅ¡tartovaÅ¥?\n(Aby ste prediÅ¡li strate dát, uistite sa, že žiadna aplikácie práve teraz nepoužíva SD kartu!) + Zakázanie úspeÅ¡né + Nepodarilo sa povoliÅ¥ blokovanie reklamy pomocou VPN. + Nepodarilo sa zakázaÅ¥ blokovanie reklamy pomocou VPN. + Povolenie Magisk modulu hosts + Povoľte funkciu Systemless hosts v Magisk Manageri. V jeho nastavení povoľte voľbu Systemless hosts, a potom reÅ¡tartujte zariadenie. + Zakázanie Magisk modulu hosts + Zakážte funkciu Systemless hosts v Magisk Manageri. V zozname modulov odinÅ¡talujte 1Systemless hosts1, a potom reÅ¡tartujte zariadenie. + + + Zadajte URL k hosts súboru: + Toto nie je platný názov hostiteľa! + Nesprávne formulovaný názov hostiteľa + Toto nie je platná IP! + Nesprávne formulovaná IP + Nikdy nereÅ¡tartovaÅ¥ a túto otázku už nezobrazovaÅ¥! + NaÄítavanie… + + + ObnoviÅ¥ + PridaÅ¥ + Pomoc + ImportovaÅ¥ zálohu + ExportovaÅ¥ zálohu + + + S-ON/S-OFF + FAQ + Problémy + + + Adware + Tu môžete nájsÅ¥ nainÅ¡talované Adware aplikácie, zlé aplikácie, ktoré AdAway nemôže zablokovaÅ¥. Tieto aplikácie používajú napríklad Airpush upozornenia, ktoré sa zobrazujú aj keÄ aplikácia nie je spustená alebo vám môžu zmeniÅ¥ zvonenie. Jediné dostupné protiopatrenie je odinÅ¡talovaÅ¥ tieto aplikácie kliknutím na položku v zozname. + Vyhľadávanie… + Nebol nájdený žiadny adware. + + + Blokovanie reklám + Nie je nainÅ¡talovaný žiadny textový editor + Nebol nájdený žiadny textový editor na otvorenie hosts súboru. Môžete nainÅ¡talovaÅ¥ aplikáciu Jota alebo iný textový editor.\n\nChcete nainÅ¡talovaÅ¥ aplikáciu Jota? + Nie je nainÅ¡talovaný žiadny správca súborov + Nebol nájdený žiadny správca súborov na otvorenie súborov. Môžete nainÅ¡talovaÅ¥ aplikáciu OI File Manager alebo iného správcu súborov.\n\nChcete nainÅ¡talovaÅ¥ aplikáciu OI File Manager? + + + Tcpdump + Tcpdump je nástroj na monitorovanie DNS žiadostí a ich ukladanie do záznamu. Môžete ho spustiÅ¥ na pozadí, spustiÅ¥ aplikáciu, ktorá zobrazuje reklamy a potom analyzovaÅ¥ DNS požiadavky pomocou záznamu. Adresy serverov s reklamami si potom môžete pridaÅ¥ do Äiernej listiny. + ZakázaÅ¥ monitorovanie + PovoliÅ¥ monitorovanie + ZobraziÅ¥ výsledky + ZoradiÅ¥ domény + VymazaÅ¥ záznam + PridaÅ¥ položku do Äiernej listiny + PridaÅ¥ položku do bielej listiny + PridaÅ¥ položku do zoznamu presmerovaných + + UpraviÅ¥ hodnotu predvoľby textu + OtvoriÅ¥ menu + ZatvoriÅ¥ menu + + + + Domov + Hosts zdroje + VaÅ¡e zoznamy + OtvoriÅ¥ súbor hosts + ZaznamenaÅ¥ DNS požiadavky + VyhľadaÅ¥ adware + Nastavenia + Pomoc + + + + + DNS žiadosti + VaÅ¡e zoznamy + Nastavenia + + + NainÅ¡talované pred %1$s + Aktuálne %1$s + Dostupná aktualizácia %1$s + Posledná aktualizácia pred %1$s + Neznámy stav aktualizácie + Zakázané + pár minútami + + %dminútu + %d minúty + %d minúť + %d minút + + + %d hodinu + %dhodiny + %dhodín + %dhodín + + + %d deň + %d dni + %d dní + %d dní + + + %d mesiac + %d mesiace + %d mesiacov + %d mesiacov + + + + Host skopírovaný do schránky + + + spúšťa sa + aktívne + zastavuje sa + Äaká sa na sieÅ¥ + znovu sa pripája + chyba pripájania + pozastavená + zastavené + Blokovanie reklamy pomocou VPN %1$s + PozastaviÅ¥ + PokraÄovaÅ¥ + + + Povolenia AdAway + PovoliÅ¥ interakciu s AdAway + OdoslaÅ¥ príkazy do AdAway + Umožňuje odoslaÅ¥ príkazy do AdAway ako zapnutie alebo vypnutie blokovania reklamy v systéme + + diff --git a/app/src/main/res/values-sk/strings_app.xml b/app/src/main/res/values-sk/strings_app.xml new file mode 100644 index 0000000..8467749 --- /dev/null +++ b/app/src/main/res/values-sk/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + BlokovaÄ reklamy s otvoreným kódom + AdAway logo + diff --git a/app/src/main/res/values-sk/strings_errors.xml b/app/src/main/res/values-sk/strings_errors.xml new file mode 100644 index 0000000..4b27c82 --- /dev/null +++ b/app/src/main/res/values-sk/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Bez internetového pripojenia + Nepodarilo sa nadviazaÅ¥ pripojenie na internet. Prosím, skontrolujte pripojenie. + SÅ¥ahovanie zdrojov hosts zlyhalo + Žiaden z vaÅ¡ich povolených zdrojov hosts nie je dostupný. Prosím, skontrolujte pripojenie na internet. + + Nepodarilo sa vytvoriÅ¥ súkromný súbor + Nepodarilo sa vytvoriÅ¥ súkromný súbor na vytvorenie nového zdroja hosts. Prosím, skontrolujte dostupné voľné miesto na zariadení. + Nedostatok miesta + Nepodarilo sa skopírovaÅ¥ súbor hosts na systémový oddiel. Prosím, skontrolujte, Äi je povolený systemless modul Magisku, a potom reÅ¡tartujte. + Nepodarilo sa nainÅ¡talovaÅ¥ nový súbor hosts + Nepodarilo sa skopírovaÅ¥ súbor hosts na oddiel /system. Prosím, skontrolujte, Äi je povolený systemless modul Magisku, a potom reÅ¡tartujte. + Nepodarilo obnoviÅ¥ súbor hosts + Nepodarilo obnoviÅ¥ pôvodné nastavenie súboru hosts. + + Nepodarilo sa povoliÅ¥ blokovanie reklamy pomocou VPN. + Prosím, skontrolujte nastavenia VPN, aby aplikácia mohla spustiÅ¥ VPN pri Å¡tarte. + Nepodarilo sa zakázaÅ¥ blokovanie reklamy pomocou VPN. + Skontroluje nastavenie VPN a vypnite ju manuálne. + diff --git a/app/src/main/res/values-sk/strings_home.xml b/app/src/main/res/values-sk/strings_home.xml new file mode 100644 index 0000000..71f5df0 --- /dev/null +++ b/app/src/main/res/values-sk/strings_home.xml @@ -0,0 +1,50 @@ + + + + + Blokované + Povolené + Presmerované + + + + %d aktualizovaný zdroj + %d aktualizované zdroje + %d aktualizovaných zdrojov + %d aktualizovaných zdrojov + + + %d neaktualizovaný zdroj + %d neaktualizované zdroje + %d neaktualizovaných zdrojov + %d neaktualizovaných zdrojov + + SkontrolovaÅ¥ aktualizácie pre hosts + AktualizovaÅ¥ hosts súbor + + + ZobraziÅ¥ záznam požiadaviek DNS + + + ZobraziÅ¥ pomocníka a tipy + + + OtvoriÅ¥ stránku GitHub + + + PodporiÅ¥ projekt + + + Projekt na Githube + Nastavenia + + + OtvoriÅ¥ boÄný panel + PozastaviÅ¥/obnoviÅ¥ blokovanie reklamy + AktualizovaÅ¥ blokované domény + ZobraziÅ¥ požadované domény + + + Prosím, pre viac informácií si preÄítajte Pomoc. + + \ No newline at end of file diff --git a/app/src/main/res/values-sk/strings_hosts.xml b/app/src/main/res/values-sk/strings_hosts.xml new file mode 100644 index 0000000..376eaa4 --- /dev/null +++ b/app/src/main/res/values-sk/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Hosts zdroje + + Používateľský zoznam + Hosts AdAway official + Hosts StevenBlack Unified + Hosts Pete Lowe blocklist + + nie je dostupné + Hosts %s + + PridaÅ¥ zdroj + UpraviÅ¥ zdroj + URL: (https:// alebo file:// zdroja) + URL zdroja hosts súboru + diff --git a/app/src/main/res/values-sk/strings_lists.xml b/app/src/main/res/values-sk/strings_lists.xml new file mode 100644 index 0000000..ced8022 --- /dev/null +++ b/app/src/main/res/values-sk/strings_lists.xml @@ -0,0 +1,24 @@ + + + VaÅ¡e zoznamy + PridaÅ¥ hostiteľa + + Blokované + Povolené + Presmerované + + FiltrovaÅ¥ hostiteľov + NájsÅ¥ hostiteľa… + Prepnúť zdroje + + PridaÅ¥ host do Äiernej listiny + PridaÅ¥ host do bielej listiny + PridaÅ¥ host do presmerovania + UpraviÅ¥ hostiteľa na Äiernej listine + UpraviÅ¥ hostiteľa na bielej listine + UpraviÅ¥ presmerovania + Názov hostiteľa: + URL zdroja hosts súboru + (Zástupné znaky * a ? sú povolené!) + IP (IPv4 alebo IPv6): + diff --git a/app/src/main/res/values-sk/strings_log.xml b/app/src/main/res/values-sk/strings_log.xml new file mode 100644 index 0000000..ef55945 --- /dev/null +++ b/app/src/main/res/values-sk/strings_log.xml @@ -0,0 +1,11 @@ + + + Prepnúť zaznamenávanie logu + StlaÄením tlaÄidla záznamu spustite zaznamenávanie požiadaviek, prehliadania webu alebo používaných aplikácií, a potom sa vráťte späť alebo potiahnutím obnovte logy. + \n\nBlokované požiadavky nebudú zaznamenané. Najprv zakážte blokovanie, ak ich chcete zahrnúť do logu. + + Zoradenie podľa abecedy + Zoradenie podľa domény najvyššej úrovne + + PresmerovaÅ¥ doménu + diff --git a/app/src/main/res/values-sk/strings_notification.xml b/app/src/main/res/values-sk/strings_notification.xml new file mode 100644 index 0000000..3f75c60 --- /dev/null +++ b/app/src/main/res/values-sk/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Aktualizácie + Nové upozornenia na aktualizáciu + Aktualizácia dostupná + NovÅ¡ie súbory hosts sú dostupné na stiahnutie. + Je dostupná aktualizácia aplikácie + Nová verzia AdAway je dostupná na stiahnutie. + + VPN + Upozornenia na spustenú VPN + \ No newline at end of file diff --git a/app/src/main/res/values-sk/strings_prefs_backup_restore.xml b/app/src/main/res/values-sk/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..6a09c0c --- /dev/null +++ b/app/src/main/res/values-sk/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + ZálohovaÅ¥ a obnoviÅ¥ + ZálohovaÅ¥ + ZálohovaÅ¥ pravidlá blokovania na externé úložisko + ObnoviÅ¥ + ObnoviÅ¥ pravidlá blokovania zo záložného súboru + diff --git a/app/src/main/res/values-sk/strings_prefs_main.xml b/app/src/main/res/values-sk/strings_prefs_main.xml new file mode 100644 index 0000000..3fca651 --- /dev/null +++ b/app/src/main/res/values-sk/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Nastavenia + + VÅ¡eobecné + Tmavý motív + + Svetlý + Tmavý + Podľa systému + + Automatické aktualizácie + + Blokovanie reklamy + BlokovaÄ reklám s rootom + BlokovaÄ reklám pomocou VPN + PovoliÅ¥ podporu IPv6 + ZálohovaÅ¥ / obnoviÅ¥ pravidlá blokovania + + Odstraňovanie chýb + OdoslaÅ¥ hlásenie o zlyhaní + NahlásiÅ¥ na Sentry (sentry.io) + Toto zostavenie nie je podporované + Podrobné zaznamenávanie + Aplikáciu je potrebné reÅ¡tartovaÅ¥ + diff --git a/app/src/main/res/values-sk/strings_prefs_root.xml b/app/src/main/res/values-sk/strings_prefs_root.xml new file mode 100644 index 0000000..42c9c4a --- /dev/null +++ b/app/src/main/res/values-sk/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + BlokovaÄ reklám s rootom + + InÅ¡talácia hosts + OtvoriÅ¥ súbor hosts + Umiestnenie hosts súboru + Pre použitím tejto funkcie si preÄítajte pomocníka + + /system/etc/hosts + /data/hosts + /data/data/hosts + Vlastné umiestnenie + + Vlastné umiestnenie + Po aplikovaní skryÅ¥ dialógové okno reÅ¡tartu + + Presmerovania + ZadaÅ¥, kam presmerovaÅ¥ blokované domény + Presmerovanie IPv4 + Presmerovanie IPv6 + Neplatné presmerovanie + + Miestny webserver + Miestny webserver poÄúva na miestnej IP adrese, aby odpovedal za požiadavky blokovaných domén. + PovoliÅ¥ web server + TestovaÅ¥ web server + InÅ¡talovaÅ¥ certifikát s vlastným podpisom + RuÄná inÅ¡talácia certifikátu + Od Androidu 11 (R) aplikácie nemôžu automaticky inÅ¡talovaÅ¥ dôveryhodné certifikáty (CA).\n\nPrejdite na nastavenie \"ZabezpeÄenie\", \"Å ifrovanie a poverenia\", potom \"InÅ¡talovaÅ¥ certifikát\". Tam vyberte \"Certifikát CA\" a vyberte nový exportovaný súbor s certifikátom. + OtvoriÅ¥ nastavenie ZabezpeÄenie + Kontrolovanie… + Nie je spustený + Spustený, ale certifikát nie je nainÅ¡talovaný + Spustený a certifikát je nainÅ¡talovaný + VyplniÅ¥ prázdne reklamné miesto ikonou apky + diff --git a/app/src/main/res/values-sk/strings_prefs_update.xml b/app/src/main/res/values-sk/strings_prefs_update.xml new file mode 100644 index 0000000..c511326 --- /dev/null +++ b/app/src/main/res/values-sk/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Aktualizácie + Upozornenia sú vypnuté + Upozornenia aplikácie sa nezobrazia. Klepnutím ich povolíte. + + Aktualizácie aplikácie + SkontrolovaÅ¥ aktualizácie pri spustení + Pravidelne kontrolovaÅ¥ aktualizácie + Aj betaverzie + + Aktualizácie hosts + SkontrolovaÅ¥ aktualizácie pri spustení + Pravidelne kontrolovaÅ¥ aktualizácie + SynchronizovaÅ¥ pri aktualizácii + SynchronizovaÅ¥ len na neplatenej sieti + diff --git a/app/src/main/res/values-sk/strings_prefs_vpn.xml b/app/src/main/res/values-sk/strings_prefs_vpn.xml new file mode 100644 index 0000000..d9e051d --- /dev/null +++ b/app/src/main/res/values-sk/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + BlokovaÄ reklám pomocou VPN + + PovoliÅ¥ pri Å¡tarte + Sledovanie pripojenia + Pravidelne kontrolovaÅ¥ stav siete, pri odpojení reÅ¡tartovaÅ¥ VPN. + + VylúÄené aplikácie + Nastavte, ktoré aplikácie by nemali používaÅ¥ VPN a nebudú sa blokovaÅ¥ žiadne ich pripojenia. + VylúÄiÅ¥ systémové aplikácie + + Žiadne + VÅ¡etky okrem prehliadaÄov + VÅ¡etky + + VylúÄiÅ¥ užívateľské aplikácie + + + VylúÄené aplikácie + VybraÅ¥ vÅ¡etky + NevybraÅ¥ niÄ + Ikona aplikácie + diff --git a/app/src/main/res/values-sk/strings_source_edit.xml b/app/src/main/res/values-sk/strings_source_edit.xml new file mode 100644 index 0000000..c06c594 --- /dev/null +++ b/app/src/main/res/values-sk/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + UpraviÅ¥ zdroj + PridaÅ¥ zdroj + + Menovka + Menovka je povinná + Typ + URL + Súbor + Adresa + https:// + Adresa je povinná + StlaÄením tlaÄidla Súbor vyberte zdrojový súbor + Neplatná cesta + Formát zoznamu + BlokovaÅ¥ + PovoliÅ¥ + PoužiÅ¥ presmerovaných hostiteľov + Povolenie presmerovaných hostiteľov môže spôsobiÅ¥ bezpeÄnostné problémy. Toto nastavenie používajte len na dôveryhodnom zdroji, pretože by mohlo presmerovaÅ¥ citlivú komunikáciu na ľubovoľný server. + diff --git a/app/src/main/res/values-sk/strings_support.xml b/app/src/main/res/values-sk/strings_support.xml new file mode 100644 index 0000000..83b2849 --- /dev/null +++ b/app/src/main/res/values-sk/strings_support.xml @@ -0,0 +1,5 @@ + + + Podpora + Staňte sa sponzorom + \ No newline at end of file diff --git a/app/src/main/res/values-sk/strings_update.xml b/app/src/main/res/values-sk/strings_update.xml new file mode 100644 index 0000000..c701500 --- /dev/null +++ b/app/src/main/res/values-sk/strings_update.xml @@ -0,0 +1,22 @@ + + + Aktualizácia AdAway + + Aktualizácia je dostupná! + + + Aktualizované + Aktualizácia dostupná + Aktualizovanie AdAway + AktualizovaÅ¥ teraz + %1$s / %2$s + Hotovo + Posledné zmeny + Zoznam zmien + Podpora vývoja + PodporiÅ¥ + Sponzor + + + SÅ¥ahovanie najnovÅ¡ej verzie AdAway + diff --git a/app/src/main/res/values-sk/strings_welcome.xml b/app/src/main/res/values-sk/strings_welcome.xml new file mode 100644 index 0000000..7036871 --- /dev/null +++ b/app/src/main/res/values-sk/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Vitajte + Sprievodca – 1. krok + Sprievodca – 2. krok + Sprievodca – posledný krok + + + Vitajte v AdAway! + AdAway poskytuje 2 metódy blokovania. Vyberte si jednu: + + Logo rootu + BlokovaÄ reklám\npomocou rootu + RýchlejÅ¡ie + Å etrné k batérii + Vyžaduje root + + Logo VPN + BlokovaÄ reklám\npomocou VPN + PomalÅ¡ie + Beží na pozadí + Kombatibilita + + Je potrebné rootnuté zariadenie + BuÄ sa nepodarilo nájsÅ¥ binárny súbor SU alebo ste nepovolili oprávnenie roota v AdAway.\n\nK tomuto dochádza, keÄ vaÅ¡e zariadenie nie je rootnuté. Informácie o tom, ako rootnuÅ¥ vaÅ¡e zariadenia nájdete na wiki.lineageos.org alebo na inej stránke o zariadeniach s Androidom. + + Výhody + Nevýhody + + + Synchronizácia skonÄila + Nastala chyba poÄas synchronizácie + + Synchronizácia + Synchronizované! + AdAway sÅ¥ahuje reklamné siete na blokovanie z online zdrojov. Neskôr ich môžete upraviÅ¥. + ZopakovaÅ¥ synchronizáciu + Synchronizácia zlyhala: %1$s SkúsiÅ¥ znova? + Môže posielaÅ¥ upozornenia na zobrazenie stavu a kontroly blokovania reklám a upozorniÅ¥ na dostupnú aktualizáciu aplikácie (niekoľko za rok). Ak ich chcete maÅ¥ stále aktuálne, povoľte ich. + + + Podpora + Podporte ma! + Je bezplatná aplikácia s otvoreným kódom, ktorú robím vo svojom voľnom Äase. Ak sa Vám teda páÄi, neváhajte vyjadriÅ¥ svoju podporu: + Podpora na PayPal + Máte radi chyby? Ani ja nie. + PovoliÅ¥ telemetriu a posielaÅ¥ hlásenia o chybe + + + Späť + ÄŽalej + DokonÄiÅ¥ + diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml new file mode 100644 index 0000000..53c9871 --- /dev/null +++ b/app/src/main/res/values-sl/strings.xml @@ -0,0 +1,270 @@ + + + + Izhod + Zapri + Da + Ne + Dodaj + PrekliÄi + Shrani + PomoÄ + + + DobrodoÅ¡li! + AdAway je brezplaÄen in odprtokodni program za zaviranje oglaÅ¡evanja. Pridobi naslove oglaÅ¡evalskih omrežij, da jih onemogoÄi v vaÅ¡i napravi.\nŽelite izvedeti veÄ? Spodaj preverite pomoÄ! + Prikaži veÄ pomoÄi + Stanje posodobitev + Vse hosts datoteke danih virov so preneÅ¡ene, združene z vaÅ¡imi osebnimi seznami in nameÅ¡Äene kot ena hosts datoteka na vaÅ¡em sistemu. + OmogoÄi zaviranje oglasov + OnemogoÄi zaviranje oglasov + Spletni strežnik + Izvajanje + Ustavljeno + Zaženite ali zaustavite spletni strežnik na lokalnem gostitelju, da odgovorite na zahteve onemogoÄenih imen gostiteljev. + OmogoÄi spletni strežnik + OnemogoÄi spletni strežnik + VPN + Izvajanje + Ustavljeno + Zaženite ali zaustavite VPN za filtriranje zahtev. + OmogoÄi VPN + OnemogoÄi VPN + + + Uredi vnos + Uporabi + Uredi + IzbriÅ¡i + + + Uvažanje… + Varnostna kopija je bila uspeÅ¡no uvožena iz vaÅ¡e zunanje shrambe. + Uvoz varnostne kopije ni uspel. Je njegova oblika pravilna? Preverite \'logcat\' za veÄ podrobnosti. + Izvažanje… + Varnostna kopija je bila uspeÅ¡no izvožena v datoteko \'%s\' na vaÅ¡o zunanjo shrambo. + Datoteke varnostne kopije \'%s\' ni bilo mogoÄe izvoziti. + + + Datoteka gostiteljev (hosts) + Datoteka gostiteljev je sistemska datoteka, ki preslika imena gostiteljev v naslove IP. Je datoteka z navadnim besedilom, katere Nastavitve upravlja AdAway. Tukaj je nekaj njegovih prvih vrstic: + Nalaganje vsebine datoteke gostiteljev… + Odpri datoteko gostiteljev + + + Preveri obstoj posodobitev + Preverjanje vira %s za posodobitev + Pridobivanje virov + PrenaÅ¡anje vira %s + Branje vira %s + RazÄlenjevanje vira %s + Sinhronizacija zbirke podatkov pravil + Vrnitev na privzeto datoteko gostiteljev + Privzeta datoteka gostiteljev je obnovljena + Ustvarjanje privzete hosts datoteke + Na voljo je posodobitev vira + Na voljo so posodobljene hosts datoteke + Ni najdene posodobitve vira + Ni omrežne povezave + Omrežna povezava ni na voljo + Nedosegljivi viri + Noben hosts vir ni dosegljiv! + Korenski dostop je zavrnjen + Dovolite korenski dostop iz vaÅ¡e korenske aplikacije + Nekaj ​​je Å¡lo narobe + Preverite \'logcat\' za veÄ podrobnosti + OmogoÄeno + Uporabljene so najnovejÅ¡e hosts datoteke + OnemogoÄeno + NameÅ¡Äena je privzeta datoteka gostiteljev + Uporabi najnovejÅ¡e vire + Ustvarjanje nove datoteke gostiteljev + Kopiranje nove datoteke gostiteljev + Preverjanje kopije datoteke gostiteljev + Datoteka \'Hosts\' je bila uspeÅ¡no posodobljena + Nastavitve VPN so bile uspeÅ¡no posodobljene + VaÅ¡e nastavitve so se spremenile. Uporabiti jih morate. + Uporabi + Uporaba novih nastavitev… + Novih nastavitev ni bilo mogoÄe uporabiti. + + + Manjka simbolna povezava do cilja datoteke gostiteljev + Symlink vaÅ¡e tarÄe /system/etc/hosts ne obstaja ali ni pravilen! AdAway ne bo deloval, Äe ne bo kazal na pravo datoteko.\n\nAli želite poizkusiti ustvariti symlink? + Symlink ne obstaja + Na particiji ni dovolj prostora!\nPoizkusite spremeniti pot hosts datoteke na /data/data/hosts v nastavitvah. + Ni dovolj prostora + PreneÅ¡ene datoteke ni mogoÄe brati. + Privatna datoteka spodletela + Ponovno montiranje particije z read/write dovoljenjem je spodletelo! + Ponovno montiranje spodletelo + Datoteke gostiteljev ni bilo mogoÄe kopirati + Kopiranje hosts datoteke spodletelo! + Kopiranje spodletelo + Uporabljeni viri gostiteljev + Uporaba uspeÅ¡na + Uporaba je bila uspeÅ¡na.\nMorda bo treba znova zagnati Android, za uveljavitev sprememb.\n\nAli želite znova zagnati?\n(ÄŒe želite prepreÄiti izgubo podatkov, se prepriÄajte, da nobena aplikacija trenutno ne uporablja kartice SD!) + Simbolna povezava je bila ustvarjena uspeÅ¡no.\nMorda bo treba znova zagnati Android, za uveljavitev sprememb.\n\nAli želite znova zagnati?\n(Za prepreÄitev izgube podatkov se prepriÄajte, da nobena aplikacija trenutno ne uporablja kartice SD!) + Symlink je bil uspeÅ¡no ustvarjen + Android ni mogel ustvariti simbolne povezave.\nTo ne uspe predvsem zaradi \'funkcije\', imenovane S-ON na telefonih HTC!\n\nReÅ¡itev je, da telefon zaženete v obnovitveni naÄin in tam ustvarite simbolno povezavo z \'ln -s / data/data/hosts /system/etc/hosts\'.\n\nÄŒe to ne deluje, poiÅ¡Äite na spletu S-OFF in svoj telefon. + Ustvarjanje symlink-a je spodletelo + Prosimo, preberite pomoÄ za veÄ informacij. + V vaÅ¡em Androidu je nastavljen namestniÅ¡ki strežnik APN!\nAdAway ne bo zanesljivo deloval v mobilnih omrežjih, kot je 3G. Ta namestniÅ¡ki strežnik lahko deaktivirate tako, da odprete izbrano APN (v aplikaciji Nastavitve: Omrežje in internet -> Mobilno omrežje -> Napredno -> Imena dostopnih toÄk) in odstranite vrednost v polju namestniÅ¡kega strežnika. + APN proxy nastavljen! + Omrežna povezava ni vzpostavljena. + Ni povezave + PrenaÅ¡anje… + Uporabljanje… + Uporabljanje seznama blokiranih in dovoljenih virov + Združevanje hosts datotek + Izgradnja hosts datotek + Uporabljanje hosts datotek + Nove datoteke gostiteljev ni bilo mogoÄe uporabiti. + Uporaba hosts datotek na vaÅ¡em sistemu je spodletela!\nPoizkusite spremeniti pot hosts datoteke na /data/data/hosts v nastavitvah. + Uporaba neuspeÅ¡na + Preverite svojo aplikacijo za upravljanje korena, da zagotovite, da je odobren korenski dostop. + Povrnili ste se na privzeto datoteko gostiteljev.\nMorda bo treba znova zagnati Android za uveljavitev sprememb.\n\nAli želite znova zagnati?\n(Za prepreÄitev izgube podatkov se prepriÄajte, da nobena aplikacija trenutno ne uporablja kartice SD !) + Povrnitev uspeÅ¡na + Datoteke gostiteljev ni mogoÄe povrniti + Povrnitev spodletela zaradi neznanega razloga. + Povrnitev neuspeÅ¡na! + Noben od vaÅ¡ih uporabljenih hosts virov ni dosegljiv! Ali ste pravilno povezani na omrežje? + Prenos spodletel + Nove datoteke zasebnih gostiteljev ni bilo mogoÄe napisati + Privatne datoteke ni bilo mogoÄe ustvariti. + Privatne datoteke ni bilo mogoÄe ustvariti. + OmogoÄili ste brezsistemski naÄin.\nMorda bo treba znova zagnati Android, za uveljavitev sprememb.\n\nAli želite znova zagnati?\n(Za prepreÄitev izgube podatkov se prepriÄajte, da nobena aplikacija trenutno ne uporablja kartice SD!) + UspeÅ¡no omogoÄeno + OnemogoÄili ste brezsistemski naÄin.\nMorda bo treba znova zagnati Android za uveljavitev sprememb.\n\nAli želite znova zagnati?\n(Za prepreÄitev izgube podatkov, se prepriÄajte, da nobena aplikacija trenutno ne uporablja kartice SD!) + UspeÅ¡no onemogoÄeno + Zaviranja oglasov VPN ni bilo mogoÄe omogoÄiti. + Zaviiranja oglasov VPN ni bilo mogoÄe onemogoÄiti. + OmogoÄanje gostiteljskega modula Magisk + OmogoÄite funkcijo brezsistemskih gostiteljev v upravitelju Magisk. V nastavitvah omogoÄite možnost Brezsistemski gostitelji in znova zaženite napravo. + OnemogoÄanje gostiteljskega modula Magisk + OnemogoÄite funkcijo brezsistemskih gostiteljev v upravitelju Magisk. S seznama modulov odstranite Brezsistemske gostitelje in znova zaženite napravo. + + + Vnesi URL do hosts datoteke: + Neveljavno domensko ime! + Nepravilno oblikovano domensko ime + Neveljaven IP! + Nepravilno oblikovan IP + Nikoli znova ne zaženi in naslednjiÄ ne pokaži tega vpraÅ¡anja! + Nalaganje… + + + Osveži + Dodaj + PomoÄ + Uvozi varnostno kopijo + Izvozi varnostno kopijo + + + S-ON/S-OFF + Pogosto postavljena vpraÅ¡anja + Težave + + + OglaÅ¡evalski programi + Tukaj lahko najdete nameÅ¡Äeno oglaÅ¡evalske programe, slabe aplikacije, ki jih AdAway ne more zavirati. Te aplikacije uporabljajo na primer obvestila Airpush, ki se prikažejo, tudi ko se aplikacija ne izvaja, ali celo spremenijo melodijo zvonjenja. Edini razpoložljivi protiukrep je odstranitev teh aplikacij s klikom na vnose seznama. + Pregled… + OglaÅ¡evalski programi niso bili najdeni! + + + Ad blocker + NameÅ¡Äen ni noben urejevalec teksta + NameÅ¡Äen ni noben urejevalec teksta. Namestite lahko aplikacijo Jota ali katerikoli drug urejevalnik teksta.\n\nAli želite namestiti Jota? + Noben raziskovalec ni nameÅ¡Äen + Noben raziskovalec ni nameÅ¡Äen. Namestite lahko aplikacijo OI File Manager ali katerikoli drug raziskovalec.\n\nAli želite namestiti OI File Manager? + + + OdlagaliÅ¡Äe TCP + Tcpdump je orodje za nadziranje DNS zahtev in njihovo shranjevanje v log datoteko. Zaženete jo lahko v ozadju, zaženete aplikacijo, ki prikazuje oglase, ter analizirate DNS zahteve preko log datoteke. Morebitne oglaÅ¡evalne strežnike lahko potem dodate na vaÅ¡o blacklist-o. + OnemogoÄi spremljanje + OmogoÄi spremljanje + Prikaži rezultate + Razvrsti domene + PoÄisti dnevnik + Dodaj vnos na seznam nedovoljenih + Dodaj vnos na seznam dovoljenih + Dodaj vnos na seznam preusmeritev + + Uredi vrednost nastavitev besedila + Odpri meni + Zapri meni + + + + Home + Hosts viri + Your lists + Odpri hosts datoteko + Log DNS requests + Scan for adware + Nastavitve + PomoÄ + + + + + Zahteve DNS + VaÅ¡i seznami + Nastavitve + + + NameÅ¡Äen pred %1$s + Posodobljen za %1$s + Potrebna posodobitev za %1$s + Zadnja posodobitev pred %1$s + Neznano stanje posodobitve + OnemogoÄeno + nekaj minut + + %d minuto + %d minutama + %d minutami + %d minutami + + + %d uro + %d urama + %d urami + %d uro + + + %d dan + %d dneva + %d dnevi + %d dnevi + + + %d mesec + %d meseca + %d meseci + %d mesec + + + + Gostitelj kopiran v odložiÅ¡Äe + + + zaÄet + aktiven + zaustavitev + poÄakajte na omrežje + ponovno povezovanje + napaka pri ponovni povezavi + zaÄasno ustavljen + ustavljen + Zaviralec oglasov VPN %1$s + Premor + Nadaljuj + + + AdAway dovoljenja + Dovoli interakcijo z AdAway + PoÅ¡lji ukaze v AdAway + Dovoli poÅ¡iljanje ukazov v AdAway, kot je omogoÄanje ali onemogoÄanje sistemskega zaviranja oglasov + + diff --git a/app/src/main/res/values-sl/strings_app.xml b/app/src/main/res/values-sl/strings_app.xml new file mode 100644 index 0000000..294a7a4 --- /dev/null +++ b/app/src/main/res/values-sl/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Odprtokodni zaviralec oglasov + Logotip AdAway + diff --git a/app/src/main/res/values-sl/strings_errors.xml b/app/src/main/res/values-sl/strings_errors.xml new file mode 100644 index 0000000..71d48ef --- /dev/null +++ b/app/src/main/res/values-sl/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Ni internetne povezave + Ni mogoÄe vzpostaviti povezave z internetom. Preverite povezljivost vaÅ¡e naprave. + Prenos vira gostiteljev ni uspel + Noben od vaÅ¡ih omogoÄenih virov gostiteljev ni dosegljiv. Preverite, ali ste pravilno povezani z internetom. + + Zasebne datoteke ni bilo mogoÄe ustvariti + Ni mogoÄe ustvariti zasebne datoteke za izdelavo novega vira gostiteljev. Preverite prosti prostor na vaÅ¡i napravi. + Ni dovolj prostora + Ni mogoÄe kopirati datoteke gostiteljev na sistemsko particijo. Preverite, ali je nesistemski modul Magisk omogoÄen, nato znova zaženite. + Namestitev nove datoteke gostiteljev ni uspela + Datoteke gostiteljev ni mogoÄe kopirati na /sistemsko particijo. Preverite, ali je nesistemski modul Magisk omogoÄen, nato znova zaženite. + Datoteke gostiteljev ni bilo mogoÄe povrniti + Ni mogoÄe obnoviti privzetih nastavitev datoteke gostiteljev. + + Zaviranja oglasov VPN ni bilo mogoÄe omogoÄiti. + Preverite svoje nastavitve VPN, da dovolite zagon aplikacije VPN. + Zaviiranja oglasov VPN ni bilo mogoÄe onemogoÄiti. + Preverite nastavitve VPN, da ga roÄno onemogoÄite. + diff --git a/app/src/main/res/values-sl/strings_home.xml b/app/src/main/res/values-sl/strings_home.xml new file mode 100644 index 0000000..62a96ca --- /dev/null +++ b/app/src/main/res/values-sl/strings_home.xml @@ -0,0 +1,50 @@ + + + + + OnemogoÄeno + Dovoljeno + Preusmerjeno + + + + %d up-to-date source + %d up-to-date sources + %d up-to-date sources + %d posodobljenih virov + + + %d outdated source + %d outdated sources + %d outdated sources + %d zastarelih virov + + Preveri posodobitve gostiteljev + Posodobi gostitelje + + + Prikaži dnevnik zahtev DNS + + + Prikaži pomoÄ\in namige + + + Odpri stran GitHub + + + Podpri projekt + + + Projekt GitHub + Nastavitve + + + Odpri predal za krmarjenje + ZaÄasno ustavi/nadaljuj zaviranje oglasov + Posodobi onemogoÄene domene + Prikaži zahtevane domene + + + Prosimo, preberite pomoÄ za veÄ informacij. + + \ No newline at end of file diff --git a/app/src/main/res/values-sl/strings_hosts.xml b/app/src/main/res/values-sl/strings_hosts.xml new file mode 100644 index 0000000..debca6e --- /dev/null +++ b/app/src/main/res/values-sl/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Hosts viri + + UporabniÅ¡ki seznam + Uradni gostitelji AdAway + Poenoteni gostitelji StevenBlack + Gostitelji seznama zaviranih Pete Lowe + + ni na voljo + %s gostiteljev + + Dodaj vir + Uredi vir + URL: (a https:// ali datoteka:// resource) + Izvorni URL gostiteljev + diff --git a/app/src/main/res/values-sl/strings_lists.xml b/app/src/main/res/values-sl/strings_lists.xml new file mode 100644 index 0000000..081d44c --- /dev/null +++ b/app/src/main/res/values-sl/strings_lists.xml @@ -0,0 +1,24 @@ + + + VaÅ¡i seznami + Dodaj gostitelja + + OnemogoÄeno + Dovoljeno + Preusmerjeno + + Filtriraj gostitelje + PoiÅ¡Äi ime gostitelja… + Preklopi vire + + Dodaj gostitelja na seznam nedovoljenih + Dodaj gostitelja na seznam dovoljenih + Dodaj preusmeritev gostitelja + Uredi gostitelja na seznamu nedovoljenih + Uredi gostitelja na seznamu dovoljenih + Uredi preusmeritev + Ime gostitelja: + URL vira gostiteljev + (Dovoljena sta nadomestna znaka * in ?) + IP (IPv4 ali IPv6): + diff --git a/app/src/main/res/values-sl/strings_log.xml b/app/src/main/res/values-sl/strings_log.xml new file mode 100644 index 0000000..96957ff --- /dev/null +++ b/app/src/main/res/values-sl/strings_log.xml @@ -0,0 +1,11 @@ + + + Preklopi snemanje dnevnika + Pritisnite zapis, da zaÄnete beležiti zahteve, brskate po spletu ali uporabljati aplikacije, nato se vrnite nazaj ali povlecite, da osvežite dnevnike. + \n\nBlokirane zahteve ne bodo zabeležene. Najprej onemogoÄite blokiranje oglasov, Äe jih želite tudi prijaviti. + + Abecedno razvrÅ¡Äanje + Razvrsti domene najviÅ¡je ravni + + Preusmeri domeno + diff --git a/app/src/main/res/values-sl/strings_notification.xml b/app/src/main/res/values-sl/strings_notification.xml new file mode 100644 index 0000000..e7d904c --- /dev/null +++ b/app/src/main/res/values-sl/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Posodobitve + Obvestila o novih posodobitvah + Na voljo je posodobitev vira + NovejÅ¡e datoteke gostiteljev so na voljo za prenos. + Na voljo je posodobitev aplikacije + Nova razliÄica AdAway je na voljo za prenos. + + VPN + Obvestila o delovanju VPN + diff --git a/app/src/main/res/values-sl/strings_prefs_backup_restore.xml b/app/src/main/res/values-sl/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..445d9aa --- /dev/null +++ b/app/src/main/res/values-sl/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Varnostno kopiraj in obnovi + Varnostno kopiraj + Varnostno kopirajte svoja pravila zaviranja na zunanjo shrambo + Obnovi + Obnovite svoja pravila zaviranja iz varnostne kopije + diff --git a/app/src/main/res/values-sl/strings_prefs_main.xml b/app/src/main/res/values-sl/strings_prefs_main.xml new file mode 100644 index 0000000..1bbac50 --- /dev/null +++ b/app/src/main/res/values-sl/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Nastavitve + + SploÅ¡no + Temna tema + + Svetla + Temna + Sistemska privzeta + + Samodejne posodobitve + + Zaviranje oglasov + Zaviralec oglasov na osnovi korenskega sistema + Zaviralec oglasov na osnovi VPN + OmogoÄi podporo za IPv6 + Varnostno kopiraj/obnovi pravila zaviranja + + Odpravi napake programa + PoÅ¡lji poroÄila o zruÅ¡itvah + Prijavi na Sentry (sentry.io) + Ni podprto v tej zgradbi + Podrobno beleženje + Za uporabo je potreben ponovni zagon aplikacije + diff --git a/app/src/main/res/values-sl/strings_prefs_root.xml b/app/src/main/res/values-sl/strings_prefs_root.xml new file mode 100644 index 0000000..eb65daa --- /dev/null +++ b/app/src/main/res/values-sl/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Zaviralec oglasov na osnovi korenskega sistema + + Namesti gostitelje + Odpri hosts datoteko + Uporabljena hosts datoteka + Pred uporabo te funkcije preberite pomoÄ + + /system/etc/hosts + /data/hosts + /data/data/hosts + Cilj po meri + + Ciljno mesto po meri + Po uporabi skrij pogovorno okno za ponovni zagon + + Preusmeritev + DoloÄite, kam želite preusmeriti nemogoÄene gostitelje + Nastavite preusmeritev IPv4 + Nastavite preusmeritev IPv6 + Neveljavna preusmeritev + + Lokalni spletni strežnik + Lokalni spletni strežnik posluÅ¡a lokalne naslove IP, da odgovori na zahteve po onemogoÄenih imenih gostiteljev. Morda pomaga pri zamrznitvi aplikacije pri onemogoÄeni povezavi. + OmogoÄi spletni strežnik + Preizkusni spletni strežnik + Namesti samopodpisano potrdilo + RoÄna namestitev potrdila + Od Androida 11 (R) naprej aplikacija ne more veÄ samodejno namestiti overitelja potrdil (CA).\n\nPojdite na nastavitve \'Varnost\', \'Å ifriranje in poverilnice\' in nato \'Namesti potrdilo\'. Od tam izberite \'Potrdilo CA\' in izberite novo izvoženo datoteko potrdila. + Odpri nastavitve \'Varnost\' + Preverjanje… + Ne izvaja se + Izvaja se, vendar potrdilo ni nameÅ¡Äeno + Izvaja se in potrdilo je nameÅ¡Äeno + Zamenjajte prazen oglasni prostor z ikono aplikacije + diff --git a/app/src/main/res/values-sl/strings_prefs_update.xml b/app/src/main/res/values-sl/strings_prefs_update.xml new file mode 100644 index 0000000..a7d6cfa --- /dev/null +++ b/app/src/main/res/values-sl/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Posodobitve + Obvestila so onemogoÄena + Obvestila aplikacije ne bodo prikazana. Tapnite, da jih omogoÄite. + + Posodobitve aplikacije + Preveri posodobitev ob zagonu + ObÄasno preveri obstoj posodobitev + VkljuÄi izdaje beta + + Posodobitve gostiteljev + Preveri obstoj posodobitev ob zagonu + ObÄasno preveri obstoj posodobitev + Sinhroniziraj ob posodobitvi + Sinhroniziraj samo v neomejenem omrežju + diff --git a/app/src/main/res/values-sl/strings_prefs_vpn.xml b/app/src/main/res/values-sl/strings_prefs_vpn.xml new file mode 100644 index 0000000..11d6a98 --- /dev/null +++ b/app/src/main/res/values-sl/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Zaviralec oglasov na osnovi VPN + + OmogoÄi ob zagonu + Spremljaj povezavo + ObÄasno preveri stanje omrežja za ponovni zagon VPN ob prekinitvi povezave. + + IzkljuÄene aplikacije + Nastavite, katere aplikacije ne smejo uporabljati VPN, da nobena povezava ne bo onemogoÄena. + IzkljuÄi sistemske aplikacije + + Brez + Vse razen brskalnikov + Vse + + IzkljuÄi uporabniÅ¡ke aplikacije + + + IzkljuÄene aplikacije + Izberi vse + PoÄisti izbor vseh + Ikona aplikacije + diff --git a/app/src/main/res/values-sl/strings_source_edit.xml b/app/src/main/res/values-sl/strings_source_edit.xml new file mode 100644 index 0000000..fa37324 --- /dev/null +++ b/app/src/main/res/values-sl/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Uredi vir + Dodaj vir + + Oznaka + Zahtevana je oznaka + Vrsta + URL + Datoteka + Lokacija + https:// + Zahtevana je lokacija + Pritisnite Datoteka, da izberete izvorno datoteko + Neveljavna lokacija + Oblika seznama + OnemogoÄi + Dovoli + Uporabi preusmerjene gostitelje + Dovolitev preusmerjenih gostiteljev lahko povzroÄi varnostne težave. Te nastavitve uporabljajte samo na zaupanja vrednem viru, saj lahko preusmeri del obÄutljivega prometa na kateri koli strežnik, ki ga želi. + diff --git a/app/src/main/res/values-sl/strings_support.xml b/app/src/main/res/values-sl/strings_support.xml new file mode 100644 index 0000000..c65ff13 --- /dev/null +++ b/app/src/main/res/values-sl/strings_support.xml @@ -0,0 +1,5 @@ + + + Podpora + Postani pokrovitelj + diff --git a/app/src/main/res/values-sl/strings_update.xml b/app/src/main/res/values-sl/strings_update.xml new file mode 100644 index 0000000..97cb016 --- /dev/null +++ b/app/src/main/res/values-sl/strings_update.xml @@ -0,0 +1,21 @@ + + + Posodobitev AdAway + + Na voljo je posodobitev! + + + Ste na tekoÄem + Na voljo je nova posodobitev + Posodabljanje AdAway + Posodobi zdaj + %1$s/%2$s + Zadnje spremembe + Dnevnik sprememb + Podprite razvoj + Daruj + Pokrovitelj + + + Prenos najnovejÅ¡e razliÄice AdAway… + diff --git a/app/src/main/res/values-sl/strings_welcome.xml b/app/src/main/res/values-sl/strings_welcome.xml new file mode 100644 index 0000000..c89178f --- /dev/null +++ b/app/src/main/res/values-sl/strings_welcome.xml @@ -0,0 +1,53 @@ + + + DobrodoÅ¡li + Prvi korak Äarovnika + Drugi korak Äarovnika + Zadnji korak Äarovnika + + + DobrodoÅ¡li v AdAway! + AdAway ponuja dva naÄina zaviranja oglasov. Izberite tistega, ki vam je vÅ¡eÄ: + + Logotip korena + Zaviranje oglasov\nna osnovi korena + Hitreje + Prijazen z baterijo + Zahtevan je korenski dostop + + Logotip VPN + Zaviranje oglason\nna podlagi korena + PoÄasneje + Zaženi v ozadju + Združljivost + + Potreben je root dostop + DvojiÅ¡ke datoteke \'su\' ni bilo mogoÄe najti ali pa niste dovolili korenskega dovoljenja za AdAway.\n\nTo se lahko zgodi, Äe vaÅ¡a naprava nima dostop do korena. Informacije o tem, kako povezati svojo napravo s korenom, najdete na wiki.lineageos.org ali drugih spletnih straneh za Android. + + Pro + Con + + + Sinhronizacija je konÄana + Napaka med sinhronizacijo + + Sinhronizacija + Sinhronizirano! + AdAway iz spletnih virov prenese oglasna omrežja, ki jih blokira. Kasneje jih lahko prilagodite v nastavitvah. + Ponovi sinhronizacijo + Sinhronizacija %1$s ni uspela: Želite poskusiti znova? + PoÅ¡ilja lahko obvestila prikaza stanja in nadzora zaviranja oglasov ter za obveÅ¡Äanje o razpoložljivih posodobitvah aplikacije (nekaj na leto). OmogoÄite jih, Äe želite biti na tekoÄem. + + + Podpora + Podprite me! + AdAway je brezplaÄna in odprtokodna aplikacija, ki jo razvijam v prostem Äasu. ÄŒe vam je vÅ¡eÄ, vas prosim, da izkažete svojo podporo: + Darujte na PayPal + Ali imate radi programske napake? Jaz tudi ne. + OmogoÄite telemetrijo, da mi poÅ¡iljate poroÄila o zruÅ¡itvah + + + Nazaj + Naprej + KonÄaj + diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml new file mode 100644 index 0000000..9e45587 --- /dev/null +++ b/app/src/main/res/values-sq/strings.xml @@ -0,0 +1,14 @@ + + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-sq/strings_app.xml b/app/src/main/res/values-sq/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-sq/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-sq/strings_errors.xml b/app/src/main/res/values-sq/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-sq/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-sq/strings_home.xml b/app/src/main/res/values-sq/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-sq/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-sq/strings_hosts.xml b/app/src/main/res/values-sq/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-sq/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-sq/strings_lists.xml b/app/src/main/res/values-sq/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-sq/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-sq/strings_log.xml b/app/src/main/res/values-sq/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-sq/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-sq/strings_notification.xml b/app/src/main/res/values-sq/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-sq/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-sq/strings_prefs_backup_restore.xml b/app/src/main/res/values-sq/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-sq/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-sq/strings_prefs_main.xml b/app/src/main/res/values-sq/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-sq/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-sq/strings_prefs_root.xml b/app/src/main/res/values-sq/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-sq/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-sq/strings_prefs_update.xml b/app/src/main/res/values-sq/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-sq/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-sq/strings_prefs_vpn.xml b/app/src/main/res/values-sq/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-sq/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-sq/strings_support.xml b/app/src/main/res/values-sq/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-sq/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-sq/strings_update.xml b/app/src/main/res/values-sq/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-sq/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-sq/strings_welcome.xml b/app/src/main/res/values-sq/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-sq/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml new file mode 100644 index 0000000..980eb31 --- /dev/null +++ b/app/src/main/res/values-sr/strings.xml @@ -0,0 +1,110 @@ + + + + Izlaz + Zatvori + Da + Ne + Dodaj + Otkaži + SaÄuvaj + Pomoć + + Sve host-ove datoteke sa odreÄ‘enih izvora su preuzete, spojene sa vaÅ¡om listom i instalirane kao datoteke jednog host-a na vaÅ¡em sistemu. + Omogući Ad Blocking + Onemogući Ad Blocking + Omogući webserver + Onemogući webserver + + Uredi ulazak + Primeni + Uredi + Ukloni + + + Uvoz… + Izvoz… + Kreiranje standardnog hosts fajla + Ažuriranje dostupno + Noviji host-ovi fajlovi dostupni + Nema internet konekcije + Nema dostupne internet konekcije + Nedostupni izvori + Ne mogu da pristupim ni jednom izvoru hosts fajlova! + Omogućeno + Noviji host-ovi fajlovi omogućeni + Onemogućeno + Primeni + SimboliÄki link od tvojeg fajla do /system/etc/hosts ne postoji ili nije dobar. AdAway neće raditi ako ne pokazuje na dobar fajl.\n\nDa li želiÅ¡ da pokuÅ¡aÅ¡ da kreiraÅ¡ simboliÄki link? + Nedostaje symlink. + Na particiji nema dovoljno mesta!\nProbaj da promeniÅ¡ lokaciju hosts fajla u podeÅ¡avanjima na /data/data/hosts. + Nema dovoljno memorije + Preuzeti fajl nije moguće proÄitati. + NeuspeÅ¡no kreiranje privatnog fajla + Remount particije za Äitanje/pisanje nije uspelo! + Remount neuspesan + NeuspeÅ¡no kopiranje host-ovih fajlova! + Kopiranje neuspeÅ¡no + Primena uspeÅ¡na + Kreiranje symlink-a uspesno + Kreiranje symlink-a bez uspesno + Molimo da proÄitate Pomoć za viÅ¡e informacija. + APN proxy postavljen! + Konekcija sa internetom ne radi. + Nema konekcije + Preuzimanje… + Primenjivanje… + Primenjivanje Crne i Bele liste + RaÅ¡Älanjivanje i spajanje host-ovih fajlova + Izgradnja host-ovih fajlova + Primenjivanje host-ovih fajlova + Primena hosts datoteke na vaÅ¡ sistem nije uspela!\n PokuÅ¡ajte promeniti ciljanu hosts datoteku u podeÅ¡avanjima u /data/data/hosts. + Primena neuspeÅ¡na + Vraćanje uspeÅ¡no + Vraćanje neusÅ¡erno iz nepoznatih razloga. + Vraćanje neuspeÅ¡no! + Nijedan od vaÅ¡ih omogućenih izvora hostova nije dostupan! Da li ste ispravno povezani na internet? + Preuzimanje neuspeÅ¡no + Privatni falj ne može biti kreiran. + NeuspeÅ¡no kreiranje privatnog fajla + Omogućavanje je uspelo. + Onemogućavanje je uspelo + + Ulazni URL do host-ovih fajlova + Ovo nije važeći hostname! + Nije dobro formirano ime hosta + Ovo nije validan IP! + Nije dobro formiran IP + UÄitavanje… + + + Osveži + Dodaj + Pomoć + + S-ON/S-OFF + ÄŒesto Postavljena Pitanja + Problemi + + + Ad Blocker + Nema instaliranog ureÄ‘ivaÄa teksta + Nema instaliranog ureÄ‘ivaÄa teksta za otvaranje hosts datoteke. Možete instalirati Jotu ili sliÄni ureÄ‘ivaÄ teksta.\n\n Želite li da instalirate Jotu? + Nije instaliran fajl menadžer + Nije moguće pronaći menađžer datoteka za otvaranje datoteka. Možete instalirati OI File Manager-a ili drugi menađžer datoteka.\n\n Želite li da instalirate OI File Manager? + + Tcpdump je alatka za praćenje i Äuvanje DNS zahteva u log fajlu. Možete ga pokrenuti u pozadini, pokretanje aplikacija koje pokazuju reklame, i posle toga analiziraju DNS zahtev korišćenjem log fajla. Mogući ad serveri mogu biti dodati u Crnu listu. + + + Home + Host-ovi resursi + Your lists + Otvori host-ove fajlove + Log DNS requests + Scan for adware + PodeÅ¡avanja + Pomoć + + PodeÅ¡avanja + + diff --git a/app/src/main/res/values-sr/strings_app.xml b/app/src/main/res/values-sr/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-sr/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-sr/strings_errors.xml b/app/src/main/res/values-sr/strings_errors.xml new file mode 100644 index 0000000..126ca8e --- /dev/null +++ b/app/src/main/res/values-sr/strings_errors.xml @@ -0,0 +1,6 @@ + + + + Nema internet konekcije + Nema dovoljno memorije + \ No newline at end of file diff --git a/app/src/main/res/values-sr/strings_home.xml b/app/src/main/res/values-sr/strings_home.xml new file mode 100644 index 0000000..e22ce2f --- /dev/null +++ b/app/src/main/res/values-sr/strings_home.xml @@ -0,0 +1,9 @@ + + + + PodeÅ¡avanja + + + Molimo da proÄitate Pomoć za viÅ¡e informacija. + + \ No newline at end of file diff --git a/app/src/main/res/values-sr/strings_hosts.xml b/app/src/main/res/values-sr/strings_hosts.xml new file mode 100644 index 0000000..eaa3076 --- /dev/null +++ b/app/src/main/res/values-sr/strings_hosts.xml @@ -0,0 +1,6 @@ + + + Host-ovi resursi + + nije dostupno + diff --git a/app/src/main/res/values-sr/strings_lists.xml b/app/src/main/res/values-sr/strings_lists.xml new file mode 100644 index 0000000..95895da --- /dev/null +++ b/app/src/main/res/values-sr/strings_lists.xml @@ -0,0 +1,6 @@ + + + Your lists + Hostname: + IP (IPv4 or IPv6): + diff --git a/app/src/main/res/values-sr/strings_log.xml b/app/src/main/res/values-sr/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-sr/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-sr/strings_notification.xml b/app/src/main/res/values-sr/strings_notification.xml new file mode 100644 index 0000000..e4248c7 --- /dev/null +++ b/app/src/main/res/values-sr/strings_notification.xml @@ -0,0 +1,4 @@ + + + Ažuriranje dostupno + \ No newline at end of file diff --git a/app/src/main/res/values-sr/strings_prefs_backup_restore.xml b/app/src/main/res/values-sr/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-sr/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-sr/strings_prefs_main.xml b/app/src/main/res/values-sr/strings_prefs_main.xml new file mode 100644 index 0000000..b9134df --- /dev/null +++ b/app/src/main/res/values-sr/strings_prefs_main.xml @@ -0,0 +1,6 @@ + + + PodeÅ¡avanja + + Otklanjanje greÅ¡aka + diff --git a/app/src/main/res/values-sr/strings_prefs_root.xml b/app/src/main/res/values-sr/strings_prefs_root.xml new file mode 100644 index 0000000..c655268 --- /dev/null +++ b/app/src/main/res/values-sr/strings_prefs_root.xml @@ -0,0 +1,14 @@ + + + Otvori host-ove fajlove + OdrediÅ¡ni hosts fajl + + /system/etc/hosts + /data/hosts + /data/data/hosts + PrilagoÄ‘eno odrediÅ¡te + + + Prebacivanje + Omogući webserver + diff --git a/app/src/main/res/values-sr/strings_prefs_update.xml b/app/src/main/res/values-sr/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-sr/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-sr/strings_prefs_vpn.xml b/app/src/main/res/values-sr/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-sr/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-sr/strings_support.xml b/app/src/main/res/values-sr/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-sr/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-sr/strings_update.xml b/app/src/main/res/values-sr/strings_update.xml new file mode 100644 index 0000000..bb7def8 --- /dev/null +++ b/app/src/main/res/values-sr/strings_update.xml @@ -0,0 +1,4 @@ + + + Ažuriranje dostupno + diff --git a/app/src/main/res/values-sr/strings_welcome.xml b/app/src/main/res/values-sr/strings_welcome.xml new file mode 100644 index 0000000..e952508 --- /dev/null +++ b/app/src/main/res/values-sr/strings_welcome.xml @@ -0,0 +1,4 @@ + + + Neophodan Root-ovan Android + diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml new file mode 100644 index 0000000..6138c3d --- /dev/null +++ b/app/src/main/res/values-sv/strings.xml @@ -0,0 +1,262 @@ + + + + Avsluta + Stäng + Ja + Nej + Lägg till + Avbryt + Spara + Hjälp + + + Välkommen! + AdAway är gratis och öppen källkod gjord för att blockera annonser. Den laddar ner annonsnätverk och konfigurerar din enhet att blockera dem.\nVill du veta mer? Ta en titt pÃ¥ hjälpen nedan! + Visa mer hjälp + Uppdateringsstatus + Alla värdfiler frÃ¥n de förinställda källorna är hämtade, ihopslagna med dina egna listor och tillämpade som en värdfil pÃ¥ ditt system. + Aktivera annonsblockering + Inaktivera annonsblockering + Webbserver + Körs + Stoppad + Starta eller stoppa webbservern frÃ¥n att svara pÃ¥ förfrÃ¥gningar till blockerade värdnamn. + Aktivera webbserver + Inaktivera webbserver + VPN + Körs + Stoppad + Starta eller stoppa VPN frÃ¥n att filtrera förfrÃ¥gningar. + Aktivera VPN + Inaktivera VPN + + + Redigera post + Verkställ + Redigera + Ta bort + + + Importerar… + Säkerhetskopian importerades framgÃ¥ngsrikt frÃ¥n din externa lagring. + Det gick inte att importera säkerhetskopian. Är dess format rätt? Kolla logcat för mer detaljer. + Exporterar… + Säkerhetskopian exporterades framgÃ¥ngsrikt till filen \'%s\' i din externa lagring. + Exporteringen av den säkerhetskopierade filen \'%s\' misslyckades + + + Värdfilen + Värdfilen (HOSTS) är en systemfil som mappar om värdnamn till IP-adresser. Det är en vanlig textfil som AdAway kan hantera. Här är nÃ¥gra rader frÃ¥n början av filen: + Laddar värdfilens innehÃ¥ll… + Öppna värdfilen + + + Söker efter uppdateringar + Kontrollerar %s-källa för uppdatering + Tar emot källor + Ladda ner källa %s + Läser källan %s + Tolkar %s-källa + Synkroniserar regel-databas + Ã…terställer standardvärdfilen + Standard värdfil Ã¥terställd + Skapar standardvärdfil + Källuppdatering tillgänglig + Nyare värdfiler är tillgängliga + Hittade inga källuppdateringar + Ingen internetanslutning + Ingen internetanslutning tillgänglig + Otillgängliga källor + Inga värdkällor är nÃ¥bara! + Root-Ã¥tkomst nekad + TillÃ¥t root-Ã¥tkomst frÃ¥n din root-app + NÃ¥got gick fel + Titta i logcat för fler detaljer + Aktiverad + Nyaste värdfilerna aktiverade + Avaktiverad + Standard värdfil är installerad + Verkställ de senaste källorna + Skapar en ny värdfil + Kopierar en new värdfil + Kontrollerar värdfilskopia + Värdfilen uppdaterad + VPN-konfigurationen uppdaterad + Din konfiguration har ändrats. Den behöver nu verkställas. + Verkställ + Verkställer den nya konfigurationen… + Det gick inte att verkställa den nya konfigurationen. + + + Symlinken till värdfilsmÃ¥let saknas + Symlink frÃ¥n ditt mÃ¥l till /system/etc/hosts existerar ej eller är inkorrekt! AdAway kommer inte fungera om den inte pekar pÃ¥ rätt fil.\n\nVill du försöka skapa en symlink? + Symlink saknas + Inte tillräckligt med utrymme pÃ¥ partitionen!\nFörsök ändra mÃ¥lvärdfil i inställningarna till /data/data/hosts. + Inte tillräckligt med utrymme + Hämtade filen kunde inte läsas. + Privat fil misslyckades + Ommontering av partitionen som läs/skriv misslyckades! + Ommontering misslyckades + Det gick inte att kopiera värdfilen + Kopiering av värdfil misslyckades! + Kopiering misslyckades + Verkställda värdkällor + Verkställd + Verkställning lyckades.\nDet kan bli nödvändigt att starta om enheten för att ändringarna ska träda i kraft.\n\nVill du starta om?\n(För att förhindra dataförlust, se till att ingen app använder SD-kortet för tillfället!) + En symbolisk länk har skapats.\nDet kan bli nödvändigt att starta om enheten för att ändringarna ska träda i kraft.\n\nVill du starta om?\n(För att förhindra dataförlust, se till att ingen app använder SD-kortet för tillfället!) + Symlink skapad utan problem + Symlink kunde ej skapas av Android.\nDetta fel beror oftast pÃ¥ en \'funktion\' som kallas S-ON pÃ¥ HTC-telefoner!\n\nEn lösning är att boota telefonen i Ã¥terställningsläge och skapa en symlink därifrÃ¥n med \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nOm detta inte fungerar, sök pÃ¥ internet efter S-OFF och din telefonmodell. + Skapande av symlink misslyckades + Läs Hjälp för mer information. + En APN-proxy är inställd pÃ¥ din Android!\nAdAway fungerar inte lika tillförlitligt pÃ¥ mobila nätverk som pÃ¥ 3G. Du kan inaktivera proxyn genom att gÃ¥ till din valda APN (frÃ¥n appen Inställningar: Nätverk & Internet -> Mobilnätverk -> Avancerat -> Ã…tkomstpunktsnamn) och ta bort värdet i proxyfältet. + APN-proxy inställt! + Internetanslutningen fungerar ej. + Ingen anslutning + Hämtar… + Verkställer… + Verkställer Svartlista och Vitlista + Tolkar och slÃ¥r ihop värdfiler + Bygger värdfil + Verkställer värdfil + Det gick inte att verkställa den nya värdfilen. + Verkställning av värdfil pÃ¥ systemet misslyckades!\nFörsök ändra mÃ¥lvärdfil i inställningarna till /data/data/hosts. + Verkställning misslyckades + Kontrollera din root-hanteringsapp för att säkerställa att root-Ã¥tkomst har beviljats. + Du har Ã¥tergÃ¥tt till standard värdfil.\nDet kan vara nödvändigt att starta om Android för ändringarna ska träda i kraft.\n\nVill du starta om?\n(För att förhindra förlust av data, se till att SD-kortet inte används av en app!) + Ã…terställd + Det gÃ¥r inte att Ã¥terställa värdfilen + Ã…terställningen misslyckades av okända skäl. + Ã…terställning misslyckades! + Ingen av dina aktiva värdkällor kan nÃ¥s! Är du ansluten till Internet? + Nerladdningen misslyckades + Det gick inte att skriva en ny privat värdfil + Det gÃ¥r inte att skapa en privat fil. + Skapande av privat fil misslyckades + Du har aktiverade systemlöst läge.\nDet kan bli nödvändigt att starta om enheten för att ändringarna ska träda i kraft. \n\nVill du starta om?\n(För att förhindra dataförlust se till att ingen app använder SD-kortet för tillfället!) + Aktivering lyckades + Du inaktiverade systemlöst läge.\nDet kan bli nödvändigt att starta om enheten för att ändringarna ska träda i kraft. \n\nVill du starta om?\n(För att förhindra dataförlust se till att ingen app använder SD-kortet för tillfället!) + Inaktiverad + Det gick inte att aktivera VPN-annonsblockeringen. + Det gick inte att inaktivera VPN-annonsblockeringen + Aktiverar värdfil Magisk-modul + Aktivera systemlöst läge i Magisk manager. I inställningarna, aktivera alternativet Systemless hosts och starta sedan om enheten. + Inaktiverar värdfil Magisk-modul + Inaktivera systemlöst läge i Magisk manager. I modullistan, avinstallera modulen Systemless hosts och starta sedan om enheten. + + + Importera URL till värdfil: + Detta är inget giltigt värdnamn! + Felaktigt utformat värdnamn + Detta är inte en korrekt IP-adress! + Felaktigt utformad IP-adress + Starta aldrig om och visa inte denna frÃ¥gan igen! + Laddar… + + + Uppdatera + Lägg till + Hjälp + Importera säkerhetskopia + Exportera säkerhetskopia + + + S-ON/S-OFF + FAQ + Problem + + + Annonsappar + Här hittar du installerade annonsappar, stygga applikationer som inte kan blockeras med AdAway. Dessa appar använder till exempel Airpush-aviseringar som kan visa sig även om appen inte körs och den kan även ändra din ringsignal. Den enda tillgängliga lösningen är att avinstallera dessa appar genom att trycka i listan. + Söker… + Hittade inga annonsappar! + + + Annonsblockerare + Ingen textredigerare installerad + Ingen textredigerare kunde hittas för att öppna värdfilen. Du kan installera Jota eller andra textredigerare att hantera detta.\n\nVill du installera Jota nu? + Ingen filhanterare installerad + Ingen filhanterare kunde hittas för att öppna filer. Du kan installera OI File Manager eller andra filhanterare att hantera detta.\n\nVill du installera OI File Manager nu? + + + Tcpdump + Tcpdump är ett verktyg för att övervaka DNS-förfrÃ¥gningar och spara dem i en loggfil. Du kan starta det i bakgrunden, köra program som visar annonser, och efterÃ¥t analysera DNS-förfrÃ¥gningarna med hjälp av loggfilen. Möjlig annonsserver kan dÃ¥ läggas till pÃ¥ din svartlista. + Inaktivera övervakning + Aktivera övervakning + Visa resultatet + Sortera domänerna + Rensa loggen + Lägg till post till svartlistan + Lägg till post till vitlistan + Lägg till post till omdirigeringslista + + Redigera textinställningsvärden + Öppna meny + Stäng meny + + + + Hem + Värdkällor + Dina listor + Öppna värdfil + Logga DNS-förfrÃ¥gningar + Sök efter adware + Inställningar + Hjälp + + + + + DNS-förfrÃ¥gningar + Dina listor + Inställningar + + + Installerad för %1$s sedan + %1$s behöver inte uppdateras + %1$s behöver uppdateras + Senaste uppdateringen %1$s sedan + Okänd uppdaterigsstatus + Avaktiverad + nÃ¥gra minuter + + %d minut + %d minuter + + + %d timme + %d timmar + + + %d dag + %d dagar + + + %d mÃ¥nad + %d mÃ¥nader + + + + Värden kopierades till klippbordet + + + startar + aktiv + stoppar + vänta pÃ¥ nätverket + Ã¥teranslutning + Ã¥teranslutningsfel + pausad + stoppad + Annonsblockerare VPN %1$s + Pausa + Tryck för att Ã¥teruppta + + + Behörigheter för AdAway + TillÃ¥t interaktion med AdAway + Aktivera och inaktivera systemets annonsblockering + TillÃ¥t att skicka kommandon till AdAway exempelvis aktivering eller inaktivering av annonsblockering för hela systemet + + diff --git a/app/src/main/res/values-sv/strings_app.xml b/app/src/main/res/values-sv/strings_app.xml new file mode 100644 index 0000000..24a00fd --- /dev/null +++ b/app/src/main/res/values-sv/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Open Source annonsblockerare + AdAway-logotyp + diff --git a/app/src/main/res/values-sv/strings_errors.xml b/app/src/main/res/values-sv/strings_errors.xml new file mode 100644 index 0000000..36fe31a --- /dev/null +++ b/app/src/main/res/values-sv/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Ingen internetanslutning + Det gÃ¥r inte att upprätta en anslutning till internet. Kontrollera anslutningen pÃ¥ din enhet. + Det gick inte att ladda ner värdkälla + Ingen av dina aktiverade värdkällor är Ã¥tkomliga. Kontrollera att du är ansluten till internet. + + Det gick inte att skapa privat fil + Det gick inte att skapa en privat fil att bygga ett nytt värdkälla. Kontrollera att du ha tillgängligt med ledigt utrymme pÃ¥ din enhet. + Inte tillräckligt med utrymme + Det gick inte att kopiera värdfilen till systempartitionen. Kontrollera att den systemlösa modulen i Magisk är aktiverad och starta sedan om. + Det gick inte att installera den nya värdfilen + Det gick inte att kopiera värdfilen till partitionen /system. Kontrollera att den systemlösa modulen i Magisk är aktiverad och starta sedan om. + Det gick inte att Ã¥terställa värdfilen + Det gick inte att Ã¥terställa standard värdfilskonfiguration. + + Det gick inte att aktivera VPN-annonsblockeringen. + Kontrollera dina VPN-inställningar och auktorisera applikationen VPN sÃ¥ att den startar. + Det gick inte att inaktivera VPN-annonsblockeringen + Kontrollera dina VPN-inställningar för att inaktivera det manuellt. + diff --git a/app/src/main/res/values-sv/strings_home.xml b/app/src/main/res/values-sv/strings_home.xml new file mode 100644 index 0000000..9f2927c --- /dev/null +++ b/app/src/main/res/values-sv/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Blockerad + TillÃ¥ten + Omdirigerad + + + + %d uppdaterad källa + %d uppdaterade källor + + + %d inaktuell källa + %d inaktuella källor + + Check for hosts updates + Uppdatera värdar + + + Show DNS request log + + + Show help\nand tips + + + Öppna GitHub-sidan + + + Stöd projektet + + + GitHub project + Inställningar + + + Öppna navigeringsmapp + Pausa/Ã¥teruppta annonsblockering + Uppdatera blockerade domäner + Visa begärda domäner + + + Läs Hjälp för mer information. + + \ No newline at end of file diff --git a/app/src/main/res/values-sv/strings_hosts.xml b/app/src/main/res/values-sv/strings_hosts.xml new file mode 100644 index 0000000..3a25f9b --- /dev/null +++ b/app/src/main/res/values-sv/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Värdkällor + + Användarlista + Oficiella AdAway-källor + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + ej tillgänglig + %s värdkällor + + Lägg till källa + Redigera källa + URL: (använd https:// eller file://-resurs) + Värdkällans webbadress + diff --git a/app/src/main/res/values-sv/strings_lists.xml b/app/src/main/res/values-sv/strings_lists.xml new file mode 100644 index 0000000..eec3eea --- /dev/null +++ b/app/src/main/res/values-sv/strings_lists.xml @@ -0,0 +1,24 @@ + + + Dina listor + Lägg till värd + + Blockerad + TillÃ¥ten + Omdirigerad + + Filtrera värdar + Sök värdnamn… + Växla källor + + Lägg till värd till svartlistan + Lägg till värd till vitlistan + Lägg till värdomdirigering + Redigera svartlistad värd + Redigera vitlistad värd + Redigera omdirigering + Värdnamn: + Värdkällans webbadress + (Jokertecknen * och ? är tillÃ¥tna) + IP-adress (IPv4 eller IPv6): + diff --git a/app/src/main/res/values-sv/strings_log.xml b/app/src/main/res/values-sv/strings_log.xml new file mode 100644 index 0000000..e665954 --- /dev/null +++ b/app/src/main/res/values-sv/strings_log.xml @@ -0,0 +1,11 @@ + + + Stänga av/sätt pÃ¥ logginspelning + Tryck pÃ¥ spela in för att börja logga förfrÃ¥gningar, surfa pÃ¥ webben eller använd appar, gÃ¥ sedan tillbaka eller svep för att uppdatera loggarna. + \n\nBlockerade förfrÃ¥gningar kommer inte att loggas. Inaktivera annonsblockering först om du ocksÃ¥ vill logga dem. + + Alfabetisk sortering + Toppleveldomän + + Omdirigera domän + diff --git a/app/src/main/res/values-sv/strings_notification.xml b/app/src/main/res/values-sv/strings_notification.xml new file mode 100644 index 0000000..0c23d35 --- /dev/null +++ b/app/src/main/res/values-sv/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Uppdateringar + Nya uppdateringsaviseringar + Källuppdatering tillgänglig + Nyare värdfiler finns att ladda ner. + App-uppdatering tillgänglig + En ny version av AdAway finns att ladda ner. + + VPN + VPN-aviseringar + \ No newline at end of file diff --git a/app/src/main/res/values-sv/strings_prefs_backup_restore.xml b/app/src/main/res/values-sv/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..f742488 --- /dev/null +++ b/app/src/main/res/values-sv/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Säkerhetskopiera & Ã¥terställa + Säkerhetskopiera + Säkerhetskopiera dina blockeringsregler till extern lagring + Ã…terställ + Ã…terställ dina blockeringsregler frÃ¥n säkerhetskopia + diff --git a/app/src/main/res/values-sv/strings_prefs_main.xml b/app/src/main/res/values-sv/strings_prefs_main.xml new file mode 100644 index 0000000..9fe0c6e --- /dev/null +++ b/app/src/main/res/values-sv/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Inställningar + + Allmänt + Mörk tema + + Ljust + Mörkt + Systemstandard + + Automatisk uppdatering + + Annonsblockering + Root-baserad annonsblockering + VPN-baserad annonsblockering + Aktivera IPv6-stöd + Säkerhetskopiera / Ã¥terställ blockregler + + Felsökning + Skicka kraschrapport + Rapportera till Sentry (sentry.io) + Stöds inte i denna versionen + Utökad loggning + Appen mÃ¥ste startas om för att verkställas + diff --git a/app/src/main/res/values-sv/strings_prefs_root.xml b/app/src/main/res/values-sv/strings_prefs_root.xml new file mode 100644 index 0000000..cff41f6 --- /dev/null +++ b/app/src/main/res/values-sv/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Root-baserad annonsblockering + + Värd installerad + Öppna värdfil + MÃ¥lvärdfil + Läs hjälpen innan du använder denna funktionen + + /system/etc/hosts + /data/hosts + /data/data/hosts + Anpassat mÃ¥l + + Anpassad mÃ¥lplats + Dölj omstartsdialog efter verkställ + + Omdirigering + Definiera var du ska omdirigera blockerade värdar + IPv4-omdirigering + IPv6-omdirigering + Ogiltig omdirigering + + Lokal webbserver + Den lokala webbservern lyssnar pÃ¥ lokala IP-adresser till att svara pÃ¥ blockerade värdnamsförfrÃ¥gningar. Det kan förhindra appfrysningar pÃ¥ blockerade anslutningar. + Aktivera webbserver + Testa webbservern + Installera självsignerat certifikat + Installera certifikat manuellt + Med start i Android 11 (R) kan appar inte längre automatiskt installera certifikat (CA). \n\GÃ¥ till Säkerhet under Inställningar, \"Kryptering & Certifikat\" och \"Installera ett certifikat\". Här väljer du \"CA-certifikat\" och väljer den certifikatfil som du nyss exporterade. + Öppna Säkerhetsinställningar + Kontrollerar… + Körs inte + Körs men utan installerat certifikat + Körs med installerat certifikat + Ersätt tomt annonsutrymme med en appikon + diff --git a/app/src/main/res/values-sv/strings_prefs_update.xml b/app/src/main/res/values-sv/strings_prefs_update.xml new file mode 100644 index 0000000..5086a87 --- /dev/null +++ b/app/src/main/res/values-sv/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + Uppdateringar + + Applikationsuppdateringar + Sök efter uppdatering vid uppstart + Sök regelbundet efter uppdateringar + Inkludera betautgÃ¥vor + + Värduppdateringar + Sök efter uppdatering vid uppstart + Sök regelbundet efter uppdateringar + Synkronisera vid uppdatering + Synkronisera endast pÃ¥ nätverk med obegränsad data + diff --git a/app/src/main/res/values-sv/strings_prefs_vpn.xml b/app/src/main/res/values-sv/strings_prefs_vpn.xml new file mode 100644 index 0000000..6bb09b7 --- /dev/null +++ b/app/src/main/res/values-sv/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN-baserad annonsblockering + + Aktivera vid uppstart + Övervaka anslutning + Kontrollera periodvis nätverkets tillstÃ¥nd för att starta om VPN vid urkoppling. + + Exkluderade applikationer + Konfigurera vilken applikation som inte ska använda VPN sÃ¥ ingen anslutning blockeras. + Exkludera systemapplikationer + + Inga + All except browsers + Alla + + Exkludera användarapplikationer + + + Exkluderade applications + Markera alla + Avmarkera alla + Applikationsikon + diff --git a/app/src/main/res/values-sv/strings_support.xml b/app/src/main/res/values-sv/strings_support.xml new file mode 100644 index 0000000..49d1723 --- /dev/null +++ b/app/src/main/res/values-sv/strings_support.xml @@ -0,0 +1,5 @@ + + + Support + Bli en sponsor + \ No newline at end of file diff --git a/app/src/main/res/values-sv/strings_update.xml b/app/src/main/res/values-sv/strings_update.xml new file mode 100644 index 0000000..ab54061 --- /dev/null +++ b/app/src/main/res/values-sv/strings_update.xml @@ -0,0 +1,21 @@ + + + Uppdatera AdAway + + Uppdatering tillgänglig! + + + Allt är uppdaterat + Uppdatering tillgänglig + Uppdaterar AdAway + Uppdatera nu + %1$s / %2$s + Senaste ändringar: + Ändringslogg: + Stöd utvecklingen + Donera + Sponsor + + + Laddar ner den senaste AdAway-versionen… + diff --git a/app/src/main/res/values-sv/strings_welcome.xml b/app/src/main/res/values-sv/strings_welcome.xml new file mode 100644 index 0000000..f079ba5 --- /dev/null +++ b/app/src/main/res/values-sv/strings_welcome.xml @@ -0,0 +1,52 @@ + + + Välkommen + Guiden första steget + Guiden andra steget + Guiden sista steget + + + Välkommen till AdAway! + AdAway tillhandahÃ¥ller tvÃ¥ annonsblockeringsmetoder. Välj den du gillar: + + Root-logo + Root-baserad\nannonsblockering + Snabbare + Batterivänlig + Root krävs + + VPN-logo + VPN-baserad\nannonsblockering + LÃ¥ngsammare + Kör i bakgrunden + Kompatibilitet + + Rootad Android krävs + Antingen sÃ¥ kunde binärfilen för su inte hittas eller sÃ¥ tillät du inte root-Ã¥tkomst för AdAway.\n\nDetta kan hända när din enhet inte är rootad. Du kan hitta mer information om hur du rootar din enhet pÃ¥ wiki.lineageos.org eller andra Android-webbplatser. + + Pro + Con + + + Synkriniserad + Fel vid synkronisering + + Synkroniserar + Synkroniserad! + AdAway laddar ner annonsnätverk att blockera frÃ¥n online-källor. Du kan anpassa dem senare i inställningarna. + Försök synkronisera igen + Det gick inte att synkronisera: %1$s Försöka igen? + + + Support + Stöd mig! + Detta är en app som är gratis och öppen källkod. Jag utvecklar den pÃ¥ min fritid. SÃ¥ om du tycker om den, för du gärna visa ditt stöd: + Donera pÃ¥ PayPal + Gillar du fel? Inte jag heller. + Aktivera telemetri för att skicka mig kraschrapporter + + + BakÃ¥t + Nästa + Avsluta + diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml new file mode 100644 index 0000000..19d44b7 --- /dev/null +++ b/app/src/main/res/values-ta/strings.xml @@ -0,0 +1,45 @@ + + + + வெளியேற௠+ மூட௠+ ஆம௠+ இலà¯à®²à¯ˆ + சேர௠+ ரதà¯à®¤à¯à®šà¯†à®¯à¯ + சேமி + + வரவேறà¯à®•ிறோம௠+ மேலà¯à®®à¯ உதவியைக௠காடà¯à®Ÿà¯ + நிலையைப௠பà¯à®¤à¯à®ªà¯à®ªà®¿ + விளமà¯à®ªà®°à®¤à¯ தடà¯à®ªà¯à®ªà¯ˆ இயகà¯à®•௠+ விளமà¯à®ªà®°à®¤à¯ தடà¯à®ªà¯à®ªà¯ˆ à®®à¯à®Ÿà®•à¯à®•௠+ வலை சேவையகம௠+ நிறà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ + வலை சேவையகதà¯à®¤à¯ˆ இயகà¯à®•௠+ வலை சேவையகதà¯à®¤à¯ˆ à®®à¯à®Ÿà®•à¯à®•௠+ நிறà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ + விணà¯à®£à®ªà¯à®ªà®¿ + திரà¯à®¤à¯à®¤à¯ + அழி + + + இறகà¯à®•à¯à®®à®¤à®¿ செயà¯à®•ிறதà¯â€¦ + விணà¯à®£à®ªà¯à®ªà®¿ + மேலà¯à®®à¯ தகவலà¯à®•à¯à®•௠உதவியைப௠படிகà¯à®•வà¯à®®à¯ + சேர௠+ + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + உஙà¯à®•ள௠படà¯à®Ÿà®¿à®¯à®²à¯à®•ள௠+ விரà¯à®ªà¯à®ªà®¤à¯à®¤à¯‡à®°à¯à®µà¯à®•ள௠+ + diff --git a/app/src/main/res/values-ta/strings_app.xml b/app/src/main/res/values-ta/strings_app.xml new file mode 100644 index 0000000..d9d078e --- /dev/null +++ b/app/src/main/res/values-ta/strings_app.xml @@ -0,0 +1,6 @@ + + + ஆடà¯à®…வே + திறநà¯à®¤ மூல விளமà¯à®ªà®°-தடà¯à®ªà¯à®ªà®¾à®©à¯ + ஆடà¯à®…வே சினà¯à®©à®®à¯ + diff --git a/app/src/main/res/values-ta/strings_errors.xml b/app/src/main/res/values-ta/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ta/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ta/strings_home.xml b/app/src/main/res/values-ta/strings_home.xml new file mode 100644 index 0000000..f7bed94 --- /dev/null +++ b/app/src/main/res/values-ta/strings_home.xml @@ -0,0 +1,40 @@ + + + + + தடà¯à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿ + அனà¯à®®à®¤à®¿à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿ + வழிமாறà¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ + + + + %d பà¯à®¤à¯à®ªà¯à®ªà®¿à®¤à¯à®¤ மூலம௠+ %d பà¯à®¤à¯à®ªà¯à®ªà®¿à®¤à¯à®¤ மூலஙà¯à®•ள௠+ + + %d காலாவதியான மூலம௠+ %d காலாவதியான மூலஙà¯à®•ள௠+ + + + உதவி காடà¯à®Ÿà¯ + + + கிடà¯à®¹à®ªà¯ பகà¯à®•தà¯à®¤à¯ˆà®¤à¯ திற + + + திடà¯à®Ÿà®¤à¯à®¤à¯ˆ ஆதரி + + + விரà¯à®ªà¯à®ªà®¤à¯à®¤à¯‡à®°à¯à®µà¯à®•ள௠+ + + வழிசெலà¯à®¤à¯à®¤à®²à¯ அலமாரியைத௠திற + விளமà¯à®ªà®°à®¤à¯ தடà¯à®ªà¯à®ªà¯ˆ இடைநிறà¯à®¤à¯à®¤à¯/மறà¯à®¤à¯à®¤à¯à®µà®•à¯à®•௠+ தடà¯à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿ களஙà¯à®•ளை பà¯à®¤à¯à®ªà¯à®ªà®¿ + கோரபà¯à®ªà®Ÿà¯à®Ÿ களஙà¯à®•ளைக௠காணà¯à®ªà®¿ + + + மேலà¯à®®à¯ தகவலà¯à®•à¯à®•௠உதவியைப௠படிகà¯à®•வà¯à®®à¯ + + diff --git a/app/src/main/res/values-ta/strings_hosts.xml b/app/src/main/res/values-ta/strings_hosts.xml new file mode 100644 index 0000000..e71ca5a --- /dev/null +++ b/app/src/main/res/values-ta/strings_hosts.xml @@ -0,0 +1,14 @@ + + + ஹோஸà¯à®Ÿà¯à®•ளின௠மூலஙà¯à®•ள௠+ + பயனர௠படà¯à®Ÿà®¿à®¯à®²à¯ + ஆடà¯à®…வே அதிகாரà¯à®µà®ªà¯à®ªà¯‚à®°à¯à®µ ஹோஸà¯à®Ÿà¯à®•ள௠+ + கிடைகà¯à®•விலà¯à®²à¯ˆ + %s ஹோஸà¯à®Ÿà¯à®•ள௠+ + மூலதà¯à®¤à¯ˆà®šà¯ சேர௠+ மூலதà¯à®¤à¯ˆà®¤à¯ திரà¯à®¤à¯à®¤à¯ + ஹோஸà¯à®Ÿà¯à®•ளின௠மூல URL + diff --git a/app/src/main/res/values-ta/strings_lists.xml b/app/src/main/res/values-ta/strings_lists.xml new file mode 100644 index 0000000..d0d386b --- /dev/null +++ b/app/src/main/res/values-ta/strings_lists.xml @@ -0,0 +1,11 @@ + + + உஙà¯à®•ள௠படà¯à®Ÿà®¿à®¯à®²à¯à®•ள௠+ + தடà¯à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿà®µà¯ˆ + அனà¯à®®à®¤à®¿à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿ + வழிமாறà¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ + மூலஙà¯à®•ளை இரà¯à®¨à®¿à®²à¯ˆ மாறà¯à®±à¯ + வழிமாறà¯à®±à®™à¯à®•ளை திரà¯à®¤à¯à®¤à¯ + ஹோஸà¯à®Ÿà¯à®•ளின௠மூல URL + diff --git a/app/src/main/res/values-ta/strings_log.xml b/app/src/main/res/values-ta/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-ta/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-ta/strings_notification.xml b/app/src/main/res/values-ta/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ta/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ta/strings_prefs_backup_restore.xml b/app/src/main/res/values-ta/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..ed8d1c0 --- /dev/null +++ b/app/src/main/res/values-ta/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + காபà¯à®ªà¯à®ªà¯à®ªà®¿à®°à®¤à®¿ & மீடà¯à®Ÿà®®à¯ˆ + காபà¯à®ªà¯à®ªà¯à®ªà®¿à®°à®¤à®¿ + உஙà¯à®•ள௠தடà¯à®ªà¯à®ªà¯ விதிகளை வெளிபà¯à®ªà¯à®± சேமிபà¯à®ªà®•தà¯à®¤à¯à®•à¯à®•௠காபà¯à®ªà¯à®ªà¯à®ªà®¿à®°à®¤à®¿ எடà¯à®•à¯à®•வà¯à®®à¯ + மீடà¯à®Ÿà¯†à®Ÿà¯ + காபà¯à®ªà¯à®ªà¯à®ªà®¿à®°à®¤à®¿ கோபà¯à®ªà®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ உஙà¯à®•ள௠தடà¯à®ªà¯à®ªà¯ விதிகளை மீடà¯à®Ÿà¯†à®Ÿà¯ + diff --git a/app/src/main/res/values-ta/strings_prefs_main.xml b/app/src/main/res/values-ta/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-ta/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-ta/strings_prefs_root.xml b/app/src/main/res/values-ta/strings_prefs_root.xml new file mode 100644 index 0000000..9d72eff --- /dev/null +++ b/app/src/main/res/values-ta/strings_prefs_root.xml @@ -0,0 +1,11 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + வலை சேவையகதà¯à®¤à¯ˆ இயகà¯à®•௠+ diff --git a/app/src/main/res/values-ta/strings_prefs_update.xml b/app/src/main/res/values-ta/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ta/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ta/strings_prefs_vpn.xml b/app/src/main/res/values-ta/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-ta/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-ta/strings_support.xml b/app/src/main/res/values-ta/strings_support.xml new file mode 100644 index 0000000..4e2add1 --- /dev/null +++ b/app/src/main/res/values-ta/strings_support.xml @@ -0,0 +1,5 @@ + + + ஆதரி + ஆதரவாளர௠ஆக௠+ \ No newline at end of file diff --git a/app/src/main/res/values-ta/strings_update.xml b/app/src/main/res/values-ta/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ta/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ta/strings_welcome.xml b/app/src/main/res/values-ta/strings_welcome.xml new file mode 100644 index 0000000..14d7c77 --- /dev/null +++ b/app/src/main/res/values-ta/strings_welcome.xml @@ -0,0 +1,5 @@ + + + + ஆதரி + diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml new file mode 100644 index 0000000..6e41d48 --- /dev/null +++ b/app/src/main/res/values-th/strings.xml @@ -0,0 +1,213 @@ + + + + ออภ+ ปิด + ใช่ + ไม่ + เพิ่ม + ยà¸à¹€à¸¥à¸´à¸ + บันทึภ+ ช่วยเหลือ + + + ยินดีต้อนรับค่ะ! + à¹à¸ªà¸”งความช่วยเหลือเพิ่มเติม + อัพเดทสถานะ + ไฟล์โฮสต์ทั้งหมดจาà¸à¹à¸«à¸¥à¹ˆà¸‡à¸—ี่à¸à¸³à¸«à¸™à¸”ไว้ถูà¸à¸”าวน์โหลดà¹à¸¥à¸°à¸•ิดตั้งเป็นไฟล์โฮสต์บนระบบของคุณà¹à¸¥à¹‰à¸§ + เปิดใช้งานบล็อคโฆษณา + ปิดใช้งานบล็อคโฆษณา + เว็บเซิร์ฟเวอร์ + à¸à¸³à¸¥à¸±à¸‡à¸—ำงาน + à¸à¸³à¸¥à¸±à¸‡à¸«à¸¢à¸¸à¸” + เปิดใช้งานเว็บเซิร์ฟเวอร์ + ปิดใช้งานเว็บเซิร์ฟเวอร์ + VPN + à¸à¸³à¸¥à¸±à¸‡à¸—ำงาน + à¸à¸³à¸¥à¸±à¸‡à¸«à¸¢à¸¸à¸” + เปิดใช้งาน VPN + ปิดใช้งาน VPN + + + à¹à¸à¹‰à¹„ขรายà¸à¸²à¸£ + นำไปใช้ + à¹à¸à¹‰à¹„ข + ลบ + + + à¸à¸³à¸¥à¸±à¸‡à¸™à¸³à¹€à¸‚้า… + à¸à¸³à¸¥à¸±à¸‡à¸ªà¹ˆà¸‡à¸­à¸­à¸â€¦ + + ไฟล์โฮสต์ + à¸à¸³à¸¥à¸±à¸‡à¹‚หลดเนื้อหาไฟล์โฮสต์… + เปิดไฟล์ hosts + + + à¸à¸³à¸¥à¸±à¸‡à¸•รวจสอบอัปเดตใหม่ + à¸à¸³à¸¥à¸±à¸‡à¸•รวจสอบ %s จาà¸à¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาสำหรับà¸à¸²à¸£à¸­à¸±à¸›à¹€à¸”ต + à¸à¸¹à¹‰à¹‚ฮสต์ไฟล์ต้นฉบับà¸à¸¥à¸±à¸šà¸„ืนà¹à¸¥à¹‰à¸§ + à¸à¸³à¸¥à¸±à¸‡à¸ªà¸£à¹‰à¸²à¸‡à¹„ฟล์โฮสต์มาตรà¸à¸²à¸™ + สามารถอัพเดตได้ + สามารถอัพเดตไฟล์โฮสต์ได้ + ไม่พบà¸à¸²à¸£à¸­à¸±à¸›à¹€à¸”ตà¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มา + ไม่มีà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่ออินเตอร์เน็ต + ไม่มีà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่ออินเตอร์เน็ต + ไม่สามารถใช้งานà¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาได้ + ไม่สามารถเข้าถึงà¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาโฮสต์ได้ + สิทธิ์ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸–ูà¸à¸›à¸à¸´à¹€à¸ªà¸˜ + อนุà¸à¸²à¸•สิทธิ์ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸ˆà¸²à¸à¹à¸­à¸žà¸œà¸¹à¹‰à¸”ูà¹à¸¥à¸£à¸°à¸šà¸šà¹à¸¥à¹‰à¸§ + มีบางอย่างผิดปà¸à¸•ิ + ตรวจสอบ logcat สำหรับรายละเอียดเพิ่มเติม + เปิดใช้งานà¹à¸¥à¹‰à¸§ + เปิดใช้งานไฟล์โฮสต์à¹à¸¥à¹‰à¸§ + ปิดใช้งาน + คืนค่าไฟล์โฮสต์เป็นค่าเริ่มต้นà¹à¸¥à¹‰à¸§ + ใช้à¹à¸«à¸¥à¹ˆà¸‡à¸‚้อมูลล่าสุด + นำไปใช้ + ใช้ตั้งค่าใหม่ + ใช้ตั้งค่าใหม่ล้มเหลว + + Symlink จาà¸à¹€à¸›à¹‰à¸²à¸«à¸¡à¸²à¸¢à¸‚องคุณไปยัง /system/etc/hosts ไม่พบหรือไม่ถูà¸à¸•้อง AdAway จะไม่ทำงานหาà¸à¹„ม่เลือà¸à¹„ปยังไฟล์ที่ถูà¸à¸•้อง\n\nต้องà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¹„ฟล์ Symlink? + ไม่พบ Symlink + พื้นที่ไม่เพียงพอ\nลองเปลี่ยนไฟล์โฮสต์ในà¸à¸²à¸£à¸•ั้งค่าไปยัง /data/data/hosts + พื้นที่ไม่เพียงพอ + ไม่สามารถอ่านไฟล์ดาวน์โหลดได้ + ไฟล์ส่วนตัวล้มเหลว + à¸à¸³à¸¥à¸±à¸‡à¹€à¸¡à¹‰à¸²à¸—์พาร์ติชั่นเป็น read/write ล้มเหลว! + เม้าท์ล้มเหลว + คัดลอà¸à¹„ฟล์โฮสต์ล้มเหลว + คัดลอà¸à¹„ฟล์โฮสต์ล้มเหลว + คัดลอà¸à¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§ + ใช้à¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาของโฮสต์à¹à¸¥à¹‰à¸§ + à¸à¸³à¸¥à¸±à¸‡à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹€à¸ªà¸£à¹‡à¸ˆà¸ªà¸´à¹‰à¸™ + สร้าง Symlink เสร็จสิ้น + สร้าง Symlink ล้มเหลว + à¸à¸£à¸¸à¸“าอ่านช่วยเหลือสำหรับข้อมูลเพิ่มเติม + ตั้งพร็อà¸à¸‹à¸µà¹ˆ APN! + à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่ออินเตอร์เน็ตไม่สำเร็จ + ไม่มีà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่อ + à¸à¸³à¸¥à¸±à¸‡à¸”าวน์โหลด… + à¸à¸³à¸¥à¸±à¸‡à¹ƒà¸Šà¹‰à¸‡à¸²à¸™â€¦ + à¸à¸³à¸¥à¸±à¸‡à¹ƒà¸Šà¹‰à¸£à¸²à¸¢à¸à¸²à¸£à¸—ี่ถูà¸à¸«à¹‰à¸²à¸¡à¹à¸¥à¸°à¸£à¸²à¸¢à¸à¸²à¸£à¸—ี่อนุà¸à¸²à¸• + à¸à¸³à¸¥à¸±à¸‡à¹à¸¢à¸à¹à¸¥à¸°à¸£à¸§à¸¡à¹„ฟล์โฮสต์ + à¸à¸³à¸¥à¸±à¸‡à¸ªà¸£à¹‰à¸²à¸‡à¹„ฟล์โฮสต์ + à¸à¸³à¸¥à¸±à¸‡à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹„ฟล์โฮสต์ + นำไฟล์โฮสต์ใหม่ไปใช้ล้มเหลว + ใช้งานไฟล์โฮสต์ไปยังระบบล้มเหลว!\nลองเปลี่ยนไฟล์โฮสต์ในà¸à¸²à¸£à¸•ั้งค่าไปยัง /data/data/hosts + นำไปใช้ล้มเหลว + คืนค่าเสร็จสิ้น + ไม่สามารถคืนค่าได้ + คืนค่าล้มเหลวไม่ทราบเหตุผล + คืนค่าล้มเหลว! + ไม่พบà¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาโฮสต์ที่สามารถเข้าถึงได้! ต้องà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่ออินเตอร์เน็ต? + ดาวน์โหลดไฟล์ล้มเหลว + ไฟล์ส่วนตัวไม่สามารถสร้างได้ + สร้างไฟล์ส่วนตัวล้มเหลว + à¸à¸²à¸£à¹€à¸›à¸´à¸”ใช้งานเสร็จสมบูรณ์ + à¸à¸²à¸£à¸›à¸´à¸”ใช้งานเสร็จสมบูรณ์ + à¸à¸³à¸¥à¸±à¸‡à¹€à¸›à¸´à¸”ใช้งานไฟล์โฮสต์จาà¸à¹‚มดูล Magisk + à¸à¸³à¸¥à¸±à¸‡à¸›à¸´à¸”ใช้งานไฟล์โฮสต์จาà¸à¹‚มดูล Magisk + + ใส่ URL ไปยังไฟล์โฮสต์: + ชื่อโฮสต์ไม่ถูà¸à¸•้อง! + รูปà¹à¸šà¸šà¸Šà¸·à¹ˆà¸­à¹‚ฮสต์ไม่ถูà¸à¸•้อง + IP ไม่ถูà¸à¸•้อง! + รูปà¹à¸šà¸š IP ไม่ถูà¸à¸•้อง + ไม่ต้องรีบูตà¹à¸¥à¸°à¹„ม่à¹à¸ªà¸”งคำถามนี้ครั้งหน้า + à¸à¸³à¸¥à¸±à¸‡à¹‚หลด… + + + รีเฟรช + เพิ่ม + ช่วยเหลือ + นำเข้าข้อมูลสำรอง + ส่งออà¸à¸‚้อมูลสำรอง + + + S-ON/S-OFF + ถาม-ตอบ + ปัà¸à¸«à¸² + + + Adware + à¸à¸³à¸¥à¸±à¸‡à¸ªà¹à¸à¸™â€¦ + ไม่พบ Adware + + + บล็อคโฆษณา + ไม่ได้ติดตั้งตัวà¹à¸à¹‰à¹„ขข้อความ + ไม่พบตัวà¹à¸à¹‰à¹„ขข้อความเพื่อเปิดไฟล์โฮสต์ สามารถติดตั้ง Jota หรือตัวà¹à¸à¹‰à¹„ขข้อความอื่นๆ\n\nต้องà¸à¸²à¸£à¸•ิดตั้ง Jota? + ไม่ได้ติดตั้งตัวจัดà¸à¸²à¸£à¹„ฟล์ + ไม่มีตัวจัดà¸à¸²à¸£à¹„ฟล์เพื่อเปิดไฟล์ คุณสามารถติดตั้งตัวจัดà¸à¸²à¸£à¹„ฟล์ OI หรือตัวจัดà¸à¸²à¸£à¹„ฟล์อื่นๆ\n\nต้องà¸à¸²à¸£à¸•ิดตั้งตัวจัดà¸à¸²à¸£à¹„ฟล์ OI? + + + Tcpdump + Tcpdump เป็นเครื่องมือตรวจสอบคำขอ DNS à¹à¸¥à¸°à¸šà¸±à¸™à¸—ึà¸à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ คุณสามารถเริ่มใช้งานในพื้นหลัง ใช้งานà¹à¸­à¸žà¸¥à¸´à¹€à¸„ชั่นที่à¹à¸ªà¸”งโฆษณาà¹à¸¥à¸°à¸§à¸´à¹€à¸„ราะห์คำขอ DNS โดยใช้บันทึà¸à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹‚ฆษณาสามารถเพิ่มไปยังบัà¸à¸Šà¸µà¸”ำของคุณ + ปิดใช้งานà¸à¸²à¸£à¸•รวจสอบ + เปิดใช้งานà¸à¸²à¸£à¸•รวจสอบ + à¹à¸ªà¸”งผลลัพธ์ + จัดเรียงโดเมน + ล้างบันทึภ+ เพิ่มรายà¸à¸²à¸£à¸¥à¸‡à¹ƒà¸™à¸šà¸±à¸à¸Šà¸µà¸”ำ + เพิ่มรายà¸à¸²à¸£à¹„ปยังบัà¸à¸Šà¸µà¸‚าว + เพิ่มรายà¸à¸²à¸£à¹„ปยังรายà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹€à¸ªà¹‰à¸™à¸—าง + + à¹à¸à¹‰à¹„ขค่าà¸à¸³à¸«à¸™à¸”ของข้อความ + เปิดเมนู + ปิดเมนู + + + + Home + à¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาโฮสต์ + รายà¸à¸²à¸£à¸‚องคุณ + เปิดไฟล์โฮสต์ + Log DNS requests + Scan for adware + à¸à¸²à¸£à¸•ั้งค่า + ช่วยเหลือ + + + + + คำขอ DNS + รายà¸à¸²à¸£à¸‚องคุณ + à¸à¸²à¸£à¸•ั้งค่า + + + ติดตั้งเมื่อ %1$s ที่ผ่านมา + อัพเดทล่าสุดสำหรับ %1$s + ต้องà¸à¸²à¸£à¸­à¸±à¸žà¹€à¸”ทสำหรับ %1$s + ปรับปรุงครั้งล่าสุด %1$s ที่ผ่านมา + สถานะอัพเดทที่ไม่รู้จัภ+ ไม่à¸à¸µà¹ˆà¸™à¸²à¸—ีที่à¹à¸¥à¹‰à¸§ + + %d นาที + + + %d ชั่วโมง + + + %d วัน + + + %d เดือน + + + + à¸à¸³à¸¥à¸±à¸‡à¹€à¸£à¸´à¹ˆà¸¡à¸•้น + à¸à¸³à¸¥à¸±à¸‡à¸—ำงาน + à¸à¸³à¸¥à¸±à¸‡à¸«à¸¢à¸¸à¸” + รอสัà¸à¸à¸²à¸“อินเตอร์เน็ต + à¸à¸³à¸¥à¸±à¸‡à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่ออีà¸à¸„รั้ง + เชื่อมต่อผิดพลาด + หยุดชั่วคราว + หยุด + Ad-blocker VPN %1$s + หยุด + à¹à¸•ะเพื่อดำเนินà¸à¸²à¸£à¸•่อ + + + เปิดใช้งานหรือปิดใช้งานระบบบล็อคโฆษณา + + diff --git a/app/src/main/res/values-th/strings_app.xml b/app/src/main/res/values-th/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-th/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-th/strings_errors.xml b/app/src/main/res/values-th/strings_errors.xml new file mode 100644 index 0000000..fd901b6 --- /dev/null +++ b/app/src/main/res/values-th/strings_errors.xml @@ -0,0 +1,6 @@ + + + + ไม่มีà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่ออินเตอร์เน็ต + พื้นที่ไม่เพียงพอ + \ No newline at end of file diff --git a/app/src/main/res/values-th/strings_home.xml b/app/src/main/res/values-th/strings_home.xml new file mode 100644 index 0000000..497c671 --- /dev/null +++ b/app/src/main/res/values-th/strings_home.xml @@ -0,0 +1,9 @@ + + + + à¸à¸²à¸£à¸•ั้งค่า + + + à¸à¸£à¸¸à¸“าอ่านช่วยเหลือสำหรับข้อมูลเพิ่มเติม + + \ No newline at end of file diff --git a/app/src/main/res/values-th/strings_hosts.xml b/app/src/main/res/values-th/strings_hosts.xml new file mode 100644 index 0000000..5408f42 --- /dev/null +++ b/app/src/main/res/values-th/strings_hosts.xml @@ -0,0 +1,11 @@ + + + à¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาโฮสต์ + + ไม่สามารถใช้งานได้ + + เพิ่มà¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มา + à¹à¸à¹‰à¹„ขà¹à¸«à¸¥à¹ˆà¸‡à¸‚้อมูล + URL: (https:// หรือ file://) + URL à¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาของโฮสต์ + diff --git a/app/src/main/res/values-th/strings_lists.xml b/app/src/main/res/values-th/strings_lists.xml new file mode 100644 index 0000000..0d35c9e --- /dev/null +++ b/app/src/main/res/values-th/strings_lists.xml @@ -0,0 +1,13 @@ + + + รายà¸à¸²à¸£à¸‚องคุณ + + เพิ่มโฮสต์ลงในบัà¸à¸Šà¸µà¸”ำ + เพิ่มโฮสต์ไปยังบัà¸à¸Šà¸µà¸‚าว + เพิ่มà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹€à¸ªà¹‰à¸™à¸—างของโฮสต์ + à¹à¸à¹‰à¹„ขà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹€à¸ªà¹‰à¸™à¸—าง + ชื่อโฮสต์: + URL à¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาของโฮสต์ + (อนุà¸à¸²à¸•ให้ใช้อัà¸à¸‚ระ * à¹à¸¥à¸° ? à¹à¸¥à¹‰à¸§) + IP (IPv4 or IPv6): + diff --git a/app/src/main/res/values-th/strings_log.xml b/app/src/main/res/values-th/strings_log.xml new file mode 100644 index 0000000..6c6c7bd --- /dev/null +++ b/app/src/main/res/values-th/strings_log.xml @@ -0,0 +1,8 @@ + + + + จัดเรียงตามตัวอัà¸à¸©à¸£ + จัดเรียงโดเมนยอดนิยม + + เปลี่ยนเส้นทางโดเมน + diff --git a/app/src/main/res/values-th/strings_notification.xml b/app/src/main/res/values-th/strings_notification.xml new file mode 100644 index 0000000..892ace9 --- /dev/null +++ b/app/src/main/res/values-th/strings_notification.xml @@ -0,0 +1,8 @@ + + + + อัพเดท + สามารถอัพเดตได้ + + VPN + \ No newline at end of file diff --git a/app/src/main/res/values-th/strings_prefs_backup_restore.xml b/app/src/main/res/values-th/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-th/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-th/strings_prefs_main.xml b/app/src/main/res/values-th/strings_prefs_main.xml new file mode 100644 index 0000000..190ce7f --- /dev/null +++ b/app/src/main/res/values-th/strings_prefs_main.xml @@ -0,0 +1,6 @@ + + + à¸à¸²à¸£à¸•ั้งค่า + + ดีบัค + diff --git a/app/src/main/res/values-th/strings_prefs_root.xml b/app/src/main/res/values-th/strings_prefs_root.xml new file mode 100644 index 0000000..1cbb428 --- /dev/null +++ b/app/src/main/res/values-th/strings_prefs_root.xml @@ -0,0 +1,14 @@ + + + เปิดไฟล์โฮสต์ + ไฟล์โฮสต์ + + /system/etc/hosts + /data/hosts + /data/data/hosts + à¸à¸³à¸«à¸™à¸”เอง + + + Redirection + เปิดใช้งานเว็บเซิร์ฟเวอร์ + diff --git a/app/src/main/res/values-th/strings_prefs_update.xml b/app/src/main/res/values-th/strings_prefs_update.xml new file mode 100644 index 0000000..0847d56 --- /dev/null +++ b/app/src/main/res/values-th/strings_prefs_update.xml @@ -0,0 +1,4 @@ + + + อัพเดท + diff --git a/app/src/main/res/values-th/strings_prefs_vpn.xml b/app/src/main/res/values-th/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-th/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-th/strings_support.xml b/app/src/main/res/values-th/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-th/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-th/strings_update.xml b/app/src/main/res/values-th/strings_update.xml new file mode 100644 index 0000000..dee0bc2 --- /dev/null +++ b/app/src/main/res/values-th/strings_update.xml @@ -0,0 +1,4 @@ + + + สามารถอัพเดตได้ + diff --git a/app/src/main/res/values-th/strings_welcome.xml b/app/src/main/res/values-th/strings_welcome.xml new file mode 100644 index 0000000..4c60c6b --- /dev/null +++ b/app/src/main/res/values-th/strings_welcome.xml @@ -0,0 +1,4 @@ + + + จำเป็นต้องรูท + diff --git a/app/src/main/res/values-tl/strings.xml b/app/src/main/res/values-tl/strings.xml new file mode 100644 index 0000000..9e45587 --- /dev/null +++ b/app/src/main/res/values-tl/strings.xml @@ -0,0 +1,14 @@ + + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-tl/strings_app.xml b/app/src/main/res/values-tl/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-tl/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-tl/strings_errors.xml b/app/src/main/res/values-tl/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-tl/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-tl/strings_home.xml b/app/src/main/res/values-tl/strings_home.xml new file mode 100644 index 0000000..fea7956 --- /dev/null +++ b/app/src/main/res/values-tl/strings_home.xml @@ -0,0 +1,16 @@ + + + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-tl/strings_hosts.xml b/app/src/main/res/values-tl/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-tl/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-tl/strings_lists.xml b/app/src/main/res/values-tl/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-tl/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-tl/strings_log.xml b/app/src/main/res/values-tl/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-tl/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-tl/strings_notification.xml b/app/src/main/res/values-tl/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-tl/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-tl/strings_prefs_backup_restore.xml b/app/src/main/res/values-tl/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-tl/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-tl/strings_prefs_main.xml b/app/src/main/res/values-tl/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-tl/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-tl/strings_prefs_root.xml b/app/src/main/res/values-tl/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-tl/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-tl/strings_prefs_update.xml b/app/src/main/res/values-tl/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-tl/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-tl/strings_prefs_vpn.xml b/app/src/main/res/values-tl/strings_prefs_vpn.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-tl/strings_prefs_vpn.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-tl/strings_support.xml b/app/src/main/res/values-tl/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-tl/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-tl/strings_update.xml b/app/src/main/res/values-tl/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-tl/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-tl/strings_welcome.xml b/app/src/main/res/values-tl/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-tl/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml new file mode 100644 index 0000000..2141690 --- /dev/null +++ b/app/src/main/res/values-tr/strings.xml @@ -0,0 +1,262 @@ + + + + Çıkış + Kapat + Evet + Hayır + Ekle + İptal + Kaydet + Yardım + + + HoÅŸgeldiniz! + AdAway, reklamları engellemek için ücretsiz ve açık kaynaklı bir yazılım tasarımdır. Cihazınızda bunları engellemek için reklam ağı adresleri getirir.\nDaha fazlasını öğrenmek ister misiniz? AÅŸağıdaki yardımı kontrol edin! + Daha fazla yardım göster + Güncelleme durumu + Tüm kaynaklardaki host dosyaları indirildi, listenizdekilerle birleÅŸtirildi ve sisteminize tek bir host dosyası olarak yüklendi. + Reklam engellemeyi etkinleÅŸtir + Reklam engellemeyi devre dışı bırak + Web sunucusu + Çalışıyor + Durduruldu + Engellenen ana bilgisayar adlarına yönelik istekleri yanıtlamak için localhost\'ta web sunucusunu baÅŸlat veya durdur. + Web sunucusunu etkinleÅŸtir + Web sunucusunu devre dışı bırak + VPN + Çalışıyor + Durduruldu + İstekleri filtrelemek için VPN\'yi baÅŸlat veya durdur. + VPN\'yi etkinleÅŸtir + VPN\'yi devre dışı bırak + + + Girdiyi Düzenle + Uygula + Düzenle + Sil + + + İçe aktarılıyor… + Yedekleme, harici depolama alanınızdan baÅŸarıyla içe aktarıldı. + Yedekleme içe alınamadı. Dosya biçimi doÄŸru mu? Daha fazla ayrıntı için logcat\'i kontrol edin. + Dışa aktarılıyor… + Yedekleme, harici depolama alanınızdaki \'%s\' dosyasına baÅŸarıyla aktarıldı. + Yedekleme dosyası dışa aktarılamadı \'%s\'. + + + Host dosyası + Sunucu dosyası, sunucu adlarını IP adreslerine eÅŸleyen bir sistem dosyasıdır. Bu yapılandırmanın AdAway tarafından ele alındığı düz bir metin dosyasıdır. İşte ilk birkaç satırı: + Hosts dosyası içeriÄŸi yükleniyor… + Host dosyasını açın + + + Güncellemeler kontrol ediliyor + %s kaynağı güncelleme için denetleniyor + Kaynaklar alınıyor + %s kaynağı indiriliyor + %s kaynağı okunuyor + %s kaynağı ayrıştırılıyor + Kural veritabanı senkronize ediliyor + Varsayılan hosts dosyasına geri dönülüyor + Varsayılan hosts dosyası geri yüklendi + Varsayılan bir hosts dosyası yapılıyor + Güncelleme mevcut + Daha yeni host dosyaları mevcut + Kaynak güncellemesi bulunamadı + İnternet baÄŸlantısı yok + İnternet baÄŸlantısı yok + Kullanılamayan kaynaklar + Hiçbir host kaynağına ulaşılamadı. + Kök eriÅŸimi reddedildi + Kök yönetim uygulaması üstünden kök eriÅŸimine izin verin + Bir ÅŸeyler yanlış gitti + Daha fazla bilgi için logcat\'i kontrol edin + Etkin + Yeni host dosyaları etkin + Devre dışı + Varsayılan sunucu dosyası yüklendi + En son kaynakları uygula + Yeni bir hosts dosyası oluÅŸturuluyor + Yeni bir hosts dosyası kopyalanıyor + Hosts dosya kopyası kontrol ediliyor + Hosts dosyası baÅŸarıyla güncellendi + VPN yapılandırması baÅŸarıyla güncellendi + Yapılandırmanız deÄŸiÅŸti. Uygulamanız gerekiyor. + Uygula + Yeni yapılandırma uygulanıyor… + Yeni yapılandırma uygulanamadı. + + + Hosts dosya hedefine yönelik sembolik baÄŸlantı eksik + Hedefiniz ile /system/etc/hosts dosyası symlink ile baÄŸlanmamış veya hatalı baÄŸlanmış! Bu baÄŸlanma olmadan AdAway çalışamaz.\n\nÅžimdi bir symlink ayarlansın mı? + Symlink kayıp + Disk bölümünde yeterli boÅŸ alan yok!\nTercihlerden hedef hosts dosyası seçeneÄŸini /data/data/hosts yapmayı deneyin. + Yeterli alan yok + İndirilen dosya okunamadı. + Özel dosya baÅŸarısız + Okuma/yazma bölümü tekrar baÄŸlanması baÅŸarısız! + Remount baÅŸarısız oldu + Hosts dosyası kopyalanamadı + Host dosyası kopyalama baÅŸarısız! + Kopyalama baÅŸarısız + Hosts kaynakları uygulandı + Uygulama baÅŸarılı + Uygulama baÅŸarılı oldu.\nDeÄŸiÅŸikliklerin etkili olması için Android\'i yeniden baÅŸlatmanız gerekebilir.\n\nYeniden baÅŸlatmak ister misiniz?\n(Veri kaybını önlemek için hiçbir uygulamanın SD kartı kullanmadığından emin olun!) + Symlink baÅŸarılı bir ÅŸekilde oluÅŸturuldu.\nDeÄŸiÅŸikliklerin etkili olması için Android\'i yeniden baÅŸlatmanız gerekebilir.\n\nYeniden baÅŸlatmak ister misiniz?\n(Veri kaybını önlemek için hiçbir uygulamanın SD kartı kullanmadığından emin olun!) + Symlink oluÅŸturma baÅŸarılı + Symlink Android tarafından oluÅŸturulamadı.\nBu HTC telefonlarında S-ON adlı bir \'özellik\' nedeniyle baÅŸarısız oluyor!\n\nBunun bir çözümü, telefonunuzu kurtarma moduna geçirmek ve orada \'ln -s /data/data/hosts /system/etc/hosts\'\' ile sembolik baÄŸlantı oluÅŸturmaktır.\n\nBu iÅŸe yaramazsa, internette cihazınız ve S-OFF ile ilgili araÅŸtırma yapınız. + Symlink oluÅŸturma baÅŸarısız + Daha fazla bilgi için Yardım\'ı okuyunuz. + Androidinizde bir APN proxy\'si ayarlandı!\n3G gibi Mobil AÄŸlarda AdAway güvenilir bir ÅŸekilde çalışmaz.SeçtiÄŸiniz APN\'ye giderek bu proxy\'yi devre dışı bırakabilirsiniz (Ayarlar uygulamasından: AÄŸ ve İnternet -> Mobil ÅŸebeke -> GeliÅŸmiÅŸ -> EriÅŸim Noktası İsimleri) ve proxy alanındaki deÄŸeri kaldırın. + APN Vekil Sunucu ayarlandı + İnternet baÄŸlantısı çalışmıyor. + BaÄŸlantı Yok + İndiriliyor… + Uygulanıyor… + Kara Liste ve Beyaz Liste uygulanıyor + Host dosyaları incelenip birleÅŸtiriliyor + Host dosyası oluÅŸturuluyor + Host dosyası uygulanıyor + Yeni hosts dosyası uygulanamadı. + Host dosyasının sisteminize uygulanması baÅŸarısız oldu!\nTercihlerden hedef hosts dosyası seçeneÄŸini /data/data/hosts yapmayı deneyin. + Uygulama baÅŸarısız + Kök eriÅŸiminin verildiÄŸinden emin olmak için lütfen kök yönetim uygulamanızı kontrol edin. + Varsayılan host dosyasına geri döndünüz.\nDeÄŸiÅŸikliklerin etkili olması için Android\'i yeniden baÅŸlatmanız gerekebilir.\n\nYeniden baÅŸlatmak ister misiniz??\n(Veri kaybını önlemek için hiçbir uygulamanın SD kartı kullanmadığından emin olun!) + Geri alma baÅŸarılı! + Hosts dosyası geri alınamıyor + Geri alma iÅŸlemi bilinmeyen nedenlerden dolayı baÅŸarısız oldu. + Geri alma baÅŸarısız! + Aktif ettiÄŸiniz hiçbir host kaynağına ulaşılamıyor! İnternet\'e baÄŸlı olduÄŸunuza emin misiniz? + İndirme iÅŸlemi baÅŸarısız. + Yeni özel hosts dosyası yazılamadı + Özel dosya oluÅŸturulamadı. + Özel dosya oluÅŸturma baÅŸarısız oldu. + Sistemsiz modu etkinleÅŸtirdiniz.\nDeÄŸiÅŸikliklerin etkili olması için Android\'i yeniden baÅŸlatmanız gerekebilir.\n\nYeniden baÅŸlatmak ister misiniz?\n(Veri kaybını önlemek için hiçbir uygulamanın SD kartı kullanmadığından emin olun!) + EtkinleÅŸtirme baÅŸarılı + Sistemsiz modu devre dışı bıraktınız.\nDeÄŸiÅŸikliklerin etkili olması için Android\'i yeniden baÅŸlatmanız gerekebilir.\n\nYeniden baÅŸlatmak ister misiniz?\n(Veri kaybını önlemek için hiçbir uygulamanın SD kartı kullanmadığından emin olun!) + BaÅŸarıyla devre dışı bırakıldı + VPN reklam engelleyici etkinleÅŸtirilemedi. + VPN reklam engelleyici devre dışı bırakılamadı. + Hosts Magisk Modülü\'nü etkinleÅŸtiriliyor + Magisk yöneticisinden sistemsiz hosts özelliÄŸini etkinleÅŸtirin. Magisk ayarlarından, sistemsiz hosts seçeneÄŸini etkinleÅŸtirin ve ardından cihazınızı yeniden baÅŸlatın. + Hosts Magisk Modülü\'nü devre dışı bırakılıyor + Magisk yöneticisinden sistemsiz hosts özelliÄŸini devre dışı bırakın. Modül listesinden, sistemsiz hosts modülünü kaldırın ve cihazınızı yeniden baÅŸlatın. + + + Host dosyasına URL gir: + Geçersiz host adı! + Hatalı host adı! + Bu geçerli bir IP deÄŸildir! + Uygunsuz biçimlendirilmiÅŸ IP + Asla yeniden baÅŸlatma ve bir daha ki sefere bu soruyu gösterme! + Yükleniyor… + + + Yenile + Ekle + Yardım + Yedeklemeyi içe aktar + Yedeklemeyi dışa aktar + + + S-ON/S-OFF + SSS + Sorunlar + + + Adware + AdAway tarafından engellenemeyen, adware yüklü kötü uygulamaları burada bulabilirsiniz. Bu uygulamalar, örneÄŸin uygulama çalışmıyorken bile ortaya çıkan Airpush bildirimlerini kullanır ve hatta zil sesini deÄŸiÅŸtirir. Kullanılabilir tek önlem, listedeki öğeleri tıklatarak bu uygulamaları kaldırmaktır. + Taranıyor… + Adware bulunamadı! + + + Reklam engelleyici + Yüklü metin editörü yok + Hosts dosyasını açacak bir metin düzenleyici bulunamadı. Jota veya benzeri bir metin düzenleyici yüklemeniz gerekebilir.\n\nÅžimdi Jota yüklemek ister misiniz? + Yüklü dosya yöneticisi yok + Dosyaları açacak bir dosya yöneticisi bulunamadı. OI File Manager veya benzeri bir dosya yöneticisi yüklemeniz gerekebilir.\n\nÅžimdi OI File Manager yüklemek ister misiniz? + + + Tcpdump + Tcpdump, DNS isteklerini izleyip bir log dosyasına kaydeden bir araçtır. Aracı arkaplanda bırakıp reklam gösteren programı çalıştırdıktan sonra log dosyasından programın DNS isteklerini inceleyebilirsiniz. Böylece olası reklam sunucularını karalisteye ekleyebilirsiniz. + İzlemeyi devre dışı bırak + İzlemeyi etkinleÅŸtir + Sonuçları göster + Alanları sırala + Günlüğü temizle + Kara listeye giriÅŸ ekle + Beyaz listeye giriÅŸ ekle + Yönlendirme listesine giriÅŸ ekle + + Metin tercih deÄŸerini düzenle + Menüyü aç + Menüyü kapat + + + + Ana ekran + Host kaynakları + Listeleriniz + Host dosyasını aç + DNS istekleri günlüğü + Reklam yazılımı tara + Tercihler + Yardım + + + + + DNS istekleri + Listeleriniz + Tercihler + + + %1$s önce kuruldu + %1$s güncel + %1$s için gücelleme gerekiyor + Son güncelleme %1$s önce + Bilinmeyen güncelleme durumu + Devre dışı + birkaç dakika + + %d dakika + %d dakika + + + %d saat + %d saat + + + %d gün + %d gün + + + %d ay + %d ay + + + + Ana bilgisayar panoya kopyalandı + + + baÅŸlatılıyor + etkin + durduruluyor + aÄŸ için bekleniyor + yeniden baÄŸlanıyor + yeniden baÄŸlanma hatası + duraklatıldı + durduruldu + Reklam engelleyici VPN %1$s + Duraklat + Devam et + + + AdAway izinleri + AdAway ile etkileÅŸime izin ver + AdAway\'e komutlar gönder + AdAway\'e sistem çapı reklam engellemeyi kapatma ve açma komutları göndermek için izin ver + + diff --git a/app/src/main/res/values-tr/strings_app.xml b/app/src/main/res/values-tr/strings_app.xml new file mode 100644 index 0000000..80ab180 --- /dev/null +++ b/app/src/main/res/values-tr/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Açık kaynaklı reklam engelleyici + AdAway logo + diff --git a/app/src/main/res/values-tr/strings_errors.xml b/app/src/main/res/values-tr/strings_errors.xml new file mode 100644 index 0000000..8fed934 --- /dev/null +++ b/app/src/main/res/values-tr/strings_errors.xml @@ -0,0 +1,22 @@ + + + + İnternet baÄŸlantısı yok + İnternet baÄŸlantısı kurulamıyor. Lütfen cihaz baÄŸlantınızı kontrol edin. + Hosts kaynağı indirilemedi + Etkin hosts kaynaklarınızın hiçbirine ulaşılamıyor. Lütfen İnternet\'e düzgün ÅŸekilde baÄŸlandığınızı kontrol edin. + + Özel dosya oluÅŸturulamadı + Yeni bir hosts kaynağı inÅŸa etmek için özel dosya oluÅŸturulamıyor. Lütfen cihazınızda kullanılabilir boÅŸ alanı kontrol edin. + Yeterli alan yok + Hosts dosyası sistem bölümünüze kopyalanamıyor. Lütfen Magisk sistemsiz modülünün etkin olup olmadığını kontrol edin ve yeniden baÅŸlatın. + Yeni hosts dosyası yüklenemedi + Hosts dosyası / sistem bölümüne kopyalanamıyor. Lütfen Magisk sistemsiz modülünün yeniden baÅŸlatmanın etkinleÅŸtirildiÄŸini kontrol edin. + Hosts dosyası geri alınamadı + Varsayılan hosts dosya yapılandırması geri yüklenemedi. + + VPN reklam engelleyici etkinleÅŸtirilemedi. + Uygulamaya VPN baÅŸlatma yetkisi vermek için VPN ayarlarınızı kontrol edin. + VPN reklam engelleyici devre dışı bırakılamadı. + El ile devre dışı bırakmak için lütfen VPN ayarlarınızı kontrol edin. + diff --git a/app/src/main/res/values-tr/strings_home.xml b/app/src/main/res/values-tr/strings_home.xml new file mode 100644 index 0000000..941e677 --- /dev/null +++ b/app/src/main/res/values-tr/strings_home.xml @@ -0,0 +1,46 @@ + + + + + EngellenmiÅŸ + İzin verilmiÅŸ + YönlendirilmiÅŸ + + + + %d up-to-date source + %d kaynaklar güncel + + + %d outdated source + %d kaynaklar güncel deÄŸil + + Hosts güncellemelerini kontrol et + Host\'u güncelle + + + DNS istek günlüğünü göster + + + Yardım\ipuçlarını göster + + + GitHub sayfasını aç + + + Projeyi destekle + + + GitHub projesi + Tercihler + + + Gezinme çekmecesini aç + Reklam engellemeyi duraklat/devam ettir + Engellenen alan adlarını güncelle + Alan adlarının isteklerini göster + + + Daha fazla bilgi için Yardım\'ı okuyunuz. + + \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings_hosts.xml b/app/src/main/res/values-tr/strings_hosts.xml new file mode 100644 index 0000000..20a852b --- /dev/null +++ b/app/src/main/res/values-tr/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Host kaynakları + + Kullanıcı listesi + AdAway resmi hosts + StevenBlack BirleÅŸik hosts + Pete Lowe engel listesi hosts + + Uygun deÄŸil + %s hosts + + Kaynak ekle + Kaynak düzenle + URL: (bir https:// veya file:// kaynak) + Hosts kaynak URL\'si + diff --git a/app/src/main/res/values-tr/strings_lists.xml b/app/src/main/res/values-tr/strings_lists.xml new file mode 100644 index 0000000..6d2945f --- /dev/null +++ b/app/src/main/res/values-tr/strings_lists.xml @@ -0,0 +1,24 @@ + + + Listeleriniz + Engelli adres listesi ekle + + EngellenmiÅŸ + İzin verilmiÅŸ + YönlendirilmiÅŸ + + Hosts filtresi + Ana bilgisayar adında ara… + Kaynakları aç/kapat + + Kara listeye host ekle + Beyaz listeye host ekle + Host yönlendirmesi ekle + Kara listeye alınan sunucuyu düzenle + Beyaz listeye alınan sunucuyu düzenle + Yönlendirmeyi düzenle + Ana bilgisayar adı: + Hosts kaynak URL\'si + (Joker karakterler * ve ? izin verilir) + IP (IPv4 veya IPv6): + diff --git a/app/src/main/res/values-tr/strings_log.xml b/app/src/main/res/values-tr/strings_log.xml new file mode 100644 index 0000000..a990818 --- /dev/null +++ b/app/src/main/res/values-tr/strings_log.xml @@ -0,0 +1,11 @@ + + + Günlük kaydını aç/kapat + İstekleri günlüğe kaydetmeye baÅŸlamak, Web\'de gezinmek veya uygulamaları kullanmak için kaydet\'e basın, ardından geri dönün veya günlükleri yenilemek için kaydırın. + \n\nEngellenen istekler günlüğe kaydedilmez. Onları da günlüğe kaydetmek istiyorsanız, önce reklam engellemeyi devre dışı bırakın. + + Alfabetik sıralama + Üst düzey alan adı sıralaması + + Alanadı yönlendir + diff --git a/app/src/main/res/values-tr/strings_notification.xml b/app/src/main/res/values-tr/strings_notification.xml new file mode 100644 index 0000000..2f1fcae --- /dev/null +++ b/app/src/main/res/values-tr/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Güncellemeler + Yeni güncelleme bildirimleri + Güncelleme mevcut + İndirilebilecek yeni hosts dosyaları. + Uygulama güncellemesi mevcut + AdAway\'in yeni bir sürümü indirilebilir. + + VPN + VPN çalışma bildirimleri + \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings_prefs_backup_restore.xml b/app/src/main/res/values-tr/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..256b609 --- /dev/null +++ b/app/src/main/res/values-tr/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Yedekle ve geri yükle + Yedekle + Engelleme kurallarını harici depolamaya yedekle + Geri yükle + Engelleme kurallarını yedekleme dosyasından geri yükle + diff --git a/app/src/main/res/values-tr/strings_prefs_main.xml b/app/src/main/res/values-tr/strings_prefs_main.xml new file mode 100644 index 0000000..eac5f3f --- /dev/null +++ b/app/src/main/res/values-tr/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Tercihler + + Genel + Karanlık temayı etkinleÅŸtir + + Açık + Koyu + Sistem varsayılanı + + Otomatik güncellemeler + + Reklam engelle + Kök eriÅŸimi tabanlı reklam engelleyici + VPN tabanlı reklam engelleyici + IPv6 etkinleÅŸtir + Engelleme kurallarını yedekle/geri yükle + + Hata ayıklama + Kilitlenme raporlarını etkinleÅŸtir + Uygulamanın Sentry\'ye (sentry.io) hata ve kilitlenme raporları göndermesine izin verin. + Bu derlemede desteklenmiyor + Ayrıntılı günlük kaydını etkinleÅŸtir + Ayarları etkinleÅŸtirmek için AdAway\'ı yeniden baÅŸlatın. + diff --git a/app/src/main/res/values-tr/strings_prefs_root.xml b/app/src/main/res/values-tr/strings_prefs_root.xml new file mode 100644 index 0000000..14f7ff2 --- /dev/null +++ b/app/src/main/res/values-tr/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Kök eriÅŸimi tabanlı reklam engelleyici + + Hosts kurulumu + Host dosyasını aç + Hedef hosts dosyası + Bu özelliÄŸi kullanmadan önce Yardımı okuyun + + /system/etc/hosts + /data/hosts + /data/data/hosts + Özel hedef + + Özel hedef konumu + Uyguladıktan sonra yeniden baÅŸlatma iletiÅŸim kutusunu gizle + + Yönlendirme + Engellenen hosts\'u nereye yönlendireceÄŸinizi tanımlayın + IPv4 yönlendirmesi + IPv6 yönlendirmesi + Geçersiz yönlendirme + + Yerel web sunucu + Yerel web sunucusu, engellenen ana bilgisayar adı isteklerine yanıt vermek için yerel IP adreslerini dinler. Engellenen baÄŸlantıda uygulamanın donmasına yardımcı olabilir. + Web sunucusunu etkinleÅŸtir + Web sunucusunu test et + Kendinden imzalı sertifika kur + Manuel sertifika kurulumu + Android 11 (R)\'den baÅŸlatılan uygulama artık otomatik olarak doÄŸrulama sertifikası (CA) yükleyemez. Bunun için: \"Güvenlik\" ayarlarına gidin. \"Åžifreleme & kimlikleri\"ni seçin daha sonra \"Bir sertifika yükle\"yi seçin. Oradan da, \"CA sertifikası\"nı seçin ve yeni dışa aktarılmış sertifika dosyanızı seçin. + \"Güvenlik\" ayarlarını açın + Kontrol ediliyor… + Çalışmıyor + Çalışıyor ancak sertifika kurulu deÄŸil + Çalışıyor ve sertifika kurulu + BoÅŸ reklam alanını uygulama simgesiyle deÄŸiÅŸtir + diff --git a/app/src/main/res/values-tr/strings_prefs_update.xml b/app/src/main/res/values-tr/strings_prefs_update.xml new file mode 100644 index 0000000..f6b4113 --- /dev/null +++ b/app/src/main/res/values-tr/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Güncellemeler + Bildirimler devre dışı bırakıldı + Uygulama bildirimleri gösterilmeyecek. EtkinleÅŸtirmek için dokunun. + + Uygulama güncellemeleri + BaÅŸlangıçta güncellemeleri kontrol et + Güncellemeleri günlük denetle + Beta sürümleri de dahil + + Hosts güncellemeleri + BaÅŸlangıçta güncellemeleri kontrol et + Güncellemeleri günlük denetle + Güncellemede eÅŸitle + Yalnızca ölçülmemiÅŸ aÄŸda eÅŸitle + diff --git a/app/src/main/res/values-tr/strings_prefs_vpn.xml b/app/src/main/res/values-tr/strings_prefs_vpn.xml new file mode 100644 index 0000000..db64204 --- /dev/null +++ b/app/src/main/res/values-tr/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN tabanlı reklam engelleyici + + BaÅŸlangıçta etkinleÅŸtir + Ekran baÄŸlantısı + VPN baÄŸlantısı bulunmadığı durumlarda düzenli olarak VPN baÄŸlantısının tekrar saÄŸlanabilmesi için baÄŸlantıyı kontrol et + + Hariç tutulan uygulamalar + Hangi uygulamaların VPN\'yi kullanmaması gerektiÄŸini yapılandırın, böylece baÄŸlantı engellenmez. + Sistem uygulamalarını hariç tut + + Yok + Tarayıcılar hariç tümü + Tümü + + Kullanıcı uygulamalarını hariç tut + + + Hariç tutulan uygulamalar + Tümünü seç + Tüm seçimleri kaldır + Uygulama simgesi + diff --git a/app/src/main/res/values-tr/strings_source_edit.xml b/app/src/main/res/values-tr/strings_source_edit.xml new file mode 100644 index 0000000..8c24910 --- /dev/null +++ b/app/src/main/res/values-tr/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Kaynak düzenle + Kaynak ekle + + Etiket + Etiket gerekli + Tür + URL + Dosya + Konum + https:// + Yer gerekli + Kaynak dosya seçmek için Dosya\'ya tıklayın + Geçersiz konum + Liste Formatı + Engelle + İzin ver + YönlendirilmiÅŸ hosts\'u uygula + YönlendirilmiÅŸ hosts\'a izin vermek güvenlik sorunu oluÅŸturabilir. Yalnızca güvendiÄŸiniz kaynaklar ile kullanınız. Aksi durumda hassas bilgileriniz farklı kaynaklara yönlendirilebilir. + diff --git a/app/src/main/res/values-tr/strings_support.xml b/app/src/main/res/values-tr/strings_support.xml new file mode 100644 index 0000000..42aa69e --- /dev/null +++ b/app/src/main/res/values-tr/strings_support.xml @@ -0,0 +1,5 @@ + + + Destek + Sponsor ol + \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings_update.xml b/app/src/main/res/values-tr/strings_update.xml new file mode 100644 index 0000000..c392c21 --- /dev/null +++ b/app/src/main/res/values-tr/strings_update.xml @@ -0,0 +1,21 @@ + + + AdAway güncellemesi + + Güncelleme mevcut! + + + Güncel + Güncelleme mevcut + AdAway güncelleÅŸtiriliyor + Åžimdi güncelle + %1$s / %2$s + Son deÄŸiÅŸiklikler + DeÄŸiÅŸiklikler + GeliÅŸtirmeyi destekleyin + Bağışta bulunun + Sponsor + + + AdAway\'in en son sürümü indiriliyor… + diff --git a/app/src/main/res/values-tr/strings_welcome.xml b/app/src/main/res/values-tr/strings_welcome.xml new file mode 100644 index 0000000..b47bfbd --- /dev/null +++ b/app/src/main/res/values-tr/strings_welcome.xml @@ -0,0 +1,53 @@ + + + HoÅŸgeldiniz + Kurulumun ilk aÅŸaması + Kurulumun ikinci aÅŸaması + Kurulumun son aÅŸaması + + + AdAway\'e hoÅŸ geldiniz! + AdAway iki reklam engelleme yöntemi sunar. BeÄŸendiÄŸiniz birini seçin: + + Kök eriÅŸimi logosu + Kök eriÅŸimi tabanlı\nreklam engelleyici + Daha hızlı + Pil dostu + Kök eriÅŸimi gerekli + + VPN logosu + VPN tabanlı\nreklam engelleyici + Daha yavaÅŸ + Arka planda çalıştır + Uyumluluk + + Kök eriÅŸimli Android gerekli + Su binary dosyası bulunamadı veya AdAway için kök eriÅŸimi izni saÄŸlanmadı.\n\nEÄŸer cihazınızda kök eriÅŸimi saÄŸlanmadıysa bu yaÅŸanabilir. Ayrıntılı bilgi ve cihazınızda nasıl kök eriÅŸimi saÄŸlanacağını öğrenmek için wiki.lineageos.org veya diÄŸer Android web sitelerini ziyaret edebilirsiniz. + + Pro + Con + + + EÅŸitleme tamamlandı + EÅŸitleme sırasında hata + + EÅŸitleniyor + EÅŸitlendi! + AdAway, çevrimiçi kaynaklardan engellemek için reklam aÄŸlarını indirir. Bunları daha sonra ayarlardan özelleÅŸtirebilirsiniz. + EÅŸitlemeyi tekrar dene + %1$ssenkronize edilemedi. Tekrar denensin mi? + Reklam bloÄŸu durumunu ve kontrolünü görüntülemek ve mevcut uygulama güncellemesi hakkında bilgi vermek için (yılda birkaç kez) bildirimler gönderebilir. Güncel kalmak istiyorsanız bunları etkinleÅŸtirin. + + + Destek + Beni destekle! + AdAway, boÅŸ zamanlarımda geliÅŸtirdiÄŸim ücretsiz ve açık kaynaklı bir uygulamadır. BeÄŸendiyseniz, desteÄŸinizi göstermekten çekinmeyin: + PayPal\'da bağış yapın + Hataları sever misin? Ben de sevmem. + Bana kilitlenme raporları göndermek için metriÄŸi etkinleÅŸtir + + + Geri + İleri + Tamamlandı + diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml new file mode 100644 index 0000000..6750500 --- /dev/null +++ b/app/src/main/res/values-uk/strings.xml @@ -0,0 +1,270 @@ + + + + Вийти + Закрити + Так + ÐÑ– + Додати + СкаÑувати + Зберегти + Довідка + + + Вітаємо! + AdAway — це безкоштовний заÑтоÑунок з відкритим вихідним кодом, Ñтворений Ð´Ð»Ñ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¸. Він збирає адреÑи з рекламної мережі Ñ– блокує Ñ—Ñ… на вашому приÑтрої.\nХочете дізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ? Прочитайте довідку нижче. + Розширена довідка + Оновити ÑÑ‚Ð°Ñ‚ÑƒÑ + Ð’ÑÑ– файли хоÑтів, що завантажуютьÑÑ Ð· заданих джерел, об\'єднуютьÑÑ Ð· вашими ÑпиÑками Ñ– вÑтановлюютьÑÑ Ñƒ вашій ÑиÑтемі у виглÑді одного файлу hosts. + Увімкнути Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ + Вимкнути Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ + Веб-Ñервер + Працює + Зупинено + ЗапуÑтити або зупинити веб-Ñервер на локальній машині, Ñкий буде відповідати на запити до заблокованих хоÑтів. + Увімкнути веб-Ñервер + Вимкнути веб-Ñервер + VPN + Запущено + Зупинено + ЗапуÑтити чи зупинити VPN, Ñкий фільтруватиме запити. + Увімкнути VPN + Вимкнути VPN + + + Редагувати Ð·Ð°Ð¿Ð¸Ñ + ЗаÑтоÑувати + Редагувати + Видалити + + + ІмпортуваннÑ… + Резервну копію уÑпішно імпортовано із зовнішнього Ñховища. + Ðе вдалоÑÑ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ñ‚Ð¸ резервну копію. Можливо формат не вірний. Перевірте logcat Ð´Ð»Ñ Ð·\'ÑÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð¸Ñ†ÑŒ. + ЕкÑпортуваннÑ… + Резервну копію уÑпішно екÑпортовано в файл \'%s\' на зовнішнє Ñховище. + Ðе вдалоÑÑ ÐµÐºÑпортувати резервну копію в файл \'%s\'. + + + Файл hosts + Файл hosts — це ÑиÑтемний файл, Ñкий міÑтить ÑпівÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ñ–Ð¼ÐµÐ½ хоÑтів з IP-адреÑами. Це звичайний текÑтовий файл, вміÑÑ‚ Ñкого оброблÑÑ” AdAway. ОÑÑŒ його перші Ñ€Ñдки: + Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ð¼Ñ–Ñту файлу hosts… + Відкрити файл hosts + + + Перевірка оновлень + Перевірка джерела %s на наÑвніÑть оновлень + ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¶ÐµÑ€ÐµÐ» + Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð´Ð¶ÐµÑ€ÐµÐ»Ð° %s + Ð§Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð´Ð¶ÐµÑ€ÐµÐ»Ð° %s + Обробка джерела %s + Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð±Ð°Ð·Ð¸ даних з правилами + ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ ÑƒÑталеного файлу hosts + УÑталений файл hosts відновлено + Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñтандартного файлу hosts + ДоÑтупне Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + ДоÑтупні Ñвіжі ÑпиÑки хоÑтів + Ðе знайдено оновлень + Ðемає з\'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· Інтернет + Ðемає доÑтупного Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð´Ð¾ інтернету + ÐедоÑтупні джерела + Ðемає доÑтупних джерел хоÑтів! + ДоÑтуп ÑуперкориÑтувача відхилено + Ðадати права ÑуперкориÑтувача Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ додатку ÑуперкориÑтувача + ЩоÑÑŒ пішло не так + ПереглÑньте logcat Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð¸Ñ†ÑŒ + Увімкнено + ВикориÑтовуютьÑÑ Ð½Ð°Ð¹Ð½Ð¾Ð²Ñ–ÑˆÑ– ÑпиÑки + Вимкнено + Ð’Ñтановлено Ñтандартний файл hosts + ЗаÑтоÑувати оÑтанні джерела + Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ файлу hosts + ÐšÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ файлу hosts + Перевірка копії файлу hosts + Файл hosts уÑпішно оновлено + ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ VPN уÑпішно оновлено + ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð¼Ñ–Ð½ÐµÐ½Ð¾. Потрібно Ñ—Ñ… заÑтоÑувати. + ЗаÑтоÑувати + ЗаÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¸Ñ… налаштувань… + Ðе вдалоÑÑ Ð·Ð°ÑтоÑувати нові налаштуваннÑ. + + + ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° файл hosts відÑутнє + ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° ваш /system/etc/hosts неправильне або не Ñ–Ñнує! AdAway не працюватиме, Ñкщо не вказати правильний файл.\n\n Чи ви хочете Ñпробувати Ñтворити поÑиланнÑ? + ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ñутнє + Ðе виÑтачає міÑÑ†Ñ Ð½Ð° розділі!\nСпробуйте змінити в налаштуваннÑÑ… шлÑÑ… до файлу hosts на /data/data/hosts. + Ðе доÑтатньо міÑÑ†Ñ + Завантажений файл неможливо прочитати. + Збій файлу + Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ñ‚Ð¸ розділ Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ/запиÑу! + Перемонтувати не вдалоÑÑ + Ðе вдалоÑÑ Ñкопіювати файл hosts + ÐšÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ hosts не вдалоÑÑ! + ÐšÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ð½Ð½Ñ Ð½Ðµ вдалоÑÑ + ЗаÑтоÑовані джерела хоÑтів + УÑпішно заÑтоÑовано + ЗаÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð¹ÑˆÐ»Ð¾ уÑпішно.\nÐеобхідно перезавантажити приÑтрій, щоб зміни набули чинноÑті.\n\nПерезавантажити зараз? \n(Щоб уникнути втрати інформації, переконайтеÑÑ, що ніÑкі програми в даний момент не викориÑтовують карту пам\'Ñті!) + ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ñтворено уÑпішно.\nÐеобхідно перезавантажити приÑтрій, щоб зміни набули чинноÑті.\n\nПерезавантажити зараз?\n (Щоб уникнути втрати інформації, переконайтеÑÑ, що ніÑкі програми в даний момент не викориÑтовують карту пам\'Ñті!) + ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ñтворено уÑпішно + Android не зміг Ñтворити поÑиланнÑ. \nМожливо, це через оÑобливіÑть S-ON на телефонах HTC! \n\nÐ Ñ–ÑˆÐµÐ½Ð½Ñ Ð¿Ð¾Ð»Ñгає в завантаженні телефону в режимі Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ– ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñимволічного поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ñ‡ÐµÑ€ÐµÐ· \'\'ln -s /data/data/hosts /system/etc/hosts\'.\n\n Якщо це не Ñпрацьовує, то необхідно шукати інформацію в інтернеті по S-OFF Ñ– вашому телефону. + Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð¾ÑÐ¸Ð»Ð°Ð½Ð½Ñ + Будь лаÑка, читайте Довідку Ð´Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ñ— інформації. + У налаштуваннÑÑ… APN вказаний прокÑÑ– Ñервер!\nAdAway не буде працювати в мобільних мережах, таких Ñк 3G. Ви можете вимкнути цей прокÑÑ– Ñервер в налаштуваннÑÑ… викориÑтовуваної APN (в Android 4: Бездротові мережі -> Більше … -> Мобільна мережа -> Точки доÑтупу APN) Ñ– вилучити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñƒ полі прокÑÑ–. + У викориÑтовуваної точки доÑтупу APN вÑтановлений прокÑÑ–! + ВідÑутнє Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð´Ð¾ мережі інтернет. + Ðемає з\'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ + ЗавантаженнÑ… + ЗаÑтоÑуваннÑ… + ЗаÑтоÑувати чорний Ñ– білий ÑпиÑок + Ðналіз Ñ– об\'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð² зі ÑпиÑками хоÑтів + Побудова файлу hosts + ЗаÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ hosts + Ðе вдалоÑÑ Ð·Ð°ÑтоÑувати новий файл hosts. + Ðе вдалоÑÑ Ð·Ð°ÑтоÑувати файл hosts на вашій ÑиÑтемі!\n Спробуйте змінити в налаштуваннÑÑ… шлÑÑ… до файлу hosts на /data/data/hosts. + Ðе вдалоÑÑ Ð·Ð°ÑтоÑувати + Будь лаÑка, перевірте ваш заÑтоÑунок, Ñкий керує правами ÑуперкориÑтувача, щоб переконатиÑÑ, що права ÑуперкориÑтувача було надано. + Ви повернулиÑÑ Ð´Ð¾ уÑталеного файлу hosts.\nМожливо, знадобитьÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ Android, щоб зміни набули чинноÑті.\n\nХочете перезавантажити?\n(Щоб уникнути втрати даних, переконайтеÑÑ, що жоден заÑтоÑунок не викориÑтовуює карту пам\'Ñті цієї миті!) + УÑпішно повернуто + Ðе вдалоÑÑ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ файл hosts + Ð’Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½Ðµ вдалоÑÑ Ð· невідомих причин. + Ð’Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½Ðµ вдалоÑÑ! + Жодне з ваших активних джерел хоÑтів недоÑтупне! Ви правильно підключені до інтернету? + Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð½Ðµ вдалоÑÑ + Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати новий приватний файл hosts + ОÑобиÑтий файл не може бути Ñтворений. + Ðе вдалоÑÑ Ñтворити оÑобиÑтий файл + Ви увімкнули безÑиÑтемний режим.\nЩоб зміни набули чинноÑті, необхідно перезавантажити Android.\n\nПерезавантажити зараз?\n(Щоб уникнути втрати даних, переконайтеÑÑ, що жоден заÑтоÑунок не викориÑтовуює карту пам\'Ñті цієї миті!) + УÑпішно увімкнено + Ви вимкнули безÑиÑтемний режим.\nЩоб зміни набули чинноÑті, необхідно перезавантажити Android.\n\nПерезавантажити зараз?\n(Щоб уникнути втрати даних, переконайтеÑÑ, що жоден заÑтоÑунок не викориÑтовуює карту пам\'Ñті цієї миті!) + УÑпішно вимкнено + Ðе вдалоÑÑ ÑƒÐ²Ñ–Ð¼ÐºÐ½ÑƒÑ‚Ð¸ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ VPN. + Ðе вдалоÑÑ Ð²Ð¸Ð¼ÐºÐ½ÑƒÑ‚Ð¸ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ VPN. + Ð’Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ Ñ…Ð¾Ñтів Magisk + Увімкнути позаÑиÑтемні хоÑти в Magisk Manager. Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ потрібно вибрати опцію ПозаÑиÑтемні хоÑти Ñ– перезавантажити приÑтрій. + Ð’Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ Ñ…Ð¾Ñтів Magisk + Вимкнути позаÑиÑтемні хоÑти в Magisk Manager. Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ потрібно зі ÑпиÑку модулів видалити модуль Systemless Hosts Ñ– перезавантажити приÑтрій. + + + Ð’Ñтавте URL у файл hosts: + Це недопуÑтима назва джерела! + Ðеправильно відформатована назва хоÑта + Це недопуÑтима IP! + Ðеправильно відформатована IP-адреÑа + Ðіколи не перезавантажувати Ñ– більше не показувати це питаннÑ! + ЗавантаженнÑ… + + + Оновити + Додати + Довідка + Імпортувати резервну копію + ЕкÑпортувати резервну копію + + + S-ON/S-OFF + ЧаПи + Проблеми + + + Додатки з рекламою + Тут ви можете знайти вÑтановлені додатки з рекламою, так звані Adware – погані додатки, Ñкі AdAway не може заблокувати. Вони викориÑтовують ÑиÑтему Ñповіщень Airpush, Ñка показує рекламу навіть тоді, коли заÑтоÑунок не працює Ñ– навіть можуть змінити мелодію вашого дзвінка. ПозбутиÑÑ Ñ‚Ð°ÐºÐ¾Ñ— реклами можливо лише видаливши такі заÑтоÑунки, натиÑнувши на них в цьому ÑпиÑку. + СкануваннÑ… + Додатків з рекламою не знайдено! + + + Блокувальник реклами + Ðе вÑтановлено текÑтовий редактор + У ÑиÑтемі не знайдено текÑтовий редактор Ð´Ð»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñ„Ð°Ð¹Ð»Ñƒ hosts. Ви можете вÑтановити редактор Jota або будь-Ñкий інший текÑтовий редактор, щоб це виправити.\n\nХочете вÑтановити редактор Jota? + Ðе вÑтановлено файловий менеджер + У ÑиÑтемі не знайдено файловий менеджер. Ви можете вÑтановити OI File Manager або будь-Ñкий інший файловий менеджер щоб це виправити.\n\nХочете вÑтановити OI File Manager? + + + Tcpdump + Tcpdump — це інÑтрумент Ð´Ð»Ñ Ð¼Ð¾Ð½Ñ–Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ñƒ запитів DNS Ñ– Ñ—Ñ… Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð² файлі журналу. Ви можете запуÑтити його в фоновому режимі, далі запуÑтити програму, Ñка показує рекламу на екрані, Ñ– проаналізувати збережені в журналі запити DNS. ХоÑÑ‚, кваліфікований Ñк джерело реклами, може бути внеÑений у чорний ÑпиÑок. + Вимк. моніторинг + Увімк. моніторинг + Показати результати + Сортувати домени + ОчиÑтити журнал + Додати Ð·Ð°Ð¿Ð¸Ñ Ð² Чорний ÑпиÑок + Додати Ð·Ð°Ð¿Ð¸Ñ Ð² Білий ÑпиÑок + Додати Ð·Ð°Ð¿Ð¸Ñ Ð² СпиÑок перенаправлень + + Змінити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÐºÑтової переваги + Відкрити меню + Закрити меню + + + + Ð”Ð¾Ð¼Ð°ÑˆÐ½Ñ + Джерела ÑпиÑків хоÑтів + Ваші ÑпиÑки + Відкрити файл хоÑтів + Журнал запритів DNS + Ð¡ÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Adware + ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ + Довідка + + + + + DNS запити + Ваші ÑпиÑки + ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ + + + Ð’Ñтановлено %1$s тому + Ðктуально %1$s + Потрібне Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ %1$s + ОÑтаннє Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ %1$s тому + Ðевідомий ÑÑ‚Ð°Ñ‚ÑƒÑ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + Вимкнено + пару хвилин + + %d хвилина + %d хвилини + %d хвилин + %d хвилин + + + %d година + %d години + %d годин + %d годин + + + %d день + %d дні + %d днів + %d днів + + + %d міÑÑць + %d міÑÑÑ†Ñ + %d міÑÑців + %d міÑÑців + + + + ХоÑÑ‚ Ñкопійований до буферу обміну + + + запуÑк + активний + Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ + Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¼ÐµÑ€ÐµÐ¶Ñ– + перез\'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ + помилка перез\'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ + пауза + зупинено + Ad-blocker VPN%1$s + Пауза + Відновити + + + Дозволи AdAway + Дозволити взаємодію з AdAway + ÐадіÑлати команди в AdAway + Дозволити надÑилати команди AdAway, наприклад увімкнути або вимкнути загальноÑиÑтемне Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¸ + + diff --git a/app/src/main/res/values-uk/strings_app.xml b/app/src/main/res/values-uk/strings_app.xml new file mode 100644 index 0000000..add121f --- /dev/null +++ b/app/src/main/res/values-uk/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Блокувальник реклами з відкритим вихідним кодом + Логотип AdAway + diff --git a/app/src/main/res/values-uk/strings_errors.xml b/app/src/main/res/values-uk/strings_errors.xml new file mode 100644 index 0000000..16e8b5f --- /dev/null +++ b/app/src/main/res/values-uk/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Ðемає з\'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· Інтернет + Ðе вдалоÑÑ Ð·\'єднатиÑÑ Ð· Інтернетом. Перевірте Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð½Ð° вашому приÑтої. + Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ джерело хоÑтів + Жоден з увімкнених джерел хоÑтів недоÑтупний. Перевірте, чи Ñ” з\'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· Інтернетом. + + Ðе вдалоÑÑ Ñтворити приватний файл + Ðе вдалоÑÑ Ñтворити приватний файл, щоб Ñформувати джерело хоÑтів. Перевірте, чи Ñ” вільне міÑце на вашому приÑтрої. + Ðе доÑтатньо міÑÑ†Ñ + Ðе вдалоÑÑ Ñкопіювати файл hosts на ÑиÑтемний розділ. Перевірте в заÑтоÑунку Magisk Manager, чи увімкнено модуль позаÑиÑтемних хоÑтів, Ñ– потім перезавантажте приÑтрій. + Ðе вдалоÑÑ Ð²Ñтановити файл hosts + Ðеможливо Ñкопіювати файл hosts в розділ /system. Перевірте, чи ввімкнено systemless модуль Magisk, а потім перезавантажте. + Ðе вдалоÑÑ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ файл hosts + Ðе вдалоÑÑ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ уÑталену конфігурацію файла hosts. + + Ðе вдалоÑÑ ÑƒÐ²Ñ–Ð¼ÐºÐ½ÑƒÑ‚Ð¸ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ VPN. + Щоб розпочати, авторизуйте заÑтоÑунок Ð´Ð»Ñ VPN в ÑиÑтемних налаштуваннÑÑ… VPN. + Ðе вдалоÑÑ Ð²Ð¸Ð¼ÐºÐ½ÑƒÑ‚Ð¸ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ VPN. + Ð’ налаштуваннÑÑ… VPN його можна вимкнути вручну. + diff --git a/app/src/main/res/values-uk/strings_home.xml b/app/src/main/res/values-uk/strings_home.xml new file mode 100644 index 0000000..4424fb0 --- /dev/null +++ b/app/src/main/res/values-uk/strings_home.xml @@ -0,0 +1,50 @@ + + + + + Заблоковано + Дозволено + Перенаправлено + + + + %d оновлене джерело + %d оновлених джерела + %d оновлених джерел + %d оновлених джерел + + + %d заÑтаріле джерело + %d заÑтарілих джерела + %d заÑтарілих джерел + %d заÑтарілих джерел + + Перевірити Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ…Ð¾Ñтів + Оновити хоÑти + + + Показати журнал DNS запитів + + + Показати підказки + + + Відкрити Ñторінку GitHub + + + Підтримати проєкт + + + Проєкт на GitHub + ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ + + + Відкрити навігаційне меню + Зупинити/продовжити Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¸ + Оновити заблоковані домени + Показати запитувані домени + + + Будь лаÑка, читайте Довідку Ð´Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ñ— інформації. + + \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings_hosts.xml b/app/src/main/res/values-uk/strings_hosts.xml new file mode 100644 index 0000000..666a14b --- /dev/null +++ b/app/src/main/res/values-uk/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Джерела ÑпиÑків хоÑтів + + СпиÑок кориÑтувача + Офіційні хоÑти AdAway + ХоÑти від StevenBlack + ХоÑти від Pete Lowe + + недоÑтупно + %s хоÑтів + + Додати джерело + Редагувати джерело + URL: (реÑÑƒÑ€Ñ https:// або file://) + URL джерела хоÑтів + diff --git a/app/src/main/res/values-uk/strings_lists.xml b/app/src/main/res/values-uk/strings_lists.xml new file mode 100644 index 0000000..72d0685 --- /dev/null +++ b/app/src/main/res/values-uk/strings_lists.xml @@ -0,0 +1,24 @@ + + + Ваші ÑпиÑки + Додати хоÑÑ‚ + + Заблоковано + Дозволено + Перенаправлено + + Фільтрувати хоÑти + Пошук ім\'Ñ Ñервера… + Переключити джерела + + Додати хоÑÑ‚ в Чорний ÑпиÑок + Додати хоÑÑ‚ в Білий ÑпиÑок + Додати Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ñ…Ð¾Ñта + Редагувати хоÑÑ‚ з Чорного ÑпиÑку + Редагувати хоÑÑ‚ з Білого ÑпиÑку + Редагувати Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ + Ім\'Ñ Ð´Ð¶ÐµÑ€ÐµÐ»Ð°: + URL джерела хоÑтів + (ДопуÑкають Ñимволи підÑтановки * та ?) + IP (IPv4 або IPv6): + diff --git a/app/src/main/res/values-uk/strings_log.xml b/app/src/main/res/values-uk/strings_log.xml new file mode 100644 index 0000000..8860fd9 --- /dev/null +++ b/app/src/main/res/values-uk/strings_log.xml @@ -0,0 +1,11 @@ + + + Перемкнути Ð·Ð°Ð¿Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ñƒ + ÐатиÑніть «ЗапиÑ», щоб почати реєÑтрувати запити, переглÑдайте веб-Ñторінки або викориÑтовуйте програми, а потім повернітьÑÑ Ð½Ð°Ð·Ð°Ð´ або проведіть пальцем, щоб оновити журнали. + Заблоковані запити не будуть реєÑтруватиÑÑ. Спочатку вимкніть Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¸, Ñкщо ви також хочете зареєÑтрувати Ñ—Ñ…. + + Ð¡Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° алфавітом + Ð¡Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° найвищим рівнем домену + + Перенаправити домен + diff --git a/app/src/main/res/values-uk/strings_notification.xml b/app/src/main/res/values-uk/strings_notification.xml new file mode 100644 index 0000000..64d3924 --- /dev/null +++ b/app/src/main/res/values-uk/strings_notification.xml @@ -0,0 +1,13 @@ + + + + ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ нові Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + ДоÑтупне Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + Ðові файли hosts доÑтупні Ð´Ð»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ. + ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÑƒ вже доÑтупно + Ðова верÑÑ–Ñ AdAway доÑтупна Ð´Ð»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ. + + VPN + Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ VPN + \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings_prefs_backup_restore.xml b/app/src/main/res/values-uk/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..0be675a --- /dev/null +++ b/app/src/main/res/values-uk/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Ð—Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ñ– Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + Ð—Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ + Ð—Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð° зовнішнє Ñховище + Ð’Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + Відновити правила Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ñ– збереженої копії + diff --git a/app/src/main/res/values-uk/strings_prefs_main.xml b/app/src/main/res/values-uk/strings_prefs_main.xml new file mode 100644 index 0000000..0cf080d --- /dev/null +++ b/app/src/main/res/values-uk/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ + + Загальні + Темна тема + + Світла + Темна + СиÑтемна + + Ðвтоматичні Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + + Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¸ + Блокувальник реклами з root-правами + Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð° оÑнові VPN + Увімкнути підтримку IPv6 + Ð—Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ / Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ + + Режим Ð½Ð°Ð»Ð°Ð³Ð¾Ð´Ð¶ÐµÐ½Ñ + Відправити звіт про збій + Звіт до Sentry (sentry,io) + Ðе підтримуєтьÑÑ Ñ†Ñ–Ñ”ÑŽ збіркою + Детальне Ð¶ÑƒÑ€Ð½Ð°Ð»ÑŽÐ²Ð°Ð½Ð½Ñ + Додаток потрібно оновити, щоб прийнÑти зміни + diff --git a/app/src/main/res/values-uk/strings_prefs_root.xml b/app/src/main/res/values-uk/strings_prefs_root.xml new file mode 100644 index 0000000..84a6ca4 --- /dev/null +++ b/app/src/main/res/values-uk/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Блокувальник реклами з root-правами + + Ð’ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ…Ð¾Ñтів + Відкрити файл хоÑтів + ШлÑÑ… до файлу hosts + Прочитайте Поміч перед початком кориÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ†Ñ–Ñ”ÑŽ оÑобливіÑтю + + /system/etc/hosts + /data/hosts + /data/data/hosts + КориÑтувацькі Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ + + КориÑтувацьке Ñ€Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ + Приховати діалог Ð¿ÐµÑ€ÐµÐ·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ–ÑÐ»Ñ Ð·Ð°ÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ + + ÐŸÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ + Вибрати, куди направлÑти заблоковані хоÑти + IPv4 Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ + IPv6 Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ + Ðевірне Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ + + Локальний вебÑервер + Локальний вебÑервер Ñлухає локальні IP адреÑи Ñ– відповідає на запити від заблокованих хоÑтів. Це може допомогти із завиÑаннÑм заÑтоÑунку, коли його Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð»Ð¸. + Увімкнути веб-Ñервер + ТеÑтовий вебÑервер + Ð’Ñтановити ÑамопідпиÑаний Ñертифікат + Ручне вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñертифікату + Починаючи з Android 11 (R), заÑтоÑунки більше не можуть автоматично вÑтановлювати Ñертифікати (CA).\n\nЩоб це зробити вручну, зайдіть в налаштуваннÑ, розділ «Безпека» далі Â«Ð¨Ð¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¹ облікові дані», потім «УÑтановити Ñертифікат». У вікні, що з’ÑвитьÑÑ Ð²Ð¸Ð±ÐµÑ€Ñ–Ñ‚ÑŒ щойно Ñтворений файл Ñертифікату. + Відкрити Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Â«Ð‘ÐµÐ·Ð¿ÐµÐºÐ°Â» + Перевірка… + Ðе запущено + Запущено, але Ñертифікат не вÑтановлено + Запущено, Ñертифікат вÑтановлено + Замінити порожнє міÑце від реклами іконкою заÑтоÑунку + diff --git a/app/src/main/res/values-uk/strings_prefs_update.xml b/app/src/main/res/values-uk/strings_prefs_update.xml new file mode 100644 index 0000000..41c2083 --- /dev/null +++ b/app/src/main/res/values-uk/strings_prefs_update.xml @@ -0,0 +1,15 @@ + + + ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + + ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°ÑтоÑунку + ПеревірÑти Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ñ–Ð´ Ñ‡Ð°Ñ Ð·Ð°Ð¿ÑƒÑку + Періодично перевірÑти наÑвніÑть оновлень + Шукати бета-релізи + + ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ…Ð¾Ñтів + ПеревірÑти Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ñ–Ð´ Ñ‡Ð°Ñ Ð·Ð°Ð¿ÑƒÑку + Періодично перевірÑти наÑвніÑть оновлень + Синхронізувати при оновленні + Синхронізувати лише коли W-iFi + diff --git a/app/src/main/res/values-uk/strings_prefs_vpn.xml b/app/src/main/res/values-uk/strings_prefs_vpn.xml new file mode 100644 index 0000000..41fff03 --- /dev/null +++ b/app/src/main/res/values-uk/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð° оÑнові VPN + + Увімкнути під Ñ‡Ð°Ñ Ð·Ð°Ð¿ÑƒÑку + ПеревірÑти Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ + Періодично перевірÑти Ñтан мережі, Ñ– за потреби перезавантажувати VPN при роз’єднанні. + + Виключені заÑтоÑунки + Ðалаштуйте, Ñкі заÑтоÑунки не повинні викориÑтовувати VPN, щоб Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð½Ðµ блокувалоÑÑ. + Виключені ÑиÑтемні заÑтоÑунки + + None + All except browsers + All + + Вимкнені заÑтоÑунки кориÑтувача + + + Виключені заÑтоÑунки + Вибрати вÑÑ– + ЗнÑти Ð²Ð¸Ð´Ñ–Ð»ÐµÐ½Ð½Ñ + Іконка заÑтоÑунку + diff --git a/app/src/main/res/values-uk/strings_support.xml b/app/src/main/res/values-uk/strings_support.xml new file mode 100644 index 0000000..3bbdb7d --- /dev/null +++ b/app/src/main/res/values-uk/strings_support.xml @@ -0,0 +1,5 @@ + + + Підтримка + Стати ÑпонÑором + \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings_update.xml b/app/src/main/res/values-uk/strings_update.xml new file mode 100644 index 0000000..f678bc5 --- /dev/null +++ b/app/src/main/res/values-uk/strings_update.xml @@ -0,0 +1,21 @@ + + + ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ AdAway + + ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð´Ð¾Ñтупно! + + + Ви маєте оÑтанюю верÑÑ–ÑŽ + ДоÑтупне Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ AdAway + Оновити зараз + %1$s / %2$s + ОÑтанні зміни + Журанал змін + Підтримати розробку + Пожертвувати + СпонÑор + + + Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¾Ñтанньої верÑÑ–Ñ— AdAway… + diff --git a/app/src/main/res/values-uk/strings_welcome.xml b/app/src/main/res/values-uk/strings_welcome.xml new file mode 100644 index 0000000..2dbef53 --- /dev/null +++ b/app/src/main/res/values-uk/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Вітаємо + Перший крок + Другий крок + ОÑтанній крок + + + Вітаємо в AdAway! + AdAway надає два ÑпоÑоби Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¸. Виберіть один: + + Логотип рут + БлокуваннÑ\nчерез рут + Швидший + Ощадливий до батареї + Потрібен рут + + Логотип VPN + БлокуваннÑ\nчерез VPN + Повільніший + Працює в фоні + СуміÑніÑть + + Ðеобхідні права ÑуперкориÑтувача (root) + Ðеможливо знайти бінарний файл su, або ви не надали AdAway рут права.\n\nЦе може трапитиÑÑ, Ñкщо ваш приÑтрій не рутовано. Ви можете дізнатиÑÑ, Ñк поÑтавити рут права на ваш приÑтрій на wiki.lineageos.org або інших Ñайтах про Android. + + Переваги + Ðедоліки + + + Синхронізовано + Помилка під Ñ‡Ð°Ñ Ñинхронізації + + Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ + Синхронізовано! + AdAway завантажує мережі оголошень, Ñкі потрібно блокувати. Ви можете змінити Ñ—Ñ… в налаштуваннÑÑ…. + Повторити Ñинхронізацію + Ðе вдалоÑÑ Ñинхронізувати:\n %1$s .\n Повторити? + Може надÑилати ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ñтану контролю та Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¸ , а також Ñповіщати про доÑтупні Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÑƒ (декілька разів на рік). Увімкніть, Ñкщо хочете бути в курÑÑ– подій. + + + Підтримка + Підтримай мене! + AdAway — безкоштовний додаток з відкритим кодом, Ñкий Ñ Ñ€Ð¾Ð·Ñ€Ð¾Ð±Ð»ÑÑŽ у вільний чаÑ. Якщо вам він до вподоби, ви можете підтримати мене: + Заплатити через PayPal + Любите помилки? Я теж ні. + Увімкнути збір даних про помилки + + + Ðазад + Вперед + Завершити + diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml new file mode 100644 index 0000000..751634f --- /dev/null +++ b/app/src/main/res/values-ur/strings.xml @@ -0,0 +1,30 @@ + + + + نکلیٔے + بند کریں + جی ÛØ§Úº + Ù†Ûیں + جمع کریں + منسوخ کریں + محÙوظ کریں + مدد + + + خوش آمدید + AdAway Ø§Ø´ØªÛØ§Ø±Ø§Øª Ú©Ùˆ بلاک کرنے Ú©Û’ لیے ایک Ù…ÙØª اور open source ساÙٹویٔر ÛÛ’Û” ÛŒÛ Ø§Ù“Ù¾ Ú©Û’ سسٹم پر Ø§Ø´ØªÛØ§Ø±Ø§Øª Ú©Ùˆ بلاک کرنے Ú©Û’ لیے Ø§Ø´ØªÛØ§Ø±ÛŒ کمپنیوں Ú©Û’ ویب اڈریس (web address) اکٹھے کرتا ÛÛ’Û” مزید معلومات Ú©Û’ لیے نیچے دی Ú¯Ù”ÛŒ مدد Ù…Ù„Ø§Ø­Ø¸Û Ú©Ø±ÛŒÚºÛ” + مزید مدد دکھائیے + جمع کریں + مدد + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + diff --git a/app/src/main/res/values-ur/strings_app.xml b/app/src/main/res/values-ur/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-ur/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-ur/strings_errors.xml b/app/src/main/res/values-ur/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ur/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ur/strings_home.xml b/app/src/main/res/values-ur/strings_home.xml new file mode 100644 index 0000000..a530b93 --- /dev/null +++ b/app/src/main/res/values-ur/strings_home.xml @@ -0,0 +1,6 @@ + + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-ur/strings_hosts.xml b/app/src/main/res/values-ur/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-ur/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-ur/strings_lists.xml b/app/src/main/res/values-ur/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-ur/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-ur/strings_log.xml b/app/src/main/res/values-ur/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-ur/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-ur/strings_notification.xml b/app/src/main/res/values-ur/strings_notification.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ur/strings_notification.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ur/strings_prefs_backup_restore.xml b/app/src/main/res/values-ur/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ur/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ur/strings_prefs_main.xml b/app/src/main/res/values-ur/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-ur/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-ur/strings_prefs_root.xml b/app/src/main/res/values-ur/strings_prefs_root.xml new file mode 100644 index 0000000..0bb70c8 --- /dev/null +++ b/app/src/main/res/values-ur/strings_prefs_root.xml @@ -0,0 +1,10 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + diff --git a/app/src/main/res/values-ur/strings_prefs_update.xml b/app/src/main/res/values-ur/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ur/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ur/strings_prefs_vpn.xml b/app/src/main/res/values-ur/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-ur/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-ur/strings_support.xml b/app/src/main/res/values-ur/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-ur/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ur/strings_update.xml b/app/src/main/res/values-ur/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-ur/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-ur/strings_welcome.xml b/app/src/main/res/values-ur/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-ur/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-uz/strings.xml b/app/src/main/res/values-uz/strings.xml new file mode 100644 index 0000000..3592fd3 --- /dev/null +++ b/app/src/main/res/values-uz/strings.xml @@ -0,0 +1,53 @@ + + + + Chiqish + Yopish + Ha + Yo\'q + Qo\'shish + Bekor qilish + Saqlash + Yordam + + + Xush kelibsiz! + AdAway - bu reklamani blokirovka qilish uchun bepul va ochiq kodli dasturiy ta\'minot dizayni. U bilgan reklama adreslari bilan sizning qurilmangizdagi reklamani bloklaydi. \nQo\'shimcha ma\'lumot bilmoqchimisiz? Quyidagi yordamni tekshiring. + Qo\'shimcha yordamni ko\'rish + Holatni yangilash + Hamma xost fayllar belgilangan manbadan yuklab olinib, sizning bor ro\'yxatingiz bilan birlashitrilib, sizning sistemangizda bitta xost fayl qilib o\'rnatildi. + Reklama blokirovkasini yoqish + Reklama blokirovkasini o\'chirish + Veb-server + Ishlamoqda + Toxtatilgan + Bloklangan xost nomlariga berilgan so\'rovlarga javob berish uchun veb-serverni ishga tushiring yoki to\'xtating. + Veb-serverni ishga tushirish + Veb-serverni ishdan to\'xtatish + VPN + Ishlamoqda + Toxtatilgan + So\'rovlarni filtrlash uchun VPN-ni ishga tushiring yoki to\'xtating. + VPN-ni ishga tushirish + VPN-ni ishdan toxtatish + + + Yozuvni tahrirlash + Qo\'shish + Yordam + TSS + + + Uy + Xostlar manbalari + Sizning ro\'yxatingiz + Xostlar faylini ochish + DNS-so\'rovlarni ro\'yxatdan o\'tkazish + Reklama dasturini qidirish + Sozlamalar + Yordam + + Sizning ro\'yxatingiz + Sozlamalar + + diff --git a/app/src/main/res/values-uz/strings_app.xml b/app/src/main/res/values-uz/strings_app.xml new file mode 100644 index 0000000..d3a87c4 --- /dev/null +++ b/app/src/main/res/values-uz/strings_app.xml @@ -0,0 +1,4 @@ + + + AdAway + diff --git a/app/src/main/res/values-uz/strings_errors.xml b/app/src/main/res/values-uz/strings_errors.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-uz/strings_errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-uz/strings_home.xml b/app/src/main/res/values-uz/strings_home.xml new file mode 100644 index 0000000..a530b93 --- /dev/null +++ b/app/src/main/res/values-uz/strings_home.xml @@ -0,0 +1,6 @@ + + + + Preferences + + \ No newline at end of file diff --git a/app/src/main/res/values-uz/strings_hosts.xml b/app/src/main/res/values-uz/strings_hosts.xml new file mode 100644 index 0000000..8d829ed --- /dev/null +++ b/app/src/main/res/values-uz/strings_hosts.xml @@ -0,0 +1,4 @@ + + + Hosts sources + diff --git a/app/src/main/res/values-uz/strings_lists.xml b/app/src/main/res/values-uz/strings_lists.xml new file mode 100644 index 0000000..8ba3dd4 --- /dev/null +++ b/app/src/main/res/values-uz/strings_lists.xml @@ -0,0 +1,4 @@ + + + Your lists + diff --git a/app/src/main/res/values-uz/strings_log.xml b/app/src/main/res/values-uz/strings_log.xml new file mode 100644 index 0000000..95cd46d --- /dev/null +++ b/app/src/main/res/values-uz/strings_log.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-uz/strings_notification.xml b/app/src/main/res/values-uz/strings_notification.xml new file mode 100644 index 0000000..8210efb --- /dev/null +++ b/app/src/main/res/values-uz/strings_notification.xml @@ -0,0 +1,5 @@ + + + + VPN + \ No newline at end of file diff --git a/app/src/main/res/values-uz/strings_prefs_backup_restore.xml b/app/src/main/res/values-uz/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-uz/strings_prefs_backup_restore.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-uz/strings_prefs_main.xml b/app/src/main/res/values-uz/strings_prefs_main.xml new file mode 100644 index 0000000..b8c0bd5 --- /dev/null +++ b/app/src/main/res/values-uz/strings_prefs_main.xml @@ -0,0 +1,4 @@ + + + Preferences + diff --git a/app/src/main/res/values-uz/strings_prefs_root.xml b/app/src/main/res/values-uz/strings_prefs_root.xml new file mode 100644 index 0000000..97b7497 --- /dev/null +++ b/app/src/main/res/values-uz/strings_prefs_root.xml @@ -0,0 +1,11 @@ + + + Open hosts file + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + Veb-serverni ishga tushirish + diff --git a/app/src/main/res/values-uz/strings_prefs_update.xml b/app/src/main/res/values-uz/strings_prefs_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-uz/strings_prefs_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-uz/strings_prefs_vpn.xml b/app/src/main/res/values-uz/strings_prefs_vpn.xml new file mode 100644 index 0000000..d1f0e22 --- /dev/null +++ b/app/src/main/res/values-uz/strings_prefs_vpn.xml @@ -0,0 +1,8 @@ + + + + None + All except browsers + All + + diff --git a/app/src/main/res/values-uz/strings_support.xml b/app/src/main/res/values-uz/strings_support.xml new file mode 100644 index 0000000..efe0a1d --- /dev/null +++ b/app/src/main/res/values-uz/strings_support.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-uz/strings_update.xml b/app/src/main/res/values-uz/strings_update.xml new file mode 100644 index 0000000..4a4cb75 --- /dev/null +++ b/app/src/main/res/values-uz/strings_update.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-uz/strings_welcome.xml b/app/src/main/res/values-uz/strings_welcome.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/app/src/main/res/values-uz/strings_welcome.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml new file mode 100644 index 0000000..4bb6adf --- /dev/null +++ b/app/src/main/res/values-vi/strings.xml @@ -0,0 +1,258 @@ + + + + Thoát + Äóng + Có + Không + Thêm + Huá»· bá» + Lưu + Trợ giúp + + + Chào mừng! + AdAway là má»™t phần má»m miá»…n phí và mã nguồn mở được thiết kế để chặn quảng cáo. Nó lấy địa chỉ các mạng quảng cáo để chặn chúng trên thiết bị cá»§a bạn.\nBạn có muốn biết thêm không? Hãy xem trợ giúp ở bên dưới! + Hiện thêm trợ giúp + Cập nhật tình trạng + Tất cả các tập tin miá»n từ nguồn xác định sẽ được tải vá», ghép vá»›i danh sách cá»§a bạn và cài đặt thành má»™t tập tin miá»n duy nhất trên hệ thống. + Bật chặn quảng cáo + Tắt chặn quảng cáo + Máy chá»§ web + Äang chạy + Äã dừng + Bắt đầu hoặc dừng máy chá»§ web trên localhost để trả lá»i những yêu cầu đến các tên miá»n bị chặn. + Bật webserver + Tắt webserver + VPN + Äang chạy + Äã dừng + Bắt đầu hoặc dừng VPN để lá»c các yêu cầu. + Bật VPN + Tắt VPN + + + Chỉnh sá»­a mục + Ãp dụng + Chỉnh sá»­a + Xoá + + + Äang nhập… + Äã nhập tệp sao lưu thành công từ bá»™ nhá»› ngoài. + Lá»—i nhập tệp sao lưu, nó có đúng dạng không? Xem logcat để biết thêm chi tiết + Äang xuất… + Bản sao lưu được xuất thành công ra tập tin \'%s\' trên bá»™ nhá»› ngoài. + Xuất tập tin sao lưu \'%s\' thất bại. + + + Tệp hosts + Tệp hosts là mootk tệp hệ thống nằm trong /system/etc dùng để chỉ dẫn tên miá»n đến địa chỉ IP. Nó là má»™t tệp txt được cấu hình bởi AdAway. Äây là má»™t vài dòng + Äang tải tệp hosts trong máy + Mở tệp hosts + + + Äang kiểm tra cập nhật + Äang kiểm tra cập nhật từ nguồn %s + Äang lấy nguồn + Äang tải nguồn %s + Äang Ä‘á»c nguồn %s + Äang hợp nhất nguồn %s + Äồng bá»™ cÆ¡ sở dữ liệu bá»™ lá»c + Quay lại tập tin nguồn mặc định + Quay lại tập tin nguồn mặc định + Äang tạo tập tin miá»n chuẩn + Äã có bản cập nhật + Äã có tập tin miá»n má»›i + Không có cập nhật má»›i + Không có kết nối mạng + Không có sẵn kết nối mạng + Không có nguồn nào + Không kết nối được tá»›i bất cứ nguồn nào! + Quyá»n truy cập root bị từ chối + Cho phép quyá»n root + Có gì đó không ổn + Kiểm tra logcat để biết thêm chi tiết + Äã bật + Äã dùng tập tin miá»n má»›i + Äã tắt + Tệp máy chá»§ mặc định được cài đặt + Ãp dụng các nguồn má»›i nhất + Tạo tập tin máy chá»§ má»›i + Sao chép tập tin máy chá»§ má»›i + Kiểm tra bản sao tập tin máy chá»§ + Tập tin máy chá»§ được cập nhật thành công + Cấu hình VPN được cập nhật thành công + Thiết lập cá»§a bạn đã thay đổi. Bạn cần áp dụng nó. + Ãp dụng + Äang áp dụng thiết lập má»›i… + Ãp dụng thiết lập má»›i thất bại. + + + Thiếu liên kết đến mục tiêu tệp máy chá»§ + Liên kết biểu trưng từ mục tiêu đến /system/etc/hosts không tồn tại hoặc không đúng! AdAway sẽ không hoạt động nếu nó không được dẫn đến đúng tập tin.\n\nBạn có muốn thá»­ tạo liên kết má»›i? + Thiếu liên kết biểu trưng + Không đủ dung lượng trên ổ đĩa!\nHãy thá»­ đổi tập tin miá»n mục tiêu trong tuỳ chỉnh thành /data/data/hosts. + Không đủ dung lượng + Không Ä‘á»c được tập tin đã tải vá». + Tập tin riêng tư thất bại + Thất bại khi gắn phân vùng thành Ä‘á»c/ghi! + Gắn thất bại + Sao chép tệp miá»n thất bại + Thất bại khi sao chép tập tin miá»n! + Sao chép thất bại + Äã áp dụng các nguồn tên miá»n + Ãp dụng thành công + Ãp dụng đã thành công. \nCó thể cần phải khởi động lại Android để các thay đổi có hiệu lá»±c. \n\nBạn có muốn khởi động lại không?\n(Äể tránh mất dữ liệu, hãy chắc chắn không có ứng dụng nào sá»­ dụng thẻ SD vào lúc này!) + Liên kết biểu tượng đã được tạo thành công.\nCó thể cần phải khởi động lại Android để các thay đổi có hiệu lá»±c.\n\nBạn có muốn khởi động lại không?\n(Äể tránh mất dữ liệu, hãy chắc chắn không có ứng dụng nào sá»­ dụng thẻ SD vào lúc này!) + Tạo liên kết biểu trưng thành công + Liên kết biểu tượng không thể được tạo bởi Android.\nViệc này thất bại phần lá»›n vì má»™t \'tính năng\' gá»i là S-ON trên các Ä‘iện thoại HTC!\n\nMá»™t giải pháp là khởi động Ä‘iện thoại cá»§a bạn vào chế độ phục hồi và tạo liên kết biểu tượng ở đó bằng lệnh \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nNếu việc này không được thì hãy tìm kiếm S-OFF và Ä‘iện thoại cá»§a bạn trên Internet. + Tạo liên kết biểu trưng thất bại + Hãy Ä‘á»c Trợ giúp để biết thêm thông tin. + An APN proxy is set on your Android!\nAdAway will not work reliably when on Mobile Networks like 3G. You can deactivate that proxy by going to your selected APN (From the Settings app: Network & Internet -> Mobile network -> Advanced -> Access Point Names) and remove the value in the proxy field. + Äã tạo proxy APN! + Kết nối mạng không hoạt động. + Không có kết nối + Äang tải xuống… + Äang áp dụng… + Äang áp dụng Danh sách Ä‘en và Danh sách trắng + Äang xá»­ lý và hợp nhất các tập tin miá»n + Äang tạo tập tin miá»n + Äang áp dụng tập tin miá»n + Không thể áp dụng file hosts má»›i. + Thất bại khi áp dụng tập tin miá»n vào hệ thống!\nHãy thá»­ đổi tập tin miá»n mục tiêu trong cài đặt thành /data/data/hosts. + Ãp dụng thất bại + Hãy kiểm tra ứng dụng quản lý root để chắc rằng quyá»n truy cập root đã được cấp phép. + Bạn đã quay vá» tập tin miá»n mặc định.\nCó thể cần phải khởi động lại Android để các thay đổi có hiệu lá»±c.\n\nBạn có muốn khởi động lại không?\n(Äể tránh mất dữ liệu, hãy chắc chắn không có ứng dụng nào sá»­ dụng thẻ SD vào lúc này!) + Äổi lại thành công + Không thể quay lại tập tin miá»n ban đầu + Äổi lại bị thất bại mà không rõ nguyên nhân. + Äổi lại thất bại! + Không truy cập được bất kỳ nguồn tên miá»n đã kích hoạt nào! Bạn có Ä‘ang kết nối mạng không? + Tải vá» thất bại + Viết tập tin miá»n riêng má»›i thất bại + Không thể tạo tập tin riêng. + Tạo tập tin riêng thất bại + Bạn đã bật chế độ không dùng hệ thống.\nCó thể cần phải khởi động lại Android để các thay đổi có hiệu lá»±c.\n\nBạn có muốn khởi động lại không?\n(Äể tránh mất dữ liệu, hãy chắc chắn không có ứng dụng nào sá»­ dụng thẻ SD vào lúc này!) + Kích hoạt thành công + Bạn đã vô hiệu hoá chế độ systemless.\nCó thể sẽ cần thiết phải khởi động lại Android để sá»± thay đổi có hiệu quả. \n\nBạn có muốn khởi động lại?\n(Äể tránh mất dữ liệu hãy chắc rằng không có ứng dụng nào Ä‘ang sá»­ dụng thẻ SD lúc này!) + Vô hiệu hóa thành công + Không thể khởi động trình chặn quảng cáo qua VPN. + Không thể tắt chặn quảng cáo qua VPN. + Kích hoạt module Magisk hosts + Kích hoạt tính năng systemless hosts cá»§a Magisk. Ở cài đặt, kích hoạt lá»±a chá»n Systemless hostsrồi khởi động lại thiết bị cá»§a bạn. + Vô hiệu hoá module Magisk hosts + Vô hiệu hoá tính năng systemless hosts cá»§a Magisk. Ở danh sách module, gỡ cài đặt module Systemless hosts rồi khởi động lại thiết bị cá»§a bạn. + + + Nhập URL vào tập tin miá»n: + Tên miá»n không hợp lệ! + Äịnh dạng tên miá»n không đúng + IP không hợp lệ! + Äịnh dạng IP không đúng + Không bao giá» khởi động lại và đừng hiện câu há»i này lần tiếp theo! + Äang tải… + + + Làm má»›i + Thêm + Trợ giúp + Nhập bản sao lưu + Xuất bản sao lưu + + + S-ON/S-OFF + Những câu há»i thưá»ng gặp + Vấn đỠ+ + + Adware + Ở đây bạn có thể tìm thấy ứng dụng quảng cáo, đó là những ứng dụng xấu không thể bị chặn bởi AdAway. Các ứng dụng này sá»­ dụng, ví dụ là các thông báo Airpush hiện lên kể cả khi ứng dụng đó không chạy hoặc kể cả là thay đổi nhạc chuông cá»§a bạn. Biện pháp phản lại duy nhất có sẵn là gỡ cài đặt các ứng dụng đó bằng cách nhấn vào các mục trong danh sách. + Äang quét… + Không tìm thấy Adware! + + + Ứng dụng chặn quảng cáo + Chưa cài trình sá»­a văn bản + Không tìm thấy trình sá»­a văn bản để mở tập tin miá»n. Bạn có thể cài Jota hoặc các trình sá»­a văn bản khác.\n\nBạn có muốn cài Jota? + Không có trình quản lý tập tin nào được cài đặt + Không tìm thấy trình quản lý để mở tập tin. Bạn có thể cài OI File Manager hoặc các trình quản lý khác.\n\nBạn có muốn cài OI File Manager? + + + Tcpdump + Tcpdump là công cụ giám sát các yêu cầu DNS và lưu chúng vào tập tin nhật ký. Bạn có thể khởi động nó trong chế độ ná»n, chạy các ứng dụng có quảng cáo và sau đó phân tích yêu cầu DNS qua tập tin nhật ký. Máy chá»§ quảng cáo nhận được sẽ bị đưa vào danh sách Ä‘en. + Tắt giám sát + Bật giám sát + Hiện kết quả + Sắp xếp theo tên miá»n + Xoá log + Thêm mục vào danh sách Ä‘en + Thêm mục vào danh sách trắng + Thêm mục vào danh sách chuyển hướng + + Chỉnh sá»­a giá trị cài đặt văn bản + Mở menu + Äóng menu + + + + Home + Các nguồn miá»n + Your lists + Mở tập tin miá»n + Log DNS requests + Scan for adware + Tuỳ chỉnh + Trợ giúp + + + + + Các yêu cầu DNS + Danh sách cá»§a bạn + Tuỳ chỉnh + + + Äã cài đặt %1$s trước + Äã cập nhật %1$s trước + Cần được cập nhật %1$s + Cập nhật lần cuối %1$s trước + Trạng thái cập nhật không xác định + Äã tắt + vài phút + + %d phút + + + %d giá» + + + %d ngày + + + %d tháng + + + + Host đã được copy vào clipboard + + + Ä‘ang bắt đầu + hoạt động + Ä‘ang dừng + Ä‘ang kết nối + Ä‘ang kết nối lại + lá»—i kết nối lại + đã tạm dừng + đã dừng lại + VPN chặn quảng cáo %1$s + Tạm dừng + Tiếp tục + + + Quyá»n truy cập cá»§a AdAway + Cho phép tương tác vá»›i AdAway + Gá»­i lệnh đến AdAway + Cho phép gá»­i các lệnh như bật hoặc tắt chặn quảng cáo toàn hệ thống đến AdAway + + diff --git a/app/src/main/res/values-vi/strings_app.xml b/app/src/main/res/values-vi/strings_app.xml new file mode 100644 index 0000000..1f6e9bc --- /dev/null +++ b/app/src/main/res/values-vi/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Trình chặn quảng cáo mã nguồn mở + Logo AdAway + diff --git a/app/src/main/res/values-vi/strings_errors.xml b/app/src/main/res/values-vi/strings_errors.xml new file mode 100644 index 0000000..b277da4 --- /dev/null +++ b/app/src/main/res/values-vi/strings_errors.xml @@ -0,0 +1,22 @@ + + + + Không có kết nối mạng + Không thể kết nối internet. Làm Æ¡n kiểm tra cài đặt mạng. + Không thể tải xuống tập tin nguồn + Không thể tải xuống tập tin nguồn. Làm Æ¡n kiểm tra cài đặt mạng. + + Không thể tạo tập tin. + Không thể tạo tập tin má»›i. Làm Æ¡n kiểm tra dung lượng còn trống trên thiết bị. + Không đủ dung lượng + Không thể sao chép tập tin vào phân vùng hệ thống. + Không thể cải đặt tập tin nguồn. + Không thể sao chép tập tin nguồn vào phân vùng hệ thông. Hãy bật chế độ systemless host cá»§a Magisk rồi khởi động lại + Không thể đảo ngược tập tin nguồn + Không thể khôi phục cài đặt tập tin nguồn mặc định + + Không thể khởi động trình chặn quảng cáo qua VPN. + Làm Æ¡n kiểm tra cài đặt VPN thiết bị. + Không thể tắt chặn quảng cáo qua VPN. + Làm Æ¡n kiểm tra cài đặt VPN thiết bị. + diff --git a/app/src/main/res/values-vi/strings_home.xml b/app/src/main/res/values-vi/strings_home.xml new file mode 100644 index 0000000..27810f1 --- /dev/null +++ b/app/src/main/res/values-vi/strings_home.xml @@ -0,0 +1,44 @@ + + + + + Äã bị chặn + Äã cho phép + Äã chuyển hướng + + + + %d số nguồn đã được cập nhật + + + %dsố nguồn chưa được cập nhật + + Kiểm tra cập nhật tệp miá»n + Cập nhật file hosts + + + Hiện nhật ký yêu cầu DNS + + + Hiện các mẹo trợ giúp/nand + + + Mở GitHub + + + Ủng há»™ dá»± án + + + Dá»± án GitHub + Tuỳ chỉnh + + + Mở thanh Ä‘iá»u hướng + Tạm dừng/tiếp tục chặn quảng cáo + Cập nhật các tên miá»n đã chặn + Hiển thị các tên miá»n đã yêu cầu + + + Hãy Ä‘á»c Trợ giúp để biết thêm thông tin. + + \ No newline at end of file diff --git a/app/src/main/res/values-vi/strings_hosts.xml b/app/src/main/res/values-vi/strings_hosts.xml new file mode 100644 index 0000000..6fa1d0d --- /dev/null +++ b/app/src/main/res/values-vi/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Các nguồn miá»n + + Danh sách cá»§a ngưá»i dùng + AdAway official hosts + AdAway official hosts + Pete Lowe blocklist hosts + + không có sẵn + %s hosts + + Thêm nguồn + Chỉnh sá»­a nguồn + URL: (có dạng https:// hoặc file://) + URL tập tin nguồn + diff --git a/app/src/main/res/values-vi/strings_lists.xml b/app/src/main/res/values-vi/strings_lists.xml new file mode 100644 index 0000000..c9fc4d9 --- /dev/null +++ b/app/src/main/res/values-vi/strings_lists.xml @@ -0,0 +1,24 @@ + + + Danh sách cá»§a bạn + Thêm nguồn + + Äã bị chặn + Äã cho phép + Äã chuyển hướng + + Lá»c nguồn + Tìm tên nguồn + Bật/tắt nguồn + + Thêm nguồn vào danh sách chặn + Thêm nguồn vào danh sách cho phép + Thêm nguồn vào danh sách chuyển hướng + Chỉnh sá»­a danh sách chặn + Chỉnh sá»­a danh sách cho phép + Chỉnh sá»­a danh sách chuyển hướng + Tên miá»n: + URL cá»§a tập tin nguồn + (Cho phép sá»­ dụng các kí tá»± * và ?) + IP (IPv4 hoặc IPv6): + diff --git a/app/src/main/res/values-vi/strings_log.xml b/app/src/main/res/values-vi/strings_log.xml new file mode 100644 index 0000000..8f7b4fe --- /dev/null +++ b/app/src/main/res/values-vi/strings_log.xml @@ -0,0 +1,12 @@ + + + Chuyển đổi ghi nhật ký + Nhấn ghi để bắt đầu ghi yêu cầu, duyệt Web hoặc sá»­ dụng ứng dụng, sau đó quay lại hoặc vuốt để làm má»›i nhật ký. + + \n\nCác yêu cầu bị chặn sẽ không được ghi lại. Trước tiên hãy tắt tính năng chặn quảng cáo nếu bạn cÅ©ng muốn ghi chúng. + + Sắp xếp theo thứ tá»± chữ cái + Sắp xếp miá»n cấp trên cùng + + Chuyển hướng miá»n + diff --git a/app/src/main/res/values-vi/strings_notification.xml b/app/src/main/res/values-vi/strings_notification.xml new file mode 100644 index 0000000..45d3cd9 --- /dev/null +++ b/app/src/main/res/values-vi/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Cập nhật + Thông báo cập nhật má»›i + Äã có bản cập nhật + Có thể tải vá» tập tin nguồn má»›i + Ứng dụng có bản cập nhật má»›i + Phiên bản má»›i cá»§a AdAway đã sẵn sàng để tải xuống + + VPN + Thông báo khi mở VPN + \ No newline at end of file diff --git a/app/src/main/res/values-vi/strings_prefs_backup_restore.xml b/app/src/main/res/values-vi/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..bd9af4a --- /dev/null +++ b/app/src/main/res/values-vi/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Sao lưu và khôi phục + Sao lưu + Sao lưu cài đặt ra bá»™ nhá»› ngoài + Khôi phục + Khôi phục cài đặt từ tập tin sao lưu + diff --git a/app/src/main/res/values-vi/strings_prefs_main.xml b/app/src/main/res/values-vi/strings_prefs_main.xml new file mode 100644 index 0000000..c46b505 --- /dev/null +++ b/app/src/main/res/values-vi/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Tuỳ chỉnh + + Chung + Chế độ Äêm + + Sáng + Tối + Mặc định hệ thống + + Tá»± động cập nhật + + Chặn quảng cáo + Chặn quảng cáo sá»­ dụng quyá»n root + Chặn quảng cáo sá»­ dụng VPN + Bật IPv6 + Sao lưu / khôi phục cài đặt + + Dò lá»—i + Gá»­i báo cáo lá»—i + Gá»­i báo cáo Sentry (sentry.io) + Không được há»— trợ trên phiên bản này + Ghi nhật kí chi tiết + Bạn cần khởi động lại AdAway để tuỳ chỉnh được thá»±c thi. + diff --git a/app/src/main/res/values-vi/strings_prefs_root.xml b/app/src/main/res/values-vi/strings_prefs_root.xml new file mode 100644 index 0000000..0080aa0 --- /dev/null +++ b/app/src/main/res/values-vi/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Chặn quảng cáo sá»­ dụng quyá»n root + + Cài đặt tập tin miá»n + Mở tập tin miá»n + Tập tin miá»n mục tiêu + Trước khi thay đổi cài đặt, hãy Ä‘á»c Trợ giúp vá» tính năng này. + + /system/etc/hosts + /data/hosts + /data/data/hosts + Äích tá»± chá»n + + Äích tá»± chá»n + Ẩn há»™p thoại khởi động lại + + Chuyển hướng + Tùy chá»n Ä‘iá»u hướng tập tin miá»n + Äiá»u hướng IPv4 + Äiá»u hướng IPv6 + Chuyển hướng không hợp lệ + + Webserver cục bá»™ + Máy chá»§ web cục bá»™ sá»­ dụng các địa chỉ IP để phản hồi các yêu cầu truy cập các tên miá»n đã bị chặn, giúp giải quyết việc treo ứng dụng do kết nối bị chặn. + Bật webserver + Thá»­ nghiệm web server + Cài đặt chứng chỉ tá»± kí + Cài đặt thá»§ công chứng chỉ + Từ Android 11 (R) trở Ä‘i, ứng dụng sẽ không được phép tá»± cài đặt các chứng chỉ uá»· quyá»n (CA). \n\nVào cài đặt \"Bảo mật\", \"Mã hoá & chứng chỉ\" rồi \"Cài đặt chứng chỉ\". Chá»n \"Chứng chỉ CA\" và lá»±a chá»n file chứng chỉ má»›i được xuất. + Mở cài đặt \"Bảo mật\" + Äang kiểm tra… + Không hoạt động + Hoạt động nhưng chứng chỉ chưa được cài đặt + Äang hoạt động và đã cài đặt chứng chỉ + Äổi chá»— quảng cáo bằng icon ứng dụng + diff --git a/app/src/main/res/values-vi/strings_prefs_update.xml b/app/src/main/res/values-vi/strings_prefs_update.xml new file mode 100644 index 0000000..1c9041d --- /dev/null +++ b/app/src/main/res/values-vi/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Cập nhật + Thông báo bị vô hiệu hóa + Thông báo ứng dụng sẽ không hiển thị. Nhấn để kích hoạt chúng. + + Cập nhật ứng dụng + Kiểm tra cập nhật khi khởi động + Kiểm tra cập nhật má»—i ngày + Bao gồm các phiên bản beta + + Cập nhật tập tin miá»n + Kiểm tra cập nhật khi khởi động + Kiểm tra cập nhật má»—i ngày + Äồng bá»™ khi cập nhật + Chỉ đồng bá»™ bằng wi-fi + diff --git a/app/src/main/res/values-vi/strings_prefs_vpn.xml b/app/src/main/res/values-vi/strings_prefs_vpn.xml new file mode 100644 index 0000000..f13acf8 --- /dev/null +++ b/app/src/main/res/values-vi/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + Chặn quảng cáo sá»­ dụng VPN + + Kích hoạt khi khởi động + Giám sát kết nối + Äịnh kì kiểm tra tình trạng mạng để khởi động lại VPN khi mất kết nối. + + Các ứng dụng không bị chặn + Tùy chỉnh các ứng dụng có thể sá»­ dụng VPN + Không chặn các ứng dụng hệ thống + + None + All except browsers + Tất cả + + Các ứng dụng không bị chặn + + + Các ứng dụng không bị chặn + Chá»n tất cả + Bá» chá»n tất cả + Biểu tượng ứng dụng + diff --git a/app/src/main/res/values-vi/strings_support.xml b/app/src/main/res/values-vi/strings_support.xml new file mode 100644 index 0000000..7caf02c --- /dev/null +++ b/app/src/main/res/values-vi/strings_support.xml @@ -0,0 +1,5 @@ + + + Ủng há»™ + Trở thành má»™t nhà tài trợ + \ No newline at end of file diff --git a/app/src/main/res/values-vi/strings_update.xml b/app/src/main/res/values-vi/strings_update.xml new file mode 100644 index 0000000..2bbbcd2 --- /dev/null +++ b/app/src/main/res/values-vi/strings_update.xml @@ -0,0 +1,21 @@ + + + Cập nhật AdAway + + Có cập nhật má»›i! + + + Äã cập nhật xong + Äã có bản cập nhật + Äang cập nhật AdAway + Cập nhật ngay + %1$s / %2$s + Các thay đổi má»›i: + Các thay đổi + Ủng há»™ nhà phát triển + Quyên góp + Tài trợ + + + Äang tải xuống bản má»›i nhất cá»§a AdAway… + diff --git a/app/src/main/res/values-vi/strings_welcome.xml b/app/src/main/res/values-vi/strings_welcome.xml new file mode 100644 index 0000000..57ceed9 --- /dev/null +++ b/app/src/main/res/values-vi/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Chào mừng + Bước đầu wizard + Bước wizard thứ hai + Bước wizard cuối cùng + + + Chào mừng dến vá»›i AdAway! + AdAway cung cấp hai phương pháp chặn quảng cáo. Hãy chá»n phương pháp phù hợp vá»›i bạn: + + Logo root + Chặn quảng cáo sá»­ dụng root + Nhanh hÆ¡n + Tiết kiệm pin + Thiết bị cần được root + + Logo VPN + Chặn quảng cáo sá»­ dụng VPN + Chậm hÆ¡n + Chạy ná»n + Tương thích + + Yêu cầu thiết bị đã được root + Chuá»—i nhị phân SU không được tìm thấy hoặc AdAway chưa được cấp quyá»n root. Lá»—i này có thể xảy ra do thiết bị cá»§a bạn chưa được root. Thông tin vá» cách root thiết bị có thể xem trên wiki.lineageos.org hoặc các website tương tá»±. + + Äiểm cá»™ng + Äiểm trừ + + + Äã đồng bá»™ xong + Có lá»—i xảy ra khi đồng bá»™ + + Äang đồng bá»™ + Äã đồng bá»™ + AdAway tải xuống thông tin vá» các host quảng cáo để chặn chúng. Bạn có thể tùy chỉnh các host trong Cài đặt. + Thá»­ đồng bá»™ lại + Äồng bá»™ thất bại: %1$sThá»­ lại ngay? + Nó có thể gá»­i thông báo để hiển thị trạng thái và kiểm soát khối quảng cáo cÅ©ng như thông báo vá» bản cập nhật ứng dụng có sẵn (má»™t vài bản cập nhật má»—i năm). Kích hoạt chúng nếu bạn muốn luôn cập nhật. + + + Há»— trợ + Ủng há»™ AdAway! + AdAway là ứng dụng mã nguồn mở hoàn toàn miá»…n phí. Nếu bạn muốn, hãy á»§ng há»™ chúng tôi tại đây: + Ủng há»™ qua PayPal + Có lá»—i xảy ra? + Báo lá»—i cho chúng tôi qua + + + Quay lại + Tiếp theo + Hoàn thành + diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000..b583bac --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,258 @@ + + + + 離開 + 關閉 + 是 + å¦ + 加入 + å–æ¶ˆ + 儲存 + 說明 + + + æ­¡è¿Žï¼ + AdAway 是一個å…è²»ã€é–‹æºçš„廣告阻擋工具,專為 Android 設計。它會自動擷å–廣告網路的地å€ï¼Œç„¶å¾Œåœ¨æ‚¨çš„æ‰‹æ©Ÿæˆ–å¹³æ¿ä¸Šé€²è¡Œå»£å‘Šé˜»æ“‹ã€‚\n想進一步瞭解?請查閱下é¢çš„使用說明。 + 顯示更多說明 + 更新狀態 + é€™å€‹æ‡‰ç”¨ç¨‹å¼æœƒè‡ªå‹•下載您所設定的所有 hosts æª”æ¡ˆï¼Œèˆ‡æ‚¨å€‹äººçš„éŽæ¿¾æ¸…單進行åˆä½µï¼Œä¸¦å®‰è£ç‚ºå–®ä¸€çš„ hosts 檔案。 + 啟用廣告å°éŽ– + åœç”¨å»£å‘Šå°éŽ– + ç¶²é ä¼ºæœå™¨ + 正在執行 + å·²åœæ­¢ + 您å¯ä»¥å•Ÿå‹•或åœç”¨æœ¬æ©Ÿçš„ç¶²é ä¼ºæœå™¨ï¼Œä»¥è™•ç†åˆ°è¢«é˜»æ“‹ç¶²ç«™çš„請求。 + 啟用網é ä¼ºæœå™¨ + åœç”¨ç¶²é ä¼ºæœå™¨ + VPN + 正在執行 + å·²åœæ­¢ + å•Ÿå‹•æˆ–åœæ­¢ VPN ä¾†éŽæ¿¾è«‹æ±‚。 + 啟動 VPN + åœç”¨ VPN + + + 編輯項目 + 套用 + 編輯 + 刪除 + + + 匯入中… + æˆåŠŸå¾žå¤–æŽ¥å„²å­˜è£ç½®åŒ¯å…¥äº†å‚™ä»½è³‡æ–™ã€‚ + 備份匯入失敗。請確èªå‚™ä»½æª”案的格å¼ï¼Œæˆ–查看 logcat 以瞭解更多詳情。 + 匯出中… + 備份æˆåŠŸåŒ¯å‡ºåˆ°å¤–éƒ¨å„²å­˜ç©ºé–“çš„ã€Œ%sã€æª”案。 + 無法匯出備份檔案「%sã€ã€‚ + + + hosts 檔案 + hosts 檔案是一個與系統相關的純文字檔案,主è¦ç”¨æ–¼å°‡ç¶²ç«™åç¨±å°æ‡‰åˆ°å…¶ IP ä½å€ã€‚AdAway æœƒç®¡ç†æ­¤æª”案的設定。以下是此檔案的首幾行: + 正在載入 hosts 檔案內容… + 開啟 hosts 檔案 + + + 檢查更新 + 正在檢查 %s 來æºçš„æ›´æ–° + æœå°‹ä¾†æºä¸­ + ä¸‹è¼‰ä¾†æº %s + 讀å–來æº%s + 正在分æžä¾†æº%s + æ­£åœ¨åŒæ­¥è¦å‰‡è³‡æ–™åº« + æ¢å¾©åˆ°é è¨­ hosts 檔案 + 已還原é è¨­ hosts 檔案 + 建立標準的 hosts 檔案 + 有更新 + 有更新的 hosts 檔案 + 找ä¸åˆ°ä¾†æºæ›´æ–° + 沒有網路連線 + 沒有å¯ç”¨çš„網路連線 + ä¸å¯ç”¨çš„ä¾†æº + 無法連接é ç«¯ hosts 來æºä¼ºæœå™¨ï¼ + Root 權é™è¢«æ‹’絕 + 從 root 應用程å¼å…許 root æ¬Šé™ + 發生一些錯誤 + 檢視 logcat 以ç²å¾—更多詳細資料 + 啟用 + 已啟用最新的 hosts 檔案 + åœç”¨ + é è¨­ hosts æª”æ¡ˆå·²å®‰è£ + å¥—ç”¨æœ€æ–°ä¾†æº + 建立一個新的 hosts 檔案 + 複製一個新的 hosts 檔案 + 正在檢查 hosts 檔案副本 + hosts 檔案已更新æˆåŠŸ + VPN é…置更新æˆåŠŸ + 您的é…置已更改,你需è¦å¥—用它。 + 套用 + 正在套用新é…置…… + 無法套用新é…置。 + + + hosts 檔案目標的符號連çµéºå¤± + 由您的目標ä½ç½®åˆ° `/system/etc/hosts` 的符號連çµä¸å­˜åœ¨æˆ–是錯誤ï¼è‹¥éžæŒ‡å‘正確的檔案,AdAway 將無法正常é‹ä½œã€‚\n\n您是å¦å˜—試建立新的符號連çµï¼Ÿ + 符號連çµéºå¤± + 分割å€å‰©é¤˜ç©ºé–“ä¸è¶³ï¼\n請在å好設定中將目標 hosts 檔案更改為 `/data/data/hosts`。 + 空間ä¸è¶³ + 無法讀å–已下載的檔案。 + ç§äººæª”案失敗 + 釿–°æŽ›è¼‰åˆ†å€ç‚ºè®€å¯«æ¨¡å¼å¤±æ•—ï¼ + 釿–°æŽ›è¼‰å¤±æ•— + 複製 hosts 檔案失敗 + 複製 hosts æª”æ¡ˆå¤±æ•—ï¼ + 複製失敗 + 已套用 hosts ä¾†æº + 建立æˆåŠŸ + 應用æˆåŠŸã€‚\nå¯èƒ½éœ€è¦é‡æ–°å•Ÿå‹• Android æ‰èƒ½ä½¿è®Šæ›´ç”Ÿæ•ˆã€‚\n\n您是å¦è¦é‡æ–°å•Ÿå‹•手機?\n(為防止資料éºå¤±ï¼Œè«‹ç¢ºä¿ç›®å‰æ²’有應用程å¼åœ¨ä½¿ç”¨ SD å¡ï¼ï¼‰ + ç¬¦è™Ÿé€£çµæˆåŠŸå»ºç«‹ã€‚\nå¯èƒ½éœ€è¦é‡æ–°å•Ÿå‹• Android æ‰èƒ½ä½¿è®Šæ›´ç”Ÿæ•ˆã€‚\n\n您是å¦è¦é‡æ–°å•Ÿå‹•手機?\n(為防止資料éºå¤±ï¼Œè«‹ç¢ºä¿ç›®å‰æ²’有應用程å¼åœ¨ä½¿ç”¨ SD å¡ï¼ï¼‰ + 符號連çµå»ºç«‹æˆåŠŸ + Android 系統無法建立符號連çµã€‚\né€™ä¸»è¦æ˜¯å› ç‚º HTC 手機上一個å為 S-ON 的「功能ã€ï¼\n\n解決方案是將手機é‡å•Ÿè‡³å¾©åŽŸæ¨¡å¼ï¼Œä¸¦ç”¨ `ln -s /data/data/hosts /system/etc/hosts` 命令建立符號連çµã€‚\n\nè‹¥ä»ç„¶ä¸è¡Œï¼Œè«‹åœ¨ç¶²è·¯ä¸ŠæŸ¥æ‰¾é—œæ–¼ S-OFF åŠæ‚¨çš„æ‰‹æ©Ÿåž‹è™Ÿçš„資訊。 + 符號連çµå»ºç«‹å¤±æ•— + 請閱讀說明以ç²å¾—更多訊æ¯ã€‚ + 您的 Android 設備設定了 APN 代ç†ï¼\n在使用如 3G 之類的行動網路時,AdAway 將無法穩定é‹ä½œã€‚您å¯ä»¥é€éŽè¨­å®šä¸­ç§»é™¤ APN 代ç†ä¾†åœç”¨å®ƒã€‚(設定 -> 網路與網際網路 -> 行動網路 -> 進階 -> å­˜å–點åç¨±ï¼Œç„¶å¾Œæ¸…é™¤ä»£ç†æ¬„ä½çš„值) + 設定了 APN 代ç†ä¼ºæœå™¨ï¼ + 網際網路連線無法正常連線 + 無法連線 + 下載中… + 套用中… + 套用白å單和黑åå–® + è§£æžåŠåˆä½µ hosts 檔案 + 建立 hosts 檔案 + åˆä½µ hosts 檔案 + 無法套用新的 hosts 檔案。 + å°‡ hosts 檔案應用到您的系統失敗了ï¼\n請在å好設定中將目標 hosts 檔案更改為 `/data/data/hosts`。 + 建立失敗 + è«‹ç¢ºèªæ‚¨çš„ root ç®¡ç†æ‡‰ç”¨ç¨‹å¼å·²æŽˆäºˆ root å­˜å–æ¬Šé™ã€‚ + 您已æ¢å¾©è‡³é è¨­çš„ hosts 檔案。\nå¯èƒ½éœ€è¦é‡æ–°å•Ÿå‹• Android æ‰èƒ½ä½¿è®Šæ›´ç”Ÿæ•ˆã€‚\n\n您是å¦è¦é‡æ–°å•Ÿå‹•手機?\n(為防止資料éºå¤±ï¼Œè«‹ç¢ºä¿ç›®å‰æ²’有應用程å¼åœ¨ä½¿ç”¨ SD å¡ï¼ï¼‰ + 還原æˆåŠŸ + 無法還原 hosts 檔案 + 因未知原因還原失敗。 + é‚„åŽŸå¤±æ•—ï¼ + 所有您啟用的 hosts 來æºéƒ½ç„¡æ³•é€£æŽ¥ï¼æ‚¨æ˜¯å¦å·²æ­£ç¢ºé€£æŽ¥è‡³ç¶²éš›ç¶²è·¯ï¼Ÿ + 下載失敗 + 無法寫入新的ç§äºº hosts 檔案 + ä¸èƒ½å»ºç«‹ç§äººæª”案。 + ç§äººæª”案建立失敗 + 您已啟用 systemless 模å¼ã€‚\nå¯èƒ½éœ€è¦é‡æ–°å•Ÿå‹• Android æ‰èƒ½ä½¿è®Šæ›´ç”Ÿæ•ˆã€‚\n\n您是å¦è¦é‡æ–°å•Ÿå‹•手機?\n(為防止資料éºå¤±ï¼Œè«‹ç¢ºä¿ç›®å‰æ²’有應用程å¼åœ¨ä½¿ç”¨ SD å¡ï¼ï¼‰ + 啟用æˆåŠŸ + 您åœç”¨äº† systemless 模å¼ã€‚\n變更需è¦é‡æ–°å•Ÿå‹•æ‰èƒ½ç”Ÿæ•ˆã€‚\n\n您è¦é‡æ–°å•Ÿå‹•嗎?\n(為了防止檔案éºå¤±ï¼Œè«‹ç¢ºä¿æ²’æœ‰ç¨‹å¼æ­£åœ¨ä½¿ç”¨ SD å¡ï¼‰ + å–æ¶ˆæˆåŠŸ + 無法啟用 VPN 廣告阻擋。 + 無法åœç”¨ VPN 廣告阻擋。 + 啟用 Magisk hosts 模組 + 在 Magisk Manager 中啟用 systemless hosts 功能。請在該軟體的設定中,啟用Systemless hostsé¸é …並é‡å•Ÿæ‚¨çš„è£ç½®ã€‚ + åœç”¨ Magisk hosts 模組 + 在 Magisk Manager 中åœç”¨ systemless hosts 功能。請在該軟體的模組清單中,移除Systemless hosts模組並é‡å•Ÿæ‚¨çš„è£ç½®ã€‚ + + + 輸入 hosts 檔案的 URL: + 主機åç¨±ç„¡æ•ˆï¼ + 主機å稱格å¼éŒ¯èª¤ + IP ä½å€ç„¡æ•ˆï¼ + IP æ ¼å¼éŒ¯èª¤ + ä¸è¦é‡æ–°å•Ÿå‹•並且ä¸å†é¡¯ç¤ºï¼ + 讀å–中 … + + + 釿–°æ•´ç† + 加入 + 說明 + 匯入備份 + 匯出備份 + + + S-ON/S-OFF + 常見å•題 + å•題 + + + 廣告軟體 + 在此,您å¯ä»¥æ‰¾åˆ°å·²å®‰è£çš„廣告軟體和 AdAway 無法阻擋的ä¸è‰¯æ‡‰ç”¨ç¨‹å¼ã€‚這些應用程å¼å¯èƒ½æœƒä½¿ç”¨åƒæ˜¯ Airpush 的通知功能,å³ä½¿æ‡‰ç”¨ç¨‹å¼æ²’有é‹è¡Œï¼Œä¹Ÿæœƒå½ˆå‡ºé€šçŸ¥æˆ–更改您的鈴è²ã€‚唯一å¯è¡Œçš„å°ç­–æ˜¯é»žé¸æ¸…單項目,移除這些ä¸è‰¯æ‡‰ç”¨ç¨‹å¼ã€‚ + 掃æä¸­â€¦ + 沒有發ç¾ä»»ä½•å»£å‘Šè»Ÿé«”ï¼ + + + 廣告阻擋器 + æ²’æœ‰å®‰è£æ–‡å­—編輯器 + 找ä¸åˆ°é©åˆé–‹å•Ÿ hosts 檔案的文字編輯器。您å¯ä»¥å®‰è£ Jota 或其他文字編輯器來處ç†é€™å€‹å•題。\n\n您想è¦å®‰è£ Jota 嗎? + æ²’æœ‰å®‰è£æª”案管ç†å™¨ + 找ä¸åˆ°é©åˆé–‹å•Ÿæª”案的檔案管ç†å™¨ã€‚您å¯ä»¥å®‰è£ OI 檔案管ç†å™¨æˆ–其他檔案管ç†å·¥å…·ä¾†è™•ç†é€™å€‹å•題。\n\n您想è¦å®‰è£ OI 檔案管ç†å™¨å—Žï¼Ÿ + + + Tcpdump + Tcpdump 是一個用於監視 DNS 請求並將它們ä¿å­˜åœ¨è¨˜éŒ„檔案中的工具。您å¯ä»¥åœ¨èƒŒæ™¯åŸ·è¡Œå®ƒï¼Œé–‹å•Ÿé¡¯ç¤ºå»£å‘Šçš„æ‡‰ç”¨ç¨‹å¼ï¼Œä¹‹å¾Œä½¿ç”¨è¨˜éŒ„æª”æ¡ˆä¾†åˆ†æž DNS 請求。之後,您å¯ä»¥å°‡å¯èƒ½çš„廣告伺æœå™¨æ–°å¢žåˆ°æ‚¨çš„黑å單中。 + åœç”¨ç›£è¦– + 啟用監視 + é¡¯ç¤ºçµæžœ + 排åºç¶²åŸŸ + 清除記錄 + 加入項目至黑åå–® + 加入項目至白åå–® + åŠ å…¥é …ç›®è‡³é‡æ–°å°Žå‘清單 + + 編輯文字設定值 + 開啟é¸å–® + 關閉é¸å–® + + + + ä¸»ç•«é¢ + Hosts ä¾†æº + 你的清單 + 開啟 hosts 檔案 + 記錄 DNS 請求 + 掃æå»£å‘Šè»Ÿé«” + 設定 + 說明 + + + + + DNS 請求 + 你的清單 + å好設定 + + + %1$s å‰å®‰è£ + %1$s 是最新的 + %1$s éœ€è¦æ›´æ–° + 上次更新 %1$s å‰ + 未知更新狀態 + åœç”¨ + å¹¾åˆ†é˜ + + %d åˆ†é˜ + + + %d å°æ™‚ + + + %d 天 + + + %d 個月 + + + + 主機已複製到剪貼簿 + + + é–‹å§‹ + 有效的 + åœæ­¢ + 等待網路 + 釿–°é€£æŽ¥ + 釿–°é€£æŽ¥éŒ¯èª¤ + å·²æš«åœ + å·²åœæ­¢ + 廣告攔截器 VPN %1$s + æš«åœ + æ¢å¾© + + + AdAway æ¬Šé™ + å…許與 AdAway 互動 + 傳逿Œ‡ä»¤åˆ° AdAway + å…è¨±å‘ AdAway ç™¼é€æŒ‡ä»¤ï¼Œå¦‚啟用或ç¦ç”¨ç³»çµ±ç´šå»£å‘Šæ””截 + + diff --git a/app/src/main/res/values-zh-rTW/strings_app.xml b/app/src/main/res/values-zh-rTW/strings_app.xml new file mode 100644 index 0000000..ef195d1 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + é–‹æºçš„廣告阻擋器 + AdAway logo + diff --git a/app/src/main/res/values-zh-rTW/strings_errors.xml b/app/src/main/res/values-zh-rTW/strings_errors.xml new file mode 100644 index 0000000..6d0133c --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_errors.xml @@ -0,0 +1,22 @@ + + + + 沒有網路連線 + 無法建立網路連接。請檢查您的設備連線。 + 無法下載 hosts ä¾†æº + 無法存å–已啟用的 hosts 來æºã€‚è«‹æª¢æŸ¥æ‚¨æ˜¯å¦æ­£ç¢ºé€£ç·šåˆ°ç¶²éš›ç¶²è·¯ã€‚ + + 無法建立ç§äººçš„æª”案 + 無法建立ç§äººæª”æ¡ˆä»¥ç”Ÿæˆæ–°çš„ hosts 來æºã€‚請檢查è£ç½®ä¸Šçš„å¯ç”¨ç©ºé–“。 + 空間ä¸è¶³ + 無法將 hosts 檔案複製到系統分割å€ã€‚請檢查 Magisk çš„ systemless 模組是å¦å·²å•Ÿç”¨ï¼Œç„¶å¾Œé‡æ–°å•Ÿå‹•。 + ç„¡æ³•å®‰è£æ–°çš„ hosts 檔案 + 無法將 hosts 檔案複製到 /system 分割å€ã€‚è«‹ç¢ºèª Magisk çš„ systemless 模組是å¦å·²å•Ÿç”¨ï¼Œç„¶å¾Œé‡æ–°å•Ÿå‹•。 + 無法還原 hosts 檔案 + 無法還原é è¨­ hosts 檔案設定。 + + 無法啟用 VPN 廣告阻擋。 + 請檢查您的 VPN è¨­å®šä»¥æŽˆæ¬Šæ‡‰ç”¨ç¨‹å¼ VPN 啟動。 + 無法åœç”¨ VPN 廣告阻擋。 + 請檢查您的 VPN 設定來手動åœç”¨å®ƒã€‚ + diff --git a/app/src/main/res/values-zh-rTW/strings_home.xml b/app/src/main/res/values-zh-rTW/strings_home.xml new file mode 100644 index 0000000..a39ed81 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_home.xml @@ -0,0 +1,44 @@ + + + + + 已阻擋 + å·²å…許 + 釿–°å°Žå‘ + + + + %d å€‹æœ€æ–°ä¾†æº + + + %d å€‹éŽæ™‚ä¾†æº + + 檢查 hosts æ›´æ–° + æ›´æ–° hosts + + + 顯示 DNS 請求記錄 + + + 顯示說明\n與æç¤º + + + 打開 GitHub é é¢ + + + 支æŒé …ç›® + + + GitHub 專案 + å好設定 + + + 打開導覽抽屜 + æš«åœ / æ¢å¾©å»£å‘Šé˜»æ“‹ + 更新阻擋網域 + é¡¯ç¤ºè¦æ±‚的網域 + + + 請閱讀說明以ç²å¾—更多訊æ¯ã€‚ + + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings_hosts.xml b/app/src/main/res/values-zh-rTW/strings_hosts.xml new file mode 100644 index 0000000..621b4ba --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Hosts ä¾†æº + + 用戶自訂清單 + AdAway官方hosts + StevenBlack的統一化hosts + Pete Lowe的阻擋hosts + + 無法使用 + %s 個主機 + + åŠ å…¥ä¾†æº + ç·¨è¼¯ä¾†æº + ç¶²å€ï¼šï¼ˆä¸€å€‹ https:// 或 file:// 資æºï¼‰ + Hosts ä¾†æº URL + diff --git a/app/src/main/res/values-zh-rTW/strings_lists.xml b/app/src/main/res/values-zh-rTW/strings_lists.xml new file mode 100644 index 0000000..dcc1a76 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_lists.xml @@ -0,0 +1,24 @@ + + + 你的清單 + 加入主機 + + 已阻擋 + å·²å…許 + 釿–°å°Žå‘ + + éŽæ¿¾ hosts + æœå°‹ä¸»æ©Ÿå…… + 切æ›ä¾†æº + + 將主機加入至黑åå–® + 將主機至白åå–® + åŠ å…¥ä¸»æ©Ÿé‡æ–°å°Žå‘ + 編輯黑å單主機 + 編輯白å單主機 + ç·¨è¼¯é‡æ–°å°Žå‘ + 主機å稱: + Hosts ä¾†æº URL + (å¯ä½¿ç”¨è¬ç”¨å­—å…ƒ * å’Œ ?) + IP ä½å€ (IPv4 或 IPv6): + diff --git a/app/src/main/res/values-zh-rTW/strings_log.xml b/app/src/main/res/values-zh-rTW/strings_log.xml new file mode 100644 index 0000000..3c8b0b7 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_log.xml @@ -0,0 +1,11 @@ + + + 切æ›è¨˜éŒ„的記錄功能 + 按下「記錄ã€ä»¥é–‹å§‹è¨˜éŒ„請求,ç€è¦½ç¶²é æˆ–使用應用程å¼ï¼Œç„¶å¾Œè¿”回或滑動以更新紀錄。 + \n\nè¢«é˜»æ“‹çš„è«‹æ±‚å°‡ä¸æœƒè¢«è¨˜éŒ„。如果您也想記錄它們,請先åœç”¨å»£å‘Šé˜»æ“‹åŠŸèƒ½ã€‚ + + 按字æ¯é †åºæŽ’åº + æŒ‰é ‚ç´šç¶²åŸŸæŽ’åº + + 釿–°å°Žå‘網域 + diff --git a/app/src/main/res/values-zh-rTW/strings_notification.xml b/app/src/main/res/values-zh-rTW/strings_notification.xml new file mode 100644 index 0000000..56493e2 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_notification.xml @@ -0,0 +1,13 @@ + + + + æ›´æ–° + 新的更新通知 + 有更新 + 較新的 hosts 檔案å¯ä¾›ä¸‹è¼‰ã€‚ + æ‡‰ç”¨ç¨‹å¼æ›´æ–°å¯ç”¨ + å¯ä»¥ä¸‹è¼‰æ–°ç‰ˆæœ¬çš„ AdAway。 + + VPN + VPN 執行通知 + diff --git a/app/src/main/res/values-zh-rTW/strings_prefs_backup_restore.xml b/app/src/main/res/values-zh-rTW/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..0f4ff33 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + 備份和還原 + 備份 + 將阻擋è¦å‰‡å‚™ä»½åˆ°å¤–部存儲 + 還原 + 從備份檔案還原阻擋è¦å‰‡ + diff --git a/app/src/main/res/values-zh-rTW/strings_prefs_main.xml b/app/src/main/res/values-zh-rTW/strings_prefs_main.xml new file mode 100644 index 0000000..b56697b --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + 設定 + + 一般 + 深色主題 + + 淺色 + 深色 + 系統é è¨­ + + 自動更新 + + 廣告阻擋 + 基於 Root 的廣告阻擋器 + 基於 VPN 的廣告阻擋器 + 啟用 IPv6 æ”¯æ´ + 備份 / 還原阻擋è¦å‰‡ + + 除錯 + 傳é€å´©æ½°å ±å‘Š + å‘ Sentry (sentry.io) 報告 + æ­¤ç‰ˆæœ¬ä¸æ”¯æ´ + 詳細的日誌 + 需è¦é‡æ–°å•Ÿå‹•æ‡‰ç”¨ç¨‹å¼æ‰èƒ½æ‡‰ç”¨ + diff --git a/app/src/main/res/values-zh-rTW/strings_prefs_root.xml b/app/src/main/res/values-zh-rTW/strings_prefs_root.xml new file mode 100644 index 0000000..7132653 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + 基於 Root 的廣告阻擋器 + + Hosts å®‰è£ + 開啟 hosts 檔案 + 目標 hosts 檔案 + 使用此功能å‰ï¼Œè«‹å…ˆé–±è®€ã€Œå¹«åŠ©ã€ + + /system/etc/hosts + /data/hosts + /data/data/hosts + 自訂目標 + + 自定義目標ä½ç½® + 應用後隱è—釿–°å•Ÿå‹•çš„å°è©±æ¡† + + 釿–°å°Žå‘ + å®šç¾©é‡æ–°å°Žå‘被阻止的 hosts ä½ç½® + IPv4 釿–°å°Žå‘ + IPv6 釿–°å°Žå‘ + ç„¡æ•ˆçš„é‡æ–°å°Žå‘ + + 本地網é ä¼ºæœå™¨ + 本機網é ä¼ºæœå™¨æœƒç›£è½æœ¬æ©Ÿ IP ä½å€ï¼Œä»¥å›žæ‡‰è¢«é˜»æ“‹çš„主機å稱請求。這å¯èƒ½æœ‰åŠ©æ–¼è§£æ±ºæ‡‰ç”¨ç¨‹å¼åœ¨è¢«é˜»æ“‹çš„連線時出ç¾çš„å‡çµå•題。 + 啟用網é ä¼ºæœå™¨ + 測試網é ä¼ºæœå™¨ + 安è£è‡ªç°½æ†‘è­‰ + æ†‘è­‰æ‰‹å‹•å®‰è£ + 從 Android 11(R)版本開始,應用程å¼ç„¡æ³•è‡ªå‹•å®‰è£æ†‘證授權(CA)。\n\nè«‹å‰å¾€ã€Œå®‰å…¨æ€§ã€è¨­å®šï¼Œé»žé¸ã€ŒåŠ å¯†èˆ‡æ†‘è­‰ã€ï¼Œç„¶å¾Œé¸æ“‡ã€Œå®‰è£è­‰æ›¸ã€ã€‚åœ¨é‚£è£¡ï¼Œé¸æ“‡ã€ŒCA 憑證ã€ä¸¦é¸å–新匯出的憑證檔案。 + 開啟「安全性ã€è¨­å®š + 檢查中…… + 未執行 + æ­£åœ¨åŸ·è¡Œï¼Œä½†æœªå®‰è£æ†‘è­‰ + æ­£åœ¨åŸ·è¡Œä¸”å·²å®‰è£æ†‘è­‰ + 將空白的廣告å€åŸŸæ›¿æ›ç‚ºæ‡‰ç”¨ç¨‹å¼åœ–示 + diff --git a/app/src/main/res/values-zh-rTW/strings_prefs_update.xml b/app/src/main/res/values-zh-rTW/strings_prefs_update.xml new file mode 100644 index 0000000..84625d8 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + æ›´æ–° + 通知已åœç”¨ + 應用程å¼é€šçŸ¥ä¸æœƒé¡¯ç¤ºã€‚點擊啟用它們。 + + æ‡‰ç”¨ç¨‹å¼æ›´æ–° + 啟動時檢查更新 + 定期檢查更新 + åŒ…å« beta 版本 + + Hosts æ›´æ–° + 啟動時檢查更新 + 定期檢查更新 + åŒæ­¥æ›´æ–° + 僅在ä¸é™æµé‡çš„ç¶²è·¯ä¸ŠåŒæ­¥ + diff --git a/app/src/main/res/values-zh-rTW/strings_prefs_vpn.xml b/app/src/main/res/values-zh-rTW/strings_prefs_vpn.xml new file mode 100644 index 0000000..36f76b9 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + 基於 VPN 的廣告阻擋器 + + 開機時啟用 + 監視連線狀態 + å®šæœŸæª¢æŸ¥ç¶²è·¯ç‹€æ…‹ï¼Œä¸¦åœ¨æ–·ç·šæ™‚é‡æ–°å•Ÿå‹• VPN。 + + æŽ’é™¤çš„æ‡‰ç”¨ç¨‹å¼ + 設定哪些應用程å¼ä¸æ‡‰ä½¿ç”¨ VPN,以é¿å…阻擋任何連線。 + æŽ’é™¤ç³»çµ±æ‡‰ç”¨ç¨‹å¼ + + ç„¡ + 排除ç€è¦½å™¨ä¹‹å¤–çš„æ‰€æœ‰æ‡‰ç”¨ç¨‹å¼ + 全部 + + æŽ’é™¤ä½¿ç”¨è€…æ‡‰ç”¨ç¨‹å¼ + + + å·²æŽ’é™¤çš„æ‡‰ç”¨ç¨‹å¼ + å…¨é¸ + å…¨ä¸é¸ + 應用程å¼åœ–示 + diff --git a/app/src/main/res/values-zh-rTW/strings_source_edit.xml b/app/src/main/res/values-zh-rTW/strings_source_edit.xml new file mode 100644 index 0000000..09dda53 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + ç·¨è¼¯ä¾†æº + åŠ å…¥ä¾†æº + + 標籤 + éœ€è¦æ¨™ç±¤ + 類型 + URL + 檔案 + ä½ç½® + https:// + 需è¦ä½ç½® + é»žæ“Šæª”æ¡ˆä»¥é¸æ“‡ä¾†æºæª”案 + ä½ç½®ç„¡æ•ˆ + æ¸…å–®æ ¼å¼ + 阻擋 + å…許 + å¥—ç”¨é‡æ–°å°Žå‘ hosts + å…è¨±é‡æ–°å°Žå‘的主機å¯èƒ½æœƒå°Žè‡´å®‰å…¨å•題。僅在信任的來æºä¸Šä½¿ç”¨æ­¤è¨­å®šï¼Œå› ç‚ºå®ƒå¯èƒ½æœƒå°‡ä¸€äº›æ•感æµé‡å°Žå‘任何它想è¦çš„伺æœå™¨ã€‚ + diff --git a/app/src/main/res/values-zh-rTW/strings_support.xml b/app/src/main/res/values-zh-rTW/strings_support.xml new file mode 100644 index 0000000..cfe836d --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_support.xml @@ -0,0 +1,5 @@ + + + æ”¯æŒ + æˆç‚ºè´ŠåŠ©è€… + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings_update.xml b/app/src/main/res/values-zh-rTW/strings_update.xml new file mode 100644 index 0000000..6c00d5a --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_update.xml @@ -0,0 +1,21 @@ + + + AdAway æ›´æ–° + + æ›´æ–°å¯ç”¨ï¼ + + + 您已是最新的 + 有更新 + 正在更新 AdAway + ç¾åœ¨æ›´æ–° + %1$s / %2$s + 最近更改 + 更新紀錄 + 支æ´é–‹ç™¼ + 資助 + 贊助者 + + + 正在下載最新的 AdAway 版本… + diff --git a/app/src/main/res/values-zh-rTW/strings_welcome.xml b/app/src/main/res/values-zh-rTW/strings_welcome.xml new file mode 100644 index 0000000..249d0e0 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings_welcome.xml @@ -0,0 +1,53 @@ + + + 歡迎 + ç²¾éˆç¬¬ä¸€æ­¥ + ç²¾éˆç¬¬äºŒæ­¥ + ç²¾éˆæœ€å¾Œä¸€æ­¥ + + + 歡迎來到 AdAwayï¼ + AdAway æä¾›äº†å…©ç¨®å»£å‘Šé˜»æ“‹æ–¹æ³•ï¼Œé¸æ“‡ä¸€å€‹æ‚¨å–œæ­¡çš„: + + Root logo + 基於 Root\n 廣告阻擋 + 較快 + çœé›» + éœ€è¦ Root + + VPN logo + 基於 VPN\n 廣告阻擋 + 較慢 + 在背景é‹ä½œ + 相容性 + + éœ€è¦ root æ¬Šé™ + 找ä¸åˆ° su 二進ä½åˆ¶æª”案,或者您沒有å…許 AdAway root 權é™ã€‚\n\n 當您的è£ç½®æ²’有 root æ¬Šé™æ™‚,å¯èƒ½æœƒç™¼ç”Ÿé€™ç¨®æƒ…æ³ã€‚您å¯ä»¥åœ¨ wiki.lineageos.org 或其他 Android 網站上找到有關如何 root è£ç½®çš„資訊。 + + Pro + Con + + + åŒæ­¥å®Œæˆ + åŒæ­¥æ™‚出錯 + + åŒæ­¥ä¸­ + å·²åŒæ­¥ï¼ + AdAway å¯ä»¥å¾žç·šä¸Šä¾†æºä¸‹è¼‰å»£å‘Šç¶²è·¯ï¼Œä»¥é€²è¡Œé˜»æ“‹ã€‚您å¯ä»¥åœ¨ã€Œè¨­å®šã€é¸é …中,隨時調整這些阻擋清單。 + 釿–°åŒæ­¥ + åŒæ­¥å¤±æ•—:%1$s,ç¾åœ¨é‡è©¦ï¼Ÿ + AdAway å¯ä»¥ç™¼é€é€šçŸ¥ï¼Œç”¨æ–¼é¡¯ç¤ºå»£å‘Šé˜»æ“‹ç‹€æ…‹å’ŒæŽ§åˆ¶ï¼Œä»¥åŠæé†’æ‚¨æœ‰å¯ç”¨çš„æ‡‰ç”¨ç¨‹å¼æ›´æ–°ï¼ˆæ¯å¹´åƒ…æ•¸æ¬¡ï¼‰ã€‚å¦‚æžœæ‚¨å¸Œæœ›ä¿æŒæœ€æ–°ç‹€æ…‹ï¼Œè«‹å•Ÿç”¨é€™äº›é€šçŸ¥ã€‚ + + + æ”¯æŒ + æ”¯æŒæˆ‘å€‘ï¼ + AdAway 是一個我在閒暇時間開發的å…費且開放原始碼的應用程å¼ã€‚å¦‚æžœæ‚¨å–œæ­¡å®ƒï¼Œæ­¡è¿Žéš¨æ™‚è¡¨é”æ‚¨çš„æ”¯æŒï¼š + 在 PayPal 上æè´ˆ + 你喜歡臭蟲嗎?我也ä¸å–œæ­¡ã€‚ + 啟用自動傳é€å´©æ½°å ±å‘Š + + + 上一步 + 下一步 + å®Œæˆ + diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml new file mode 100644 index 0000000..b16d751 --- /dev/null +++ b/app/src/main/res/values-zh/strings.xml @@ -0,0 +1,259 @@ + + + + 退出 + 关闭 + 是 + å¦ + 添加 + å–æ¶ˆ + ä¿å­˜ + 帮助 + + + æ¬¢è¿Žï¼ + AdAway 是一款å…è´¹ã€å¼€æºçš„广告拦截器,它能在线获å–广告的域å,并通过系统的 hosts 文件本地å±è”½å®ƒä»¬ã€‚\n想了解更多信æ¯ï¼Ÿè¯·æŸ¥çœ‹ä¸‹é¢çš„å¸®åŠ©ï¼ + 显示更多帮助 + æ›´æ–°çŠ¶æ€ + 已从指定的 hosts æ¥æºä¸‹è½½ hosts 文件,与自定义列表åˆå¹¶ï¼Œå¹¶å®‰è£…到了您的系统中。 + å¯ç”¨å¹¿å‘Šæ‹¦æˆª + ç¦ç”¨å¹¿å‘Šæ‹¦æˆª + 网络æœåС噍 + 正在è¿è¡Œ + å·²åœæ­¢ + 在本地主机上å¯åŠ¨æˆ–åœæ­¢WebæœåŠ¡å™¨ï¼Œä»¥å›žç­”å¯¹è¢«é˜»æ­¢çš„ä¸»æœºå的请求。 + å¯ç”¨ç½‘络æœåС噍 + ç¦ç”¨ç½‘络æœåС噍 + VPN + è¿è¡Œä¸­ + å·²åœæ­¢ + å¯åŠ¨æˆ–åœæ­¢ VPN 以过滤请求。 + å¯ç”¨ VPN + ç¦ç”¨ VPN + + + 编辑æ¡ç›® + 应用 + 编辑 + 删除 + + + 正在导入… + å·²æˆåŠŸä»Žå¤–ç½®å­˜å‚¨ä¸­å¯¼å…¥å¤‡ä»½ã€‚ + å¯¼å…¥å¤‡ä»½å¤±è´¥ï¼Œè¯·æ£€æŸ¥æ ¼å¼æ˜¯å¦æ­£ç¡®ã€‚æŸ¥çœ‹æ—¥å¿—æ–‡ä»¶ä»¥èŽ·å–æ›´å¤šä¿¡æ¯ã€‚ + 正在导出… + æˆåŠŸå°†å¤‡ä»½å¯¼å‡ºåˆ°ä½ çš„å¤–éƒ¨å­˜å‚¨ä¸Šçš„æ–‡ä»¶ \"%s\" + 备份文件 \"%s\" 导出失败 + + + hosts 文件 + hosts æ–‡ä»¶æ˜¯ä¸€ä¸ªå°†ä¸»æœºåæ˜ å°„到 IP 地å€çš„系统文件。它是一个纯文本文件,由 AdAway 处ç†ã€é…置。这是它的å‰å‡ è¡Œï¼š + 正在加载 hosts 文件内容… + 打开 hosts 文件 + + + 检查更新 + æ­£åœ¨ä¸ºæ¥æº %s 检查更新 + æ­£åœ¨æ£€ç´¢æ¥æº + æ­£åœ¨ä¸‹è½½æ¥æº %s + æ­£åœ¨è¯»å–æ¥æº %s + æ­£åœ¨å¤„ç†æ¥æº %s + æ­£åœ¨åŒæ­¥è§„则数æ®åº“ + 正在æ¢å¤ä¸ºé»˜è®¤ hosts 文件 + å·²æ¢å¤ä¸ºé»˜è®¤ hosts 文件 + 创建标准 hosts 文件 + 有更新å¯ç”¨ + 有新的 hosts 文件å¯ç”¨ + 暂无更新 + 没有网络连接 + 没有å¯ç”¨çš„网络连接 + ä¸å¯ç”¨çš„æ¥æº + 没有å¯è®¿é—®çš„ hosts æºï¼ + Root æƒé™è¢«æ‹’ç» + 请从您的 root æƒé™ç®¡ç†å™¨ä¸º AdAway 授予 root æƒé™ + å‘生了一些错误 + 检查 logcat ä»¥èŽ·å–æ›´å¤šè¯¦ç»†ä¿¡æ¯ + å·²å¯ç”¨ + å·²å¯ç”¨æœ€æ–°çš„ hosts 文件 + å·²ç¦ç”¨ + 已安装默认 hosts 文件 + æ›´æ–°æ¥æº + 正在创建新 hosts 文件 + 正在å¤åˆ¶æ–° hosts 文件 + 正在检查 hosts 文件副本 + å·²æˆåŠŸæ›´æ–° hosts 文件 + å·²æˆåŠŸæ›´æ–° VPN é…ç½® + 您的é…置已更改。 您需è¦åº”用它。 + 应用 + 正在应用新é…置… + 无法应用新é…置。 + + + æŒ‡å‘ hosts 文件目标的符å·é“¾æŽ¥ç¼ºå¤± + /system/etc/hosts 的符å·é“¾æŽ¥ä¸å­˜åœ¨æˆ–è€…ä¸æ­£ç¡®ï¼AdAway 将无法è¿è¡Œã€‚\n\n是å¦å°è¯•创建符å·é“¾æŽ¥ï¼Ÿ + 符å·é“¾æŽ¥ä¸¢å¤± + åˆ†åŒºä¸Šæ²¡æœ‰è¶³å¤Ÿçš„ç©ºé—´ï¼ +请å°è¯•将首选项中的目标 hosts 文件更改为 /data/data/hosts。 + 没有足够的空间 + 无法读å–已下载的文件。 + 文件æƒé™èŽ·å–失败 + 挂载分区为读/å†™å¤±è´¥ï¼ + 挂载失败 + 无法å¤åˆ¶ hosts 文件 + hosts 文件å¤åˆ¶å¤±è´¥ï¼ + å¤åˆ¶å¤±è´¥ + 已应用的 hosts æ¥æº + 应用æˆåŠŸ + 应用æˆåŠŸã€‚\nå¯èƒ½éœ€è¦é‡å¯ Android 系统æ‰èƒ½ä½¿æ›´æ”¹ç”Ÿæ•ˆã€‚\n\n是å¦é‡æ–°å¯åŠ¨ï¼Ÿ\n(为防止数æ®ä¸¢å¤±ï¼Œè¯·ç¡®ä¿ç›®å‰æ²¡æœ‰ä»»ä½•åº”ç”¨ç¨‹åºæ­£åœ¨ä½¿ç”¨SDå¡ï¼ï¼‰ + 符å·é“¾æŽ¥åˆ›å»ºæˆåŠŸã€‚\nå¯èƒ½éœ€è¦é‡å¯ Android 系统æ‰èƒ½ä½¿æ›´æ”¹ç”Ÿæ•ˆã€‚\n\n是å¦é‡æ–°å¯åŠ¨ï¼Ÿ\n(为防止数æ®ä¸¢å¤±ï¼Œè¯·ç¡®ä¿ç›®å‰æ²¡æœ‰ä»»ä½•åº”ç”¨ç¨‹åºæ­£åœ¨ä½¿ç”¨SDå¡ï¼ï¼‰ + 符å·é“¾æŽ¥åˆ›å»ºæˆåŠŸ + Android 无法创建符å·é“¾æŽ¥ã€‚\n失败的常è§åŽŸå› æ˜¯ HTC çš„ S-ON 的功能。\n\n一个解决方案是é‡å¯è®¾å¤‡åˆ°æ¢å¤æ¨¡å¼ï¼Œå¹¶ä½¿ç”¨å¦‚下命令创建符å·é“¾æŽ¥ï¼š\'ln -s /data/data/hosts /system/etc/hosts\'。\n\n如果这ä¸èµ·ä½œç”¨ï¼Œè¯·æœç´¢å¦‚ä½•å°†æ‚¨çš„è®¾å¤‡è®¾æˆ S-OFF。\n\n译者注:这是 2015 å¹´çš„äº‹æƒ…äº†ï¼ŒçŽ°åœ¨åŸºæœ¬å·²ç»æ²¡æœ‰ S-ON 了。 + 符å·é“¾æŽ¥åˆ›å»ºå¤±è´¥ + è¯·é˜…è¯»å¸®åŠ©ä»¥èŽ·å–æ›´å¤šä¿¡æ¯ã€‚ + 您的设备设置了 APN 代ç†ï¼\n当在 3G 等移动网络上时,AdAway 将无法å¯é åœ°å·¥ä½œã€‚您å¯ä»¥å°è¯•ç¦ç”¨ APN 代ç†ï¼šè¿›å…¥æ‚¨é€‰æ‹©çš„ APN(设置 -> 网络和移动网络 -> 高级 -> 接入点å称),并删除“代ç†â€å­—段中的值。 + 已设置 APN 代ç†ï¼ + 网络连接缓慢。 + 没有连接 + 正在下载… + 正在应用… + 正在应用黑åå•与白åå• + 正在解æžã€åˆå¹¶ hosts 文件 + 正在构建 hosts 文件 + 正在应用 hosts 文件 + 无法应用新 hosts 文件。 + å°† hosts 文件应用至系统时失败ï¼\n请å°è¯•将首选项中的目标 hosts 文件更改为 /data/data/hosts。 + 应用失败 + 请检查您的 root æƒé™ç®¡ç†å™¨ï¼Œç¡®ä¿å·²æŽˆäºˆ AdAway root 访问æƒé™ã€‚ + 已还原默认 hosts 文件。\nå¯èƒ½éœ€è¦é‡å¯ Android 系统æ‰èƒ½ä½¿æ›´æ”¹ç”Ÿæ•ˆã€‚\n\n是å¦é‡æ–°å¯åŠ¨ï¼Ÿ\n(为防止数æ®ä¸¢å¤±ï¼Œè¯·ç¡®ä¿ç›®å‰æ²¡æœ‰ä»»ä½•åº”ç”¨ç¨‹åºæ­£åœ¨ä½¿ç”¨SDå¡ï¼ï¼‰ + æ¢å¤æˆåŠŸ + 无法还原 hosts 文件 + 由于未知原因,æ¢å¤å¤±è´¥ã€‚ + æ¢å¤å¤±è´¥ï¼ + å·²å¯ç”¨çš„ hosts æºå‡æ— æ³•è®¿é—®ï¼æ‚¨æ˜¯å¦å·²è¿žæŽ¥åˆ°äº’è”网? + 下载失败 + 无法写入新的ç§äºº hosts 文件 + æ— æ³•åˆ›å»ºç§æœ‰æ–‡ä»¶ã€‚ + ç§æœ‰æ–‡ä»¶åˆ›å»ºå¤±è´¥ + systemless 模å¼å·²å¯ç”¨ã€‚\nå¯èƒ½éœ€è¦é‡å¯ Android 系统æ‰èƒ½ä½¿æ›´æ”¹ç”Ÿæ•ˆã€‚\n\n是å¦é‡æ–°å¯åŠ¨ï¼Ÿ\n(为防止数æ®ä¸¢å¤±ï¼Œè¯·ç¡®ä¿ç›®å‰æ²¡æœ‰ä»»ä½•åº”ç”¨ç¨‹åºæ­£åœ¨ä½¿ç”¨SDå¡ï¼ï¼‰ + å¯ç”¨æˆåŠŸ + systemless 模å¼å·²ç¦ç”¨ã€‚\nå¯èƒ½éœ€è¦é‡å¯ Android 系统æ‰èƒ½ä½¿æ›´æ”¹ç”Ÿæ•ˆã€‚\n\n是å¦é‡æ–°å¯åŠ¨ï¼Ÿ\n(为防止数æ®ä¸¢å¤±ï¼Œè¯·ç¡®ä¿ç›®å‰æ²¡æœ‰ä»»ä½•åº”ç”¨ç¨‹åºæ­£åœ¨ä½¿ç”¨SDå¡ï¼ï¼‰ + ç¦ç”¨æˆåŠŸ + 无法å¯ç”¨ VPN 广告拦截。 + 无法ç¦ç”¨ VPN 广告拦截。 + å¯ç”¨ Magisk hosts æ¨¡å— + 请从 Magisk Manager 中å¯ç”¨ systemless hosts 特性。从 Magisk Manager 设置中å¯ç”¨Systemless Hosts功能,并é‡å¯è®¾å¤‡ã€‚ + ç¦ç”¨ Magisk hosts æ¨¡å— + 请在 Magisk Manager 中ç¦ç”¨ systemless hosts 特性。从模å—列表中å¸è½½Systemless Hosts模å—,并é‡å¯è®¾å¤‡ã€‚ + + + 输入 hosts 文件网å€ï¼š + ä¸»æœºåæ— æ•ˆï¼ + ä¸»æœºåæ ¼å¼ä¸æ­£ç¡® + IP åœ°å€æ— æ•ˆï¼ + IP åœ°å€æ ¼å¼ä¸æ­£ç¡® + 从ä¸é‡å¯ï¼Œä¸”ä¸å†æ˜¾ç¤ºæ­¤ä¿¡æ¯ï¼ + 正在加载… + + + 刷新 + 添加 + 帮助 + 导入备份 + 导出备份 + + + S-ON/S-OFF + 常问问题 + 其他问题 + + + 广告软件 + 在这里,你å¯ä»¥æ‰¾åˆ°å·²å®‰è£…的广告软件,AdAway 无法对其进行有效的广告å±è”½ã€‚比如说,这些应用程åºå¯èƒ½ä¼šåœ¨æ²¡æœ‰è¿è¡Œçš„æ—¶å€™å¼¹å‡º Airpush 通知,甚至改å˜é€šçŸ¥é“ƒå£°ã€‚唯一å¯è¡Œçš„对策是,通过点击下é¢çš„列表项,å¸è½½è¿™äº›åº”用程åºã€‚ + 正在扫æâ€¦ + æ²¡æœ‰å·²çŸ¥çš„å¹¿å‘Šè½¯ä»¶ï¼ + + + 广告拦截器 + 没有安装文本编辑器 + 找ä¸åˆ°æ–‡æœ¬ç¼–辑器,无法打开 hosts 文件。\n您å¯ä»¥å®‰è£… Jota 或其他文本编辑器æ¥è§£å†³æ­¤é—®é¢˜ã€‚\n\n是å¦å®‰è£… Jota 文本编辑器? + 没有安装文件管ç†å™¨ + 找ä¸åˆ°æ–‡ä»¶ç®¡ç†å™¨ï¼Œæ— æ³•打开文件。\n您å¯ä»¥å®‰è£… OI 文件管ç†å™¨æˆ–其他文件管ç†å™¨æ¥è§£å†³æ­¤é—®é¢˜ã€‚\n\n是å¦å®‰è£… OI 文件管ç†å™¨ï¼Ÿ + + + Tcpdump + Tcpdump 是一ç§ç›‘控 DNS 请求并将其ä¿å­˜åœ¨æ—¥å¿—文件中的工具。您å¯ä»¥å…ˆåœ¨åŽå°å¯åŠ¨å®ƒï¼Œå†è¿è¡Œå«æœ‰å¹¿å‘Šçš„应用,然åŽé€šè¿‡æ—¥å¿—文件分æžå¹¿å‘Šçš„ DNS 请求,最åŽå°†å¯èƒ½çš„广告æœåŠ¡å™¨æ·»åŠ åˆ°æ‚¨çš„è‡ªå®šä¹‰é»‘åå•中。 + ç¦ç”¨ç›‘控 + å¯ç”¨ç›‘控 + 显示结果 + 排åºåŸŸå + 清除日志 + 添加æ¡ç›®åˆ°é»‘åå• + 添加æ¡ç›®åˆ°ç™½åå• + 添加æ¡ç›®åˆ°é‡å®šå‘ + + 编辑文本首选项值 + 打开èœå• + 关闭èœå• + + + + 主页 + Hosts æ¥æº + 列表 + 打开 hosts 文件 + 记录 DNS 请求 + 扫æå¹¿å‘Šè½¯ä»¶ + 首选项 + 帮助 + + + + + DNS 请求 + 列表 + 首选项 + + + æœ€åŽæ›´æ–°äºŽ %1$så‰ + æ— éœ€æ›´æ–°ï¼Œæœ€åŽæ›´æ–°äºŽ %1$så‰ + éœ€è¦æ›´æ–°ï¼Œæœ€åŽæ›´æ–°äºŽ %1$så‰ + æœ€åŽæ›´æ–°äºŽ %1$så‰ + æ›´æ–°çŠ¶æ€æœªçŸ¥ + å·²ç¦ç”¨ + 几分钟 + + %d 分钟 + + + %d å°æ—¶ + + + %d 天 + + + %d 个月 + + + + Hosts å·²å¤åˆ¶åˆ°å‰ªè´´æ¿ + + + 开始 + 活跃 + åœæ­¢ + 等待网络 + 釿–°è¿žæŽ¥ + 釿–°è¿žæŽ¥é”™è¯¯ + å·²æš‚åœ + å·²åœæ­¢ + VPN 广告拦截器 %1$s + æš‚åœ + æ¢å¤ + + + AdAway æƒé™ + å…许与 AdAway 交互 + å‘ AdAway å‘é€å‘½ä»¤ + å…è®¸å‘ AdAway å‘é€å‘½ä»¤ï¼Œä¾‹å¦‚å¯ç”¨æˆ–ç¦ç”¨ç³»ç»Ÿçº§å¹¿å‘Šæ‹¦æˆª + + diff --git a/app/src/main/res/values-zh/strings_app.xml b/app/src/main/res/values-zh/strings_app.xml new file mode 100644 index 0000000..484d66e --- /dev/null +++ b/app/src/main/res/values-zh/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + å¼€æºå¹¿å‘Šæ‹¦æˆªå™¨ + AdAway 徽标 + diff --git a/app/src/main/res/values-zh/strings_errors.xml b/app/src/main/res/values-zh/strings_errors.xml new file mode 100644 index 0000000..0f1fb50 --- /dev/null +++ b/app/src/main/res/values-zh/strings_errors.xml @@ -0,0 +1,22 @@ + + + + 没有网络连接 + 无法建立与Internet的连接。 请检查您的设备连接。 + 无法下载 hosts æ¥æº + 您所有å¯ç”¨çš„hostsæºå‡æ— æ³•访问。 请检查您是å¦å·²æ­£ç¡®è¿žæŽ¥åˆ°Internet。 + + 无法创建ç§äºº hosts 文件 + æ— æ³•åˆ›å»ºç§æœ‰æ–‡ä»¶ä»¥æž„建新的hostsæºã€‚ 请检查设备上的å¯ç”¨ç©ºé—´ã€‚ + 没有足够的空间 + 无法将hosts文件å¤åˆ¶åˆ°ç³»ç»Ÿåˆ†åŒºã€‚ 请检查Magisk systemless moduleå·²å¯ç”¨ï¼Œç„¶åŽé‡æ–°å¯åŠ¨ã€‚ + 无法安装新的hosts文件 + 无法将主机文件å¤åˆ¶åˆ°/系统分区。请检查 Magisk sytemless æ¨¡å—æ˜¯å¦å¯ç”¨ï¼Œç„¶åŽé‡æ–°å¯åŠ¨ã€‚ + 无法还原hosts文件 + 无法还原默认hosts文件é…置。 + + 无法å¯ç”¨VPN广告拦截。 + 请检查您的VPN设置以授æƒå¯åŠ¨åº”ç”¨ç¨‹åºVPN。 + 无法ç¦ç”¨VPN广告拦截器。 + 请检查您的VPN设置以手动将其ç¦ç”¨ã€‚ + diff --git a/app/src/main/res/values-zh/strings_home.xml b/app/src/main/res/values-zh/strings_home.xml new file mode 100644 index 0000000..ba9fbf8 --- /dev/null +++ b/app/src/main/res/values-zh/strings_home.xml @@ -0,0 +1,44 @@ + + + + + 阻止 + å…许 + é‡å®šå‘ + + + + %d ä¸ªå·²æ›´æ–°æ¥æº + + + %d ä¸ªéœ€æ›´æ–°æ¥æº + + 检查主机文件更新 + æ›´æ–° hosts + + + 显示 DNS 请求记录 + + + 显示帮助\nå’Œæç¤º + + + 打开 GitHub é¡µé¢ + + + æ”¯æŒæœ¬é¡¹ç›® + + + Github 项目 + 首选项 + + + 打开导航抽屉 + æš‚åœ/æ¢å¤å¹¿å‘Šå±è”½ + 更新被阻止的域å + 显示请求的域å + + + è¯·é˜…è¯»å¸®åŠ©ä»¥èŽ·å–æ›´å¤šä¿¡æ¯ã€‚ + + \ No newline at end of file diff --git a/app/src/main/res/values-zh/strings_hosts.xml b/app/src/main/res/values-zh/strings_hosts.xml new file mode 100644 index 0000000..8de7b97 --- /dev/null +++ b/app/src/main/res/values-zh/strings_hosts.xml @@ -0,0 +1,17 @@ + + + hosts æ¥æº + + 用户列表 + AdAway 官方 hosts + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + 无法使用 + %s hosts + + æ·»åŠ æ¥æº + ç¼–è¾‘æ¥æº + URL:(以 https:// 或 file:// 开头) + hosts 链接 + diff --git a/app/src/main/res/values-zh/strings_lists.xml b/app/src/main/res/values-zh/strings_lists.xml new file mode 100644 index 0000000..3cd69d5 --- /dev/null +++ b/app/src/main/res/values-zh/strings_lists.xml @@ -0,0 +1,24 @@ + + + 用户列表 + 添加 host + + 阻止 + å…许 + é‡å®šå‘ + + 过滤 hosts + æœç´¢ä¸»æœºå… + åˆ‡æ¢æº + + 将主机添加到黑åå• + 将主机添加到白åå• + 将主机添加到é‡å®šå‘ + 编辑黑åå•主机 + 编辑白åå•主机 + 编辑é‡å®šå‘ + 主机å: + hosts 链接 + (å…许使用通é…符 * å’Œ ? ) + IP 地å€ï¼ˆIPv4 或 IPv6): + diff --git a/app/src/main/res/values-zh/strings_log.xml b/app/src/main/res/values-zh/strings_log.xml new file mode 100644 index 0000000..0d3d0c1 --- /dev/null +++ b/app/src/main/res/values-zh/strings_log.xml @@ -0,0 +1,11 @@ + + + åˆ‡æ¢æ—¥å¿—记录开å¯çŠ¶æ€ + 按下录制按钮以开始记录请求,æµè§ˆç½‘页或使用应用程åºï¼Œç„¶åŽè¿”回或滑动å±å¹•刷新日志。 + \n\n被拦截的请求ä¸ä¼šè¢«è®°å½•。如果你也想记录它们,请先ç¦ç”¨å¹¿å‘Šæ‹¦æˆªåŠŸèƒ½ã€‚ + + æŒ‰å­—æ¯æŽ’åº + æŒ‰é¡¶çº§åŸŸåæŽ’åº + + é‡å®šå‘域å + diff --git a/app/src/main/res/values-zh/strings_notification.xml b/app/src/main/res/values-zh/strings_notification.xml new file mode 100644 index 0000000..daa434b --- /dev/null +++ b/app/src/main/res/values-zh/strings_notification.xml @@ -0,0 +1,13 @@ + + + + æ›´æ–° + 更新通知 + 有更新å¯ç”¨ + 有新 hosts 文件å¯ä¾›ä¸‹è½½ã€‚ + 应用更新å¯ç”¨ + AdAway 有新版本了。 + + VPN + VPN è¿è¡Œé€šçŸ¥ + \ No newline at end of file diff --git a/app/src/main/res/values-zh/strings_prefs_backup_restore.xml b/app/src/main/res/values-zh/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..10d678f --- /dev/null +++ b/app/src/main/res/values-zh/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + 备份与还原 + 备份 + å°†å±è”½è§„则备份至外部存储 + 还原 + 从备份文件还原å±è”½è§„则 + diff --git a/app/src/main/res/values-zh/strings_prefs_main.xml b/app/src/main/res/values-zh/strings_prefs_main.xml new file mode 100644 index 0000000..d7284a5 --- /dev/null +++ b/app/src/main/res/values-zh/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + 首选项 + + 常规 + 深色主题 + + 浅色 + 深色 + 系统默认 + + 自动更新 + + 广告å±è”½ + 基于 root 的广告拦截器 + 基于 VPN 的广告拦截器 + å¯ç”¨ IPv6 æ”¯æŒ + 备份/还原å±è”½è§„则 + + 调试 + å¯ç”¨å´©æºƒæŠ¥å‘Š + å…许本应用程åºå‘ Sentry(sentry.io)å‘é€é”™è¯¯ä¸Žå´©æºƒæŠ¥å‘Šã€‚ + æ­¤ç‰ˆæœ¬ä¸æ”¯æŒ + å¯ç”¨è¯¦ç»†æ—¥å¿— + 具体的日志级别为 verbose,需é‡å¯ AdAway æ‰èƒ½ä½¿æ­¤è®¾ç½®ç”Ÿæ•ˆã€‚ + diff --git a/app/src/main/res/values-zh/strings_prefs_root.xml b/app/src/main/res/values-zh/strings_prefs_root.xml new file mode 100644 index 0000000..f1bf3a9 --- /dev/null +++ b/app/src/main/res/values-zh/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + 基于Root的广告拦截器 + + hosts安装 + 打开 hosts 文件 + 目标 hosts 文件 + 在更改此设置之å‰ï¼Œè¯·é˜…读有关此功能的帮助æ¡ç›®ã€‚ + + /system/etc/hosts + /data/hosts + /data/data/hosts + 自定义路径 + + 自定义 hosts 文件路径 + éšè—é‡å¯å¯¹è¯æ¡† + + é‡å®šå‘ + 定义é‡å®šå‘被阻止hostsçš„ä½ç½® + IPv4 é‡å®šå‘ + IPv6 é‡å®šå‘ + 无效的é‡å®šå‘ + + 本地网络æœåС噍 + 本地WebæœåС噍侦嬿œ¬åœ°IP 地å€ï¼Œä»¥å›žç­”被阻止的主机å请求。 它å¯èƒ½æœ‰åŠ©äºŽé˜»æ­¢è¿žæŽ¥å†»ç»“çš„åº”ç”¨ç¨‹åºã€‚ + å¯ç”¨ç½‘络æœåС噍 + 测试网络æœåС噍 + 安装自签åè¯ä¹¦ + 手动安装è¯ä¹¦ + 自Android 11 (R) 起,应用程åºä¸èƒ½å†è‡ªåŠ¨å®‰è£…è¯ä¹¦é¢å‘机构(CA)。\n\n进入“安全â€è®¾ç½®ï¼Œâ€œåР坆&凭æ®â€ï¼ŒæŽ¥ç€â€œå®‰è£…一个è¯ä¹¦â€ã€‚从那里,选择“CA è¯ä¹¦â€å¹¶é€‰æ‹©æ–°å¯¼å‡ºçš„è¯ä¹¦æ–‡ä»¶ã€‚ + 打开\"安全\"设置 + 正在检查… + 未è¿è¡Œ + 正在è¿è¡Œï¼Œä½†æœªå®‰è£…è¯ä¹¦ + è¿è¡Œå¹¶å®‰è£…è¯ä¹¦ + 用应用程åºå›¾æ ‡æ›¿æ¢ç©ºç™½å¹¿å‘Šç©ºé—´ + diff --git a/app/src/main/res/values-zh/strings_prefs_update.xml b/app/src/main/res/values-zh/strings_prefs_update.xml new file mode 100644 index 0000000..d197868 --- /dev/null +++ b/app/src/main/res/values-zh/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + æ›´æ–° + 通知被ç¦ç”¨ + ä¸ä¼šæ˜¾ç¤ºåº”用通知。轻按å¯ç”¨å®ƒä»¬ã€‚ + + åº”ç”¨ç¨‹åºæ›´æ–° + å¯åŠ¨æ—¶æ£€æŸ¥æ›´æ–° + æ¯å¤©æ£€æŸ¥æ›´æ–° + 包括测试版 + + hosts æ›´æ–° + å¯åŠ¨æ—¶æ£€æŸ¥æ›´æ–° + 定时检查更新 + åŒæ­¥æ›´æ–°ï¼ˆSync on update) + 仅在连接至ä¸è®¡è´¹ç½‘ç»œæ—¶åŒæ­¥ + diff --git a/app/src/main/res/values-zh/strings_prefs_vpn.xml b/app/src/main/res/values-zh/strings_prefs_vpn.xml new file mode 100644 index 0000000..9116d0f --- /dev/null +++ b/app/src/main/res/values-zh/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + 基于 VPN 的广告拦截器 + + å¯åŠ¨æ—¶å¯ç”¨ + 监视连接 + 定期检查网络状æ€ä»¥ä¾¿åœ¨æ–­å¼€è¿žæŽ¥æ—¶é‡æ–°å¯åЍ VPN。 + + 排除的应用 + é…置哪些应用程åºä¸åº”使用 VPN,以防止其连接被错误阻止。 + æŽ’é™¤ç³»ç»Ÿåº”ç”¨ç¨‹åº + + æ—  + 除æµè§ˆå™¨ä»¥å¤–的所有应用 + 所有应用 + + æŽ’é™¤ç”¨æˆ·åº”ç”¨ç¨‹åº + + + 排除的应用 + 全选 + å–æ¶ˆå…¨é€‰ + 应用程åºå›¾æ ‡ + diff --git a/app/src/main/res/values-zh/strings_source_edit.xml b/app/src/main/res/values-zh/strings_source_edit.xml new file mode 100644 index 0000000..1f202e0 --- /dev/null +++ b/app/src/main/res/values-zh/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + ç¼–è¾‘æ¥æº + æ·»åŠ æ¥æº + + 标签 + éœ€è¦æ ‡ç­¾ + 类型 + URL + 文件 + ä½ç½® + https:// + 需è¦ä½ç½® + æŒ‰ä¸‹â€œæ–‡ä»¶â€æ¥é€‰æ‹©æºæ–‡ä»¶ + 无效的ä½ç½® + åˆ—è¡¨æ ¼å¼ + 拦截 + å…许 + 应用é‡å®šå‘ hosts + å…许é‡å®šå‘ hosts å¯èƒ½å¯¼è‡´å®‰å…¨é—®é¢˜ã€‚å› å…¶å¯èƒ½ä¼šå°†ä¸€äº›æ•感æµé‡é‡å®šå‘到任何它指定的æœåŠ¡å™¨ï¼Œè¯·åªå¯¹ä¿¡ä»»çš„æºä½¿ç”¨æ­¤è®¾ç½®ã€‚ + diff --git a/app/src/main/res/values-zh/strings_support.xml b/app/src/main/res/values-zh/strings_support.xml new file mode 100644 index 0000000..ac6d980 --- /dev/null +++ b/app/src/main/res/values-zh/strings_support.xml @@ -0,0 +1,5 @@ + + + æ”¯æŒ + æˆä¸ºä¸€å赞助者 + \ No newline at end of file diff --git a/app/src/main/res/values-zh/strings_update.xml b/app/src/main/res/values-zh/strings_update.xml new file mode 100644 index 0000000..9b0c48d --- /dev/null +++ b/app/src/main/res/values-zh/strings_update.xml @@ -0,0 +1,22 @@ + + + AdAway æ›´æ–° + + 有更新å¯ç”¨ï¼ + + + 您已安装最新版本 + 有更新å¯ç”¨ + 正在更新AdAway + ç«‹å³æ›´æ–° + %1$s/%2$s + 完毕 + 最近更改 + 更新日志 + 支æŒå¼€å‘ + æèµ  + 赞助者 + + + 正在下载最新AdAway版本… + diff --git a/app/src/main/res/values-zh/strings_welcome.xml b/app/src/main/res/values-zh/strings_welcome.xml new file mode 100644 index 0000000..ea95ff3 --- /dev/null +++ b/app/src/main/res/values-zh/strings_welcome.xml @@ -0,0 +1,53 @@ + + + 欢迎 + å‘导第一步 + å‘导第二部 + å‘导最åŽä¸€æ­¥ + + + 欢迎使用 AdAwayï¼ + AdAway æä¾›ä¸¤ç§å¹¿å‘Šå±è”½æ–¹æ³•。选择您喜欢的: + + Root logo + 基于Root 的广告å±è”½ + æ›´å¿« + 电池å‹å¥½ + éœ€è¦ root æƒé™ + + VPN logo + 基于 VPN 的广告å±è”½ + æ›´æ…¢ + åŽå°è¿è¡Œ + 兼容性强 + + 需è¦å·²èŽ·å¾— root æƒé™çš„ Android 设备 + 找ä¸åˆ° su 二进制文件,或者您没有为 AdAway 授予 root æƒé™ã€‚\n\n如果您的设备未获得 root æƒé™ï¼Œåˆ™å¯èƒ½ä¼šå‘ç”Ÿè¿™ç§æƒ…况。 您å¯ä»¥åœ¨ wiki.lineageos.org 或其他 Android 网站上找到有关如何将设备 root 的信æ¯ã€‚ + + 优点 + 缺点 + + + åŒæ­¥å®Œæˆ + åŒæ­¥å‡ºé”™ + + æ­£åœ¨åŒæ­¥ + å·²åŒæ­¥ï¼ + AdAway ä¼šä»Žåœ¨çº¿æ¥æºä¸‹è½½å¹¿å‘Šç½‘络的数æ®ä»¥ä¾¿å±è”½ã€‚ 您ç¨åŽå¯ä»¥åœ¨è®¾ç½®ä¸­è‡ªå®šä¹‰å®ƒä»¬ã€‚ + 釿–°åŒæ­¥ + åŒæ­¥å¤±è´¥ï¼š%1$s ç«‹å³é‡è¯•å—? + 它å¯ä»¥å‘é€é€šçŸ¥å±•示广告拦截状æ€å’ŒæŽ§åˆ¶ï¼Œå¹¶æç¤ºå¯ç”¨çš„应用更新(æ¯å¹´å‡ æ¬¡ï¼‰ã€‚å¦‚ä½ æƒ³ä¿æŒæœ€æ–°ç‰ˆæœ¬ï¼Œè¯·å¯ç”¨å®ƒä»¬ã€‚ + + + æ”¯æŒ + æ”¯æŒæˆ‘ï¼ + AdAway 是一款我利用业余时间开å‘的自由开æºåº”ç”¨ã€‚å¦‚æžœä½ å–œæ¬¢å®ƒï¼Œè¯·éšæ—¶è¡¨è¾¾ä½ çš„æ”¯æŒï¼š + 通过 PayPal æèµ  + 你喜欢 bug å—?我也ä¸å–œæ¬¢ã€‚ + å¯ç”¨é¥æµ‹ï¼Œå‘我å‘é€å´©æºƒæŠ¥å‘Š + + + åŽé€€ + å‰è¿› + å®Œæˆ + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..93993b3 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,23 @@ + + + + #ef5350 + #e53935 + #000000 + + #B71C1C + + #FF5252 + #64FFDA + #536DFE + + #78b71c1c + #f5f5f5 + #3F000000 + + #FF424242 + #388E3C + #B71C1C + + #b71c1c + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..28b4e8a --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,10 @@ + + + 8dp + + 8dp + 16dp + + 16dp + 16dp + diff --git a/app/src/main/res/values/preferences.xml b/app/src/main/res/values/preferences.xml new file mode 100644 index 0000000..d19e132 --- /dev/null +++ b/app/src/main/res/values/preferences.xml @@ -0,0 +1,70 @@ + + + darkThemeMode + MODE_NIGHT_YES + + MODE_NIGHT_NO + MODE_NIGHT_YES + MODE_NIGHT_FOLLOW_SYSTEM + + updateCheck + true + neverReboot + false + enableIpv6 + false + updateCheckAppStartup + true + openNotificationPreferences + updateCheckAppDaily + true + includeBetaReleases + false + updateCheckHostsDaily + true + automaticUpdateDaily + true + updateOnlyOnWifi + false + redirectionIP + 127.0.0.1 + redirectionIPv6 + ::1 + openHosts + writeToSystem + customTarget + /data/etc/hosts + webserverEnabled + true + webserverTest + webserverCertificate + webserverIcon + true + adBlockMethod + 0 + rootAdBlockMethod + vpnAdBlockMethod + vpnPaused + 0 + vpnOnBoot + true + vpnWatchdog + false + debugEnabled + false + enableTelemetry + false + displayTelemetryConsent + true + backup + restore + excludeSystemAppFromVpn + none + + none + allExceptBrowsers + all + + excludeUserAppFromVpn + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..dc42208 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,262 @@ + + + + Exit + Close + Yes + No + Add + Cancel + Save + Help + + + Welcome! + AdAway is a free and open-source software design to block advertising. It fetches advertising network addresses to block them on your device.\nWant to know more? Check the help below! + Show more help + Update status + All hosts files from the defined sources are downloaded, merged with your own lists and installed as one hosts file on your system. + Enable ad-blocking + Disable ad-blocking + Web server + Running + Stopped + Start or stop webserver on localhost to answer requests to blocked hostnames. + Enable web server + Disable web server + VPN + Running + Stopped + Start or stop VPN to filter requests. + Enable VPN + Disable VPN + + + Edit Entry + Apply + Edit + Delete + + + Importing… + Backup successfully imported from your external storage. + Failed to import backup. Is its format correct? Check logcat for more details. + Exporting… + Backup successfully exported to file \'%s\' on your external storage. + Failed to export backup file \'%s\'. + + + The hosts file + The hosts file is a system file that maps hostnames to IP addresses. It is a plain text file which configuration is handled by AdAway. Here are its few first lines: + Loading the hosts file content… + Open the hosts file + + + Checking for update + Checking %s source for update + Retrieving sources + Downloading source %s + Reading source %s + Parsing %s source + Syncing rule database + Reverting to default hosts file + Default hosts file restored + Creating standard hosts file + Source update available + Newer hosts files available + No source update found + No Internet connection + No Internet connection available + Unavailable sources + No hosts sources are reachable! + Root access denied + Allow root access from your root app + Something went wrong + Check the logcat for more details + Enabled + Newest hosts files enabled + Disabled + Default hosts file installed + Apply latest sources + Creating a new hosts file + Copying a new hosts file + Checking hosts file copy + Hosts file successfully updated + VPN configuration successfully updated + Your configuration changed. You need to apply it. + Apply + Applying new configuration… + Failed to apply new configuration. + + + The symlink to the hosts file target is missing + Symlink from your target to /system/etc/hosts is not existing or incorrect! AdAway will not work if it is not pointing to the right file.\n\nDo you want to try creating a symlink? + Symlink missing + Not enough space on the partition!\nTry changing the target hosts file in preferences to /data/data/hosts. + Not enough space + Downloaded file could not be read. + Private file fail + Remounting the partition as read/write failed! + Remount failed + Failed to copy hosts file + Copying of hosts file failed! + Copy failed + Applied hosts sources + Applying successful + Applying was successful.\nIt may be necessary to reboot Android for the changes to take effect.\n\nDo you want to reboot?\n(To prevent data loss make sure no app uses the SD card at the moment!) + Symlink was created successful.\nIt may be necessary to reboot Android for the changes to take effect.\n\nDo you want to reboot?\n(To prevent data loss make sure no app uses the SD card at the moment!) + Symlink creation successful + Symlink could not be created by Android.\nThis fails mostly due to a \'feature\' called S-ON on HTC phones!\n\nA solution is to boot your phone into recovery mode and create the symlink there with \'ln -s /data/data/hosts /system/etc/hosts\'.\n\nIf this does not work search the Internet for S-OFF and your phone. + Symlink creation failed + Please read Help for more information. + An APN proxy is set on your Android!\nAdAway will not work reliably when on Mobile Networks like 3G. You can deactivate that proxy by going to your selected APN (From the Settings app: Network & Internet -> Mobile network -> Advanced -> Access Point Names) and remove the value in the proxy field. + APN proxy set! + The connection to the Internet is not working. + No Connection + Downloading… + Applying… + Applying Blacklist and Whitelist + Parsing and merging hosts files + Building hosts file + Applying hosts file + Failed to apply new hosts file. + Applying the hosts file to your system failed!\nTry changing the target hosts file in preferences to /data/data/hosts. + Applying failed + Please check your root management app to ensure root access has been granted. + You reverted to the default hosts file.\nIt may be necessary to reboot Android for the changes to take effect.\n\nDo you want to reboot?\n(To prevent data loss make sure no app uses the SD card at the moment!) + Reverting successful + Unable to revert hosts file + Reverting failed due to unknown reasons. + Reverting failed! + None of your enabled hosts sources are reachable! Are you properly connected to the Internet? + Download failed + Failed to write new private hosts file + Private file can not be created. + Private file creation failed + You enabled systemless mode.\nIt may be necessary to reboot Android for the changes to take effect.\n\nDo you want to reboot?\n(To prevent data loss make sure no app uses the SD card at the moment!) + Enabling successful + You disabled systemless mode.\nIt may be necessary to reboot Android for the changes to take effect.\n\nDo you want to reboot?\n(To prevent data loss make sure no app uses the SD card at the moment!) + Disabling successful + Failed to enable VPN ad blocking. + Failed to disable VPN ad blocking. + Enabling hosts Magisk module + Enable systemless hosts feature from Magisk manager. From its settings, enable the Systemless hosts option then reboot your device. + Disabling hosts Magisk module + Disable systemless hosts feature from Magisk manager. From the module list, uninstall the Systemless hosts module then reboot your device. + + + Input URL to hosts file: + This is not a valid hostname! + Improperly formatted hostname + This is not a valid IP! + Improperly formatted IP + Never reboot and don\'t show this question next time! + Loading… + + + Refresh + Add + Help + Import backup + Export backup + + + S-ON/S-OFF + FAQ + Problems + + + Adware + Here you can find installed adware, bad applications which can\'t be blocked by AdAway. These apps use for example Airpush notifications that pop up even when the app is not running or even change your ringtone. The only available countermeasure is to uninstall those apps by clicking on the list items. + Scanning… + No Adware were found! + + + Ad blocker + No text editor installed + No text editor could be found to open the hosts file. You can install Jota or other text editors to handle this.\n\nDo you want to install Jota? + No file manager installed + No file manager could be found to open files. You can install OI File Manager or other file managers to handle this.\n\nDo you want to install OI File Manager? + + + Tcpdump + Tcpdump is a tool to monitor DNS requests and save them in a log file. You can start it in the background, run applications that display ads, and afterwards analyze the DNS requests using the log file. Possible ad server can then be added to your blacklist. + Disable monitoring + Enable monitoring + Show results + Sort domains + Clear log + Add entry to black list + Add entry to white list + Add entry to redirect list + + Edit text preference value + Open menu + Close menu + + + + Home + Hosts sources + Your lists + Open hosts file + Log DNS requests + Scan for adware + Preferences + Help + + + + + DNS requests + Your lists + Preferences + + + Installed %1$s ago + Up-to-date for %1$s + Need update for %1$s + Last update %1$s ago + Unknown update status + Disabled + few minutes + + %d minute + %d minutes + + + %d hour + %d hours + + + %d day + %d days + + + %d month + %d months + + + + Host copied to clipboard + + + starting + active + stopping + wait for network + reconnecting + reconnecting error + paused + stopped + Ad-blocker VPN %1$s + Pause + Resume + + + AdAway permissions + Allow to interact with AdAway + Send commands to AdAway + Allow to send commands to AdAway like enabling or disabling the system-wide ad-blocking + + diff --git a/app/src/main/res/values/strings_app.xml b/app/src/main/res/values/strings_app.xml new file mode 100644 index 0000000..af6a933 --- /dev/null +++ b/app/src/main/res/values/strings_app.xml @@ -0,0 +1,6 @@ + + + AdAway + Open Source ad blocker + AdAway logo + diff --git a/app/src/main/res/values/strings_errors.xml b/app/src/main/res/values/strings_errors.xml new file mode 100644 index 0000000..da703ab --- /dev/null +++ b/app/src/main/res/values/strings_errors.xml @@ -0,0 +1,22 @@ + + + + No Internet connection + Unable to establish a connection to the Internet. Please check your device connectivity. + Failed to download hosts source + None of your enabled hosts sources are reachable. Please check you are properly connected to the Internet. + + Failed to create private file + Unable to create a private file to build a new hosts source. Please check the free space available on your device. + Not enough space + Unable to copy hosts file to your system partition. Please check Magisk systemless module is enabled then reboot. + Failed to install new hosts file + Unable to copy hosts file to /system partition. Please check Magisk systemless module is enabled then reboot. + Failed to revert hosts file + Unable to restore default hosts file configuration. + + Failed to enable VPN ad blocking. + Please check your VPN settings to authorize the application VPN to start. + Failed to disable VPN ad blocking. + Please check your VPN settings to disable it manually. + diff --git a/app/src/main/res/values/strings_home.xml b/app/src/main/res/values/strings_home.xml new file mode 100644 index 0000000..d4feb49 --- /dev/null +++ b/app/src/main/res/values/strings_home.xml @@ -0,0 +1,46 @@ + + + + + Blocked + Allowed + Redirected + + + + %d up-to-date source + %d up-to-date sources + + + %d outdated source + %d outdated sources + + Check for hosts updates + Update hosts + + + Show DNS request log + + + Show help\nand tips + + + Open GitHub page + + + Support the project + + + GitHub project + Preferences + + + Open navigation drawer + Pause/resume ad blocking + Update blocked domains + Show requested domains + + + Please read Help for more information. + + \ No newline at end of file diff --git a/app/src/main/res/values/strings_hosts.xml b/app/src/main/res/values/strings_hosts.xml new file mode 100644 index 0000000..9708f7a --- /dev/null +++ b/app/src/main/res/values/strings_hosts.xml @@ -0,0 +1,17 @@ + + + Hosts sources + + User list + AdAway official hosts + StevenBlack Unified hosts + Pete Lowe blocklist hosts + + not available + %s hosts + + Add source + Edit source + URL: (a https:// or file:// resource) + The hosts source URL + diff --git a/app/src/main/res/values/strings_lists.xml b/app/src/main/res/values/strings_lists.xml new file mode 100644 index 0000000..d87d9e4 --- /dev/null +++ b/app/src/main/res/values/strings_lists.xml @@ -0,0 +1,24 @@ + + + Your lists + Add host + + Blocked + Allowed + Redirected + + Filter hosts + Search hostname… + Toggle sources + + Add host to blacklist + Add host to whitelist + Add host redirect + Edit blacklisted host + Edit whitelisted host + Edit redirect + Hostname: + The hosts source URL + (Wildcard characters * and ? are allowed) + IP (IPv4 or IPv6): + diff --git a/app/src/main/res/values/strings_log.xml b/app/src/main/res/values/strings_log.xml new file mode 100644 index 0000000..8e33945 --- /dev/null +++ b/app/src/main/res/values/strings_log.xml @@ -0,0 +1,11 @@ + + + Toggle log recording + Press record to start logging requests, browse the Web or use apps, then go back or swipe to refresh the logs. + \n\nBlocked requests will not be logged. Disable ad-blocking first if you want to log them too. + + Alphabetical sort + Top level domain sort + + Redirect domain + diff --git a/app/src/main/res/values/strings_notification.xml b/app/src/main/res/values/strings_notification.xml new file mode 100644 index 0000000..46c6770 --- /dev/null +++ b/app/src/main/res/values/strings_notification.xml @@ -0,0 +1,13 @@ + + + + Updates + New update notifications + Source update available + Newer hosts files available for download. + App update available + A new version of AdAway is available for download. + + VPN + VPN running notifications + \ No newline at end of file diff --git a/app/src/main/res/values/strings_prefs_backup_restore.xml b/app/src/main/res/values/strings_prefs_backup_restore.xml new file mode 100644 index 0000000..910b88b --- /dev/null +++ b/app/src/main/res/values/strings_prefs_backup_restore.xml @@ -0,0 +1,8 @@ + + + Backup & restore + Backup + Backup to external storage your block rules + Restore + Restore your block rules from backup file + diff --git a/app/src/main/res/values/strings_prefs_main.xml b/app/src/main/res/values/strings_prefs_main.xml new file mode 100644 index 0000000..ac8940e --- /dev/null +++ b/app/src/main/res/values/strings_prefs_main.xml @@ -0,0 +1,26 @@ + + + Preferences + + General + Dark theme + + Light + Dark + System default + + Automatic updates + + Ad blocking + Root based ad blocker + VPN based ad blocker + Enable IPv6 support + Backup / restore block rules + + Debug + Send crash reports + Report to Sentry (sentry.io) + Not supported on this build + Verbose logging + App restart is needed to apply + diff --git a/app/src/main/res/values/strings_prefs_root.xml b/app/src/main/res/values/strings_prefs_root.xml new file mode 100644 index 0000000..0f3ceaa --- /dev/null +++ b/app/src/main/res/values/strings_prefs_root.xml @@ -0,0 +1,37 @@ + + + Root based ad blocker + + Hosts install + Open hosts file + Target hosts file + Read Help before using this feature + + /system/etc/hosts + /data/hosts + /data/data/hosts + Custom target + + Custom target location + Hide reboot dialog after apply + + Redirection + Define where to redirect blocked hosts + Configure IPv4 redirection + Configure IPv6 redirection + Invalid redirection + + Local web server + The local web server listens on local IP addresses to answer to blocked hostname requests. It may help with app freezing on blocked connection. + Enable web server + Test web server + Install self-signed certificate + Certificate manual install + Starting from Android 11 (R), application can no more automatically install certificate authority (CA).\n\nGo to \"Security\" settings, \"Encryption & credentials\" then \"Install a certificate\". From there, choose \"CA certificate\" and select the newly exported certificate file. + Open "Security" settings + Checking… + Not running + Running but certificate not installed + Running and certificate installed + Replace blank ad space by app icon + diff --git a/app/src/main/res/values/strings_prefs_update.xml b/app/src/main/res/values/strings_prefs_update.xml new file mode 100644 index 0000000..b8150f3 --- /dev/null +++ b/app/src/main/res/values/strings_prefs_update.xml @@ -0,0 +1,17 @@ + + + Updates + Notifications are disabled + Application notifications won\'t show. Tap to enable them. + + Application updates + Check for update at startup + Periodically check for update + Include beta releases + + Hosts updates + Check for update at startup + Periodically check for update + Sync on update + Sync on unmetered network only + diff --git a/app/src/main/res/values/strings_prefs_vpn.xml b/app/src/main/res/values/strings_prefs_vpn.xml new file mode 100644 index 0000000..43102a4 --- /dev/null +++ b/app/src/main/res/values/strings_prefs_vpn.xml @@ -0,0 +1,24 @@ + + + VPN based ad blocker + + Enable at startup + Monitor connection + Periodically check the network state to restart VPN on disconnection. + + Excluded applications + Configure which applications should not use the VPN so no connections will be blocked. + Exclude system applications + + None + All except browsers + All + + Exclude user applications + + + Excluded applications + Select all + Deselect all + Application icon + diff --git a/app/src/main/res/values/strings_source_edit.xml b/app/src/main/res/values/strings_source_edit.xml new file mode 100644 index 0000000..9ea94be --- /dev/null +++ b/app/src/main/res/values/strings_source_edit.xml @@ -0,0 +1,21 @@ + + + Edit source + Add source + + Label + Label required + Type + URL + File + Location + https:// + Location required + Press File to select source file + Invalid location + List format + Block + Allow + Apply redirected hosts + Allowing redirected hosts may cause security issues. Only use this settings on a trusted source as it could redirect some sensitive traffic to whatever server it wants. + \ No newline at end of file diff --git a/app/src/main/res/values/strings_static.xml b/app/src/main/res/values/strings_static.xml new file mode 100644 index 0000000..dc2e060 --- /dev/null +++ b/app/src/main/res/values/strings_static.xml @@ -0,0 +1,5 @@ + + + https://wiki.lineageos.org/ + https:// + diff --git a/app/src/main/res/values/strings_support.xml b/app/src/main/res/values/strings_support.xml new file mode 100644 index 0000000..308ebf9 --- /dev/null +++ b/app/src/main/res/values/strings_support.xml @@ -0,0 +1,5 @@ + + + Support + Become a sponsor + \ No newline at end of file diff --git a/app/src/main/res/values/strings_update.xml b/app/src/main/res/values/strings_update.xml new file mode 100644 index 0000000..34b0984 --- /dev/null +++ b/app/src/main/res/values/strings_update.xml @@ -0,0 +1,22 @@ + + + AdAway update + + Update available! + + + You are up-to-date + Update available + Updating AdAway + Update now + %1$s / %2$s + Complete + Last changes + Changelog + Support development + Donate + Sponsor + + + Downloading latest AdAway version… + diff --git a/app/src/main/res/values/strings_welcome.xml b/app/src/main/res/values/strings_welcome.xml new file mode 100644 index 0000000..350f616 --- /dev/null +++ b/app/src/main/res/values/strings_welcome.xml @@ -0,0 +1,53 @@ + + + Welcome + Wizard first step + Wizard second step + Wizard last step + + + Welcome to AdAway! + AdAway provides two ad blocking methods. Pick the one you like: + + Root logo + Root based\nad blocking + Faster + Battery friendly + Root required + + VPN logo + VPN based\nad blocking + Slower + Run in background + Compatibility + + Rooted Android required + Either the su binary could not be found or you did not allow root permission for AdAway.\n\nThis can happen when your device is not rooted. You can find information about how to root your device on wiki.lineageos.org or other Android websites. + + Pro + Con + + + Sync done + Error during sync + + Syncing + Synced! + AdAway downloads ad networks to block from online sources. You can customize them later in the settings. + Retry sync + Failed to sync: %1$s Retry now? + It can send notifications to display ad block status and control, and to notify about available app update (a few per year). Enable them if you want to stay up-to-date. + + + Support + Support me! + AdAway is a free and open-source app that I develop on my free time. If you enjoy it, feel free to show your support: + Donate on PayPal + Do you like bugs? Me neither. + Enable telemetry to send me crash reports + + + Back + Next + Finish + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..72b5d99 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,41 @@ + + + + + + + + + diff --git a/app/src/main/res/xml/list_searchable.xml b/app/src/main/res/xml/list_searchable.xml new file mode 100644 index 0000000..c42d246 --- /dev/null +++ b/app/src/main/res/xml/list_searchable.xml @@ -0,0 +1,5 @@ + + diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..8177e15 --- /dev/null +++ b/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,9 @@ + + + + localhost + + + + + diff --git a/app/src/main/res/xml/preferences_backup_restore.xml b/app/src/main/res/xml/preferences_backup_restore.xml new file mode 100644 index 0000000..6807c82 --- /dev/null +++ b/app/src/main/res/xml/preferences_backup_restore.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/app/src/main/res/xml/preferences_main.xml b/app/src/main/res/xml/preferences_main.xml new file mode 100644 index 0000000..5c71b4b --- /dev/null +++ b/app/src/main/res/xml/preferences_main.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/preferences_root.xml b/app/src/main/res/xml/preferences_root.xml new file mode 100644 index 0000000..ad57d29 --- /dev/null +++ b/app/src/main/res/xml/preferences_root.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/preferences_update.xml b/app/src/main/res/xml/preferences_update.xml new file mode 100644 index 0000000..b341dff --- /dev/null +++ b/app/src/main/res/xml/preferences_update.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/preferences_vpn.xml b/app/src/main/res/xml/preferences_vpn.xml new file mode 100644 index 0000000..f3f82c0 --- /dev/null +++ b/app/src/main/res/xml/preferences_vpn.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml new file mode 100644 index 0000000..6812875 --- /dev/null +++ b/app/src/main/res/xml/shortcuts.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + diff --git a/app/src/test/java/org/adaway/model/git/GitHostsSourceTest.java b/app/src/test/java/org/adaway/model/git/GitHostsSourceTest.java new file mode 100644 index 0000000..319445f --- /dev/null +++ b/app/src/test/java/org/adaway/model/git/GitHostsSourceTest.java @@ -0,0 +1,86 @@ +package org.adaway.model.git; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.net.MalformedURLException; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.Collection; + +/** + * This class tests the git hosted source behavior. + * + * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com) + */ +@RunWith(Parameterized.class) +public class GitHostsSourceTest { + + private static final String GITHUB_HOST = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"; + private static final String GIST_HOST = "https://gist.githubusercontent.com/PerfectSlayer/a552900539d10271542063d67424b467/raw/56aabad791fbd085f4b9c5051a1dfa76b9a9d748/hosts"; + private static final String GITLAB_HOST = "https://gitlab.com/quidsup/notrack-blocklists/raw/master/notrack-blocklist.txt"; + + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList(new Object[][]{ + {"GitHub", GITHUB_HOST, GitHubHostsSource.class}, + {"Gist", GIST_HOST, GistHostsSource.class}, + {"GitLab", GITLAB_HOST, GitLabHostsSource.class} + }); + } + + private final String label; + private final String url; + private final Class expectedClass; + + /** + * Constructor. + * + * @param label The Git hosting label. + * @param url A git hosted file URL. + * @param expectedClass The expected git hosting strategy. + */ + public GitHostsSourceTest(String label, String url, Class expectedClass) { + this.label = label; + this.url = url; + this.expectedClass = expectedClass; + } + + /** + * Check the source is well detected as git hasted. + */ + @Test + public void testIsHostedOnGit() { + assertTrue( + "Git hosting for " + this.label + " was not detected", + GitHostsSource.isHostedOnGit(this.url) + ); + } + + /** + * Check to retrieve the last update date. + * Requires a network connection to the source. + */ + @Test + public void testLastUpdateFetch() { + try { + GitHostsSource source = GitHostsSource.getSource(this.url); + assertTrue( + "Invalid git hosting strategy for " + this.label, + this.expectedClass.isInstance(source) + ); + ZonedDateTime lastUpdate = source.getLastUpdate(); + assertNotNull( + "Failed to get last modified date of " + this.label + " host file", + lastUpdate + ); + } catch (MalformedURLException e) { + fail(e.getMessage()); + } + } +} diff --git a/app/src/test/java/org/adaway/model/source/SourceLoaderTest.java b/app/src/test/java/org/adaway/model/source/SourceLoaderTest.java new file mode 100644 index 0000000..a0a75c6 --- /dev/null +++ b/app/src/test/java/org/adaway/model/source/SourceLoaderTest.java @@ -0,0 +1,171 @@ +package org.adaway.model.source; + +import org.adaway.util.RegexUtils; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; + +import static org.adaway.model.source.SourceLoader.HOSTS_PARSER_PATTERN; +import static org.junit.Assert.*; + +public class SourceLoaderTest { + + // Test data comes from Guava InternetDomainName unit test + // https://github.com/google/guava/blob/master/android/guava-tests/test/com/google/common/net/InternetDomainNameTest.java + private static final String ALMOST_TOO_MANY_LEVELS = "a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a"; + private static final String ALMOST_TOO_LONG = "aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.aaaaa.a1234567890.c"; + private static final Set VALID_NAMES = new HashSet<>(); + private static final Set INVALID_NAMES = new HashSet<>(); + private static final Set VALID_WILDCARD_NAMES = new HashSet<>(); + private static final Set INVALID_WILDCARD_NAMES = new HashSet<>(); + + static { + VALID_NAMES.add("foo.com"); + VALID_NAMES.add("f-_-o.cOM"); + VALID_NAMES.add("f--1.com"); + VALID_NAMES.add("f11-1.com"); + VALID_NAMES.add("www"); + VALID_NAMES.add("abc.a23"); + VALID_NAMES.add("biz.com.ua"); + VALID_NAMES.add("x"); + VALID_NAMES.add("fOo"); + VALID_NAMES.add("f--o"); + VALID_NAMES.add("f_a"); + VALID_NAMES.add(ALMOST_TOO_MANY_LEVELS); + VALID_NAMES.add(ALMOST_TOO_LONG); + + INVALID_NAMES.add(""); + INVALID_NAMES.add(" "); + INVALID_NAMES.add("127.0.0.1"); + INVALID_NAMES.add("::1"); + INVALID_NAMES.add("13"); + INVALID_NAMES.add("abc.12c"); + INVALID_NAMES.add("foo-.com"); + INVALID_NAMES.add("_bar.quux"); + INVALID_NAMES.add("foo+bar.com"); + INVALID_NAMES.add("foo!bar.com"); + INVALID_NAMES.add(".foo.com"); + INVALID_NAMES.add("..bar.com"); + INVALID_NAMES.add("baz..com"); + INVALID_NAMES.add("..quiffle.com"); + INVALID_NAMES.add("fleeb.com.."); + INVALID_NAMES.add("."); + INVALID_NAMES.add(".."); + INVALID_NAMES.add("..."); + INVALID_NAMES.add("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com"); + INVALID_NAMES.add(ALMOST_TOO_MANY_LEVELS + ".com"); + INVALID_NAMES.add(ALMOST_TOO_LONG + ".d"); + + // The following are generally valid if the wildcards match at least against a single [a-zA-Z], + // or even [a-zA-Z0-9] in some circumstances. + // However, keep in mind that they can also match against invalid host names, like when matching a + // single [-_.] or empty string. But, because this is a white list, this is not an issue for us. + VALID_WILDCARD_NAMES.add("*.example.com"); + VALID_WILDCARD_NAMES.add("?.example.com"); + VALID_WILDCARD_NAMES.add("*-example.com"); + VALID_WILDCARD_NAMES.add("?-example.com"); + VALID_WILDCARD_NAMES.add("*_example.com"); + VALID_WILDCARD_NAMES.add("?_example.com"); + VALID_WILDCARD_NAMES.add("example.*"); + VALID_WILDCARD_NAMES.add("example.?"); + VALID_WILDCARD_NAMES.add("example-*"); + VALID_WILDCARD_NAMES.add("example-?"); + VALID_WILDCARD_NAMES.add("example_*"); + VALID_WILDCARD_NAMES.add("example_?"); + VALID_WILDCARD_NAMES.add("sub.*.example.com"); + VALID_WILDCARD_NAMES.add("sub.?.example.com"); + VALID_WILDCARD_NAMES.add("f--?.com"); + VALID_WILDCARD_NAMES.add("*"); + VALID_WILDCARD_NAMES.add("?"); + + // The following cannot be valid in any circumstance, because they can never match against a valid host name. + INVALID_WILDCARD_NAMES.add("abc.12*"); + INVALID_WILDCARD_NAMES.add("abc.12?"); + INVALID_WILDCARD_NAMES.add("foo*-.com"); + INVALID_WILDCARD_NAMES.add("foo?-.com"); + INVALID_WILDCARD_NAMES.add("_*bar.quux"); + INVALID_WILDCARD_NAMES.add("_?bar.quux"); + INVALID_WILDCARD_NAMES.add("foo?+*bar.com"); + INVALID_WILDCARD_NAMES.add("foo?!*bar.com"); + INVALID_WILDCARD_NAMES.add(".*foo.com"); + INVALID_WILDCARD_NAMES.add(".?foo.com"); + INVALID_WILDCARD_NAMES.add("..*bar.com"); + INVALID_WILDCARD_NAMES.add("..?bar.com"); + INVALID_WILDCARD_NAMES.add("*..bar.com"); + INVALID_WILDCARD_NAMES.add("?..bar.com"); + INVALID_WILDCARD_NAMES.add("baz*..com"); + INVALID_WILDCARD_NAMES.add("baz?..com"); + INVALID_WILDCARD_NAMES.add("fleeb.com*.."); + INVALID_WILDCARD_NAMES.add("fleeb.com?.."); + INVALID_WILDCARD_NAMES.add("fleeb.com..*"); + INVALID_WILDCARD_NAMES.add("fleeb.com..?"); + } + + @Test + public void testHostParser() { + Matcher matcher = HOSTS_PARSER_PATTERN.matcher("# [mocean.mobi]"); + assertFalse(matcher.matches()); + matcher = HOSTS_PARSER_PATTERN.matcher("127.0.0.1 www.domain.com ## some comments #"); + assertTrue(matcher.matches()); + assertEquals("127.0.0.1", matcher.group(1)); + assertEquals("www.domain.com", matcher.group(2)); + matcher = HOSTS_PARSER_PATTERN.matcher("127.0.0.1 ad.domain.net ## some comments"); + assertTrue(matcher.matches()); + assertEquals("127.0.0.1", matcher.group(1)); + assertEquals("ad.domain.net", matcher.group(2)); + } + + @Test + public void isValidHostname() { + for (String validName : VALID_NAMES) { + assertTrue( + "The hostname '" + validName + "' should be valid.", + RegexUtils.isValidHostname(validName) + ); + } + } + + @Test + public void isValidWhitelistHostname() { + for (String validName : VALID_NAMES) { + assertTrue( + "The hostname '" + validName + "' should be a valid white list host name.", + RegexUtils.isValidWildcardHostname(validName) + ); + } + for (String wildcardName : VALID_WILDCARD_NAMES) { + assertTrue( + "The wildcard hostname '" + wildcardName + "' should be valid.", + RegexUtils.isValidWildcardHostname(wildcardName) + ); + } + } + + @Test + public void isInvalidHostname() { + for (String invalidName : INVALID_NAMES) { + assertFalse( + "The hostname '" + invalidName + "' should not be valid.", + RegexUtils.isValidHostname(invalidName) + ); + } + } + + @Test + public void isInvalidWhitelistHostname() { + for (String invalidName : INVALID_NAMES) { + assertFalse( + "The hostname '" + invalidName + "' should not be valid.", + RegexUtils.isValidWildcardHostname(invalidName) + ); + } + for (String invalidWildcardName : INVALID_WILDCARD_NAMES) { + assertFalse( + "The wildcard hostname '" + invalidWildcardName + "' should not be valid.", + RegexUtils.isValidWildcardHostname(invalidWildcardName) + ); + } + } +} diff --git a/app/src/test/java/org/adaway/ui/log/LogEntrySortTest.java b/app/src/test/java/org/adaway/ui/log/LogEntrySortTest.java new file mode 100644 index 0000000..b08b8b1 --- /dev/null +++ b/app/src/test/java/org/adaway/ui/log/LogEntrySortTest.java @@ -0,0 +1,69 @@ +package org.adaway.ui.log; + +import org.junit.Test; + +import java.util.Comparator; + +import static org.adaway.db.entity.ListType.ALLOWED; +import static org.adaway.ui.log.LogEntrySort.ALPHABETICAL; +import static org.adaway.ui.log.LogEntrySort.TOP_LEVEL_DOMAIN; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class LogEntrySortTest { + @Test + public void testTopLevelDomainComparator() { + Comparator comparator = TOP_LEVEL_DOMAIN.comparator(); + LogEntry entry1 = new LogEntry("google.com", null); + LogEntry entry1Copy = new LogEntry("google.com", ALLOWED); + LogEntry entry2 = new LogEntry("beta.google.com", null); + LogEntry entry3 = new LogEntry("www.google.com", null); + + // Check equality + assertEquals(0, comparator.compare(entry1, entry1)); + assertEquals(0, comparator.compare(entry2, entry2)); + assertEquals(0, comparator.compare(entry3, entry3)); + + // Check transitivity + assertTrue( comparator.compare(entry1, entry2) < 0); + assertTrue( comparator.compare(entry2, entry3) < 0); + assertTrue( comparator.compare(entry1, entry3) < 0); + + // Check sign opposite + assertTrue( comparator.compare(entry2, entry1) > 0); + assertTrue( comparator.compare(entry3, entry2) > 0); + assertTrue( comparator.compare(entry3, entry1) > 0); + + // Check equals elements have the same order + assertEquals(0, comparator.compare(entry1, entry1Copy)); + assertTrue(comparator.compare(entry1, entry2) * comparator.compare(entry1Copy, entry2) > 0); + } + + @Test + public void testAlphabeticalComparator() { + Comparator comparator = ALPHABETICAL.comparator(); + LogEntry entry1 = new LogEntry("google.com", null); + LogEntry entry1Copy = new LogEntry("google.com", ALLOWED); + LogEntry entry2 = new LogEntry("beta.google.com", null); + LogEntry entry3 = new LogEntry("www.google.com", null); + + // Check equality + assertEquals(0, comparator.compare(entry1, entry1)); + assertEquals(0, comparator.compare(entry2, entry2)); + assertEquals(0, comparator.compare(entry3, entry3)); + + // Check transitivity + assertTrue( comparator.compare(entry2, entry1) < 0); + assertTrue( comparator.compare(entry1, entry3) < 0); + assertTrue( comparator.compare(entry2, entry3) < 0); + + // Check sign opposite + assertTrue( comparator.compare(entry1, entry2) > 0); + assertTrue( comparator.compare(entry3, entry1) > 0); + assertTrue( comparator.compare(entry3, entry2) > 0); + + // Check equals elements have the same order + assertEquals(0, comparator.compare(entry1, entry1Copy)); + assertTrue(comparator.compare(entry1, entry2) * comparator.compare(entry1Copy, entry2) > 0); + } +} diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..6bb02f1 --- /dev/null +++ b/build.gradle @@ -0,0 +1,31 @@ +buildscript { + repositories { + google() + } + + dependencies { + classpath libs.gradle + } +} + +plugins { + id 'org.sonarqube' version '3.4.0.2513' +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +sonarqube { + properties { + // Root project information + property 'sonar.projectKey', 'org.adaway' + property 'sonar.organization', 'adaway' + property 'sonar.projectName', 'AdAway' + property 'sonar.projectVersion', libs.versions.appName.get() + property 'sonar.host.url', 'https://sonarcloud.io' + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..380e64d --- /dev/null +++ b/gradle.properties @@ -0,0 +1,14 @@ +## For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx1024m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx2048m +# Enable build cache +org.gradle.caching=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..54026d0 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,52 @@ +[versions] +# Build +appName = "6.1.4" +appCode = "60104" # Read x.yy.zz to match version name +gradle = "8.7.1" +# Common +guava = "32.0.1-android" +junitVersion = "1.2.1" +okhttp = "4.12.0" +timber = "5.0.1" +# Root +libsu = "6.0.0" +# VPN +pcap4jCore = "1.8.2" +pcap4jPacketfactoryStatic = "1.8.2" +dnsjava = "3.5.3" +slf4j = "1.7.36" +# Test +junit = "4.13.2" +json = "20220320" +androidxTestCore = "1.6.1" +androidXCoreTesting = "2.2.0" + +[libraries] +# Build +gradle = { module = "com.android.tools.build:gradle", version.ref = "gradle" } +# Common +guava = { module = "com.google.guava:guava", version.ref = "guava" } +okhttp3-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } +timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } +# Root +libsu = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" } +# VPN +pcap4j-core = { module = "org.pcap4j:pcap4j-core", version.ref = "pcap4jCore" } +pcap4j-pcap4j-packetfactory-static = { module = "org.pcap4j:pcap4j-packetfactory-static", version.ref = "pcap4jPacketfactoryStatic" } +dnsjava = { module = "dnsjava:dnsjava", version.ref = "dnsjava" } +slf4j-android = { module = "org.slf4j:slf4j-android", version.ref = "slf4j" } +okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp" } +# Test +junit = { module = "junit:junit", version.ref = "junit" } +json = { module = "org.json:json", version.ref = "json" } +androidx-test-core = { module = "androidx.test:core", version.ref = "androidxTestCore" } +androidx-test-core-testing = { module = "androidx.arch.core:core-testing", version.ref = "androidXCoreTesting" } +androidx-test-ext-junit = { module = "androidx.test.ext:junit", version.ref = "junitVersion" } +androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidxTestCore" } + +[bundles] +pcap4j = ["pcap4j-core", "pcap4j-pcap4j-packetfactory-static"] +androidx-test = ["androidx-test-core", "androidx-test-core-testing", "androidx-test-ext-junit", "androidx-test-runner"] + +[plugins] + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f GIT binary patch literal 59203 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

    K7UpUK$>l@ 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 E2O(~oYXATM literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..19cfad9 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..ac1b06f --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/metadata/af/full_description.txt b/metadata/af/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/af/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/af/short_description.txt b/metadata/af/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/af/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/af/title.txt b/metadata/af/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/af/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ar/full_description.txt b/metadata/ar/full_description.txt new file mode 100644 index 0000000..2ab2b61 --- /dev/null +++ b/metadata/ar/full_description.txt @@ -0,0 +1,9 @@ +أداة حظر إعلانات مجانية ÙˆÙ…ÙØªÙˆØ­Ø© المصدر لنظام Android. + +التطبيق متاح للأجهزة التي لها جذر وغير جذر. +باستخدام الجهاز الجذر ØŒ يقوم التطبيق بتحديث مل٠مضي٠النظام الخاص بك الذي يحتوي على قائمة بالتعيينات بين أسماء المضيÙين وعناوين IP. +باستخدام جهاز بدون جذر ØŒ يستخدم التطبيق ميزة VPN لحظر الاتصالات الصادرة للإعلانات وأجهزة التتبع. +لذلك عندما يطلب أحد التطبيقات إعلانًا أو أداة تعقب من مضي٠ÙÙŠ هذا المل٠، تتم إعادة توجيه هذا الطلب إلى عنوان IP المحلي 127.0.0.1 ØŒ والذي لا ÙŠÙØ¹Ù„ شيئًا. + +يمكنك تنزيل الإعلانات المحددة مسبقًا وقوائم المنع ÙƒÙ…Ù„ÙØ§Øª Ù…Ø¶ÙŠÙØ© من داخل التطبيق لتضمينها. من الممكن أيضًا استخدام Ù…Ù„ÙØ§ØªÙƒ الخاصة ÙˆØ¥Ø¶Ø§ÙØ© مضيÙين معينين إلى القوائم المسموح بها والمحظورة. +توجد خيارات لتشغيل خادم الويب المحلي للردّ على أسماء المضي٠المحظورة وتوجيه الطلبات إلى عنوان الآي بي الذي تختاره أنت بدلاً من ذلك. \ No newline at end of file diff --git a/metadata/ar/short_description.txt b/metadata/ar/short_description.txt new file mode 100644 index 0000000..250987c --- /dev/null +++ b/metadata/ar/short_description.txt @@ -0,0 +1 @@ +أداة حظر إعلانات مجانية ÙˆÙ…ÙØªÙˆØ­Ø© المصدر لنظام Android. \ No newline at end of file diff --git a/metadata/ar/title.txt b/metadata/ar/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ar/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ast/full_description.txt b/metadata/ast/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/ast/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/ast/short_description.txt b/metadata/ast/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ast/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ast/title.txt b/metadata/ast/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ast/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/az/full_description.txt b/metadata/az/full_description.txt new file mode 100644 index 0000000..e72b4e2 --- /dev/null +++ b/metadata/az/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +Yerli server açıb bloklanmış host adlarına cavab vermÉ™ vÉ™ öz seçiminzÉ™ görÉ™ olan IP ünvanlarına yönlÉ™dirmÉ™ imkanlarınız da var. \ No newline at end of file diff --git a/metadata/az/short_description.txt b/metadata/az/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/az/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/az/title.txt b/metadata/az/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/az/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/be/full_description.txt b/metadata/be/full_description.txt new file mode 100644 index 0000000..fc17362 --- /dev/null +++ b/metadata/be/full_description.txt @@ -0,0 +1,9 @@ +БÑÑплатны блакіроўшчык Ñ€Ñкламы з адкрытым зыходным кодам Ð´Ð»Ñ Ð°Ð½Ð´Ñ€Ð¾Ñ–Ð´Ð° + +Праграма даÑтупна Ð´Ð»Ñ Ð¿Ñ€Ñ‹Ð»Ð°Ð´ з root-доÑтупам Ñ– без Ñго. +ВыкарыÑтоўваючы прыладу з  root-доÑтупам, праграма абнаўлÑе ÑÑ–ÑÑ‚Ñмны файл hosts, Ñкі змÑшчае ÑÐ¿Ñ–Ñ Ñ–Ð¼Ñ‘Ð½Ð°Ñž host Ñ– Ñ–Ñ… IP-адраÑоў. +ВыкарыÑтоўваючы прыладу без root-доÑтупу, праграма будзе выкарыÑтоўваць функцыю VPN Ð´Ð»Ñ Ð±Ð»Ð°ÐºÑ–Ñ€Ð¾ÑžÐºÑ– выходных злучÑннÑÑž з Ñ€Ñкламай Ñ– трÑкерамі. +Такім чынам, калі праграма запытвае Ñ€Ñкламу або трÑкер ад хоÑта Ñž гÑтым файле, гÑты запыт перанакіроўваецца на лакальны IP 127.0.0.1, Ñкі нічога не робіць. + +Ð’Ñ‹ можаце Ñпампаваць гатовы ÑÐ¿Ñ–Ñ Ð·Ð°Ð±Ð»Ð°ÐºÑ–Ñ€Ð°Ð²Ð°Ð½Ñ‹Ñ… Ñ€Ñкламных адраÑоў у файле hosts. ТакÑама можна выкарыÑтоўваць Ñвой файл Ñ– дадаваць пÑÑžÐ½Ñ‹Ñ Ð°Ð´Ñ€Ð°ÑÑ‹ Ñž «белы» Ñ– «чорны» ÑпіÑÑ‹. +Маецца магчымаÑць запуÑку лакальнага вÑб-Ñервера Ð´Ð»Ñ Ð¿ÐµÑ€Ð°Ð½Ð°ÐºÑ–Ñ€Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ñ‹Ñ‚Ð°Ñž да заблакаваных адраÑоў на абраны вамі IP-адраÑ. \ No newline at end of file diff --git a/metadata/be/short_description.txt b/metadata/be/short_description.txt new file mode 100644 index 0000000..2f66627 --- /dev/null +++ b/metadata/be/short_description.txt @@ -0,0 +1 @@ +БÑÑплатны блакіроўшчык Ñ€Ñкламы з адкрытым зыходным кодам Ð´Ð»Ñ Android. \ No newline at end of file diff --git a/metadata/be/title.txt b/metadata/be/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/be/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/bg/full_description.txt b/metadata/bg/full_description.txt new file mode 100644 index 0000000..8865b1e --- /dev/null +++ b/metadata/bg/full_description.txt @@ -0,0 +1,9 @@ +Безплатна и Ñ Ð¾Ñ‚Ð²Ð¾Ñ€ÐµÐ½ код програма за блокиране на реклами за Android. + +Програмата е налична за уÑтройÑтва ÑÑŠÑ Ð¸ без роот доÑтъп. +Чрез използването на руутнато уÑтройÑтво, приложението актуализира вашиÑÑ‚ хоÑÑ‚ файл, който задържа ÑпиÑък Ñ Ð²Ñ€ÑŠÐ·ÐºÐ¸ между имена на хоÑтове и IP адреÑи. +Чрез използване на уÑтройÑтво без руут, приложението използва VPN фукциÑта за да блокира изходÑщи връзки до рекламите и тракерите. +Когато приложение поиÑка реклама от тракера от хоÑÑ‚ в този файл, иÑкането е пренаÑочено до локалното IP 127.0.0.1, което не прави нищо. + +Може да ÑвалÑте дефинирани хоÑÑ‚ файлове от приложението, за да ги включите в ÑиÑÑ‚ÐµÐ¼Ð½Ð¸Ñ Ñ…Ð¾ÑÑ‚ файл. Също така е възможно да използвате ÑобÑтвени файлове и да добавÑте определени хоÑтове в бели и черни ÑпиÑъци. +Има опции за Ñтартиране на локален уеб Ñървър, който да Ð¾Ñ‚Ð³Ð¾Ð²Ð°Ñ€Ñ Ð½Ð° блокирани имена на хоÑтове и да препраща заÑвки към IP адреÑи по Ваше желание. \ No newline at end of file diff --git a/metadata/bg/short_description.txt b/metadata/bg/short_description.txt new file mode 100644 index 0000000..0cb0893 --- /dev/null +++ b/metadata/bg/short_description.txt @@ -0,0 +1 @@ +Безплатна и Ñ Ð¾Ñ‚Ð²Ð¾Ñ€ÐµÐ½ код програма за блокиране на реклами за Android. \ No newline at end of file diff --git a/metadata/bg/title.txt b/metadata/bg/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/bg/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/bn/full_description.txt b/metadata/bn/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/bn/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/bn/short_description.txt b/metadata/bn/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/bn/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/bn/title.txt b/metadata/bn/title.txt new file mode 100644 index 0000000..0f1e5ba --- /dev/null +++ b/metadata/bn/title.txt @@ -0,0 +1 @@ +অà§à¦¯à¦¾à¦¡à¦…à§à¦¯à¦¾à¦“য়ে \ No newline at end of file diff --git a/metadata/ca/full_description.txt b/metadata/ca/full_description.txt new file mode 100644 index 0000000..ff8e614 --- /dev/null +++ b/metadata/ca/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +Hi ha opcions per executar un servidor web local per respondre als noms d'amfitrió bloquejats i per dirigir sol·licituds a l'adreça IP que trieu. \ No newline at end of file diff --git a/metadata/ca/short_description.txt b/metadata/ca/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ca/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ca/title.txt b/metadata/ca/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ca/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/cs/full_description.txt b/metadata/cs/full_description.txt new file mode 100644 index 0000000..e75aacf --- /dev/null +++ b/metadata/cs/full_description.txt @@ -0,0 +1,9 @@ +Bezplatný blokovaÄ reklam pro Android s otevÅ™eným kódem. + +Aplikace je dostupná pro zařízeni s i bez ROOT přístupu. +PÅ™i použití na zařízení s ROOT přístupem aplikace aktualizuje Váš soubor hostitelů, který obsahuje mapování mezi názvy hostitelů a IP adresami. +PÅ™i použití na zařízení bez ROOT přístupu aplikace použije funkci VPN pro zablokování odchozích pÅ™ipojení k reklamám a sledovaÄům. +Takže když nÄ›jaká aplikace požádá o reklamu nebo sledovaÄ od hostitele v tomto souboru, daný požadavek je pÅ™esmÄ›rován na místní IP 127.0.0.1, která nic nedÄ›lá. + +Přímo z aplikace můžete stáhnout pÅ™eddefinované seznamy blokovaných reklam jako soubory hostitelů k zaÄlenÄ›ní. Také je možné použít VaÅ¡e vlastní soubory nebo pÅ™idat urÄité hostitele na seznam povolených Äi zablokovaných hostitelů. +Jsou zde možnosti spustit lokální webový server aby odpovídal na požadavky na zablokovaná jména hostitelů a aby smÄ›roval požadavky přímo na konkrétní IP adresu dle vaÅ¡eho výbÄ›ru. \ No newline at end of file diff --git a/metadata/cs/short_description.txt b/metadata/cs/short_description.txt new file mode 100644 index 0000000..d2affd4 --- /dev/null +++ b/metadata/cs/short_description.txt @@ -0,0 +1 @@ +Bezplatný blokovaÄ reklam pro Android s otevÅ™eným kódem. \ No newline at end of file diff --git a/metadata/cs/title.txt b/metadata/cs/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/cs/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/da/full_description.txt b/metadata/da/full_description.txt new file mode 100644 index 0000000..4b7890d --- /dev/null +++ b/metadata/da/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +Der er muligheder for at køre en lokal webserver til at reagere pÃ¥ blokerede hostnavne, samt til at rette anmodninger til en selvvalgt IP-adresse istedet. \ No newline at end of file diff --git a/metadata/da/short_description.txt b/metadata/da/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/da/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/da/title.txt b/metadata/da/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/da/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/de/full_description.txt b/metadata/de/full_description.txt new file mode 100644 index 0000000..7783f26 --- /dev/null +++ b/metadata/de/full_description.txt @@ -0,0 +1,9 @@ +Ein kostenloser und quelloffener Werbeblocker für Android. + +Die Anwendung ist für gerootete und nicht gerootete Geräte verfügbar. +Wenn Sie ein gerootetes Gerät verwenden, aktualisiert die Anwendung die Hosts-Datei Ihres Systems, die eine Liste der Zuordnungen zwischen Hostnamen und IP-Adressen enthält. +Wenn Sie ein nicht gerootetes Gerät verwenden, nutzt die Anwendung die VPN-Funktion, um ausgehende Verbindungen zu Werbung und Trackern zu blockieren. +Wenn also eine App eine Werbeanzeige oder einen Tracker von einem Host in dieser Datei anfordert, wird diese Anforderung an die lokale IP 127.0.0.1 weitergeleitet, was nichts bewirkt. + +Sie können vordefinierte Werbungs- und Sperrlisten als Hosts-Dateien aus der App herunterladen und einbinden. Es ist auch möglich, eigene Dateien zu verwenden und bestimmte Hosts zu erlaubten und blockierten Listen hinzuzufügen. +Es gibt die Möglichkeit, einen lokalen Webserver zu betreiben, der auf blockierte Host-Namen reagiert und Anfragen an sie an eine selbstgewählte IP-Adresse weiterleitet. \ No newline at end of file diff --git a/metadata/de/short_description.txt b/metadata/de/short_description.txt new file mode 100644 index 0000000..a027f04 --- /dev/null +++ b/metadata/de/short_description.txt @@ -0,0 +1 @@ +Ein kostenloser und quelloffener Werbeblocker für Android. \ No newline at end of file diff --git a/metadata/de/title.txt b/metadata/de/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/de/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/el/full_description.txt b/metadata/el/full_description.txt new file mode 100644 index 0000000..80ef568 --- /dev/null +++ b/metadata/el/full_description.txt @@ -0,0 +1,9 @@ +Ένα Ï€ÏόγÏαμμα Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ δωÏεάν και Î±Î½Î¿Î¹Ï‡Ï„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± για Android. + +Η εφαÏμογή είναι διαθέσιμη για rooted και μη rooted συσκευές. +ΧÏησιμοποιώντας rooted συσκευή, η εφαÏμογή ενημεÏώνει το αÏχείο hosts του συστήματός σας που πεÏιέχει μια λίστα αντιστοιχίσεων Î¼ÎµÏ„Î±Î¾Ï Î¿Î½Î¿Î¼Î¬Ï„Ï‰Î½ hosts και διευθÏνσεων IP. +ΧÏησιμοποιώντας μη rooted συσκευή, η εφαÏμογή χÏησιμοποιεί τη δυνατότητα VPN για τον αποκλεισμό εξεÏχόμενων συνδέσεων με διαφημίσεις και Ï€ÏογÏάμματα παÏακολοÏθησης. +Έτσι, όταν μια εφαÏμογή ζητά μια διαφήμιση ή έναν ιχνηλάτη από έναν κεντÏικό υπολογιστή σε αυτό το αÏχείο, αυτό το αίτημα ανακατευθÏνετε στην τοπική IP 127.0.0.1, η οποία δεν κάνει τίποτα. + +ΜποÏείτε να κατεβάσετε Ï€ÏοκαθοÏισμένες διαφημίσεις και λίστες Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Ï‰Ï‚ hosts αÏχεία από την εφαÏμογή για ενσωμάτωση. Είναι επίσης δυνατό να χÏησιμοποιήσετε τα δικά σας αÏχεία και να Ï€Ïοσθέσετε οÏισμένα hosts σε επιτÏεπόμενες και αποκλεισμένες λίστες. +ΥπάÏχουν επιλογές για να εκτελέσετε έναν τοπικό διακομιστή Î¹ÏƒÏ„Î¿Ï Î³Î¹Î± να απαντήσετε σε αποκλεισμένα host names και να κατευθÏνετε αιτήματα Ï€Ïος την διεÏθυνση IP της επιλογής σας. \ No newline at end of file diff --git a/metadata/el/short_description.txt b/metadata/el/short_description.txt new file mode 100644 index 0000000..49e5b2c --- /dev/null +++ b/metadata/el/short_description.txt @@ -0,0 +1 @@ +Ένα Ï€ÏόγÏαμμα Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Î´Î¹Î±Ï†Î·Î¼Î¯ÏƒÎµÏ‰Î½ δωÏεάν και Î±Î½Î¿Î¹Ï‡Ï„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± για Android. \ No newline at end of file diff --git a/metadata/el/title.txt b/metadata/el/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/el/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/en-US/full_description.txt b/metadata/en-US/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/en-US/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/en-US/images/featureGraphic.png b/metadata/en-US/images/featureGraphic.png new file mode 100644 index 0000000000000000000000000000000000000000..153e5ea145f90aa21399ba253761a1ef597dc2ce GIT binary patch literal 20917 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 literal 0 HcmV?d00001 diff --git a/metadata/en-US/images/icon.png b/metadata/en-US/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a000baf5f472413887e518caa31a378db99767f2 GIT binary patch literal 1923 zcmV-}2YmR6P)jNI0mU#M=LCiU@yw86K<)r^F)}jPs8XE(FiWNoF0=aiJ)d1y*Ch6M zqR*iJ;T!@mUuf7G(c{LBM~G~0G*GG4ewSczLqiP z@I`N#)nduXZfv~EC&+i*Wk7C7$b3H8uZxnnT>|7WVdV&!2sueGAdiP5Qce;C=v;KP z+Nx9@mVGIw4X%N5Hrpke#WHtRQ&S6T7tDY-IDUQypitzp4(4Y03$~t~TvkX-fV?KG zM9fLlfV>`#z??({=!tKa(PI>oxP^7iAT;vNKu1rG5-w>BR!%k$9P(t@_%OVL(#1&@CH4c&h~ zl-EgDM{@va5TKuRx}R8{$^*xY!MGzw;TxpxHL>T>qsOpHFT-%-CX6-Juvsjwx*&&s zSyp|0THk?&0%T*gBc_|5A4%JHAZ&UDCvP>GpfA~rrb7n>&05I-5#xM=gAq1u8Z!jU*h{`gw#>NU`=Ts27S?$#}MaO@bL`k?EQ0_r=ON~c3;S~?a(MuATndDW;16D$qT^~ zCnBz(0P0kBKz5HBb{9imQZmTFu#8M3ZQTYRm8$pJnbW6{o}P{vt(Nozsq)ti2=-qpujEHa<%)kyv@+GSrff5iO@3enQXD2H2UPDKDIkO#- z0wUI^Q&YLsEF>+>;j+(cHKRiP7dz4T)d5DW$KsL$vRmaJqlJG|By1Kd6n=h4+P)ns zZLA=pS(L~ut5}o^i^0I6)+;L;Ap3}1&X_w7@f$V@UiMi$Z7BW{`u+P@RQk!v3P=?f z4_$sfG?_C58_cRma!*@nDXW@$W>9$cY$R^^M7CUH>*+!H%uJY@o4o@Nv2x_g%Me#k zDA-^YMU%b(s){mu%2g<}K%yb0*+6KxFSaY1QgHJcEcJ{gH0eGK1_5Ne0-ytM}ZUc5jpKa`-`W{?o8lMfz7$fQYBs$^@U^3`R% z+bvW|LkM{dAeB~&l;bDi7Z%3rtEIgim8(_=dU_w&xmN&EPndvF9~2=dIhhv@sh;aT zEW*Pd&+y992zWFg|LAD$j4fi$3-AdHURhcJj|4;#aa7I%L@!xN zz1e2GcMrAiZ-U|abz0x4{!ITQ;5(hQ}{&tT{m36hU&rsm!8;NEfkrKo|(J@xZI*$u@X_a3z>_-_N!M>wJskd z_ej+EkDggyUSKhl>@Jd{8ci1aM?mCBz4Dc1FzNLyL(f2fP8T=47(R00ok4Oy>PsYH(|d?o zxTyDEh8s6%;-X2!|OE zQIP9n7V;RP)M#Kec7eR}C_;Uhaf^&iI#&Lgq!@o+hI3EWH_Sa zAdi700USvH^$EA(pU0uf30^KF$|~mN44j%j42b9M4g=x=^dAR2j&?&O=X?MF002ov JPDHLkV1jTwh;0A> literal 0 HcmV?d00001 diff --git a/metadata/en-US/phoneScreenshots/screenshot1.png b/metadata/en-US/phoneScreenshots/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..34d7ab1f809c85708ad0f6a8d8f8d28b181d54cf GIT binary patch literal 102017 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

    P5}Glx{|~Q5(r6ah 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%0Di0clLo{vjZfI~qc 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 literal 0 HcmV?d00001 diff --git a/metadata/en-US/phoneScreenshots/screenshot3.png b/metadata/en-US/phoneScreenshots/screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..f7058725f1071074278818980a1fa34a6f407834 GIT binary patch literal 108017 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

    LcgKfdxi-yg!#8_-lUqIUiDY<*ko}S*` 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 z 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 literal 0 HcmV?d00001 diff --git a/metadata/en-US/phoneScreenshots/screenshot4.png b/metadata/en-US/phoneScreenshots/screenshot4.png new file mode 100644 index 0000000000000000000000000000000000000000..d6c73dac488b8310b4f52bcb4d40d2fb847db8ea GIT binary patch literal 47915 zcmeFZbyQbt_dSZoLQp{^R8#~7X)HogQ9wZiNhK9j8l)QxFi=Dq>68xXMn#ZR8fihg z8|gdudEf8&-M{a+f824$*KyAAps+uCKhLw)nsctX_G`IYlKaSxl97;*?7MOOnmh@~ z4t^36(#NF#;7=smkEGzYZ5Hy9VkD_Qj*a4r?G|D;6iG=*JNsmRlaQPwxpD1^qHV}T zx1HnOAo)99jP=H|7W~4%Dq*lr9~hy#bA$B zR;>O3tDOhLPn$5>Fz%_^+zgyHbzTeZPOdZY4*fR1^78wHuCB;hd%H}n;QXcJuCA^f z_;`}|*V(aj#Q%^;?Vu)pOS~$#4ZlSQ{J-#}j^XGoT(($d=Acbf002Qwq1cE#Hx_wV1|*^m<@EyXHE`b?@p zjClBTAuX-mo#ZsvHHvDfXlQtyRxPJeuMhY#lCp`*d?I5L5fKRs3u|w0|McloTbh>2 z)$EgePY8WQ44X+K?cm_BNtY>>>tCnQ8Y z;;EEiEGf@UKe3Xcg{7rbjlvvC#`EXTGc#BC(x^R?dS0EBR?-nC8=hm_xisCoRr}$> z3!ButnM2=RAL`6DR4H+^%b!`A?0iW_< zdsC&syp)&xwJ$sT#0m{~CV#c2sQnBRF1%m%qEYg_kI(#1(XHAbp7G`c1v^_GnyA!> z{^8-}Ry9+r$&PF(KQ{Rra&mIEws}vl?%I1e-FCLWF;;rqiIHl-1 zSZLg6L0%qJm-J~Srp2+An#w|&wWUcPli<9w=d%y zPdwF}Qj-4nT|0I-u1)5?d-u+L?%TI-B2KFzf;K-c8@61gz7i`RD`i@|sO)({*z)DO zBb${DOB4C`%XX=$UG?FJi;XRwt)S!Ho42B5yp3lM2?^B&xA*d=D|D&Lu85m?(NI#( zG|7tYVX$8uiydKOre{~VQ|XkdoTAEe?=wla`F!wwuOww3&yC64-k4yk+qZ8E+Dv7A z`gG)?-uv9#T+04|DxdB`o3@^Oo$v3Mr2Y5q+s8A*=2rW4JYF$X-L5_3;kIqttgWr> zgmV-VT30shaFk^Jcg}QVyBszgO*N^KSQ#bahd8aT(0Bm-Fx(6 zW#vYp)i|>$&cD`X?de{Ztqm=g4JJ{?KOTHkFV|L9Jm~mRwMv~=?xcJmR*oCN@ap&P z-(q>R2aX+cob4~i9r4r)a>bsc8d6HC`YvUo>Po4vuix>ql0w>#jmh{gu5pw{iqvd* zs{4|~(BYMjWKRd5SO59$S-Lh=_~rTTwbj*y6(iC^csk7t#|Upy6@ ztd?uCd;hUOVTYw49z*NN4nM7yAPWu>65DoHH@CXLbJ3SGs~1L_r~`7!k@J$s1Y++D z5c`&ykrA`+();TJBt9QLuo`pRNx#e%BI;6-I2C^H z9odHDQIE1&Bg|MkILuoNeta^|PfJS+4pwt?ETW7;1jz?B=v~C|7JGF&S|Z!1U7pnJ z?@S+#_V8jiH4FJ}>PuCFN;oFTDO(PL*F_r0a!q^vbE%JCzHt8hz+_0sv6aY6EkW%_ zjx***1+9%XRu^&S^SK?;0bFjbt^=l_V~UUe$Y(hn?Kq zx^+QJgGo4iF0Tuf)| z{AMX5)`V(8}lP#t2dJ4&2zIOEJjAgk21kI=7Uo6NkP2EL0-}gv`33`ZL-!lK15Jf#14?x zXlhRNmbz?hZXoG2*89fCv*=sh5)>@NalWIbChD+cG*tV+&dKlVZN=vRE|qNd8aW@-dugWArw33vn2*_xHpYI^`99>}u=ix_;j3-|0q$-J9l541 zs3!_>w~TvBHjvX0WD}bkYrz-wz1sqQ*ogDQ3puSS_WYQ98FTIR!48UWAv^j1b8S{u zR(^i|wC&?KInSRzSISn^y25fWdYHP|+AiS^e=JTPf_HI#-e)}b(oGAq5yQSjv0;}<{DTP=m zYP-(LBdh;YEj7geR%gv6{v9 zjS9Ly!#v)+@ySV3&p${_&E%S%o$Y6n{wnIIqAO+N5#KE1PGy^yKoR5J`M(o6Bbc|5 zJPBwbH}$*Dr#ZJ_^{2moA(e@qlJcIao4ujK+(1={)0(EOk=HHOgFNb*V;cP8N9DO) zugl1^^jub{r+cEsn|VLKU;T@bKO|vp=hg z;{l%k34RhcWc@B0i6W;p>&K5DGj!Fzr{27%C2pzi{_H3h_aavaqt)y|)z{+kA8#Jf zKXvL<+2=JjJ!KOU6Bl=9W4vo7}q>A@m#9UBU&u5|KjlFSe-z5Z?+HnH(61Y0yKK zIC}iJapP#!ZgKv2QU*8NSUKnY(@Tm4z zu|ux)N_(bmaZ!;gC6HWKmc9?AHWs2Tn2%NrXe|{1yh}4Hg1RqNOY9ZB%eomV{+tZE z25K;BY}-a{mZ=VM1-%-OytbTuf3XD`qLCdYFUZfy3J2D$v*B=l7yg$FZ ztP(@T@D2DVOw@(TRS$uSQvi_89qaq{?c0_4VLE4pohf>|sTsZjv;f~(4OAW|f4Ph@ zjCi%4?$KDDrxZ&D(#Gi$BlVET)Nf+$w)-xV)Vi(%Zm^)5rRQ~V&o7)de7w=<5LHB! z;Gs|VX-bQl3*AS6fB*)j4S#YnyXIk)keD{srb|oHfBX|$kgCOOVP>{x?_LhAk|N4} z9ELNuLe3V&Bt=K-AS)7C8U@lZnYZ-aPSASl+pq=vn@Zke^g15Ih@&jm% zsO?MyWydZhGjsE?wzTllQkS|Qo*G|Pg{W(XLas*-{ZheQbnisbrc=zQNV&9g^YSs8SgV*mag#LeH?Kh!!x za_cvPd5s%mZn*nK)u-Pt+egO>@EljKituqSV01iiL+bXW-Me2hTzyeASIzFjEF&c= zn`>zyck%@VeNUV$z0Q)Qjm_3Vlk9Ga6CpuCs`V*sjS?P57f}!l0@gv$lT^}j6dfQf z_(s`Fy7|g0W*N1cLw#8^@z4;?)C=x3Ny|F=D(_dx0rp@tQ;vLWbQ345^M9~sy4mCFY{_Z%$ zlwI$T-0PEAc2dhrdA)!CKEfe;425@OM9*s};x~(kLa}r*^XbzM9zN6$(7PD)%oxRp zg~t768@IgF0due&vp*I30e9}+RZ3M~0Tp^dfi&v~M2@pKJ~*gUV5yHS#IeiD%IeHD zm6VX!oU7r+-`5!GKveo?`*tn6LFzMS&gfqjH!v8Bmh{A`I09p?k3ENAb@4$ZB^@1| z_zHmF31R!wu8(bO=)w1w6cQ2=w44@|OsKIUch4;<09Qe^p(+Hy(UT={0%a(BNkPt_ zuAu?0+KS4J@VO)?DC)8)#K6#pOzaiV^WtP@uJgv~!y5kOa)HZ}eE^Ji;gx%YzZkM-5@ zG<(mZ0+#VYr54=8h2ebH>n z$+o{gZxioB&~a%N1$Hu=IB{aSbjukirnuP2WDUE0T-4cdWo}TS!Y?8s;+#&!;SoJw zs8Fc1X`00X=g-Se??)ox03csN*4iv6Z13oBUKtDk#8B~_?kQe_lH-?y=Vj8EtOD=) z1(4g-(TeWv9Gkeq;iW6aa-yWbtVbUv4U5@e1O3x^C-Ga2iVi!VXq zt0^vAxZtoj#L!zlF9x+bK8e5qlAL|}< z8o|xW%bUAVXgyhA+?m6rQE>P=GOIU}wDnlCJ~Xy`jT8E6S$Yj$-N^S*yiCu@*-uJ( zC)Y#+>#BJtavOMWiwrC7*-t?#(#+a=^Y0(eGcrLBep66lm!$nUj$AU2S>cY$qkpKY z%V+fK?4Hcle{Sk7>W=g$`Rh;xT;40Fu^XAI%i_$UXk+!s61QY^vAF$muH!^A@qyj8; z8M&oF=EUorBt^B&Cy=$oZ@=7soQesB;`Qs-_BQ*;$by6&a*~pgy!;CD@}QzbAYgVa z-7T{H)W78Mvz`h0R3qHZY!98Ku?bG6LHGht~+5;O8 z)YLi=DaGJo`IBcYhHBfiT)L~Pt1CZ3Ff&29m6$Sm8+rBRt)Pole`o$oPnQCdf;-S< zX6}^bAo~(_LAN?P;GmU({eX>-Kf9e#USX5&CQD4If=j7KxH%O%#kq* z7)1h8_;}Nyz!PKKAnoa;JV$ys9N}CVQx+(+y3j9B?*G^pEbmGQ8Pymp;!06Jsz91nsU{^)>1lO! z_0{ERQN8+;<$l#*1i2>NiOZ-ml;!SE8wEHCvLsy{z%7atfCO(at(^I&E=<^Asxw#i z_I)UTmOfXFj3)3`kWj;eg4m7=-uwIn)lOfl6Ho2x>UuNq?3Z6Q?BAf<3z&5Am-jYI zcNg-R^?&O!p{IU_B|FX!yz+GWfddDiDM9WV2W&!(rY?302@OSkd{h_o@P{F%T23<3 zXh*m$pb});)L)ZO3c!+h?sM&ELfu34^7Waff<8YM1l+Ur&+M>$9p?U+lf@xch5a8BThFu=4kxKTUgz?A&W+ zuRPyn+@2vWWwNoh98hxxPXiHgQkW=BT?GdU3JRbG-Sv{klH>qR(mVfUU}KXa?Hd^Z z$6H3yWP9=DqG^vK)IlO6^#m=l)gB@zc_Q^(%7k?%&G67rj&?bj_2a*E~iYQRCN04V^Z;};&i zwKmT~30z;9C(3};nBwIA4QzXYdVa++ z^BVvpfN5e^uc{>9=^Gx7D@J=@#-`UPPA^5%%~5+B31#BsDv$OzQh9fQO9BEp4Gl$h z^EhDRAAM(LW|n&#rtyV+5*FT{QSn2%&k=^3BL5dXNmw%*^s93B>gJ&>4dOILY@<^+Bk!kqlXXDMsLl(cS*opy$u6Wnz2(*yzU();E9$acAb8 zF1Qz`)rE!<(~p7Sst!lBZs0C0k|sfZ+(RD!so1wY#VHcml>J4DC`u+kTK**QGk{cg zKZVJnw(**D>HSvXF#mVI_pu=mHHz(d?#5mxa>?b(pYg*gsp<(fFZ1&F|ESE@Z}=2V z*<5YlyGeSV|B`y%V}?tY?h4KTjL@092o3Ed0!Gpv60|=$V{Es7+G$K$(kzoMt z2drO--$H{#Ec=T1K$ueCVok=yqaHo4V~mW9EQgPqTUs7Fr+p3Sc(3RE`iF*w<3mHt zDU+NYimioX`C{mHP%-uO^}V3L4aQk#S_GexUPAbwMZ-o0lx#F4^IFUT4VrS-Z9p*l z_wV18%DV6G@8=YjFTD-fRZ_d+!kq;Snpwn622jOxv&2fDgi`R3&_ z40cB)O^l6G1n13dZEa0*-ztvu6gvPNb!@a^N!b+RPs&vLo+gHSC9ADXr^&C7WCnBg+app@5(;gmO&&>^+1RMmmiqenJ-p>6!FD_98-z$J?q)@4 zn{6`P`g``WYn7~zG(=N>nEX!f5`tbRu1CwM8Y4LQ3r{+@AP*;ixSZYkU$d~I_c9!h z%zsp?g8GTB%`tj<)88y`0sypdspU)ro0jNz=A^9Du>fN9r$&2q*ETjbQZWs=IFOGJ z?7>|8WISnx)NLOxuUW)8JDJtXPBMn|jSb@S)^>LjMG#y9{1Jp*&>n~_T2hODLX*!w zu->lrA_{_%<>u`R-A&$YE&aRq9*)S%0(l)md0-R`5pgQWYL2L_t~OZzJBvn?*ee2< z-Wm;#+ZCAnyW}7m=o6i}(>MlNdG5EsJBj`C6y5w)tJ1tLBqv9ro1sm3&yYA1$zuse9Zq{Afoe{uIn_XBV#8=|0WPEpRQ&R9L9v&sH zv!$zJNlkIG!_!IYi)~ts9dKE^Ll!asS|GrftOKyC%j#$x#P#5HF+^p@l~|Y=dU|@e zLuey$(%lbkAE!Oi>n+Cr3H=_KhLKgKniPt_b8pzA&yMbQsGm%T>Qr!nvt%ea-)y=^ zc=9EbxdL*Tz)=8RXaJjFHZ)x7@rMuo9vb3>d7x{5?YLF|`K!{>(thq$#Zk*EQd**B5gpcmuI_;3Ffkbp|?znIwGv!%HF!2`+A z^;o+77QyayB;sj8k<%S28K%7=+iQHt8Q^{L&{}A6EYM2-{Q0tvp#{{X%`L0ZM)Bz| zP$8V69zyEts;Q|NP@xqYNfjWvd1Wtm?AXCFH3?uFEUK%qiK9buTAUkQovEJULW35z za;=eI9>a=X_I{A7rkfLdqRyg5-zK_T;;)~^ZnskKAX+f2QZWsk`QY5QKzqgv&IxUJ zNkli4=x3UA3v@qZmw0#VE~;I(4!y8_OkVD9^pOJBrGoV@RCN6M#X{rL@W{|GX)Ql+ zrp>bZMgg!$K<5uEN|mvO1sW(YJ`|M{T(WGtx-dIC+L1j@PC@uHEKLups;POdZN1ok z+#tdmD2!FAHpE2Q#yT5IXOI>ZFMZA;>+D+EcJFmzl*#Mv59AIkY*YAz;O4rUacx;Z zEw`*-%3uU7&w91E=;%L4omzhzp(-j{zL=evu^mszHSgRCwduKiEt-~#G9mrmmw(D9 zcR~dO?;j~viyEPSXl&eF>|j&eA|N2}4hoPgr`NAvzixgw&y=eR4%BLL{ zM!dA8`c*XT$}cMws0`Rkej5MrC04LR+I)3Eznm`ziu)nvo0Tcs(C=#~9?Sqy>{{Z} z{O?Zk#J^I{AX`@AC~s}e0YyU;v;#VahllsKgV%toAxjV2+v9LsamP41I+m=Cu|u8c zR%te_0ECHRv4egAR{@pV($W(4R=#Vu?drlPlB4DL#ox%b*rwZ5Q1~2>mhEknefQGw z-sB7BG5Ylw_>wjE=XWzud#c7{7%W%!smVf@q;2UVFFQCB&K)oH&nCkxV!-};B$ZmceP;% zJ``jS5$E+^)zyhehv@OTJCKXLB6$0qPhy1wNV6Rl$Au%HV;a7_ux-zPT%tH-|4{sfDzCIrDjvqYfb*( z>FF7z>LD@TAW8p$_u7Ey)`~2&O{?A-)JY5Yn1J|ko1j>$|Nc7qSGx40?IgioM&_II<3xl}d6LaH`sHkZ9Zm$m?E&<4PPrWffxgdF^ zO$qM+T1oJMb~IU%G29B_pZ()0s+xGC{Dq0!xi8qmx$v!Z$!P^TUZeU#$`~)4YK!?H z8S(olYX4%t{Ys^P$An~Xq_#4mzpw9;)wpuGXCvCY&z?WeE_8qkZVQl(dF$ICYy4qc zee>^38HJ2sYfFn2_)fk@@$0zhb#vJw2NJnTHP}vqm`~Vuk1dsNnBW<6f!GV=$7Tx2k{qElc zPW3W^adS)P9^@||2>Go7hw|X&X#HA10vgWq>1vP?T=yKZ+-=J8t-PGDdD&bPH?h%y z=mD`xzcw})*Mq+dJ33b|68RPFb1QBxkcMBmrdpHUTFxsE5xd+suYu{I%W&?zxt;?E zJmQi1RFReVwQG)uK|782nhXFx=wIMIm3DY`K{B;Oz?&A$R=~IrVVg);)4C?Xy9K9< z=5Oig#cQ+WbcG0586X1kW&RYxQ}9z{?WRra$zo(7IMvSE%?+UCIGpnn;Wu}Yt`m=s z*4`l+nn$&|2k7Zb@e^Iz-XG?c|3%s5k>dfiAk5!h9e_~D7&}1wr_lM~qep1cU1VZn z5)fELNY^ao+Z#T!@?$m0MB zse(5d;a(9Ea)iFWi_81%#3~bn5TaS1J$Ur!#fujP;gmWB&NqrJp@?q%5S+FgYrbIokwK&80!-K4eiD1n=D+mL!AaeBTp$Z{&)(&b zh|A_WkT7@J+j&U$ptfy=Wj<$Q;iV}-a>PHy>AXK&3+0c?$ulBPRCjX@GJk(H+QgSCYGOyA6McTtiDsi$n>O zj^GR7H~adTKFniaaIgiL2wYdcaR7BSFfb4)MB$T>9s_U~M2~D#7ML{b?d`?HpqkLm z3G5DdYAA&ZL26b^)9fxUXF|ILniLyb;^i&NZuH#R=o-PF*z^%{wL`_ofpPM zNm?SuY5)D5;a_8l+;PGth(G?{FR=>$yBhx=I}E=cHk7(-o!J@(63DT%z!u$mMI7*K z2h13tU?namgoK0u>@!2l5*J7FiH(OR`+X-){F8q7h-b6}94al{BDX;W$50D2^(MqT zd8869#nLmf>b8F0)U+3-6F_6&-;PFOgx+PZ@5iYJuH3ov3$QXv8rA?MbZ;T$!N{pYVblr^VT>rCPvQA67>1!Ij2;os95VrW?FzvxXpG?gAaNHcaAxRr zefcu(<3}(eGQza5Z(2Q4%ne1SB}J{Rz5OmJ%o&si4wymz85nr*N9z-$2^eNzfWhd4 z?Dgve93c=SG0Hi0yd`F$3s2!HUqh-d4lFQ<%sS#C4t zIzhGMLH`G3yR);CJxuE6&2@lPBv(`ZRD6dvq{uH{zQBy3AhZag81B5P4|LGM@Z~y$ zjb7(9WAL5Wmyr8?1=ES)5ImJ%4!&G(QPCPri3Bf0x864=4rXhR;*|unV^RV5JErO* z%dmCm-nEoCIlv(@c@(Ne9&{sk6bG_rv8v^JHA>%`!U3g4m`eq7L+VlU>g(&vuQ-br2=X0u_b|h_P>M4CSZUv}EPuNloP72-3cHWOH>e^v2$BccX-U*VG*e z#tqGzLn+aBVFsN82v)RdNmXsF z5L(&Ld7-H(qgxNcE_J*L^6@HG3&56LK%k?t!W8W|7!MkkKyjd@KDb4DzU-rHIG4CD z+G`lq;A3Kng*6pWj}S#V`u_4aSabEu`>myabJal)n7of-YI=5!|hTgxr-A3sc>KoSZU+-@bf_L>Pb^%73O5 z0~6!p=f7j~{st%;KpL0vG#V&G-}U%^Is;= zKr8n#kSKURB_j(~MG!^^&x)?^^YZcl94F8R zfs;Xu6n1~~;?QuV)sx1}D!z$$CKP!7q5D%^xPnT6{XkmED=NlB)IQ$)fTMq-6V2q% zo} zeHFWoTrPpA7mwy|PecX|5&kJofAROPEo*$`pSg#PDZ3c10gjo>o9tl#LpXHk5co_&FUtpkKgg4P=E?^~GZJi=$E1>D?8Pl)@B7_)h5!`mU zPtdI2^;p&V`Z_VJ_AVQv$h~vRQ9+*5cq%=K_T#zt*$&P)*Cd!8JH()Tbqr)DS z2po?#P4R1As;WjY6lDaN0(S#T!SQ3q21dWa6SiLZEIql6ANV=K5T1|JkER2TY#j7mXtc;oNF*<( z-mhXYWl()^d>a2*sz9rvsL1%Qwfngq$9b7cM=?IPF!BjLoeSf&-2V;+&D;Cq@VW1^ z;`}@E=Z``l_nC*(E7J>So2q=yKubQO-`U+=jBzdZ<7m849z7}m%iGGTAn-F-5mLkO zriw{^!x!SajxyER?^ecQNdP`bKRR~A*#0} zDoN))nygA2U^-P7*`SBh*qWv#%DVS0?Efexk&%%@ZAQ%C4|c(wPQ=(x>{tZIGchiN z0W;R5`rRB_T?JOsJ!r%vFDXEiBYFa{lej|; zGr-x&M2H8_A;7)@wel|!!>^_n_|9QMLq8#DJRla=F4gNDCkCOMrBu&ql6v|3FNJTd zpGo7v5X99JL5#ak_z;bYMt2{Kg9OC2B;NVd54yED#r;#9*|NZ6un^g~vU9~s@&E#% zk|BOQz*0-x;pC2+^tVtIUb|f*;H6C>)=; zGU)wkv&mTuoaONV;vF#m#mCtWNynMNj?xWgOurV}oI3>x;pLzbP^nr3+ z>o{>v+ZC+{6DCA^AfIX2f*D*^ge5w#BAnk$8@>HTYuH_g*2I1J ziQdxQz-}blxI&H%oV&H-K?fIL=n_2qsf23SJ;IMrI4nld566QdqF1AKMJqCT=BD-Z$+KP;S9 zHmLbpTB9D)i?En}>!0_;!`-2@QG6ecUA%bzt1EiFqap;PgxrkvRN*qSv`mIG46rCB zX$zDAauB{%(Z02!0&CA(un3KP0>a>2*-;(?NGq(U=s@7+QY*l{MBnsq-If@@amd;G z&x)Rp>QnxY7a+A}H@)M@pNh<`upmtX3=eY4eqz{h^&ZSJu{QSeee8(M3K&3;{*rA>5Bx?WFF%=H(L_8u}l{J|GR6ve{5))N+if zjE4bu@xw&waAz{i$jpRyY981KDSr^>z}yZ;+mhW52@tIT5!fhzNFV9yvWI!N6Lv*a zz$Cy*-LIW1kfDJPnTUsPNS^-UF?2E;zpAV{UuU&$iHUcqdE z<${=lA#sSITPSthA&&`L7trPV971^luqR~zJjM*77DmFM(cuVUvGj&7f>#B6Nc zg4h@tTe3AWC7ey1@nFxGIYWj%7 z_lrST*a@ALw+*}TSML6d#}o-c^3*Alsw*YfDFzn6 z_n&OdEi52z3n&@k^@7R4-(>%c*4#8PrGh%gB>O#aOid%pc_nGAd7Ht(M4}3AFU5q7O`UZRa)wT z;v^H#DJ&e?!tfB-{b9B5x%8_rR*$u&bV5u((l_ZTS^+9^YvslDsC3F1&{IZ1-2U&c zx->StsA65pJr)Na%(#le*vJSkzR=OtJwv>h!vKaPTn*sT$KU@^J}(VDvhO&o?UemM z{$P%uEG@{s)y$mWbh98QVcCTZ$06Z4>hbWU??ATCRE-W=hPbX06)*g_sJ;Kb0|2j1 z$Ol#k<}=N?{Kx$`p!n$SFBKIPjmE4j++_|~R6jULA`Z*7Eqo)M7=6l}bj0{JI{IIB zQC)(agfKA&o*j>cuB1UiJiZkjG5KBb14_!u{z9`sh3F7vJml;= zK`g-bv9VPq*X!^;wBpb_f~5g5NZ6pD2!wUq#nFb*rrOw_ zwr{jGB^UxeB_kW#7}VZo;dG#KNbWRZQ0z^5OEkEqk&g56Zmtbj6X8C= zOb80)_wV1eFinVbhIXe!PCDQkauT7jm?nIyt20J-qj3pFUQ8jT@yCE+BGQ-V=Dhdc zym15hO9V|0U^K&lH)Bd@)&c=5Cn?u8G@JuC$1wHz^K-~B2&N8V{9^wx{&b?Iz5#3`4i_T_M>5D16dcxnha=Hv6t$a+ zSrVb;Qs+n3^6^oC0TMNDxW8W;qIh87VQOkCv~dVp_rvp2ukInmBxMG$YW2qYIw)}tMo-Xs9ZSiF$b>-hp{ek;gU#;m zUsUG}9t`@6qjm9vBGc1vP7V)*-_=Q-)Kb2XxRqq=N$DyE%2z%jGq0>4)p3k-C-R zO8lkk`_2x13tCSoey^`JB(zaL;=ZHBYNJtF>SV{(P!0u$*s3v?t1WyYQ(E=~Hq)E% zcS!|s-~~kxJdr_=6dEO!p~^tcsSMcJ0pLQ|$G0T$s-8@ET`J1UZ|v^q>_nUW@#iPo zDzfUkyEQgFp-o$%<&HXiezI+ChB<(rGjIq5hf%fOORIIIY z6r&pS2EO9G9d@#Oe7VS7yoRkeS4$NHE}{SH@BKVG+X~7c#&6g*WIAk-Kai&ln?8Ch zY^h5~RA5msM;4p=2NMU{-(I0K>(gfdZvw1JakFvW|7Z*uvr&8)<%QR@XB{t2_|qG` z$D?6re7qCm%#-Y=yL%79@Ldh5?o9SsVPRp6`}cfrZ(qR-PE&F71#E2)OoujTM+$6j zjB|vka^-{uHViqBV>y?jcG~l4li?hzL08_Vbu&^1%z%dl2C{5$_O`d%L9d3mUY#QR z$XP85uR5w~zgl7(B?sM4|LTE<*C7%K`~oWf;TC|tFA{qtRSi~T8Fl=c#kJK}iXF`7&>n$x^VBbX4 zL0XU;`Yki%bIx-O>O3E9 zr#)`_7~ZH|+!Qr;)p|;{er_JNLpxe~e%HDU?~0F){J= zRrs=2X6A)V-5+7By&n{i{0^b)nVNEYU1z=-_;_jJuIA)3NR^Eaq3-VP!1)=&x_BUn zhzk-7c!kKBGsC!5Re3!_!$O!1?B6ITDN#eefGNFC@CQ>sjiI5TClV*T)2e5_eE+VC z4l9huCtdLp4dSI&U{)R`x^O>R_G3~oqPvEOIOGInEps51ELAaM<4J5BlC9V{D|{D{ z*RJiQ7wP);Ee3H1VYgtN>jFd^dy5D~w&lrAn}w0vt8umt4&Z+d4i3_>jTm)U#vM*v z(vy*?1IeC+vnD7g$llf#@BB)4Nkodw>e$XOfbs@@YT76==5?5B)r3J*bPN4j@Cpo9 zDwJM{Jl^{7!GnqJ!T^6Vq#js1Uef48<3(&4L5ktzju9GXxOg!O8kD5~1H*j?Ow+ zBVSNg85y7TM1wF9YzxJ(&FQ&VhM3|Rm#0UPc5jebD9F;1aJvQk@gRG31w8D9Ihr=m zJy$TK5Pbe2nUk{*CTKNhZ6LyC@hUnyZ$el4#YxUE01Sj&8SVMX$k@2u@CasxZ!a*$ zDY8Kypq*0NM67~IhbXVVzkV9(t*W=NzJ5NA1Roz?K?1CCZ{O~{e<|{*RIIy)2QVpn z(xuSgU^op4+eCvWO75e&U9RN&_QfjwP-JTX>&r3i{h_Mh>+f&Um3NMd>z%VBeC$W< zPbYJoKJB_m&gN%;%Rmy)UG{=T2;R)IK@CcV`R^%rAeCfZI5&1UX!AX+rs@!$!UqtY zs2Hba!E@>;KdaCNFegcfAK$)R^PrxA>V^@SFD6b64T&h%U|y=wj| zN@6q}g&_0$x}TpPIHt_?>k;%A*BjX=ez#Z2`QoFr_g8xw8oWLlpw!}6JzT@MXUlZS z+N~PSgey|yZLk=OxTz<1)`W%g8&9SB?B`N+s;L?h6{vVcVIE~(;W6$p``6$hxPsSg~uVp;+#6){JP zTTDtLQalEh@e8taJ>RA}fbD%_RXw`9kC5su`*F0#CU+PZ8n%0w;t(7am;^4fMq6v4 zK~Y1a8%BI?^}PC+;?~;|61xgB`#Lfnk{@SMVDvit;Ih2Iuk`ztMC1dwjgbSUg?FDM z)cx;ujk+_g?-v#<7gt+xr0(ytz%taWS;JA1CA*WIJqf(vkXXgL+8vi9}@4kMqZwhp&m+F`24dg^$fKx6D@L*ivz z$VTx$J>R^Ewy8My+BMXlj_EY}H|sgtz)v!mjdxaGn=!#it^-Pr0U-c-m!TWB~fgcFy8f4TX3JYjc)2iBqD@Q0YZ`Lm?%BXk&S||Sg{vOIUpE5I} z7b8fA&CbihbAu6|Jq&P%od1vv*yp6Ap-~Lk2u2d*u%+=fZca{PNTmx&@Rado|1^90 znwSG>)3aQ_o2)!)(t{Pr$;qc2H>xvxew9j?R@#J!Tr^nK;a+>)x`!(BtSCTR2EZrZ=ZT0<>@lR4Q!pg0A)edkFsT237hL^Pc z{fn{Mlf1k+k->YV*!&v9Xwa7!J!XBX(l{|*j%7sB-or@G5ZY_Le=qUk8DqvM`2<98 zY>)FtI~0-UyV$a{r28;ra96Dg`Vnu|9V{2vx6I9(G4ctZs?o*1_*3HgyZxT; z2Jf1JOk+aal@iznc5$e*{UA+vbjl2wQ-0wuMgql=i=q?c6BLWus65Wg>tC`OqvEVJ z&+qE(4Nv)+a<6Ria>9oTIhO{9h8i!6fAvf&~; zJ%zp!!j6C6-#Tm{chVp4J7Q9m(6hq}^6uU}qH!m{L{o2`MC?^U0({hlbgFL`OOrpP zg@NR+tgL_yJ=HJ-a*ba*d;W#Y+u4iRLgU0soXFgswZ4YB5u?O4KR1VYd}tQgT^0KG zW9G`5nmM$EoiNFem9V|xa6(pBiIbqHXt+rCbWTJ9iG~FazC_oE)g*JJO;o(9(r6n!o+jMR#GxmOm!~ z`rk3%H#8K4kr`^xST5_+U*on43JS-^L-fA?6DDyXE-}$P*PW(oxU1k|_JgehZ8#K5 z=&E8GZ`JGF^Y)RCZ+#D+YKRsh{{%LK-Y#SmcjW-o)_Jhc+1WktoniW z!6vF+=U7RXmK75h*L2yfWz*c;TwD0=YzM`~s}(s^)(3sAp9X|9v`iOgxZ4nPYtx?c zPT)RgWM?x{#m^)oPns5#1dqS-fM!BCq4j&$!J-JNj?rR}Xn@&~`2Bca+)h*KD2wu7 z3F2(5mZ0?ujT%EfY41};Ukb0{OxbJM=l^>6v7t6Hjpvm~fFtku%SuXqT&D{4kG1Xi`xjD&jy0nhMTg!qFD5LPdVh#UeyS zF&@u-guNsc8ff<%`(Yb92-72~3J(vDU(FzfZJ>eR#X`|5)-cFwe&MyQ$T>MBcuphn z;GQb?R?E4z=QCf8el_j9{N`%JKQF%A3Ml#%PdFm%Ys``Jso9lhUOYA-b$IgKu)6Cs zo*es3PQwwQAzT911GnWxBk5fl>BH6dyj^y_<#Y8N9ja^IM%y$pLI>@Xlv>?mXCj(%aixZ~NJN^%KXA;a!#V_Jz}Zedkcr5vAjK z$4~juOO$eGzZq@V^K@298kQ2|alPOPI405kN$(F03aVE7_3KFIv%IU1$Gji?cN@p0B%sV*G1wYpb#}w@*(`Pcm;gh~Cj|4u=ZJ z-f(=!NP;?r0B~Q9LqA$yHUlCf8kuqmd`v>;Dk5y`c$4v^eYKKOpL7J3^ z61Ef>LbH+vLn29|OldR};XFRtzu!6Mo_p82f8Dk2TE2g@T4neQ@8R`&PVct|YVVzo z3P|qW)YNn?Gf>iis`1H!Nn#J?N1h7kwnY9?^+u_F2c;iw`a0m=tM=nJdR@N$@3*FR z_}!JQp6l1I=px~|FDEi_-PyP})#gQ}!wxtNYFY%Cz+2;^I&jf^&HK5zel2ynK832G zxq=ZqOMY(c^`Q&zf4!(Mprrf!a1@@G7xzxu`|xHK#@E8-8!xfkmWD+c4jTkIF}UXm zpx?SNhkv*D3bCF4gFKu!LB<6VyTe4-GIX4~g1&4%9UrzRCU z3MT9U@+len{K)~yAUiue6z0!Eaw@)3FBh6w0)o|yJ$ikwc8#sc06UcziEUj=<_DKD zOjk_$(QDafKl4vF-Om1V&pjk%WU?(bxtX{dh;8uHc^W?nuq$)^=`R!APA1U)UtBQc zZ=^~*Sb7L{Exjj;rm@R&LDSDMwtm1{ewEqy^}R7&}&B*ZOJdwy=Ti`(~svapHFQ$B&Hi+1fdj}6n)eV2}`QjrFt@Vq1 zXp5Vt6l0KuNz7;w0VX0D_OMcPM#fLjB)zsOfJdiOG(nG{7g}Y73_3`-Wwh)h>qu|N zii{i{TOV@rD6|6E!)e@JBPLFY4%)TLln?};bLp(V zk#m05*4BDYbGc&jL*eG7DoWk@DXWYBegWI?V8U@!bxP*PpX7a#O-{P_+{s7gLR_4i zlj0Cw~!JeL4n|sc+v%4_K(r4Pgo_O}PXvcq^xK{LU3(Zgd zDYR`9?%uq4Gbd+Prs?_k_!pGi3Ex_g$zTVznYSh1-Izt%i zNHV4We$IWvz(t)q2ltt~OjARH0qv9jJS-w2g4LqtU>j|L28tW?(86Xx$D%Fwx59`K z%YobLkEm;EUV`UlJ&sFA2+ge^#6++0l5GF}Nys#a4gKpcQ8rqBB;&kvuuYUTY>sx! z2z@zMApn@&jSME>S8{wJTCew)mKG`pns=#PhG#5EQu>MhB57`5Y^*CHrs`EwH*apG z+3@`2S<8e%VlHschQqM4wgX^co&=Acy>KCpo>!HXq=OCc$-OBjj;8RqgQ(ErKppE$ zX1XgX3iv){8}|V5TQ@^C{$U;|AAdPYQ@b{$tRf zoJU>xwG}}>9*X76-+nT{-!jGqmIam&PxacVQ@2^iu$KNVA#wJ#zgbl2<(0FhP59fw zWUf|aj^og!KV6%pS16q8B{G%`GkrTX5 zV2hcVS=G3a4VA{vQ`|`tJ=5R`<;uSPZ~^q)Z#b~>za0F=md(rc!$d`m1)xb_!lF#8 z{53r>EiPTL!uavmq|-y*gMpL|*-NcO=m?*^e~h>hBee@P)C4S7R#iQ#yS_eP zlEOPg1#!3TLvEtPz|v-{nwy2t}O%ftsv$H@s-AMg#z{l$;XG#0kX)*nAmWqrnVN#_gQOaAf2@MKUGvzKnmdJR?e6) zL+|Ku2sGD}`>^MrTK6#bWM>DqOiX5ZLQM<2J}!3HOyayeKa?Dhw5AI@dGf)GnO0T@ z42O|QKSKET#OUb2%v23!Wl|rH?Ag;R;q)<90hE+c(a{AnqOD_)Bo1xS(bA&zEXRpJ zqX8)df?D>m9ap9B#u4s0J(yMp^H%-#?XAs9f?9F)o}bW^?7k$V_)gw;a>u{40KUGf z)nucry}>5vuErxe-2XCjeVrX3Zf2&w`(>376%7q{G_8!Y<>Tb#gRbd?Z@xlBYK{=w8=peagW>dZj;VKNX1K@%4jub2B|KLEy+DAo7x--E@_PnC|| ztx8T8Jfwdx>^^~Efs(kMDn5O3$L?yQ0+sAPuY2RSZ`2lqO!{iF;)@W_?=d+EHi9$ygl=HGXl{PXj)L+PK8U?}7X%7vW< zNKL@uO7l|UWQEMU=ZumB@EPAIfK_o^WG)rg;AQi-!JEkci|@6&@a+i0xAZL4}Bj;cweIWFsOwe;4kD zPv;Nnd`7}J=p0A?nj+In3wnwqo*26{kU)*>1RIq(EcL(EX)ho}=!6v(9S7wk%@wl= z?~4dp?DyYSdnU4fP+U_R;Sh)&WZg00;!oVhi5FEU5+N{V3q_@s2>L{2siv$v#^GQ+ z)Vw0H2?LYGi(eB?Wv4e@colg=yQ$=ftqxyH0#=lDPV3W~Hx1N7(KnhzwSTG;_*J?W zs+AMkXY`07cY1zBP2n9ja!ej8W{ecnRwA!ZpQZEkhflrmDJe9DmS~RcWqydgJv}mxAYL$QZ%Gn|3ryP+1RDcE0z3z6FrghE2J!^^D{jY*DA?kG{*(R}Xgk)=3&cd= z84(DS9lO@vcD4D>G5Ck*pwAXkLc+1_ZhnevyeZ{c>%-#W(9nArGs7nPZK30!R*{|k zC&`MATYdys2qisOVSCfH_PV!kr&Zd_o98NFliI9Ezg%(o2eq)JtsIgIKXo)w=$dd&o7Pj*Hu|$LIdTNe)g>4=54fAv%>U3 zEQ*VZ@qHoBcv4h^ zp-L4~plN~wriBpp_=TF|$N!)=^z?zNijI!<4@SAu_;uv);oF<0u}Oygxn@|{+!z~* zNLn#=1$^|05X*Z6>B z;j%kqLKcEM7@58Xic&eSYRD$cc5FJP@2j&QEPs1DJp73lR|?Q$Ti; z=^_gmxbKWd`AbGw|A3Mnsiah}A7B`#K;F^;PQ$7_y}TL(m}8H%n1Ub!OLmd&n8Eb% z$?og0%EM`XM6>J^+sse;yv5?vL_uolbO)}dOKN(08ye`Bo4)mSUGfEo2)NOj&|@fO znZQ-`%#1bF1tS``=5>{jTb`xG#VODiA4UUQ=)|}E9msPYaN;9N;@}BLygi@xU&gDY z-#V9l2Yu14f+79;Yq^zN4Aj{OBt)F#nKSO)-*-%j(TxT3S`X$dBcY8CtXA0%B9R{x ze3P3S3qBK*lst)yhscJQqW}=l%UL`g{<3_WkTg-gb}5v%XGC=L3i#XJtwKDtbCl{X zLn#>uj`sC{<*wMJyh1FO{9cF%@Xvx->J}01Sv77MeM%x@Xz~Nv(;K9M3?}v`giV> zK0|I?NBh)!)oWnG3=tO-8!EKER{Kx)JJq4LjW5aV zfBs&@S5E3d316F%ZgA%N-N|hS&_Q#GLXdu?K_s{+PM%&L|A0qEBb)Ec>2HB9Bi6WA zWOjVKevEhU65ME`Lhhs8&s(tG*SCe#=e;Zf$T0!9m>BiQnXIj?k0(vHCwa@wE>!BK zODN&8M~@x*qH;(3{!nkB0M4_^)Y@h?fBt+Mo5M4e`lW^ed~x0wVw}@@UiXLg^o;^! zIDgIMb7Nz4{!*AKWJf8>b7dN&^ouN5TzM3|G^3{duQjI+KJ(&lg~|X_-DD&xNH8H29m_klDrgp zORzTN2T5Hr*`xW(Or>uP4PHdSIXWmELQFH`jAh)yt51){Y?-qOc?qxZZ0qLMI(NV4 zgcW&tX}b^lc#>Z$-*p#7Lc=j3tYX8*lSCl>I`yQIPj$7a-@;)BK$KtkwKw_E??0~V zGIKhUba`RA|82TlVUk40Sc#8y`gM_$mh`b%ruj^WW&GohxVAYwTJFWgMI|9*Vv4l* zs&x=1?hQI>^pKjz+`xCLWM+mliWLfr`Dh!=Pfa|wFA7RN5oD4)Tb4&{=M&w#cXtC8Yz$I=e0-0GuVP`?jc*+* zrFP$zKUHKS3DZ6Zn!`3LkDJ2R(E)B0!jGk3!PWKgKC#<@8cB%AyFO~m2$ZwClk<*_ zUD`u#w||;%le+J=@RwpE?O3i>f|w8-x~R7e*Mt8@U;oOt?_ZYcy+Ao$*XtLjomY(v zMyDZV=YftZc(r_F%@m`hhoy!LnamAFUl}u=G04wC?dJWhZ|p!r;#tu>Rwa?VjBVz| zf^b;O%<7ubBFQwLQUJW&Kj@+Xpak5yIrF`2eLH9xy;x4ruQ-Mb^y&c+ZYB;?s_oVSny z#UaV5@25a*O--p=v&D#m=>2pH$C7PAOPSGq3rigEU|uzIc;@Lz3*WA%kH-s?!fp$* zc<~r-@x#LDYz|P3v1?usIl9Mdchs7nhI5N9oUzy<7!6LJek}Eai+8nmBk2f$^;{uk zT7JTzvBOknacv@Yy0ckEj#zB(fixMS``x1-R0AAGv?Mr)ofTb`$LJ8yW$H%E`*O=# z;%6>frYQGiDO*IG^p12+h7r~pajWw3a$%z6<}Q6XmxXxVyh5EOuxT(cz&ez_Wsed- z^|*Xpk5^OJQ~LM!Y;E?^nV4Y~B|CntqQdPbPdwRvSmr4hVq;6nQATEKKE=I zS;g}f7?)zp`(!smka#w;*h9+pt~h%ApKU>rAFLMEV-kzqwf5FeWyPbICk8H?oI&-a zVQs>`VaQoh=Ho>nyL9S866=%tJj_95tx86T%dWbCl0eU3s ziZ@KklQ{Zop9vXwRq%&Q)HUM)T3s8^e>M0r<$0N`BNCeF;luKT8z;K|Y6t3v(Ow9L z%xILudoW5(t(DToSze81s=>$JEK2a6*i#<4w~?!0!<)#KbI;q)Q!gxWZ(#41b8(Qu z*gtr%#qi!xD5bBmA|n1uDFMNP;n0Wl(u+Pz?TUED{g_a%Hx$i7D(R#=+H<7hukkrL zKiTR)Zbina#Z4Tr=_KdWO2pBc$twNDlWh7{;bB6QwseTLjwJT-FBFV|S%HE0EsIiu z#a-w&vL}26c*XRF$?{K}8`{TLGB_YwCgUb%G9_jm^d`>}J;0qxkUl>{|$4lMd9=nPMIhh_c-9(X2o0$7LJ-WR-TZ#(PQO zaOrk~@f|q-=Pw0Ow0iPICcW@r-eM7Ee#lC*w1P?-E(m|BblK z##@Q1+x#^>I?~`Pdom z>8?UWAtaLRpOgAT?ijYB<8pL~prQa7(-OtqohAouY~9;&4O8~GCSGu4Srpy2-Xine*7ZbkWp56{ zmbZJX5X!=nJ2_ueIzlE^Yu4eLwL^Z;8X315b^K3Wz)n%=o4e*5S1?l$vi-NUj79ZE zPE*O`Ur=h0OJbKHat2GKR}XM77LL6O%}rZJ-?#L`kYAwd!kx82;zbfxLIp}7;RXv5 zTR(0N`1QoBc8#?ht3wZMdwIp0N}IWJQO71m6@aVrnHUkWyc7%i2u{F?^=7U%b~IFbj{9KlI>CS@L`ayW0ZA8 zWhJcmJILU&9~#AHx_!R1@tCNzo$DUSVWGM0U-tVQK75!37b?!hd6PzHF19_+WxXe- z5dcfkf+8>I=$p{fJ9gaVNEfXwZ2R+o2jT3Uwf27%4R1z;n1SHFXkmEIA0Fd5% zJ3I8J_=%ZH_$XL&~wf!rR~dCj{5s=b#3hiG-1r_U(_PAL~ZnF*XnMf87dCPrywTbW36;3 z#;@Y_>l>m{A!c`6l@r#?W~(*6dN>*mdyY!The#Wh+jklcvr_Jl7rz-i4T@`l zI>(`EVzDNGqMv~5Szn{y8?$vT3FkP@xzzKu3r z$2UU6!AiqCoXLj=wv0l343Q|gOM;9?@oK4PRn*mWoN63;g0;b)>$yj>u8&_UpavtP zc5$<`CEpSK<5s+4B0g%Dp~0SQF)_})l)8#Y#L_i*iuM+{eje9>u}~Pq4QBD9y*;68 zB$DuVsFJ0EKXXjT6lc*T=!UsvzEEFHO@K3px$pg60A$B!@rxMtr!|6pSzv}C`0b=A z5`_GTpmc{tHXNtpDf(Eei(MIguB8ya&pX1a$BB|$r?hxLV+EZwdorIj*<()uUN%)1 z?pQyw`qQWV0L>D6TK-C+hUz|BG=6ZeU0>dJ3%`@OX`A>Qj%gybb;yueV(`gm_TuJ> zG%#gpGnslW)%_$SqOM$N~R{r83|A_Vw$j^ER=F z(N5A|!$il79YKv88GnY3TM+L+nEj4M>EkD6GG8Ha>6$&yk}p^C2iGKf(&()wz@osf z3HVgp`SX&gClG0Zf(=)A#|;RsPRDTIKajV1v*yhHHhls|k|O`{@%4qbM5px_dFA*4LGYtNoN&E-d9-d~3T%QHPZe9F>0QiB(2&i&+P zKHXSx^WLnMmTnFqQxg;9VEJPM z7{hhtnG+QJ3Hr}F)Aj1ky!J2;i(Jsb$yf>xX>J?%CSBySnYV3MY4s=XrJ^bVzWz%K z&~<(C<%<_B+vj3b0sO`_Tz0j$0Xf-zgd@O`b975g))5;OeEG7P%f#H($kn2XgMDqK zL|*#(F8=+h(el~l<);=75U@6S<5jCBe}C1rG%4_^87&y`RL3|G4qPbog~u4cbI-#f zF*bq$RnXZLc~7gaO1V~pBKw)TaH=nibWJXYV4Ve=^A851a5xgdT)XsTapmoHk;h-ZDq79^`Os5WT1x6> zG>1_b?#cXkXV$fwSa9|ev~6I51efDYs7D@|hrr?!;Km8(Lf6Ww2zsqcpd&-SObyv4 z2aY>|s>4DTEx%h-y}_PikijyZF=i(e78Pla8RNl*4BqE*{tum5ImK728mscRHzs_h zH|Kt^w8Yf6zbLqP@`oS-=g^25!<_pZDH{*a!pAe6uA+wuvq#H=m?E=7qSDhA4iIq| zr4*zg8s7Ekp2X(u`V`S1c;KCU( zHZnAPGBTI$F69!c-7ZJ&X1_{S*!P$DT9C5T~oJ?@hS37;RscBF1gD4bvGB3R=WbN%eF?ZVQ?3 z;OXTr#*esgFyTe`)a`(b!;ufE%t4NCWYj%((7buY4A9Gqrd>ULT(;ckY*yB(5Up)t zw+DU}rlNCicbo7#$uJXMhpa6vueYoR*{*lNOZAV1&FAs!x;mscJY%&GGaPI$D4aY_ zFCk&IAbpvCFv=`6F+iNhW;T+mA)FB=wd*zsBt(`AkbX}EL1x{{kHqLC-#4ISn;Dih zF=6;9HeYr`KS=v8WQB!>_A?+1lruLtj&k*qB?U++XcRHcJC!*$*C_p06Wm*e4Gqs7 zgMjq}JKChYb7>P{n---E&De3^=7!nsrA$SN8015vMmaOsv9#gx)6?T{vAnCZFlGUi z2#{pDyQRt82PelLdhfwYL&o-O_%g~_x=Gm)d@W@Yws)fz3pM-H;NQDi|JzRZV#7A6 zqlrFFr?#i$Ye^bVQkC4BCv`+$!V|09u(p-iA(z<2w*s zE!$YD{PZ;hvEb9!1_=lMi+xz{|m^6D9~5)>zA;9UH0( zM`~&oAj}zdfRg?-z)8l+nGq^KN)aHV#(-Giee9iUf|X#9?rM9AV=)C(fyga}D1{|Vk{_+@`1StarLw9Mt^6K&`HpJ0|U|4f$03ts@F}MHqCie7k&hA zC*NGyP11l;6=Gl@p*WMX8cSV!XWky_Pb_f_TO_Uwo#4LurY}z;Eefx;-kY0-CJ)o&+r!E6?!Z)9%)P6MImi)c5&~*sFnS zbB5kELN_L$3BnU-6+(-zwKXKLcINMw+9e$QMVv~w;FG&_Y3;8TBYFsh4AZ5dBq4h6 zfZ@h_!;{Z^{q{|;^F{PGxW`N^j$bf+Nagd=(o5rdj<|U+A>iLOL{}Zo-urJh#8m?p z_}@tAC6e&FAciKohkp}C zhq(v8cyi*%&wK%^-0-2~%%sT}9~~aS53zmyj9_ksGV2!1?suIq) zkxj1@ICieI`qmR_6zT{v8>Zg9Ej-$2DIV=`wX|iyZ{L8D)O?ae9_!q-M-6#ZHLa;9 zY5AXyq6I<17W65neb)ZBZx|Dxo_s)mEfdl_;j{_5FLW-QB{KZV!Gwjl0)4}8F~(%{ zOcD);Ae^oNyJo`uBIs=+N8CalA&QuYJBnkAiBDVqy0Zx??AmYQd3AD*m-?Crlf)f5Et zaJrkB$y`(i7a#cv%IP(CP*<}P6t0d$ZLM7%+Tr6nC9!$;%@$?r>?--);f40$ z8G(B0sX^AMC0zq}(5yKZG%P8Ot*oX#K9=-AYuDhrcPL1b-7hC49oCTtq;ZQDn~}A? zcf-cHzg&Q$AJ%Nl9@AsEutoRX7%7@gTeh|WC&6MXGd#*LhuFYX%8fFqbv^61V~J^$ zIaSFDQhz2iCT3KV-A#wSscC6yY;aVt&@rMLZs0OY{#dke~RL4vCO;QT5o*uOvk}Fym;o+g14Cn zxC@<(yje)l%YdiMeO=U|*|_@3P#wiI*nJz7RrL*jF@b6? zt&lKB2z^IoDvaQhjk691O?CS%!6V_rn#In}KS(hXpjNbc#rcekNIF% zR3*6x{4-;Yr-FxHGAS|Vwu#5K!o%Ly(|9w-M@P8)#&Ek~2a*^J`3jZ(%er&u;gB)= zc1*aqKR&(=a#NycyX82^=Ql=|#d_P5>tPPYuN$#veaDrL)z)4WqcSJ^Dz88sdcKVo zZQAIbgi$QUHp+0XRJ&d?-e%66YE6?NuFrBf4w#o1$>9lzW(ZkvK{LB~M%FPV%Oy-JmsiR^-#jY@K@E>7VrNk?8>2Vcvz;ubXY{NJ z0pcO21v$`591aZ5`iAfDWci$LQ2x|zcFxL#Q9v6rT2K7v9Wt31p3WL0C~#&X=XhH< z`-3x_Ooy4QO-Ow?dsfk4r@cA{d4I&Jn3;;8oP01}7$UvZJG@5T4?O24wqUF7)2r(P zOC7zy3E4fv)n>QUS98GC4VTAAUB1fvdNqquuUwfMs?{q;ywUyAZxKE;YP)ysvc0&d zOWn!(Al>p*&Jl~v7`Z~2JHFlb@1bitVLVE(t0yiA*mt$?xY?xKW2op?Y}tNy;3vkH z%9N!(k^**-)H9s-3oE#0B(4YJo)jUg+Qd$bqdUjJEq<%e6>x;sx)=Onq@ zz&RYLaQfradE-JiMV|7&095V2Z>7Z2F*ROY!i!Mh{snlIe>ciMm=--fHPz!9Vwtn@ z)6EnQ@((px&xkRm)ME8M9Hjf0ql?!+9f5u2+`bc;TUzzxJf_S@Y5ouk?4;ED{JEyK znm4#Xlm1G!R~O=K<3AiYbSQF5yMl+VZTFt5_eVW6ow36tu3bdueb{<~OXP6vnIs-! zqG;DccRuHZ)0NDeDRFhglKBhX;US}F3<|7Yo3;rJZn|QYsYF}CuDVy!k4ko2OVn;i z^}q@zeR}?hwS!l$be#F?_DW1ByHn?mN|l@YtX6= zOV>>CUzRTK(FM^dN#|r6=1?-1R0PfYcC=V~P@h<3ZH|%++TZktygc)7);U(Pgypkk zXGgtktBL4vZQV95aXTM6N8u_>PCvafV=H?qz)+db@afmRTerMzs!u8}@0;M=s^_Gj zIJ(4g11GaCZrWteoF&-~0*@U5M%?b;0Z!5+6hiL>OS-@~-L0?1`)9Z3kBsaUPj0;| zIqqYB@#Dds3T`5U2v_sb*7~??-H}bNjf&Zlmkw{p%d@;<{^Ie#9xI>JicX2$F{Qgd zmHp!Fe{l>_;g;)1F&*U9MuD#(?0WJzpJJ{3-Jw~=`vd3d6F~@bcPi#;@FHgv9#9TaPap2L7nH7+x1LK z?C|xKhVJsX3FTxb&Ahkz(t+QI7QaO)>}VQQ08>!d<;mW=m@bi9WcX@s*w934)+{2Z zb2fWc!a?t59mw-5eDPv4uRCLcPJqD|$oqUjD6ebRbqk=hTmJxoJl3z(7Q>+P(C@SC ziNrpBkuEiBzJL;3x}>Qm-?#6LmKN&o$v@upduo5GDLs1pjI7TQwf|VxdJX!Qb*=IJ zHKTzI=^}aQXU6IeybkI`KMW?qgTUT-5o=>(5oI~%q;k5~U50NyerzLZ7=Rfo*SYlc zQrq zrQk#1$dyKo+OA0CZ&-T~~+pem>)}uRZ`up|>uDF6)oB^=Juo9Rh zZqtV4=I$vr+p%x#W381rx+eL(#l`KI{Y*b>Ss;3$q4PXE#?(nn>2R_H;c_pn0(Jq#1(gX&zHmRoy#ps(qBTJnDTKy0T;c z!@RWr#=p%=4yhhzXf7QBou%nO*aK~^1%o_dlOynJH?;^>LTG#M1(qry*i-U-gEd$%dDKE-Sst(dIx?c6oTTPb6uF$X!w}zF{y4up`zTPrz=kL@%3=aw?bQYDqfT?@ zXsY+IV-ro~`hVRIc=iGx(o@w9>(|qqX}NDheTs<4`0mEH_}h8F?H?{b#?r)Xtb9OI z-B6=cH)Gn~`ULH7H=axE-TYl{KV>XLJV{ErEBdGSfuho5_EH`7k=5Gy`;8XCHG4s^4rKunKljXrxxj;|3)^sv0V}hb zurHr?U&q!5$`6S*6Cs4Re)9lnX<@i*ekVh6pm6k{=S0KZ#VfS9U0vM`yc{wLP7IE+ zK87uaN_AV16DY+(5?b@8L}g^y`-U5I`+%~lM&J!lPdn%zf|6xP=-LoJa@n3fjVyUF|H~IdO%RVJ^Ng%Gf(_4E~kg~YEzXC5qbLj*)ueE zJXV6vUq5I35rl$66^S)(%;t$7#MKjcX>S! z3Ntf6r4vtrrd|&DsU-b^d=m=QLz1+*0f14G2J~h)kyfo*6=JrW%5+@H)`BphM;FG} z*3cZzdN3Nj_9s}LTFL(2B2#j$``CztH%v`%6w&BS_fQ&R=j=QxLZJ7ZUSNC4_=EOl z9KznxJ?Be|Hwygdm_M-_NhY%xAuDE7Q%UEa@}~db0-ulxBYcTEd~}4&e|P%?RY>q( zd3MnBlG^ZM(Fg>{Z}P%UdSu4${MVFm!evB6TPnks(hB3*Ly-2@hEbT6Bu9=Mi7iqr z233QKic9r7k*!w$X~yB(gioi_;$KdSPBT)+fY@5~pJU|z6Eo7!A&s@1FpAVA_*#S3 z`ol;iCPXl&KI}vjad9}-wCno>%Ub6@c0Q2K!O%GoI#-7OC##~KUsDCs$e6VV~!Jb1fcCod|9k>7rA34XX_Cn%s|gAYUZi|;)qv1C>&ZneWB2g)yk&iRO7#hS*?F0S@Ly^F z)f>WeuP@N#2!=h*#rBr+Q&SbhdUIbtW^Vtt`?nfts!%cJrdToFbt2DE*M)HwBPy0z z4?8w3C#P?4B^Ve{i#%Ev(ElhDl|{ebCwq^+5sW1QMfBUN4~giz;OD$di2kvgG86sw z8BgE}yuG!@qDB9hD)gUz_4ncu`cU7CEXOLP;<-5exNS=b2)xTMTfP#(s8ee_B`7m+F(~mGKK{Nv860CnhlYj*pJzwb(9p2l za?G26GcLcD#eyw{AUQGdJ{{c(s(hlosmY{9-6ecL$Mf{vRdPQ+zYTlgPOQHduBLBj z$a}n60!NYlA?9w*rXele9`abCxVTt7*>YS$j7AXay}#q%yK~YO7jL%f;K{JxG)>RV z&20!E>ZweYRq(%`=@i38s0i0yX}_dfq>6)s(;mz5P^gGr@i7KQXT-^xW8LxTy65^h zvyRi0Pntv|+j2-)SlHy`YfA5*Y{UaXVJ;QwuiYi76ap}5EyQmyUkO*Pt&x27YH_Tp zoZtZ?ot1bHk3e@Kvq5v1>w1mj&SF=IVOw*1JHo@ZBc8|ecx2)eF-y8ahV*j% zj~_qiHOfwQ3p{IJ#Cn!HV|6t$#W64vgRrr&)v6E{=VzxH$s4h;vBWHfnpKFlhV6j@ zorEu6D82ps{pCgKjKd=$DpjTR^;5Op?e6NgG&e`{x>p7?utjKz-=M#xsE*1nH5vGH zmuWiK^JM1jg-c-+@A^!6tS7%K$ncapu8)gUzrz1QmzkQL-X726I{oXTjg3w77qL(( z)I{Ax)8qXK&-3my2`APK%ibQ$#G^}z=7&tSF;nJw6s2t@y zoa@(-T-w^&9_uyxcojpw8bwBbaqze==3Vo`g zs5t7rKZc8`=}0&ts035oLXs}^w$F-MgR^W=l~_w_t7f@n9D#0QATdI#q1UYMqDDnW z-_~5qdfoY1jEF2s`{2Wpvk%^H`|`qxey^;d7*yy;Egy0;p|>5#oQ zyE*gw_~^)T7}?ZRf@H=oNa-#$8&J`9e$2ws)6r2-G=O>eGB?c3<&IUjd$@sd6&?4v zl@-@xRCz}n*TBSt4pvu@-ftppr#B}Dn|ZS4*Oag^FpxYQJo}n($&@c&z4`;Qb>PJJ zTGe9m+OT<9WmcotvII@rY*tl2l}=1_bav|P&?b90c08Y_HdfJ_pT2O}2gk?wq-;+q zDW^s&?3$ZAJUlx1&fRo%r-^jjHhU7zkl5=o5*ya&VI*U>)a=QJ!9+wdXoaDcmzSNl z=TYM|8bf1c79(e;$LDAJb#!8m-``%)YYZH!urrb%`e#%-rW*nV@-&EU-t6v{(Pxf| zc&gUj-SOZfEYh0C^8Op6T4tdIQqt1OYa&ov$;c+nKh0nV8zKA3pcdON{=Z-{-u zEoE&So-iUZBR!q>WaH=lm}3HIfQ4Z=1heBWp`k2}Yop4>0bjWs*Sbt1eu)&@5tVy4>M;W=Hwb#%8leh7UCzV0tAUpEi|a;J?pfQYfIs?;I}!ryo|O~XUSJgM5U^mLIS*-IYy&WDf{5MdMUcS zv2VHTE;}suW*OcYX{Eh@@fNX|S3WK-Ep3^^wc3}XQn%Z$K`&Qqu5PU9A0fJ?9%Gm1 z!u|O1V{Y#1++0bl8>FN;-o!C&h^<*M%3m-H+fzS3T%#;AAKGf7PGH^ZD}920mGF7f zb7f7viD zoSmJEii(2y&c1zixF5Pu1AS@%3Yo{tw~ zsM#AfyL1)rwxFVt63=!ki=dxTyt9Z}-1hE(j-$<&mLhRWy_tI;e^J`Kj+CT64I!QeQanfr-nvaa7o$B z2MZ}76%$9>!ZS5+kmlp7%SiB0FBll;@8><74GnUS=%30%=lH~+!^M=~N{5xbs)^Hl z4xgu5l{+cHytXRgqYaizNAqTJHZ&F@%E}RA!Tee;=HOQ$2<;bW2=Vr*HYCBYu-m9^ z;-F%ao^*&{^)*ViKMYG~Byh`^4}YhZ%B?19 zAtQy;spPAdE>G5b!EN57)Dh;&s0=a&K}uy7jtuSLsqHeYnpWZlPk3<5U61o zc2cgwaed~tI4+g!z9aSbDuMCk4@XdGV?SshrX5at;ma#1^ljl{3c0u(iBh=F?$MNx zwrF_y?-@<5teEZJk~gNdXNhUccXNnQ_$NlQ1G2H3Z#C(C4F8vl)G*Gew%7DmERS>` zl0JkG+nXeGmGT#4i1VEczSB8IPdO?MfGx7=&-U(H;nE5V3lEnS*18|}^H4J|NRJ_G zd~4@#|0}SfWR;cslZ68`R}V{!yB?GWD?9qg*Yq!8%m-P};AB}cqV7nG$;ilvi{BIs z3lAT27|?=w=DOKH1d%i^w>IRO2XFKzKJbv6AJe7>wKG(}5@rb15e0#4^T8@58;yHx# zHT%-hNtfMY#G}>mI83YL0mwuteEOc*uVtu3a?c2AjtE*qX-ZdysO`T1P)K;(asOd7UUWj)k zci-tMEPOVXr1$$%5Xp0KSJZ4%=!EkE*_>#x!%DweiD5<%}<03>ucC zrKQDjIp&L51(Q12$leefg-K#ncUq>so~xBvS?SWB3m6jBO%B-;pIRz9bq!MVNpF@y z8)I420F2`cRv2)6-UI%TL?)~8YKSXNh2r#ik6qlHX*02~Eg3yeS9BOv3tu;dJWg=i z`nY#c?{#%%X2u7Nj+`MTdlPIgbWpIFe>=1?dZsEPSd06nw`x}Vm=QyLBaO~(=f$G%B`$CqS^)!e+#*{Y(H13JkXV$ zvFrb}TKgXqdjI>?|5x?!zkQgbV{mA-D(#&ChgI1xO)vSwQ^qj9gRbo}Rwl{eSBHHC z9)tu0vTACFjigq$iHKY)MK%g4P8UVpk9NAqhXAHR?#@`g1YaB=1}0!1>Rf^c_wP@t z)EyD3T@m_#N5-MUvJp+;Qyhn=22L}b=Vq-JKw5b$m z(=#xPLn7_Z)5yum8QWTgE3*E>^&W>Nt>$B3pl0FgdMH5ApyPK+a)>D}7;qr^*{)^t zL*)a3l!RNVVBmZ!vaT9RiMq30Mn|6Ka1n~~<(Z%5hhscWk2oZ0*kanC!jq)R=`-E` zT>ttY;ruWGLRw`G9-{4qa!zSkS^rcNrq|Te2a2`ctk9}>5;z2{vxefmbSPutVZcj* zdxq4i+Gf5rD&h%o{>J{k=h0FIN?zQ-VRs?Hv(~UJ8lD|CrLL}Sx^x_;QTsgu^O^@Q zUK~Jza9=I@J*pZtJUk557GMM>YU+&a>})6_pdgBUZl-K(oVkbm{Q0xbH6q^KUIj}x zQ#e1CiI=!L%@uMYGBOxN(}52B>(}i!Td$HkC5i@<4?leV{5h0nP|sDl%t8`auRYFZ z4%8+!5eXt8BqCB#Rb6yxhEZCj6Rg!QT81{e~ptm+q2QQl(#~dQZz5skRRq&_f;yQ-3_Vu}0gv&2u z)^RBO0KM5sNI`X&FGZ6LV{m%d;i+9_9wnWjfR9-0d^3zR0Vc$@MFEyFKjqTh@cnVu zg5u)to>Kl5Vh-EXu@|90cA-D4-G*svQKX6#)g->K?jIc;{oJg-cYhJCemQ@F*?jO> zIrra(8-f`=Jw44n?&Ou*?Qxx)dvNU!q(Zyx`L?5WsL0l@;ou-eVa<-;B+SWK+oH+a zLr+Z9hg7Y)UwOGda&=HI<>f=hzF?}@R@*PhLw>3pK?jY~BcLBzPs5Ls0E(Q?v)6Tz zFTomsP!szLz3^Ehss)65LzTj4>i*Ei+n${qqD!LugoKC)HozH}G71r~1C?+q88QiL zvmuoVH$`8*{H9$*#pQYC=ImU7IAZjwCmHnTb{G@78K)2eEEt;rH*~ zRkrG5P4zDOYh!+<*p%L#?P{aRaQlYrGDTwy@Rew>ZYElFyx%#gX=ywg-!H{y-yChH z53Md8mb7sYmAP{DYI!?)ppmz<2^24@rI9_mdp$m1@L_LW-jMm;D=9d{Fzry4N7mw{ z{xT(H<)gzxli*dL#7s-svOmLosw|b?%^tB=(AFO3l);4{Cha68dqY2*4b>P#iulQm zrY_u%_nfnN+xy6lJb?iV?!62vHgD@wzE1Yh(c3Z4^HcOyB_ol&Ykz>58YuIul)hkf&M}eInVIgA7JU$zeK|| zBj1b@DS8t$G&HnCGM1aE5Odl;(Oaoe8KVgXWJx6*J2>eBIJ(@`Xq5Txbtrasc}!VJ zs3pI?c6`Rj*bzhs$9TKZo%jH5dwzAKykHG=W(ADp+E^7=#j+9K@er&a;7ryU)5vi# zf1<1IBXX_6*8=wT$UVO{!;x<`DOK@kz843|pXB&l!7BfK^$Odxu`hrA{GEFcFdbyp zMk}^k80)Hm^Nf=QLbDF0=tC;1My=-+GoQHPo#% z8MY`ND+8Ja=*x;6=ALw^mOp?HW|9$tfu?b)&<=QhSz=8AIk}j^ob1wPet_ zDctcYp$%QmQ_XLkz~k|JjfhZIQrbOSNN_FGHGU81kd29niI-Q~RW_q14Vci>)E5<< z`pgwP&%8f;=!oU$IphE`dl!QK=y5e1k3f5DS0XJiZ=n4W9OyCX<~{4=>gp2+sJu4Q zFH`a>-43^Ag84iSHr|x?)|-}&S3CEFv&bayp6>L>RLzM&(0`plf0=Oer}K9RjSx+= zH8oe4#FJ?J{r$;Z7L#C9)Sli^X`iTaTnB<}A8MR@oUd*36Q^sA1_lQ0GA&I_&Jbr+ zKa<03^g(_}d|TCYdtJF?F5S&tlp>;8S=^f26+iR8>|{ zadsRB&485{b({^FHEFJX%9+BtZ{FKdl0t2a&!(mxi96 z$9XH2RKp5JPL|?5&M+7CU)dtQ8&UZ$M9lKvK*XQAdI&MNS7FTim+Y7G+YGl~8^8$? zUmLi<8%B513K9DK-=LrT+wtQ6Hz@Ug&-(9^)c*4+fu555q^Y+a@Mm1RDY$4qU{NL> z(>A|EdjTa102h#?b^#+D`jwNHw`(6XOy=o%J~%jt29s^`D-c4fow{_3oGRswdB{&N zkTnH-R)$=nvYX0FA~V5mZkl}Oam&lxIix;eQA!#O}QFdN7xymQCU$OukWWFoAV*AK`8 z!Vbu3AZ7vh%#^DOKHgbkaXZ)`=W(%L9hBoyRZy^lXb)8gAccbZo3XuZx<$ZuYu9<4 zg02L}yrZefrshd#)6R4NW911aNq(RZkZyF!xyFT`fsj}oD)}9L(Q`9E$9|<>%5}C+ zMTefA-oaMP*w|P^LOAY{WN;bh>ha&Y)}1Nm>?WL_ zEDV(x#l@ZjOD8s_U2ds`K$Hb2wf*_?mD{;kz6Mf;vWf~9cV1g{RQ_PK^EM>BF%7{O z0T@9K!C#B^`3dVQJG0oBUh3+|t^+j-RG&!M`vdIFhdL8tB6?#POQ{1BSpzcLn}^-z zXQ}B~#8?~m`1trxR!=_wIbc6xQ4RzWEj9H5a28e0+lD><{(gRo{dpq*&8cMKt4(^S zR6I@{7dxi__)Cb1b@d%agX**g*8%WsX=%xV2rKW|jt^o)5UBh^6i{7@*nt z`AYe)A#=-($E-=r2u}OONpVUjQfwb*z7!VTT^rLVI2Twq_Nt$p4FLj$Mj`z&CT73; zpNR=RNL@@!HU}G1Xxtf(m`vl|y)Ixr&cvfO#@%adBLk(SL>6o{1WYccuTtbJ^2PdBhz^dVd_Jo#}6S1o5?$a8>ULX<4uxtsG7HDVU;^Mi=W=>8{1==<5y}ZId2nq_qVam;i zm_wU-2P3n3mVnmO)zj|6IV^QQR`CaH2U7;E>BS{PgoI3+ z&UyO<2Pc4>dDK(>m#60f0uR{LKoLC%FR+Nr&2zVmotzF%_b2My4s8coKFo3-peI9} z?&@F>V1Qb;!(xr>?7Ohaw>02RRhs6O`Lvia?%4*~9-@*4dY(XjsqNlxo|233KrtA7~(&!@b=zTNP z=hHJYePb*}?YY2lgXF~n45}v_CP#`QDJf}x)UJaM)H_UVeIAE^z`$y#eOz}IlU6Y? zG4aT`oj|w1jp&!$tyz!?jg4L9&fGzb41_Ba^#RE4Juxg&1^H2^imMQ?70m)BK% zWyGypx2|5lD?5=8I^}>~HWdYRE{CmAEGu}Yrk`eK^$i{Zo}Ri}4P(T1UdOn9c6HHV z@u+Y7@zU;_@@THD=S?u{Tx>GEq#X+kCC?2@4ts{xxA8TsOnnZ%l_6rNqDE(CdJJ6^ zl51$6JaGc9m6ndK@8NPmw@6lQt|n-fpgQzD1hpPyF^7)pSXiB(%AUesF2p$^>(qP* zARNN7?*8O1BQ4#3#%mb{PzHX=-V5Eq+TTI`%U zkWivSsL!f`Rd3v@z;8%?h=FV$r~`Gza&?NBf}()U_udQZ@358*+Fte$C=ORiO5Hy+ zl9C$Ao0v<%#Z)Q&W$i^dsoY*+S>mqTG3(Ao$(xs#SFPk!C>=SkPH?gMm5Ip`5GcK4 z?QvXO6dovVgf4MPS0?InA_h#TKRNkkoW0Gzo#wRp{}N&HzE*Ts_a5fGTte zaP6{Xim$7SvY6P%O4RIl3xp=X$ju0JndFhlJ8W~Zi(8bJmDSYIq2fr|r+cZ%dG=DL zsm?iszZbDt$=EO$VN(Ov%7oGS$7Ny=XqDnN-C1izC5Ffp>Hvdx6U~&flEi6q(wCG*Dj!swoSc0A zOki*#1NC-6LBUVgFGwWoZp347l$4EFnibAQN0UH4G2jA8x3&jzT!yrk)TjkW3 zom_l=`ZV@#J`?lUFZ^z`}pc~jDUMNov{C6&wbX#NX6e}KnnPIfll zy%*0cM_(AQ)6=6s4%{t$_bn6jt!7O><($4I`A6tj&eFA;qt%0#!uPrei*hTk|5~}a zFedT!FVfUYE04U(TnBx8BeW|r#hB{_y_sd0hGSvM<&41h^CL@E(2AGkhKSGWb-Gc=uTkgOaHzx1PfP;tU0hW-ydB9JmjOx0rzkiEX3C8~PKtY9RN^}U| z2X6DO)?#Wl%EF431SmQnAT>YK>~>O>o?T5OtUZfiw^Ba8o;0vx)cUn+_EWC^yGvJT zNqu~Lq|d&0QB6p)UZtl+sj%17F68m;&uirQDCZFTp!x;5r^GVv9&4}hsA@;yEy|bQ z@k1L+ebp6L(>JemE|FB_KDu85-YFDn9SlxnW!|irkVPJf1j;%F1O!0xFm?RIDVLtS zhK*p*t~M?i>fOCSvTDD!u)uCH%!;xE02NHm(`zYrC%^zTTnglAdy7o~(87R}xHzUJ z&d(gZw!KM$8mp_TflUw<7RIK8#7s^|XfVJeQ{~nSWty;105@$dWZBfzN6$5ucaPxK z($mxL+_@9a?Y#B<-KDj-Ny1{2Q+$32&r=@)NSJ_C6Zkx9w}KXd0{|uGY%WrVE$;`I zSAe{eFDsqtS}_f^qKfuP?7m|^u)>#no+GbcdNwY{w`Jd^gX3tDKHFTTZZtMbZpCVu zotMWbIY>V?I7t>YhJ$pg=!yWh)l7cX8V)wLT<{CEZ(2!E(*NXl;M98g@+FLkFCJO; z*;dJrIo`r~DQRipzw=wXydenQHuI6PHfOo|`g-sk zc!%CHXBz=t8;^`rai6k^K@3mjQDF+%<%w49dm<@JY;0`o>;vHo;oi1-MNqptB>93p zz(Tf*Az^FGaYC!YR@lVV#-~A7t<bv1sYP8w@LP5At$zHZV4 zQT698WAj3VEl~Qv)OKokR$q{utPAzRE`5ga{zz}QPQ-BI1v4SC=WT{1V_0&)>q1CQ zqj&|dh|F=ctHyO7G)APLa*=u-At9l(v~?O@GYXx`Ks^Yns7_8!1}tVb{R?~UvPDW8 zD5b)2G`J-8z<2?vah;f1f3Wb)=H@1XoquX-3KID8P{~5JQVxmI(`sQmUJR(AfZs4W`suwv6Lvt|W_ z#GzkgGrdw5=HRg(anskZiB)+57H*GzB62lU;D*Hs+ z)UvWN2zi;Ai}2v`gBc65v%A})3Gd#`%&+f;Ne$rc!}bF0s^x9Sv~heYXzH`zt(1oI zB%~8i$;ALp_7&YTF)@i@v)J;-d%diq4>TN~^On8=PA`Z-2Zx7BDk^4?G8~B2uUr1n zcNA{}Gp7N%f3X2XaIHot6<&YG*u^wk>`a2Fzzg3j(Z-+cPo{XQe0EfzRka6ViBc^d zELvbHjZ)OFgocKO2SFZUMV;dmc(6e3M9c3~DjoEHLxn3Ok>2@`5ALL@ULMG<#b=qC zW$JBgF_kwZ0=0FPcg_>mR60;j0oxr`uRL)x0z|=Ab#co z1t%oIUFk|tFW|ZmTbckrhsR*zQ>nN@UN@D+#=#MP_3DM)ykw|^*>lriynqH<@H~QZ z;iJa2>{T!v#sS|}f*Pw*8R|b9LpJ#b1b~&t85Yj*T9r&iUDuL54BX{##E%C2?_BHE z3KN=x4hu=9a|P#6qa)TvIe;cLaO_MJz`NSc(VM5i?$Ev0$d=LDhdD0EdPg9Qhh*eW zkxr9~J5t&)OFBRE#&lR)ggss6PS1*69A@|H}bWgt98b{DY4VT5bYS z1g`_B`jm)KJ1{s{1px)ZRJA?|XN4*>%S2)S$!b5bb+HRl5gA~GF3RE2GzYZn*k8dpzGz|L8KXmA&u=7qd?{+m1jx}bEKk}1_$39eU5q7!q)|`0v?wzS)KqX>*T+41n!t~i)Fxsh2L_zpd z^3{Jr!etU1*W0Uz%8$%9%*4D|qs?c(C~Hs!_!hN4_W(sQ0-|^qL!h2$RlX)Ho0Rw~ z-CMm^6JbD&+G90H;ECxApS zdFN>S)9@QfLGw=5?ADFVC}Y-P`rzbSy2vi40;->GavEm3Z*eC7z>-ILj*~*+J52OL z8q}$>4o6VEWjwY*D?K%1U)bo1i1=1QJw1fU_4)-9#5K7Tku0=Bt!M>%o*q6=8IR5s z(gP8rYtW|gDn7ZQS6Y{`8=%V4eWq;4=_am$##VnO`=E~8_%m=0x}mZ46e3T+3zG&7 z6Z20*yYj~+zxgrIq9pw52~th^|JV%Y+Wa&eF)Gp@#bJ9G*f{eXZ=T|;x~#0O{D;1fP} zaB%RO!t(?oEj&HBJISE9ul8hg!0-CHYLs)r4Jbyg<9lGJudV1LfT;%-D!42)7Jj(2 z0X$evZ3MkPKWyUf=p=U626nS%xS6rBzc}10hf2oeS#I}|Wv>Z#7NM@1!|sfShnAH= z_@f%$tauY1Mvc6J-WUE{7?vF1r1*G?`e+Z8vx;~3*zAGe`-R5vQ&%Kfa zno~M&0+>{QuB}zgrKH+Gan-zcv;?DPJNs&3VRmi~0Aib#Fb6hmei*FraFHv7lrMo~ zWXlW#hkkcZZ9eGBza}Q?bm}~sEnmNW4Sf*sa$oQSKa=EPUxd^0rA}KNPil10gO2_U zoJ>G`88lm!46V9E7^_%OX$lM!ARb9(kS3c94X*rn@0JP7E2+_7Yf2tgQ>BGpZnuf^}h7Bzc1Ysz-1@Lk4%LsRda-HPzcha)eOE9b@+J z2rYL;6%~SOF3KoA%W6tpWy7${?lK|L*EnwN2C&LU^wjhbb^X1)WSgM2RS$zit6{Ks z2#^z^&eGEI_kbIUo#H1x2U!Udei|v7y!ly&Kg_ApK~Qdl9-b$srEtg1EiF7+WKK-) zanysQ{XUA!T;k=WGc`q&Og;qlYgtrQ!0cN8k}B#3{M63G!=z411O6cl+z0=K2BQC5 z?fCz@o}_nDD0Ee3;KJKT=Z$$O85Iy^kv7Qx>#+RG(FMbYfx*WgfL50OS6}?E^`iZE zrqW&T!_h3-S9W%G`uSl6G@xD5sNv@_16VNr#sl2Mil8WZl`K3#j`np(Z7wW1Y`{Yhxs=oJJvNV&(U3z5Y3_O=EXB><&KXOy@;VP>}d;f)P(7J2|?Aj?1} z+)6kYL@+wtitSIKJx$)iB5&IcT3A*;-3@AlhK-ymC?oBeGC{s!P%BOa7kG32kU1|H z)4_7|FCriEw{*t#=4KR=o`|AiFFJ4+sgi7)qOXrN;HkhIsAoJ5%Zhph;xaP$czDW= z(CP#);H(BFed-R|tir-{OVz=Me+KF}Xmncctel)KfMh{Xx+w^bKuypAJkR$%Nj2Ef z2bG#1EAa>-<5C_1%pX|H^yY^*Wk&_dlv>5YYh)BNX; zwXG6lThLJnewdb`2|ej{!1`!Ub1}LZE;I8W6no}$R7ds*hIqZJBRMXvjn z297|^NavHhuud%g5*ewYuD*OigJxh`9did(`mUj!xky&9yFkZVKu{2&AS8T{KNYby zp}#~$MdcbL)`hcJ*vf z7;q?eTxyPtwLnQ~7J-~iCzEZ)Tug%2$-kQv$b)CIJcdD46AE*=qxU`sF0?_algMHsd{YZlD$L0-)m0RH<42-*8f;p>83T@AB=sA z>d6!(HMJ-ifAY~<)jBB9l?c=_Krv7R!C@(XoLOd&ZW(CviYG5Uy)k?n{eV~#o(eRW zmI6M&l<8TrN3*15;C_ROU1dKOZ3zU$L(q>&uW|57xW7M6PG7eDG*G{YG+iiHntiqQ zS}pR&pwSTw=f0t#XzY*1z{akWzrg#Nl9J*>07MT!2eS?0@YaXk zPiSaNbkqJ`M@VFl95ENdJf*!3Xj9auOtMxmWcE$YamF!FQr52t{yk4yjJo2*OP8+V zlBAl0VXgv7>{=EWE{Hk|-hWzKPoSFxDWnO|CORsL#`~3+7&abWK3B6a9W+-xeJVM` zYdy)ot%IIj7%EN*vOt-{f)9#d8Z>v1)~#&~;SmB!xw^7KN=mlr69I2NN%#b`PF^mxB&Mi_lG>yHEW zr_s;eyf5Aa{xJ@S<@#-W5T}682JSAU>xIY30lJ4_S?Er{9Q1Y^d7iJI3yX@ zjIsr44tiZ`v?riGfhNeDlA8%Y-ovuB`ly1A#fiM*UCFwvB;oa&f__l+SJ{4S(3Sg; z9!T=Md94e$8hW+jM~sXzLtrK*es0XARm-}*n3sXfJf2n-m48s<|pyhJ7Wf0tt#%#u-ShSxGkB-ik zRqEsyF0({QqC4Rrk??5Hq3>7CxVb&@D|%QaMeI*aRbd8Mj#n=&slz82C_l&6qdB$I+wkwi@EiZ* z&h!6Hw*Q~^yZ_tH`Z&7&?tgdz{!1PA|F$dmkF)+YyLl7ng5~b-VuIj>?*S|=c~-C^ z#3*O9IU7$|QIQ*d3!kY#y2Qc9uY;CtsI|GZzzH{rA#g<=3l|sFmlHWw57t+gRAz0_ zjGjLCeJJ-tX&=^skDFfe+cO#(v5X#Y1wpqu_&L#_CO#j&e{cc+YBv`jIDe7c_t0Sw0xAkm8)DPL@C%*u zFcp7^7FHH;^yWaJ$>#) z&APk|8y^r0TzTtw3?28Vg@p_rc`dC|h^3s|6`7fta=)h>NOqkuF#ZHCeY}8t2owld zN=v!E#>KhMw-UoOV_@{c6H0VH1P$W^lq+qpwgO#@MD9$SpRt!X!ZW7?XQHuAc1{j7 zip8Ogq&^(ZQIX(;`FoF=)S>oSe`w59%k35|DqEKeDkv$A|R}MiNNouxSBn zlq9;*FF)T>Jsi*-#0w!IA?Poozas%cDX0#>hej)_YsGOo_<#I}jf)F^$^h1=r%!XU zvTU5v>tFkU3<$6n2d5I6y`g6yhRt3zqX%dJ;FNs4y`L0hLc<%hd$hTdF<@h1y^@p+ z^z+Ni%cBRI8MJXmTxoz{c#n*1tVmBZrArkmR&ZY@Bv=)xM$3lnQESV~+X7xFA1I4b zU%Yjbl$4Z+XaL;dIVuJ7b8~(B99AZfJ0WV~!<53p0`@2uU>3X>8LiY!==Uv5CC*vC z&GGFu+OFf1V07w_-%x~%Y6GJ-Oy)NGMHC%fR#vzmpu!9AqcKGuFi`U`R$zuzQ1MU$ z_l7i3?0{8Zvjmq@eDx?(Gc$nM(0W_sevAO#MAt_&h$I{uB|$ZM`xc|>1A|U&ERY2- z9%%Ji3>$F3L6eM!uHyz+dih-Ua=VOU0R#XY1$}eb?#SX|^p*`kP}!K6WVt+}qB4ZO z2EZxsl!ilFT3X71^?|)HAOTix`2)-YrLPlupJBfUIG1*{6L1yavN25<2m+LC*byHG z_L7;I6mr0x@DPFWZ)$GNc5R|K+xP$^N0pc8r+bGZ6KC@qG$1?bxT2n?be*jf!eRtb znJuZEGtLs$F|^q&_GHL_;y9K9UF9%+(9P=bZ0J5VK&t^vJG6T@u47hPBx(!5H_#=Ev0IwnOh1CrIdp+kr+w zV8)`L!E$}Prf&w_yaMEQmDA?5xA)~aKd>o`l>!Sl9Ir(IWG3tfkhfNQI3F|I5rPKU zygQvjcq>%iSlHN6+|IUO4}keKc8)LT2Z$92oYMuqa~mG^%F~*y?sMYN0}59=UVPf} z^TZ1nZL?$oY49gdOCheptOp5|h+bXMvFQ~hm_xopFGf#K5874@K!A(J4R9uu0Xkz7 z#W)lc2_u$OD6mY#aM;aHob8oYS932Yf!?qWrV*g@qm7OZ$ zD}fYi#oq1bo6*L)J0wzap-xgeR0B63b`3sBzAZfm;y#b$rLGEGU6W z5V)cDRg4a;4$=rh>^3pdZEI;svCQ?vOKL+wYyFKIH-Mi@Ri-5nR905*O(3{@@!gRQ zY$MQjZmOpzR3)PxN+kt54BRlmU%q$m9!SV{$;jLRBEy9EQvAR{Pv}?p$B66q?yMfo zUJV@ahBWaV`_@_tGoU%JLw1h0V!=gdK}Sx6Xd@US>Y)2S+LUG)vJw!Y%x`{NrXK

    ?)i1gA;H1; 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

    0$R2sco{aml!XUtW9zS-V9Y+lts>_ZU4 zOz_(3vWIClcx)Dt8)R>=CL#JW*j`y<6))JUFZJj3UpuxRB_05|s`kx9wq2pM!j&Kz z#h+h>sP#wzeKRcbCkaVfd$rp;Z609lF5&;NFn6krq-;iu}>*U#6?c4_LC`$!mC`&C7b# z3$PhVnC7$3J39&Ur-*Gz|Iu(-MRK{%>}y%3q*)-M?%BPVi_I+QygS#eSbJY8qJPSH zzu|ZGZoLQj8=Hvv=5I9>^CnP|`XIolpO-PnjZN=5Xg=qQb{LPGBx+-z#R}*Ys@}Fg z^(>wj;nU4EEx;ndW+z%<=X_iSD4G+&^&jK%9*L5KxAo=96oNzZ;y?*w0^P}zRGy|@ ztn$pgI#LkViVxC}Fl-W|@P72(h7wCqK}f zpt%H+4XHm8#~@~`DqyR?5`hF8N>plRf4Cn4P;e~aY{GX!iiNVMu8y0R7vbi?U+xpH zy{oGXfpp&|!0i%=UR|nrtx%$)TZI!bWzi^m}av*6h0<`Y7>gs?c zz|jwq(%~0klEu=O4!W`D-*kNOe(?n;)XMEJ2tefd12LSRDm} zt$h#-62la{geopGWHq9s>v1#LNi%u@g8rCm(5hVUZ{4+(*TQI}|?^5!Kx4 z4;XMGG04&3+#ogq6gn2CDRt?QD}b-RmY)JikZ~OhC|k!YSlqXBWya>6k%zW>ryqt; zy{)S&OJ=V$I>{BF`A|h#AKVr33exia+9O)%ry#xn-uf8Sj6)@Iq7@L@HaBw7(F0gH z2wX4~{u}PX5Q1ti&sqmjWe|m~MKX&b{@)jIQD77i;0gP}%v(D67VJT4KHHv*%PHx^ zOYtus#uDKEJq(>HG_^_Vz0aP|`370j~$1g)U4=HYS8yp8jNAa1so!h- z+IepChsI(OT$yMaqK$+lL*4OTO1~w%Gd}8i?ESPs9X_A{OKKM z3$_aOZD!JUJVto3W-l#uWgtltg?iOUfSuB0M&+9Y$0M&+1YJ_n(IDIY+$1sLU1I&` z)W9aM8sTy!`rtnIrta=DMmE$WO#gW=(Urd@boYm4nnoR}-n}arv4(=Le@qCb-?HbW zrDL4+JD}rIY#fkP!~({k^=~NdCJuhDgof6V+5V*v4Vbmq%j>FG6=O>{HXFpUm)Pq3|)dmt(fv1+yN z+^l!f(Rm#h+2MC(?A)i$&N%VIA(bteaj`q}D|cZ!_iunKpRX)AJ309QnXS}Z#v}w$ z*TExfrlTKqADl|U?D`QSmB(kZ&Sz+}(vALs#Vg)G>x-l8^gsc$&hD-5PEPszS668i z$v@mUen5Lez~9xLANCwtnw!uXD0cbJuIR@DU)z?)bij1XsMm3V@*!RLy60Qe~Xh>VM@_!Az;dP7CHi1-J) z+`UdNE)Z@^qsJyrsC?z5v-#B*zPv|!%P3^x`0^`F)%;DSj)3rYU6J+(#LC-iefUO~ zRvE+0mgFo%XFbJ=s6j!@`Urajg&b;WRPS^0i&M78H%)OF_>|TixbLD>ks1S+rsam35K~J&l&^MF)9yb7YX?E^~nH=;^e$qst9ldsEE@o349~@`McL>e2)EEUao=F zMp|FWYxeH`bMrV0I4vn0iC-y;ZTl1Mv?)E5^olnGiQji!Ghd&O=x*H+6@{O{IsYQd zl$`Uzo?ykoi&OeDma}-tG)26`w|-vF&CBbD4;|QW{!WPM$>kD(4o-f%=lQ?jkZX{W`6?|yzoj#(OV9+H!opKku6dv?s9j!voT4A5^OsRgjwmv-vf z@69r9!X=8niNulc1_==YF|w;7GVlBQK?6J0@93?Qi)QEbvg5Q&JG4V3&p|nQ>wlx5Z*vdkIf2ossefXcr@kgw;dr*dbOQyTiB^l(lSH1 zJ6w%}iaI9raUApm^*`OQv2OYm7aW1UA&N=l+Aj}46#CIS9q*7VjgXk_g`A5GL=Y{o zw6c>ebrzATKkgY&k}CN-5l^DOq`W8G{H(8EZ|7-u|Ik<^wY{yE8I5YyshD>Nu|G8r z&90-04Z4}})uE#R?m>WoL-a_x8~$Z(Cw9H&nFMy6vu< zFE}*C=)(6+clMT&N?k<5qn@EJkL!3iE%z-yxdgUZNggwqf_)p`zV*FN7eI4pd-ok` z>bXGzD0)}d9K8`Ln?=-!qzX_e;ENvV=Wf7=HN$dlP6Z+x}hnGG?kw2}zPUnMFb}yCY*l<`AjKP|-k2G9*LhGKC09C}U+NWXe!U z6Cx!UDoXZo_5S~R?{BaDeQSO9de?fNrzh_FzOM5+&)@I(9mC7sZD%YkxdL{l07U{% z2s363b&nkR1kL~uouAA8;o5Prv9Za?$d6+rKwT7v)9$%n-j7DteppKhhAl8^SSpQN zvz7Ub)v*&@2s^=iitzsap&8)E3=@il`S0JUg24|$8EZX{h6!Q2JEWwZ19Sq~CY7Xw zQSyx&d}@I=Dt05v1z{%CM3wF1Bi;O?D~RHuyMPF^UP zR35u7bjw2CfF6mKK;)UwKJb4~2NBG1^#QQ8ctsT#zm0i|}31V+@)3lBLP#o*$6-_GVQp z@PuWUz(oOy7;SJ{dfvLNnogG8LHiEewW;7G=ox68G`A8X76no~f1focWXEY|>qq!( zWSHso<1k9PYtbx`@b|X%rjza9g~Le%dGAQIFz1AwpN+kJI!HMO4<2z}wuYH9l$>N? zhUOqt^CT!2m>l4n!ghRNr;)*NfYYdw5d?ug3AGQ3b`Os!lGlhCfC(@7QKU>UHIM2Y zdI#`D<^80iYFe+2o>nW9QxU_h$rn;x7Y{!yweTv=TI;2M^}J{zmazz5Yfq zg~{G>yZXYO%`L*=N&Xby37Z|_;#I%`QKdksrlCO)q$>}YFxzg00mpzr@s`ny+hU(n zj-+RaF%j#wsE_pYI8p**>`HHIxMC9+YXo*g^$sIXgk}*43GVgGL~MW}Ozh`Ij4vZr z3|6}s*e@X+Xl@l_>`{7rqoBCMMQntL``1 z1AQ@fuoHpH+4J4ZZE?WDBZQIPr+dtoA78!O& zitgH#VmJbB?+*5GmNy$OQ3RdAjn6TI0%k3rvNs;7oU1O6$)qu4E*u}JEJd`ih{yzR zi*G|E853M!p;M|es5N-t(Pa>pRL`HfTxL&NnCw*Tl`*p7L%xGBy|27+`;KfsJG z0Om3(k2i5~Jv_JMGx5+uj1!Me&I~MLe32em6t<;IC=()p?IF_Im)boy)jhhWllG#`H(+ z_UY>jYyl4{P;H$^AS!4Qq>0;%)*0d!3!F8JhBuYY%)TQ#=HA}e#U0_=58%%LPRz}7 zrPyjPx5>)7_@x3-eE>{>e|IhV+CJd#l)r3K?8bF>*Y$L49{{w3n+?Hj1$zEwp5^P* z)Drx;7QVh7vi&_=NJU-GRB%IE{Mu1}wUyN^pMEpbM)L7h9(=;>n652nBq?G_5jAo! zD|mK5qK`shk#T*24-&`p9h6!Hw=Q$$GsmLE5{@< zE*C7#^RO4Mv+OJ5K6yRu!8dwW*DDhTN!iv+WR@`7KA@z~@(CnRu+?K)Gf{XS+z>be z;JhocDh0?45D-VcQyhHg9RjC>^N0bL`M8jz4H4_LjKi`FKDdte-Q-3z1V$)g*RsR% zrobx1Es5Qe!sMEWs%I_>E-3RWapM$w7sVfQx}oK9)M(*t=d$3t0?Z%86IKRV)CeDs z+tU&Mp|OmefU5zZvOgcM?`d--v&BbzyT9wQxfy6UIcV|33^V-Kz(a{&aRt#YVMn_!_>J==WH9$#2zV*Ts zY#CUHE9j?CMH3+Wo5d{AWER^(s37&s+YpCcu z!LjwY@ExuK!p5RLRp+qTKnEjo_S46Y^0=WWqDrm)K&pg1NsThOzR8S_HnnGDmuBzm zSqXpf4B$SAI=vbcl`fc{n}aFgfkTIw34pvnNhNs#>)*UN4{)$Z=|#)e+v@bpp+wAW zi@(_>F(QZ75!WM|`O=m4T13yRP&+VMVtf{g56>QkY z!fA=Q7oSU%k8fgmQ?#y%;(E`Fk>F@{o_jtPqgmQN{AjIYf71sxK{leie*vZNMhgj_ z>1vY~%+B8#V)NJQ)JewHiYEQ!Wt$3W?@EymQ~35}28ZO?pP)HYBusGK=Mj2=U__&T zp-{CDVCfp3{yILc)9<%`|8pFPWFQs+e>}kTP1yhFs4s%yOiuVb`bAch+$l#fn>Oa1 z0cI6@^QOU=!{51$bE!YU2iT62ACsPF1^wJUa1dj5>O-ZDGjOX?!QQA!vMSLklhc~t z-uKgN^}KAhkTViuroND#W}^KP;xK~%YL_!83F$6q)YKO>zi6?o3C9630Q(v` z<^s1}#CK%GMzA8mt1FMqP!On3%H&m9RPb|IsG@)hjnv891}kGOtGs*xo3G3M%aFvu zS!)H@Vf-F&(l4uNwNk@aM>XJ6p=BXxHQ2QG=8bu}yZ-_L3Gj*PDS}HGMU0kq`7VJ; zy$2kY395V~-NGle8jd4n=Be8^)m;xuax#x^%@sx_NXzH4!zmqXuhL*(zbs}~&4bjNlckXY|gzSf-TrbWSp$))D+ zg0Xuqu^w_So7f=9YRDB1o@f8`_}si2#_S`xQ^gPuzBo!SY+$&O>?PEL$;h4DTq?q- zA4B_bti=?OFLEizP!mEDwPVSb1n#)Z1DD^2Z2^5uH=C2B8xB`^ZZwyc$6*!}6tq3( z6f9W`Pm?*m*mnsGQ2?B#*G_Wb(b}_89<2cJ22y`Q!@}Z?@LwLoJ-d6MjN6agcrDwW zvAo*&ks@e>f%~QP>VTdE%A~RLlNfG_t`SyRULJf$6b=vo`FAU1=%V`G_7Or-!K*p8=olhC&u#9B4oNH+f%z96LBP6yFW5 zS?3(a`+1vpiHj@B4zO6d|7=!>=|9%l^6OjB>b}w4%w*opX}4Ydi62p8k4VX42!q0F z_mZIxA4kx0NpRpW`PG}51Lz;KKBtSZaq|2Ny;zF>{ZFR$=6j8!`TT-7)gFI()9e)b zf!*QwWI)1ai*EX|ne{%)i^uN9m3-GoH#4xY3Kx6U9{&k z-kF~=ugSetzDQ03mrP7dU;!gO!-TR&V#f~Q4EW?6oBSbdSKYMx&R0w|3?sZFvXfN@ zvkQb*CW&_-XO8S#RxtWDTzcu8o9ms_%bM?Dsj1&psF_7(H>GfGyCS#1ujKl6$E^gO zYU!2)?Nn4j;ITck(eGaX$3A7x>i6qGV!L<_+S~JsBXrk!phoQ~S^s6M+h$dza0Jzn z{Arcxn$AY{M<0?GqNqt%(2=3+;W%OG2fQ`z%Q{zLs0qv8Vtx0-VNXC{Sc!t6b2%zOTPf3BJM<0nDIRqQ6VwuT|UL5`6Tc1EFKFyIJBYOuM$!- z#=cJ-dCQEUnwIgw$a4bfkiNJ9@}M~jD&kdjJN(|_USvVo5}_@acTE1nr_OQoj3d-E zMDnTG)E%ddUh18fIWJ^o6Ud)ur^r8}!>O44Np|__4~HeYT*`)ULg0YdpY-hHgM5aq z?Ps!PPv^!h*4$E1`#Gw%V*dO-xaImRF@3%x`#pG=r=7d!lmVzY{t32L(|=+%w}jqm z;NdIs;E}qIH4M`e6B_ynwlJLn3y201UCtNTaPP|*L;*UMLOfMfxsPiPxc}PNP2gwX z(v0{|bZ2BFCo>R7E69Pyn5ErRcjnoVCVAJXqR!0oR2&q+7PTEplJl0JI>7Axdc&$oq~ORir>@WD1cY6Z^83r|*mKS^D6mT*zbpdp{v z!qSyZ8$g9M(-u#l$c-e5;k zC+Tid_tPHDeTjJwvMyt}&9Y4Hx464uY8ZR^FwJ`R;UI#Iol-G?pG;VQJI+z@js)(_=iRQD{)6V1_OGx-W!<_V2*t8^h z*ib6TGcrHrh;!Ga*_Z@upFt{q_kBFzpfH&Ui;}KE2Xr+#M>;U_P&`}m^6r?9+mYX| z$tXs@Ph<%ha;61iX)?=;n_Db_g1Nr67MI*NK3FXu_R|wHXE!l36O3<19RqtlsaSpe z-TT?&{rvq&5k{8DNVWfV0fFEb^K6C|jl0Fttt6j6d&UcP4k~zs)>AL=-dWk%A(sz9 zdt{h)Y(g&}O)%LGLmHg09@D$rK|8%f-#$*tM=-g<7yqsv6!V9UKn;qJ)jP*KI+b^& z`XAH%bJHmK!F9LRTDyWl%j0weK}mg_Wf{gu>%GdHvhV03f9MB;Qf}f3b7*5|!>Lp$ zv^g(6%T-kO4)1zL-Ws28yBOASE-HP!O(VOQq8q)%Z;#v9ApBT2-`SUCg5xc=!|*2& zPVdBf164v&w%Dy9=3tKkS9-hS9v-q%a~ zMamZo^n27+635vyEhM0)2wS@e%64%7uuilE**s{-&CK}@5Gp7x&;-D~4d;#-r;cC* zOtDW$cek~*VcHk3SYE3R4pX}u#A!jl-mf9NPn{A;I0a4I(dHkRPC?xcux9_L_P*Rc z=%(<3#VJ5fwC=$HOIk8CO6Hu+=bf6Hc_&}?WRx*-{OqmeJIi0W`|NJXuWH-x>puJQ zNYnJ5nNgB{TU5kz&IA$m*hBe-#p;HI2GQ&+Y0&^p*U^!@D97cL2ak$6C*#^Q z`9tG0*QDKChZ1vHIdDOY(E`Nb6pc`ewGj4LMsn9k1jLFTKz+L$nOb}7Tu40i$%m;&E7 zJZg;uMGWDLZEyN|dS+ox4(a($1qGSw4CwF%cD|Z}*a-@R05aGo2p+$=IXN+nW)>DM zlTpv}Q2zoKZpD3rlnB0p$dhmTJ&EoTZx)R!jY&E7$RaO)7zwEv`3r15XSBL2O(t+l z*VU=xebcw3rx-mdIZTr74&>U|)l=6yUKH3b6pO1$vt*FQmI7_}@fa=Keo#kV2WGSagn{;6i+eF55&#<@ zB84miVKX`WRY(MUZENtuWKPh0SlOgENR>x$`*u%Yr=1y{o1Oi($Z>EG1aRaOwX+}? zU7}wblKwu};Go5W1`xUsbAfM0|R_8j4u zc%@h7XrFUtVdpunei@xZQHP2x;Z6Vh21Q&WStCY-JvUODh>_%cmTNZSA|Cjl$IYn8 zZ|wk0!&Iu+N8F#bZ_UGyf0h-UD6m_(w>%yJB`nBt4_dRE$8=H8=F^Xs#5~)Rdwlp z!Ooj^-!&6?1WkU~zd+>od$EjzDz=wjH=1t=t|;=-X30sL0NVq=s#TNRkxCG-wg-gA zh+*%#b*KFOg_XRKAwJ=4kB+b#)?w?`{rLWU>t+j1Cc5n=7=at+w&CQsmd~RGDm9}; z+aXiAbRU@bLBFx~)w;6NH+EeK`8qkNjQ`4W=+c-p`oYdfaX0;67gm-LW0q#0mHYeC zv4$_d-6N{g1$S5pc<1DwwV^0)jF_95O0ph$%}l#XBgMvU@Qq!Tfw$lc?rEb#lC_&yZXJ>GerFYx&j7s^quk;=X5 z3)4g0_4Qdp^cJ?@yn?f^mH>5IQBqP;KtMwxfwY)FI)`kv)BV4aC&@D}#h%@|;kF5C zjKY2=U@=3n+w}5`Go)A$a;Czf~|G{6dI7b<&BvXlO_+~3BTM4ilf-x&}Wnf?W6jdVRw`^=w z1inqthyKRKOFUZEuj4Pyw7my@ibabK8T2j^sa*MrtOqam!4{#;%vW8&nK6)|CXM0% zPgiaK1FCHxh>H3(m4I^MDh^m!#PmX92F_gzIFLJ*eRn!7sM}~V8@;tCq@kl`60jFj zEp}CC$x>Tuaj$T|u-WUXM$8T_8Vz})Zxc27(c%g6LhOB^je6g%HfW|PmZ(%zU(2%- zr)ZmMX$u~2?SfXY8Y7%9@89n=wSdh0;h$?MsU(>{HNJjIt5s%i=XPtgOIys%4#5-< zvSiHcE^5RiC+B|^o`r|2cJ(RXc4S&BYPP`l9piH(cn@Xd4N5My2AtGy%01%Mr<6j) zf1mKOPMH#p6;@?JS^uAXo8AM&Uuo$r3hpM58{x1oFs?##{3!e7J)mPuhoY&Ub-wEN zJopW1iL%>1l<|7X$~MBnyJfdE#l|M};ROpf1H%2XFihQgt?CK+jQti|`?NOOsV>y1PldufTMWOCpk9d>cMCl_uFFkH*?U{8^8a0$FGV{_`M)#^{duj zS#WF(67K*5TB8VI)B5%~%r6mr`>f083JcGJb4zn5?}6nHFJ$yzD@bs&;<8wTL$tL`aEy{LHQwPEDzqAGc01#YaA6YRk=~r$-b0eO~HNi zG58K)1wa&R!i&p#uBXnZMD2@1L8%3#H$+>{HMGS)0XU>dqDp;(?~;-P+Zlg62dMl`z&i%t4+Ar3CmudrJ3%3c9tAry zvj)}2^NG{=8*cW^=!0Z^Io+SNw+CQ?L>CY#8N0v1JF<2*IwC9jn$n*3A_9<*#1* zA+?|@OtdAGTpfu7+D!f2qq!dDJ3Wm~dj#$~{gb`m1~s<`=Y_F%vuS1lh{Yxly9j00&hHZl@!jK?KJT*}HktGU^0RHr4-f4BsLX^TSZ8L|dor;D3w zVPRoo!yCX`178eJv!lmBXDtM(h6cO9Vwp?@uzt{#{q;9MVeY$KwP6 zrm=|Tu9~R*uXPv8CFSx?kRWAT4|&GFqHxhIGs=WWJGnJb?X?Kp1(1@n2Ln}tOiJuh zb^<{WYZrdzFgMztBBwJSiA@1jOwsR`wTuMmA?bFh=#)bzQw|Ly0odUC-zGp!P>iO> z#ZeQec#3wqp{PcV$=JcR%8Ayk}blgLX4cMZZatyb6_*z^~jQ zgpDwKBL%1q=f3O2>LcO$S-EeIAMCVAGHp>P+#g_^d{gc0LnOqUIt9_CpeG%ieGym! zY(91TlV2rxjo`Jy?VAX${Vl?5B`8VGL`L5{aapB z6EXkv{DI=pkvA*V77|pmTny>&3+a@zEoMG(Zc-Zf?3^I6U+i-F6?@`-d0}Bfp3%#q zgbf828PCSO^mEyRFHqO}-u#%CGv&n@VXM{ma$5K_tQD{+e5e?*N1QFD&^czh@wQT{ zFlehPHdrhL95FWLg8LU2^x)68)xRYV?^2E%8hizw3y+qz;=NZyor+Bk9H=<;)kf{( zHE?fnLi>T$1P3|+fp-|zj2}PlrHezO*E%J1ZhP4c-0=7~%~jcoFSCB!w}jAMT|puU zH%GqAT7xq$541-{9Zt)0KwpGALZBmE3`%z6bqAqh9iOtvyaQCwq_g#-v*R!{o&{et z_U~3MBaI6e9@`Yt2cwrZi)_g@D}eO6{m9JICR(F@(ya~D`8EofGJ#4MOzvm3g^bM1 z{gz$6$h(`%LcrSY1Ci-qeb+iSGv%%2{s_1Xe1l=wt~`{U7#l0Ht(pVcKf)W0x4*Em zIP@xAe%)r3a)hE`5tg-Zn-mV<*9OAIZWW}Q}t?&iw9+(HrldEefwa8GQ`dTXQZY zW$mGWe)I9x=}|J)*GhiJXtlp5W`3}JkabSW%lU!*>QK$8<6uoL{}n)+u(Sn9C~)zw zN~v0hXW(tns@jq&9xJ)7hdMlU-*k_-CbpGynz3779iTAfeNW$;bQ7ok?RfIk7sv@^ zCSXtQy#;0f{4S=P0b5qQGsPq%B|BSN^@=UQHjY1 z%Q+RU7(ihHU}zYA=MH?jlc9L~=QdsOmqufsP#h%nV9AtPjr8`O1Wm(|yWpCYT}LRNPSS-&J4xDC+O7<1q7p<;4w(D{S!aRCVn(sXO`GeXC%^T$b2IA~U~6;f+Rr zU<(cY;I^1(1bbgOOXkJA-3z~*_gs9sNyEtWw0pH_@x+Dt$}XF?tGiEd3g=Ai4-QP- zS!$iCo^(@N5UXZ>b~e+aIyaZpt}Poj=dXuI6nbHB;!VUL8-m%L;oCg%0{@dIq2xG; zEFOsjw6L`mdwz6Io>!9EUS@K^m15xH!L>si1c}E;`i<3x_Xvi)xhO+V4)xZrGY%6s zc;Mr4V%LvE{+v5u5+-|z`(T96QT)Iiz@+Kn{&gT?E(q|z(jWFB1k44zG07nR_`1TT zZo})H9dF*;GIX+rL#pYsMu|h0AAP;FwRP~;QC3aeWEm&wrQmok0T8Vp`j7dGetz)p!c2lOml@*j+b6yeJv&! z?)&SIG6PE*aFM*gwfjfCbrC$ay!f=AueA(=EaWxS|KlK&3Z>a=&uFAU=#`c2MYHz! z@m~z;hd(g?`!O}z|3&EC{JQhM8NHe+|34VJs^#2Ma8YN+Iki2y!YSGb_sp;f9v_ z?;B&k4zHdR0R`}FA%LNGo)u7Qdf9trb#YpnOe=5NiGb3Ko|9A=)-QeV7tM|67XABv`=JbWoHTnINNd_2%;UvG)El%`9akM}Y{3qZ1Ym8CrWehJ?hk?tFPM-P$Gb^?`5J=YZow@uXmoyk z!>S$)F($L0y3&TgM4K*8e)dfC`Mq^-XaakkGo3erPxc+k8ETD_CuJY`tbi7aQitfl zyX_I4ZruAb_R%^J_Yk`{16TJiA3tiTV`z7G;OLCXFl~e1;1haG3&Hqr|3oT!K$A>e zT|vl)!TkBxfea6Bt@)tL0Z3&`%iewz)(IrDSG1;D0NMb6uk-}ch3W$*34o9~Xdts`dxmn2ir@Mfoyd7m z@M8|h8t1}t_@Q_}rJ7i)b=jSimD;hruQ2Y4RdU2690gNcar|LWEnEQGKinT0V71ir zavfLum!Jyzzf)S@?O*`Y4=OE!09$OM zw0%@~c>A+wFfJ#8NtXm<-@&X82n`_v!spxuFRyQCFyp%6>Loy zkqyTG3#WF?(@ZtqT|Pon-$~x^{|9|@qOR6Tk{@y#IG=z$W+i#T%d4cQNEHu1T-bQb zoB2Nd7c*EeHU|$cF2(;zw0(X~r+b^%^81PnKAz~7CY2d%={KL+Cn|z17^7~8_F;OE zosZTJWe2)vd(YNIRckDI1RAxyD>G~j2bd)P#0s>ZqmiJW8pPq@_x1H%98qqx746M_ z8NE|Ci7u5t^P?(~1hP!>UmkFSYTvLh3cf|*HA7cMH-ZSij)jFb80aht_ZcRLk>QO( zQtRQg(I}}T=-?`wA3T!~&D^(;!`sxu-;OH`X5VJjGu}u)1ewiB(o&2Q$N)Ua?qLuw zApu@Q$b^6!sBm!9qYH+%*8X*IYchnPW!>t`uUb#aEeugPqHaRVvz~!`&Cbm^ziOI` zR@`%b+3(G7bs+43fsx7v(J3}uaA5$TfkwRma&xW25*UGmfT-vZ&{r_E4MP8lVE_i} zq)k3P0fCdZfx}q!JrH^@Owo^GV*e)Ws#8G@)P@j=wF$KSt}+8Ul(!@NZ+gNn7>n6d?C5 zPFh+tO0Na$NrcOqF)}(D!)_@FiC6d#-xwb1e(8ni)xdOXd^=g#V;STnwjN)PKn8?0o|k{hw>Ij#-NXwbRL!zb&%v-sj>jhSVtKFNyo2EF^BJojs+iOJCTp58Me+O#YKSS(|sC zn%!xpH0ff!%6m0D-07k50?d%e=Eql0Z_PYmq_Q?c#s6968u$5hZD!ZqD%^Hl_f<7o z$x!fAYq5Wqq4N_Kj;DJ6rqd2Nd3kaC<(gSBN+ygfEJ9(^Xgg9bMzAg2713gzw4bUJ zFfzQm7f@U>e>*sAGyW@(WA0g9>dx7Jc`LFg%?e-xk2P>=}SVcGd`3c+@#+*!q zi>vD*Z$37$nDtLq|JGPv*i673@%8kDslylmfwl1Bk3Xtq81TV13fms?$^HUD85*=k zmn{aHK6Ix!hnf*Rmjricoa>;AlW*;E3r3${)6@a-US^3tG8rx}^?gFckC+9+0v3{& z{AWY+==1y-y)$&WFoT=eMrvPaY&It(rY#{M$RtD z7|FEO)E9~a!wfXp_&qT9gFF%+2-*Sh2%poZ9m?H%Vf#}~_Y%eC{Nmz(t)_$w+;$2s zz$R(zgayFs;`QIejBP>anL~Zhegp<+zkeLBumMVhfJ}k_LUsWS96ks%;c8u8DV2IS z1aoN7_G9DocmzP(ml_VzJwdO1qONGKXvgwUux6IyN;W0e`A0+LQMW7O z`vs-T-fqP1YP-JYBoaZ!DBH@mPzS>Z=blQG8R0nH=?QKn5>9!$Dv{N z-FX`i?^77v*V)WoVjthy)XIG=K(VUDXIrWx`#uHss7yavZ90nxYTal0r#1N8l9&Dt ze|z(`wm*57>vO7~-`1x$rj&KRbS=XRa+6iwTLldwwj9EGjw1 zA$JV>r=o9g{8k|}3jLw&StE^`aHLwdwYj<8$>G-`%3x%hAfnf$Eyk(w%1Py$SZgGi z55eHygmOS>2E+`gR62oz%*`s>d+0IHMcgq;L)y9n41RcdpMCs(?AS4~@&ga{2k(|L zrfBam@pcvBDei|tt0d^rIi%AZjL?zBa@ozO6OD1{XcowwSFj=DK_r<~iOF z_m{r_LChUZ84wX$sh{Y=r6eU^*j9CXnjb1YwC0*4wsb5IL_C*29~~uQWbY2Xe|!~& zc*CYVyH6F3MpMq5QLgQY3r6WypK1UFEyU|+Ic3zL%>cdv$`?Fe2kssqX@|Ren9qu1 zID{h-rQbhl8$H3gWy|_48aA+Ktv>(zRD2n$z7YEhTi|KOFnQ`+qmDVzXe}Q2lU25$ zuHdoUfW-v3)y!f&b?h_ysSA zhwG;FQ+VpP8C()C8DfD3agb0uiY$vXWt% zF2L|nA#1~i^6}dgLg7+uTwLFDBZApN%phhs36^ECdJY_YtgNh{@*P~JJ~PpcbCQa{ zzN*k?y7y>uLc-#gm-3Xy>xiD4Ry4fDU%|QNSWgpv^=fdxgG9n-{Ovuff66ARYv9-b z3<5T`Hm> zI&bdcSTqBmZ~?m~$`*l|)=%?Dpi)DPfN>#*gL`7n16C2G{wKdaMBa}FwGDxH8J>wB zP}YJ+&AcY@9c`}LQ%nFGOlcD+i?~b(THdy{=~%N?uH=!7 z^H)R$t88b;4=^(lo;WO?z%DYk`MuShcQNkR9SOPHy4ND2qv;7mL|}FT6qaj%6?i|ue*Fv3pXIo6 zxl0tOZ>90un9X(L6XW~prwvxh8Eh^KA?%%f&i~fPQ7M!%G9I|*a<1D3f&IVJK^rt< zco5bQ2rhurZE9Lt#f9oK-vv3*L6~&89!t$UEK3l9NoE{>RSeFkjsnPF6ny{+Y!aTS z;x~Kom||I9R)TQu-4#ANP{D3cglmIOSK6L%a})UzmnEloV^39=QZ|OBkoCw!?&>qXQNiZ_9u9P!Th4pIqlt z6g+=PK-3dISbb?N=yWI|0`xE(n%Oki;KOcSVA0@u&IX;8)>{WOBm*`>R|n5~ zJRW@YiuV?;n>&XYBp@KK5(KvWbLtL{{QthIr+M=#i5;v>YH1*tXH?S%vk}xaIAnj; zXghzkD-z2#~bg0%>Mhue?u)eX^c@^iIM3VQF%~OJTv6k_%ovW2?|&i0VWtr`!ew z1F;fn1(e!2fg}m&lU_G%ZUsCn>z0k(@Fla@=LAScm#a!XmO-ykbf`GL#9AnubCZ=((T;X6)z}d5n zw}kLCYTBLpwJV>VDf9yd5rJ<3bguW;6<`&3E0;)R6i${cfZ_R&=u?u$>0!in7eGK& zR;rnAL9VNFXy>)6NM8mQY0us?M#Jz&qis>#vea%Rwo*#juOM-isnifa^QZCCLqhUL zNANgv?2M{xsnmTLLvdz6m5}56;DKFjVJ5wrv^%L+$Ti7cSj%Br@NECjvm&Z(~gQMh8ytV5N&li6S^1ddRt>{my= zD_+mWK^u<%Vgir6y8ikvhHSeJ>j<3v%~ka5l*J`*&$xM(%*8ly`(!5E*Rp38lglSj z8uaR>5v(4WTuGtDhK87;%$J5G^4!(1HaU(#Bh=eH#aAOEJFw2-9OQ>31fCyin~&*R zF=SzRvx8Kkcq;R4j)X+m$^Bi%*bw73_V9NwzQSPNs&{(6%{8AZ@V1^~Vqa0nZHc+d zdr#36pBAPe7Yoa23uurropH3>xMgiIn|kdOO4j?ghn^mdC9KhSG7Vdu&(p;>^&u5 zo`3i5GFm1iD+6lX%*y)oy?3Rp)J@T-$jIL~pBK}EsG+d7gV_tZhYXm#JPFd#p{w=s z^o+ET)U~9E`=jF2Y3Fdnozm3A!5ek>M7`;TfChoreT9#IGC5_rZepns{R?a|Q!$B> z3qRr`pl4Y~=$N0y2~mB4#Z)wHmhS{Ad-%8j^15^96Abk*m;e^xcoG~u9ve>h;yO_b zv`VD8M9_KR1&{~+BVuB0Z{BQ{=*BT;Sz@n-E}S$N5{dT+bv_bd#l7A6Be8~VOdrsAqZV2Pl1O9xIoN*9yNa!A%&~9&#&^U?k3j+!-@BbOV+Xs64$Cr} zyTy$Y{G!oUOon-0?K#ZDz{&S9_S@uSFq^=xI>UsX2UIOPMdr?^Drn{nwLjV#b6X`= zU;B*k2~68>9>7M&_p9WIbf_jCr>sRG-h14tXJjtTPq{%%9h;H@2I&5=eR_hiPsO)A z9VEY2pltfTuXXmofep3b>F(?k!T5LbAZHURzFVP7uyClpvN0-Y^1F!?Y;=#H;a|H~ z>4rtmvBQ{1c%P}s%nbe$?NVuqLgJdcBd5QrA5w~Xj7v?#F4r``weo#n2b76uPWqSq zodr&7bDfGTV!jx1Sar^wBgoNFAmyjY_VUgKE4}94UbbBc@_x%%_Kg6#!lJA8?ta&m zi&Lnmh=oA@hH$KYrZ&vbvl8g9!s4)UHmPGg`?!JRUKqgvYQz8F8P@;%DH`YAyRKuD zkXz!;PDNK;z21f#cxexj-@y)VWj;G;B?iuJ+>_f6w;6>Fh`Ky&`1d5=`_GfCD;?Zo z&nA~1U=$X|lzN;stzIVDrdaoo%e9}AJyM*N3p5-2aIN2`==MKZr?6a|cdUz=S5FpR zb#gV-F&g!zn*w~x))B#p30I&-+Lac$F3XjvMMWa@uSU!sWh0%71%kMYa)iS055pv zIRec69gI&_!O454+%Tduw7`m|J>cJ?nI>afb84+UV&L_@G1*}-;P)pb?=7=j=)jQc zf4*%@0kb6IrDvK}__kFXJ&W;Dvz=#|vT{P))`Kq8)9?4MJZ22_(oM~O-g&`Xo zRzY>TFn_19%qBSiM2cZzMn=iccIe3H25W#{k{jJ(KeiB3$P2<2XpZ(z3OBllJGvN- zp&;-ci)#G{gDI}6W^J;GdME_6U*WvZApsp)MAv?5rOJs(+}`J8P6K21PH44-Dl;v0PjhV&;+z{_6_{ z>c!_;Ilrgf6<@$4?CcvcIs&F2$SYv5wc7&?Wze6GTdHrl0M+mrYlDH~BG`4G7eku_ zEWKaoj*g&5R6W1Ud7KA>0Wy_@7ZLD^SKT~4VUBPa^oX9GearP83#l?yDeAj+ErE=I zK0YvT=Jg|z#9vwp<6ZD7aBYsN7aVvBizEyQ9l$9g1pbY9MWM$pDDc3T1ut-g@|2^_ zB0C#i2f)wXKY=}#(pbhJw1q&;zyzD{Rt8G{U-%T51-4S?Ci!8*t1WoZ0Y$jb4UScZ zR6AQ+JhPS{t-HD=q@-4iFbVP)Og>;j1L>fzj}ItU8ER+2zEHr}Pk|*R zF)^>Iu8&$=kl0o#7dL;o>@;Qucwc$~Oj)D^)W-$r6PApZFu*|o4{oDV`nNa#;;`?% zT%4PWxONTHcUl5SD=Yy`d<9~>ou~q_4Ol&3ooeG~@V^-9M6m`!K#;B)fKg`8C7`$? z!$n~Cc(lSsl8bcPjXo}fn=9#rtKwa2kY&O;91E!}|37voMu3*!n4qvn{uq2pxgv44 zI;jJ?x}_S>_v`FmP_{Aih4LZu-URGCoJvc;j(^HA10tIQ$7{!Sy}$5Uzayz&+oW zi-%ej0OGs=V-pk;5Jvs|&m#a{A!vuBBpfdW@4okg?3ed*erA<_9q{hCGqpfA!@55q z*5o;MplPZE3Vyr*oh0vS_Eu=tK=EBWj@ zF?7e{nwikV&`_-r#$v_4k4tboKr`<@CA(7{$T=9c4OjaYCM0YKYh+x%KFl+W74zI1 zULxe)N0Yicj`7!)gJPWCQ_*#Gb))`qW(5o6qgIjqZD!_qC-x9uk#qR`Zy@2@@naEJ z4C7S|(?_MH7k7NKukxERJAV8tYFA+01ObRAP>;vmhsyB5yZi{%Qaq*Sutx@gHiU=# zy(|SER-xR_d}Ex)k*$WOEFi2xLk`W`9*lF0b|4#d75F2`GJ>StYS+^8@~h!t_gzxM zPlAHrbq+-w%dHSC@L@6Z^~Q0roeP~}ke>YX;^J4M;Q|8dajUktIp;2aeCjoBL>>C;-jP3vF7A`N64I4K90C1K-)lv8c929l}Fum(7oxXLBu8ZCzBW1XL zw9v9RB0QXtiOC1slD9W2Q>ZGxah3_7DRuaJfSv_tUWC8m0+4i^`&uanE-QwxDvI9)@XeDomgS%gz}1uB>9>;^vvF1~fGu#%MIDzuP5h`Hs-o-hr8+4*_kCK%wO+^Y&&RS(^# z4vYlYd!B^^32zk^cFj$}lYiyU9|Qu!4HrNYt^l5QaVj*jPLh0u_P(PkipQbi-{YW)4%Vs8+s6lTMbH6e zzI-VvDA;@G(q!Y@2EU+Yc#2>aV=Hw~Dv7k~tD6aKbzELsG@0)x!_7i}sorq`=Vb(T zAcDZS2W;bRNQt;RdXM}lclyuYQ1!a1Em-*;q_0(M!G?NkE|rQ^-VUk%_X`@$M&U$u z<_lR>01rxzUPph}G~{InFV(9ad>73`en@88#r2#lRPv==&Y&XToLw^JVdSrk~nB`LD13@8ACC?_i;C zRPolM`_H@KP4BN8G5xP^f&VL_Ic@R3{g~sh+IKWkEYhI)ASWv2TBmOa=I(xra2feC z`(7*W_NA@NQYI`d4S-zvudgAHws)i5g^M||UiFjXqAZH(OG!x^2@R>FpQ1s7zxWb9 zMPq3i-&AHJViFTcMUc$q%`Dd57oBCeCIBV#$~Yn`6Y&8%BqSbKSs7+%AUk%~F12&N z?%%l+HdVQx6qUa|<=D3^IwG<9>c8I65WygoBe6|Var7yw*JN8f*ZwLqoJRKOQ0OPwM=`hP)k=G|PWr`V-|D{kDl3f+sdiVAUGj>4_`H0~*cghP}$9)tLxE~ z_*Bh?OjZ7omW*P*!ggOshOWc+0-h*b3mc_fe9y14ZG+B01riWK0}%@(XMD0}tBBy$ zfX8?;YY#4@|CwWsWh{|--wyA!Xsk1N4wZ^3(6p=BpRa9 zb_P zodY8T&~KyKBZ5)1L84V^#kXnGZs#TjMDwDg!yFu^EWE%z<|6JA@f9vGwLlFfmGl}h zL7+b%12b->n~_tDcnU9XkT}DdE5axgU3CtZayZ)-UG1OphMk z9McaB79m}}I+eVgogtqBQ#6vC6byw4@MUOAn$L(eIK|E;-M9f`)!mp*zbf~DGM@+r znhjaSQ8h1va6!p1!*DgHwjpZ}>>*1gg0WmcE1EukWsa7e%g3m*qOXqWuJ8e4uZL;L zg60t{$zI$$9BwThRG!UO&eK?<{up_}=x~5E7tP3{?IPU|6#K7&`vPtwBQ5ot42)aJ z!50}t6Ru@w*m=mSjxP5lE7s4J^9!+~$!Q_6(M+W!)8m-1uthdsxp3|J^^$w{=!v33 zkJfFjIf)@D#%}n9?rK;FwWx-kJ)^w&c{wbs1YG`-VO(U=C7EnvlqkBtUcdcIze680 zS0=s9v#1g9g(pH{^+gTk+>smPmp>>$&nngw?K>ZtwKdRM$%;a_CgfRqR3G_ z{rv>q7b~1BSWdsZXI&t3P#N-pR($MUiJPp<4BQ#rB)Jp5%Xw+0c%(=d6`P?P#siwp ziR;+8=(mxMd-t{3IXK`Ea(gM>N>X>*ZYVkW-rUY^N5Zze=b$9<6jKcBs)sqA?AH(y zz(;m~!SRVfMI|NBT~lBB%OKlrr+UUOYxoGI}g6WwT zDiiWa=zR#nLISCzD`2(|1b}?lf57XTiWq+Rk_y9GCk$Spyc^{o1D6BtEOf>aFoTxH zU&_ySKYpC7tsXpJXQ0J%k12O$rIi;gdZIG8qz@}heg2G=5ibZ=K>bAhhh4~o21nH0 z#Va7yvajvoPk>|)k8r{t2hv1?++^@n;zuUg*SKA!AkSbnj*X(iPx?RfX4LeTrGqdj1FbTw5y{(Ef&c(}VtDK6 z*%cAThI0$NMkFo-O+y#4s%ty^~Bw}6NR_Ih#g4gwyS#bsq2Eld~C z6!&5#)w6j?MoA|I{2VYFs0gfP3{Nm7LIf=Oj+q(V0Dwu{5V8RM+x`d!6Qh_yXSK(7 zj6=+V5)rec`=3!r!=eJL9HmkneLR6I-1p(D18Gx3>ln$BMBls#g~RpMk3Ln{|9}Uf zL#l3dOi5s(Zdd}fgT{R8v(2di;LKKvgHU)H(P{OPWNSe6q;u#_$>;wVc z5=z7dt)0+Fg=XjG(vkLy=-{|FY!GH;aO?&5333Ayb}q&z`a+ty1O}g%`~~k~4YtPG&T&X?BjzqlrB z@Dm`N2`C<@CcxYS%Ns*<=mnAT#Gp7hBF3{;{*8*jDTxCKbIOqZp8pHsLqD&<)*!fep*rBdxd3WGHlgOsDzw1u;amusBmr&{ zm@&Vg@qahe?ED?~?NUexEptG;*Dd?<9n2`;3jlhN`KLy1G`N zLOOFEzz7&6?k5;YxbOV3!spku-&-~X9*_D(s z%cdxl-QbiJ38BpFkr9mP#^Qg~tUElBb{{8Oz_Rn>F9vSCx9Pi`(e!ZUS z^=$z$ZRD;Dl;cpI9P9t}_^#OgYU$hRv$o6DVVRg2RbQk4`-Y`QD(01jT3Oz#cF z`34!4vnU5W6w1HA>`yk~CfS?5?JhLVx55cJ53nV=k&~pYr`Lwg9U#DD6E=PO%0_I( z3%UQOJhmWX3*V@5^1Z+hRj};mNtw}m=+wQ2Bx=GC<_^E_3&>wQDtvIaAwKGptkM?$mnal30DF+w;{Ro;7SVgf= zcqi_ZW1|?3ZJ%hhxT@{8>7bLg#ac^^tehVC&y?HTOwOi8)A${b4UaTtU%JF3cRX>| zWej%p;l}tn-m%}uA;Yc7oB(T)wL>O}%Ah)Dqx0u^R3(7P1{)zqS|x`KTKR((7-2-f z!Db5E>7#M6Q@?+ODzn9_J8>c?;28d+^paOKpFabMg!HQ+4Q5$!@l~v2N7V%IBmLRk zg%X%jj$)zi3kL*tB)*Os4xMcQV1n>UnwN$_I`bWE-DGu|f9}>`e_>JP<4Rsb zMc66VJKm|P!v31UakkvpEK8Ze5f+g7_ga=E!#KVas}y6+?DP@yj5>b#m#gy`5$Km@prB?&V#!tj;0610hD`Xc%LBY zR%_af(+yBk=_*uMtI|(kpPd1ukD9gM>u4^cTa%-ML+O`e-KUdnug=RhK4Kw%zt|Z{ z!#;&=Cg{Vp3d3k!%AJ9K)DX$^s=Pwoh22R_=W#coBx!XRv%guAT=*HByI^AB#yXs- zWsRS+7VXxy-k`>y_62s0KW=m8#!smB(6^FEXY{FmK6r42F>X5gq90Wy&hR~}2tUx- ziF9{2x7N@gl={BG%ndtFe)iI_;*}sK&Dj@PE`AGv_4C7r#AhMPOG`hHp11kIIEzAZ zIYc3ChIPwyd4E(Pb9G0A*VtZ!XXOposa{jgaEnmmw=!(g46e7WHg70O+x>S5mi}FW z9ZBLW*01W6D8A_zlFO4I9}l36UY|x&hdu?@f>RwjLX3{R1q2*fKg)AIDI6I;>x3<; zokKpOX2S^IH&vtwogTM)Q$ER2-P3-0GUC?j-#Gk=&Dm^#cB%YYuD_-ON`HN5Z<+@N zK4fD~4-!TQWzhK1AjSuKb70O1s})Y~UEblQ3qvIoYuN)lWLlv79&froUJtW#RAXSu zC@Yh@VSzh3BIZZ?%$a%o6cTYb*KT5Rm)q`~69uUr-)U{Ji$tjn8B+VikzC_{Njnl; zqaC}WR2F}7r%6y#R+1j?6|7s+eZeHt?#3J2_0)rhc)#23jn{en&{Ft?uf+zA7N)7- zO%Jw6*XP%U;!7Ob^4P+D*AHs?_ zn(Vzls(@4Yq=5Ya!M{2P+52!A;47tf8f78w3O-`v%H2H1R|oD;C@tOFuIf@S2PWc@ z*n>K{<}7QE7OBaoOnMRuI3jm@iT9&SfoG2N<;D%s;kM`<@mLNYevc3X@@4)*H;r>P zsv@p;X2;rO25-i+^nYDs7Du;KeQbH&+ymOmnB*%RJ!GHRqHV#S`<@9Ey-Fyf)jqQM zRa|Xx@f>jA^9c!1uAM-nc5K_EUo93YzCey+t5>qOFkRJmYJA^cIYdtIdHv_ncR4BV zmZ`(Fj|I}ePtX#HYa-;0m3N@)hunb}hK=6LM2#kqwMoD~ zZ+%dhKun04@-3e%P+aUTwO7H;pb`9e&|M(&XWc9^cc6CA4F86NHUf`*_z)%fS^HOD z0cV2PT)FLcMU6Ztww4;ttN^!zFT`l0R7Pz8{kdA~R-eb^==^tPDbHfhOTXtzyT*;$ zklV&9TySvRYNu^n8`qFZY_UoXm+;2E#)lro| zdY_HYf-e^@Dr4kCVoq>jF!oWMz(u0jSLdUD)PcOYL=|1_0ZN_ zS_qa-YUE_32^JFLkk~|iYqfFB$c-;bB9>w?b9ycV(kUB~qE96H{&~mb5Ar_QbA$O| ztm;cRgh-COU*5$F#N@6EZp^hU!8wXy(sB3W^c_D*lPdSC(k6E4X#_MD-d)=AX2)v3 z38x;a9Q5vht{`dDf3LX#{DEwUm(JV^JlA$cXkVAS%lKTsS!+L*yj=7Qd!O08AkxaM zbXI34?pBd-)_beZ=+DTiimw^rv=g!H)T`KVA(Y(8;959-Kp(ev^`G0DhTB_<8Y zHa1mdg|4YZIO`^>&vZozgFAu7o3 z{hm{}SjPV91%Pv0nXtezHuUDKW}VJSgTpI-5l^GA;e_n6!o(D;6rUaWMVWkF%CRe z_&IN%koHgE@D!ZBJ{^vk!jGaTEE3&=00r}OVz+=jAB`9Wb|#!X!c87~0? zLng#6_WT8B2*Cowte^=&%r#^vxu16|6hRN%?fDijz=Kf5>rNEkhqRaZqDKMMs4CaN zw|MQ~T@MZp5IlCcu(iqBh0L&e=zTcD0!$-@KCe6K9T$@+XN85&n&4K8!`D&qhMq_? z8_TrPm}1|NJk27ywM5Bnwrw3(zSWr>1`Z7Yi{Q9aE+uReJkk%mRzod-@oz8u5fx&) zyk_0HM&wf*kBd6|^vZdORns2BK`m+_Kt50|ELVk9-Zo(9Z=CFZsDl+%3HzADy96OPT|WUz5IqFw(i6W_=tuC zLKke1rS zkr+7RJ2b`C#b`S`-v=XC1j6-kC@Ru>L9J`RjEKtP;K6CMi>76V zaxj??QNfspk_T)6ET^DVie_-p&@t+|Y?C+9=#e1`Og4_% zOs@@)8^GK#2q^SgkPvp+x$4fH(XISogqjeN;+T)gt-tZ^Al(;e*yG2|J50+gmi=Y^ zAsW`O{jw?6k$b0;3gXFdxcCk2wxO2-m@nYAaF^^ zrmXr$ub_hV5a-JMA9VYpU?EI>d;k?%+{Pa1oBNx7A>OlWPbE~efJ~eDbl1Qi^`e=o zf4eYw(i+E$=SCHk)UK&UOd|-<1We7HMK;Iu!oO%pN#I3R;aL^p-fk5Z}ITvdagdl1xacW z5{yED+oF%LH$97|Pk@K`%x``k2Jec74x%4QAmfHt_QQ;4m&K)-rK9qU z!L0oTrhkxtov#-S|Fazx z1sMum6k*~w+`QX8p;@O3S(xhq?!!%on*$sX=$7@j35a~K^Fqu-3hV6b1e^Zox!JB1 zW0%8cH9^=yut3s=g9~w>G$c^c=oAnS2#^PqboZm&qfxpP2wt&QX$t|d#H8|(TldrS zB{)}BR@BwiQ4s>E1W4cbv~G!hLlPr5qxd-ZIqZCpt%PeYfUE^}e(6?oq@S?DMq;rs zVX^&pnw>joaNUUh-RtZxy-t$t;&0(yq2@X>WviNnO(oS+PI**H72=#ICEnQ zh}}+~<6EWv#r%5BvYGye`8Ct}?}YAuxa9vE4;=in)v2!&s~*)fX<=!07ba^GocSLr zdPVr(#5Nc`yH$=W(f{Uwa)758KjJvILt z?i|`P`X6zql1SLyf#}_9DnA{+sZ$@EyB;@q64b!Ve9FdO#AVaxkz_gJ$Vh)c0Y;^F zgpczpMAo3|R8B)`JW=hPP6@-Sjq$_4EWpGfZ51=2uW8)O_+<=N8B!pkb)6xr!T%Zd zQhB71d*RoWy4URca(Kyj1l_lAt~@ril;8vow@F3@yZ?1iK^Ub0dnyW)jPpYDZHz=4 z^M}Uf)A>Kp*fqZs71EK;MogcBzW{sf{Bv`>u_!l^yoMSs7Q#T z{Jk>T1epX8Xa!3{%RDwqywc{MM&YGtR(Zo)9B?x)Ud--lEE*z;g$EIEE0Rn;aRlfm zP8#SVAeRXLF2!3(j3$FD6k+`4=0A^+?*+`+-CUk|IB?-w`Y)NAypM=KjOKEmERUo7 zI-W5^ea7(Mn6_`^BsbS=r5|Vj;ZuK7!uF+N?L0qu`EKmdwN}Rq<+Q`{2FnFOP!2EX-37F<&G*8C))qkWQ z%B_75;5oDx|VzC=ROm-n8(+W(IP zvPw2H8`f)x8llJ_NWP$JbJGNT0Og>s8oG*+phz*;;VLUCs7QphWCAtqp1UDi8tx+0 z57{!d>}YwhRe}x1M$H=g2(m$#?o(3@+)n6%+3oC%iH-&dKt;lfNd&h|_i%|SjJE&( zalH0FlklD*^p1)&NS_KmJ-3~kn;XB6iZIkW9Y*~Gu_fijUk>?2Q-?SwBPQG9-!5Od zvPEDAGN17YVYBv0N=_)QZDvM3g32bvsQ8CZo&-Yejh7moDfEVTiO`SWXtLk&#ymy# z<67^!6>W%;Ul4=pU@n)ClRN3>2cabkGjr7+&sVvv9Ug%;j-02E>u zQKRMMlb>^>@U!FNjwXvV_ zi$!T&Dz@Cds~Y^Qov&wRMlc~-Lmod2WB|KpXy`KEbwb`?V1$Yy>kG(5Fpvy859{L9 zH#9InY~Cx#Me0xeRIeMD_M6=OA{g|Lzm_r-p}@DPNVs4Szvni1fejrzEYj|x5On&) ziQ5Hqcu|60Upa}=xtcozMG#t+ujnA4gBLHCI0pEi(9S2sAi^+1;eaDDs6Y_&v%#f| zsgdXKs~5lhHj;uol(6u_S(vLLP6|Vydx~;5tb_!kS%z!3Frqsg(|iB^$lIa>epOcW zQm7_pK79kdk9DQfgnSWP6~@xI<1I%WzTuh|H=rnGRV=X!ZIjZF1471Ve;wxfEM!9g z*8BY7d7^8l{;Wu5h1+#DSMadqvY>Y(E=de-;Ah?nU-ql1xB=B%(S;}Yl z5lXNH3DD3cc?Z5Vu&{aNGiYHF@Z+mO1CE)3SP_dFcC05mtS1;N;r}6cgV?rkEl&nE zg(vc+%f>N^?I0wf9-$(^=nA$0>Vp{8^Fnw9pmG3S^Aqno;u$7X*(EH%rAjPd>n)jf zce%PNmEm|5)l$KI>C#xc8{Bbc&+;j`F_Xf&re@z21q1{%7ik85q}{y8u)&C_F4dIh z?;^4@$CkH5w2uWmPx4`u2gEGgM^^y9Q6I8HMB=z|L`I8s(hSEXj;3@@yA|;Oi0^a14Hu~ zEwQsl^I(7JTr<49KS>DC*>Mbqrig<~o=4LmNWZ`}&^JI_k8Pkq&@ z*e1jw!gi)nW+73<@$}K7NDl9pZ&`?VPc>m-s^WYzF;vQWqH)+7po^|}zbHLpIDCAY zhDQH6=FHrE6)qh(6P=|nu^JsF6gr>a!Tw5|!5BED2_@gxve}1p!bue~#fjV?O9@UA z0uBVh!4Ar~ts9P}U%$RI!CY|o$t}7O7QnQqlO@J5RtSsQ(7uczx}(1)#wuD{D2%5d zv0}CCKCBZnyKcM`@L`1US-~EMCWCj=#0)N&aM^kwxWMB577}f3$YA8U4os4$*5~%)f zB&)=iFI}vY^kSIzAQP4|8H!rK6}jO>5LXl0m%2K?+Gn7j>dVX7>vFA1h7t9LF{>m} z!g?*oldbI-2>Rs7TFuO>R}XJ904A~^A}hM(bQ5?3xH#ck?XGS6hDF!(aDpS`Wb8m;@*BfK9>*W^_lGwo(p(+PI+#=k z)4p!+lGO>Xwp3?o2l8vn&DifS9igU`SKVTmqgT76dq~fe>6o{=W;PK9@@CGVR~CYY zMo0xH6iQY+wOMQfFS`e;hPeFgOu>E=lq>rxce0V<5)y_QlwhYQEw?yLB0)>0tx80f zKDLpOlOwQomBL<(+^9VH!BOooFx-R)8d8$cI24say>Yx+r?xd9S4g{8##j*;q}o)O zZ3!EMK^UZ|EIo#4^q8-Lt+?&9IL!5HZKjCFBdcU{-5QA6LBt1Tjldd-veT22&2MLx>=PvOkF{Klgt1cyi?HhV<#p#0kHJg z%S(H6%m+5G;$mtNpe^%~u1Q}YZoq#uG_nlmKoJs|Y=MCo7I5i3doOXIBNluad*EPb zze=3NePx}>ftejfe9r%n#ujBJ$jDxM$O9s^yJyO-fb4GQ9vCokIR^M`l$(&swb?zm$zL{(iu_= zfV`Rwhdn(X@VRZKoowBBz@|IOfS4Mhb!y*-olyrPGv*!?mSbOosPthYk>UJmf@PUq z=vDPF+3@4#F|(Wo7Hx*K8*~}btka6Lp)4}TdYKFmu%%t*pnI6BKY~L+UKMxQOz^86 z?4b3xv4O%lA=`klFhXjfCs4?vSVCR;^zmcd?G09tVfywH{#pb>1tG-$!r}lze^`mZ z5IHJdm#$o4DYU>(lu2$xPhlU3Igjs;=Lx^~tP&79`*5RPB8O+HGqK2$cPi;q zN+Oxco<)1iAR@m>rM>XKQ`kq9cq>{rdfJdybfVJF8f90Am z_mx&>ug}vsKTs#fGevY*hx8gkzu%^GfuyF)Fws)09d{K#s!v7{FhbEX z6;AHkT%3&2Y1iBl`=D{doQ|5x@14P>?gdZQJOwVBM&c%d(f)@6M{sV{wvxf9iK;g) zbt_AZid{HFEm+RkZ_CPTHa_|&kK(3)W2)wNFEmo_eHr0Fl2A6oF4QwHApZH(8m9C- z8)1Qw_AhJFSX_#`;#zZs?WV+ot%^!JDcja~9HOycT31clO1ZaSe~UuLoWk?gmI|s! zuILkI4lBr4jJ)rX-*OEzTpkV&t02lA=ob(Jqg50Qs1u=PO4g+mm6rOSJjuqyq(@0I zcr?$q^S`j%UG16`)>7EcWA)U);rQNMOA6C8@#)WXOuBXkE-=x(BnbFX7CoDfaeI0$ zY~~5Z3HGlm4c`x~|F<82>(>S`*A@@XM|3KdOBHX3hl|=2&SAQ{fc^1>NGhn=s;ZQ= zwDyo&FA>$5thbMZ9 z7)TTbb>-WSQk;zaG}^`y4ZXsr&&OyNN@lvy4Sro4UY*+gNfh0{O?k7BiI2GUSMkKi zYkUBLK#y03#+&Fb;KT&KPq>iq_&vxyitM)Qvz+p3JRe$As)c-&A2VYBT(mP=^N@#! zP{<5V_}@KCh3>*F9kXTWvT~1Lz@LNmPHic-tu8U7+@X?Y=I^7M9&`_o85vZhy=B^% zmcD1nRKbZ0<}e)6M<$}4&KREKv%zd@Zf<%mno_Usd-uZm6Va9-8#!37vNTp>Bq4`YO{ zX)3q;*#r7;Rgx7_w5?gor~W?Kf^v`iv-@O6rA0S;Y_iGJcII#XxMX@vCwsEmPOsOP z_61$_8or-a%yx7aFU?Ys&?ulRqa_TvV^5ywnC`ZQW>(8+kpx2$b8LF@O z6?}W&$5~@rgVgi6@VRyO^`WW~|2T)a@ChHT<V6OUS z*@zQAqB$_r;Q*9{4$#0#8waX6B(0_n8)n|Km5?=NZB#w(lyr1&66AF< z*DhUpiW$MQU&JPAjz*4o<=no_eg7ihl#C2sy+q-%Z&1XK+{k6NL^i;)gF@^1#H<`0 zSx3$1g67@%Z=99N%uO-g@R!$r3eosdj5_p`_I<^{+qkEbcCT0e`)bk)@2hdW!3dp- zw%z8q>w>!&<2x^@Tv9Rf+!UIry`4X7wQ&|x3axGJmHgoa`vS_rxPk()DvNWv^+UhC zSZ=q37|~_sf$IXl<5fLE(E=Qf5#7k>%2Zl)({Wg%!01s0^T&&&_dvlUd;2zGh+UP$ zXC!XL@MO6UXP#el#=bO<{${Dp3(Cn%(9#We5nO&|y#WmeTC%}lWgWz0O`JQLwN?{D z@AX6_P-sA1EU%!b+;Y2!L)HW{WH^W~MKtkMb$V;6?a$50%P{Te5)ueprqHaMy|kL; zAfsZm>Eq%g=BJzflt#&xj~(IRd01Z+idw2WzQpZHcgpRD=?p1VR6)@NvrLLJxft!_ zm~&l8=J!cq4)uf`93|J;1`lFWA4Q>V5 zeEhV=>0jFfyrFwYNK72PFdI&@3ZZ7JJDXr!!L}-PiilJ#r$#2l`jCb2wBYYZ=Y=J4 zz~V8%&fCiW69N$934uH?H^;jnfgvFcXBH_8SnR%*gb0AO=pPY4RxgmJ)&lLFI}_8y zgQp%EFq;g;vU*4zHdIcL?B@LEjAFk?tb0S};EtzHzoUy8?O6}Y5p)x6^L2IV{U^5U z8Z+51X7P~z4VSvKxRARn>JJ(@VC+>Z8w6NiBZV|RAwhY`A?pGSrTS`qF~xw{HJzSK z@P>Cfk{d8beEW;)pErniUq&UTB4{f6Jp7L;(!-eI)qf4vN_MR}O0e7hX^`Ac^70?L&J} zAEc(*faXiM{cj)qUsFAy-c?itP)H(y)+5xraqs_f=~?erUAuYnJzV1puSPL_3R$k` zPNAd2R7CXch$!aW^3C-B$>-mKy_vz49F5a6D&7jpUnHvlRhP#(`oCNHg|cAjub#hO zb9{A7!^$9)c}IU-j3W7;B435hg*Y&~C2mMIz=ID24(W!(o|D)G=p+N9G?w(>-#x!> zYeDsvtE&&?%dIK$qT!7d>)qbD4-+9vC=@Ee8x`=2^Ed`z(z11_ZG6W|$N_ktKQq|n zCsZ|3X{}NfXNipbw;bCd5o5M$EFTHb34AJNGaTklSJRhZty7cWM-o%CvOjkBO*oE4 zkDAFKTL&mtUcY|LLyY9YX4_q)gFXlozFzFkp$TXd+8IX*Lr|8;8LAgJTkw+jCd*#l z6swv{SNlKR>;8uS(Co+D@9eyyu7Wwwm@Y+4f|Q?_{@%YI8hmW;)x`?>h>A??3I>+@ zHRNt-={syCRe~4`460onBU1KQ=F72oxUf0o|5~E0$`LELC&z&Z3@+pINu=bC#Sa#1X{V$_{J7(YWxtr{r?WHvtBXv^l z`B8Js=>Ac3I{`TcZ6UxazHOVpJCg`kcX$3V6P^8k?re&375Nj?i}+nTGUTa9LfrAy zZ>_L6aS%|Qj3!FgOP7gWGzL=%W2+5dOdjb=ol2r0f)LrW9>^P0JGt4yl}DA zNB@P2SXY;tuMj|s%7$pHg#}ncq7yEChMPSXN6V-4wyGMUqEkmsf8UE}!;$mawfnB3 z8#^tsFpeG=gbmT3enL9NJfbnmVP!47{NN?9aNu5OAMGuHxzo0xw5>;s& zOcx-BE=$|6$hcs)fD%SfBglH5HUnE9AU5!TI+nCE_21s_#6o@1%y9h|ZEV{jqGpdB zqalG)LBd9c>>*G-zWu;nK7zN|-r3&U>kXj=tVh^t>gw!|Cncb0* zdLU|mbNDU#(9&0@UNCc_&5{<6DzE(?j`as)`3Gq2FVaw+EnpOp2y>MwbWrfa0$U^k z{Ay2PHc!oIw?_r$?e{0%;r{TyiCxE~NRZYG&62IuX9=1;;V8lP_Z_1~vJHk@AX|lt zq+M!TW>*pM_04I#xENDM6z*J;3qf0d)Nx$B>aL7VfcqXyp{0P z#Et@)N=p(ItW(ArQ&f%$3{3p+uCSIgA)_y8}}XfD;r3P)gXQsZRm-vKMqiE z1va~PpZuxy`Tn+>*AIk#y_i&fPbxXgLO4ulFQ>k?eluMMcY58ZeQ??Bj?xnk#43ic6QQN4V@rP5#PNSxRzPO%bNIIAMsvNuzviOOg2WB^ziA^5~E~@ zH^Q}r*bV7plm>@T-}^(B>FK!zkze0}O-xLPrsZ4B3EI%bnw{3Z0_sr~D9VX} zvX?HE7zO_8S1{A73`)t#od%=~?h>IEf!knrTfGk%Xb_jcDQV>AcWbh}Zi5iVGG;Yw zk(bA?hN_B+MR>_wq(Yq5O|#3yJd z@oet2Ty0;-_=J!1&tE6gMo{Utu37W%|BQ?@`!E02q9Z2t_e${%EiZ)DaN)9ft$3MZ z?ivg-h^p)-{&A4UHCGp(LeI$9xEngb!XuK$TVvOsQiB6A)Kmxm5|tdOlYI@d3#fJO z+1uO0Ik+stiu>oG5BDon5SeBL@$shS=I8EqJP^atjb)4Ulo_D|Y zd4m4^^OrC4d$}V_5QhgWj)^HAe+jQQ&c0C7B|CO5uIj_%>hzJ8R#xbaX+q<#NlA^Q zA$=J#KFGNLj3sY{Q${##7uVO2Uq~xSV25E7MpUcC{ZXsi_>VL=ySc@%k70fYhBiqh zCLJY*=j>+=%5||ofD(4<-u)k-uX_8IlS~UtkC+7a?EHHqR*XZ-fw&uJH4wXcJoM_O z5A7 z0OQpqBPJQqV-OL}uACztFRw|rzJX0bLIRxi~dzYXc?r!{gX+bjpy!!qI}+UD5Iquz9@&$HuOUQ1_Zn6 zQG{+9xjG)bIgHZW-f+!*9ROuAzvNGQNWtn-t*~}an*7JXPv;pg-lM%nUF;b?`Kg0v ze@c4#l-642PMD05=Dm9DT2DAep@j*>M*_Qn;HyMkRu-H+z+LeSpimG=_K17_etLR& zXxC06;8yR)#ANijbNxhPDw~I=jQhJCdDhGH$OD5ua&XWhY7n(UZ%+>dx=SK+@;2li zBAe;>ab;a1zls3gFKn&Ow^R1y$r?>VC4*3;uFg(8vl+-$5%zdZI7TWeCdPixo=L61 zZGwqi2+4i;V4ghYqQChVO?Zlo^DCX=Tighzf$-tiDD;__pBG+uJvDV0D#9l|x9=M8 zGvd7?q?16Es2brda%FI|^| z`S<>R)_V}v`z74z(-?zXUeP?Yhy#@BQowUu|$_n>C1HFI@b@H90C~=Bl!gVr@5J#N1TEL zw6tgd$P|c(Ll--ElICG`k^UhGpK0`O+jWR~x|w7I{dgHAXF!S#-ghuz&V z8*2L9J5bFyuJIy)-9T#2;{0Qu&p7j8YjkmU?{cd|>IGb)!H{(WaM<{<((VQZocm?_3iJ{uqZdu3iO`cwtzRcI2(6b##1yK@AK5R=iO20=rCv^(JABLEdCFK^Mv z>s`7i`LJWG)3A^cDr_yt zUSZeOr7U2-u=&b)lf+Cvg@>THv2)TF8h|aQegr^?E_U(B_&5d^gM$`6wu6o(I>&aB z`HA>NaoDVg<2B{VmC`frwR2|;+D_=y-?sSu6j~dMS~z|BH$+P2*_uBAPgKh zs}2Fi)5nLw25(@rJ};<&by0HV#}7ID3QQ>!-y@xdO($>rMd*NC4`bZf9wc%AK1<;8 z1g4E2fprwQKf+p!&>n}cc7_xZdmIvTbsUP1gArh0*i-JL15g5XehlP?F{mLN$${dL6qZL!?m2=*4mmTx1Z2`Kd(8eH$zM){_2aP%q&s~~uQx{M;H(ZI)rCZ?v5jX8L|DVK{7 zh61cYI0`2)=MHNK+bCjMAzzc!Eh!X1^nPElvFi-?_w-!Ql0OcS)PgK}jp#M0kS6FP zL_zgE=g;Sr6!W9*@JtwnFaf(Nl6$!rfZ#)b|LOq?Iju(4v7KsBjwch3U(;22n_^^j z^1AI}ah%w@Zm9J^9ib)cJZj+g`O9gt~wQSPtx&UE- zj(TGi0g|AkVT1*Cuoof+E1$qDfpo%KKL(IxN{l-n?1YO;TL>B6hrPWwrDR}1LduH} zDo@Th^on)aI}K3ZQ+sPcV+cw8?k`7KDsNn4qbwK4|Ez@d9#nM7GgQ>r9q>hEHIY(3o;`;*0fteSLY3r?G{nOYfoH1Bp1w?UOi$j~tQvLF73S6SHb-xBR$Xr#o2g zdwl60eME;#OInJxRHOfV+8mpdeys~7cYA$~!(P`gt1gLuX#pgprK6${R63&f34wVL zjeCwAQ{wc2rqT7uz(8W#q{kP3bp!up6o;{QbYM=A_`R#fZ{_RPW=%mZBu`bQpuY9$ zqh}e;nfu75qlCrryxN;b@K(HjF7{=Q86YXxp{yTPuri)I8Yed1c-~q<``Ru+=ka{| zjuJ+`w4KOc0A_i;_(G7>6~R?iF=3}pSmVagpK-q$NZ%lXsD%m0{lnkKmR8^<09hGt zI=x=l)zkAE-1rgmd4Dk-*ZXRFn@(v+mor4SLgl-!){pMK`D?#g)XyIm7o97g;Fh0; z^yv8Nl469sp*<9CpIUVNg$1_iKsxp+U;{`q)A{WM6)s9Bm?kg@3yB&SGj}vc55f3{ zacuxnCd`oHcnSj}oUJG4=ISuoSM1`RefvV*K2}(WK3HLgiUmWI^6^$(ytfaMm%g)O zP+TIsqFk~A1x(_q^}wfriX8X#byCd4BI@t$-Svew$j;7Y{?qk1Z6QL2jnw!^_N;Az zey*;sAiuN;vHc`H|58tAo%J}BpQvadp~kQ`D1V75ML4kRL^tV3rMewF7{1ODoVI@( zEoLZ&=}@et@?{Tv`W8}dsY8bRNLE2%bx&-Ei;P{l6RI9FG0dn7#4Hp@JoM%yXjzzy zjIw=%ka*p!hVI;a(*v;-32v#ZDyFe&gBV~^C?kj!nvns8l$RNOV1U3Woa9#d1QWH8e9vhHKc}>#7Lg>iX(nXrvI`@arg+ zPq}-?Hq=DrMY}L^1S5DY(~Y4aCiFXYPa%P(*`6;@t(k5A0~vrQkCGfK-Oja&&T-}j zrui=lAGh?!y^}%kdZN;I9zk* z4$o7ww%4QT0eg43{pO6FCkA=5fG2vcZjx+mYy0vVKRU`n3#pAo-@gs%;%wgHN6UGxx_TKj znRST8pI7ls(Hww&Bm%S58|}5TLrn#Qd14EiC3NmLTqzX|4FdJSx`n26A3AyyNagQX zhFfVdTj9qlW)7m+J#@%sAbKYHTKvueTA$y@EwWf;CH-;mFpqKMm8o!}c&Z)~xTy}fo~=gVZ%*q&*Ty~Lm%Sd2&l^X(4E6Vt z=VhxM8?w?dxV#?#GUqST55$|aO=OGh?%lnogZ1|m=4EkU?}4vEcLhV07*Aua;UU!E zWMMR7E)_%S&$PM94{aQN$8b4c2)dp8@T-l-XF0kDUVlR8)!-7k^d`A=)#4A7&(1VQ zrEtz7u*pZ_psg#$9j3aGF~BwaSm|8vJ>F`~^(;7~Q9M^-vTT$E0IY73gSEck-&i+6QBbTE8en?cf2QW2q%h-N`wz%P5APleGe0SS46+XB$t z!T$a=L{qS=zP47U5ougGBZmFMIVXmY5<#qO*Fp;yh(DMHM;R-vm?;%Rne#Oow z%b2)K493egx7L}K@|4X?AH!g^=>6^N^i@Ib0dI?#X@3b0<%?oR8ARlz0Z5z8 z&QE+kV@@K)zr{C%t$58-l(^-u(>MmkP^NYBT_er-yy-tT6H*zKks8WYh;Tr zygc~&DQ9=cbFpD>batX(6D9`&HWwnM+zc+XkSpefg<>WT5R4(- z6sTUt;qm?cp-JvTTnK{BEOKBHwjL$NO-B&zN9vjL5vq1LPbLCiUxEC+f9IV+&qfO4rl$R$nz_6v@`ZdSzSLPz zigRA>=6^q)e=~k}{PY3xpY@FFVCs+y?7Gt2^H8nRjK@s*6y4P?@3=U!W;UA_)aKt2FZL9*kxC9y9ieWGec+5h!Ov$Aq!AU> zV55iCojtHBcn{R+_@Y=~7T`Dnv@Ty3h;}}|s)K#3y6#2w-b3croKoByu~G2)doyv( zJt2EFS~H;Npx>F0n=A6|D=mxyzy)yLp^il%IoEkXkQ*^#UzV0KkYf`Nz{}6CHyp8L zJN^i8MB@#`Wo0m*w90V){IKQf$0koTucQ-7UG?c`9%EkYyzyr-7H^5!wKK_0BjWto z-8|Du0$Vjpm8iv~0+!FWI2GM0D(D#2WZvwbb6$Kw=)fSm`q#HtDL0M*86c8lPL$q@ zy#St%NPd3xwY$4}Y3X>N(!sUNGQE2H{9z&kWQz#_kUmtpu>^D?j2TPp-SejGAa~pn zGiy}P1WFy1gy#Fk?=$)$4H2f(2*Ad9?YJDPJ$o3$ppYV zP8!Z8q$j&nJ^^lmCQO=}=|%#eDyM|2mo5>Wxk+ElPzGDOmYKfl`OJ*lw*_zde0r?D z1{d@1w9fBx15cLua}^8I+w4s0)QA{~-);1t8C@F^CaSlPW<7OcE99m^62=AN8t zy2w$^>ijO`r!u>r6OBSbftp3l>Sh>lfEv#o(sF^Ti8T5Rr^pP9ko5GeWcqBXtjtV? z=rw$N!0rf0gtrS*w|H;xS>MS#FfY{4a;7@Mwk~+xbqhXT9}OM8C9=Krgs?=m^U$K_ zmDOsNEnM((Y}M2}^@a|`(&LnD`-*a>$QZ^BRgdYnbT)QaK2;U)!ej61@$RGStEFJz zy(VO5*q#Pl6@fXStiIMB{FqdEBfc2IBs=-DZ=kN!>dESXFcXSIszyYr7hV;c7#@ab zjC??}{8#JZT~5PFij}oBZJQ{daqRLaTFsI0B&>{K0hn9x4)66Y1<{}*qsqSh4M&7l?fgvk3X*?+e7k~T&AkWOZbM zzb<=ZZTK24ftDal$Vf{|)2p1&-iUFUD<81hyt=}^Jli609$ZhtZ-toNX_x-|@m&w; zTf4i-1Izd`F+Ti8JfN?MG21BN^~eTBMr^JcM>6(|7z|@0jJ{Y3#YQE%+KnfXT33DN zPTSe)kk^nP(631a(w=?#*V@)55FKbfu1jp+y_@GTtIYnp0=g*>#}1D+EKl6@4CA>| zr5M0xTu~Hp_MPtDYP#kEY5P5|D$C28ckmElo!Z|6$ik4Fp@9&ILQ>~v?5#z?+NJg{ z){mwIUXnuOC>WMH0LX~0+`G4}rufE<1TXdgd|;@ZfWP2$XO+THSTM$$!#lYp#NIu?=%y5-+DvSX*{5lRKI!?~xtE_Bpw&q!n^)px_IWL{-h>#a6QhHZ5ts;d$yF4~J(~_{ zW)oT81U?EMm*v-7oUKzQC@Yy8Rt}9WHDBA<&yt=h!Odlv@8D5#o1`{szvY7;2#7&9 zI_eg%e4idQzo2miY4U17V@UR~sBRnY{2X=ozD% z!}6Fa%#9c(#6lPXg_=#&8u?a`*Wa>onmJikMrAIsUB7$sr z3^#Cm`%Zij_%M__zvvNOw8~8JlfXtsoy2!pn}=*{%ul&nbmTG?S1}zL<|ftu>RrEN zNE0&A(E5VK8mxa54SkWfOo42G?A**u!2{$r-6(P8*=Ycv@i#*Li!o}44&zbI5lO=DWI2*4&IVCYg|FXE~G88G{_kU0` zZ|=1(tAiEm-o1NCj`)S(Tk-~(B_$-t$R2=G9ZIur!M;sQkzptVQ2u>;O31EEBY{-` z5xKB_4M=cprP&W3(ixb`_6akG){i8?!mG0$;c^~0-T0bva$PKwb)H6Zdo$TJg!O%# z)O7F9T874ge$}cH3H0SOzXcEl-owaxvjl*Pz|eN>HNX{xCue5Fl*Ey1KcMkNfS2NV z1yS3PtI5ipb8}v64~Sp4W>i{pIrMEy#DjFcAxotuOn_8Yl}-N+e_-$Bgw^cq3y4hh z+{9F@U0*+Xg)zSiO^J%6WAvN4kQj%qLjR?=*CN@q36ZAQ!{qR+tOGp613JFR4XgD0X$S=%YI0+J?MUUrKUw^-i$4?C5g)`(ka38&m_!P!? zhj1Ff(}KKJl*$WZ58?WD{b7{4iPqtccPUzaDB=2Fe?qa6J+Qlm${_l-i{%wO)!SZ7 zCtg7Pk#=;$xwtrJTWEg#!Wy>zW>beWNbUiaZ*-1t8ivacAIdr&owW%+ak6YHm&v8%AqOw31{w-B zr4u;huqhGY+iR3u;jkE;;(%P@lKez26j;-3eVB? z?M6bM#?MdL6_qm;1HNkjaQ&|jzkeOc;s5&z{`~n92VmfV1EO|985tS0badhF4a~r0 z;SP)D&|4?)8MIDTmipi!G)zQniPo=0Htu-Lm^;_cUj$;{G~)dfc~;qw)enu^W<=%sJ!FGLOkt+3bDc%9iILygvI1%2s@bs>kad7pM?J1{K?DyL)=5%dVo! z7&nL8X%-hU5i~D@l9)bH0RjmDb~aSpgUP-6IyzLc+-vLQLiBJ%zdaMaGk#l;Wn`WA z43Rkl0+!GgTGpX{%axr3np#Q6eVgZiho-cM**Q@T{{e`EGKXdlu6(Sea7{gC`vhQhcgq{HN zfCy{o*KHQpOG>^YO%CIO3I~6jw1}3cePJC{n|xNWmj2Jj1n zc&QbNVzH4p%b$$g*nLlQ20YgCr5B*rZLMHV-g)d^F;$ z7_VQNzqLOqM#Oah57if$#k7;+Vk?C=&gdTOS`bnULdGoB2>wBhZQD?QJoY((cv_T( zeZ0ED#S*lUhej14XF(k)8ihS&v%r8!q2*q5E{*|{bjrRO3Q9^CNpuqFP)khz$UG zR&sPJ7+`O2QGo93L)`hjT-|z^v$(W0dIF|Xn0#}rv zGFQ_f)Yh(Pgf5BJ{Eu!)UX7Vv6fR&FiX);%p1)*Pg20q+Rk(~p9YQka_6n?1bnD|? z;KiISwa}HSyB)&#(bk1d4~YRS;?FXvUH3ws1|pw00ybdwYX~R?(TP*r>!GQ6-WaSZ zBGL-J3_CK+?$oMpR@29Kz!EB+-ixyh<-?=)p-aSN(CQPCDjf#2#tzk9soB}_|&sJZ1*kQer%o0`FdX`=#K#f=OfDL4l7dHtkS3AlO=X11BRe zdz&9TP^PIQF6&QY(7U{nk{%g{vYeJy_KF$G-A({L2>y*ZJ)om75F?b^WXpwnW zuMTIgLx~7g>2Q#3{ffz&?c^BxZ&`}WLw5h0=qrX{Z8N(e2mZ!EA*2VKd^d*EZJ(p# zT}W_Ic^x@Jt`pg?!4C;#YuT#aJUKNbVk;ig`cbp>|}|o6wVOQExU;>-;a$ z-UA%VzW*O5vd5K`oy(}KGD{&`C>dpisB9s#RFY6uMpkxZMn+cB(6F*8g-9vV5Dl|b z)clZ`sg*-AC&c$Exe>z$8B3eh)dzBRe_s;0{nrD24;KWd}Tlen({awRP(c6v6UN zoGOZn)euXli-=I!VvH!EETmbn0$Sx?^A*7#{MyQ2-K3eje}}9+$9+0SG+x{Bgy4*x z|5ZF{E75s?`KBZHp?rAp;;OeV-9f0Z3{qvZ7!W3N5B1Rxo`XJf8!Azk<7xSfu*Rom z2!BP}1=B#J25LPBaX0eBAO{CK+$suyO%$oGst?95il%Cc@Xmb$jbwEmu?#h|W|t7f zK5~MBvDaWm(>gIzOOruYM+b4K#Bj2$0W~jQ#f=9Yr#U$ILHf+G$9J|0ZC7JEr@P}s z-{s6iDg7Q=1rrlQds&;Aorh3&8F71ZQzf*CXgSx4&&kHv0VYDyb8H{3hqog|*H;O=~fY4BgcrEh0| z5T_(#T?#@!vlX0~C@|kHVT@0scT`+l5HfziK0tv1mKjP!g_)OeN(-Oq9#-~R(tc9- zI9DfpLXbZuZl-9bve=&F97dR}N96+zMCpQu zyZZ!iXQ+dToS=!UC`_e^w+5hawcaIffzgLp_UCpt%z7fi#Pgy=^PNI?(D0~g3n!@|@wFJ^rnx-m6jc5>gq z!12+>l^MUYwj7~b)LvX#(uz%-J9c^c_`2ndLT+xnx)l0C%ns9L06qMw_Gst80Mglq z+S?h)ei&8pJ$w(MIY4us2nYa_h45-r7=(;cS-IxQl^yLiI2!Zw@>VPl#vxHqed6BX zKA{s97+-}(0wSz1W6Z?p%5isf+RiZjeG%9=f)sGmqjb>C;4wIiSg48phs;0@+!Z#TDgJ2`;OD9pgix~VdttndIV zgx}uY))pc?#9s+z4P}LDRZ%m5dy!l@?<13cYXR~S21#otrl;-__x5p^^qR zh*k)_Q%hU|xlYLK=ba-eMBao*7y{B@Xg~N}0Aml3LQbL(^NG+?)Y(71x)+&PWIy0D zVE@}*QJvc$A_9#!z(ZqJ9ZS4HHQSz~+xw(lXlgWM#3B*mauAM@aj9-Z+3{BC? zmoM=jb3|Q+t^p}*>gqx^C6&)ULIY;Be0TxXL~t)OVBa7pM9JM@tFybg>i6Vn+Vh|RfL`m{1wKbOG&vmhB3nAfn5V144|qp z$9j%@uXRNoRNLnR3@S1o2U$p~-?x~^txbY4R7F))EDX&vio!SE5ba0D#wMrf51YJo zJiBe36t*tXD-1>YM=axyE>Zj5`DO=oL{9)#RB()e%?q-6A@u+p?Utj`Q0U(9c($U1 zY2-hoI3t>8Zr{3vu^YT(aT0^m(05WB%#F7oH{=VpC7lFWr?EIiBisVXQCg;Q7%8oD zW&0`$q;ZILdf;3{s-cA@_HSX;9zqiHkFZLsi3;=jI#p&*Z%KHEK1egKwA5huAa-hakQEO3Oa2FL$;5yqKz}2L{Lr5wmm&xo+sX@`-u)XJ77X`;Wc8fW->D6 z9qG(HaCn7l7eQ>)@X`bmB^HC178en%?CR|uUjYpQCb1*+tEIIS>&V#KBCmp~e@}Eo z(t5JEIBmpAQ1y6ftg0MVdTnGNqXI_2H42Rft*x7tln@Z*g_3Z4J`&=ZTUxT`=T%2lKw5p8%zioY?!HLM(l{ zVBVTONzJiCC3{MM2{I?7rCH*bF~*g44Kv1Kz^s}imWjL+)*-9wum$UZ1ELfm%s@`g z=h-!9QYSzU^ z+e~3x&5YafWvGVvCMO1P_4UzqM*flQTy|%rNzA~I7G#(D>tVVg)D1vd#5ou#uCPT4 zZ1SMG;u&WAD7e9MyJ+G_%+%S48P}UEdsYwrtF|(ters%N%g)Zv$JhMe0jA^GoZoo% zu|@h2l6|!tdUS11AY+S+2J&it<+lZ~*O%7t;dEwaWN1=OdRa~~x_{EvcFjw=3>DwJ zMOJudA_%n-rpk2%L;M??4ayth59eQ#uU}t7lgO(Hbq?m7jY-)bJoxS11@Fe`jZ%53 z`j3mn>(PyZ004O_$`b<-OYzSw|1Iu{^a3U3=GKsTy4wXAJ3MK!+(S|u6clFQ2@BgB zts{!66Ic?2sp0gHZbPHQBPgh5dN!ei4KNGMuJ15kvUU2Jhc< z%z2OH6{>R;#a_j*`M=J64<##C^trKL&Mq!ek8*a|JTsnw&`$m5$7(ERYCQiTx3m`TMtKlhz<^O3l7`^6u*F-7cg1q?`^YPilm3Gpxel)8e!Dwmcj0>RwI`)kGa$UDqTcn|zNR4OhC*ou%L$ zZOFS>?FI%ZC4GsmXAx0UoCOdd7hHY)df?Y*2N7y?j)bXvmmmU!9(zx+nQTg)*-k2q zl^Y(ul#mcoRs#7W0q5{;#@+(XEfmuvSFc`!&K%)M7yW`KfTAGz5)FeN_RVHPu<1Fc(Z~bY zc+00#>*1^&1^<|yIPBYV$N-~OJc8nc(9X5=K%~?{U-rnpt zO44x&Lld)gM8Bi%I-itO$?AYM18ahQ|3kij3^7sBO8d94>70$^V#vj!kKguV9I9Xj zGOk?U_rv{fmEI_rx8VV?Z`}up%~rp0)b)c-H!$H7O9sS9xCR(Gdy#_5nW^!NZtSaYY9Km@G}xT9Nu{^X!1pz$2*l9DB4dL-S4^eZeN{IV97qe?JKXV z`S)~35@!k^Xu$F77gyid331u^%|9nUeOiLjo6IW3tq8%I9`0{jg%1`G^lx*hOW$Oc>a{|Nc$T zV5L+G$>ZYK-PxF^hkV2$=~b&5ZTe|WDFp6cePQUwsXH4`P{WzSK!zg!qZCv9CSXE4 z5TcQEsO(>TQiTr#nCYX4GWtFVCsl%vpP#vj9_yZH9*G7-qN0lGFgQc+$&gD-tj()$ zS7S&CYp`pJRl`XQ6P63==7R?bDs3j_GqewbrmF;wb>w)h8fDcEZ_y)sGxbs}06`HJ zIx66nUtTn)UjuR0Nr9&Hc&1HHO??v$j+c3?Z|~?pq;+!LFKl8BD(US`ulZzhCU+UH zHoCB>woT?_G`CN_{(P==%-&lANa5KVr%8Dm zL`^?@{+#-Sd47F0%Gax>M8kaOMYN%-Lb-}tgdNrVV++e|7VZ_loD%M1W~=7S(O^u( z*>s_7KVP3SG?_h;IL8RXqr18)QlzGMWH)SRF=(r$`u3Vh)`~<~Fq_CzoBw%C$OPOp zilsMV;qi7qLsil*wG5U<71Y=Xy2V-!0{})vet0x&&j&>8~u) zL%Dk5rYa?{v7pvZC>)yWweV%gg%lP_0=!PQbgNuZIH|&WG-e!-MZy%6oY{OgYHHNK z*e=hEjA^yaG89HYI4;xFEhS z;r5+7HuecjcEGw&cYv`7jUFDXly1UEQoGG&5?>&r4b27a8L{)seFg+Irf>s?1_r8@ zYPwSHe<I?jr6f7WvN$nD*3mpab4NJ>U+bJKTVa^(QDN!}C znW-s%$N-^OnGec}r9A_t+O(Vsaxi?;r$Jf#S3`jkqSdeY5nWV(%yw4H1;<1giG z$h>jbFKzG9$qhihkSs3Y4OPqha# z`>Y1h^b>jWS$s%t>kVOZ7w06 zn3XLwAkyUSMf!3e$>_WjlE(cm0MbophHb~n}KjdGKCV zx69bQ8v8y*_qbh(r55UeSEEn)+xMtS5gMUAaql0j+C^WZ$hV>|h0pu;L>q_Qtz`1c zdwg^E7U(1n3QV#AKf{qt85ux>U3BuR1O?n?)81k9Jh$g~moIDh`6s~Oy?H}>=NeH~BQ+1^H=Oxm zHL-d}>CZt;0e6xb40Ilw1g?64SA!K<%W*Xik16{jla<pX)0Nap)q+|H|};X6Mb?&>LM_nI3KZ*g>jW{cyr`#eM3ZSJ?RQ zzz~(X+xAnZmXK@Z=5H}VB?gI;cI7){f7S~+fK-FfotcrJ-hzJtmjf6UcthOkg~l@j zg;p{x_Ipq}3S)$kxAz)e-gK0NM(-msXP7>P#3-nOPS&2B&v7*^A$(`$P+g_(59w!(tG=8%yxOj< z%uu_2ZZ&}__&N*lT*|r8VB*2_Z$7SZf;(m4GBz7fAxEo}_+9 zs9y_v$C_)ZbHuYhy$d5#P4a+;ZTR)2$NMuV4n7ZdSoNSYI>m3|3}>-jfyIDHlsus( zPhgkYcw`A5TLY8x$sY>zq!Cq2waa@!_sb`W13lZ6|iLmKRmUCrhv@URnnMc>w& zI!Cfje%^An6Z)+hMta;;s$w?m79T`w`=wSEHl$&0WT^rA8qT^_wEF}DmN2J z-2ksft)HZyox-m>Dm`Wh40Ec!dewtrU!C7&Qx?`CDK7xjgHtX!q5aoY-@zNctlROf zBc|(wZ@#$g6u);ln^M6Ve%CaqwP3y1asX^3#6G{XfjU3AK;rk1?j_x=-z_x5AGEGW z*YDEa{>j{kq>+wI*N#`tpV8V4@>cTcHUJ8OuKQat=m$f_6jo3BomkeRutJaGc+gBX zFRIIbqXIH2?CBxh_%b@$@b)k^sp3ry`h_zQdm}mqgr_pDA)Bg~+iQD`d4)*r)h=0}VjnnTMn}+xSS}^?Y9==|PtxlKS#*N(8!CLM5 zSajimR2HxL-IwKNQz49^MrJmG#;CoKtw2IzdHB~nFF%!`9t+7Ph9Rjq{w~tRO6RGW znZ|=rt}BH*gBb)tuppQ2^T>Kj< zM_;lD%AWAEjObW-A4(mMcYiB&en784D0LEIQ1s?jU08vB>=(*Q z(J*n2cKnLs==fsF6geK&^y~Qt;k8d~9m_~h|C6RvGSh}0PGlO*l3B_-prr)raSDL< zs_(~!36rOsSHx`#f<#?=!CWd_o^um#{f+tBh#UHR2YSqWAzoZCP)DP!up4Uu##aGp z^|A+CcuO{!20$ywk!EcD3V`K7J#8UI3gz?~yfG=?<)(dStbW9PjnX;9HU!?!t>rx| zEx;ule-nus8EkzoUj`wfE#ZFf@B3ZXJE&B(j7lNd1_CDL1{OP*m^m}SGEamet+dW( zv@uD-fJ6b7hKdy69+oWVCfKsz46^)2RY6YJD?-9U6ad_TAs2!^43q`Gg1SZ}d^19F zlt9!B*Zp4d#`}F94h_Q?Z1jhhva`J%9FkH~;peqWcP`pDLeN+{;=OR|+nwlWX^Ea6 zKvCs!__X*jWq@7>RO*^7hjoUj6f!IEa+ zGOsWNqos+n9_Dm_&cu9Mz;nRw&{GdKs4FU(=`zpQe>*lzPSKBviSb=`xsti7qk}*# zFC#WKCySl>`ks!dGdH4PU^~+YeBl3-2$9X{T#SEP?}1Sr`}Go(En3w=TMmokU>DaNSd?Pi`QcZW%5;xQ=9M*n>y={|_c#8vK z6A-Jpx!AL3Lo}5kgn__ap_7(wkkQ?=d+zyI=>c}-#LIsqJhj!92TnNunEL>kv1u__ zYNS>ra#|`i^sJL&$VKIfg#{yJT(bi@&)3bCv7lUzPH-KlXhxp2J6Hu6jTy*58+2oM zOnzTTOGBWpQ-IjL&cM$vw!rUv>lIW02kzpmM}R=P)k=a`sIBGqu&cjLwZVba!PQx% zs20<>TFTboNYmbv{k9o_X@zyn;*ZvHm?gXu!|yTiBVf}HR%b3Q_vr9^8I<-CCB z9>TBs4}g{NV*D+Qp|7xLi7nu0LkGm3>tv`h#fo(!w}JZ5PjYCMKHo7sMwnyvZE6bb zfi45q;i&xvV_+78gABGjI|_Oez$U^*`5DvP>0_F&-MG=>B5po2J6rejvuc0v5#yu! z0z*Rdbo6Y?6q~zfEcvFwTPSB6qPu_@y#0L=@j2mfCnBCMU+R~{rFJubGz!*$IYba( zD**igD8P|kTtrOF@$CM>9V`)EKURvbTj%}!hAiSjTQ=_!O~h6Di5?Vl9IrM)7NX`4 zcquiNXQCN!E$|&*9ENsJ++7tAqE7|aibcEKF4s66?$Y0R-`tl7$WcpFLc+Nxv>;jY=zVi_rf5C!AK0P*lE83- zsW%%qqQE8r@6rI(0AEe%=aX9nUzMvKhQ+=HOp=tJ&BT{4$jA?w>)FAabHy}5NXh)- zKLQ?SePkPn$;8l5oGD9s*bdjZzt*f^Ai*_#?w{>k^>fgY`Y^ONELp0dQac zlsPAjx3m7O;NQO>Gswuyl$za(W1skL5-VL@FXgQ5H>^{?Z#|!ILmaZrXV6I8pl&j^ zv?K(@Durvb_VZTWQr%}){S0|8xON_!exe}-LQwKC9>QEO3mej;i8NvAm*Il^#!+J@tV6T(bUGQ_`_{ev{c=a_hiG`2@nyj-CZw93UU zKPIL>^lJ|#!7Gin`9fyqvE#=F`ubQZ%wky+>^GSZ(i12;WH72?^GIL|`iRuDv`L$b zWZj@VO3&)}BkF?GEbN5pgV0zsF%XKF`YTYx#IiB|IMdfO%9c^I{1%!$YyYTTRy6)m zy^w^>^oSo0En3d*fhuPWdW{Wfhfq-q3x6h32`0wJc{_T`p;Va|Z9DUK9FXg2s4D|^ zaZ&U{6OqHFbAAe<30Az<&VOVZvYM=?5nKD6h-iEFZo)*kag4DzQjC#fK4w`8a)t+^ z0N|!kQdUMqfMk`HvAYpKk3C_tB0*tbf}H64%_r`P%=?J{AHhQ=b;Jev^Dh5uDAE6} zA!*ZD&PQ7QQC`6}g50MX-_JtDNuofAARb8mTW%6U9*vrBhmOegKN5WIKd8iltFFf6 zgHK<+45YFA{RviZU(27l1sUia2t5$Pfyxz<>zxIrrwnxdd=7ljH7TuGIFZrPi-mzj z1JpdXoO!f-TS7>QuR1fAReb>p#mK7JbH#CqDMl8@=#rrgj$R!JLBW()eWE9d+$|&&0qUFc;!MTmF zJzW zMT>iRV&)-k1~gM`^?No0ZFZWh%`x;ZFJ9~mtg5a)0)?k>#Fi~v;1ZkB7)SC3!fKXD zmxJMUe1B^JpqpE<8YhEQHh9zLr zl7gb*bC}U!hqVur{X1sC-o*jM6(=WQA~~DQjQcgJxd$M1^6zdOhuV#;t*w}R@vaW) z3>QiG?4STp_zm26xXO{f%M?&OJYmzfMRC`O*e(n&F@JOk#26~ z>&x9)wyc7BdUsdX1U+$vT;#5J0&7G{4nGsp!v8!&Z8`6SQjjo(oh=O9rmcg+Yb0CO z-|YbFiHaUVR0yWgY7t3NIC7@V{2F0nJ$br17M@{MQ8h`6}IfXG%ye% z76Ok)ebw~74aXsxfRMvu(@6{rfi#xsr5E%Dv-9)13=mVi1x+?n7j?x4%%G(NGea&k zPa)0L28VDzx#44Rj-7#l ziy#i|bK;5QGz8#kA&7(0_VT6hUEdI_u=Vvg6B7dbYKGZaL4V>flSh(A_eC zeM>~%?TL7xFF5^58uUF>_lFQt(x*;>ZWfxPFk>uG$dwi+kwwVO_8J9+2zBAUPzQJS zj{f}$B-J3H7z<#~Rp7mU3Rwhyi@J8v8OSQcsZM}Sc z(OP>*PNyz_ErR66CvmG&>vI=CNP6`^x=U5*a75|g&*j?aRx{`PA8`5$4ZB^)b^K2_9on#I zGk=Tx$-!Hd_d-aRg=8{dE2t1df|wjI?3(dSg7Pe1&r%he!!yap$r(ywVrOrC-vzEs zEm$BKQf_TbUG;Pg`=ePyK_D0K+@!%b2$qJFS5fTrm)YE#9prCSR6g@y=x=tYs!zRI zRK)O(PEG(JlmJs1$aJC9Hw^KSM;h`}E5muuDT?~)IWHsaDlQ?04DVnAXXb$RXhGC) z6pD{uUvl6d)}oX(@hNj4q0Iqa;&cCgW2$>b=GZ96)U6w(s9#MX%WYyFK@JF=mFH!Flq1X- zlqv-Slg37x@z!XiDsSFoXJG-;TF)j$vvTcIQI+FZ=hw48{RJ)~c*O7QYC&P)tn_ph zU{-qBA$Pbxw{SkhyLPanx={8eZXY=orssUt9qK?yLfWQj=MD2wN z0#8-hn0_8h0ogG=#+cWxEoTDLL14|#!K8{G z`C4%J*RP-6G7%GW)|t%z96KWFyUfv8G<=Nw3-`1!H|G*ZgBU{JkPdh`jPwV^>^kUl z_sw)}H1HN&?Hvrb>W`-cOww>kwdZ7Ye4Q*4F`C_n*XBb5hQdzZ)d-g z)?=J<9jLbXHGob|%gO+OWz`dD0-nAMz)sn#)E_u9ig5^k3ZTocXx3EN*0Dtm4qCx< z@?8L0MUfEhyoIx74ZTU&xAT9u+|7IW2QXx-pkn9wUcLIL4yH?pLxgIePEE%tEF35F zwAlDa6>y@{UnS6lqcBqIc|N^Y0v>w$M`*~*r~;V|!m4*H_zI|oFQe1H2T#u4DvU3i z4(8xU(0!_BY@906mbCsXgWjqMQ?D578jC}pX8Npky*@c^tYJS|YH{+=y|S|Yw4u_n zm+qemYK|7CxO1l%anU-T*WD{cp*7h=rb~LYX7=7}XZQA*y-7Lmm*^`-&p%RtIxyo? zS8N@|uT@t!4e#16%1-s?_3mR4M(GIdR)tgqNgyTjd$9H(%?-DyMazN2mA*i2UEP%j zxK5v3fl6yZiT#Xe@dI_v*BaX`Dl3V?XF7r!oH`<0w>4lxkwxWcn#`53P!%>B`mZ@NGcXOZ(nj?Po)FLnD%WLp8gZoHHqhAMH`LeHW9_~8SqqE_`P7;k zGr-zVdo$z$6}wVU@Ijyd&sU!kw|f}JL>UKGgV5rB{Ox<-eH;~DPfJD5w`0r6ZM7}E zbt~P^yl?S-8-X49f0Mmi*z6<-F9Qw$ye$J614zMw9hgT-B;~Z`$fr+b^Uv`80Vc^F zxSQTO#wxT`2{OV@bm0_V#1R9I#E1=iQN11E{?GV2v2TNDo*uY&@1C+F%8xt1VQVhs z7wcwSG<`JcLooP4+{+&~WF4R4adQ#{?~M8uya388%lThP?M}E0m@V~WpLT^lsuxP` z$l=@A#r-#JKL;;Asxw>-r=)XH{kX&@fo?(dHf?>R3)l_Rs{^=C#H@159V^LxSlSS% zKoE%txMKb7xyINBexU^V!7e3<;ojcfh=qWg57l_``M;*aLq+rG)hpYhJeZ^-3w{;g zqV;?C^*Y;BRZk+38Q3UzCHD)Wf37&yZhpa!2b>wPBZB&bN2tK`1kfwo=sm1acW&LnKphlAK!{3&Bpvw$g@oW{z#T_NgswKf#-=FB zB=IH?uc;}_QZ&DiNB!p)W+}-OA$k6hFKH66`Vg>z7m2zYh7o`4tU{$7xxb zU%k?hkwKMsuJbL1E_^`&j&j8Bz&Lt6B8j*b>7$5t*M1x*DC#&02Etl2k%(cpu|WXc zKz}~~0i#j{94?@9M8cdD_QLU0EXJgEqDQiA_t{#7L+$enMvr!fw!KU$0zidl`-19L zbAJk#02Ng#FRc*wx^-6&mk}$ZYBB#BHM83>bL2ik?H)-&7ehEK%GN(=$rE*~La_|u zmiPppYB52ny!=32&?#Hn?1`foH4P3xEDS@|^!1||9Wa@E91~h0MSk_l`^+QiAM&S; zAyQ8jQ3NJZZH1PWoJ|oD17b?*8jsu8a%z`Epi%OAb$|H9d1xlWSyj%ji2p^{T~ z`CQ~NT-#4%f&z-vaCUNXeQD?Ec@Oc)IMr(=@dOo~U1KMY@C3|+e~i)Gv&1}WSiGMa z$g86=M3WA@ue_wh8qr~<#Y*0RSw14FGE9|kLL~WgnuAHY+*Dm>GE}9Id4a8vfs7}y zY%{@4-|{k(NlfdQz9tGm0x@z^Za|M_bR?gW9R8PPm&;3Y@}=RQKsmW^aKN)ZH< z`SIHvwjJIrRk-@9p7_kSZ>^*7e%s#i(V8Cs!wIiJh6w+U+epfUc92jF_j7FB!G0ReETkrO`0W7p+G~G&V(Y&K5liGsz)by zm9Wm!!3QQQd+AxW%GBlq@B-N8gSGkWZX$Kp+4JW)*{l|>`{O`yb}qQ>NWG|mYe0)j z|KaaTZy2w8ym*Ts8>3BQ!WO#?deT>*J-I7SO;vAIpG1QvtFN+$F9lLPgrpa5P}9@b zpZNT_WfbzS57<9zvo38pQWzRaLvaNIu@DU)00~gO3kYGwvy-_Sj|lLDNLWp2SNs_f z4Ku}$IXCDl*JS|-M*1AiABfEUV5fJ2mI6?XbbnQr`9JMSZ|>g>fElc2*)5V5!)6)%c3piU)bc{QKvt%+2sDA}m}a3_?iwGx&jzYo?!7!%4?Ol?bg%dh1>wiO8Yj{ z0j5EICo1<#En5vX?O@GhT*rH;J>y5YiE-!JttKgY;;`SqsE1A;{TV1Z!tr+evtVNE zX%=X+@QMAii@@HMc~#Zsc*Lx?RLX=O6k$4KBB&3~jk5RD+}uUA6ABc)wdcWk(emvJ zW36i8deV4ybWf8KH~mThua~hFq1O;YEJtlo)f3kNM5$e5>pNs3kVny9j2AOzop{Ih z;wl+e1ZI>GA1|+Rm(v))z5jk7FmKh{1fz{YJ~{b18Uh?S-4#GcV6p;J>ZbNGxLpn= zjhA;%U{)ql6L>`ux8{)e1OzU?S%c+Mdg2n|baC2!A;NOm1bZeHJ4Ssl(U!Fz;h6Gca0+QW)j7Ay!L_1`a{u3^I0^S+mD*3ck5v9610JD zZ|^HP2~I;NC-H6jN3oufVC@;6Yh1{H{hx?T*zgd}%_nNtH=xL>(--G(`&1;e?-uFj zFK!;55{XwsLtB-U{JwsC=F}C0qC_P}Sv6L_4d*a^DmwnT7y``UzknEh8rHY_f#0u{ zn~Q~E#Pw=fYbB>P(qZD@0bD65=?3jKmlUw2IDRG0@@SLPiw$4+*=juU1p9$m!EXcb zv-AM4I^+ZR!!}0v@-C^Ld|IE5rVQydUMO!Ea>0Znae#k8#MwsYcHU!M1O_e}$vZmq z5B)?n%Dnm!0zzK|DOWN~-fT(krSwj@H!E>RniM|bP{`EWyJD?kI@NQlqDjj~!6KGU z3VgSVg7bY33rOlQg`e4HzMjkd8#-E)arQ?LRrwvEhBHAJA%P%G+u4t7fotn+f6c7k zM^$_04yd65Q^}y7=H|EF!9OpcvPke@O024>*$>zc$H+O)Xv4L4PW?Ovul}z4nDqnH zE>ro?6x~^OnZ4JXP*==uRWF4#7$Jk)n+UL>uv|NbB% z_3rB(2}`+W*vDk1U?L_i{(zRr(Idn3EpDejKkYiR*$ANGW15h|xSw1_-dETxEr%eus+} z0j?veZsstWGhFZ2p3hiYohI}ZN8Ne7+B25QPvgPtFu}X530fe3C>Y5DsuHH*?(Lm@ z@uJ$1cZS*ypGQV2G4b|=0cI{Ewb;?XAm(&&p-arTxe^Pdm1ouXmGCp81$1WIk)wyJ z6JpmIpAU(eJRY(~#&7#u5H30l*jEWL>Vm$zd&z0X1ayZgL{i77=K}h32r_dfgVfH0 z13r#*fz3c9EP_qw2Z&vuncRfTNCEP6+o12d^NBDjjdpCugRkNa0lQ?_3h1W9qR`F0NfUXC?&w*-xp}Q)k*;X=z!OeSY;G8B zJ#xgYwzhVY=TKPZeX{Wl-DGKgmt40Pxw&3S!<1=ALv)kR?Y(;29oHMwC(opLW}DN)>ikq!*nZg1IvY9|iHKJ47R`_)bFHNQ5K$y(j7M3D7Ok97nBLvQVRl=(!! zE?CdeU_h4VwibjH3@9)^&nTiRRglkUG>*8{Kubqg@-RpwEH6KQPlaK+oYtqk9FZve z+)sUnLH-9O!y{P*v3It&55EPnE81>5Wtm?R?VPSc!cp&N2YQAivDZb9@>|bpE zqoePMLS`nd;l4T=4;mqEa~qqJQzKg4ld!|6gj^Y5baF>yWz+lo+RdBaz#i7y?=!bL z*99!yCkGZ%6d$tw32?HI}wym0us?izb>_r&>+RjQa~UFMA(@tz63U<4rV+kx?ekO|U^IVxb8PBqN$ zXL_cyr3B#utAdzf(uiyT5CU|jd4G=my@wwlTnX(Eo z!*-0@pEz6{Er|FaZD!Ev>dqnOyTn#`F1$757 z%X9*qNgLx^aS%94D)>vtvt@5Rsz0EL4Jdp}CQ%P)cg8quc=gm(RvxHL-xc_v8HEC- zc`BXLDnK^0@={c0_dn2^bNv z!$p%yii-hZJ_-DU4t8#%e(v^wfZAUIFnmvGs=n0Q!MXoRI1W)%C44{SOXi>X+3Wv% zWn@cm3#|HAQ7$K5CRD3y`KQeb;w2MxXlZhMv&eU2DL z5ph+n$&1Ds?frvzNVV0rokM1B6LoO#Z$Kw<3JRv4M_Ak|=d9`EPp!>7u-0Qei%{Dy zsgjo~aMvG9w_{H4^P1v-;8ouk%LJO!iFsG}j1d3MtkIJWYy9x=a(2YGNkP()XMzv> z8fAaqDd9~wqT3E{Bk4ChR{Je2uS|Nvz^sqPYuB!)Lk1_1Bnr`97|C=!7qYaJ!^;L& zN!U1Tztf=NaYeUu`D?QM`I`9+v{sGRtP@h%58RC*Az~hI=D<;bXCxZ-_$u0GQ8nm} zAKkjPZ-cj|XS4h|&SHjKL}wyK{*)5J)$u};j0bz~-e)P&mUDfDKkPr$usHlMyiUsK zG3VV1xf{@5gh7FqK||+g>G)#ZhfkkmmpdWYZxCkbU(c%@pzQK&N7AGB2qlw+BmB{$ z-JbFLwMbz<6`;i@R>{CO&~Z*Ak}zy%aaElaovM7)GQryWiu| zY3Ip!>?QYbL_a1MAz*Bi&Tu|5C~Wv!FTZn1fbjM; zRa$3Fb+y1$tOjSP^hw5>U0)_ByEmDfm1@5wT+-TAEPMtMyUdFh4Nv^mcJxf-`$RX! zQhPo9+UrWgQC?~4828K6u~b6b(SApdCQ3L5)JrSuJ+lzOrqXHX)uVRu4LVcw+*~ou zVD~{d;8G9j5+lqBWfvnO((w>MqqNCO=3Xl1Zb!MKF^Vy1XW(qU>lXxV6uuM|;Vm9) z^i223Fe_C&L|`XUe%>KdqH49#&Yg^AzH$kePVblDqD0g&?eM;<8_YdI15C}&F zF~ORhUBhpjv^OX3kfXy_e~k9>HMoxB4EtER3V_5Gd*& zAIeLIitWi6t^pa9xpEOucrQU65|)4i2S7o&qm;Dto}06cr#R3Y@LU2^Z`1B6(_k{?b=+$3u{QZTC;BNE1x*F%AFW)f@+!oX|Z^VuIGqxyxoVpPo2_LIA!(MCUetiR~sgJwWBV79DIbs3N&lgLJF|N^hrQ324g>2F{ zaR~`G*=-o&2atI^7sfk(_;$fk{XH1gR6&U?BFUbsjPB$zUt_M$&dz=+FeUlHI@cq{ zN}qYG(%g4E?Sihek}{)}wHRy8qp=qz1H=pEE#h{NvKfv`WEkF};nrCdx_n414o$b$)p&`o>K zA^T8m2vM7p~Fjz!t3kMG`nt^576&Y!Cez(HkYPyL{&#Q2gg$5J)K0 zqJl_S&)aK#G*^QR8w)%c6owNgPX?p#z`=oN78JGsyWC|d`?Fp!g#)k~i`jS|$%lua z0BU!__}AE|sD>*k(kUG@^lU|!u3e??nAnQC_hYT+$m!2>oV!?$oJyl?GKnjJS_2un z)72Ocfp-LK2wDbZ!5`Jut;i$5iqM`nB(z~;LH<1}khqqXcaZv?!t@9_L5nLMF|I?b z`yt{egOhJf;PgY)FKQU91|Su^<9aSY2jd#~q1R*`BxPe^EX%d^;z@a&EMaGYjd>fM z@&aIqFsh&2@S0I4Ffpk2J+=+lXK}c`oAw7-XQZ!hdPghQ7=+dW&PF8-CkAL+enDb_ zaYhf{&mx8mR9@+^P_!)25f?HWX=yD-%|dNG>#qh(NFlpaA7NRDpUppJQfDVw_w>O( zYhT`^5LuNwcj$J1iFwh}-yd!h?Qg^^FuuDD1uRl_kcdN~;A&qU3q$U;r>RM!4P z#1KvdL&Mmo2R{soZhF#4=V2~L)6t!$ka>+(rX-QB=Z){NB?`kS%&$PnRbn}JHA^WP ztrjTL1GRoTJqs#8g%lMLvJeR68rvdS$kNi2xRt~(mzY??wVmDF%^Gf}A0hXB~F z#PdZ?kR5myZ6`~V=b2My4jIKtDn8D0qU^ONeNxzCY@CCcWfX$S%h~mZ%5xBOIa;?- zozX-p1@7->KnAAI@KMl@5c)=I{tRYlPOR5S|AN{NFw$@QWvM!X;5uK35#deDCD}7g z=&Nn+LW2Bm#Z3_k|LjF)#|rXHR!Z`+2MqaI>e`Bo#;f*2RR+XzvQ1em$D;`UcJu z@tYwvBLc-HClP}Ij@R*+LD05rF!x_xzXo9dMHC87x9#z3F(CyWp@|7RJ1~manwdF{ zL>&gE2)r9Gd*HUZ($Z2)*hZ=V%{Jv6yW)FK=l))A5&a6z`g7~Tnnsc2!nS4`)Nlw+ z+P~k^L;r-@0gT1PkD?iHcW)F>>V2SjR7k<84S+cQ3}IV!Jf4BO4pX!&pp(F$%!CrL!c0R#uP;H-0zY_$)P%VR?n^b%-Tx_<5 zmiUvRW$H1c^&A5DmX&~z*gt!Ip7oMMQpr?l_(FCcl&49?r;^*6e@^=df zQBm<~@BZL&d4$l({}1}IEI+@gD4qC_B}ga(Qn8$l1Bv$S{MmH7$3iJUH1LjOLJ^4q z$n9m@A1?9fT%xa^pWl%q*r16+_}+#@y_Z2hJ;M^rrBLhJPt;I_XsR2o41Z!&J#zAY zCok88X47N|*1J;GW1j56Lx*BWLw8Rc!IbU4em6Hf;Z86kVI=~z1*&8rm6Ez>Z3IKz zOaC!e!C&AdF?EtI5UUT+#cxD5QHZFpFN0MyM79z!nRkDD+uIqm0w8xSFvCV8_!pkv z%x^{aN5St9A$-4Fkruo3$ve1d6a=gWa+mAVH8!Oist-Ei`9(JGa^iucm{`+`$B*Ma zyhSiP2qI!eUUxPU(2!tby>TTK%Nuz)2pp`|_Lx+;0t{OYw4XMn1 z1iM)%3H!6+<$T27pdRoAdCW_XN*k5YyqYp9X^gMOMhxB!33^}PJTX6XxcI(3I1(HZ zULGEOvlL*PzhmO%*P5|^#aC{87D<0ohO@U5M;+fc(>I5|qnHGUC%i3i96E&2QF(|e zAOpD}Mx|D+MzTjLix>ZP;Q^R;{Ao<8N0MnJq~Q z_ct}+{vo}|7J~s;e!4X~P1tXcdGIma>LJF!yn3}J63x^pB*FFDLK=2;A9{S)|Au?aJ2BP*UO|a|sGABAp03 zo6SHZ#DLi_*Z~0PAAF<6m~N`xbtXJrh_iFcfAF(R2Fx-#Ng<4t7q>R=3%SA0BXUJp zQDn93C0udHLtKXwT36VX?)3GYM#6*-@0aa4ksu-9J>nwNK&-z}!b1Uw6H6N|@cT1Z z!FV`6oNxj}PRZ?=+O1}SrI+PnD0%SiXJ#_3*A^;)kjGS1A*_%`RK}PVL($hXisEbh z_(rmN1{6=2VP?GW6e4V}Hk7lSZ#gz9D04Bbq__f8J!E7IMM$`0;PIilC!+BqKn1I* zVHy<&i8L}kJ_wi}OaK})gbruc)M$zzOY479m~j^0qM+1PtF=9FU>DEX($^n8Y(Xq? zSc2hNRit>|MmQv7YoR10^==JXTnMRBFs=+ZAb<&^#LPy7OHW{BUM(xb$Ac`;E4iy* z1<5^#fuXcLek?B|6KfbyWbf%I#KRNO1fV6N&Nc-lABa_4d$BMdiW0cVF2zS`&~LJ` zUfPC&qW4PiDFgNur$-PI0HztTGNejEfQVe!w(f4BDRHL!z7!`5H@6SOC=Ut+N#XB4 ze25|q)dl}X!WV>Ct0*w}*B;w4=A(i!s}PhkIgV#tmnmKcD~m5|?;;jzd~X3SU;B zyYl<&rvM^M>?IZ!@7}x_&y3CU*u+7C0)0Ywxe*+im_*B zq44_6!t2k*u}beiXdQeG4psi3k^qn*C==UnYHF57@PWy~Os?0DZtNEwx#8;Xf9t{p z0m?Y41BBN=CjXJMMzu&%e)o>IpovXpYgaLa)D*e4CR4)I>_2QcJfn#c!^laO&9AXONzkDd8xItH>r z1?#(LJ_1iQA}3z=%itgGV(ceyM9JV?tS{!Wl@Fz6K3(~rB($}_11>C^RLsD_u?SYp zH;sm@gqRd8MF`e}RX<=TA(5V*xdy+!Ife~2BoWpb=&M;K0DT+grh=`U&_!(oEgtm# zqqe_)3_!ohw^O9rSWYzzg*yhxuq-3`TSS$n;uJWS4Uw5mNzr3H9*XIx+?tJm~TMh!r9wpZ9j*iv-)2|m6{FT3a z#i9aW2W7`Q@C})V%KVyoI74Bd%G@MZY}Cpa*K`Nv*eA!_+xuwVw$QA6TxI`O z4y`-1?2_9QE&#(M0;U6}n+f&@6q|cR9x3?7Cyuqq)dQ4XvZit6d$b8KOx}6AgDNw< zb-whyMgm8v@%lF1j~V&VH*X$CNo~=KvJ=ZSVJQttz zptVk&x@Ruc%#H}OMV#J9$l?-3m@E*?*kzg*?3Z{WX7ZtLRUU(hl*xh}G$n34JN}ag zr!l2i`Hp5i&0&UIoFXuGHrbXVoWGS?y~*Q&b{7)Z(ZD3v6(CE_020}l-u36(i3%U2 z7#iTkNeGT$yGB~*m9JbzM?ub~1IcmgB8MgGJENS2riS16Xy`UX#9CH4L8Ft}pWAM{&g;24Liky{WOtbqnISc_ddm`oJutabDLMYy5 zr}JKP&_1~rfBy1iU2)+iTGw0R&x}2^9rTPqY{J~2ww zf6ak1<4qU1gfGk3Z+oudIdp|+qXZ7uVeg(2y2MBls^=psKPZth5?tc!edz#B{>^(|^$hph^U56%GRg z&SSM#nWY-9Hw0qL#`bRZJ0O>ni1UdZ&V%pnABL7OTXq}+uyK0f2arw(}D*<~d{g2r$}F8fiooc)>1FQUb> zV8;yaN`6J>d#3Zlf6?e$zbNfXl9BuxV%!VrI}JWQ(J&lx$yr%JFh{Fhgv~=07Y^S8 zVjQG#LYw^Y#ci|6xCs5d}zx(uwoc_BX0Nw5$`^3*SHXPl5_T0HwSXGk8 zP(j3<>LO8o+@x&teNB5TK#SqtkBL&J-Qrsxv_dZeZVEj@yU$VV!o7_S=>{={DPW;?c?(hoj;4scW%gX zn2gL!g#duZ`yHmq9{)J#3n#6D#B*5Bva;?YWo6MDk*1lw$x_MPg>Dln?v1&jdua{2 zxq43*JE* ztq5L{X2Xv2!8S4eCPPz1OMAN;lpKBAN|?O9iG^LS{YH#q^=BJGo!#6VzVAv!Ijo6< zChYFZ=g$o$Sd6}G6rII~qKW)|1yfyUFwP=#*C=>y9c|IX1Rko=w~w8mUxywpEaB26 zp}kk58bW)pBcKKtuj`E?VM-PHwPlUpx|00HKNtLAx;za%6EibX9+Yhn^UZhd|6%XV zqp^JVzG0;#O%i1)q0ALRC_~0F&vRtVkVKRuL&%VlDN~up3yBD&DD$jLi3XX;Po|2< z`#H7m`+4?#KhIjv`@U{wnl2Yxv7@v19je}Vn zwNsahz<&C(98C0w#q07-;P}L`1MUb2f{;TTFdoF64}FJUa=iXCHCN33caL9yBb(sZ z9i>EQB3OE5{afzD?eY}5PjKoxxQilAcXzrHoVxAt{N}^EWw2`9%NlxnW9o+{#NU|k zrkmuvMS3l2pbz8hxWs^s8!$Fdrb=T(}vX<%%&ld36B{(AtQ_fk&%(I7g>ZG7&d|c0A=FH z_8Wi=F~{QrJJvrqHP=NUr#AslxTZ&z9(kk|>z3=b0EQBxwGZlLAdj0w|?oxb9d;6|!K=(3pbDLG1 zPY7S+eRee4j@z^(%o|f5qaMdVOF+e`#1@XgqgI8j)=%x?#qY&mF8*Y5aFm8`v$o2X z%!o#cx{!N@yfKN1kEJ|-EWan;?DSq<>d$hD$<^E28Dt&`yLQI{V?`*mRWx4}tzTMN z>Nc&yoFCuh*>>yEg7KN+yN99KaVj>JmephPfbfD9DaW;8c|OUr9LC7pWgA`YyK8i8 zY-qLuD*x_#N+u@EUdAvvUOm-8{@}?0!Zr!15KN!+G`WDTk&g8BKpS>w$F1YvunzdmXY^mp=HZL~p~SLjFvP%!XlLKVANp(S0&O z^+T8(Y1Zpl^E-$+K#iqHpz!5Ogk%ZKk_?+Uj~@rOh!j`+(FD!?msu18`*e3v1*F1L zjnfKqa0FLet-g`{z;XPjeh5~smG-rjcI0KRZ zqRT%*{;Zphr7V~?5jUkMBIMUihND-C%F{Jph$R%B5>$h8Q(Zj_OA&#!FnK2yRloXx zBLSXDm-33j!nd8B$4{MlcuIcq#8`z{7_WH%rl*-_l8`P!UZMI^ySlH$K_4gAwqq4OSx#$-0wf+vEd5~?L>|R zwAj0MzaE>fwQx2!XAP^bKFR`mx9kTG7Z)_cw3M6J!imHH=ABz!s33LU=$p!JrdZz3 zIdL=ncy#5P?QQaF8A^Af%JpXYa^=uqbIFK1Lqix zd<4VH6$8LlST}T$5>+qWm0$Fy9>3yn7={)oD=1U2tqo`fV;4J40{w0;L7k7mBzI;b zxe%{EyR{XX4;1Qn;L_)x5iLN4yC&aW?x(}9@g9Xoekb#Z~(v|jn;?&%@z@s8f!QnWva z{H09tpGRf;&O|qi8WTrf>-D3-!O$Xv7(iVmOL-SEM+i-TCDoM1DV&2&{`(~ST<>AT zERrqOe09|-I9>D3zE*<+eFvqaym2t&&O5CUyUjwL5W0zD8UNBvOtbB|(V%_w0a9DV52DOo{xfp{DEnv<8O^KqP_w+9w*nH1_5#LmE(pJwsc zGb=Nr#!Ma}Mmq;|P;?}iUj&Fi!#CqcMv6d4 zIx@ouQT%>UK8zR7K?aFL^}-h)$YpYm-*{ibt#3a`Hhw|cX^nM-d<^eI?}dc0{f;tw z>Cyd7*#kjICo6sm!T+kP7b?RRo@cf$lfX#F4v%UGY|b!8HSVswn9GZaS(}qCO$-gO zho89|_B=bgfh!IN?~tbS(U{!lp;~vIM}**nlpE?)~C;@3K1ztmopbsGw*W z(NW``=sqM#H1X*>G*pLh&U+Me4j!M?Ob~=A>HPgZFy+P+p4coy2^ZeiNRn2G7#9CTuI>by)FCH^*$A1rEcm-}@fb4YMxmQS z8>)k%wa?}7(gX`t($LeNQ4=<&e(;Ux)-HbmZ1&c}KnX1e>$ZgrmI4rtY#&GCbNtr_ zR1@cq4}bgi5PGScJ9u`DUwSN}2Zdzf?#*&c+5y4Zz03nz73zhxJDkR_6(KfC*Soe& zjS?|4Qo>K)AV2>42wjnyAGZMwANwhf1xlvV(3zArdw&1o>sz1r1pG~~Zx)Na3x-3T zI)j0-(Gd};ecfkORBB3WyuB+Ycm9({;sw>ZO~29LFsdEyh808wijq)3zYjKC)Ccg1 zSajyLmXN`DK;RvuDK zdmoRc6^PQ%Zf(#D5QmgJ%lwxVga*VYq#%vw{kf$LpLO~B*+wyTZhKI~-4o`u^+}XU z=ZORSp$6pyaFk{0F>zS<2o!_FIP1P%-`Db!e0>=hT=4aAj0Tq{(lENOrc-X)c4I2P zG*)S2a!B01&dA77;NWP@%ye|DEG;7+JyP9yDCPG5fo0Yzi`&xdu?82QafFTBflz`- z-%$|(^oAV0iW;RHodcqmrKgz(2sjGuz>bQ~7{#8I=z$rJDj3EY@CLI3MOOA3((q{` zZCet0gW=E6-5a*88(-*8Tw)GT0RjCPIUZ2Ol$l&YE*L<6Br-tQfhmemC1z#lbSodk|*_oSy;Ve(MoILBS_Q z{|j{pwp`M+on^ax2cKBQ5Mr#AU$g6p{J#D^VJ0bjolRx5@b5dP7Myr7`a zP-aO_QA4woCZfR+)5u?Mx(ngmfMy%>YA`puD1LKfLPB$1FZ+#K*8VWbmp*$&!|u>9 z%gvFNm30B~5+VUvaj*}nS0XV7nuD=fcPMVHQq7{F5y77+OtamXBsKkYCKnZagl_`X ziSu^UrQJMC{u+*s)2On#nR&7gLq8QRTD5LYuGP8nz-xl*=ur;cvUtT!*l^g6v9`xQ{(&h>N4W*Bj9z()ft9;SwS0%#;&OjG6goI7 z^;b)tJkdBvZM&DthhubRjgV@%#~t&{F`bAzenCrH``EeX>CdW^;cC{=0S-QhfX+vC*+U#Z+BaZ{l$x@=BD7+DwcG^o<``g>`Y{kHVLnvk_f9g^^Z->lvb7l%gY|h zCn*b(lYR2W`5(Zk0TYhtOAp;Euf76P2l`iHvyH4e;yFnRw!cSv(zS9jc^KPpgk$WW ziLP!y?>sfOkXIm95sUKeMIJ@KCgj!+-L!#qAWov^kk}d5YvB+O{{Xw;%isUJfCkmRFuKtS>abs&A{NR!nuu*)Jfm*mR>sAUMgHVX z@6TjTFzupO$a|=jLzo_jP^e5z9C*k|K`UbQ7?YI+%I1&VxM~MQ5{mqn*JctYYayp5 zW|1PlI=JT+d56DW7JDlam)ij!0D6Y}3QIZGZ4=bxXdls9L!5z3C@hlDi{@=Zv(SG* zKsVxYU0Zw4r#2^PbT4vjZ|}3p;`o3fzk5ZJAyD`AMh{Gr{qgfBEKa~z(LzB`VxOtH zk1vOpNffi;e*F>^6C;wJ%C9IoSZ4-nZbcaFUzfL)rGqlpeiieeL#-L_yNdC^86Bd* z$<7nqL@2?#x(wzRUZI6NEh?mZcVe@0AMMl|>a9=0RrZ`X5F7B{R3aO1G$)<|^n#h; zT(ms2R49ZWwvvfFiTWQFZnD?6Jbej)!upH<|F+Tlf2*GOf9EB4w^_kpfYRJt-gW8= zMWRjURxC?zYD~zKBu8vtwp#R=g zctgv8vxG7Q8#9T-12rR{b-)QI@B?HJcISas2wio#$-SAe`K3q>Rp4B=z;PzE&tNv= zz9D+1@>47@F`QkHiFO1 z`P5S80(I)4Lx)0{PPBD*!<#Vh;#vWg4bnt8BEwyfPn6Tlr72=Tdh$qE;cTo-Dv)Q? zA=EMmj(~tC{sc%&6i*CLr(OvxqN2vep-#EhbxW`n1)rOdzgVaCwiZvy#%apzxi2Yq=@>3;@V^4Dlw^vXG4E-LQf# zQ9wX|G6h%TuW;itAl$`1pk_p}AtXA`*MQg~1anZsXD;7H@BuzLRHAU6*(z*htr?m% zy)j*ad38BkQ40JIw{eGO6W1&w<>sZ1mT<(EAcrB_=4C;Flbl=);Lu8VRMXg;4l11O zmo8zZw%oQmU`C7U11)Ws6=3Rr(YvtE|2eBW-KWupF%+ery^I%m<#bCbc2uBhXJu43!4MKI>iq`Um#e3@tk(G|V`=xKQofiKK(G%E~CixMYag)L4JN zT1Dki1iWyYdSEkx@A49ZT2VyvWn%;Q3(Gn=A*2OCf~eCB&Ye3FtuztTOP$>qsCEyw zYg`Uc!e6{`1{xbPJqUjE=$wkmb}+kJkqd2q>5|AHItW_`BUQu-#LZn^!g|DW=*30L zMpgUzeX6SJY{Nd7z|V&8!~cgvP!x|IVyyE_Uovu1uPW+_GVjE@kt{I#&ha8J1$4}| zO=i0;UbyQ^lld?ks0lnS2mR3{BM0DdoHUvteEY#`7y%g?Zjzivq?tfJ6vROHO%r43 zVAM4?xw9SN#1JSYVpNh$Lv1aQ22F_5CfWZN-rK8~$N1m9w@wCZ;VMaz`vbAX#V01- zleiA@4H}<)d>#BHR6_>K~67YR!n6by`Z?{3?eh(UUaD7;G>auF0C)($S3dGFp# z@%9`FYxYdKJytsu!u%Q3qgXpyHpjmsPCJ8It^Z^y*)7lENyIjOl!xcd8e##u6A-EV zUyZe_|NNV=cEbq|N&s!58UU){D=qqj@r5%`gK&_$L0{vp6ER(UieTn8rvGK;NJBN) zv!N^1=AxxUcy00nY8g3bO+johOce^>7z|1k(B0NqwUSd`3ePFQ&WihANqhoyNU7fhIZm5<@^=) z4xJm5D1vLA5(5#9Dr50n&5x><+)>I9Jb5x<qleL4k*BcCW z?vsa6)R%lq@t>M9mk3c1ZMM46um(;T1v)Y=O}&1f$2uPV_q$U@We}CqlMwkbFGL&K zJv+Ty#!8mwTcF=-WijVpumtz~8UrM*`d;8Xx{4f93YB>Ivf1_HA zqL16_uR%Cl_dP2vKHuwDa(34n6gefPoYfCO5TLk-KLMu}W+{B7n{?m2%?4Ytf$O?3 z&Hm0mXH^xJHkb* zZTGTO3+Vk?kcXcANWPhz3NI&IjNpCply#wi#{lKb&*6>31zRkS(4CI)Z;jv*FHfej zwj-XMJd54Od7dB4r`A;uC5pJ{0;tHQ;+0iEDtIAgYRjfg_or%{>OX&8tKKDrhEAt{ zE%0!0ru?4&+0(k&?weR=`sRa?jjkmWXN*;KDcQm)OW%yREI}1mEE&{$g54jsV$;qr zbK{EbO^OaU2iR5;iMih&Y7e@mt1`p~1W7*kZzplZ>Z%QB%TRLDQd#QOew*v{^L?PS z=jovkwWIVK|9<4q^Z3XLr$v%4Ub@sH>>5Ii2p*6|?jJdwm!v5Hm_R1|?aKk&a9UcF zQjpan+yxQ5TKf9+m%h1Gjm?98-n)PQ^w`*mFVEGVVMZJ!jy}|JQ_t^yJCZ5RR2|{2 z%E9t={>scJiO!32vWg#~QVfF(ZaHf5=RSn+Nfd_Yo0efcg(^#(HGILTk%W%iXXN-V zaUO^oMLYWYbJx^d_#Ybi*+6gy@xif*?;Ec&VBpABbRp0;N_l(9%2wluhQ2o|E7khp zU&@8_NdCM67|>hf?k5bYXX^Qnnrb%%wzS873px@1E|X$ariOxpdb3~CSsiO>278OR zxvb#zhnKjM%@@AA=`@J`^tm!SOwk(tzhGG`0+SHaixJYChYnrrE6PCOJyGUhUK6w% z+fcPCW~DFVAwy6qfdY+Pe>5gb3kU}6j*e%0*T7idz7!P7^O%QQ>mshSTR_ez}gQ|j<89nlopUren zb71Tz?Bx)S?R7Y895Z(@c>V^62dgmdV7ad-zvVm^&8@BFZOCzQS+V+M4(CN6$W%aU zReNv2#E9&@cu47mT1jMe8IF_}Y1x)zBSBZ*#8)FLS6T=1qyXl=Wk?I!liH_Wy|rSneXIfR(K7dwb2v zL4_1GAL&yy*pWtZRLF(_MF!z@a-p}Y%G_0tAq49maL_}SQ8oEF^=!7b>-1G)wb-R6 z|GLZtI$)a5$MNV0j;Qa64`$1K6Z(NNR_!QpJsz}wnZgiDR2e?x1d#sI2e;x3Fylcm zj*(N~GXTofenl-5K5d}`EHnL;4pU{8$d@dZ?wc76c4Q=w+Yyn6Rc^!O$W%_u?&^L2 zEGg+T%6y%Ij@<=%Eo@0BhX$)4$ttw-kG4 zoKgca!pZ%b3xYd$lTgB=RdB}VtN%s(qrsu(vt&eWbB#sdGh~fy?CgE+ zVz_fY44!u;b`w1Y#JguzRS`~xdJY8$b~aK$fgmd$I}nP zlSKqcf?1n^gsli|WkyCV)ZAQL4gLMbi)|ZXvIT?w53qOlf^_6c&C%|koqV$}hqkB< zqHkclcc?*EVIJHI*9k57>0iFQ32ChXpU4lZ#tkVPj@zwE(oKSFy<#LZ#{+kaT(q}m zBi-7yLeq>G>HC091Iq;#cmgMkdWGM=xR;3t}g{Q-(@?r5bH4f@@? zQ!c!wM+>KdcnTzI%GjcM2gFxr&yI_G{-9q`+AZqmo=bBGnk&J~RamePbnC$VFFcko zF+AQ!OY1q`dII7yafBedxUhLql4$AZZsO1E_hA|u0btLI|6qN+&rWX*CFeX8&>Io8HM($=znrDE+?^^w3U z?MFV}P*34%Laq&flO}H%8!oxI39s^mCoa9VMO-+hHJ2kE3H#KA3nwt!v~D9hKzzuP z*XPn*Qrl{CL(VphK`;xr5`9-XR};iHh|X&AhMEDTijDtSk9YaS+^eLFHqP+G-@58! zspI>`q9aqYz5mQ7VS`3Hn8wwFltxWma2^=}HeMj_Uo4s^cr_$Sy&@e{tP= zXmpTT4w?>mdG2HPqoXrO`$8lYPoDtXvjDX}5gz1AMdsrhYu$Ow$irh9Q=Q!=-W{$R z@Dz;W%30XU7#&+oKH!c%$E*bqFvpe33JMCcvu$x4LeyQ^ zP~v*jR4?kwk8u5}zq z=TbTvGxLeM{pNpY0Y1L?32-g+>^Zdmgzg9i#L9vK^}<8t&m~6+ZV&Ff%i;Pb3m*a) z2!}iqe*j1$RI1#!t=T88)4JXd4?i6iYO-!2sBRS5K<0BOxw1Av7+V}@RjAp@P5$8h zp;8!8dq1haor(%+q!@FFqNt+c;VcMk6yf#tM0Ji{3xAY*GD-R%W|U&YPcjz?J85xo z*RSK**=#hy0Nj|FnUQdV(QgR!7PezbGoB?`M9jer0fR1}3alJ}6Cn!16dA^LQ-(*} zB!joRig&p3QmI}x7Ry=7=fN97umk)WSgETfGrH;n#A&(%-J|_nn(CI$5fdI=SAdm#yLB0U8h<}MyAqSU2Tb0mh^`-PBD)kKgGhd^WH|XDrxJ-k0v(Y@9}%E zQn6mK(4iVbhobRk3dw*($o`rq23}|*i^3<3jEvuhRbvBLM*tL15?ohhWZvNV5=s!< z7=!|1pa+)0E+&ysQ{ck%VGXza)_*1?3@i5@k>`bo;+(hFKq z?@#VWv19JX4|EoWVH+&m z>4W1_Q_bz|#1n#!NLO)d=IyqC-jUB? zap+U|6+rb89F4okV!5#!5_@JPUl!LS>I)1gJNn_rWi>8Zh@%@J!v53!=8Xj?TF}54 zYgmdB%5J`nnvQM}=>Z0ieHsDuX^&mn;Num?p#g&AX>qZuv$J{n77B{dk&zrDobe%r zRP2|`DWT%Ja>eox>{RHpFPu4gBb>L1VLS|MCwuFZ*?u@u!KOwZ?Fbm8?q9=kH2M?{q{3h z7ZJ3&&(GpQMuagJ;}n6P3Rp0VHl`yCWL$eFcyQobu{qeD)^;0Wz+p;~h6!4+dKKGq z74jXewr%^t{RZ*{NGunCG|-DFlN+PPML>jsL9B}fLRJet9NW$!`Ec<{6HpzzeQ4r- zvW}=m4$q34zn`gaSRV3lcjtdD#e;mrrXp|OPZXH4mx>w*- z=I^M-;ne<6tP^Ae0=LY}*0AHwI#Sc_+OpRvsD%gzo}Z6L^R4tcCz6weuAp;Dqi~2&I3$e1?P(8Fb9dCPqf~ z#e5Q5!S6#NifGx3lcCu);{SX{r52jBhpZ!{@m014&zsvg4h02-gmk*IJj2fj0eKUY zIC#)UWw<-WmW=F65Bi(m=WI~pDKu>TPUT>E7v#jy*e0@Ki>9qC;4zUoV5h(~rExAV zB}fKC9mFWu94c2(;oHT?hX7Q<2i&Dia*{82Q>`p88$pgPliBjtcSleWJy<#A#eoG*wonA1-vXRky+XY*A^l( zKsipWr3jPj8s#^2N}~`#o>b+XyD%W&26cPO&_ODJEiy;v1CY9o4h&2nO@Dbt@!W*h z)=NXhO_K5XCeaHWx4y0%LLW2#{X63F@m(=c4LQ|lJ$Cj@nr=B&={xCt32Ysl`H*ts z=!Kvion>c0+|}L3JAxc-+vA@ zKUUFCd@u>G6$7!G@P!VSCZkM&pfkwrH{8v5(|uHNBWoB)H_>CI$3;s}VwkNP>J35j zED=Tln~dvw4o8q^06j7K!%DpdHw0oCRGGD*AG+*rSe@PIdl0-BH0SVnqQMWXY_clC z1Awmmf{jhYz5%FHBAh(8QBe`)QO`|?*#G%lnIvFBBd@vcs*eNji{U%$Y;5qxGkBxo zdxfMXz)$Of13%Kmfilh61FwPH&gz5t8oAAa5Y1YIjTx3&K4cUI_k{GnfN&yV1}0;y z;7UlSn)IVF8v!oIV7HSd(OGhA*C%tbz77px*J_-p1}*c~Ys$BjTz9r`O54s(Jc?7F zPT>l^=CF4RHk|PiiwhT^-^jA3-TMKE!ExlTDttxK7oY$LMs2XOW2ghG>}{?!gsL4! zZpe$7S5rR={c@XyIinv&&d+{%?H8)P7X>Lm2i=m2!Ak~Bs2%C9A1p|vm6rfh*0gUJ z=n}KI>zVGJg=1Wgk1DMem6SXZuvDtvb02%J|< z!DzHG^h4|i9p$FH=`vcF)){gQ3=I*se0=W;AsJ>rfQif8s)#cUF2jF~VC|co7Zbhgasv z+>BAmApPN?ri@zS*?XtaI@B-?a)ZVJadGi`EK*)@l@80&m2ckJdH$uFa!h4Fn7Ovd2W_-_0G9=rCbAr{<$uxu@7t~n>ufDLPJ2mD+XBqWD*a>4n{c} zQ=VwZY>08f9PLUWslY3Ux$0lP?qpu)3hbMiO&>4j4KpW(fpUnv5@M6gv^TiKGb*^& zVkAUS@e&VNe{`?mVh0|$0FOMDReZ}>setv#zhmRb&TamY&Q3#^Mhi==fbYwMkFsNeZ zo<>eI=2#Z^_i6;5D zo`np@P91|lQ*#}57n0)K4K7QDo{;Q8{$tQY#&?nD=sd@qzS;t?tQI>~5d&bT9~KmJ za1RuPLX9bcC=+)uiP*Z-cTYZMW@37QLG?u?w;9nB5`5m;a#OME$s#ITI}|{g!k!{9 zI%1ley@Ep>c9Q$b2)&PY+m`2h$;O6*y%zl@umYo2a$=_fc%(Z&vRD(z2zeY|&rj3P zs<7(0hxk9*>Jk~c93VzH zo1cNP1jD#XYjWfIC3{Ho<^FD}km^WV@UvD4T*Ce`gSa)i5*hs8hbc%QiDMk{nurV4 z5;kM;TXx>epu98GIM^;uRKxsc*#*}h=Up`>rl#1Lo(MiLpAPp1@3#L+jtpX*Tz<7N z+JrI+ho}HFVB@_6pns=t6L4*H5tq(L9UjoYaXSn8A#eb<``Xb)<(9J*cL>sy@{Yaa z3W4$v+s-GTBiI%iD?{Yi>f{5rALpX;&4tbE`dv7v;YQI=D=aQHDY2)U`jRk-8G6>J z!9P6CApg_FrR%qa$2)!G$tlEKfE!diids58G7^&~`w&*q^C}F>85n!TGluhDp1dQa zp1sc4inUMAjZ9&{<;h$;Cr`dWqV4AqF>pO{Ka7NGM&i3>P74e!+2WdoI8%k>Mk2u^ z>7xF?F#sCS#M;vZFE%Hi&{!=@Ou#~YyE1k6HbqN*&9Dly-P=w{K~qkCk6r;AIk*Uj z*W<@}uRaMpU}c#BbW_3@o%-a-cWl0}BofW|;v$m57*DzLTQZIE zZSyb$iwcJUV92Im@W{gl=I7=bjB`A2gdP5<-!^ ze|OQb2dQ1iBSAP5-~;lF8YQojPgBJ4OAG|S6 z!n}ELq@rC|ulRW^#&>JZ0da;+$R`Oh<8uq@cbyRC- z^KowOV9&;wgoGEcxz?7!oC;z#+NuOc&>UJZv|4SoZRQ!>d(S0`kC|*iO^?eGT7yok zbCm{b2Qm!FtKSSpDxqrxEH}x2v6|p>1qD%}VuQ!21nQ*4=q2{B=o6Qcn@dJ%qX%@x z(q@$po;Yz0PMw8z1gT&ia_DAaiXysWE-yz12kk$(cE?OUcxf6U`(WuG6OKq^e8W?R z%Oox)24?c!MK$Cci((zX=65>sW$X$CDe)5VFkvDk+Y|*ZJ}f^dz3{w&f+c*BrWbSu z`}5_hFV5c&Ca3GMV~HlGLpiFzbn-cqGgSF5$zM?w4i9&AbVzGPNgq7F{g=h`dLcP=K0HH5Xz({8 z;-Y>JVX6(Reo|aqL2sooJ|0vHFH1NMg1QqXShOGn&tYteSoq?VEoq6A0Wv-9uYrui zwyUv%B@ZG%=~?lQ`T1>Ix4!*uX^E-NUoXs&IAfaeYAkU#NJH;{NV)5Pxq!W+ctm4b ztHD3;fV1yn30MWRaynjzVcom({mW~V>vcPb{IK@+8EBH8)19n!!)c;>ee&Uz{ZF0^ zX0Qk>C!;2vFnwzE{%Fky#+H0RJ&c$(x<*vy_T6s5DSFTBV zhb=#mbf6pE(XcsVG&MaKP-A#?k|gxsuva#vN#Ulq;s(H_7J9fol%dlp`Arg2Hjj8x z0-mNkmSs@GMUdT$s7v4qfAn7M^$wr6zwhqOJ8`1D!uo5b8LctPH9#^bRhKUm-IcsK z+>mk?74bC8eb^A78{UhkwLWmJ-&;#)&Idn>U`` z@4K=Wm#F6c4YyX0YiOr)0}X=URi!IDf^iE z5H(c*4%5&YP;IW8wkjkCYzwnFc-Q)`o^{Ik4R1XxJU@$nz zBS5-=T^*+pLo)yz9`B!4`#+yu4f>O3AjOPj3Gt7Q4$omJA7l(g_}$=n@@h>(>NMwP zTNf+gdhv;4eV^jDi;d4b4KXvE+S(_1-}zQY*T4|)GJ0;b{R2PJb?QnPVH?=7xN8%x zPg*OdyyiyV^VqV0ENMxFW`^4t*qvQ{kmda374>0W8i#Hr6_qY2^1MhouF68enh_&9 z;VrfP#O09ouH)lcRVQYo&E@N1@Yj^Al)NUM@WY!PDdwJN+@W)2H8BB;VE8g7t$xhg z!6Nk2>XXv;nguf*gRGnBN$;UbWT>vlvb1&Y2nZmf+zHqg8?9BbnafijV!I>D=O=Y4%m%@p+*ZlH3$($bf-TfeiTuKR{G z{V4K2#h`YfQ$rgoG6ulh1s+DzWTbIjXo-D&hG=?HUkmlwB)@u< zC?FO?6inV8E58ck2SXcP6hMTBIVYIJc&Pt_U;!g$0)d3~eVAE=+;t3?K*;3<FV}uZ)ye(m+M%AdJCmi{k&Q-1M)ZyX@BnIXVc67L&f_b@926WY zP?hRlp?4SuvK<;e#T60~6qI~Jh%j&7Q~@H$9^iIrPocp|melIm+!i7Vo=Zbu{c7Pv znnyA?$zuZ);COYEBF2-1%dvt~XC;xSjLuYDN2x0U4wbnYlejvINu-9y6h z{4O~TwWQG&oHW<9HZlqpY}@D1%+<4NKSzDF!|tgPJBMVy)jZa^~Yt z5)1Rp)VgPMU`v%czin4*tiTY?Ohl#7aPBj7`Q?vi_g#_)u3@7M4Sds9>6e8$jVeEK zx!ITsH&Kr)K{e>$atr#;Q}Zpv1SWUb<;qs0+8r}SSbO5q4f_Xi*Knu`zD?dk>e%jF z-s8KqT`@7r=XT4~n_7hpzTfAKYCyL3v~0M}E5K^%scAkfO~cIGGCqh=8@U6= zMsR9CJkWHE9}TWyeY}-WtUxhDn`-ew!Qu2sq)19qzxNGwrux;ucblfNbS1_NE%%cJ zE;id$ifOKm^fIHG4RfnI{0Kwph!5Jt{Wtm#mT#*qghEH~((XEX@2GCtcFjaI zOW-q_8ygKFzNjqSfl>t)0DvJQ6Pp)aU(Xm}!s9oRc#ewDXJC5WZKhd3PCtL182|q0 zcA3dkmH!yKx{|c)sN106z~+at6)*P|Lb+dW^wRelufP%0O+0y>k`!CE9Iul;$kK(U zD7tb8NPmRH1QupwO@gmm@=DN9)$qgSl`j-ACf#ZjFL zj=Purm#=8C+Eq<|t-1J@=Mjt5h4c&haT~7k3W)vvmZ%iNozESV3WbGBSxf_+2&%)fp(ZOqM@8e& zaty(|A0`ReHD;b#4EQw8%65VCkxIPz!*C=DiCq8%ijwH2ly~>&HGp;ihM6&XJ((+{ z`ub1$mRtpf;#1HB0s(GQ;X>*R6%WJ3dxF_&N+;o$eL`D%tu+BAeJA7)1kz-?h zp-j|ceNPqJALJnpJ5<^lB1|+Hp=|j%Ip+CwQ1JnQ3%y1N{;&e4OT|i@WA*O}s$ECD zje6?sm1}1XML=#q7)4bZVn6+d7GQX~uf5#~ZzkUU(6&senFW@E;VAp(a1Y_mkUXA^ zx1*riAN$>N`0Q5OhKi#mdHP#>a(Yy6jrFqiSPl;jrL}WWl20I2#&hCK$Bcg{t}~1b zp*5IQ++%AH_vd)_cyeA|Xv-0XnW7)xx-gS`v)I=%^fECqF>U>5X*n(kLLgvI;TIMh z%(_QaYxFjf_*4(P0OY-T;XWkj2l|dWLwp-bt2<2&WnF``J{K(qC+Ae0z+-&Jug^|_ z24P>@BNlQAk_x0hVb^aKH;!B0!oIj&-)_k-l3Rn;fYWj?1ogT&|KL(XBu&Tt>*vZ~ zERt?Nmeo>SEvu`38@bR0Tdi(bKK{O91V1?YoB_eAkdsn;U3mw|Uv1)96-m(+cG)Lp z5i6*c>CttU<8)Bl^sDSO$770_Qn;*n&5^#z9lH41s0-+x-r5M^Jcl~yUfXfcLah?vd6Fjcg9}PZO?7L<&|dWD zeZ#?7x%z`C?s21M3n}Dda`b~e9(q#P6ne^&z-HwxSBqaB!{oYh#@s+Fw4yt~Im~5k z60$PgceH1WS$7BfgyvxeMkb~mQ78VG-7#Qc2Su50AGJ|cayb5DzJL2Kn(U5FNs^&- zcf+|!#RU(n#hh11-W@+hat8MzAyro>qH{(~jpNuXDo|XVEJe#6i_{rClPcyYBb?%TFN5ZgrP~Oa>EoEDpi)>-ec6 z&h56auQUF{X4v70(v&(KfSqGCOgZ){lI;Q-0KguhxB>Y6aH!#e;Uj=cgx^d4#dm-n z00q!)>9qdP#UMG(wa(H{9=yWBCC{IGpb^IIzQB9<@8W~T36U^W^kc3-|6pqYYuvOJ z9vHY~X#qJeiaVb@zFx>w{BBZu{-HyV+dof1!q~mLRt^m-P9?B!;gaTW{9zKXOWcxA z|L@h^6y)ZJ>^;A*gxv*U8(wgt1AKuqE-lRxjz28<2FlZ=hFQWjr4GBfVY9=c^8E7< z{D`!471%O7un3H-c=>V<4NaHOns(j1aq#s)&15YjBc*$N@(!0S**Ll@YU;pHr>Gc6 z3jfu0V*Bx8NU3tEbb!*kCX8uf99};#yq4HIeyLoLA4EjRB(gG!!*>trjKS*bF8pbepJjd$+xE83~D(&iH(~gAh`| zkQ{N$4rBv5A8`a03QwWaeVLg#`g!e7>GHYzpuyCy_AGq=Zct>kbrl)^55AUnR@l?( zkMs=;tRN{)(C8WLK$wE!0(b!98|-au>4j|XCnOlVyNilB$%3pDJ6SYZdud!L_eegE zN+qzUhVXIj?)g(iN6%95z~Xy5L8Dfh*s&))ht>b?*pL=MpLRU0Bmxj>v2FM=owZ;e zFgB;M(AjAtIq21a{ul!iUCKhXA6x|=MViNmE34djOv#b`sPODxw7LOvTq@ihM)8${#dKz|4^s*v=bkb~zpQGFS zVAex@clcQK0z>7_(7-F&WV_SGd#i`bPBB+(kuMPe$M&VK>uukON5#<91kYE|vHK2e<^iy!=_c2G zEl6M30%U|Skq0E!sSC21RN*YVGgF1*H@LcuNGjg;uHt$L{vx}TyeD*u_ZGL6L z0;&<0lMViY2&9q@2TM6*g z9f}*d5seShh!oyOaT_5p!!X@zdDr7%{!nDSZ7Ht1uFeKKoV}h-_ip+5AHLApp_l1h zd8C1{&2Wk3&$CWJL;vzdDaS5mD%96yJVZ(==4t59PY1cf$i?mpd0V_+ z#}*5O;0K3pn81D_Hd!u-WIqr{PceiB@wW6gw&keS%G3E?UlGNNIvA5b}S zM&rt7Rdsccz>;bHfH6y!4;dg}6?q$|?qO2E@KXO0{ZthWUM?+aLs9LOM14+&$qMar?Eo^ZZ)4TsJ@P`-mKf{MEI?bGYsT#uXJtix~Z>_<(E zZ{dvJ3)U5rn@d*fu}uHy7=7evsj@61>Ms|`InsLl^%zwJ;c?a4OT_aK|H<3x04X)tsL5WCyZH4#;f($eA3#*vU1zR%cmyO1iw>m+UR0~gsf9? z-0S~taBAu|((yhbHL+EYm{!b?(be0_t|Y*`iHD;2@}P_hrDJ5N`MPRzGb$61gdjeM z+zZm^0?1o-)k68Ugfi7G(;K^UaCE-ptDpYC0|$F&NQo=hZGhL|9J8BG=uMJ zWyq~~2BqK+7$(~sZG1ME>4c`kKZ$(mhhf{-Cv1rS?ydaO-QWMh_AQ%B2&e9_%XK58 z51dJ!NPgN8e?mIhVmrV(Bx;<6sWIpHx?Xi{5Vkusny^mEU@V_l7H2iYQbf^;l=7kB z>8-d;UzC)ULGv1EX<1B$5?6uj4xrgf{m)v#H{hYgxI57LuuF$jqD}i$>0OD{$IdR> zx-wfOrt+&n0M1`1uAb|FB46U)#z(w^tu^X1s1~7M2CN98ue7wcOU#3Y&;t{%Pp`Ah z*8j)3NWvjZOk4RX8-XFA%z5pH%8>A46C{JP_%OXI1wI zQtIlvjmR6pL1kgA0CazFcK*^vasw+aE$A;e&Nf?WLZ zi2-@bINd)C3|tId|BWlhHu0Q)V4z6-3gI)XJ&a_a31vATyhE`(53x{46hd{-(B(tN z({u-`2~nmye;E+F)vvnLHF>gMiq}IF0#NkH<_VKwkBJDzhz6Z|S~!Jyc$$#^6|*oq zE1VPc<7)WN@ zK6!%a{Ql#|)ytP5w{sN$*v(kHuVnUT!`4er9if&V9AphYL$T|?0G8dmcP?XX`{PvV z91}5zJT4Yq431A=s|Zz`92jaxFMM{gW$SopYiRXRU@x=-D-5lK9t6XN4Q8j1$n1=w zxMy1Bp{M{90zyJj-&iq4E+#2y4QBCyS2z2Mmk@vn9Tfl@92;3#WctWnz-G~&B$b31 z4(}QZYiq)50o-d&{crC;J7omX2YvvU6gG=cDP4ViBB>9OO8|==qpE8XIP*|xM*WEs z_&_&}sT7Hrf4EM-5(2Z*644eBUNk!p-{2nL5j`Gngb|dume|#2K;6ttOql0o8$SZ? zb@;|ReO=vf1_wJk);$bj#9Sl(jh&kaFe$IV-461xrGh+JItW!RLU)DGHj)S=PJ+l1 z#f*iPmKHE~MUq|&tV!6`ohoK;$9p0lDGw9Q9&f8uq&Q>eHH027G#wRIUcu{YK0-3Fy}V z#GexUkOGw?dU?F?#CtEiRSdOLam|ecxS<=#QYR(Dk;*B7uR)(=_=@Z9ojd(S)_3Bw zyf*{4#Vizvp{udoP%>B|=o^_uSsY6+8P(Tc0KSp;C{Y*{)Um?HrY0tUAG~@b{&`<0 z+ge?E3z0^UOD;d^cxhJmnVqw&^#|^61=KydnjwNz{?nW^Xo!u$Q(mSE?}L(-0=!(Y`2u+fDAeA)k^JGnl#h)Rsm z>|1Gcef+qJ2?S5B#)2lls-Zz0=Y^(~s9vEYWeexx=jZ3<#)EhE`Ub2PJl!~!)vGI< zU(^Fz!PfS60)I(}JMvdiZ3EQOT=~$`lR1y&X>5+Hdl}aGP$URpE5`E2u8sUQY#evc z!SD_Jr@F)UU78vxCN}mLp>TUN3drZ`-0;~QCx~6TiWQF@mS;#(`*28^z)Iv- zl2nDm7Vvq>uSJM{5Y+GqdpG_=uS|GfbEV}=J+)|SKj@8t#?~OD{CI@^Lu=u!@KB3kXu3I?7``mR5%C2b@7klp=&vpO5 z4Ofa!vMNGWA|c7no{^;NRm#Z7Orj(+t0WY%w`4@3j8sTA5n703CM6jm<38SXp5NUQ+jpy??j^}Z#K#4SbVFLCz;!P==|6BlaPCa6-j2PB!)}j1{ zb_ux?XSi`bqU|uAX?1Xh^)bB5DKFc6tn&56$~Zeql*QSW$G6KD&l{lG68riBM=&^& z=9x1c5QIW&SK~dp+J)tW6a{xnjbp)q8NBv5DY?|bc6DK<{ujg!`6q5TnjF$0=BgW) z)IG7k0Fc+cWE1<@;^+DIIJszS%vA9f=@TZGlJT>gb+xguKtQvGnz-jrU`9~VLco&+ z1=aH01K&MY4iXQK>E?%x{JOc(%WfTLBoSqAkWXl!sq`D?&9m#IDJpo*1ie0G(m0D{ zM8vh*8{&50jnA<$z84xwSw90pxD1uq=v2?mDs104CmcAgeMNAid@B@_kpqMi@QYdo zr<%RbU=U;D5h3vCrH&u2@)8e4v&C@(1BkD;znf(gRXsgnIX)gm%5OO@gt24O^@sH4ZlF zTJpc&GV$?#q#8zr#}75aNU!mMSgP;pBCa{j+Z^~_>#S|M;#0)60i_yM8QR+Jb=vloa@zI2&0|@9f~?N4*&Xy zTZF#}C{ev(;+gt2;hDN_pbX6bCer<&Zt1ep%0Y_4*2IHT$b99LS;y1^%^`H<1}ic7 zm&uxJJeEHYcTwpr(FdIMeFx}OZ?T;rKBH!xV}cK#R_(oxsje(bds*xIQFbm4a905Q zDI4Ga-}Kcn?Y5lvJKdi+t=A;c9;yK5Aq1x8au=Z#;Z^smx2FrAc?l;f#u(-FRrQJfmw zw{hj(-dB958qM>YvP>4}t1x?>*_#yb_kfXb2t-6^!;@Q}Mje!4;aYY1Z9%!FaU=0y z^Wx;SIa7;*lsV4?pX4wkq!F~F80gdQ1E~eB(SrPXy?t(-jQw(dliE^B(f_k zFeC()gs6MbNCPH98yT7b_6yGTP5onl#rpgE-54)p(ic+*2h5(!?%sX1?;Wu42Nx>6 z+GhA-TZoyZ`rCw@c4h`=T}EZ@wYtwJPvKr9GMbrXU}(sH=>W+6J!a2vM@`{4*IxES z!vk{(R|g#U>PL^__79B)_$nhQiKs~7J8;L)($L6AO@!{`&~7*k5Yb8SQ{XwCq+aFr zYkHa)`O-*@Glh@*~13?a|n69sinrC>{uJ>S6eQAuD2j>`VdPK-Gi zac_gq0xZ0|VP!vjsT6KFFd22c$?fYubesVO#X0&W4JL(U0yJg(|E&4KvU z)s^2?4=m9Ms!~h?giz&5g4F~feWIqB_R^6sHiNG>Q{&)7a8ar?+5$#XRmE*gdu9+k zDY~xC+9SZ<#JeiSJJ|1+mHmp+lD~{NWTwOzb#4$Y*!HompOLR5=Q^zZv&0XjGw>6% zHhDIOAvS)Ho4W`+s=#1AjJS0Yzu~)M8b4mRI^Z9Q!VyRpD54b2cN2XUOyJ~k3^QHF z3qtva*J;MXWp>9R)HgiTP>V-O&mqXA7av&&g5mef-bIf_F!e#JaEV2ra#l z(cx?dgT2g+iYL6K@$LO?#mj3;AyrUCC1A8A6?-3EN#mD}ds^eB!?kpVZMWft6C*P~ z8g|OxzUb!GIO3|70eP|Wg?J*y`o7j9qRz-PFvdV1T4xj6EjmM3m3WH%kQ=)}OEs*a^;Jiljlce44k(QP~brrHg zxNhM<0;cWO_GvBCNnT-bI0_5=h_@o45wvdEQOwb1gkyErx+8~_^cnr(2M$!ly)g^P zTF6L>cSfm*i4!%;BS)IBq)?`257vWiA%a`IH9CpC8}i{!%LvBwhzxD<)C60GRnef?;9-(31hlq*6zyDnwl<3-$<@VGHPyVx_1t%D z6~-Q&2z5Aj?f_2nDO$8WfKdkEbODjs+s;nQ+g`A{T*1$T{t-j-VXVMaQ)DhV<6ENG z#b6%}kFWxiXMCmEM{GTVK-{75kEHehun07md8QJBs9E>!jg5^F_1^AVMe{dNEWnfw zQqCpZ+{P4QU6e*w#FTA4Rjd*(qH;%ni<=LN{h_g@pf>vYgal+Yt@>2n7CPWZ-la6wKbV@@Ma+BVn8sKMuk`ARfee0=f(a17LKMg-e@T zMA9dTURWcb?R$vY4jlmg9KdWozTCXL&Wkcnl4a;s7k~f8pdoTkPh@$H3^KqV%w>K|q#%O%Uo$>bl1o)-K@cup^$8NxRzs0^v<%8E zsbzj>jEWzM#$Fs5-QC^5BPUpyJBTSw44Q{#_@GW)Tb){y_|G?gN~7P8V*`x5E}=IZ z!4Z@wEu*yq=maJ$bm`x8b(O&31n#1GV~rb8eI0b}J8Nx?{-PKe#1*E_6Rh#Umtz7< zhTjT^NC~Co9IN~AVG(`Y-Y(1#_CX@3r*{FT13uN9Sz^pV1Q{+NlI-Zp@xx(EgzNj# z7-4^zpMS%&9$D?V_fkM&+z0v=RJV3+9eRrk0E}@V;vCKy*ur!*B%}fKvD-GQN^Z&ap|K+-Or4yL=|rPyz$-@3ZwWr6&lzdv^Ap)v=w zGf^fAZ+nm>YslY}9#-OyA&}f~U7X{XU~BUbC`Dp5JWr7mrmBOnk$r-Kukh3?4yR!P zCIQO$s4u94AbQO3U2QR2?dhtoyK1jJm0Or$&*5DkfwicO`dxb2t z<5V$<*9N9vDl^`8buBFp_yJHGpj_DCpN2~q!YCMF8#sK#%E7k^%|N6Y%6Nc5`CzC} zh7qPG8?RzHfee9G4~o;|5;5y$`X|CFK=cd@-T;aPZ-Om^Y8jfY9Q*w%qD1sbTpSUY z2UkNh9y@mu4m~hc%=TcA+0V<1Iej%Wpa6G?U^$&`R5gai#*N0Odpj}IgcXg_sG#7O z!2ve5;(~hoX`HQmp`cKKH^TlH{U@uiW#FORAcpc`4}v17wN?L-IeH-iV!VDGe+JW# zs6PQb6FR^Ae7zDzr+p;}t{sEr?Fr&Hd>%-_#X%aO=k5?4%(ml6gw>qXOgu@BA{fmZ zjtE#U0QUs+51%pAolbjW&D*j{_tYBLMBDjv=T zO`C={z{+nn|NN4Rc5ub>_|kb@`jPM7Q{eIfSuK_qJ~Eyu>S`2WB^No~4JTy#@-dHJ z%ua;+FG3#LF*AmL40HyJU>@b|@Fa9qIDvRWp}k0is0wiZ;~x08u&o3v6>8ubL1{Hx zmW+1K>983xkb&rfcLuKrGXaOQXL$t#WPMk?AnwRBn3ZCco(xwTsK6}!W9f=Vd97YQ z0+$oX5}7IZ(S!s1&$OM_AyH9S#@4b00W(CV>1R_K2r?!0zvOgf7_{Q-3AgeM?sYn)CfAc&ksP8 zpqC}=$tgIz(#}4 zkr0{zU1nTz@(OgkZND-+F8-RG)h~%N6&xUrF5N!DN^Iac?p$c@3KyJJGN(uYJeCP6 z?|Yw=>;7cg5a-HF;P-YXo!oL-d43VgB&9-PMMGWP18EyyE>z;u!9W>sa6rxMREPLu z3Qv{^N=O(!#Fq7jPH&~;vr>}(cV);CVQ~D@fy(LE-OVg4iNpXs^a|Oja9=S&=os$Z z@v(K72F4KyXXe-MGz?MrLoju(y&88|b~aC)A||em!$9aekfX=Vw=GL%8@}UW#U{cm z1*pfRk18;wfvSb)WQW8V)c*J#{k~PS1{kjzPYgwJ0!C!JqsjJ5OMAlcqnV7JpLR>8 zuU$!}La#md-o1om2;U1s4(ObkA2dM!__pvA3o~;CuKuMDcX3L$ATOqOCCS`1bf+%9Za@OW#ovi16^gXHbFc6>1 zm!(!j*+Oz$Av#?0vBG#bdf9^cj2s)_2vDrp-)RMvg9^8~xzkG-bF*btt8))Ri~QvS z&^M0r3q!342qSsbK1*|~Hof=zS?sSKLl(JxB}ZgA*G8kN1*&q8k{}3~(`(r;5Tblw$8O4=z0`H0VKxdw z^YPPDuuDfV`R$Ukz_yS20U0@v@hyemu_N@&9TzXycpS_3on&X5;=m79xb9ieeuH`z z2}6*WrO?nrK~Lniy|vv1$L~v_8HkETVk=>mzwLVTz|@3U5BKrn0vrG*afaiW6f7)F zjf~7;da3J|k%B@M(5sWi#=t;v%*3rK|Ajo^B#)^ISiK7aC8@h%pWx3gdTeIsx${S9 z&lrW3FIuw)TXBZrA{CKnjOy#$y?gh#&2f6wWE8kyY-W`ZAd2hY1S%11#lP9vbMXm= zwYP;2*|^CZE;Oq;{tgZnF7*wRC>fy*TC)8U2!Vv-R|^NmIRN1`9d;o*HK0HE6c-WU zrMV=f%M<0jx;O?{InyB*6|WrjUCR(O5vqp3U!EuMs6Q^1A>I2qTgMk% zen2iEdClgX2x2^q?4WX30IlrxrU{{`)JyB7ws&{^ViJGsGy12s16R(mGrB)kSWRWN zQT%Yrf4%AlC2evgtEi0^hWgdp#9E%d-Mdev>rTsKT0xWSY#ozq+Q$xe555*ObiT~B z|H%6Fo0Qha9NY0hO=2ru1G9~f?^B;&USpyxqEps3ku%F*+kW^|wO>x1@qG4bUiyJ3 zE7R?L{6r{*h2;Z~Gf)IKUtmX5^uFT4UQK=o%0>)cYTd6M-%w#F{GJr;Pz==8(rO1* zhe@YFEy^JulwH7YtKAVJy2@6zv1do-xRoQszuIhYDTh|Fy|wjaiwS@bY!*1KcI|yl zFo_to2Mq^^8na0iSAGdDztXqMuhuUm#+4<`^%D+?%RMMJoO(+K-`ESr_I7lnu~w?_ zL|NO|d~OGbYaqoJLv3LgY~nAL-^atvU9Ac%Zm>4w{9VA01my#{#SdFl;TsjK8R|t< zOb!?6!969d+1~-8x8^GI+N(8F6`pf>^`^qk18%jBt}q&ZTJl#=hDzo9VLgEz=Xy&E zN=mkK4o^&kjs|1mAfqSg_8iH$iOUh3UiDnDb&DAL$DCWBui;^#qWWWT z8Fl;j-m)oTn@XPF-8QrVR^jABUe^!(1ll%aL8hDoM=ZRmPbr9ONX4nUe4zP_(tasx zs%ko?n$XSLKUWOT}? z-C;u^^4rKrxydTE?R4SO zoA+Q+wmY`6qN0X1g@&q)i6+Pko(_&mLWmVW-xKiaG!%!3fKVT*V&ZdhXKE^?L2caq zF_VE(6_@+!3}AhDy{{;#$JP#h;&bw&wx|~pjI@b4IXRp2Ju8rIsoi&#EJXoF8E(U1 zn|f`gb}DN&%(A*@0wELcH>Igga)udKQWZDOti#9`*}H4kI!-Ymp|ta9FM_?h)(FF%o~^6JB!F+NzAH%78i>n*{Zlv!y0)_!7*g-YO+8(Nop|PPOoYpIi}+j1|46 zSFZ@m?|#j54i3mQnWU9pAkWeM8t-NMWJ+@llKQGL4I|Fx}P0U$#IBM?VJKoZ(t9Leh>p)-@kn`&<-@jwN||Vl};2X0HbfynnxdeU2h*hLjGW3{;hUzgeSE2R%Tv16Ch= zMm)sp(PKhlB`^QHq5?&#Z?K|>Cw!x*JHzQ-c$+XxeEkZ?J8F@s;o*&3d+gsRNlAsJ zJBfK)NNlbh77Za&aZStE@F$lVdrVS(+Z~0NAL6)L&_dt>g?<3jNd6UyfsrthliUa| zxjY#+U4+e`(P=noZsBdng?>XMKCEGAdT|+D4yC~?I{jmBw1pFy6Qq$)N4lf*L1qs>KV`oOra}AqoS+Ps0{BEkw#{=sg_a0of&t{ib;$P|M~Q;s0om#Hu)BkCpP)ZFVhB4Ek-M>gOW*yl za6K*nD(V!X3 zBg49ljiqR_$FbVa7{2oS2aW5JogG<79N_FX!WK|_Losc!kfn8h|59s`)b?d$XB~YL z;R1toJ4Z)M&lD9GBZ=kRj-|KSMGhKpvtX(0GUj(GEotMYqAb}e6xD~K3oFv)7$nO0 zx~xEYa`#9cq0>nHbItgtATjK&=ECkTiHJF)~N zdnza#mS_m{D={p9W8D10D7sk8-cuF9nGu)MQ%G>UUvLaHz96sDsAoFCCKe@1FUn|> z&BT)`b%;5SEC%CYm-;Us9@)6ro7fr_X&8gKPQl-CA0fLpw>*#T>Lf`t1dy}T;?fysmZ7#r$1r$}g7nC7pcME^8;-{VA0p z@tp@7=yL5C8Vxi@OBa>AA=HFE9A7Z&0rrUEio^*?9Wu5YaeH($oM+H;5lho%bGx1C zC$&X105=C5L%bGs>?qj%dbmYQ5WZ(+kw z(&mI)VYUc*LHMLbM@99S`>OB|*-wy+{K|}w z|Lj_UzedcWmgf6lj_Ok}4vc)C-8V(xWtt-IElt$|fVY(TE7Q}BR%iVv{#*q1aX6G( za42zx+L804y+Q%G$J7_j6_SQwlpg1gU5-iusGD*|T}$g;Q4g%(A7d^;Fcw{K{HH>PLB5cAc{?UOUn#+r)%>DQbYMQd!8-l6PYl?O@Jc9N*l9T zF1*dn%Hn2Xnw_8D$&ba(04BWGZ1pE&UEd0QklLCx zT?si12)y7ldtA^oA^$WNRZjQ~ly?9lg>LDYn%?hMx|e!K8lDYBXB!7yTqMoif5bZj z>Nb$42&GN|zO$f-{fi23=GsMZIJ1$H{O)_hJz~7^b`aPY^yik500BS%b zPVilBOAz0APV(X;(>$Y*RAv3LXzjId#Vkj`SRA{`viJTSC|4X60`O-AIY3BT%D&iU=vHal*?zu*0b(i9r? zota*64|x&p8yKmy{$s9xL{;~WSt`Op{^`lr+UJCwhR4Qg>mWB0OOf6N$I|vu38%kL z=)CbZ8|hCBQgid~@4N1c(Ey@?FYNA#@$np=0Oj;*Z)Y{0Joi|tA!3nv7;kvBLT9G4 z7!1g$`lUn^-M?CZ^oRHyX^h?Ta*4Fk6Y3Bpwk6)%FCT*9v-Gq$OI*xx3n&T^UJzm1 z3`wfe;2uoA^i=sOycB;cL4xorkx{q}4s^QaDpC5%Mez}nPU#QgWtYUJ7~bbCDmE_dskp^@I;A#JTGvU^-=rjDPg2gP^=_` zKovA#_hx+l>|0Tqqc1cmo(6BW&j~XbnFpd(6l`u`@zDMa|6Gc;rRDB0W^!`!M|GbL zlGygts@aTxZNx!XW3s_B2>=iOY9wXQ1~s1dXFstCsL->yqptzhZC;MsAP!en|5Ut~ zT_>a#u>vNjuU}j=BreXt$jZv!gw`CcPIN}-{_s~Oe0PLW0_N{|)xQa%H>gZ0-hsrq zg6UcD??PeMu2moY_zsp#1_ocEme75tKY?qXdDWetzH+j%a1Pz{4pY)aGl72|J&jx7 zWlVBBcs75+%8I*9mTA3cx5)=eFzBhsLFB+etj#xv{4`H=8l140FWD-=R5bi}~_xASOL-(Z159})AKasn_vB?;Yq@b~Z<#Nus#|p@8NloQg2>XD0cwrajxbWSSqc(?7ogGH; z>ydWVXmhs(_kMRlv*!el3`XO2`xthsvab>I^+UzThbeu=x}jVt8J*fd=}mjba=4|{@gh;kiWn% z-rReOtBsf=x_vw2wVYzQHjw~}GKl=1ttOCMBrihylhQsjH}__T;toS{I%Ug;3!v(H zM4Hr3>;$mk13Ck?n)(-`p&td}Q&TnT%OakUnQ6fli8SW&qldZPtH2`V3<%V)VJi$M z!_^4~f%fV{xa6YZMtNSTF{tPFr$TOhks_ow3NfI6;|`{$+pL`{+FDz&YKG9s;>BaI z5qzEldF3W`+oq!Ef7;r_jgXj#2m7)yG4b;8`G0NT>W}>{txQ5KB8c)C!l%3H;DvFF zDlGq~MKjLAmAO{O>V_;O2q!%VMN|L8whurK-V`Ap1D2k1 zNtT{cRZp*r_$AM;`zhsS@F}h!d~blIFs%G3QE9OWnUZsJpt}BqoShk?B)7a+$9m#gqjw{1I5>{|N$i=jgq9)+i*s z>GjK97VJ{4SpfSXfj0@NeM@nn>%(AJ1(iPPUVp`1NUz(l{>;VS-kbmPzyAOAdsjaw zk@NrOcWNegkum)HxBSg7M*8E!{P`y!kdSFq4EpzfcEzz-r78dOJGoDi0Q-;U`bXxW+8r5rY@lsZ4B34CZWw5<)hNA})laTvqQiNy^ z_c88m1&9ge#2h!Mhr44{n&E%*;|PP)LWMtsxIb(Gh2fDR|1_e0!UZ?B9atFfk zvnp8oNWz8Rs*3nz`f-r$pya^K1rkHIuns3^kqMvGbDmg|q;OTaPo7IEYrA zOvq{2-{B>i^WX{L!2N(c!4)%8!FTwm*3p(;?4n<7mDP`IV+y3w4<-jpj-^XV2U-Sx z4S1B^*tH)XKjV({z=b;KFdwAJRcotPFo};T6zC(t$*wK8uf<7R+4$lICoUv4KJ+-a zM6gn!*u-mu;9v_iwbQwC2i?gz4*sw2)e1QZBiMx!QaYwq5P6_JQUwbYFzJU#*ujYb zN*tZzf)f_6@Kd2M47vfCvM-9Sg6&lvVEX5?&{{g zzVOR9y)q|6Dk47XCcE5D!PVs%ttcBSy75NtTeerznapf>G~?DWqW^Wz5Y7pUYvEdh*jd4*Ha2y$)Z9Ei;U z9__r~J~#0OB?+**ddvrfglyTkfhGjO9ry)L5I>j?Euh0T$%d<~U1t`o?r@Rf{6tj^ zRm=55BJk(Iylo()Qg_ltEjIXnYTBDR`|B6B_uHZc^ zIb#m)I2#BLz(BhGG!d9$Ct0HW)_g*g{&(;VF?2uYB^AuK*ln?5EIy^?Ad|yDPr3l_ zeMDp^=VWFMfoOmwO9;)rJS~|Q9tW?l#`3FF*(#e;cG2qN_1rmNmJ%76_SuaIM%ZXE z(1R21H6I&Ot5i+vsIgHdOlHn*HJd82?jCn~T^tnJk;oa%x?q0VB ztq~-oia|iC0c!KJc8)J6mv{5 zH4V*iP0gnWtVc{?k@cW!#ljU>9l)}?+e{K|D5ww4Ks;vHwC3)~vehA@f5`>>-_Z~< zR_sn-kYRhbZdJw)fujPC?%2_znBk7cJ4-zGJlAxRlnzLjXU`ryQeMd2p3!wz_^z$u zIF)|&ie#CrN}zSNg;8=8MJSWWDlh51wkF-MN_2~+2 znyFZN()ZFg$Dfe7W?bS={>+eqXjrBw5XKI))VLg+Q5_k>`zziU?hGL3Z*9Iu^R*%G z@pd9i-o3koOAe^kgceQ@ z!uEuankYtt-N3`IvlN#7Iy^j!ft6F-+w6{t;jJRpuQ_~=yxTT2kI^JiSV z&>)uAAVLpyD~J_^_iJV@TqwGxBT(s8T|Gofhtex6J6rkddknH7WH4zTgm?HSwB-D} z6%`dxtV>+h&3%Mo1ZO4@=3WG~MBJ!wG;H|4!D=_C7y~vg8yBEl9jt;-2u|_oU_X~( zwQ#L~D*Sa8HZ+sz@W_bHarL!~Y(92WzJPw==NY5PgNn~6MG3TTAC8z`IIl3#ulSHq z(qv|m-Fr1QV|IBY1|0oY{(-fhkWR_I-qLl4|I;t@`VmaR$|F_%{rw%Z81aLMwtKJY zoerEwy6&Is>#C4(y__kpw8Gcor_H;J+1?+#n;cIZJ-S8zA)0X1URXs2KaVJ_PBC$jM}q+hJaZ^!Inv?CWv-SHr=Dau_Ev+$yI4_ zX$gW4cG_)eA?yB_dXzaQhd+;}dHDc`|gLq zA%_4=P8XT4k7!85-oSKu_P6_HXpeIBJ)w?)B{=nLLtEQ7XfoE-;0A=qAbzO?ay{}{ zZtiVO&;hQ(X57VskunHV@02t&qce;6-Fk$9-aWsqrLB#c6P|NKCJo&4(;vo`Bd%{iu8-KxvJ)#VVlcZrOVuR%5R-o+baD}4~@n_*1 z!Qa)ngvpcYp$(jFpmo3?c<`@)D!?v1ypE<2ED^`pvzywL^DfPjARX0$of(0(d9{{vzoH&a|Y< zDG-(8Uk62w0X)Y2C$h%4ozYjjy}%`-&r^s(9;2A1xC9~eu(Gw?H{kcp9ny3=+TqS@ z?R7yD9#EETRmNEjUlxBeAa+zgPh|;^A@^iG#dSdK9efL?cF_?;B`h&W={T3+y#-(S z#PB7SC4mLgFXuSM>0hKV+27BxuIKJiN>Ab|3lR9AsA85MfS$3ofpC8-veDJn{sHRv zt67S)xt6?pb>3y$FC*QQp$$U?CMD#-nf!7a(H9Zk1*~hdl=&aI$yKkqwg*;AW}E6D zE`8Il{XxnPfeztDF<<+Lk{jyqbI%vaSD~zU63VejO)wT5^a{x7`U|wE?(oc^GV@n} z7&<2Q(^h2&MEYp|BM_NZJBd&q=u>cR1V+L{(L=~#7}KyOWzMHyCWf&q%pGF5>jvEt zm;}o0RM^KjFSX~TD*+0iU$GcJKu3DyO>+z}(2F=92GLW%CAUHq72{Lc9iw>fsKzuGAkJlt@$x>x6Z(9w!aijJm$>mWq zHquZ(84oTUL7Z-BNql>=XlLtGc%oq8xd`A}@+h2FFzr?=$YCm2mY!|_TBf73nhUxd z<4;&OHG3{;|5);XX69$;MrB?e9<{|-EPx!@8$mx{cCnOI$G?+-QaGz1SXt^d95M8zDyDUeeY#cT4F5Nw@viYl#4EmYxF7$48kq023E{GjZ_?ElPp+t6;M0#qHWdNleenD8v;<>&8wzgPa! zch-Jw8QjG;4*MGy@KE_Z!)X!!?mztFtfH9PT-l4a%B z|1PW923bw^JmP36Wm4HS zeyjun|H2=~9A0CxY``R0@1ApyTA9pbsFuVMzU^X>h%A+G)Fv zNA8KWb2Y-6(TvSd{C=XwDwYflFZSK?{Z4MXY&>m!x8c%ta2;1q|C*b#quNS#|5T*} z?kFj#5BkZn3}QVLQPHw2@xmP6Iu`82dX*#`cU^g4O{YiP=^|5NX2&bipp~vkpr)b{ z>Q&M9&;75*V8X#_m-qOwL4%W#<|KzhfO0635ZOqM^ zg5F(0svr}Us-MNv#Fw|#wa5S2H>??356gCwhYQ>16x8&7UG$QVXb52DV-3DtJE&N_ z?_*9#LH9A3;Syv0+lKn6YNB=o+)>yx|NY}h44qGO*)n6Zj_D} zzVIz=fJVfb%*1=YUR;b%3pN6<-W9(EFZb&4_#HpjVi#ylJiM;DNROWnmYLS z@)@(!6{g`vs=^?|Ck~tClUeMZwIb}XtJdUs{fq@x!OH?fKsC-TfF<-bR-eXqU3kZ;|z{XN|Hs#f(FAp^~7@H!0P-#6lV_iAtME*7x|1B z=Q8O0f2^~nE?e~WI_bOZN**@hShj7gaU~ap-qVO! zlii#-k?`+3RA}`0#Bt}zk;&^DlT$YPZ`CY~XFre&`c0$L9Aq*eQ>lME=l+n;c<8cVAxg@L|o^tK!2jhJhh0OhTbQ`NW9$XV&3$)k;#p zEPzA~>X(DX7#$lEO^lRyzn#_)*5Md1RU|>oBP}VZs0DqhvXuGO*(dlZ;8{`r33E%L z9651W(!6^^-J2m{$f?BV-rdm}CgniE@@>~Kmb1g}bZhSqcO|8pYA+=1Ks1y}8O2vW zR0sLHm4Hd41vHWK6B>ot`au^=bv^zV9H9tZap6x76^#s7QD?!{rtlwqwz3`-C0sB#T1qBXITAaBU zgA9?o2x{5jpsm>UPVy_CYb5AOZnunJdWCLDjQ_XadG1u0NdRXKB)sxjRvV}+Z%?Ep zo%QyXYrS}(!gM7013w{(LLe!)I)Adsw(Zz;OYy=dzoq?Yqf9*am;Cd_@+vBrDM~Dh zLaI+6yl!x-gFs%$^w<}!X{{i-p_6I8=IvVvVd1TXC=a!69+>|5vvXX9dFRg1gqqUP zf3*N-n)pJ#A}n^H{qoGH9n0n43kw3qMT)5ps(BCBS09e%-Oj{xZOAJ>;FR)BiMW~+ zTF4>l(}kiT*@Wul;CQlbt{8^kVUmcz&G&Q1nNh+d`nvClZL)fQemUMY#ed64Ng>k_ z^}{+Pd)XZWWKI+9&e|^(KS1@MGif<78?#YO{<9v@1OENL84Fc&%${oc5oKW_q;N)2WlWA}|8zUa6F#qk!NWsnIV>+j019?{ectUqUNu6U;CLZ4%R zHIiv+C@zV_M1Ie(IU@U>FrN98wPghR`<|<2h;sTm)oOWek1YFFe|Cf?fEy1X=%MFT zdDq_kr3+k=V`A=3h8{b-Vj{w3bC)D0dgfJ+QU#k;6M1LZV13O$JEc5i7d_>hDz<1r4S8yE>g2cl`x z*9THPFS%a#p2+-!Ze$SARPGoW#-$Ai9rX#$7xED$UyQ`Ur+sd+q#b2Y z(q)7I{?QDyp~1#Az?YJ1l4fW*pKva|)dF^Xeb^Z(HY2!McJ?LMnAGcyCnHkx<%-jmmN1pIj`h^LKUlOb2z z1(pQEARtK4J%lSq+_(`SQT~^q*Y=4FUn;SZZq?X&)}}t`F{G%Cx2dzv)!qy+X}Tw+ zQjvyOyz{i25)yA48uk*03<+bdK%l!{71*FA|Mx{*uRTlT59B|1PK>0aw!@rgQ;fFS z?pu@n&rUY*d#S1hArb-OFhpv@>HzQy`#!qMNEg5?D8zd+9WNil{BPOj`cFt!0PonushBFMlE@QSD9BvCUH8De82sjmjO=b$Xtvx z>q<5aKsC9Af%5ckl?{KYkbmg(Um!X2#GaATLCHY3khjpA%VPCXn?89P9A+_d>kaT&11(P>8n{IKnc*x%DkW(bqx#2aw^EVC<00oUaoyl~KUM z_BK@OPBm~(A83Fk*u<@&qkjJfM*R6c1~|%mLkUjM zF>i6NeVPVg2$v=(KTvoLe)0@>F*dWZyquJjwBUs<@)vBR#}C+EkYq&_fd>+(4fi$! zgP2t|Z){RPBNz||l!USUA=YP*?xE4Z$6}zYgDjgE5%_}a40>6ScLgVnOib*?9k46$ zud}kTEqeLjUj*wO`m9SGbXIvJU>J5u7r$qLvwZdvF9Q^r|2!#x6Nsc|Wn~3Tf8jz& z{pv$Xx9(JfE(^m@bHjLx9RWQ`F+|bdecHi`{md=%9rl|x$!$#6=8YvP*o!q8WW67` z>s9|0!Xz6pZDGq#2_VaYqItb$Jzn~YqOe@+o8YYc=fI4C#T$YQOFL0#Q}+(t6I5;aB-NPqTY}v8K!HCiHR*ki;F2gQRVl-BfNz`#nyna z0AKlV9QMG(M^WO!gXE!llVb*fEv&l~NpOEogYk9uhs&%*rKRwqy&n*u0$n?lC}GUK zuWM_$WM#e3zoXwL?Bqmu{QWSR#M9ZV;{IRq1@<%Q9+v-?vWHPg?LimG>{tK%@j&%V z&0TbwAs?vqQRHG&z!4nqpLeN9N(VUR0ro2U)h2&Mrtr9TQv9g02p_4~mbuy4`wt!* zbia6ZaBPeb&iRv*ts}1JGjSdmogrV|gi4t+?<9CYI9A=#<9HJ3$|4{6gh%L_I``GC zoIJ=_!V)n$gKIm84l@&|z0Ae0bmNNtF*AcqieK|n18Yc()xNS>M@#}$JOafPNf0_f z*H{xF&E32l)JD?Q*1c*coawIt{ur_;Dc0j49kJ=)AX9*)16Kv~qo@bYKE*X<0e%=9 zMzaF0rVk5bF(@w~T%hKRhWHwaTCRJ}uH*%LPH`3$I;%UbI=2=TZdQpUTr2^89U?hF zz+7H#oO<}LZ|+ton>?U`;9o;JBMinWU}^%@9+IMA_6!t{_vtW7&FeRAs2qCDL>K~M zCmbe0QqCB`>8>8_Y{A0w_ru5f69MVq5rCO_d#^y@2@2e5g4K?2vc+F2d-MnmwrQ2m zv!&c`IAqYEKF5LFJZ1IC*^0a%m-FS&?0&2+t=2=+7;=|KX^lGwS;Fu=FUH&w4o04) z%}Oj*8*cnyIy_{$2@d`prr1CD${(O(VcEinkq;sQ&BP?$SOBw{ z5=XbQqtAW?fUdFeJtEavrtbO0TOGM{EdB`3oRxMi*SPuFH{$+&!u#sZ+1pEB{>lAE zu7~y5ZQ@v_ibc9H`lO_-zx2eL`2!Hc&Y3I)3DvR(>}%(2#f@iqMFIcH8ABW zcNx4|pFHg)KhWGvS%~Z8X5xXX{L=RJjnk6eTl^I}&}Dh$>LrT0K>L{Qy<~G#UcIJC@32_yCEio>D$c+%uaw%U=OAssB{=&R}gg+ z)B#u=IMOk^jaweV9T;RiPJD`-F6HZs5} z^#3f=0G;}WLd7U;U{Db1r~g)Du>JnwAq!J&Q+4%g@FoBX^CyZFV`mt&y{9psW4#&2 z9C}AJ5+K24B<&bhDe=<3iW4T|bc0(`ak0o83q-%1^psnb(Lir%aK0&S{m4~sFAqYz;$ZAx8h}4;bR;7j2=scPzgqW6; zTmWJXEHWSQ6Ii5%v$Np5%;%X!ypUuO>rm(?QrqFt4zN=C%Dm&rlZm&?!e0-l zt)H!<3gm`x4Y~+In|2=ZGlkWKfN3G2`~315++}zN@Gb$1NMx0KzP=aUSeNWmdFV)l z5(X*MIR8O=!Y~g~ZcJI;-0p?e2vhWmq>tt2@uMGF3C29v%Z3K7yQ4A3uZUg#X|;6o zae9LKAj?)|5VJyuEZoy9`7JVMcIjzoC`D2gc)m!B^GMsqz_5uC#U20J#FsDe2(Bq7 zBM8rj4|P_ip+b1E!40AXTwgiM2iPNi!C@VT|BZ&<3Ij}RY|o(lKv9QFEAQ!k@aD($ zix6H702A&a0Y>WP4-}LkBfkLFox}+lMxSeIvW$_nryVBm7eGaHVOWFx5DC>XZlhdZ z{OSesN}S!^o}N#ZsGBb-SFv)@Q%?UrfMBLVSul5SK)4ICZ575q`%rShU1$IPf+tT- z$Pw)K1LKDqj(>RpoD+j11nq=KgE{m-U#vD?Kpqn$1eBCQ5T&l%C#KqK^HE!h)98aw zMYx?V{!a&B=^AibIlbPvZR)vck=C~sq>8Ig^vOsu~4W(b{Zk7d=w{#Lm1~^d+ zAwMi;L%VS^G&BJ&ifD*oL;~R!tkaHJ+bNNbA<}@4?+Xn4Khaw~iX|ie!0VSCw~3s* z(4<7ocxV>1nqfu7sQ7;>WUn+$5z#+4T(JxIOZLe42Y4 zqdBa!k5F&pwl~mXqSt%kGwmT8SEkKNk2B9`@f<8E&}t4YUEiD1u@H>x9)jJ|W#_H6 z;Q6EDc>W(9ho%v14_8*Ed>OAF>Jizob?Za(nhn+pg-T@af2}btBgLdf0aF0r=ma{j z58o`@hM7z`FyJmxDS=tn3f48$?*`u?-9l=@rXfha2@S`xD)0c*M=AKpnz=CMivMPx zT?ZK%$c4N-nC}Eqz#&ghR~OhOpY4%&bTxwu68sd_8{h;Je1mvRqtq}I4%X2?FM|Uj zJTOe#Ip8M@*$F})*Enq8;qOve$x?+7zJJ6j!OypIidnqas8X_%jxI7GA+$31k8*_C zD|yp~nkVjGyCcXtL(swzf)*|LMQ$dC>xViqTixBg(Hia~x8mZ;i2<;!$N9W&NUP;I zBwSSEQcnMY+2iU=dfsOcYc>}BFZD)BhS})<6qB4TWB%X7Bz}*G=>v#KVmVXWeW7wF zy1nz;NN^7?1MjtX=%8^Kop0ErPcDzZm&=g4*GKdo9o%=e`5PdXPrD^0jVofhqrg01 zw*@dyp}CoyeChseXs86fSw!7BkV}(1f9?30V`kgin9oqMj8McI=&o$~GF|A|W!cQY z0QJIqwShNp?w&6(2eyorOs5Q>M#^(GXNkIe?g_5=pHqac%&;qgknj6cT3O< zgM7nH6ckV=V5)Mcpsc@B@=4IOIkXnU)#&6jGP5{wVVR#$ACNe)M^J!PAHcD}FRB6s zYf&o>zq`-PiIFBc5}h(E4?3<{;J00-k-t)%poCE1nim6^=4_fC@0LJJw$*&{0}qY@%ygtAL^ zq@qIVettU6^LL%U>%Q;ny8gTWx%=aMbRI{CzTeO1JzlTp>p8d;UP6R|u!gqZ|E7-2 zn85rUnP^wDS8+=~xjZ{H)ja7=Fmy1N;W1Gxd#C_<#ddAnBzjXcuonKG=@o_gpjRw% z9vGU;B7kR9g^+ba3&>)q38V>tB&o3yeuEeYZOLk;Dan=Be2}@rQjfK3XlyJcIr$Rc zAI61%|6-NAx!468Xi_>_P~h5N>;YBOvjgYAyCTjrn6CNCjN*xdrzGZ-VmDKH;RS`4 zdT-|iYaI0B`CTI;)G?bH;Hd^PUHU0ga4U@s46-iHux}gzujU_$$y=+oe<&tbXyU>5 zw72KG{|a={qpss51uoxwYhj2@l+(DwjLcbo;eOdf|>jTI#T2?|_m=bKG;41^MO}y&!r2+WgV-ICtf(KV%N(GIc$ZP${t zEx=)aEA<;yW^=~wP{I}tEWmS<@&B+qews%_SHrv=nduN#mM{X*LWUOgy1Q%jFp{C* zmvm0h6v=xi#LX8$2Iw4a_LJH#-j>P?)3Pk_7^qK2;H8p!=smy1#p)(I5XW?0F2Um) z!W>dYv{taJzzV+Ma}ek+{fSix`ZvrDSp_LlR;(5ozfyCfJtg((D1|5Gw*F`?XR}#B zSnKeL-jCnUPaI;{y_@HChE>Bgcv*Ovzs7{hveLL~ix*ge5NbV~J~MNxG~@Wo@*}=p z*Qk|Y<@Z1FKh{y?Z2Rj;fMC$VdKGP5-H;GLteL1gtT+CHzwwytDZe|sOw>jYoiLfY z^?!JoJpC!x)aBlL6>#FGqiOBHN4I4~zM4eA&A4W)Sau_p;5S zCK>xrS2rVhAN%qBp;4?->Fn~df`U72MWtAy{O?EA-S4f`4)6boSNr}0(ny%~Z84H+ z_K}mgKCB?IlXqeCO$tc$c?I#CVTBYr;4aB(`X=j&u~o-4?gSAPI`Ot0396?!*7GC; zFnK`=-m|c%%k;ix`ho0hEZZjiS|BmJT*;_#aw1kYl-8LILt%Y!JJL#*F?LT~DzV}% z6TD1vJi8Sfa6-J3;sUCs_q`8O<*k&rRWp5qDyRT&c5Q}&0Lnd^@zcvwpbMr><4!QlxZN|?g`>h# zX}<+)K}nm#?m0~M5f%(jFUmh#hxU_c+BNNziQc0E3dqy#$U^=&HTC>fTZVzmg>FXP zumj8d5{l164%24e-6?8I&*B5Z346%3T zHXdyHuB`fc*~sAV%eeWG<&9sB3Zg?cQRg`h?7ChNfAUjI+H2p4%=;o2GRpfTYtNrM zcUeBhVu!&bgT%YJH1(OwjnhIGNO-L-SanojLA6u;>#Y5L3E+y09^;@~#E)qZCz&whrRkiJ-qih^j;q`3SvDJ9 zc|8r&%tL4|TUuHu&Ih0zSo!e-d{PWOUib9udbp{X3yMqr!-w%|f%(He=2=r%w2Ij7 z4^IH`m_1<4HcFY2#PanBvt8U{Qh0r|EAHkb{Ni%k+yqBCMuT7cJi!`41zk^6q*H_Kkb7_KJIC+6es&F+wBXk zmT}vMmKJMY>e5qH%}aJtlhS&ocy=Th&0D?&`v}T!5JUhL0b?!}HPzNm6RG-O@+S`p*L@(5zuOkUWT2W#(NG&oU0-pilfras3IQR;>L+TmEp8m8LRSB0r8q$(UCZ$E)c!WH{F~d-YNmpLi`O63TveJkA zt5d~}HdpMH>W&%SpWO7&)I*t zBEs=z;fOJ*^Il-~Y_X7MIlJ?Qa;T&2nuVq5vtS_P7IEWA%Ku*l`=+0z`83SpkN$iF_A z%I~<$AzFI(Zr*toUFWQpiE;T%SR8M=@}W_<@f<&>-fhog+#LgdZV|Q|*VQyNC2T{w(cpJ=U8Y5htEa2$D}L z79j{~36vq@bDi3&v&$-$u-7w1$1_fMaW8_oj>WQQ;rjjD7KGt+Mlw{>z z=l-P$y`w{hXx-ZcHbORne6?WOVP^o?CAwuZys%pU_D*NJB8 zYadcT@;GYv=Cv2|ZaNKf0F-vi)(~Me(cMsy{J3bvc|Tx^IXtfKzNbW)RdH8zI~&k3d2q8n`0Ml(>IT!6v$|I-EkZ#r zx5!vU>zK3qoT=$B%v+a=POQjEbnuVV`q9bArddNF@sqK^;LLw=jE#bl7gjf=ShVE1#{<;AOI@eZsWJaG2sw*9?m&p;O6a(L2so+38HNE zGsSA%Cdf=NOUzjw0Jsc-UL_cuPOaT%f;Lzjq!Ug~vve^0z30A1>s9WhRwPznbvzvG z@f>uycDYHif;JX#>OCNMoFG3V-U8`$*ft7Y#sA)VVK1mMD7gG}3=GH;pTB<%(8pdo zdCB5FnzH}&hImFgn|tSfOEfvb-NBFc2N<b+f0@IM$P$Y_sIctYQGst$g_cLOgj4WGgh3 zlom_NCf`#9D;^9QB_EGzTR73<~x%p?&)lDo>CFt_X^h@X zAKC>B=-FIYcsR}6x+f&KGFs2>u`)~jKNvDl!y*(oKLlr~cYJEbPd+($lO<7h7@1Q= zMV+r+ZR6a%Yu6@|4M>$wmC+F~i>Pe@5{BNct2@R{Pl7oFDh{Do6a=CZM#xEdwwXRs zLkj{f95Y?T&ypDwEpmsK)6&zQqtbxZXVbe}*X0@QjICrp5f}qe?B4KXEuII*gX+Hq z;X1)_%^Rv&eR1_GfR4ui_CZ;no1=0HKeFq(HDGrYL$OV7^Bu%LwF4Cg_B zokO*poE9)_)HnUuQP>_y!p5Q;4;oHQRTZ&LI8k?Jr5}O+Ao}^bwsz_S_ig7*I8{%- zqe#O_JE5Xd1J5bpyrsq+$8*+IdH#0dF2hybZEZIi->W6dFnzWqh34a-ljf%VbB}_o z)Q#w7FJ?$78olK?{_^f!8orZ_T@)syM!lzkz4kCpBgy*>^uxmW0rL@h$|^_4@tLgTn97r3q&ah%4PHp zIfqXua^wgIC0`V-!am#IJk~ZAuI`*KO$a{9shofFQKFx$I7TPRVktI28TU43XYZRg z%lMg$y8K{p0Pk*q9a&7*F-$rjOM+_PsE zah~SCs4b?y|AX36zDua`$a$6o@f%0}UpOoVkxU9k&Peqj%@+9a{ku-0`4iAsiFr6Y zL~>aj2a%)~8~eRi^SIr`IlMm*{IpztfcPYfuq7z3*m!%+1cfj=wEaEKnEoDTvC*Dd z^32XEZ!fqm6-nxrST^1GEA@ny>UMm5>(BMoi}fifDfjNtrMzx{qq@3!WV})_)XQW) zkdfTJnVhEUV&Z?diD1*MS7fDWffL%u2pcDOa0dGNnSTrXUFTSO{ah#WiOz1`D>WIMMWtuEniX1o_S%qZ6UHoe>7 z$#r4-8{Dvh6c*;5^0!j6oM_&)jf&w0^-fZH<=dlMLbqC{?3wnPdiSUO(-B9u@pZq) znDcvNCB=`$>k_0InDOB~#~0C4BB#?XQLQEg|R@uWLpfVdCdIp zu%pm!!3QTz3j%2Oml|L_}D3##Ph9 zLAV9;^YS8+_HBOF!Tj`E#Mn<{nf(Gn8%i6mCXP9s)xj1yJiA#fN?dI(e?H~Ga{)gs zYwk>zU=uDYC0-IC{4wb(pjs#lT-R|eBNIA2LC%MBE#OCw{F5xT`1D4%Qf16Bas6L4 z$df{#Ldm_&W(ZFh$NJ@tnRER@cmAp8bpQx20A($8d;)U$qm#DDB_*NYicy6+k&r(lkqhD_B*>g$O#)P1whSx8=h3L^U!X9OJB zBa>)}#Uv-Av?u3pauvz7^Z~(terNNqFfTbz+JFAt<(a)&L?RmrNw<6|5ui#!lDKmcGztAkf1rKSD-{B|n92?>L@p>>}? zR)dm-eYCea{hcv31$Dsl^XSNn7Z20ZKj6hFOiz)dDk2Wbl^}WnXi<2HLC_=9YRi}U z(6@SFga+eZOkNi@9__p*z=xq2g26dMA0Pq*L>AGv{`$}+fKCC_Pf(o)Mw{j) ziV2Mitn*)tKgkIxg`~UH8lrEs3}_Ou{+c!JuzS^eG>(p5!r&NZre1Q~-Md%hwvu>K z1gjpLM*j>6tpdbmuP~^@fsM_$A8aSX$M!MR)qa>CVV4LE`jcO=$`;11hXQ)SNb?JQAk@%3Ea>;*b{2Aaj zZtg!pD-&>_KpoC5?U_Ri+l`;jw0Cs;!AugI)zU17Kkn|Z3=sWUjYtt(b&pM%NjyC% z^rWldV1e+huGb){NqWxQcI&m;jk*ybnFm9W$W>ia!$42ZbX0lo?x>_@OefgWa7cVu+j<%{>2e1$KKQc0!S`TjH0)aM-)FJSR5^Y}nmmK`sF?JOg#a(F zowIXR3bq4&v;aRp1t&x#nA*eC4zweyMEO*(sGz-m3@^;cF$d)nCj?EaZi`dfJ2{~S zKu{8ji%NLddw8%2ox2PLc6|K1;|LW3(}Q4+Rxk)%M*X)&`0|=x{1WCyx0xh~aTC2b zf~JgF0lhZ57S}sD~4*{OhM{uAe+L(zHNd352v7*CMmbl&6GjW4_b1R54F)G(zutQ2QEmD&r6f$^weNN=f}rS zapHhS@zi(D3`B@!MPuWHJmZV#7#jX;2yP5#YjOa2rZ(8J#(n2x+-q>cDMilp{`~d?=jI#c8MD)%J{b(eL$w0; zJUF?a=tth$;rkdJ5LRZmO>5ak%BxEj)a4TKLDU_xF>e4sgMs#|v9U2IYJehiyz=Kx z0!g&qYd#jI3GiFQ*mKU#>`+QEGY=xcQ{kktauY6Bh`C#z zm~2^O?f->i0~;9k6!Cmda^Yx$a1XI1d3^6MneApK*q3?6vlnhVo@Hij`R*LW9A2Hp zgAxLQWvoMF(4vmM9~+yMnR(#g!Edrv+gZfhM@Eup-GSKP9CAND1G^G9>u@R^z7L|n z=XOud77gnC>;|?AkP$o=?u2zSY~RUmh5JNALaMZ_#+ z_z2_vhgBXJTWbg~&U*N;+{bDthJ-VmhE4T2HgPyDL_kWXMJGOdc(a91O&W#pL!DV1 zU6bJE{+gSdq-SQ9hN~h5&(XOWSq0_|m$otRYmL%k%K)H7cpN@PVMk1bA2%R_cI1p4 zJ{;Aju$PPLBkr5y5O|`5t-fW1``J?ym(r5#C;M2(vkTHu2~JVWYxP--V51OTgLwHO zusM;y#f>El^Bk!kI}bv#gupghOMCk^mK+$m^wt4Q-#;mr*#3p#RsG-5y?Mju0OfUdVJF>0t2%7J|~C zw`dgVhy52xrp_^Nt3IpYsRcZA>pf5gga|ArTA z8=(k&Tv3r_&hq=XT0KG@+teOACbZlLb58fY6f9)~(LJP+EVjV1& zg}RI7GCYHDX{~~x?uOa~tv)JL`LdlTS0u(RmYF$N7=Htc@oH#jPP~YKzyj7i{NVS< zrUEj3g|W%&Q0irSP~Fn6X5rq$tIc$YjJA6a?@%GF$~7HsySl@pQ$+WpyOfCbSR?D> zAHHao(0z8lR%>P3won^Pdp9|`h}FiXgVRp2*-JtRI59o;>c zLP0o?R7n$&7fByS5)2c)Q^%2*)w=^+FP!cWP!!{igmEM|f@fAvr!JU4$BB-16x@Ja z3SbVI`_CR2WF5o$gH*gtus2g@7F3xF;{#n?ODJxkIlQsxf$a|cTD;h0VZoL2&v9^| zK0ZNVXK#-*$uZCml~dvYp@P%;2c3^^jsU*k+%ON{5DHElbf7EZKi_o54QB(`zvyKW;^O#CDn1cuA~dY$RHMqvL83E$ zLZorAJ4>5!->du5%(Cn>if?xjwn{{gpHkl1E@sH4_;+c%Mn0B2g|LLgANYMMX7iiX zyb;P^vGcA)VZ3S6CJIjYyP!{;JS>i&y-QlM_Z~NNZ@ye~?L#CLC$9MYu-+mvDsXG* z>gu8&n_UKh&Nv2*{|Z2uW0!tO-s6Sf3ZYtQ*r&7~aMa2q=t7CItcX4kH7&XT)FA}% z2j5}Y0RshhuOaab2yIdir~!k3hgyky@EFc7a9uo%(=mlN)ZY~9SWtvRSV>8#>opK@ z+bj{LlDyIbv8ZbSEyjN`U3<1wwloJp&IDFDFUS4s^Cd)79uJ24jFWf=2#{%d!ud^eeythW8B^ft`Vz#N>N zW)iVoq8WLa4@x*@1ZhKvKoUnv3DH-BcZQp??a^;hA;-5uYwZH}UxC&4GL$;>Has(l z3aefpBH?&xFTQX0n&Ycs%Wu2v(MYm-s}pYxP09(04&-=GQMM7wc76{~8{RXg`dTB| zNjw#H2e+ZArmj)%Lo{<2q;?p_<4_u`}pAXD`8fi~Z?O9C9bj^>IPsR-)3J z1115q5?N=NsBk^ZJ;tg%uFmE|ffM3GX)kVY29+hkHkBz52BljRlbD>Wk-`ts*6cPq zF??oxqsF95uo7Df?&I9iOYaUQnMaEaP*Fm{+R-B`cJ%7(EuMdjlZKhlM?Mo}0Bky|7(mk5|4U|uvDaRY?9#u2qn`Lo;{?p+!4mnty z1E-{99B+J&q{x7y*LL9tENh)X%kpIt%K5vxUJvh*wtd?Mh83@%?mEjcl9?O0>_+MW z?pHeJ<4O;-J58b8Cj^S_^;l!SfPmAPJs3DhCoy>u286&RSKQ%5t6HY91|Q4pOW~MK z7{{uuQ+&{QTq3O$pt&y;hKm}0H414ESnOk)4#4)BBiF@_Wp|NAi#J1_<+p?LMNiM& zT;X)n`kVqF51ED0+{#vH%`fJI&MkHx9#l(9S60|4m_z_E|+Q} z9-&_3gD(8{cke1_3T655H;VLI==Y_5AM0 zcfWJjHom$!-->Z#SV-=7#t!DOi_o^6UjL0~>2uNzS#kd61rZAWdZ3%=^-;ym+#^6A z=yZIi5pROZ04*n!f4FvR!_698-*0l_nx3CuM|}(x+D|B(q#K@`=E7~X2iR8D{@qjT zRt3TN7>djUmS<*$1vDHFToVn9Ld!~+LZ<4Tw&mcvzZ)W;u7$v_A1MpJr(yEx}l(GF+8?;$5A z@0EVCnQS{FnsU>_uhANSMyRf??-8=|d3(Df?iU=TxTtsJKT^qH!BD(#De2CgXKd~3 z*ikT_!7YxLg8K*+d|#_-{G11Rt~DNCtD1g+!-oyN$zrHoU0eGgSzN(iyw|5xzq@ye zBCSL0z?R;E3REcwqZkw1;m0&zY_B#(u1t~D3>|;c?Nz(2#b7|GX6l?c(SiVq6buwx z2AB!(4S)b0on2y$MPoR~!M)@&q?^euEu1(RHW@hoS>3+UB>#nlyMS8jOy0n&siXFmk%Dcm!uI9p;#M;&t zmY`wv>5rj?hcIsY_KR?Y!;l3c7Vr}@pM^xjy9a`KqYRyEi2hAe=c44qcoDwFHqg+g zWscxxtD(}1`*2_-BgQVm?}mNZt-VuhcW$#()ZZ(-kt}|KLf}!ZIPS%`OG3iJ;K(wZ zZ7Wi2mM&oK{UN{eir;Sr#vED&oSFbjVp#0IeQsy(9p5M>i?0^X@4YPhchwm8{G1AyYG-23QBqMk5=^z=4oj?< z%Dl8Vmt_*O8#$ZlRfwnlqf@O#ECQt$?qhLi-}(63#>N_;>RDDUga&!^9-K7BEo1FTc4}kz7 zlIt_0;X;!rsr{Kf_RobUKR6vuiI;y_WwoYJ!RJ5tz`Ofrf{tc&SV+mJE$U)>O-(Ec zPy*LDA@2Cu0GZy278}s~0N@)#C?ReKbMjS$&caVzeNfxwug9rJV$!}NVp*Z(McP?L zwnbm&${#j*C~jZ9MOI$DItphfm@MK;q2va5gOe)_pGu(kRcEKIG5M@D_KOMjOB`)F z5M9(ReZEpa2Fl-8;o?Y@4*|MOM$N25F+0{kI3^tbIllS*%>-d9vW{9*9IF^Ux|g|R zyz#OquguQ`QTQ{&80#xXPN-@MY>S_)e7A>BWOLlA@Q#zV0TZA+p31+!WrFAltoyQfU=^ZQbgc4t6w+=yzf;0N5BreJ7yc9%1lN< z(R+fBmgrOWGqoSuJ1IV+a3MC{p;o$MW@1>#@^|myf{jO$9THMf@!nFj2yX`l$*CAF z)LSib^OwqwuFPxL1k!?^F$XCubb4|&a0%sVhSzqal&F3yzz=@!LQepg3elioD{l`| zYXf+qpr|-I4OlWa*K1;GN+m#^>4^19w9OAUeD&LD%FD{`wOVg7c}CSDx+A958lpG= zz_n#qxI#V#oQ07qNsjusk`!isC0JS{`xtF~-!7Fkd5uYdc=0$5GSyM3W(3QdnX&cW z&zA$l0#Gaf?$DH+xUUWR+^ulBdTtrTF#^MGGH%3(r(`4TbK0q6AT zPA;*|b}^Hr=4Cf$#zTK*`wNFK6r4qTiUgi$nb6~bXcvpYv5RQRjv-DQJqFa2M9cEK z9!?HMfmU-HLDG+;)Sn(cM0o?KRM0YLjb%y-A%i!Us=5CGeHjEN|xMySy1Y55zYm=wxMOuw*^a?7v6dYx;s@vg_|kK~Wh8h6xan z*=gL%7rK`JX4M`uNQ{f?;yz^BJ|2#BuJ+31?5^vfQm5j$HSJ-}mJ<5||6b^Tm?=l# zayPmhBr%xx(4L%VH!bV4Q{$KpFZr4Rx)K<FsKFzPhNu3l~g2<3b99B!VpjsujO&s!|I%uD+?P8@U6NEEHlipEeL3(Ykf=()&* zXqn0#tFsPWG)~oV8hbsT8(!5Hk(S~~fVGY>`h4A|ZeXEPGxT7j-61j7btzJRDlX^ua4*`iT2+{{@=Cuig z5&I4SmlQ@#U~6n>KYaU)`ldIKFl8w#Ax`IIU|6*_HLIl7$&DN02e`PpevQD833H8t z*ermGIQIK(SFh5rr8j*?C#Waz#xfT1Xc|7{Hz3f{XkgR0>WKw~aK314_K=g{8;`#ZJ#J{(Pmz85;D z1iH4#uaKA94WBkqQ3=m05zED$hlSkr8vpYE*O1G$bc6}p=ByLl=hPIH(fa$wtFxnk ziW4ExIppi=biVTQTmH8xav7)i;xr-_IGs6-?||Ah4iWU;}`p0_+bE z8*ohUOXJlTFp30voe~-SY83X7FpP$EmaU~FCN!lu7*TLwWcLJ%6rUa)w3^#X%xR1| zw!{agU@kj`lLL)28dxqY4bpuG#9Kpg!<_h#2ccg1t#!>@E-mDPJ7^z1{e^7D@%~~ z@IzrVkF3LTR>pkHPSJE4)p+tA%R*hcim!NK^#K$H$beihUjecMr%&47wV4gp`NyOD z2U$5qpJYV?ii5p`^Se?Q>~BNK0}&khNc=6!-MVR7Fs@1LTbhNxIF^E^S~y6PC}2ck zbDgGDRaF&w_3He^Xfi7{gGjp|tv3Nce(k9D8JDzmcWe8loYB`0#OZEaq4*Xn3U}=r z);6^L-56JkTLMW^!(E z4G-_3#_VhA``7f1j{61&Qa8-$6o~MuNYcVDHRyT8k)*Bg5=|v+4btBAQIWL0V8_Zq zp=bley~mUqx(H;{IuA?sZ^wqhQn1lC#)NYn#R4JB!oPNLd0pFN;0?M3m|wwS!iNsc z!&{^LJyqdxm4iLxcTj}GWwK|WAIC|7zb;-SzE`Y{{^rL)Yvn-ulH~i2;XO{c8MF!4! z4R*CuTSWiL#z+V68aoPkqjoqZUqtf|FBg_;@HF#FOWR~}pq#K(7| ze;x^q?+ZO&-OS~jT3j5(AVqywTM14UAQA?8dOVs1d3kHZEMaYCf4@fWQ|!!9WH;h8 zDel}-ZF&h3z_oj1H~Vx;hh+Y}F>?qL0VFx05-12Cz<`U43IQ8TVDa_``u5Ia1~a!!6~`Ku5YeS# z0_S`I5r?1+f%8Cw`58o-a$frNr3Eiz`s2s0{v#1kED??_F!Ddg<|ZKW?R$~N=`~4- zh`WCCucUI4lp=fGuAW0H4iyi^#J0BIQQ8qJV|EPf{V@7vOc4NdAmqg#bRSmA+W)Nv_e+Q7qrk+rW?j>?ipY6v>iW;)(*+fN2t#k&ybu4IYuUc6MHb zH}uDkcsg)c#wfRNW9f>&YQ^n|oLe0`PnJ2{z=?~wCN4@;Hv|E&g$ifi6D08=!2t#( zz!6qP0*iODyl92cTS3wMn#8n4LA|QAKK~hq(nA_OMi1ODHSdJi;#9^PncD(JbN)+Y7 z+Ek5bdU$wd0I92-x+|x6mB!1*XIg^;%_h$1?J4ZR(icjbP;=M->?X)fVj*>Pfxg7A zpSUL*aMR+RROH@qnemtw=?FqfBtTb6hIbTQ@T2UfhOTc&q>FI0e$$v{(74%AY|-eO z4TSZ^>h*>YZj(^dZurKW#TVWV4E#W*#wx}Zp!_c<36X$GCLM!T$;8l*NAu3BNx{11 zyCprF6~=Q&JxzhrEhHS?1#uN%K9bLx=v+V(K?)_A#$8%A(Rce`%m`;Dq@|pG9|QwP zLzohRR%c>hkkt@MTAUhSiAO+<;lyZ_TZou2MvuT@R8HNJ1MNvj_YZy8xtVv^#7;*mMP(#IyJCo(8w$rui z*R{Xp=Rx{BAb(Fl9M&=u-bzXocF;dy;6RALfyE%0=R4}sVL!4R?ClGiDdmE+R<@Cl z$az2~4OcN-2%_E!q0GQCA+ktd0)r0|9Q@Xyn2WL-KUP8W*vf7nOPtU6AfU%IsYzj6 zk80KEQ86ee;B3OCB;&KvCN19#(C@m!A{d3!JN%RkBlC#ok87feZU?JmDl6tZxI^yV zyI1W2?ZwO?8xmHtwMgikupWF|U5m@g0>FR3B1fgRhhsFy;}abqX+c3jbktxxK{1VT z?$@th@Xzgt#RUZGmj&EwE-sosh}J*OgbsS~HxZO}XW26m>3tYwa_VzvQ!JE8FJG7@Tm%^DaKHh~r z{Etb_tviOO`S$JGH~7E_TsY+Th1l-Dhh2aWNZ9$locszlFfL(ghUb=-tyy$%b;FJk z#Wd33aS!7!{yg%e#iUP_qpDGXRsqHv)pVbc7wS2q)vu(tu}N_*J-7{P7y|^bgR0oR z;bYraTeG6Az`Lsbv-0g53IZmF4=D1#fNgZ^=r@eCV*+@P+_MIhvAT>f+CX(~t!@e% z*4y%rkjFN;u%Lb%U%Tv*7%aq#Zp$4?{(AUCV&J}ELWK`yQ~wLxy&T8W}ih2Oq^N8GhP z5w0NViE_NPtxekP!xooZuKPI}<8g6u2#tvp`-1I@?u0-Q!R6`!E6R2a6w11~y6UZ? z81#*weIA{gI}1+&!;O)h3gDr=;OiG_n=-9(4fc_$1u@_mb5QZ)$6ka#g)U(%4%%@) z#~yyerJrA{a1w&1Ld|sKA#l#N264EJ9}l{O6R<{LFVdK%qQt>Vd13$C!oh)so<1fz zn(JaK$iC3D;7GHHse+|4@g49VFlWcl@Vsm8xWcvT6m&$Gp054){Cb3;+B7*aF#xWi zh*EWaQEJ&lwdimgM|a?trai-4I~72mgbx9COlis&d_oX&;)&|ZH^4#S`)u!tzU{;b1x^@hF{IO=nXWoBiy9sd5r#ho0Q0+gNFyrp+BFIX z2M1eK%vfABh}PJE@&ue`Z-XOe2^%OAX$6c0C(Zo=R=X~xP=MfY;Nmq+gAaWyBDU=q zpuh37+IO!N6tQE_SRr8zHr)i-$tXdM8;C+y!X_CAF~NsN6Mc}23l_PRbz4&gIm8%( zg8rbL{Yo?2g}xJ$v8Lu`=fU#X-y7@p4C$W>#TOrEG!!OcNq|rOvd#}vQ~2=XSM!S( zaE3P9;5}GD_xAboD*-p8rKFl(yg+W?t##8&D7y*kGqE6qe&y!!x=58EJ;tYM6#WAN z4TT+}^60;~ySiTRpu}xGyhTz{5)ps(m?aIH$y1b+mNHAZTf<`)Co(4QLor-pRRW!M zEQ#>QF)(0dVL2qD_2v6_(2E+>!zAf-C(dF1gjO zQB-z)vg~sM`$=pD|@2fI^q(=QF^L zf%}J9cPoH#jTqk&Zitt0NH0PNb7I^Q5Rns;9SWv{H95 zF%cM!vlxq*shJrpQdyn7}o9AL#0d7$vaio~XpI1F4^X)G%7KWd3BDOl` zBs40w-=XICv-&#d>+d(g8slIZx*l@asc^yb4sx(Jctu5{eY9(L7!FIjs|>Sl_C@Gh zsA)C8v4R`c%oA)^L;F1@`n~U|W-1Im!kG(9hzWtTfR5X!Rp`dJ}oP2dy+4D-S>8TL)8*Quj{kjAy}~ajXwfNoaXp~Z-j(2 zf|eu7^Bqm!I-E%i=^mLqX-%t4S!dI3I&Q?R8oKI z`AR$$h#*R)pz2M+O^t&!OQs|w`6<6BHMTecyb3-&@9pg!9ZlAM&xO^?!iE33_^b`1 zkH>aylxJ{m$jNz$%4uXI5TCtP$^*WLu_N&iP`E2jq9Ev*?!@xOZy;SWTs;Gz3d2dU z`Nt(C@4w$tFsr{PB_{S5wHNdaV7=kgT=36N&9-Kd+{P^9D^%%t^6>r7Z%ab#2o1Ri zECd&~!W>fYUTfU1e2rx3&c&OP0MfXq><^d_ z%>{)i#bu3a!dlwquk|;h@T*-(1f!%pxXSL|TmbOYWTzZdRSCWk*zv6b`;kI;<*VW< zrUxM68yyHMn9Igrfzi+t9rS)(U0RcseZy3x!#=(CJQ9Nwqvp`|p`fh#)3Yio%&@pr z1GIxMGU&X6)(S<)PFmWhH5>46L!B!e$a5-FXOx-9NPJfxc=VeXSbChC!9&F@hzNnf zJn9>TyM^zxbqQ7&T0~2>D0~f2!h%hDTK&I@d^Dg7F(+OsHjLA|QsrvHW!xP&7d{w# zrrEa5>e!6u3pym7uHpyb@56BP^`#x9{^jP5(9~+@7Sr zKo21xS9K$ZLw-cw`|hIWdq|1bTnhsp>tkPfgK{bL0OB^A1UjRIXbY4|201V2&u^%f z2gWzzobNe}^Ixm9N67H6wBg}~q9XVnIbrZq@I7VMb$C8Lco&H}pD5YH7yajQvkil( zTs8{@2kzLV0HJ+6^rkT^nV15sqkj=|W!%wqAn($#Z|x$(rx($Lv}u0SLpwqk5B_45 z_w)5F{wn5t%-0~iX!r>I=u&dDkXuFaxa-7T`hRL{8rB`y!Jy$BLIw3vMS{0|$FkNQNd?^z^; zA?U}f-ldkJj*jk1yt9(@-3nOOg!gK-Nd9Mm40WB{Xs^X?FWyRiRdw}AZ%bLC+)FjI4&W5ap`Poh8C zp%+tB0x(}B{)!z4bhxEze$LnOVn(`0ZKhA{YuCTrIHDrmsexh@sAT*j%35^>!9 z)A5GVLKcmhQGZsuh~RoR2}B){+e{z$i7sP&GzAbZv7+nfop42Or2C#u!#2l>Iz2gw zI`o!Tz&xPQA>RIw8#ky%XKNz`jm+LLUdpHTTVOml57nIC{r;}5+u+9pM&M6A`Z^yL z<+Tah`H@MbMh8zUiZ4tS3a-4z)MD}x=CZ?7%fsP6E#I;R>h_sQR-WfeuVL{CMjR&Z z;!hE^t$cZC0nnWm{3Zk>V9@&|N+3CGG`YYq<}?$t==1&)rPT3Tk@{xTmu~1wZeZ)Q z4h*1rWb@kU>btjZg|fdORyKs zSGqbhz@gi9UDSGs!LfKw7UMQ|7Z17HAbnA_0gR$pQIymG)*<^ks0 z@d0v}7-HUb%&A#(bC=3=P{xOag$@&$)GYJ+&`hIaE^Xs7Oj-s-o}hfkr+|CgaoFe> z3o4T~gmxdm=&DzRV)z5k=7`kv>_E%i7(x$g2jg}{EI5k(k3i9|IN&#jZ(|ntXA6Gh zu+AuQxW(#PTtkjw?tlsl*VT8&VD>LGz_KDj-OiIe5eB13nt9QDLK`#Re;Ls2;3BgtZmjrYzQB8)Q&HNxJ4tRWdvKHrgO9(n(tv;}^u7)}AKazsoB1E9T;+wZ7UfADoWmf8XzA``)Q0 zyT0%tM6=j4`TpS7W$N+iA2zM_`^J4J+lu*U>DPW7p@7s5O?%>)2kYSY`&YBuyX2IE z)?X}vE8_=bQa`2}`2B@FYM}_WN(Vt0fZrF{swM9-D?7W^q2n3MAWXB(JbP(q;uPo5 zGSd>>&-I>LZq;G>XfU7#T~kw-OkD{H`GY7>g=>0zld*~(=Ets|_mI8{uQFE_M*s&g zCTuy_M?`sUujgsK%h^YB_|n!>CY5)+yLC&i3pOH-lqAGBrJwGOQu;x8#6ug9Z*K;?R6LDRa(@OA2EXE{CR}7q^>W91Woh zmQT=hl228Py(mJG!+vxM7&i~vH<}(*Ii9t$vNC*-Z_!E#U%a}*8@UJ<1PW49_d1W< zMXOYrb9ppk^Q5f|xsud&+{SiFGee6IY(071QxSd1R^c8w# z0(5jf=VE20xXsD0C3pATI$DLQV|h>|QSpnBb#VySYj+EbUOMhed@DAJ2r*$nf*y3D z&1nSXF5Vja*rKP~U%wUv5CmI{++2&rdMr0lQ6k7!e=}hNKc31o*fl0Ad;{waR|(`! z>M62y9rhdG|Dy#3lf7-^EuDgAUxiZQ98>uDfWt(Vx_4Q{PRiaaGJ3IyZw3wNG|p)ZDuph%#FZtZGAQTVGj=B3vy zT*jbgnq+&UZ-t8tAf=>(CD`IBDrA)nrLdO@?h~yVX>$`)BWV=*t(#Tvx~q@dufq4aQB1-C<89z!g&cbqg% zv^Z^1j?dwCm8uog^rW|*6MPqK;XDRjX50}QDj$C@uN6>4D;(c_#Wjp+E0N(&n1;GY zR};-7(Y#7t=-LbH(fJforLI$EE1ulvTVO#_H}?zWPW~D9tHx(kT7FroBVl>im=)E^ zIWbvWQG)Xt?Ze@{Jw4Ip)^I6t&yNJetEm3mQ~A;Qi)*{7l+jC}n*#d~sz^Dx%jgf_ zX_x0C56bo$1iG_lMrlgn9tHZqw0CBj*=8~3q@9(6Bm+_1x9kA1R2^8eXMc9Im+~S= z<3Mf?X;M;AferjIYWmd>$DOz0*%Jsg7vc53bSH=p8 z%x7J6J=wPQec@GLtrolLgJ*2YTu=d4@3Ke5=It%M@gO#~e|WgPmfzdm-E#6SRoHV9 zYQ1a8Kdv*r>FY~69+dn&6-MC4QKAAiObB3E`uY{e$R4)gLWrpGbqcaVQGa5B;9Rz% z(PHzWQ2gm*t7WUU!si+k?-|0}y{^zn;+Un+S)S{2fRlNFBifBnpLW_3Cyf@Ovt*Od z6~VEL8oW(i$=8KcdX`$}QES%r+grh0_qb}E`{>aaJX2x?`~XZhQt44}4wrPY%U<+_ zUs&)fYjFlSJ?Wr6!BP7RSi;yhlU%=cZCvByf;X(NQ}n;K*qatTpvMVX%JAHNW)+^9 zqwY#cz4Nl#w|-D>&(C_~ih(HSpFNd=uYfk8$`dpy4fSypA=;Yl`ejq2N_bSY24?VhIDDMG-GyY*LeUQ|f2-Onpg5^ZGeI7S)y#vTJja84 z`sw06kZ}&HF4?c`-!(Mlsf0&Xpy8W~+d92s$$MS~DLRuh?{LjOH>qBPbJUdj4hb3w z)l#Ol&MUBksHW3jF=$($);z{3e{IR%yv=p>a*pS9xk>Dj4;m3SZhWXH5kW@^o>Jwj zk)9r%QHB&Hr-s>Kd27M5wK-WwJr-DUM8(8PvQB2|V8Jau@ES z)NRmu<(m(p>^0QIq(YCr>5BoE*5dYY%)y7*E;u+m0TpZ1tpjBkh;bk>Ff%c|v(@RN zz4T`JnW2gLc6Xvgm64IL?R?N$$hZogi^tWyj&^q1muhEN4;J$|dEbDq-iw8(>zoxG zv)3>{tNxr1!~#C$k_`ex6IL%E3{-;N_=`7#jQtxPXTsi%(5K(wO6>7rcrmm$ayHK- z9#S+St;+s=?F_{&djN~w{%M=y6BFUt2zb~G$HqKdU;ls_f5G$}soYiRAQpOslW1RU zZMiEe;~{kOK;w*^9SCAB2pw>10DGcZQF5mO=uvrmS9N;x5Cm{D#tNm;^z`(%3Np-y zY*r4X2ZONatn{Vx=x0d(ckkIl%uXsQVBa+7m6CG@v1(d8hMHa|e-L1&cJgEu6l;)T z*&H!Cc@kmt+g-X#OVRZZ2ImD)F=zc}GcgxPffPf^51($B5eb$0exH^AP~k#xJM0|nqB7B|5=o^o3F#WU-{%g9*7C>C~rnY zSgUhLd(Hs#h3AmM|>k4LmPD zJa~&RG^s!w9`3GKh9NMWfFI34fH}byt=2(80uTuMb+YcLZuy-=S8O6He~F69O3)j? z8vKqZJeJ`{IqAV(k!2GpOX5j@o*%krG4(m4v;tfdzEodfFJi%#Mm;F zPjsl{(Zh$jdlaue&>FyqW_?f{=qknIV+3?n?|uu@#cymtjvhWq7BR_Y-AqfU38ts} z&mmrOpfT+FvMbZkx97LB)4!V|+0^b&*vnH^bG=8l>H8)n;;9%EIJSyS>-}OI&`|*h zK-=bzWu>t(?QbD8W?$fQ?y?73_ksJz6zV3TS<(cw-+U9~DY?E=376nJc_qI{Ab%I~ z)$4bEr4qlzGc5F(8@E8fFMcT$g9As^x4@!e^sHayQ+&_SaILSOK%@T?sxq4J@Z6p+ z>I{}jYV;ACCc&49eCYw=vr;pt^)`LR&%xQAR+AX^HdzfNi~S-Q1F;|q7M8jDE{|7j zzkc(kBQn)5*J>Q&Eg_y|&rKMS@2_Uk^Qqf30i>E!rm(=cpr49Ij_$@sA|>6^xf1&} zu;hdeQJN^>*usje<83OzL48x{`1alRemtRCD>HgZ9N+uAe^~U;v>j49nB`|wWiLK+ zaKEnZLjoS@QGZBxBO%8|g2KK&39U2Ba$v5yqss=#Gd9;g5c~XFAt(GA90;ugB31>V` z*U{_SVjb0&-!_6&2JwLDss;cvkRbOfkr^9l$Mo&%V=*||#BPDsla-CF)t>A9yU+XI z;f|ZOy>=Q!I|8JxsUISM*a+vW^_;GjPBH4vQxBl+1pr$n!vdz&MALg%hS;UeXm}#J`0piY%9QlQl zV8nCPhj1m>wF@;Wc~0N@$LTL-`04$5A@HDaOm(|>`7++w4@Ax&=quO$c>5p48)*?& zop3V%8v#K?o#;U#MdDCbay5>H07gfFqzK;)>oyQIAmCI1^)d>Jo#Rb-=x|G-Rzh5C zdU*k%dQSl(X#)^y)OqK57M3i)(z@i7QAcLg@JH%SKv)wG4-e!| z>j>d_)7R$++Wp%*hyDF;k9iC7DTp=Cb4!n+mf~)DQ-5}6 zbfs}`fAqIu^elfCzJ7+R!^^85{RoaKTU#RN>v@HKaw?Y4&CShl^TjNK6B7ReBokbz z-u14TKkb0eVcGTK#a`hIqEG{gLm_@$pe>hRB?*qpA+Q8+Ph)2bgDJ2C0Q6@ekY~^a zz!er5jXF@X<7Nkk81o~bmcZZTcCWvceTfyS8=Co969z%q&pDjvH!CV&&=V6<hvDk=b-ZLeS72J`|TQ$$3s?};P{ zMgb>(kA&Zdj0^uZ5DZqvb56MQLa+H7W*3zXhuQRtchmf(zw!5CWd_5HLJfl*m#~z} z45!^3eYVW6)`IY4nxsN+h2mvPESVA{HmGg-hcw6k4E7`q*BHN4Y}*!X9NN(FlVFGO zpT&!V;0cV7BS+3+WevZ^=jM)%(znJBMW3bk%fO2sSok(LkGW;PLK~4v>661ONGe+< zSb8t3!Or1V32GTACwnRP?;knmVx2_n zLGPj6%FX3-7pKyZksTGmFV&$L#nl}j*UKNq$aXj+1Q#IXiUgS^=|5gmvH!eyvj58i z{QoXj(#ZE4)g%}|)~IvYRd@>U_{qB+kM;xK9gqF9esFs5oG3@h2bt)&V}ye<$g}<6 zYh+}&w*Q=Tz_+94$g08!3~8pJDRU^TO2AQc=y-l)oxxf_;zerK7BbmNOl3ffAw@Z} zL{LHCp~WSq>3Gpp>;(3_7$tDfB7LxmZ^r|W2hbxw>&K9?nS-NtDHA79m}4CHH_dAc zG82Bbwu7ip_^nR9FS?bn<&f}_N6E)h`jsBfJ+*+d8MI?HW1q0(zi;23?MMb_ZHGA= zI4;1%Z9WWZ8SHAlo${GHi9C%coMfzoLITZmGyJ%qpLQ3gA6<{1-?tK!LKfde(tSKsx$#nB=#3Eu$8_vh=B}N^^jf`-szuM?kdv*P{v7T2Lh&*uQ12YYzYeEgJu1dB}^TKSlO^)KFkWE4B zGQA+1FufJH6-P@?96t{7&1bL<9YvY041n7LNXhk^71>PN(zZwyL$bzG70xe(PH#1b zJ470^+7B>zb$Q57e8n~;|nOe2%u{s1kBfr7IG5chXK~Uyfc72C}*=_ zMNxuzX`cjpTslIjV2AZ-9n=_5BW0c8_;SG6xk@7z(<4@X$erQm=LfWo0}uKeyq;iS z#Wo4@@S*{YZsIF8I}N|*P&3~S4aqx$R&WmEo$vlh_j@?L0l_~u)dmR-lGX~U$ulz% z5=gf*2E8UR(Fk`xP%SLUFi8`kE=zLB-+S?==)yfvS> z7uGU1PN(n?;DDeb>?FXzsbKSg6a>s8V7FkS;UvT{2v7(c<%(fM%pUn31)C_(XIy_D z8t4(udtny(16F@_74AXB-MyaoY8;e){Gz{~WA#bsMi?+NX{>Is%fo5}I6EBJ1>@j- zimRQs8a1H)W3lYa!dQ3Uk)9J2mvuxh{FExvIU^*hLzUq~Mc(wA-XX`0T&iH8WqSz6 zr>AD@>=rDCtj?SkG-lXF#YQqFCt-H%Jok?F@}48_wI`b9Rr90=H4lczcK@!r<7IZt z^TjiT`DYsQrpFu4ny5k94hSEsM$l-%9z=5v6+LkMmX;Pk(;(`zm_by!M1E>cazg)bntqpTCP{EFTMqog|S%tMZ=r>q5B*w>M zbGAvK?(W^!=l{TL3_a3pu#pi>?H3rIMj>_*`)4?=>X6p`o){?SM8Fjyy0cT7sJkAe>i5)Olz46ok;dm$!O&dBGfSeLjDk zJ?TmAvGV_L0oIz`xD~z4o44VCB9vie`Cm|w8u?G8*l78P%b}rKoQ6oyK21SP%oF%Q z?+YUx9UZ{iU`>I^S5mFlBDhWi<@57I%n{e^8G0FDHFT@CMaA)(^Bx!T%QatEhVCI9 z70n+2(Y?>3AeMvV3vVzIvkH&MHK_x)TtFD?Z81X0z?O>;kRWlZ_H#IzvXO){a>=Rs z!h{?xOwZcX!{Z}*boA--;6!{Gf8Cbv<|;D=|0ck|yPzu%5ku%Nm^4Ob`39S#nwJ++ zIBE;8PF*8|-$;2s=o+sXInZemu_K-|JF=aHme?`pTsQ?^bf?=MbW!p!ce1?R2wL94d(1Btq5ye5mL8CT zTcpGi(KX9=j89J1gAxdXdpqXKkoMk!c`%qR=M;bq^)f&w?GsE*++k)IdHXc=9vL;J z(8X$eyX4xIKrrQ|QUzSW>;a5Yw6w5i z-}+pLWc+xP0_Gk^aoF{CTRAuoC*9WvUC+8c;?&e&#bSA=0rWxG zc)hnAqs%!de5tEelZwprv@MrpEHx7fi;y<_OfV+EfV!;T+g|e&OU^%QxVurcVb-b{ zx;rlIEA=jSU1KHnW{1YH^i@g0&#OWOxA2o$Y@2-oWr=e_TDoRSANq@=9XnvN6%epB z3cUq*c9t?I8&}u9g|C}vy*_Bl_0hFi136h%?;FrMz&8+y#ugXu!7;ZXWNRPcf_xuz zDBxO%_U$I@zX%&kx{M203R+Nl^qoSC46NJ%d&$ zsHr?(O<>GBTaglEfPw4A_3I*=0NPuPdx{BXcmrnaRRCWHXaV$O2wOJUySHSSb6!Xf z=4*p*`*7qz{BiRplfb^m*(@Y*`2`Pu=$&?9CAFtTJxLd`ib29RWb)Oqb2yWo@k|Ia zZZR3G_1jDWObtWwjG;F;z|+47W*8%nWp4z3zy~Lh;gYT_*)Bbxe{tq}azK*DZRA>) z3He0R{0nu_1G$-*Fw=bv+%X|)2i6T!6%daGXpeVng2GKrm1Wc=7l z&y0{q^T6QXP3Pu3wMZDiEn^9G{Y0H#yUM3|IQ(%Y>4Sg@D&-c{ZJC{fn{8bB*}*LI z!sund(gqPiACk_J61D|l7Fqz?<&jDq-BBH1K2UYk?ur7-o{-5P?LxyhGbhJn+7$Fv zq^`!UIMjHvF1!Ox150VgrsI9Bt->hDfNiZVxkSkBt+uTXDojkISsDac4E%Y>VPIAQ zrYic9%o8|ARzR@)_0{3&u`3@;Nb#g#bY(c~v2sC}BAlNPOFZ5jM;b$&(}K`%B{TTd z2MvXC6!1SwOBwmVS&EKF;cUxrFSa}ev;Dcu{pBqB_}FPZUCYetc34PWKtH;;i0aj@ za6pQ)w5W(rH6-rH50s6vuI>2n;AseDcw!VRp@UJ;~deVD8N;u+J-ug@jJqgZm(06lU!eodx@XyDTVYR(kP`UWfJd zscH*}=)M!bE8nDyiaU111#g*(9(pDi2OFh5oCE)6y#s80-zW2HZtm(?eF!9hpIl0* zBy2e`f9J2Sh&Q-k@eRP`d%xqEw`OfO({X%2cZeWD7{}Ju)%7dudqHOoB7*M^IPD#R z?ig@JW6xgMy-WVSzLwfaM!Uj>``*1Hj4(H?r$Vk!Y`FyMqD+RewmuCGwh`IgoA=9J z-?KaqUoku^=d@NqU&N-ktTOdWANbDfES`GkJ6GW7z^z#B7U$;f=XV({ zNlg);e1Sms@G&MPyg<;|A8J2x3x>R+xl5_x=01mAWtQc{hd5^dFFpV!NQC4F(FL&< zOgD6zEIn5rxqA9qMI$HtC^%xLEp!8}fE`!9mWx&Bs0wy9@fxU@*7;Eo6e!Ej;W(Fp%gE}}Lr9^Y8j z7JwsZT%(u#rnAHalk(k(W+2L5x?~i2F8(fFPp?lS7It=0D9C%CXDdAJ>*H7t4GRPF zgfKvmW~|Fk&=U$4za01B;VM@uTq)NJUd(N~@K+3q=I(Wlr_!^AlLP^x=@}~t;CAm8 z@jj*aQj*&X;=|eJ=(y*~F&$sWAP`1EOt;HI;#g#6`T{NV)F#eTTd6rNA*j;e`9y_MW z%?^Qv*d6PdVtK17{|Ch+*=rPxET+wdMEZPhz7@@$Z^sNG;R#h%B~j2Y?G|v*lp7NR zEH9RlXnbyUlWFw~51Xz%@-slUT7HDJuN>LzzqK~NLU4K-v0eBpFbVSB9qj#Xs^)^Y zXd_u|cHwiWuhDNqxi={vD`T=NRmS2HyD7xE{Dh+rEfpm6XDMuD*txijn|4R|z?Ql3 zh~3rl`q&yu%9!`R=a#gZ!taJF#U}3IFo{8^f9*&+#J;hOqq%e78+X3HLF-i zfCS$+o!GfRQSp8=sjQ@=V^JR5hby7{w>lUZ7(`N^Le7D+C$=;k?eqo;U6_N0FhcpOh2jw5tPPue{@<438KEt%S3c|_F+OiN8%mkQ zA?;-F2q!*aUj4BT6D}O$4!OGOrhW~=2(IzmO|jfXPE%G;b~eT2fv%y*e_x$1j@`m7<(zxR)gb&NVktZSiBKnd0&1#9?M=h$2Pk z-7rpHTQl%eRjdpxV&eMx6n?ZCR8DI)ovSNd1(TdirnT_cG5BWZZdnx`P9$B z$t{6vXgf!ee(%ijp;5Eypshj)oUapxm|UvL8aOz>1c3$dp1Dox51>)AOcn@G?xVG| zklu8`WJ3bIOJ3Gd!-L-js(bTQ9Lmpry^@=Y9@F4vw_?5(b(7^Uc|1aTJ1%8TUIlf^ zqt*e>0+h;F8J(`$9U7__R++189RTSD3`8x*r6Iz&aPcCvNf?Z z7-DNG-tR|jT)=JPoqXsiZavcrz%+RhiwWT7d2;TCM9=in6h|)hdL7-}KcJ`*`cX_* zvUXtT@N(+2T{m9zrW^pvIt<9RiM z>temKlN0-Dyde%vACv@T6Ki}n#JA9ZUe}w!Hgpvs&sM(7_i!el zzlVwLBW?6xVd1v{sl$rM$O-}U6k+YxVT7P|XISRncRd1gS$yHoLaY>rPbDtyrPw6V zOv=m8Om+YIb)@3`mCKiTSz~qXId*T;-KfnJMVgwxDJg0tL7IfEIabNC-Wn&OFPia` zJdHZsQZUrMsfN=7xL|J>k0-;PZ(xx9;!P&y7r*9vvn@}w{UzToZ@={P7=z^f7Iegs zHIeOQ{FRS`!+>cW3s#cfl~h6NJ$sl29XB&_wD`*v7n0sK>YD))(-rm>eVJt+s@E-UbmV4&i>7QQJY$4p=Ox~Vt>Fi8WD=V>*T==1L`0s@f!K(#l zAFbP9!(s8-W?m#s4!Ear|CAU%Z#J|sVt9zse=c8n!h~1BFlwXs^^KQ9cB&W$S(d7pf>i>uz+QfKbgzJamr6M!*H^=*ntGpe zL-bJ|!SC!0SJBUw?+H!IoHQkA5{TZ^>{{}fGfzT&0|P6UYi=~|lbPn3A{jyjIQ8Jr z5a5uPDv9>y<}EHp6qOkC20jZhT`<9XGrgh>B~iJEt8swlj#)iKdzb8p{q^%Fh^%rx zL%1viUD;OvSe(v!mcK&;k5hcFv6&e&=WQ6WwkK`sZ3eZl=-sEjnBb@4(!Ql=?7ojN z$GT*$V+CzB{dsB%8WXFzp7-yG2r)IM=VFd2&d=+WXZ3AtIF$sjWpjpi)VVRVJ;3)$ zRC&J8RXv)((h}Z1LPUpx>B?y2goPjr{C@}>0HQi8f#x3a{b6Ue(;*hX34R<<46pQn z#xQvMU@r+Wp~TIzn6+09ilsv6o_g~zhB;~W+TbFSRKj-h*4Zr)Z5>Wj8l}co&@owbaEj? zLE=Zt_2r!&W?L44bG_`c#P>EOBkQWz^JiLPyaRK@YqDzR%>bd%;h= zfX0QzR~w7s97%%>9A2Xq_NN!m#{18$V@rvJTJM!BNV99+lO98`6KKV!ntKKLQj$5%vUkB> zU>xh|sV=wLW4v?HeL$3fl%Gn2BJKUa!0DZ{RAhHr6%{0fGbG?Ie|!RCo?0aU1@uCt zdC>7tsIK80g`4-nd%U~d#g;iV(pB<;wX5UjO}2)O8~^ljOcTod5(ja|1)kG-66_#~ z5U#?T#7xZv`tD$~8tAsE+l7y{Nc@jI|0(-dQ3 zfV%MrSK-MDE6E{yw9Ggb@NuisMLri>?{j>H&mDTPg+Z;fgNT1oand|tMv!0>5T*Uo?;eFl|3Kcd#{>n@a8Nutk!G_y4F zQNcr^WqT5dT)$H5CTI_*eu%o~&Se9F{whY9GQSS8Tz~bO6~ejR`iCO!*4gWWy<%Fp zTfv~ebNBRVa2=)sRgbrZR|5zozP;+tCR{&%*k5~|m`rE`VAl#EalnHTETahCjCJ3g zZFU-{A2)7D*}VnJP~U#`pkleVb84}f4B1Sa4UE(SUK`NQ6%6r8%l?=QKmgRNYWkIPJlv?z z{3Ma-2htgau$xU_Vxwq*mf|vD_ULcF8?lHVD_`<-cfSL;Q}c(?-lh9M)}Rve8GCWy z>`hD8-1T}d;6aATwlE6piZu z%)C6~=+8m|e&zttEXL$zw>(e_2)9Hq%#>>wx&p4aZF9wP6F^TSOrt6sU%`48t9QT^ zQ(GQ$DH|lGJ+sn(JSS`B-7;6nK2 z!0Uhr@VzX22&)CKK2YQU=PT_9>U{_TWf0Y_ICJzF=eF+l7V=&bzSXHWl7>{shnMMq z-&on$ObuQG&^L#sFf{br*ROtv>XDJz+4ek|CN90CwX2J8Boxjl0}bZJ4bwXA7Dmq{ zOgGRx$$GymK=?O8rY$U7U+x|(O8#`6yI)M}R&_NUEp1S6@WbtLLvP<22)_b^W0YHa z-sBSmw~W@Mh7!tnAi)U1D~H%+$EE(hK7dY_FARBYD+JaD()g7tjyS3f4C1wV98!`m z9`h6vumnQ80ep?0KLNsKYs8QhWF$T}Cx>a;-n}?aM5VtHHy0e$d(Kdik-5A;o{6%i zrejmp#oXML;lte-`9!;x4^jhJRaS@qM>I1P#Y0eP%9E8)eD+8%laWPdXJ%zBg6Gw)5&el*6}i%b;k39yGO=9qpu4gfG}0TiihQK*ePx zjg5^FD+iGIuue27K8{N7ouQ17EiAK4Ma9U-TAW#Bt+s4|7s#%bFbV&%HPUb8xw;1;aM4+(vg?|gR#f7_gL^-7(?+Q@goq1;T|>JTVYj!As;v} zW^6!bm(4YB6`I9d$}}`mfDGcJ$9eV-cN8~?b3J?#C8x;g>v`sr}&B>gzraxaaDaQRvi~NY&XU}fjmrSW4ihGffV6#Tj98P9Mj!|L2b!_yB}-VuGNO_V;`F+M1?e@rV5{ zvP5+?k0G5v;Y$O>u-iob30MhY2Mn|F%R9kMy==!fD)dk>;VBL$IFp`EgSZ;r9ZDnp zF!)F8#rQapGJ%G5T^d zU8;~U{+x?v`{T!uWDCbpP*Q4YXu#~pR61kZu@6b&L3P%}mc^x|`I;y078X8y@uIT0 z_)+gw^5M4W&v|GgzuO4KVaEE6U2@R2uR1JbToPHHauEP7ww(uz18#@fjx8|80gR`m z6*~D6?b)$QsIO$Q+8}1cFcUeFyu5q1r*!TzHg2H-8HVtSz`ou?-qyfigUTb#^FfOZ z2EvGC)L2plv*AS%pCAPpC2i(S3sn#Z-P1H-f_RqYI1*|B!q+;gLgaqZ+}Sy5WieQ! z^Y6uk{D&J%Cm8zS=m$E~`ynd}?$x8QNSyC6q2MCls2vVA0Z_9g?DX+v4@uNqHKj3` z3z_TfnRcX^fdbv~7><2uTFYe}U7%4yLN_xDf{IH4EedkgGknZI1rLc`Puz3*fYjaF zw_6|Mj49!u9_0HX5|gE=$j1wvx$4%YM?51PXV(tgPiR+8Yj9su~6y zL)hoc1OsUI^enOX^tW!_i5qfjWqGH^oS6Ui(W9-x!W2TGAXI?|U{!7<9EY<)Us$AJ zAj^Tw#l`i5TQ#JD*i;A;ne`oTyoOWlR5PGcPy=X%&@2N0_BnAHMy=o(;D$qd8Wn{u zXcBk_n4xQL-Z3>XX-z|7U&HZ*iscO;AQSCQl*fzzZ~>%9upz(`(w!h?B6$IG!BAIM z7wGBbR?13B9Gf@i!w2X3_1$l!F?-G$Wz7;odz4s#9RL080Uf8$P*u@sC0CNfFT2l9he=>Qyyx+=hlF%)!8x z(8x~cap`56wT+BuLX-}*>foSlq51H=a2W*8DJW#7D({q_`5AMNhug)wslY8x-d_Uk zQkv#3E>anA;pX+#s^txcamIR$wh*L8Y?sQNi4@i({ZniE&3)EyFMW7sQgH9yA1Gr0 zK79Z7O^Tf!9#|D$&g~Ty@DB|SFTcuiIg(B0Pe7=tWY=N{AXAa%4we6gmH0x zz5q9O5=##D5|~4bdjefu<*;NqiO}p%1m)vB{BdeQxP!jlVUiA#HQWZ8VN<<85&BlM zu=JRjivTktHQ@|MXOUqiPTbQ?I8$2s88KTRK$MGv)rDLgc>54bTi8q4tyZEGBm8J= zb(|Iwb8MMlY4;J@4WbMWNn?Av*TjTGi(Boq{#7jPpvBKx`8qzniGxE4DLD|7o;zl( z$(p1e_2=z-aF~7Ed4ag%RjndSs(1gUYW4)(xpFwi_`JGm01W1%DHtszQY-k>glIre zf+d!3a`QzWMRv~x3ile^S76YXY0Od`iL8g$4xARIPeBFZ5P)(!%hVp^F6DE%6%B|+W#270Z0Z$e~r^h6KQOvaq#Pm6Y@a z$6IBB%X4vN3>OMpIAUqpH@$OppRc#_-pk6VN6B4{>!adcf_zu5DeBamG5eOmlm3h? zzn6nqSc{G-@6U#Xm>Uj{_1aKORkUFa^GC@FD>9oZr_?{IT)9hlbpx>N5TKYTU1IXR z8%GlQk}(0}g9j1zs|Il6hW)<*El`wc06|_`$f#XR`emL$1~Sv0k1hCGM;6d+wAgX! zq{4x^L;1_8I6ZNXLTt)cIfES+S^&gc><@v>1TGelN7Z{Iem`1R2x#}POI$3itlU@% zJM%!Ss)^0Uh!TJ-D5N>|a}--*vyX(7zTx4N#L3(%SHO2xhe1z(3=?cEVeMUg^#}HY zpnkZY0A;f3!EyzT(Y0MIu0xn3f^S?Rp7x3g4|(p$5>N~=NflXcOKiPm8mX_}j+7Cu3@vuz;;lB4fgSf*ZdvY+cjo6O z()|-|=742T_G?D2s~0oguKp91t`O3Yo9nR@FYD?*w-)og3`&q*pIrMt?qn;sQxTm05U~Ir-7o zD+$W>SbDch^xZAtNox>^gUiLA=QKJ|raxE@pumA0k(-;sf&h#TTxpEI+u4#pB#Mzy z!IB)#4}FImVDXoi1c$F(yLUsWp|ayE?hD+%SCstV$O|uF`^M1n;Jas?nvN^w(FOSV zy#)Ln3nM^$rSE{~#~aX}ShoGpG`Hs#12FJ|tG3`|T=K@7e8oVfwJ_vq;HY}hu zGrP5DdR_DXd$)W>Pg!4xY@>qI5}bF4G#_=ZJ^=RK!B^c=h8S z0xg?>fDAi58uhAIP4q&dY)M2pVY>7EdtmOmiWwZA5bIs^>ddG<*$XA@SWm!|AP%v1 zAB1^cg;^Fhr!LzWeuP{zvmra~w#>~D_Y!t`U~0qEU*niO$s1&w#Z08YJG<9%%ehhI zW$Z7v%8&Rp2##seZa<8!c6LK35%E!=-n}eIS`q}&a#3atOI2ZdcH(xgKiI{o5hBP= zPYm&M{V=YZrPcTG`9eT*FDTJ(fZ5STX@G`8?OYIirqCXq9tZ)e3@8M=4IXPR2&`Q) zDL!iGRBnX=w18hwWKYnHqSjX@COqR_f>n}q)pZ-Ac;`AqN=JUYOZ{`2wh(0uH(1R7S$$4^%ETRT_88%&X)fCz^i_W@cfES}suL3@~t0TMLMSgn95pph5CeWL% zJyxE!5cL2w_6*fCm=$oXx2T3ttwZ@+biDYm@D$+9Mi8x0m0@tPfD;9JOFdf0`XKVn z=fEi(3!^1U`z^^pAD=?Cr*q=W;z7k6bSA}fK&@4d&IsD_qQNGz3;@He90ulVwONd3 z$nt683!$0i)Rgy5vj3?dE*r0K!rf1r$y6)7bh>4EV{kHj+YQe@oiab=8kGodL-_VxNzJU`<$OA5! zAn>g+FqeQKK4!dPMaN2_h#@<~^R~a=D4=p6Dwuj}`l7P=Dhn;)%J6FveyxDa#>{&w zDkSGN`20SnVew;Yy5hE#2!dsx_avtivX~ybGZl)YHM|FI?f?;22fV%#>Zf(jcug@ z(vE|DQB>SHSC>vygs`QYa<2vh)NGyk_Pm<-RhSuiANCSIOFuQ9QM6FJ(Pdtmd3XKm zGgdVl3X!rPzCBcrL{fCRCS9!Yg>R$4i|Ze$BgD`qrRFkDm2Z4j)N`sWTR6^p&0?U6 zPQWjh{LbCG9b-RU=3A3r0FHszokullJ}<)goU>ZCbA`@OIKw5=u-xj@`^}%Tk_+cX zA5yZJO=K8tc}UZ~{k$PqcDC;myiO>cyL2h>dg=kG4jUyiC`Mep9#>ZGNUau>MK;P) zG{{79#GWcTDhgO!LN{@1T~|>_nq=I}5>fd1Mh%$9Hpw7oYldtuL6cPX#;rQ*q{znj zG1(`Q|XfL zogM7yMEAJs=(M2if^20nQoZ10vdNny?EUsNHKStBO2&hSQqj{KEXnYhtAb-8F6GqM za$nl}p5rYM^&Q>qrn=P`nYx;NF{+_<(BTBvJpirxE(g_B6}MC#C3>^t=Ci+lKVEtd z@`PUG8gad@UyHhfGn3oj5o!~*E+z}lJUHz$GEvd|O#ZUDXA|seXK_Ytiu#TRCLlpQ zDg6NCAnv9}N=E|vhXk8&DTa&bGe_`2GX`!>egyI@N++iI8i_bV%Fhrgh_Vr@s-Ybs za+;xW^>XZa=gdmHu|dUT-0WU=er>?IXl27ZYc+Pdc@Xn{DACBY*#$xaN;IVFd(e!Tz_mAK{G=(mLGYou9R*iA&;OJ=kqvZitB) zN^u(L>q8oxq%Zt!p9Qi9>|df)#9$0b$DcocE?v3=@ME|VpVzq~8)ls+!p^r4si^h! zN5SGh>d^7@sU$RGn24~qf>S28h$7=hI#@Y`LV<7im!)jc%;A!(7bvij^l8g4vD`dC zw{+XB`hY0g!q-*Os1h&D_co%Ous&GC=B#}7Hw0T^1ADR4qv#VcYAi4=J?20WS`FNo%F@aZ zZ` z8>_#t)#-)eQOWtn-7cV{;tSqH*nWF^gAlD(o%RqLHP?q{dxD~kyF|3#x=~|Fgo$~nw87im~)|lyIwk#b-#y=pFdSZ zT_mo=EWh$ZbtE1E{B&5gdYE`%CT+Az-->_EO*EJ2cI~7%-G5X;^@~qGR~ioTs~eLj z7-ePj49reDwftF}jCLrH3+39MZeW*C`RXJXLP6HRs0M3%G8^4K_*9pxiSEYK1q(6X z+)HygCvU&XBNe_h8lOK;*|E~@KlO-AvJI>_$kaG#sg6#|JM|hn-bdUKI;bWbP~c!= z&djghw(r^l!L_dYT3d0Zvh2JHvm7u6P518Y*liFS8w&zQF&0w&Dp%bgTMTyS2S*AX zQMb#pm$?de^~Mj9v}zo7>@2I9&q<~HJ;vi&Qc!bY9wZ>tHV|OR%cvOvvE7?%%2ZQdfEfNp_CVKI&`uv#>*N7whPe7k%Tt)qXLi;*p#*%Cf5(ID;?Y0B5;5EKLi1|C7Y11%Ny zP<{1j(!2Mq|E)Icj8 z(6tENFPy_3b@Hn2iUeG)FKnUx1_xp{I zYMiQLz6=wx@21|vg(<7VRRoV8M!fhk5{Nio&-kiH__?IduM`{2&OA0WqK^;iM5sN= zn#*E_T#2V?p4hCEykH!eOzrpQt7q<~rrhx8z+TS>1?mUJzo5da@2Lz@)*KU4bs%jQyYuBXwVt0Y?ZM4yDmKY_E;#{&e${7eY>0G5)TKN|CstM6TS@Ck^ybb1XP5@B&=SZh@=5XAKei3 z&zQOVcx>!{6=<}078b1B<}U|GnAFy0G`9K*jZt}Id7yU^a2?a}iI7@-ftUB8oIt|6exE1(y^sf#lN`v)p& zY6L}&G2gV3Y+jn+r4AN3`n)6NPf)-ikAi}%&d&P0sp!-YPs+TLI<%mceWfiidD7L@ z=Hvv>2rCdE1?``4hW^1m?^&KEuh9AQ^wH0s!%=HM&%g@!|yvhr}nE;8?y?|G^l1klj~hy z1tq8^mBuf2o=I0uN6!1{8DoaA{?DSk2fMJ{fM`5dC0LjQ&Qp@FIG;+83r_t5{lMH{ zK^1%4-N`8rE>hFi(9ff&9e(Yf;r+xoIa#WOgK_}9DA1e28#nwBu#OR>H^~Z?4VNy} zMXg5$biKl+l}HmObTxvJAG2VyQd(RL4b`QX!c#2E-~mGDGV$UHFAIwfzoU0xpca(Q z;4qSS^RQtgGG3vlD>cm~g~b72{R5B>ihI~)pY}_J(+duMrN#|rM6?MAiFj<%Qc{XM z%Pq^n@R@-0s{q0SP1pPt+@C9Wtbt!*!FcufW2{s_-u;bh$yoG3nZ|T3iMyXcG3aR! zXu6n}=;QI|AGJDX2ud#&&n{RkzxVK}$ ziU!9CB~UYz238XKsO9jI?knnv(^MF);B-@Q=q(tXa2JGRb(gY%E^Td14Z%0VLDEH( zdj%_%&C#2lckj9bQ2Q*?1)zHYmqW>O1zYZHKoNp20K{T|Do959yd?@xH}+Pz z3=kcor%9k5=}ACW15rDOPf*aJ7Ax6^OM)K-uj0S>`^%R>U*AYyn=ZJ@RDFPtg=O@^ z2Vu@+FubsUU3#0G5HW{EIih30G$s|6;lC>@J!LrRR9()QJ*#&rNW99(OaJ#0qJyEP zqC$E`@}my`8*xJ*NorPFQXuQHhQloOUmvz~LnIE%n-~_t;)0PeG&mR(aI|OBJBKrM zXa4Dj<*bNV9{2L9X~)ySkF-=2c$Z1~P)x%Y4~(tyt!}iJJ-5Sfr^*j0Htn!RICg$c zrd!YLAA(O^885;5p)Ca8&Q)d*XWXTW7jx`#6SHG@h-9X}UnwaF(t6i=`@w@PH`pKi z53y+3NRUMehO{(dS|@(pD1UTpk$WH+kz;?qqW1&9#BvDuDzpwbtXW7PZ1a6TO6g6> z_)lydY;sJ1sA1E&RBk1Sb9x@dFU!2BnfAZ*qi7qj`BcA8P7c)i?Z<6N_i5=XnME`4 z7j!7WHN$5|TL?99cxY&r9UmE)X#&>je`R}N@Q8qN#bw7M@Bf4G^v@3yzd%;K#r)qF zOV;v@?0@s6{`&&So^6EM{NFEGbr%7=a%yVKZYn0OFkM1yjZZuZB6`jLP-1%M+p-cx zI2^F(hXDo)2{kf-TEz3P3>jI+!y7!TI%dRQb#akJsw?E?aWDV*lwIvyi!8suiz1B$ zD8Y4`oANhhQ;w-vKIDMX>`pbv%K`81t7>b%_x?>mcK*zZ<^OO2T=)hQg+cbky^JFb zRcytW#+&-@8)%Wm^oGzVR2X<(;tbYZ?HUoI6LSX3_O;!-ke|=Z&T<3(LWv`4 z7}|y4fy?BkXLSUR;>`k$mSmy**^H<1>!4RYq2I~GQ-*d2UjU!h*M2uYA1r;*(J=ug zC|J;pv zR6ifLCp^V#@a)b@Wr4ZAhyQlUmbTQ{>q+I3ViIwQjM=6o<`QLI?QYc|wj_;F_^oe(?>em&h@ zx&xxQ!Z zNc+!wym2T><>eOIGMvd<+32(|*Pzf_H77LPc>}_V*q)p?7GH$)`ulqJGSP68TP`|VU8GzM%3oSfqeedt%3OiK1( zxWV4Qo-J2UPA((H1&thpbbqNnI2PrOlA2BPwfF`2)Iv}DGGO_5=6*29$|vs+eLUnf zKSINac~t|XFpSjY8*mgMW@xiL;KuzyhEkHkD>=p$E~^)wR${l9^wv2G$Jm zBq28L(c81=2Yz6wKhE=L(<@D(mHx1K6MmL(($$lpLJnaD)6`KH75*#2FpP_Oi2PQf#jbFWFOa4P7C(6kM z1M~t8LJ?B{wkseGAglft6>;DIw?S8mkZTNL4GudpJ3$~rNE}YhYmpI{RY6W6O~Ud4 zA1^3%h>-I~l}2N)BZzKihm;f?_=`5m9Kgyr7+fR)tznReB-jB%fQyVi^VJbq1cgU^ ztA5NvLXBHr{SnodFOp&0ktUGFLJ)tDh_}1}%GSqDmk(GCHG^q}e_+O`3E~cxnSp^1 zj!X}M7DM>g6g8HWO@h4yh97DHK1u^x0(@S5A;x?Bp6+c{-2b3$sUz411g1EaHBNLK z4QN_G%!WA!3kmwglH&^EX!3Q3@sJVLKiY=@_yI04Ac&EO+p!%#k-h7>mz-=(&g9Yo z{;Uc&`J*zVC!my|+me^JT&F*s6)E3wt5cxd3c8;^p_-BKe|=dTuTRkAdL|F4#W;|xD{zxV zv|#>NMVpGURZA;nVBbPyO>P zYySHY+R68)k)(#PN-z$9S|1aMv5tdYFsnpkPp(RaRAeh)dwHd73=Y$m4%pgCJKa}N zRn4BbyM>z@B*0;i1g1ysU5e>)2@U-T0Ca{z{Zw;v6c{{^dM=^xR?sZ)Y93cS+cMJA zBZAd)rGqL0M&_!Jjfg}vg60!AVrOGxcyIq-=2jGPkZRQUczD!&UKgRefSf1O3MEn- z&OtUdHnfERBWY!H8zW5_wj@G51S5&p?WdEIFQXlX z52S9cT<<=BJ=|NiXu(sGO~)Ng|5TOdNp;FWS$Jv?O<3-|l9JjtOt^U=E~bB>`GYct@xNF%k>L zVX}sDQZ*wn0c$8N^F!rwV7_*QsmjWxAKv${=8)0J$nXbpWvm#_JNBG272CJdYO&0m z?4e?%^T>K^O^-?Ox!fY^00;?ysE^}6LGCh_x?nJlO!V1QFnTfhABO{Q(16M+H+CNg z20HUr^?x&dKH~-bm+?~vE2buxJ=C8>&jx#db98>NqakQQG_0k!5fzGlXq+TrgDBkQ6+QN5>ZoS+ikI7LWx<# zGRj>JjmkfyA`t$Gs1LwcX_5Zy0)x zokVP?Jw8$=C)4=iy$T#|)m#FT0%wzgO#tW-BpoTJ<_MBbX(=`@1WD&w{q2U$ZJ87v zHoqHQb2W}hno7SK1A>|GP91c@lR=Qo=KXpgSbXZ)%FFr_zjtW0xYlnesq>2~ooOG& z%HmZ_uw<_@XV0@TfLWXZ1T{p3#|Ou)`j7k9B0mw&T+mSzWw0z@Y7%?`5*r0{V=xRt z$wteC26?Kva}reze2N5h794%RpM@x=;k^D&3_A;bJYhzR(YK@Q2!Kl3!hg6qF4BZc zQqWi{BIN|*u=3b);#)OJX~tK4@<%?AX!#MhE0 zmyI?Ld{x}1+Yt-l&_Y9Aun9Ca*d7Ht7v8(a>m^mW4X7RL*I%oMwy!x+2+*h7j(j$E zpG>&EarADp~xRsM%&|1|C4B0D=tOh zAz8cl!E7W;me0`pk$g2f#MYhoc{# zu&yYev3Zuw)*lbsJG)v8$fbD?gXzjys^Q&7+G|p5`7H)ZD^LoKLvsE43~0s>vI$(j z0|;%rPljh{q2C#T>nM1|;A00#E4w~mGU@JH?k;6GDrpE~UL}A;G<)d;8J#eCU7T@^ z744qrt$scB5@$9Ei}Xjn~0lcMek2=aYVyNXSol945WSMuUxq~UF`q8 zxV3?J6jQ6@21ci+HPHaXrCXMxH@mO<8yZ-Sw>8+;5V;8kT2J#zhctSg9MkIP-Sg)c zd8%&e>5bGj@jR!qY76DDkvN%-Bj=5eg(^XXNii1wxv(3T6BFy+y)OV`_kBKv*`$-b zLb<9CJ35Rn<@w#6oeyci$LpQ<5Y>y=O&<4>Fj;bRkdl(Z^EI;z+Ae$hWR}~twOhBR z$Q?DV1xEw;oscN(UW%OsSpYl=#}O_e3G}lZoll;aJD;0H4~Gj&DKIX!?+R)mRFS?b zy9GjrUmQ?oyD5*tOAuHH8~e{EndIDkxY;QqM!!_6jh4Gjr4@3dM~v;HRbIl1?F{pa zJk9G5UKKW6GYdjjJI0m7G~&h|9z7Log8OdfAr6~9nh9&kKD2+edrGPs zF0~~7dsVqaSZJS6*%=xpXq`}J!&EmjX`lpYs`fR8Cc)w6Sef>~g*{pm_<(mEcP;DgHZyt}; z-nNY|^IRE1icATarzA3uQAj0GrerK*iO5Wbh%#2Dh){%zl4*-FBy*A|AsUpVRQ!%r zd*APKKksutpZAZSKlZ2Hz;&%_t@C@H=P|uM@$lBO;bAr|<(UTgwcy^A9hS?w&pdRe#mZUXgIVO z#m{yY8!%WZ?P@xW1soJ5JD*U{IEhu?zKyea*jM+rxrOur`Q}G;7RviWVq9Kqz4g$x z8AH_E-Gh)3Tu}>Tu3ZGRtMyPLI6pim6{Z;F4&`(fC!dynvB{DDLC~1Jv-B=Hsv<2G z(~dz?hE=OXwxpEb3D*PGjZp^sTT6*m%*>AEi`O;ylMIA`*$P+Di{(TeOEgiS^avwE zp|DXB;8?R}4)EeejIHSGf1QYeanEMVkfJxN>2pbY2T3%$h#?@OTD6>!L^3mfvG4pg zY^X}FV!IenWp4~kp0(5++{JM%iK?IJuiTKOj6X6D_Q^(rVv8A30VhF8d#gWJve|iU z3I)%WobycTSw8`eHR;yEKoTp#;SWJ?F7EejZ^+%{z%XE|0#f=nnCY*JcIc5W(Af{_ z(z@$ghDJ)J<`YWI<4a|^*&%zFT7S{#4VrvV>c7;3#5~?YYcSiW#QQraSZszpseT(Q&Ci$Pb#|M1F>gYUctH?!T|)U^|XD` zfj+=OyyZg+!fWvbb8yh-T3TA*syHwpBnEfD4<9h5Lo0#E`KAd2xU%e4p5 ztSqjD8Mk=L*wo%?69Pzq^`&xU3Fq-`K?=wpp=6szxDVb*slYu0+~d6 zcHqm`ubfCU#n9OD3P2>J*XIo)>WomNy;5LhydCbZKg|D&Sm=&Xy79J-j(FH7ndfcczJH;!ZpoJIqP=lKBY|3oU~iTwy?y%zfGRsrv$u&P z{-pUKh~Tr0Ki0XvnX{+p1s$qjukIxFFkM{#b86x5*Rk z0|neB4&1Tuw?!rN>U#mM|Cf8L*Hp}l`<_2vFVKfh3H|2>-JkMs%TWGy^>#tegz6!) zuQGMK{OKN%0rWC>9!{IR8qa6(4!t5p{X})1`PdY^9T9eZbu{i({~Q*ef9;E?tNR7y z2vkq6cP(fdaihG20;=E;oCGT&)4&RejV){qUWYFI!q>0KV=XAV=n&Vd`g>vu1P9|0 z)u5?LSBSE)8}Y4Em~6I@4u# zihUPlwr41>8O)i=(kbB9bl{FK5GJ=a6&Yp+f2<4z&W9A<`10w8u(0NdBn=I2Z9-Ec zFGtXpn!`+`#ipcsSogVARrUI62mI=&FZXQU%+Lwm{Uco-2r;l?c-xJn+GIg{4&FIL~jw#hAYVAH(dhf!Sj;&%@^!*`J2Zlmc zNEzbq4piq0Za6}BRjIUU?wSL=Wu~SYkL9rddybmFrsfw;f2N_NSh^{&(-vayZvXY{ zHEt}|V5q%)dmzYHqKTj*qB8HRFRZMr#A==ZNgC7>+XU}8<=7J@JmxGCQ%5Nrq8@D!x$)ED%Y5s` zGYwQ&e>4kqOSE2-WqG?*_dyeY!lAW$EIuewGkJ-1oMO)R$Hlbs_ko8K{(h<3@il7x zr%p8*HTmwd*MV1?s>T6PhMal$9w!d<%GQ>z2@g;xA2|n)HK9wdohmG`Y_65kKKLHP z?vo_pSqO&o+}eHL?>G4P;5r(7%(*ztU*7e~A7CO8WW6ATAeIrnh)ySIn_7;-Z5r%?t7A?X$xHnnK$7%MldJJ*6o((y85yTJ0f)QeCubo z6pgsii<}TET;z_bL~PYv#eD#Y(B?df6wfu`gT)Q~Y(BS^_{FAE_c3m{os&lHUBgGY z?igQx>MQ3e9K!<~WqkB?SBjK|qm;zN4BcG0&=g)+{){;%O4UrwBM#OslQgi`6)jPd zgj^h0FTSu3ZB`Ygwh&+Is^E5xHSZXM@oo4O(%<6;Sc4TA1%WNp7$axd!Q|X~oD!Bf zZX;cTgTE2u`x{tH&$C1}bY9-R-_5cf)$fM2==7GDuRi=CCsMBJT8Z~-BxabF+SJO_ z+3|d~_D+BBdC$|;!~Al1c_nPnePMK^p$si6lYGaTF?ub7N&I*KdTf6gh&;=7XbPU6 zwrbz?X4Fo$Vy9i3gXt6mFCnv%h@!)4c6MgQ;AadTe<0*zvTsZOf*cXbDU9ffiv3Bc zzy~&4TmSX?Q}^iQ7_8=+R1jiOTyj#)JNsOPWq7~^Tq~Ngkcg5-`b%nooU4u`@TsY6 z+7vnWh%~vZa$)zK#ppu2>oYDvF6RtD2$OH(2ExfG5qTogk|mqrMK%^w40Z?NffY_h zn;08MECf0`8^|Xvqa_);PvN^2=FAaZA}~h_6cJ6PR(#n{QsQ%~fy-g1ePG^48Ji|# zE|yx?$l)hXlq5%1xs%Kl_hBp&Z^945^bo)x)bCoQbE1-xk#rdLB6cvuwOG{!_@RI& z^q3dZ26RN&zwe2B%hH=PmHhDcO$YOk&7!Uv8iaLr;qqbJMK}o>UZcNMPIe8*c9JT( zPl7VG>Ok1;e;sy<@Jhh64rSeeL7!sWgoVCh%%_-RjkA>AM{*q^2+@m=F$l(gxxLdl zr4_)Z)^zB2>48c;VK(sD;&k#5TEp$#j{9i55oC?NdJ$k5=r-rR!Bs7BqPG~$^-9l9 zXq<;LLwf62_-FTudRi3%%OJcdwEqj!aF88v~50MYTmw^vL<127CkH0g2J zC2erV_e26r`14f=Kjl^RU!&+1wMk7a2=h8Yi2Ko>bdn^!jwL>s-WwxIKfy2v7)>Q!tlumup&jUNsIm8>R zb4?7vkvmgz6AlgsB=&(A4NV&~t+1#NOKbmrdKr7fzwBk*dtp9qcE&BAU-BUK0RaI^ zSVA%oF=x-hxC?7+6i1*ZSbW2xVX(4Q3(Mi1JDIFQNN9YA(uR`p_Kph6k)-;3O z=FO59U2|HEMF*s8(pzMrgQQ%Ht-lvf>x-mZR`#M)DZ)M+5i%HY5ZDUR1~8+uI+O<= zVYh?Yt$i|M=voGA&+%boeZkTPDk*}<%g@JV8`&hlG@Xtf6o-i>R zMs2=uK^)OK_grsSRWou{NSPkK9D*1Lc+RO7CSL^6)<P0G*At!1=!dZz$8y3j%M5-H5OmMYW*~(0{S}Qi7~!D} z=O~QQG|xl*44KOkjIF0Ul`;2PopkGZ@?-_qvwHN9scDFcc*I?4Url%f8XHj!Ryn_c zUkBE>U?#osR0hc4TuK9|1Kz%|QAdp#T%JK)#e9#GyqE5x_%5s<#$Yyf8Tb{(*E7HX zF%BP)7=XYB*1e^{jX=cwBCn>Tr1~m$9~a?pOWW6BpB|-}rttfK^MSKF?q<RXH=i6$SY0o2n30kjY0>G}$M2|j;6ZQ`+~esGQPTl4feZVpW$ zBWo#ar;~o12LZ4_AcRD)`M1c1g1pg#!7*44R{>w$^_Z;?wy{F5etE;0B{)-4#I=x2 zar*Z~M4UpAKJ)yw&C3V|B5iP+Js1Tdp2B1Xw$In0n~jQ&E?Eu1n|HBAW@@U_J9C>q zd?j$$ASx+t4P6Krmt93c1|3kxt#RsgXDCr)~4p*Vjm)qu~_ zQ=PCieyA0x_36>(?1{-qY%mUratuFvhN&7C<%pvrteVw_cW>552B?-+SY2HZNS<$% z)tJW5D~Ps-(&+PdoJ&l6g6sxhGgxxK1gCnkY3h?dgbV0ZK*Ymd8@!Pjw=ISZ_7ysU z=ixL?02!;kb*qQ^9?P7+DrQ~WWm0Kih@gBvA06%bqOCaYU4w@PzPr{^i+GOkT2kf3 z40kDU#=ZIY@#Ey=L;H%po$^?o1}~_?42|4q)WMaf|H+f%7^1st)?f69x>PlBy|LU$ zD=^HO2D}G;!ca%k;=Np)9nUxGp7gso#1YK!hsn|l^30w+z2#ftJ74v7P+r`6q{0&K zfHG90*aA!)4$rnPb+q zLbr?m^C!#?Up4Tq{rj&m(>i#Kl^#yl-+)u*F1s!q;TEcD{`srDA^-l*au5IWC;#_1 z`Pb{B4X;r4)TjCLBJpA@H{8t+`~8Z^S0=IQTn$Zwt&9#-w9QRT-~c>xKLM*r)GZ|D z1o<#Uem?`_PGDdJG2wm6#ih8WrBPKcro|qTIzj`V{qEg~_^ouxTvPhWN+c|TDCA%$ zlenJzDVA$c^-!`wD$84XgkOxEi+#h-8An>N6F9VqSs3* z;%>wK9^xM=VhB!J!NCv6AA$W2Cr%ZDkdu=`i)!0f_hndlt)UEe&lujVgV>z^eGsh} zBDI=MsrsszBd`jNgG`C7u(uexbtDe|8iaUkn0F>Wk$BEj z>BA2kAF&Y{2+6@5;GP)`tgJa47zdh?4u#b%-3G9WvbPr`a!{ko$~x~iP2X(h+$64@ z-V!Uz%{1;+?$z;{Aa58e+sbF|O6&R3-{m6nF_aDmvq+$5lpa*ecz!_n{4Mi|JQex$ zaI~b6MU+h3S_c`68C`m>Ggwu_OD5 zeFb(^B&wdR4*bne?fjD|GLseOGng&zO83y)KX|YV%)g4N=he?OoH2vAijmc84gKpn%34E;_YkwKjj&VXy3t&<{ubHMF3ZU zj6&f|FVKG_B~F4rtsNRn{jw*UHkXCgUdCGn`H-*$Z*?vnG9s)2$3LNiKyz&Pvosht z20SNd?&yc$oWdR6_!|Co6a!lw;`&h!1<%K?-`dsK7}{bF8aTEaQxg-@R^~2pfqjt` zoLpA0Y#jHz68ND8X0NNFhc?Z=d-oIU7xWxeqspf~Pk`O$vUk`1{ez@A z2ly3D-$4&);&_c-6om}ET^-P)@l31}(7{2%*K}$+6Wos+F&t-*!oGYEl(})g4ZmS9 z95OMT0{hB+x&(6-DCpMN7+R@A$2Q_FWz51IZ8ob!FC4VY{W`(%7Ew#K4niLShxxkt@*)&J6|1LNI@3T zfq7OkRL6L?yMF~L6q;luDXCrZ3TMDLg0DC@{ZE+>D21xcghsTG#uRL4sR_^NZUMw@ zKzG&1v315`|Nb+;gfcyN#TSt!G&8KP`=p*9%?oUx(e!7o-~#^ubKVCwfSqU76>OlI zoh#2vF40XLqh+~cuklqeI#MSn3hxS3Ub8*RxKwCMe&KBiR3tLGv?P1hEWLnX^d}OJ zDw^3k>YtyRt2qy(G8Y$sj)3U{UiH4Z^G5en+dO*qF8ZsEA}g6nZ3+}2oBjLs@7iJ! z2$o!AeX(L=Gw|>?6BE<~DmPR7u-46_^XI*wFK_mUJ#kXUD%mc#=av19%i$GkBm}>> zVS+%RMZWO@PWpofvjWtEp$G?fbi&ed2)k#y5|W8pS7%df(ZqDu`U9$l2wLRtm7e=! zH(&9m9Oy#H0iP|ym{#8qwuPg?KRke~oN{n?e+P*%lLrK{j~&SbNhsL-^D8TTu;kOx ziMTNcJ9W<6On;MfH&`1l#PZ;^hG z!0UOgnkW_;XWYUTa3NiAfz`feiTsWj?LUio4!wmj4JO7%kKV#>hHv|c(u%xQOfD`7 zJsvA78Yb)o=4W^1Ssi`%WQOk74i%xa_NRuOnnAx>Twx=LgAf>Z<3NbD)N#%m#J~g?HFA?c5sMEN6&ufw7JaE&{@`-#<YR*>4XDKj<-`XF%rAo=rf>pVJV(czw}4Jt;abR$(1C zw?;32L{OkW+g4gSx=>(_=dDHag8aPc&Q1VC&U^N-6Ag`x6YijTdL&i<>V7XF{gmlb7XJaOVcV6b-AU(bhzIxs3j zg|T7PW?|t8gfI0}SIcOBEn=GCoB}V~R1_=9Pk5Lc_g#*TZpAhV<|MxUKVgGC6L0`C zd^-q;b~3yFcwT^bF?MQ4_6mx0)1!xbOZI`N_Y!h|D)M|<$~_d0?$&S7!*^jhPByG7I9X#T1%Y-DHmPY3|9`P56E+qYu3j5%8e9$(Qe|E z6=3jNd7`tO&cV#`ulUE<*+VGi3sVw>(>>kYbA$EEYdiUFJ$nbN8OCHe8Lv=4A%B5u z599LNsVTbfWLEMsWfH&m7{>{w!+dcN0+*Kt>tUls5F;;M*fog0La~+KP>lp|;4^mu z#`M8M#sfd@PnG>-P{ocBdJ@QA0&^&SZ=2u;=%cV__w)ncAdTTT96mnyu}aL&({m2< zKInO&XN({;KEg~(#`)EQTZ}^y+9fb6@1Ok0r~6A-M5M`!1CAGX;H_(Y8D0zx44i;C z1zp_wEfeKQsi^`lwp6G=#!M?<326w20rbsk#m}AcwJ7MKiD=x$SwTNzp z6BPs0T0hVo6uyHCdkZ)x#KGT=BG1<;hH@b=K~O}5_V!t%_`F>Hy0uS&AgZdX-;dU< zr!~Z-L;M!wuQ<+=juKUUg0_aoOt<*fiBR zi)?F2K2bA+;(-s%^a-ejksnKT!P77M2_1o%`1(x;$6b6q;ypBs=1|C4Y@DPckeXDS zouT3Xjm(}NVm94RkZ zwaRsretV+?CliZ>M)!py2<4lseUD*%8R1QH+yf4O;rPcB4-=CGm`5A>806R1@)Vrw zUpr<2IS6TScLjf_q6%S@h5G7Wa)gG@buMBK^wWkI8Z;fKMPJgRHu03+2jahSdMOW6=)qDm8Js^;{9s==*rs}aLv^G{} zA{bE2{o>%xnmKU&8<-}|BCJ`RdLFDi9~EQK5c%Wq%w5+|hIf~NgsMKiyc-+Xy3OMx zT9I#%NUJ)rlxD&FY=rND6pZPn#kEL z6bh;xwnAEUNJDG5e6@H>tL5}{-PG5#)mnpYu39(R5Hmv4+fDJ}Mm5Neo}O4{t=bZ< zBFwR~<&B_kjToWfZ zfex~t)jn6=d4 zLZrqHUA63Ru#vw^lGi;<9rvY=ynDW9&4~K1x4UZ{Z7VE69>#t~V1?>HPQ^W5q4oUn zyK@+V07kFg@r_?lP|NKVD~~|gMxg!Q20(pMyPS5!h>5$m>}_1f8j_IA89pP%TWrBt zg2cQ?Dt}t7VZMYgy*Mf&ht(^c>$&418$B~~MAPEJLh-drg5_Yxp{0QLfmS7*sYe%%3aXZ_4$(4{szgrs2$&zmSzljcQRoD!*z}_01Fjg;5VZYLAhE!7GYm}Mq?r0ych)# z5+Vu$UH$v5VXq#TZXZ?n+Xtje(r19@dzE}{BI`^2Zwyr5=?Zp zObf2*U8y^t^2$=MOPzb`8ZNso(Mg}?$S?SLMLFgOIx@iG*&hUO#l;xgbD(0RUbr9u zfN_@>MvdL+GIr2XLl%wsS{+>*PHyM;Yl3AP6>f)qR>~w|3mzpMGqHAz3X#)Vbx=ig z?XAeWPLmR=B+pNI*F5Zcx2GnJxPC`iiA%m>yPSihT!D$~Ql@Y$bIm^QtT%64EnCce zYoa_6V>@JaHYP@cckR#x?3rh>Y}57l0%k|i(Sx@K2;;6bq6*+VkKMRTUwKgx{Rtf? zY0-auJN+O#`>>y%Vq8nuxFu?XCk>O2sh7TSLsFc)W_4qFlzwG?7$VdAM{+FK)4x;5 zLC1>*xlw#e$|F)c10UZE<0vahe4rv}BIfGYx!?|i2z=8+atn3O=!gDPd~ z$hSnj`2N+5@9ab~E(RN15Qz|Yky+68C4|;KT9Vf{^ig5UmxiL2+>l_{-YHgZ(q3fK zxV*tZ+sOFixsHQz#!h=W>O^V;9fqra*Vye6SfqIxX(HlaoqQpZ9Y8;LXo>ZHe!(h{ z6uNGkMRGaa^Bt}#mWvNE`{$(VKaAr&8VosJs}a9 z&^U*xVO!&n?|8hRX=<+LPy~#GV-31E$b_RC}#pJX#VzpQUYBjiW_Fi?0FpKj! zaUzNiTcM$sx!%$gRSE+`9tTZ6o|DMs%xEY~4>a-Cjhe{aA{Mrf*+RlbYQH)jDNo)? z9l>qz(;KOwcm69V!15h8Bh{?4t7{ZH?8j#X zIOB??XCjjZRu6A&#^U8K9Z4QVVaK$=)h;f6jY-GWN#dPRP@Ud!c=!BH{xvx(a=Z>Q z62=ENjHELc^$Yfn>>L9%CWKT)N6~Sox9}dYkhJeALl7JA%pJ~iT$uWBf>u_j>2@O#Wm2KM^M|Yh%RTH2hJ+v7p9Cjm8 zrl9GFOc#+oN<&ec{Lbn|na2EQW+1PGG^RcL5GsRFg5zUoas`{r_48^H{{u^a(van4 zmX`X}h2Flt2tBdxCjDm3@j*S7iQi2gZd2ymiVD_Uhbk>g!BMkG6W|@acQP@6{gNQw z=;IScd9o&N4pCy~*7>wrL6bds*INVTJ1Exq~jALhb|lME#jX16Oq zRD;-sfBM_k!KDY}b!bO2p!(QF zaseKK=&5dUcchdg2Ra zWXMs*rr;MDgrk#s6PBNdHRAj>bZDi5$o!ss=6*KA&Z#okxd;P9oW49KEou6 zz5A?T*de^yw59!pqYqtxYm{X=jg`bPNMFG&YVYXy30fcSAcT5A zLo!zD2<9?K>S`~oFx;Or7TNCgiu!afUh%(h|GS5)bp%6SzK)8bU8t)q7S-R)J0N}i ztsAShQo&)Wf651Gdk@tlL4d}D9R?Ukz!^d5Vgdxt!m_F2+GcDQmo>Os{*XkGxlJ@+ zd+WQ2;^;2E$)7bw1>#atdilozgwJQ9QvIG~a0;w;%ktIiLerBkDb;J?z}%~Pi+3&2 zfc^z?}AXs4iqr690tZ#%02p%29BIkTY*gT*On zX^R*R)FIX0u!@wW(yT8^$<8JRhThN0)Z2a$#Q!r&|5T1>BQg4xqrm8^j*)Vog9n*} zlI?5>RR(q8NpU%CP!Ap=x#)KAuK=mE*$*F9Jy)B7dmARtEQyD>;nd_nb!Se4Gq_92EL{g_uqA&&$18?z6P*aJ)V#N&!(RzzfEapIRP7awCO zj~U0sX%P4^KKcXYwq*Sc_{$Y{E4j19MgdfjP9!2e!FN_eXlYMxFZQ=-k_SaN;~3MYg(_7=uRVaP+ z>~u2nyuS?E{YrnpDQmZ<*)`1f~T2?uqUxEcjR~OWi-{BVu08H_AKBcH= z>ZNu?#$tWkxNBeu1Hcv-)umD)jM^5arUX^4Nz%u-kP3Vh z#@(;vG!-ApFfw%=Q~&H)V+}MOYX_;cz?J1+p#9lRc^;5}hwLVR zYygw)?*n(gKK%Yb z?>oD2yLpjG?LQliIy#d52GQ{P6ABKnDOy@uTxPS!`vX1}(12~TapT6#o3Eii2g9)} zf!nX>ZoVDUsQmSRxB#=|!N!N|Q$v-Flq z+m@cvn*3{<5BKc3^ag54shuScxv5TBtB7;&u{Qv4o*UzIv{_*hs4+l#S(Zfi0qK9C z_43}0|Bl`NKf~^q7MQfv(MHOM1?uZZZ<=auiFXEBid+*AFsso7tp4aj%WndK1JA$X z_sU>XlKM}iYxvlIkaHlDHO-nP8tn`BR#yP=i4#_2P5 z&lvfR?%UB$oC&8#r~&eh2m+iIs2@5dSB0xaRsZ@lQL$_HPrwtyLqh}s;d@4Q_RVE! zd_2I~upZ6L6_7XFD%YK_OI(m<14k;tN5Vq#I88#2gh+x;vu*TO=fy zFO!xIDC6K_V9UR#a#pb=^rinhu}Z@lM? z!Wz3NKNLB`fJZ`BmX+uRi4HWnV_s3DUHHya2?~N^?b^m|hnZU6QQ`w6Go|qC=)G9W z%K8c1L4Z+B>iB(>MZ8ZWLf~d32&gyEv<%<&$eO$#Yb>(<>msD>%q@-|s48I!(6<}F zlDnH55}?O%>b?B)I}w7L3Fw!L9_?``3x{5wfwv=aFsX^Q z$B*ScUuM=4JZ}s!8xZ9zdP7kS{0bb8P{=>1p=s>y0K*hIL)wESQ2dcm zd*ft>1=|Av4tub+KL#`+Q)%6X4L^YZgb#Q%y$O2QH13Hzk%j;nlw{YQJ@!U0wL%is`gH6qxN4^QP27t+{G5=r=^ zsVPH2pn!T0Vmw#Z>sq;Ep7H7Xf8u)KsH(b=UXO@wRj6Bqsk30^AHQ*nn3$blZyq!n z2EvpC{C1paRWGTYV!N@LfrTZ~Ue#zf-G$#DXd@C}6cjiJJgMP-5@0Av?xu-TloMCO z7uDfnN}0sflL}AU+6)jRLTCUJ27eYGBVuB(t|15Fb7 zngBk7GiU0rT*I>t-Vs(E5PK0CIEL)(##`dJz^nFs0dfgDFE0y$mCh!G>&8OzgvM`g zSIjKim6g%UVUR;x2Q0aG_axXNFGolD2r^H_{~^X3_<_xRLk1GC#Hu!Jt!OI&0k{*w zo)XR*m*CqK*MgH#Tv{4xM1jlWW3akFnFbr;e!zmbs`g;?^@0K#z8qZ%J&5jiH&8_t z?t!X(yb*+ItjP_&9f#VOT-kccWOZHv;Q!uGvh#;;gJVr|cCvvmI%^=sn2*p=h@|{& z!CR7$-jUEPHHRJrn?*1&@Kj-Mm;K~ug(dDhd^bdD4p!cd{ZE7!5G5kofz416+&nx> z;DVNX-wwjajvagiEUn+ev#yf~7Y%9(wu^Iz^A%hw4vRLA&ws}@YlC|5ee~K|xp(1& zgD-@=2yE;FrUa4+1p(<6_)L9Ed!{Sf>??rp*_HYOpqA<03WgB0(kM2FyJ>6`05eBk z-e>4}vD+h23huJ#sDm48yw~yYgxPR(o{J52Dx!MX0ILN5V60utbCrGG@F~&eRQ|`!P@FPIrzP3{a6g6#A z=uUF;?I|-z8@7}bhS{LpA>1gx$VV}gj9%G$2GleSevL+X=ydlUU(B+Mwvsing{-jJ zZSY}B3+q4yI$0bD@BZ*E1S-OuvCl6*z3~{Q9xs|De+~N$DCO^VpIKrjG(=KJ`%cbN z^w?T7hJ#~J#??14&}790qqD&MjrVuc8K?fhIG63vm#R`hQk~*@V?NLEs6&0x^EA6K2CXqDvJ!E$zU>xVZJV z^R?nq(F#JlS8Bv;0t2G96Uxa4FP&wx^}y= za_6pHQE|5^h+ivI)q}8hRAD%tE4sQ)MZww@$1>K$VCFDoO7&?&vvVKjJ>u|y0rYQS zv_^A(<}mbpP2pfUID9lQG76&ub=cPVC7(r%^JKIJ0DsjGm%Drg*W4mgy%Q4>5JP*? zu2TEIa7ip|$8BDF>}Xqp%w|smgErX8*hwSs3~|j&3@~>j2_;QsE`9&-Ne)Ak zNJH0Bs_?6ilQ(4qL=d%<(HLTh^ITB3`JR1zI*6GqcdHJ$(}f zKeZsggV8JJbp-do#FlCsyvkpaa`hu`X$Tl(=h8ld*Fg0$|Kq_lkbX;L&<3Dt5h18s z;POxrXidg{K968v$Ljq`pv%+b3Q8G^)d|%*c-mV;<@>^qSQVL7U(VZ=?kVyQ(<6^h zF%$=aKR@i}j*jBvM(h69Z`<{M7bI@p5;i?6f_XncPPVAf@lD7 z0I&(Bx2)u3%9S73lr`Ttf%6{mYDHpYk<;Ctp?DVQuHDB`LuS{(U#}^V)Cj`lic|Vf z$GE2!2xy4ip84^#r{7HTsma3+=Ty;`aI3y}`4ThdDXWO5)B_;L9zA+(fC+_hEOhxq zv%%@weMM5 z;VXedCxXFaNA^dMG7}+-KpVpF{Zsei-J&9cUp_m{QiMJ+wM@-JU;SOK^J3gQN{~Mh4VZovHXCDIl52-}WNpD}`UXpWLIa10 zsy~d9NFh>Q-jMr=)2Htb@C#~Wry9^}1gZ(!1^HfNV!(|;^Y@Ly?Ja`XJ=|tQ2#y21 zYm0fkKC1iPZ(7<=&oXmVAMiTB8pa9?b%c5(7KAPSwlSGbX-1Mq|(3d{}X zgqr2xXZ3C2aaWg<)NUr@Qf6QM!rb|Zfg#J!z3cwaK03?(rhRmK{!RNR;sfnt&rX+< zLdHy_{gGPW*PM0bc zx*#v}yjsQJ9aadrDOJwi!oj(4)_D$hlExG3iJUuk7BONJ>F$67A7YPk;?589$U8B+ zx(PyrM7tW65Kr%|kEyO!6fcG#t8?=Vj~1!zDiuj;1<-%a=pT*)Q{*;i-b%PuPmDK5*CWqI zHL4&|<19T$D#hEHz)v7qF5-b#Wd!8o6@dIZIyy%Mlvs#=(W$U>_m8M+nK9*>pX>~$ zgE^;U(7q|0z|Iw1MgeYmATslaw|8|ZIUd)KNJ(M0#==A#=9#S*Vu&1q!A3W#tC!96 zsM+qLF%ZlAVQtK+|N4?L>3a&uVXTj~T_|CJG z#rAn*i@m@)f&hz6^xR?jMirjUO;3Yj&z=o^O=kDbG%n(;DQyAId(8NYIC6Eb)}JdAJ&RR zbIFbN?s_Q6(%K95(>ffe@!s^M9y=eX*AmPYcc2~iw6h1zcVLsRZ|Dy0TJxNoJV&kU z$siSNbeXDndy0yC_iv#n+ZXoegF^0$1Q|(Btb_K2K23;VkgZxv23SoF867=3HM8<` zU?8ds4CqEG<(&)_m6hRqw{mib8!SM^_h&aCvn+DEKb)>|8C0wk$V*(y8P2k5RUWIC z))w{z#$2y}7!Cdq6L@PF3VtAY+k9*CLTs(sRR>f?cBZ8oFljibQFD|g2Gk_U<5td$ zOfGsa?Auf%PeJ5p^<6rvrDpD@ZEMBX-YBRdUOP8GA6~{8sg;}Ya8=L92=i3?U2Cb1 zEb8MC&Ck(E$XGviOiG2F)SAa5NDNV|p>qTW0bnt{XjLw-UTem>F~7wl;L4VZM&pZT z+utxVSPFzFJUFkooPN+zpB|vN9wEV)0OYFmIWH z=}KO{$oZu~zq7)fs;a)Ezf5QR0|J^J&W?@o z54$jiQdSfq&?rxv7588)p)jCr!hC1P%p0vP<^>sZ36AL-XP5x%|_Swfoj*S@QY3 zT~qK7kvva(pY9jsK*uom-uU)UEB5mSRd&s^-)y#dy^5%4pGKo+tCS2mVbm=)p$YG8 zzOJ=}65XfN?%Bn6Uz2A{Yd0}4h>4B;ys)4vc3n(s*qtSmA=K}DN(%Nac-#W|S|HuDR7NZVI&ts3l`$UPZ-IxS1U(CtN*57OXGD zyL$h1YCk>WCTKCR{%q^SSrZ$}I8>TuAS@F=S5(08lqaSn8@$qHT_&_O&dlo(?tye6 zSn1$R@uHmsNqG6NRh5n|!80om7O`L^&E@S>6n)-4SL39|=3Mqd-Mz&Yn5)o_69m#f zIfrui#AcQ=^l&HUZ5J24!yDJqv*CTWj~Y*gOi+GwRmZe_PuAV1TM}!0V|ub&k1-h# zVvnsSr_eN})&Hb%U4R?{2&T+eu5OXUj!i$b;IdBWaZJa~Xu4j#Lu=L4n<2!{KL(`# zs@f-2mr7pFDC&V`%w`Y_q)OQ^a#j8h6p#%(GJ4FbR)HmAoFNz4{sy%UETC1Jzx-fTL^rc2>m8oj1x zK)=q~AU&5)FE*00uKI=LWf@6vVhnQfa&mYKRS_?z!?uuNPZ-W3t@7z}jCqhKC0&*? zi|Vy|ZEPG;A(ubIz_YcZP>{TYdRlh;8o@8-+VqFu4OtV9uu~nMhefkylE$`o#J=m34n<~mkIG06RlqRNn3)n>kaEozX zzjmAImWo|hhQ;2!jTumgDuXbCEjygwhR#b#OAl7-uE&7RMqbYA8!?H&AVBz7pW^BE z4OfpiiK@-U^a=z>jc^*Ro~G<%2r3-+RL0s%>YWp!bv_JN$Nlw~@xq9NynHWpFFhu> zuKTmYW~@h!3s=|`M5r>%mafkumAQh@(4u0V`ti9`qLibkRXvEK+aGlK~Wf4UviY4GTtTm zRbtjBCK^H`>!lb6qZTiANige(U@_%B60z@7a?B6Gi32>TAWtqh3inm(m=PL>)u{VQ z6CZlZK1K-?L9xD}Mp)>y2Y>!P|@1SCyWE8|6&OW{zqd8}jO0Jw|r*O>5-) znq$gMWvo3m=N#T_9LESFu8{3Bhy@B+dGiC=MG=?$L{eID^Q^mw>Uq~TuG0yeX87su zrX3vuT^b|X`dfg4t=Qe=sa-N4sQB=*9^1h-r%I52{8&=n4OcS_v|%zwGa$bik1Z5p zLr_l!P1+_^+SIo}%7o&ls95!CV~P#8`n0 z4$Hr2Kd7qRy3$2GGu{P-ZYCGxMy@vZ-RLbk_Ho5Cmd>8VEQ>G9Vfqx@GpOu+u20>M z=jyFC9xuDWZh#Eik#baB1{J}wK+2vQhE~Cs-b!0II$niqk}CX9O+RlcYqkTY%sGR? zy@R59{B*OX)Ulz0QTY66(CE_-|Ka201utXO+^vWV7nmz0lxwMB zGl)szwn7G(l1#7qf)h#ow%?poxA2nZEwZL>55P7=EX`n(_ z6h%CU#jWt$D+0#8=_1D%;6kl0ZEB0NvS?DTz=D!1g+jYpT5j(B*G zPz}4)aqQ$sgm*(QqCJsMWc5*3Ti0|REpY9PzDNV%Frh}sCXy>nl3?c?+_#FD{YUO+eLbZaD&;R8axvY!N2O zXx#u&0V~6O_wa+W6J-W+lJL@yy+cD77#lM)GCqFv2z33>^$(!Im~Mj=A4CgsR;x(692=^zr=^~XV^dq_vY zVhFqJ;ShJYh?HOT4Gp+R4fYC!ovW7AD9W;930f_lKfGf%()CMm5ON%nV?cY z(By;>qC1Jq*nl(w%<{Q$Z2-F1&EyG8kUN13+|X+wSWR4&+q`m3>N z^zW0Tu-+70)#m2c*~nl4f)W%|XDzkTo4w3|ddO8+VsRZ}rJM{8N*Kd=u2c9aFD<=$ z@M5jTkD-10_pfIg7Qbj@cY!Oq`D|jMI&48zcU$fBWgw%yz3#ArlSnl{mB#AA z3i(UX&G3WL2){`WP80H26%NHI2Ye~Qd&lQXK>F(Wg&oKE z0?PfK`%v2B5qbA3u}zJ4$6)|J&Ot z2!qxEIKeuV2!W}-fb&%(lLM6sZZX>>pU>}cdy>sE1xVY!nU9Ft@41ZqIDXG+_C0np zMeB58#5K7Z8iEK7SgK3OIu8m}sCM z8!TLDAI5`$16aWW`6ndm%e@dx$sqZ33z1XI*JB?v@i;PX-AtpF#04FX&A&gKSCB;) z<%c=-R5eAYI&BuKpA$^#_!uAnDOjTMNxX zQgMLbW%REcDNS|e3P}wxh+8->#U&2dg{i{SyZUm~E^a@OHOeh?MAGjN&L!zWn=24( zrPl%4N$~YmNhlv1`(O~-{$}aNk9&9TLJxvX8PM1Da(f=xSK!tGpp3MeM~xr7Ap5Fngb$No%6&+;GFjQslu zMUeSCfpHK-Eie?)SLmd;Ivm>C=zlf+q3DnVrLlcyVJ34|(S6&PccbbR(p};=Plq5N zsUg*(3`ap}?T}nGxf0q=Ge0Cpc`MlNH(AH-9J-}Yjj<0Oq|O_FD?&j4xF{ScV9Z}@ zEyd0JH;rfBk{!OCUr$n!Zdc$!nj7wn$))+XzmR{0r5@x?i0|)gy1J|M7+fUe)Qi!0*5D&-=v7wcMaQ%k}4FgRt|zJBR#lT%(WqVRqD@nt`N6 zK!Yp|$Fn=i-18*3$jLc5GxOM~5~MPcbcdTP>!4`-SqvvK&5j@r!4b8lMV4OJ2R%Cu zjhdDU9fXHmya>JqcuLo_xa4`uL^DSV?vaMFN=ojjR!P>|UW86$2t z>uAXv9rlv^KM}(6w7l*3V`t7~Ey@x@sM3d3Kd-Sds{8{)m!a8mZ z2{*TObd20Np8e-#z)cGGW{2dtO`l=Hj#1+up40JTUNYPrLNU6&7RZdq_J4I2t9Q)E zN-=;>kugaq*F(6US<8X@DEBxWo;N)h~Vlw(exA!Db-?i@38ptn~ZlLL(9+ux9!NhKvE^`CR$rwUrSwf?(}i3AJ~9wl!gLV)vtzm-0BIF8LP z0wJv|t07t<`_XyE<~2)htmHi zC!w%W5WCeDEO6{WmV3&vrJJ-T`mYqBn=)`n(OZALb%UUUQ6KALfNEo!aFsl@$!^uJ zYI^daOI`hSBK7PxCI=i*V1p1LI4?d7RfKo%q#&Tw1-+7PG9F}XXatqQFL2X}N=w&! zzj+*Exl=7nr&niBW3^}K zad0sZUsY1#hRTAyCAbRa#o$`q!;ArVE%qxslrRNltN0;ybxT_Ndnm9=OUV=!T&d-g zU;Z<>X2o;n>8j{vkeSfXqB3IH|6j-`r)+IC=9h3|L2pmMU!=IC1oSRIPe8n2O$Ce@ z$a)>XRnX}MPVck$&>s#GkM*7I=g&zluT2`ffU!2fV?akohd2)~c+Jhd-}V$dc(7yU zafbSt9hW-S0}W6GKKB5uJb#3!ZA<5Qu3?r?7X1H*_sg*Z;s4S5C1RH4<`XE{;I|wW zdN~Q{Qx+$1Yg0*_M-zjWOlY8uN8;Z9SJ!pNQ~AGd6b`awWn_j@R+7wPk4mV7LZXDS zl09-V$|y<4$jGLolu*jdXc$q_B9+l1$>w`K_4LrO*jAy(dSwU8SM+!I0NmiTkqD?Y=;*Bv=YF%tX9r~!U5%q z@OB?bP0fR4{X%RbuwXDVHXig^PD%!)9u)3BEqo5(7>otF-!RY82*d&B#jbS94brLX zpz#v)NWWkckbY9`qA?8($WK^&z`QLgodTS6tyrfzM451Ovg_nU?1E z%FQ}u)^p<>bQ9kTGj@vS7)vO5Byd#iBNZ!>lw48-;`sBp@2Lsw?^@kTp;~&gx*o|K zZ7%4IQ0W~}RezRFv8 z_i9G?`S#O0X6)0Vuib5|~%1n1IVM<#yq8y))04qh%;y}3^K8bMX{^ zT8O|17)HcPb#mo#1qCh^7F|edjeDhI%zUy~3)U6!$E--XuuvR?>y5`TK9I#wWTQE5 zS5$PVS$O;UMuj(EtK*hKKEPxCx-iRjwT0E%1OWJO1mbD7v$VVx7IqlvI@Wrdc-_CH zz@>$kOCEs!#}Sq3xwE$UoQ#YyP=D1Q4@7DiJOLbR^o9Q%p<7K)FL0zNHaWd}a!qY+ zmp=`fU+gXPH5vCm2$}Qg7#ZS!;d5%^QMg_Mj@Nwy7`=D6lamZ=wxVGkxhvn;|b171vr z4$mjxnc<3l94z-{P&tu0`T_wV0FM$$guLPR3? zSV?@7?47@@&YB9VY7l`S2l$eg|lzcn1NX8{~_lkqCrUlFrRfK67w=#IuYBYUmBfuSg$(!^6Jp zd2S}$n#g2Pv^-yJVW^vZOJQ<@PmNG`TU(q;uYN<0=lD&7-+Rxt_4o5<{n{X$$K+T9 zTYE=O&z1;$O#@l8yZY|0Hke;XTva!72k2H8Xj^kP@p z$;NPBxgy+O%)XOzEW&jqa*~0(TZW&GUi-0ectn(@dCfJLn^wYO4SOW5>_-5136-de zi<4Dv44NkZEMgRNE+8g>OTc6niJk=@(_?rz;&8^B#nruYbtCXcLqkKTNhW)WGBVx} z$OOMyU{KJH*Of7yBbap@9t3a}+O4J|Okx2XgBIR8GPVDPZGqM*w6g36Jy8$PGQp^X zkM1{OPJr{^5v7owLP8c{gFKz7hc5ITHbDG`0t4sZVRW|D1BtO9O@X}u!X?lNs1F3U ztwJ6eIM$1(28awflL}rT5zlk8?vJ27ILo>jDWfS{Q<|IgNecY@{E&}4f{91S4@C2z z{8K~0UjX}U8u+vf%LbsGCu}NRS)ZnYn=FK{J*Tv1|067xC>AK&_`EO?B#*+b#TNf7 zd@c?$WKE#hOEXA<&m4PFmxSx+;_7;)hk5lGm_>oNp58ffzozEK!TW@DK11DkFdoRo zDBw8y%gW5qsE*{zjso`1;3Okr29v6MNODR_^PsLuioyTxD18?fDZf_CrzY;9=wZ=m zc**lHV*-Jnn(?)$^PnytJ{c7zb;|vsI#|B|XgJR9(9p;PEo+|+tLhOt9iDT`{^yRB zrR8SnGN!y?i`2P5rIPA~aK1%tW7r7sH!(dvrX6BYy!`pN)pNLYVvM3#fE-DnsJa@> zQU;Q@twq(vdl;6MR}HgLvMdxpd z2g?)i4Cy*1n--|UL?8k^SDP<|Zgs=gTJ+%AN z)Etg+X=y1d86L=-XNSPmy0%Uc+WmdAs)KlCPo1jOK`zVf?Bd+6pUOAK9nF_P#2Y$6F+;72y0 zorQ}Xk~o$npOFz$%dr`_{bq-U@t61ITG)dPj~|^ls;|G=+c!2V1QbR*e9zDrVvW9W zWAOZM+45Dx^X8(*uPLqAMi4$QB?q4b1X&j1ey9D+qM}_TSOnFCyYCCQ_gHP@KQ6C*|)ot+M zfD?httoc=^nUY$zXFKjBoj#l}L!oh?*WzM}5%Djvw@SYC#oUhdt2gF$D`jY0ujknG z+J`E{J#r3ahQRe?-kYC1dh{MTD=?z4{UG84Uuil`A)mPZthJoHoSfyOAw13jmHQFg z_c#Vr)v}+#nAoaW5;^9rMvoW^x0)}81`jN!o9{GTlCt`0a3exBdw>-TVjK`ttd+IrFnV7AT1!YN1}wsoCCe-zI>IF+ zw8D`t06<~&6>Wq(DO|(a784sHz_1B0k>q;YjSvuqDK`%fArTSRD&pa|3iT{(s{V#9 zAx=C@Sz-Tu3Oex=@K&mY`oh)@l?TE1JK)fT&EzdRf@SM)mBFV=WJ zWq6pwXYPL(bJ(~hsnr*nkI6}g z=s>L4JrCSSTbpRuzfb#HhsnkTwU>>pts`iWFf@r3*fL6+q@ntdG1JGl8{W*D6M#uY-Odv0<*yDajnnz;QA*v63H}|W>26bN z=JSezdCs>?j5Ie>*e>Tp2-u#$hu<}29FG8kUuWtBaE1q%<#UcVRb?Noh*R0SDz}>> z{#&bBeDv6UYn=At;A()|0unen9)wtmUyK--TUZd??sEhVk$8D2?@EACae*`2Nl;#4 zXB5KfR@}rjVMh`}^@5M%chyYq#+;A?zOY-UV)mi~tT!m!NcTV|Of5A66>9AP!<@N4Xrdabp>@ zU3h_muz*Sm4^$Kr5sCJ2+CRV3w4%@byGh_Yh-*|)0mTQukPx`LpgHJkfz6^j0-!4d zq6IW0hi_Gvl*F|T>vCA{-p%ekQmZ(f7I3HmPBZAn!MxG^zGqxPhP#8B+iu~N6mah9 zz)*6nqTZ7wFz=mmlmG!}SVW2;K3I}IdtI(p{6b)Ax^ZQXf8}>xpRQ&hMmhd8bAQau zxcJ5fd_X;+$G&egA=JsTzkZTcC8>LB%FvKgXyTD*3jdbozP@P?0UbYqI7BefOG-c- z3dpQD+9`6pU7VAw)@D;;ecXI!o8;4K+%Dhnpyw`V|1FZ0*IIn zf{+@|72tW)e<&~u!`K}6Wv87xpw0-~NER$9FOQyV0=pco_g&!(Gupx}X72kqPmA?9uYFvKRhU>}4y58I~S!rW^Zq`A_}i^|5F=vT7|_Z5w-N z247xvU%_w)d^X1h4N}zs=Y{5lpLZiq*01Zeq2KQTWe=7b=9>OZ(X4|m*bhK}*?Z&s zbIDo=wd|4nte34dNWRCqvy65|FkGp^Qts0Rn zp9h5_NCD$ZbMM}+l|K^`9MFvjI70~9E4!^w3-)56lP!FtT!2IMY}@c4VgabQR;4q= zT*jGe>k9^#nb=O&42{6soF8YOH30ne9a7^|%Mtz+nvj%q={dtz+fZYRKU3FL|DGIu zn|&2x+Zp6$XGL(=Jm@x+&=6tYeQVgG5zR_PbldPG0OdQETVjGWLg!P$cH4@=o>pw} zVo9C>2idC7yn%Dy0GmbLi_Rtiep!Bb9Gj?%PC-$fBi#3Dlhx2DgN6w&WERH$N_n9K zs{WEBS35SV#73J+EuM_Vc{12#*YjE{#fi8uq=2Z@?&7#J-%odw-jvd{zkp-}B{Fwf z>N}}bfbs>_0(d4U7T~kE4M!?Y3lw$0!VS#Ii1g~(T4O>&`JtDTM1!Lb)=Qb|42yav{3!jM+6= zp$_Hw$NL|lY{O&(FCq)f=q)GF^;Wj@-VsZ7a=bWO7l_NOaIaUZYnRASI=)dXp@z6EX{ zDk7=iXXbV;yIF=l?eH-fjLHI9(2&}9#p++za&b9I^{MF_PEYN}-s5YEJxzp2IwLA_2pu%TmmyQ%byU9c#F4&aoo)+FC?HcQ& zp&=;~83FfZ05EQkO|?LP8O?0Y>lqaJ$rDGK0!bT1skcsvf-Hx7l_Wtj8kp zF)*G6tg5Z@JOX4GZnh$B*|n9G%2{pSu#bIdOI%nqb?en3cqOT92>bfwOBME@)z3lM ztguaQY^Zcmb1BW@cUVHyJs)-XRz(Gt2Ql;NM^Ii>JkWs;SPoc4c!x^E^O=PYuu;Au zQ&Ma2$ko$>>s7fhRrmb6+MjV)aHO#wYzGaxXAVhA%pTlEI|kng8kXg=!DT%mI0jV9 za`=HvzJc0pJt`-nhH?^ltdw%slu0{t_`Mwl+Le=p1V_T;H+h8}e#5w!xzjktrS^b! zdN5q!6N*M=ROIU5X{WcH%01y-k#om(T>IWCGsCE6(~@%F5yXEmP+nvA5{f9HwQFIO z(bwOPD|rk-^xz|54A-Dl09p%d|L`Q%3^+7^3s251LdXxCikF9{{$U8vL?ZO41}YqG z?6#~N>Ri}iyaRR=o+m^{K$HggGqlxPRa9`)!|VYS9nK(QJ7QV%Yw?9Z5vfTWUBehA zu9y~J5XA5PGc&Vc>vwgsGVHq*&_QBxjaU%KB4?3cZD`my3yC$z5@Y>)jEb%=w;j2S zlb}B1adY$R!or6~;Q%;To~I_p#?pijynJb>p-oNnnovB1l{3zc>&3+g^pgWO;M=#} zgL{X|5a@#`_on~P_pFZs(Di^$4ipOI3``l&c88zaBilVHc=hY9qfc@8z$9{g!4f7* zyf+IgE6@n^#rI$VP&F9Pam{h;pr1QuSt*hTu+o|I+69Kq2h=-anf40BNbuAf%8%cu z!?64U^bE*EG-RRy#@{td5Qj1j=Wpe4jn@FH(NW#G;W5CIPL}1x;fr`7nJwcq3o{@pf z98>#Wg%X*ltW|gJ=;UwNRNWLauO>ZQ<^W(07C@j_9E{X)Jb5zdN=2NtwKY6(<4PP> z^S?S8{}=Ol3ZNTKqL7?|@OS34CM^j4f_k51&!0&+9hl2|t5gn3plU0`bynWK?Gq5d zKR;g)t|w9GQ-mQHb%CG{6%>3%&kaHvf)WgBTe|`|&^ihHF@J0^THT7ZEY>KxKB|0t zSCAOX{RreDbfx2)ZMV6))Qn?AG8D<2DA7au`w+hPsXh8QD0C{g>bvHvzz0GnOQIl0-&~pt5obIe~dZ6XK+Jqc;?g1 z^PE8M@g5p;Pev>&pGDn4w*wLre4sHHTPhgB>k9n&@P$8~uHl?$UgO~RvjvZQ_}mkR z3ECkY9QaU;8X3h@)jh!J`1t+b=d+f-CWv)mUk*fJ-0pEv=~`siQ$6+;vdU2KogI;pWrRk{c`LH-N$ z4~uUQVe<0yW&(G#c@1$){{HQE`ZOdqI8A_NL_Z%CbXeLXFApRdq6;k3V7Fjq_5_WS z&5}XHflz58#~I2yPftxHC4@Pd4(!iag@bDG;O}nn%4uu;r@6@hT!3;R=pomF5abqx zEIx|Tyrf7{|8cQ(IIiXJMdN&HIRt?wUdWA`v)R0}zl^;yEGv<1H15EXyUc=OI}2A#^GXi)p)B^0LD>l;3gyZWdpewbFP$BOK;y0(UK_8zD?%Em0^r|eammmvbqg= zKhK>gJ8Ej?^xG`{{mhmx&#!(R9**JwmUP&;atHDAtt<4>@69{G;e6eoo&-@1`Ql;ns literal 0 HcmV?d00001 diff --git a/metadata/en-US/short_description.txt b/metadata/en-US/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/en-US/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/en-US/title.txt b/metadata/en-US/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/en-US/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/en/full_description.txt b/metadata/en/full_description.txt new file mode 100644 index 0000000..7972e6a --- /dev/null +++ b/metadata/en/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. diff --git a/metadata/en/short_description.txt b/metadata/en/short_description.txt new file mode 100644 index 0000000..cdb3e7b --- /dev/null +++ b/metadata/en/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. diff --git a/metadata/en/title.txt b/metadata/en/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/en/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/eo/full_description.txt b/metadata/eo/full_description.txt new file mode 100644 index 0000000..0ff2ea9 --- /dev/null +++ b/metadata/eo/full_description.txt @@ -0,0 +1,9 @@ +Libera kaj malfermkoda reklamblokilo por Android. + +Tiu ĉi aplikaĵo estas destinita por aparatoj kun ĉefuzanta (root) aliro kaj sen tiu ĉi aliro. +Ĉe aparatoj kun ĉefuzanta aliro, la aplikaĵo modifas la dosieron “hostsâ€, kiu enhavas mapigojn servilnomo → IP‑adreso. +ĈE aparatoj sen ĉefuzanta aliro, la aplikaĵo uzas VPN por bloki elirajn konektojn al reklamoj kaj spuriloj. +Do kiam aplikaĵo petas pri reklamo/spurilo, kiu estas gastigata ĉe servilo listigita en la dosiero “hostsâ€, tiu ĉi peto estas aldirektata al la loka IP‑adreso 127.0.0.1, kiu faras nenion. + +La aplikaĵo liveras elÅuteblan liston de serviloj de reklamoj kaj elementoj por bloki. Sed ankaÅ­ vi povas aldoni proprajn listojn aÅ­ individuajn servilojn al permesataj/blokataj listoj. +Estas funkcio ruli lokan retservilon por respondi al blokataj nomregnoj kaj aldirekti petojn al iu alia elektita IP-adreso. \ No newline at end of file diff --git a/metadata/eo/short_description.txt b/metadata/eo/short_description.txt new file mode 100644 index 0000000..147862a --- /dev/null +++ b/metadata/eo/short_description.txt @@ -0,0 +1 @@ +Malfermkoda reklamblokilo por Android. \ No newline at end of file diff --git a/metadata/eo/title.txt b/metadata/eo/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/eo/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/es-MX/full_description.txt b/metadata/es-MX/full_description.txt new file mode 100644 index 0000000..0d436f0 --- /dev/null +++ b/metadata/es-MX/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +Hay, igualmente, opciones para iniciar un servidor web local para responder a los hosts bloqueados, y para dirigir pedidos a la dirección IP que desees. \ No newline at end of file diff --git a/metadata/es-MX/short_description.txt b/metadata/es-MX/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/es-MX/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/es-MX/title.txt b/metadata/es-MX/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/es-MX/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/es-rMX/full_description.txt b/metadata/es-rMX/full_description.txt new file mode 100644 index 0000000..0d436f0 --- /dev/null +++ b/metadata/es-rMX/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +Hay, igualmente, opciones para iniciar un servidor web local para responder a los hosts bloqueados, y para dirigir pedidos a la dirección IP que desees. \ No newline at end of file diff --git a/metadata/es-rMX/short_description.txt b/metadata/es-rMX/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/es-rMX/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/es/full_description.txt b/metadata/es/full_description.txt new file mode 100644 index 0000000..1e8a138 --- /dev/null +++ b/metadata/es/full_description.txt @@ -0,0 +1,9 @@ +Un bloqueador de anuncios gratuito y de código abierto para Android. + +La aplicación está disponible para dispositivos rooteados y no rooteados. +Al usar un dispositivo rooteado, la aplicación actualiza el archivo hosts de tu sistema que contiene una lista de asignaciones entre los nombres de host y las direcciones IP. +Usando un dispositivo no rooteado, la aplicación utiliza la función VPN para bloquear las conexiones salientes a anuncios y rastreadores. +Por lo tanto, cuando una aplicación solicita un anuncio o un rastreador de un host en ese archivo, esta solicitud se redirige a la IP local 127.0.0.1, que no hace nada. + +Puedes descargar listas de anuncios y rastreadores predefinidas como archivos hosts desde la aplicación para incorporarlas. También es posible utilizar tus propios archivos y añadir hosts determinados a las listas de permitido o bloqueado. +Existen opciones para ejecutar un servidor web local que responda a los nombres de los host bloqueados y, en su lugar, dirija las solicitudes a la dirección IP de tu elección. diff --git a/metadata/es/short_description.txt b/metadata/es/short_description.txt new file mode 100644 index 0000000..ee9a40c --- /dev/null +++ b/metadata/es/short_description.txt @@ -0,0 +1 @@ +Un bloqueador de anuncios libre y de código abierto para Android. \ No newline at end of file diff --git a/metadata/es/title.txt b/metadata/es/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/es/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/et/full_description.txt b/metadata/et/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/et/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/et/short_description.txt b/metadata/et/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/et/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/et/title.txt b/metadata/et/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/et/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/eu/full_description.txt b/metadata/eu/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/eu/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/eu/short_description.txt b/metadata/eu/short_description.txt new file mode 100644 index 0000000..01d83ae --- /dev/null +++ b/metadata/eu/short_description.txt @@ -0,0 +1 @@ +Iragarki blokeatzaile librea Android plataformarako. \ No newline at end of file diff --git a/metadata/eu/title.txt b/metadata/eu/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/eu/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/fa/full_description.txt b/metadata/fa/full_description.txt new file mode 100644 index 0000000..7050ec3 --- /dev/null +++ b/metadata/fa/full_description.txt @@ -0,0 +1,9 @@ +یکی از بهترین برنامه های رایگان Ùˆ منبع باز مسدود کننده تبلیغات برای گوشی های اندروید + +این برنامه برای دستگاه های روت شده Ùˆ بدون روت در دسترس است +در حالت Ø§Ø³ØªÙØ§Ø¯Ù‡ از روت برنامه ÙØ§ÛŒÙ„ hosts سیستم شما را به روز رسانی Ù…ÛŒ کند Ú©Ù‡ شامل لیستی از نگاشت ها بین نام host Ùˆ آدرس های IP است +در حالت Ø§Ø³ØªÙØ§Ø¯Ù‡ بدون روت برنامه از ویژگی VPN برای مسدود کردن اتصالات خروجی به تبلیغات Ùˆ ردیاب ها Ø§Ø³ØªÙØ§Ø¯Ù‡ Ù…ÛŒ کند +بنابراین هنگامی Ú©Ù‡ یک برنامه از یک host در آن ÙØ§ÛŒÙ„ درخواست تبلیغ یا ردیاب Ù…ÛŒ کند این درخواست به IP محلی 127.0.0.1 منتقل Ù…ÛŒ شود Ú©Ù‡ هیچ کاری انجام نمی دهد + +شما می‌توانید تبلیغات از پیش تعریÙ‌ شده Ùˆ Ùهرست‌ های مسدود کننده را به‌ عنوان ÙØ§ÛŒÙ„‌ های hosts از داخل برنامه دانلود کنید تا در آن گنجانده شود همچنین Ù…ÛŒ توانید از ÙØ§ÛŒÙ„ های خود Ø§Ø³ØªÙØ§Ø¯Ù‡ کنید Ùˆ host های خاصی را به لیست های مجاز Ùˆ مسدود شده اضاÙÙ‡ کنید +گزینه‌ هایی برای اجرای یک وب سرور محلی در پاسخ به نام‌ های host مسدود شده Ùˆ انتقال درخواست‌ها به آدرس IP مورد نظر شما وجود دارد diff --git a/metadata/fa/short_description.txt b/metadata/fa/short_description.txt new file mode 100644 index 0000000..30db8c1 --- /dev/null +++ b/metadata/fa/short_description.txt @@ -0,0 +1 @@ +یک مسدودکننده تبلیغات رایگان Ùˆ منبع باز برای اندروید diff --git a/metadata/fa/title.txt b/metadata/fa/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/fa/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/fi/full_description.txt b/metadata/fi/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/fi/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/fi/short_description.txt b/metadata/fi/short_description.txt new file mode 100644 index 0000000..c40ab0b --- /dev/null +++ b/metadata/fi/short_description.txt @@ -0,0 +1 @@ +Ilmainen ja vapaanlähdekoodin mainostenestäjä Androidille. \ No newline at end of file diff --git a/metadata/fi/title.txt b/metadata/fi/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/fi/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/fil/full_description.txt b/metadata/fil/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/fil/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/fil/short_description.txt b/metadata/fil/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/fil/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/fil/title.txt b/metadata/fil/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/fil/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/fr/full_description.txt b/metadata/fr/full_description.txt new file mode 100644 index 0000000..23e64c1 --- /dev/null +++ b/metadata/fr/full_description.txt @@ -0,0 +1,9 @@ +Un bloqueur de publicité libre pour Android. + +L’application est offerte pour les appareils débridés (racine) et non débridés . +Sur un appareil débridé, l’application met à jour le fichier hosts de votre système, qui comprend une liste de correspondances entre noms d’hôtes et adresses IP. +Sur un appareil non débridé, l’application utilise la fonction RPV pour bloquer les connexions sortantes vers les publicités et les traqueurs. +Donc, quand une appli demande une publicité ou un traqueur à un hôte qui se trouve dans ce fichier, cette requête est redirigée vers l’adresse IP locale 127.0.0.1, ce qui ne retourne rien. + +Vous pouvez télécharger des listes prédéfinies de publicités et de bloqueurs, sous la forme de fichiers hosts, à partir de l’appli pour les incorporer. Il est aussi possible d’utiliser vos propres fichiers et d’ajouter certains hôtes aux listes d’acceptation et de blocage. +Des options permettent d’exécuter un serveur Web local pour répondre aux noms d’hôtes bloqués et pour plutôt rediriger les requêtes vers l’adresse IP de votre choix. \ No newline at end of file diff --git a/metadata/fr/short_description.txt b/metadata/fr/short_description.txt new file mode 100644 index 0000000..335e28b --- /dev/null +++ b/metadata/fr/short_description.txt @@ -0,0 +1 @@ +Un bloqueur de publicité libre pour Android. \ No newline at end of file diff --git a/metadata/fr/title.txt b/metadata/fr/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/fr/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/gl/full_description.txt b/metadata/gl/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/gl/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/gl/short_description.txt b/metadata/gl/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/gl/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/gl/title.txt b/metadata/gl/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/gl/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/he/short_description.txt b/metadata/he/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/he/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/hi/full_description.txt b/metadata/hi/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/hi/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/hi/short_description.txt b/metadata/hi/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/hi/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/hi/title.txt b/metadata/hi/title.txt new file mode 100644 index 0000000..5f08754 --- /dev/null +++ b/metadata/hi/title.txt @@ -0,0 +1 @@ +à¤à¤¡ अवे \ No newline at end of file diff --git a/metadata/hr/full_description.txt b/metadata/hr/full_description.txt new file mode 100644 index 0000000..a242e14 --- /dev/null +++ b/metadata/hr/full_description.txt @@ -0,0 +1,9 @@ +Besplatan i otvorenog kôda blokator oglasa za Android. + +Aplikacija je dostupna za rootane i ne-rootane ureÄ‘aje. +KoriÅ¡tenje na rootanim ureÄ‘ajima, aplikacija ažurira vaÅ¡u datoteku poslužitelja sustava koja sadrži popis mapiranja izmeÄ‘u naziva poslužitelja i IP adresa. +KoriÅ¡tenje na ne-rootanim ureÄ‘ajima, aplikacija koristi VPN znaÄajku za blokiranje oglasa i praćenja na odlaznim povezivanjima. +Stoga kada aplikacija zahtijeva oglas ili pratitelja iz poslužitelja s te datoteke, taj zahtjev je preusmjeren na lokalnu IP adresu 127.0.0.1, Å¡to nema daljneg uÄinka. + +Možete preuzeti preddefinirane popise oglasa i blokatora kao datoteke poslužitelja iz aplikacije. Možete koristiti i vlastite datoteke i dodati odreÄ‘ene poslužitelje na popis dopuÅ¡tenih i blokiranih. +Postoje mogućnosti pokretanja lokalnog web poslužitelja kao odgovor na blokirane nazive poslužitelja i izravan zahtjev na vaÅ¡e odabrane IP adrese. \ No newline at end of file diff --git a/metadata/hr/short_description.txt b/metadata/hr/short_description.txt new file mode 100644 index 0000000..f091199 --- /dev/null +++ b/metadata/hr/short_description.txt @@ -0,0 +1 @@ +Besplatan i otvorenog kôda blokator oglasa za Android. \ No newline at end of file diff --git a/metadata/hr/title.txt b/metadata/hr/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/hr/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/hu/full_description.txt b/metadata/hu/full_description.txt new file mode 100644 index 0000000..e049573 --- /dev/null +++ b/metadata/hu/full_description.txt @@ -0,0 +1,9 @@ +Ingyenes és nyílt forráskódú hirdetésblokkoló az Android számára. + +Az alkalmazás elérhetÅ‘ rootolt és nem rootolt eszközökre. +Rootolt eszköz használatával az alkalmazás frissíti a rendszer hosts fájlját, amely tartalmazza a gazdagépnevek és az IP-címek közötti leképezések listáját. +Nem rootolt eszköz használatával az alkalmazás VPN funkcióval blokkolja a hirdetésekhez és a nyomkövetÅ‘khöz irányuló kimenÅ‘ kapcsolatokat. +Tehát, amikor egy alkalmazás hirdetést kér egy adott állomásból, ez a kérés átirányításra kerül a helyi 127.0.0.1 IP-re, amely így nem tesz semmit. + +Letölthetsz elÅ‘re definiált, hirdetéseket és blokk-listákat hosts fájlokként az alkalmazáson belül, hogy beépítsd ezeket. LehetÅ‘ség van saját fájlok használatára, valamint bizonyos gazdagépek hozzáadására az engedélyezett és letiltottak listáihoz. +LehetÅ‘ség van helyi webszerver futtatására, hogy az válaszoljon a blokkolt gazdanevekre és a kéréseket a választott IP címre irányítsa. \ No newline at end of file diff --git a/metadata/hu/short_description.txt b/metadata/hu/short_description.txt new file mode 100644 index 0000000..b7196a0 --- /dev/null +++ b/metadata/hu/short_description.txt @@ -0,0 +1 @@ +Egy ingyenes és nyílt forráskódú reklámblokkoló Androidra \ No newline at end of file diff --git a/metadata/hu/title.txt b/metadata/hu/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/hu/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/id/full_description.txt b/metadata/id/full_description.txt new file mode 100644 index 0000000..4a4853d --- /dev/null +++ b/metadata/id/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +Ada opsi untuk menjalankan sebuah web server lokal untuk menanggapi nama host yang diblok dan mengarahkan permintaan ke alamat IP yang telah kamu pilih. \ No newline at end of file diff --git a/metadata/id/short_description.txt b/metadata/id/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/id/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/id/title.txt b/metadata/id/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/id/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/in/full_description.txt b/metadata/in/full_description.txt new file mode 100644 index 0000000..4a4853d --- /dev/null +++ b/metadata/in/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +Ada opsi untuk menjalankan sebuah web server lokal untuk menanggapi nama host yang diblok dan mengarahkan permintaan ke alamat IP yang telah kamu pilih. \ No newline at end of file diff --git a/metadata/in/short_description.txt b/metadata/in/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/in/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/is/full_description.txt b/metadata/is/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/is/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/is/short_description.txt b/metadata/is/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/is/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/is/title.txt b/metadata/is/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/is/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/it/full_description.txt b/metadata/it/full_description.txt new file mode 100644 index 0000000..5af7c01 --- /dev/null +++ b/metadata/it/full_description.txt @@ -0,0 +1,9 @@ +Un Ad Blocker gratuito e open source per Android. + +L'applicazione è disponibile sia per i dispositivi con e senza root. +Utilizzando un dispositivo con root, l'applicazione aggiorna il file host del tuo sistema che contiene un elenco relazioni tra i nomi host e gli indirizzi IP. +Utilizzando un dispositivo senza root, l'applicazione utilizza una connessione VPN per bloccare le connessioni verso annunci e trackers. +Così quando un'applicazione richiede un annuncio o un tracker da un host, la richiesta viene reindirizzata all'indirizzo IP locale 127.0.0.1, che non fornisce risposta. + +Puoi scaricare liste predefinite di annunci o tracker come file host da utilizzare, direttamente dall'applicazione. È anche possibile utilizzare i propri file e aggiungere specifici host ai quali si vuole bloccare o permettere l'accesso. +Ci sono opzioni che consentono di avviare un web server locale per rispondere ai nomi di host bloccati e per inoltrare le relative richieste all'indirizzo IP di tua preferenza \ No newline at end of file diff --git a/metadata/it/short_description.txt b/metadata/it/short_description.txt new file mode 100644 index 0000000..ded133a --- /dev/null +++ b/metadata/it/short_description.txt @@ -0,0 +1 @@ +Un blocco per annunci pubblicitari gratuito e Open Source per Android. diff --git a/metadata/it/title.txt b/metadata/it/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/it/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/iw/full_description.txt b/metadata/iw/full_description.txt new file mode 100644 index 0000000..7056464 --- /dev/null +++ b/metadata/iw/full_description.txt @@ -0,0 +1,9 @@ +×—×•×¡× ×¤×¨×¡×•×ž×•×ª חינמי ובקוד פתוח ל×נדרו×יד + +זמין ×œ×ž×›×©×™×¨×™× ×‘×¢×œ×™ הרש×ות Root ×•×’× ×œ×œ× ×”×¨×©×ות. +במכשיר בעל הרש×ות Root, ×”×™×™×©×•× ×ž×¢×“×›×Ÿ ×ת קובץ המ××¨×—×™× ×”×ž×•×‘× ×” שלך שמכיל רשימה של ×ž×™×¤×•×™×™× ×‘×™×Ÿ שמות מ××¨×—×™× ×•×›×ª×•×‘×•×ª IP. +במכשיר ש×ינו בעל הרש×ות Root, ×”×™×™×©×•× ×ž×©×ª×ž×© בתכונת ×”Ö¾VPN לצורך חסימת ×—×™×‘×•×¨×™× ×™×•×¦××™× ×œ×ž×•×“×¢×•×ª ולמעקבי×. +לכן ×›×שר ×פליקציה מבקשת מודעה ×ו מעקב ממ×רח ​​בקובץ ×”×–×”, בקשה זו מופנית ×ל ×”Ö¾IP המקומי – 127.0.0.1, ש×ינו עושה דבר. + +ב××¤×©×¨×•×ª×›× ×œ×”×•×¨×™×“ מודעות מוגדרות מר×ש ורשימות חסימה כקבצי מ×רח מתוך ×”×פליקציה ×œ×©× ×©×™×œ×•×‘×. תוכלו ××£ להשתמש ×‘×§×‘×¦×™× ×ž×©×œ×›× ×•×œ×”×•×¡×™×£ מ××¨×—×™× ×ž×¡×•×™×ž×™× ×œ×¨×©×™×ž×•×ª השונות. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/iw/short_description.txt b/metadata/iw/short_description.txt new file mode 100644 index 0000000..fdf5f72 --- /dev/null +++ b/metadata/iw/short_description.txt @@ -0,0 +1 @@ +×—×•×¡× ×¤×¨×¡×•×ž×•×ª חינמי ובקוד פתוח ל×נדרו×יד. \ No newline at end of file diff --git a/metadata/iw/title.txt b/metadata/iw/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/iw/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ja/full_description.txt b/metadata/ja/full_description.txt new file mode 100644 index 0000000..7176f09 --- /dev/null +++ b/metadata/ja/full_description.txt @@ -0,0 +1,9 @@ +フリーã§ã‚ªãƒ¼ãƒ—ンソースã®Androidå‘ã‘広告ブロックソフトã§ã™ã€‚ + +ã“ã®ã‚¢ãƒ—リケーションã¯ã€root化ã•れãŸãƒ‡ãƒã‚¤ã‚¹ãŠã‚ˆã³root化ã•れã¦ã„ãªã„デãƒã‚¤ã‚¹ã§åˆ©ç”¨ã§ãã¾ã™ã€‚ +root化ã•れãŸãƒ‡ãƒã‚¤ã‚¹ã‚’使用ã—ã¦ã€ã‚¢ãƒ—リã¯ãƒ›ã‚¹ãƒˆåã¨IPアドレスã®é–“ã®ãƒžãƒƒãƒ”ングã•れãŸãƒªã‚¹ãƒˆã‚’å«ã‚€ã‚·ã‚¹ãƒ†ãƒ ã®hostsファイルを更新ã—ã¾ã™ã€‚ +root化ã•れã¦ã„ãªã„デãƒã‚¤ã‚¹ã§ã¯ã€ã“ã®ã‚¢ãƒ—リã¯VPN機能を使用ã—ã¦åºƒå‘Šã‚„トラッカーã¸ã®é€ä¿¡ã‚’ブロックã—ã¾ã™ã€‚ +ãã®ãŸã‚ã€ã‚¢ãƒ—リãŒãã®ãƒ•ァイル内ã®ãƒ›ã‚¹ãƒˆã«åºƒå‘Šã‚„トラッカーをリクエストã™ã‚‹ã¨ã€ã“ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯ãƒ­ãƒ¼ã‚«ãƒ«IPã®127.0.0.1ã«ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã•れã€ä½•ã‚‚ã—ã¾ã›ã‚“。 + +定義済ã¿ã®åºƒå‘Šã‚„ブロッカーリストをhostsファイルã¨ã—ã¦ã‚¢ãƒ—リ内ã‹ã‚‰ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ã¦çµ„ã¿è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã™ã€‚ã¾ãŸã€è‡ªåˆ†ã§ä½œæˆã—ãŸãƒ•ァイルを使用ã—ãŸã‚Šã€ç‰¹å®šã®ãƒ›ã‚¹ãƒˆã‚’許å¯ãƒªã‚¹ãƒˆã‚„ブロックリストã«è¿½åŠ ã™ã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚ +ローカルã«Webサーãƒãƒ¼ã‚’建ã¦ã¦é®æ–­ã•れãŸãƒ›ã‚¹ãƒˆåã«å¿œç­”ã™ã‚‹ã“ã¨ã‚„ã€ä»£ã‚りã«è¦æ±‚ã‚’è‡ªåˆ†ã§æ±ºã‚ãŸIPアドレスã«è»¢é€ã™ã‚‹ã‚ªãƒ—ションもã‚りã¾ã™ã€‚ \ No newline at end of file diff --git a/metadata/ja/short_description.txt b/metadata/ja/short_description.txt new file mode 100644 index 0000000..c622d6f --- /dev/null +++ b/metadata/ja/short_description.txt @@ -0,0 +1 @@ +Android用ã®ç„¡æ–™ã‹ã¤ã‚ªãƒ¼ãƒ—ンソースã®åºƒå‘Šãƒ–ロックソフトã§ã™ã€‚ \ No newline at end of file diff --git a/metadata/ja/title.txt b/metadata/ja/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ja/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/km/full_description.txt b/metadata/km/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/km/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/km/short_description.txt b/metadata/km/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/km/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/km/title.txt b/metadata/km/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/km/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ko/full_description.txt b/metadata/ko/full_description.txt new file mode 100644 index 0000000..97f2bfc --- /dev/null +++ b/metadata/ko/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +ì°¨ë‹¨ëœ í˜¸ìŠ¤íŠ¸ ì´ë¦„ì— ì‘답하기 위해 로컬 웹 서버를 실행하고 대신 ì„ íƒí•œ IP 주소로 ìš”ì²­ì„ ì „ë‹¬í•˜ëŠ” ì˜µì…˜ì´ ìžˆìŠµë‹ˆë‹¤. \ No newline at end of file diff --git a/metadata/ko/short_description.txt b/metadata/ko/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ko/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ko/title.txt b/metadata/ko/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ko/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ku/full_description.txt b/metadata/ku/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/ku/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/ku/short_description.txt b/metadata/ku/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ku/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ku/title.txt b/metadata/ku/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ku/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/lt/full_description.txt b/metadata/lt/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/lt/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/lt/short_description.txt b/metadata/lt/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/lt/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/lt/title.txt b/metadata/lt/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/lt/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ml/full_description.txt b/metadata/ml/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/ml/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/ml/short_description.txt b/metadata/ml/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ml/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ml/title.txt b/metadata/ml/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ml/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ms/full_description.txt b/metadata/ms/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/ms/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/ms/short_description.txt b/metadata/ms/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ms/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ms/title.txt b/metadata/ms/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ms/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/my/full_description.txt b/metadata/my/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/my/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/my/short_description.txt b/metadata/my/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/my/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/my/title.txt b/metadata/my/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/my/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/nb-NO/full_description.txt b/metadata/nb-NO/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/nb-NO/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/nb-NO/short_description.txt b/metadata/nb-NO/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/nb-NO/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/nb-NO/title.txt b/metadata/nb-NO/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/nb-NO/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/nb-rNO/full_description.txt b/metadata/nb-rNO/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/nb-rNO/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/nb-rNO/short_description.txt b/metadata/nb-rNO/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/nb-rNO/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ne/full_description.txt b/metadata/ne/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/ne/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/ne/short_description.txt b/metadata/ne/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ne/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ne/title.txt b/metadata/ne/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ne/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/nl/full_description.txt b/metadata/nl/full_description.txt new file mode 100644 index 0000000..008d628 --- /dev/null +++ b/metadata/nl/full_description.txt @@ -0,0 +1,9 @@ +Een gratis en open source advertentie blokkeerder voor Android. + +De app is beschikbaar voor rooted en non-rooted toestellen. +Gebruik makend van een rooted toestel, the app vernieuwd je systeem hosts bestand dat een lijst met koppelingen bevat van host namen en IP adressen. +Gebruik makend van een non-rooted toestel, the app gebruikt VPN om uitgaande connecties naar advertenties en trackers te blokkeren. +Dus wanneer een app reclame opvraagt van een host in dat bestand, wordt dit verzoek doorgestuurd naar het lokale IP-adres 127.0.0.1, wat niets doet. + +U kunt vooraf ingestelde hosts-bestanden in de app downloaden om ze in uw hosts-bestands in te voegen. Het is ook mogelijk uw eigen bestanden te gebruiken en bepaalde hosts aan witte dan wel zwarte lijsten toe te voegen. +Er zijn opties om een lokale webserver uit te voeren, die antwoordt op geblokkeerde hostnamen en verzoeken doorstuurt naar een IP-adres naar keuze. \ No newline at end of file diff --git a/metadata/nl/short_description.txt b/metadata/nl/short_description.txt new file mode 100644 index 0000000..859ed0f --- /dev/null +++ b/metadata/nl/short_description.txt @@ -0,0 +1 @@ +Een gratis en open source advertentie blokkeerder voor Android. \ No newline at end of file diff --git a/metadata/nl/title.txt b/metadata/nl/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/nl/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/no/full_description.txt b/metadata/no/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/no/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/no/short_description.txt b/metadata/no/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/no/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/no/title.txt b/metadata/no/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/no/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/pa/full_description.txt b/metadata/pa/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/pa/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/pa/short_description.txt b/metadata/pa/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/pa/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/pa/title.txt b/metadata/pa/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/pa/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/pl/full_description.txt b/metadata/pl/full_description.txt new file mode 100644 index 0000000..da2cc65 --- /dev/null +++ b/metadata/pl/full_description.txt @@ -0,0 +1,9 @@ +Darmowa aplikacja o otwartym kodzie źródÅ‚owym, sÅ‚użąca do blokowania reklam dla systemu Android. + +Aplikacja jest dostÄ™pna dla urzÄ…dzeÅ„ zrootowanych i nierootowanych. +KorzystajÄ…c z urzÄ…dzenia z dostÄ™pem do roota, aplikacja aktualizuje systemowy plik hostów, który zawiera listÄ™ mapowaÅ„ miÄ™dzy nazwami hostów i adresami IP. +KorzystajÄ…c z urzÄ…dzenia niezrootowanego, aplikacja wykorzystuje funkcjÄ™ VPN do blokowania połączeÅ„ wychodzÄ…cych z reklam i modułów Å›ledzÄ…cych. +Kiedy wiÄ™c aplikacja żąda reklamy lub moduÅ‚u Å›ledzÄ…cego od hosta w tym pliku, żądanie to jest przekierowywane na lokalny adres IP 127.0.0.1, który nic nie robi. + +Możesz pobrać wstÄ™pnie zdefiniowane reklamy i listy blokujÄ…ce jako pliki hostów z poziomu aplikacji, aby je załączyć. Możliwe jest również używanie wÅ‚asnych plików i dodawanie okreÅ›lonych hostów do list dozwolonych i blokowanych. +IstniejÄ… opcje uruchamiania lokalnego serwera WWW w celu odpowiedzi na zablokowane nazwy hostów i kierowania żądaÅ„ na wybrany adres IP. \ No newline at end of file diff --git a/metadata/pl/short_description.txt b/metadata/pl/short_description.txt new file mode 100644 index 0000000..c4a7362 --- /dev/null +++ b/metadata/pl/short_description.txt @@ -0,0 +1 @@ +Darmowy bloker reklam o otwartym kodzie źródÅ‚owym dla systemu Android. \ No newline at end of file diff --git a/metadata/pl/title.txt b/metadata/pl/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/pl/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ps/full_description.txt b/metadata/ps/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/ps/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/ps/short_description.txt b/metadata/ps/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ps/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ps/title.txt b/metadata/ps/title.txt new file mode 100644 index 0000000..4b87621 --- /dev/null +++ b/metadata/ps/title.txt @@ -0,0 +1 @@ +Ø§Ú‰Ø§ÙˆÛ \ No newline at end of file diff --git a/metadata/pt-BR/full_description.txt b/metadata/pt-BR/full_description.txt new file mode 100644 index 0000000..6423698 --- /dev/null +++ b/metadata/pt-BR/full_description.txt @@ -0,0 +1,9 @@ +Um bloqueador de anúncios gratuito e de código aberto para Android. + +O aplicativo está disponível para dispositivos com e sem root. +Usando o dispositivo com acesso root, o aplicativo atualiza o arquivo de hosts do sistema que contém uma lista de mapeamentos entre nomes de host e endereços IP. +Usando um dispositivo sem acesso root, o aplicativo usa o recurso VPN para bloquear conexões de saída para anúncios e rastreadores. +Portanto, quando um aplicativo solicita um anúncio ou rastreador de um host naquele arquivo, essa solicitação é redirecionada para o IP local 127.0.0.1, que não faz nada. + +Você pode baixar anúncios predefinidos e listas de bloqueadores como arquivos de hosts de dentro do aplicativo para incorporar. Também é possível usar seus próprios arquivos e adicionar certos hosts a listas de permitidos e bloqueados. +Há opções para executar um servidor Web local para responder a nomes de host bloqueados ou para direcionar solicitações para o endereço IP de sua escolha. \ No newline at end of file diff --git a/metadata/pt-BR/short_description.txt b/metadata/pt-BR/short_description.txt new file mode 100644 index 0000000..6700649 --- /dev/null +++ b/metadata/pt-BR/short_description.txt @@ -0,0 +1 @@ +Um bloqueador de anúncios gratuito e de código aberto para Android. \ No newline at end of file diff --git a/metadata/pt-BR/title.txt b/metadata/pt-BR/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/pt-BR/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/pt/full_description.txt b/metadata/pt/full_description.txt new file mode 100644 index 0000000..f717992 --- /dev/null +++ b/metadata/pt/full_description.txt @@ -0,0 +1,9 @@ +Um bloqueador de anúncios livre e de código aberto para Android. + +A aplicação está disponível para dispositivos com e sem acesso root. +Usando um dispositivo com acesso root, a aplicação atualiza o ficheiro hosts do sistema que contém uma lista de mapeamentos entre hostnames e endereços IP. +Usando um dispositivo sem acesso root, a aplicação usa a função de VPN para bloquear conexões de saída a anúncios e perseguidores. +Portanto, quando uma aplicação solicita um anúncio ou um perseguidor de um host nesse ficheiro, esse pedido é redirecionado para o IP local 127.0.0.1, que não faz nada. + +Pode descarregar listas de bloqueio de anúncios predefinidas como ficheiros hosts a partir da aplicação para incorporá-los no ficheiro hosts do sistema. Também é possível utilizar os seus próprios ficheiros e adicionar certos hosts às listas de permissão e bloqueio. +Há opção de executar um servidor web local para responder a hostnames bloqueados e, ao invés disso, direcionar estes pedidos para um endereço de IP à sua escolha. diff --git a/metadata/pt/short_description.txt b/metadata/pt/short_description.txt new file mode 100644 index 0000000..9bec22f --- /dev/null +++ b/metadata/pt/short_description.txt @@ -0,0 +1 @@ +Um bloqueador de anúncios livre e de código aberto para Android. diff --git a/metadata/pt/title.txt b/metadata/pt/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/pt/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ro/full_description.txt b/metadata/ro/full_description.txt new file mode 100644 index 0000000..3f8e73c --- /dev/null +++ b/metadata/ro/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +AplicaÈ›ia este disponibilă pe dispozitive cu sau fără acces la root. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +Există opÈ›iuni pentru a rula un server web local ce va răspunde domeniilor blocate cu redirecÈ›ionări la adresa IP aleasă de dumneavoastră. \ No newline at end of file diff --git a/metadata/ro/short_description.txt b/metadata/ro/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ro/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ro/title.txt b/metadata/ro/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ro/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ru/full_description.txt b/metadata/ru/full_description.txt new file mode 100644 index 0000000..0e43a12 --- /dev/null +++ b/metadata/ru/full_description.txt @@ -0,0 +1,9 @@ +БеÑплатный блокировщик рекламы Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом Ð´Ð»Ñ Android. + +Приложение доÑтупно Ð´Ð»Ñ Ñ€ÑƒÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ñ‹Ñ… и нерутированных уÑтройÑтв. +ИÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ñ€ÑƒÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð¾Ðµ уÑтройÑтво, приложение обновлÑет файл hosts, который Ñодержит ÑпиÑок ÑопоÑтавлений между именами хоÑтов и IP-адреÑами. +ИÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð½ÐµÑ€ÑƒÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð¾Ðµ уÑтройÑтво, приложение иÑпользует функцию VPN Ð´Ð»Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ иÑходÑщих Ñоединений Ñ ÑервиÑами рекламы и трекерами. +ПоÑтому, когда приложение запрашивает рекламу или трекер Ñ Ñ…Ð¾Ñта в Ñтом файле, Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÑетÑÑ Ð½Ð° локальный IP-Ð°Ð´Ñ€ÐµÑ 127.0.0.1, который ничего не делает. + +Ð’Ñ‹ можете загрузить предопределенную рекламу и ÑпиÑки блокировки в виде файлов hosts изнутри Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¾Ð±ÑŠÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ. Также возможно иÑпользовать ваши ÑобÑтвенные файлы и добавлÑть определенные хоÑты в ÑпиÑки Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð¸ блокировки. +ИмеетÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñть запуÑка локального веб-Ñервера Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñов к заблокированным адреÑам на выбранный вами IP-адреÑ. diff --git a/metadata/ru/short_description.txt b/metadata/ru/short_description.txt new file mode 100644 index 0000000..3d33f7c --- /dev/null +++ b/metadata/ru/short_description.txt @@ -0,0 +1 @@ +Свободный блокировщик рекламы Ñ Ð¾Ñ‚Ñ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом Ð´Ð»Ñ Android \ No newline at end of file diff --git a/metadata/ru/title.txt b/metadata/ru/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ru/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/si/full_description.txt b/metadata/si/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/si/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/si/short_description.txt b/metadata/si/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/si/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/si/title.txt b/metadata/si/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/si/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/sk/full_description.txt b/metadata/sk/full_description.txt new file mode 100644 index 0000000..50d01ae --- /dev/null +++ b/metadata/sk/full_description.txt @@ -0,0 +1,9 @@ +Bezplatný open source blokovaÄ reklamy pre Android. + +Aplikácia je urÄená pre rootnuté aj nerootnuté zariadenia. +Pri rootnutom zariadení aplikácia aktualizuje váš systémový súbor host tak, že obsahuje zoznam namapovaných hostiteľov a IP adresy. +Pre použitie v nerootnutom zariadení aplikácia používa funkciu VPN, ktorá blokuje odchádzajúce pripojenia na blokovanie reklamy a trackerov. +Takže ak si aplikácia vyžiada hostiteľa reklamy alebo trackera zo súboru, táto požiadavka bude presmerovaná na lokálnu IP adresu 127.0.0.1, ktorá niÄ neurobí. + +Z aplikácie si môžete stiahnuÅ¥ preddefinované zoznamy blokujúce reklamy ako súbor hosts a zlúÄiÅ¥ ich do jedného. Je tiež možné použiÅ¥ vaÅ¡e vlastné súbory a pridaÅ¥ urÄitých hostiteľov do povolených a blokovaných zoznamov. +Je tu aj možnosÅ¥ spustiÅ¥ lokálny webový server, ktorý bude reagovaÅ¥ na blokované hostiteľské názvy a ich požiadavky posielaÅ¥ na vami zvolenú IP adresu. \ No newline at end of file diff --git a/metadata/sk/short_description.txt b/metadata/sk/short_description.txt new file mode 100644 index 0000000..da21078 --- /dev/null +++ b/metadata/sk/short_description.txt @@ -0,0 +1 @@ +Bezplatný open source blokovaÄ reklamy pre Android. \ No newline at end of file diff --git a/metadata/sk/title.txt b/metadata/sk/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/sk/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/sl/full_description.txt b/metadata/sl/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/sl/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/sl/short_description.txt b/metadata/sl/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/sl/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/sl/title.txt b/metadata/sl/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/sl/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/sq/full_description.txt b/metadata/sq/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/sq/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/sq/short_description.txt b/metadata/sq/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/sq/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/sq/title.txt b/metadata/sq/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/sq/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/sr/full_description.txt b/metadata/sr/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/sr/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/sr/short_description.txt b/metadata/sr/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/sr/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/sr/title.txt b/metadata/sr/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/sr/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/sv/full_description.txt b/metadata/sv/full_description.txt new file mode 100644 index 0000000..63527f9 --- /dev/null +++ b/metadata/sv/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +Det finns alternativ att köra en lokal webbserver för att svara pÃ¥ blockerade värdnamn och att rikta förfrÃ¥gningar till den IP-adress du själv önskar. \ No newline at end of file diff --git a/metadata/sv/short_description.txt b/metadata/sv/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/sv/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/sv/title.txt b/metadata/sv/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/sv/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ta/full_description.txt b/metadata/ta/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/ta/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/ta/short_description.txt b/metadata/ta/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ta/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ta/title.txt b/metadata/ta/title.txt new file mode 100644 index 0000000..9e03c6b --- /dev/null +++ b/metadata/ta/title.txt @@ -0,0 +1 @@ +ஆடà¯à®…வே \ No newline at end of file diff --git a/metadata/th/full_description.txt b/metadata/th/full_description.txt new file mode 100644 index 0000000..8eed541 --- /dev/null +++ b/metadata/th/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +มีตัวเลือà¸à¹ƒà¸™à¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸à¹ƒà¸Šà¹‰à¹€à¸§à¹‡à¸šà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸ à¸²à¸¢à¹ƒà¸™à¹€à¸žà¸·à¹ˆà¸­à¸•อบสนองต่อชื่อโฮสต์ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸„à¹à¸¥à¸°à¸ªà¹ˆà¸‡à¸„ำขอไปยังที่อยู่ IP ที่คุณเลือà¸à¹à¸—น \ No newline at end of file diff --git a/metadata/th/short_description.txt b/metadata/th/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/th/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/th/title.txt b/metadata/th/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/th/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/tl/full_description.txt b/metadata/tl/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/tl/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/tl/short_description.txt b/metadata/tl/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/tl/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/tl/title.txt b/metadata/tl/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/tl/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/tr/full_description.txt b/metadata/tr/full_description.txt new file mode 100644 index 0000000..208c555 --- /dev/null +++ b/metadata/tr/full_description.txt @@ -0,0 +1,9 @@ +Android için ücretsiz ve açık kaynak reklam engelleyici. + +Uygulama kök izni olan ve kök izni olmayan cihazlar için uygundur. +Kök izni olan bir cihaz kullanarak, uygulama ana bilgisayar adları ve IP adresleri arasındaki eÅŸlemelerin bir listesini içeren sistem ana bilgisayar dosyanızı günceller. +Kök izni olmayan bir cihaz kullanan uygulama, reklamlara ve izleyicilere giden baÄŸlantıları engellemek için VPN özelliÄŸini kullanır. +Bu nedenle, bir uygulama bu dosyadaki bir ana bilgisayardan bir reklam veya izleyici istediÄŸinde, bu istek hiçbir ÅŸey yapmayan yerel IP 127.0.0.1'e yönlendirilir. + +Önceden tanımlanmış reklamları ve engellenen listeleri, dahil etmek için uygulama içinden ana bilgisayar dosyaları olarak indirebilirsiniz. Kendi dosyalarınızı kullanmak ve izin verilen ve engellenen listelere belirli ana bilgisayarlar eklemek de mümkündür. +Engellenen host adlarına yanıt vermek ve bunun yerine tercih ettiÄŸiniz IP adresine istekleri yönlendirmek için yerel bir web sunucusunu çalıştırma seçenekleri vardır. diff --git a/metadata/tr/short_description.txt b/metadata/tr/short_description.txt new file mode 100644 index 0000000..b827330 --- /dev/null +++ b/metadata/tr/short_description.txt @@ -0,0 +1 @@ +Android için ücretsiz ve açık kaynak reklam engelleyici. \ No newline at end of file diff --git a/metadata/tr/title.txt b/metadata/tr/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/tr/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/uk/full_description.txt b/metadata/uk/full_description.txt new file mode 100644 index 0000000..139039d --- /dev/null +++ b/metadata/uk/full_description.txt @@ -0,0 +1,9 @@ +Безкоштовний блокувальник реклами з відкритим вихідним кодом Ð´Ð»Ñ Android + +ЗаÑтоÑунок доÑтупний Ð´Ð»Ñ Ð¿Ñ€Ð¸Ñтроїв з root-доÑтупом, так Ñ– без нього. +ВикориÑтовуючи приÑтрій з root-доÑтупом, заÑтоÑунок оновлює ÑиÑтемний файл hosts, Ñкий міÑтить ÑпиÑок імен хоÑтів та їхні IP-адреÑи. +ВикориÑтовуючи приÑтрій без root-доÑтупу, заÑтоÑунок буде викориÑтовувати функцію VPN, щоб блокувати вихідні Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð´Ð¾ реклами та трекерів. +Коли заÑтоÑунок надÑилає запит на рекламу чи трекер, ÑиÑтема Android автоматично шукає адреÑу хоÑта Ñ€ÐµÐºÐ»Ð°Ð¼Ð¾Ð´Ð°Ð²Ñ†Ñ Ð² файлі hosts. Якщо такий Ð°Ð´Ñ€ÐµÑ Ð·Ð½Ð°Ð¹Ð´ÐµÐ½Ð¾, то він буде викориÑтовуватиÑÑ Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ. AdAway пропиÑує IP-Ð°Ð´Ñ€ÐµÑ 127.0.0.1, що означає «локальний хоÑт». Отже, в результаті запит на рекламу переÑпрÑмуєтьÑÑ Ð² нікуди. + +Ви можете завантажити готовий ÑпиÑок заблокованих Ð°Ð´Ñ€ÐµÑ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¸ Ñк файл hosts. Також можливо викориÑтовувати Ñвій файл Ñ– додавати певні адреÑи до «білого» та «чорного» ÑпиÑків. +Можливий варіант запуÑку локального веб-Ñервера, щоб він відповідав на заблоковані імена хоÑтів та перенаправлÑв запити до IP-Ð°Ð´Ñ€ÐµÑ Ð½Ð° ваш вибір. \ No newline at end of file diff --git a/metadata/uk/short_description.txt b/metadata/uk/short_description.txt new file mode 100644 index 0000000..d130f07 --- /dev/null +++ b/metadata/uk/short_description.txt @@ -0,0 +1 @@ +Безкоштовний блокувальник реклами з відкритим вихідним кодом Ð´Ð»Ñ Android \ No newline at end of file diff --git a/metadata/uk/title.txt b/metadata/uk/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/uk/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/ur/full_description.txt b/metadata/ur/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/ur/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/ur/short_description.txt b/metadata/ur/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/ur/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/ur/title.txt b/metadata/ur/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/ur/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/uz/full_description.txt b/metadata/uz/full_description.txt new file mode 100644 index 0000000..ae9e217 --- /dev/null +++ b/metadata/uz/full_description.txt @@ -0,0 +1,9 @@ +A Free and Open Source ad blocker for Android. + +The application is available for rooted and non-rooted devices. +Using rooted device, the application update your system hosts file that contains a list of mappings between host names and IP addresses. +Using non-rooted device, the application use the VPN feature to block outgoing connections to ads and trackers. +So when an app requests an ad or a tracker from a host in that file, this request is redirected to the local IP 127.0.0.1, which does nothing. + +You can download predefined ads and blocker lists as hosts files from within the app to incorporate. It is also possible to use your own files and to add certain hosts to allowed and blocked lists. +There are options to run a local web server to respond to blocked host names and to direct requests to the IP address of your choosing instead. \ No newline at end of file diff --git a/metadata/uz/short_description.txt b/metadata/uz/short_description.txt new file mode 100644 index 0000000..10f329a --- /dev/null +++ b/metadata/uz/short_description.txt @@ -0,0 +1 @@ +A free and Open Source ad blocker for Android. \ No newline at end of file diff --git a/metadata/uz/title.txt b/metadata/uz/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/uz/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/vi/full_description.txt b/metadata/vi/full_description.txt new file mode 100644 index 0000000..55b3469 --- /dev/null +++ b/metadata/vi/full_description.txt @@ -0,0 +1,9 @@ +Trình chặn quảng cáo mã nguồn mở cho Android. + +Ứng dụng có sẵn cho các thiết bị đã root và chưa root. +Vá»›i thiết bị đã root, ứng dụng sẽ cập nhật file hosts cá»§a hệ thống bao gồm danh sách chỉ rõ tên máy chá»§ và địa chỉ IP. +Vá»›i thiết bị chưa root, ứng dụng sẽ dùng tính năng VPN để chặn các kết nối tá»›i các quảng cáo và các trình theo dõi. +Do vậy khi má»™t ứng dụng yêu cầu má»™t quảng cáo hoặc má»™t trình giám sát từ má»™t máy chá»§ lưu trữ tệp đó, yêu cầu này sẽ bị chuyển hướng tá»›i IP ná»™i bá»™ là 127.0.0.1, thứ mà sẽ không làm gì hết. + +Bạn có thể tải xuống các danh sách chặn quảng cáo dưới dạng tệp hosts từ trong ứng dụng để tích hợp. Bạn cÅ©ng có thể sá»­ dụng tệp cá»§a riêng mình để thêm má»™t số hosts nhất định vào danh sách cho phép hoặc bị chặn. +Bạn có thể tùy chỉnh cho phép chạy má»™t máy chá»§ web cục bá»™ để trả lá»i tên máy chá»§ bị chặn và chuyển hướng nó đến địa chỉ IP tùy chá»n. \ No newline at end of file diff --git a/metadata/vi/short_description.txt b/metadata/vi/short_description.txt new file mode 100644 index 0000000..ce122d3 --- /dev/null +++ b/metadata/vi/short_description.txt @@ -0,0 +1 @@ +Trình chặn quảng cáo mã nguồn mở cho Android. \ No newline at end of file diff --git a/metadata/vi/title.txt b/metadata/vi/title.txt new file mode 100644 index 0000000..ed7c3b9 --- /dev/null +++ b/metadata/vi/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/zh-TW/full_description.txt b/metadata/zh-TW/full_description.txt new file mode 100644 index 0000000..d78d7a0 --- /dev/null +++ b/metadata/zh-TW/full_description.txt @@ -0,0 +1,9 @@ +開放原始碼的 Android 版廣告阻擋程å¼ã€‚ + +本應用程å¼å¯åœ¨å·² root 與未 root çš„è£ç½®ä¸Šä½¿ç”¨ã€‚ +如果使用已 root çš„è£ç½®ï¼Œæœ¬æ‡‰ç”¨ç¨‹å¼æœƒæ›´æ–°åŒ…å«ä¸»æ©Ÿå稱與 IP ä½å€å°æ‡‰æ¸…單的系統 hosts 檔案。 +如果使用未 root çš„è£ç½®ï¼Œæœ¬æ‡‰ç”¨ç¨‹å¼æœƒä½¿ç”¨ VPN 功能來阻擋廣告與追蹤器的連線。 +因此當應用程å¼å¾žè©²æª”æ¡ˆä¸­çš„ä¸»æ©Ÿè«‹æ±‚å»£å‘Šæˆ–è¿½è¹¤å™¨ï¼Œé€™å€‹è«‹æ±‚æœƒè¢«é‡æ–°å°Žå‘到本機 IP 127.0.0.1ï¼Œä»€éº¼äº‹éƒ½ä¸æœƒç™¼ç”Ÿã€‚ + +您å¯ä»¥åœ¨æ‡‰ç”¨ç¨‹å¼ä¸­ä¸‹è¼‰é å…ˆå®šç¾©çš„廣告阻擋器清單為 hosts 檔案。您也å¯ä»¥ä½¿ç”¨è‡ªå·±çš„æª”案,並將æŸäº›ä¸»æ©ŸåŠ å…¥åˆ°å…許和阻擋清單中。 +å¯ç¶“ç”±é¸é …建立本機網é ä¼ºæœå™¨ä»¥é‡å°è¢«é˜»æ“‹çš„主機å稱連線請求åšå‡ºå›žæ‡‰ä¸¦é‡æ–°å°Žå‘至您自訂的IP ä½å€ã€‚ \ No newline at end of file diff --git a/metadata/zh-TW/short_description.txt b/metadata/zh-TW/short_description.txt new file mode 100644 index 0000000..297b7d2 --- /dev/null +++ b/metadata/zh-TW/short_description.txt @@ -0,0 +1 @@ +開放原始碼的 Android 版廣告阻擋程å¼ã€‚ \ No newline at end of file diff --git a/metadata/zh-TW/title.txt b/metadata/zh-TW/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/zh-TW/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/metadata/zh-rTW/full_description.txt b/metadata/zh-rTW/full_description.txt new file mode 100644 index 0000000..a361f3e --- /dev/null +++ b/metadata/zh-rTW/full_description.txt @@ -0,0 +1,9 @@ +一個專為 Android 設計的å…費且開æºçš„廣告阻擋器。 + +此應用程å¼é©ç”¨æ–¼å·²ç²å¾— root 權é™å’Œæœªç²å¾— root 權é™çš„è£ç½®ã€‚ +å°æ–¼å·²ç²å¾— root 權é™çš„è£ç½®ï¼Œæ‡‰ç”¨ç¨‹å¼æœƒæ›´æ–°æ‚¨çš„系統 hosts 檔案清單,其中包å«ä¸»æ©Ÿå稱與 IP ä½å€ä¹‹é–“的映射。 +å°æ–¼æœªç²å¾— root 權é™çš„è£ç½®ï¼Œæ‡‰ç”¨ç¨‹å¼æœƒä½¿ç”¨ VPN 功能來阻擋å‰å¾€å»£å‘Šå’Œè¿½è¹¤å™¨çš„連線。 +因此,當一個應用程å¼è«‹æ±‚æŸå€‹åœ¨è©²æª”案中的主機æä¾›å»£å‘Šæˆ–è¿½è¹¤å™¨æ™‚ï¼Œè©²è«‹æ±‚æœƒè¢«é‡æ–°å°Žå‘至本機 IP 127.0.0.1,該 IP 䏿œƒé€²è¡Œä»»ä½•æ“作。 + +您å¯ä»¥åœ¨æ‡‰ç”¨ç¨‹å¼å…§ä¸‹è¼‰é å…ˆå®šç¾©çš„廣告和阻擋清單,作為 hosts 檔案來整åˆä½¿ç”¨ã€‚您也å¯ä»¥ä½¿ç”¨è‡ªå·±çš„æª”案,並將特定的主機加入å…許和被阻擋的清單。 +此外,還有é¸é …å¯ä»¥åŸ·è¡Œä¸€å€‹æœ¬æ©Ÿç¶²é ä¼ºæœå™¨ï¼Œä»¥å›žæ‡‰è¢«é˜»æ“‹çš„主機åç¨±ï¼Œä¸¦å°‡è«‹æ±‚é‡æ–°å°Žå‘到您é¸å®šçš„ IP ä½å€ã€‚ diff --git a/metadata/zh-rTW/short_description.txt b/metadata/zh-rTW/short_description.txt new file mode 100644 index 0000000..28f874e --- /dev/null +++ b/metadata/zh-rTW/short_description.txt @@ -0,0 +1 @@ +一個專為 Android 設計的å…費且開æºçš„廣告阻擋器。 diff --git a/metadata/zh/full_description.txt b/metadata/zh/full_description.txt new file mode 100644 index 0000000..40856c6 --- /dev/null +++ b/metadata/zh/full_description.txt @@ -0,0 +1,9 @@ +一款é¢å‘安å“设备的自由和开æºçš„广告拦截应用 + +应用程åºå¯ç”¨äºŽ root è®¾å¤‡å’Œéž root 设备。 +使用 root è®¾å¤‡ï¼Œåº”ç”¨ç¨‹åºæ›´æ–°æ‚¨çš„系统主机文件,该文件包å«ä¸»æœºåå’Œ IP 地å€ä¹‹é—´çš„æ˜ å°„列表。 +ä½¿ç”¨éž root 设备,该应用程åºä½¿ç”¨ VPN 功能,以阻止到广告和跟踪器的传出连接 +因此,当应用程åºä»Žè¯¥æ–‡ä»¶ä¸­çš„主机请求一个广告或跟踪器时,该请求将被é‡å®šå‘到本地IP 127.0.0.1,从而失效。 + +ä½ å¯ä»¥ä»Žåº”用内下载预定义的广告和拦截列表作为主机文件æ¥åˆå¹¶ã€‚你也å¯ä»¥ä½¿ç”¨è‡ªå·±çš„æ–‡ä»¶ï¼Œå¹¶å°†æŸäº›ä¸»æœºæ·»åŠ åˆ°å…许和阻止列表中。 +å¯ä»¥é€‰æ‹©è¿è¡Œä¸€ä¸ªæœ¬åœ°çš„网络æœåС噍æ¥å“应对被拦截的主机å的请求,也å¯ä»¥è¯·æ±‚é‡å®šå‘到指定的 IP 地å€ã€‚ \ No newline at end of file diff --git a/metadata/zh/short_description.txt b/metadata/zh/short_description.txt new file mode 100644 index 0000000..ef02bf0 --- /dev/null +++ b/metadata/zh/short_description.txt @@ -0,0 +1 @@ +一款é¢å‘安å“设备的自由和开æºåº”用 \ No newline at end of file diff --git a/metadata/zh/title.txt b/metadata/zh/title.txt new file mode 100644 index 0000000..df09908 --- /dev/null +++ b/metadata/zh/title.txt @@ -0,0 +1 @@ +AdAway \ No newline at end of file diff --git a/sentrystub/.gitignore b/sentrystub/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/sentrystub/.gitignore @@ -0,0 +1 @@ +/build diff --git a/sentrystub/build.gradle b/sentrystub/build.gradle new file mode 100644 index 0000000..7dcf56e --- /dev/null +++ b/sentrystub/build.gradle @@ -0,0 +1,20 @@ +apply plugin: 'com.android.library' + +android { + compileSdk 33 + namespace 'io.sentry' + + defaultConfig { + minSdk 26 + targetSdk 33 + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sonarqube { + skipProject = true + } +} diff --git a/sentrystub/src/main/AndroidManifest.xml b/sentrystub/src/main/AndroidManifest.xml new file mode 100644 index 0000000..cc947c5 --- /dev/null +++ b/sentrystub/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/sentrystub/src/main/java/io/sentry/Breadcrumb.java b/sentrystub/src/main/java/io/sentry/Breadcrumb.java new file mode 100644 index 0000000..cb07704 --- /dev/null +++ b/sentrystub/src/main/java/io/sentry/Breadcrumb.java @@ -0,0 +1,11 @@ +package io.sentry; + +public class Breadcrumb { + public void setMessage(String message) { + // Stub + } + + public void setLevel(SentryLevel info) { + // Stub + } +} diff --git a/sentrystub/src/main/java/io/sentry/Integration.java b/sentrystub/src/main/java/io/sentry/Integration.java new file mode 100644 index 0000000..cc69f24 --- /dev/null +++ b/sentrystub/src/main/java/io/sentry/Integration.java @@ -0,0 +1,4 @@ +package io.sentry; + +public interface Integration { +} diff --git a/sentrystub/src/main/java/io/sentry/Scope.java b/sentrystub/src/main/java/io/sentry/Scope.java new file mode 100644 index 0000000..8150439 --- /dev/null +++ b/sentrystub/src/main/java/io/sentry/Scope.java @@ -0,0 +1,7 @@ +package io.sentry; + +public class Scope { + public void addBreadcrumb(Breadcrumb breadcrumb) { + // Stub + } +} diff --git a/sentrystub/src/main/java/io/sentry/ScopeCallback.java b/sentrystub/src/main/java/io/sentry/ScopeCallback.java new file mode 100644 index 0000000..15a9429 --- /dev/null +++ b/sentrystub/src/main/java/io/sentry/ScopeCallback.java @@ -0,0 +1,5 @@ +package io.sentry; + +public interface ScopeCallback { + void run(Scope scope); +} diff --git a/sentrystub/src/main/java/io/sentry/Sentry.java b/sentrystub/src/main/java/io/sentry/Sentry.java new file mode 100644 index 0000000..224a4c3 --- /dev/null +++ b/sentrystub/src/main/java/io/sentry/Sentry.java @@ -0,0 +1,18 @@ +package io.sentry; + +public class Sentry { + public static final boolean STUB = true; + + public static void configureScope(ScopeCallback callback) { + // Stub + } + + public interface OptionsConfiguration { + /** + * configure the options + * + * @param options the options + */ + void configure(T options); + } +} diff --git a/sentrystub/src/main/java/io/sentry/SentryLevel.java b/sentrystub/src/main/java/io/sentry/SentryLevel.java new file mode 100644 index 0000000..6cad1b4 --- /dev/null +++ b/sentrystub/src/main/java/io/sentry/SentryLevel.java @@ -0,0 +1,7 @@ +package io.sentry; + +public enum SentryLevel { + INFO, + WARNING, + ERROR +} diff --git a/sentrystub/src/main/java/io/sentry/SentryOptions.java b/sentrystub/src/main/java/io/sentry/SentryOptions.java new file mode 100644 index 0000000..29aa29b --- /dev/null +++ b/sentrystub/src/main/java/io/sentry/SentryOptions.java @@ -0,0 +1,7 @@ +package io.sentry; + +public class SentryOptions { + public void addIntegration(Integration integration) { + // Stub + } +} diff --git a/sentrystub/src/main/java/io/sentry/android/core/SentryAndroid.java b/sentrystub/src/main/java/io/sentry/android/core/SentryAndroid.java new file mode 100644 index 0000000..0f30d40 --- /dev/null +++ b/sentrystub/src/main/java/io/sentry/android/core/SentryAndroid.java @@ -0,0 +1,12 @@ +package io.sentry.android.core; + +import android.content.Context; + +import io.sentry.Sentry; +import io.sentry.SentryOptions; + +public class SentryAndroid { + public static void init(Context context, Sentry.OptionsConfiguration options) { + // Stub + } +} diff --git a/sentrystub/src/main/java/io/sentry/android/fragment/FragmentLifecycleIntegration.java b/sentrystub/src/main/java/io/sentry/android/fragment/FragmentLifecycleIntegration.java new file mode 100644 index 0000000..eb348ae --- /dev/null +++ b/sentrystub/src/main/java/io/sentry/android/fragment/FragmentLifecycleIntegration.java @@ -0,0 +1,11 @@ +package io.sentry.android.fragment; + +import android.app.Application; + +import io.sentry.Integration; + +public class FragmentLifecycleIntegration implements Integration { + public FragmentLifecycleIntegration(Application application, boolean enableFragmentLifecycleBreadcrumbs, boolean enableAutoFragmentLifecycleTracing ) { + // Stub + } +} diff --git a/sentrystub/src/main/java/io/sentry/android/timber/SentryTimberIntegration.java b/sentrystub/src/main/java/io/sentry/android/timber/SentryTimberIntegration.java new file mode 100644 index 0000000..e5a302a --- /dev/null +++ b/sentrystub/src/main/java/io/sentry/android/timber/SentryTimberIntegration.java @@ -0,0 +1,10 @@ +package io.sentry.android.timber; + +import io.sentry.Integration; +import io.sentry.SentryLevel; + +public class SentryTimberIntegration implements Integration { + public SentryTimberIntegration(SentryLevel minEventLevel, SentryLevel minBreadcrumbLevel) { + // Stub + } +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..fbf65a0 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app', ':sentrystub', ':tcpdump', ':webserver' diff --git a/tcpdump/build.gradle b/tcpdump/build.gradle new file mode 100644 index 0000000..6f60292 --- /dev/null +++ b/tcpdump/build.gradle @@ -0,0 +1,66 @@ +import com.android.build.gradle.internal.tasks.LibraryJniLibsTask + +apply plugin: 'com.android.library' + +android { + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + } + } + + compileSdk 33 + ndkVersion '25.2.9519653' + namespace 'org.adaway.libpcap' + + defaultConfig { + minSdkVersion 26 + targetSdkVersion 33 + } + + externalNativeBuild { + ndkBuild { + path 'jni/Android.mk' + } + } + + sonarqube { + skipProject = true + } +} + +/** + * Task to rename executables from hello_world to libhello_world_exec.so + * If they look like libraries, they are packaged in the apk and deployed on the device in the lib folder! + * + * Help with files: https://docs.gradle.org/current/userguide/working_with_files.html + */ +def renameJniLibAsExecutable = tasks.register('renameJniLibAsExecutable', Copy) { + def flavor = gradle.startParameter.taskRequests.toString().containsIgnoreCase("debug") ? "debug" : "release" + def buildFolder = file("${buildDir}/intermediates/ndkBuild/${flavor}/obj/local/") + + dependsOn ":${project.name}:externalNativeBuild${flavor.substring(0, 1).toUpperCase()}${flavor.substring(1)}" + + from(buildFolder) { + exclude "**/objs" + exclude "**/objs-debug" + exclude "**/*.a" + exclude "**/*.d" + exclude "**/*.o" + exclude "**/*.so" + exclude "**/*.txt" + } + + into buildFolder + + rename '(.+)', 'lib$1_exec.so' + + eachFile { + println "Replacing ${it.getPath()} from ${flavor} ndkBuild directory" + } +} + +tasks.withType(LibraryJniLibsTask).configureEach { + dependsOn renameJniLibAsExecutable +} + diff --git a/tcpdump/jni/Android.mk b/tcpdump/jni/Android.mk new file mode 100644 index 0000000..f388264 --- /dev/null +++ b/tcpdump/jni/Android.mk @@ -0,0 +1,3 @@ +include jni/stub/Android.mk +include jni/libpcap/Android.mk +include jni/tcpdump/Android.mk diff --git a/tcpdump/jni/libpcap/Android.mk b/tcpdump/jni/libpcap/Android.mk new file mode 100644 index 0000000..156d108 --- /dev/null +++ b/tcpdump/jni/libpcap/Android.mk @@ -0,0 +1,24 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +libpcap_PSRC = pcap-linux.c +libpcap_FSRC = fad-gifc.c +libpcap_CSRC = pcap.c inet.c gencode.c optimize.c nametoaddr.c etherent.c \ + savefile.c sf-pcap.c sf-pcap-ng.c pcap-common.c \ + bpf_image.c bpf_dump.c +libpcap_GENSRC = scanner.c grammar.c bpf_filter.c version.c + +libpcap_SRC = $(libpcap_PSRC) $(libpcap_FSRC) $(libpcap_CSRC) $(libpcap_GENSRC) + + +LOCAL_SRC_FILES:=\ + $(libpcap_SRC) + +LOCAL_CFLAGS:=-O2 -g +LOCAL_CFLAGS+=-DHAVE_CONFIG_H -D_U_="__attribute__((unused))" -Dlinux -D__GLIBC__ -D_GNU_SOURCE + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) + +LOCAL_MODULE:= libpcap + +include $(BUILD_STATIC_LIBRARY) diff --git a/tcpdump/jni/libpcap/CHANGES b/tcpdump/jni/libpcap/CHANGES new file mode 100644 index 0000000..ef90bbc --- /dev/null +++ b/tcpdump/jni/libpcap/CHANGES @@ -0,0 +1,791 @@ +Saturday Jun. 27, 2015 mcr@sandelman.ca + Summary for 1.7.4 libpcap release + Include fix for GitHub issue #424 -- out of tree builds. + +Friday Apr. 10, 2015 guy@alum.mit.edu + Summary for 1.7.3 libpcap release + Work around a Linux bonding driver bug. + +Thursday Feb. 12, 2015 guy@alum.mit.edu/mcr@sandelman.ca + Summary for 1.7.2 libpcap release + Support for filtering Geneve encapsulated packets. + Generalize encapsulation handling, fixing some bugs. + Don't add null addresses to address lists. + Add pcap_dump_open_append() to open for appending. + Fix the swapping of isochronous descriptors in Linux USB. + Attempt to handle TPACKET_V1 with 32-bit userland and 64-bit kernel. + +Wednesday Nov. 12, 2014 guy@alum.mit.edu/mcr@sandelman.ca + Summary for 1.7.0 libpcap release + Fix handling of zones for BPF on Solaris + new DLT for ZWAVE + clarifications for read timeouts. + Use BPF extensions in compiled filters, fixing VLAN filters + some fixes to compilation without stdint.h + EBUSY can now be returned by SNFv3 code. + Fix the range checks in BPF loads + Various DAG fixes. + Various Linux fixes. + +Monday Aug. 12, 2014 guy@alum.mit.edu + Summary for 1.6.2 libpcap release + Don't crash on filters testing a non-existent link-layer type + field. + Fix sending in non-blocking mode on Linux with memory-mapped + capture. + Fix timestamps when reading pcap-ng files on big-endian + machines. + +Saturday Jul. 19, 2014 mcr@sandelman.ca + Summary for 1.6.1 libpcap release + some fixes for the any device + changes for how --enable-XXX (--enable-sniffing, --enable-can) works + +Wednesday Jul. 2, 2014 mcr@sandelman.ca + Summary for 1.6.0 libpcap release + Don't support D-Bus sniffing on OS X + fixes for byte order issues with NFLOG captures + Handle using cooked mode for DLT_NETLINK in activate_new(). + on platforms where you can not capture on down interfaces, do not list them + but: do list interfaces which are down, if you can capture on them! + +Wednesday December 18, 2013 guy@alum.mit.edu +Summary for 1.5.3 libpcap release + Don't let packets that don't match the current filter get to the + application when TPACKET_V3 is used. (GitHub issue #331) + Fix handling of pcap_loop()/pcap_dispatch() with a packet count + of 0 on some platforms (including Linux with TPACKET_V3). + (GitHub issue #333) + Work around TPACKET_V3 deficiency that causes packets to be lost + when a timeout of 0 is specified. (GitHub issue #335) + Man page formatting fixes. + +Wednesday December 4, 2013 guy@alum.mit.edu +Summary for 1.5.2 libpcap release + Fix libpcap to work when compiled with TPACKET_V3 support and + running on a kernel without TPACKET_V3 support. (GitHub + issue #329) + +Wednesday November 20, 2013 guy@alum.mit.edu +Summary for 1.5.1 libpcap release + Report an error, rather than crashing, if an IPv6 address is + used for link-layer filtering. (Wireshark bug 9376) + +Wednesday October 30, 2013 guy@alum.mit.edu +Summary for 1.5.0 libpcap release + TPACKET_V3 support added for Linux + Point users to the the-tcpdump-group repository on GitHub rather + than the mcr repository + Checks added for malloc()/realloc()/etc. failures + Fixed build on Solaris 11 + Support filtering filtering E1 SS7 traffic on MTP2 layer Annex A + Use "ln -s" to link man pages by default + Add support for getting nanosecond-resolution time stamps when + capturing and reading capture files + Many changes to autoconf to deal better with non-GCC compilers + added many new DLT types + +Saturday April 6, 2013 guy@alum.mit.edu +Summary for 1.4.0 libpcap release + Add netfilter/nfqueue interface. + If we don't have support for IPv6 address resolution, support, + in filter expressions, what IPv6 stuff we can. + Fix pcap-config to include -lpthread if canusb support is + present + Try to fix "pcap_parse not defined" problems when --without-flex + and --without-bison are used when you have Flex and Bison + Fix some issues with the pcap_loop man page. + Fix pcap_getnonblock() and pcap_setnonblock() to fill in the + supplied error message buffer + Fix typo that, it appeared, would cause pcap-libdlpi.c not to + compile (perhaps systems with libdlpi also have BPF and use + that instead) + Catch attempts to call pcap_compile() on a non-activated pcap_t + Fix crash on Linux with CAN-USB support without usbfs + Fix addition of VLAN tags for Linux cooked captures + Check for both EOPNOTSUPP and EINVAL after SIOCETHTOOL ioctl, so + that the driver can report either one if it doesn't support + SIOCETHTOOL + Add DLT_INFINIBAND and DLT_SCTP + Describe "proto XXX" and "protochain XXX" in the pcap-filter man + page + Handle either directories, or symlinks to directories, that + correspond to interfaces in /sys/class/net + Fix handling of VLAN tag insertion to check, on Linux 3.x + kernels, for VLAN tag valid flag + Clean up some man pages + Support libnl3 as well as libnl1 and libnl2 on Linux + Fix handling of Bluetooth devices on 3.x Linux kernels + +Friday March 30, 2012. mcr@sandelman.ca +Summary for 1.3.0 libpcap release + Handle DLT_PFSYNC in {FreeBSD, other *BSD+Mac OS X, other}. + Linux: Don't fail if netfilter isn't enabled in the kernel. + Add new link-layer type for NFC Forum LLCP. + Put the CANUSB stuff into EXTRA_DIST, so it shows up in the release tarball. + Add LINKTYPE_NG40/DLT_NG40. + Add DLT_MPEG_2_TS/LINKTYPE_MPEG_2_TS for MPEG-2 transport streams. + [PATCH] Fix AIX-3.5 crash with read failure during stress + AIX fixes. + Introduce --disable-shared configure option. + Added initial support for canusb devices. + Include the pcap(3PCAP) additions as 1.2.1 changes. + many updates to documentation: pcap.3pcap.in + Improve 'inbound'/'outbound' capture filters under Linux. + Note the cleanup of handling of new DLT_/LINKTYPE_ values. + On Lion, don't build for PPC. + For mac80211 devices we need to clean up monitor mode on exit. + +Friday December 9, 2011. guy@alum.mit.edu. +Summary for 1.2.1 libpcap release + Update README file. + Fix typoes in README.linux file. + Clean up some compiler warnings. + Fix Linux compile problems and tests for ethtool.h. + Treat Debian/kFreeBSD and GNU/Hurd as systems with GNU + toolchains. + Support 802.1 QinQ as a form of VLAN in filters. + Treat "carp" as equivalent to "vrrp" in filters. + Fix code generated for "ip6 protochain". + Add some new link-layer header types. + Support capturing NetFilter log messages on Linux. + Clean up some error messages. + Turn off monitor mode on exit for mac80211 interfaces on Linux. + Fix problems turning monitor mode on for non-mac80211 interfaces + on Linux. + Properly fail if /sys/class/net or /proc/net/dev exist but can't + be opened. + Fail if pcap_activate() is called on an already-activated + pcap_t, and add a test program for that. + Fix filtering in pcap-ng files. + Don't build for PowerPC on Mac OS X Lion. + Simplify handling of new DLT_/LINKTYPE_ values. + Expand pcap(3PCAP) man page. + +Sunday July 24, 2011. mcr@sandelman.ca. +Summary for 1.2 libpcap release + All of the changes listed below for 1.1.1 and 1.1.2. + Changes to error handling for pcap_findalldevs(). + Fix the calculation of the frame size in memory-mapped captures. + Add a link-layer header type for STANAG 5066 D_PDUs. + Add a link-layer type for a variant of 3GPP TS 27.010. + Noted real nature of LINKTYPE_ARCNET. + Add a link-layer type for DVB-CI. + Fix configure-script discovery of VLAN acceleration support. + see http://netoptimizer.blogspot.com/2010/09/tcpdump-vs-vlan-tags.html + Linux, HP-UX, AIX, NetBSD and OpenBSD compilation/conflict fixes. + Protect against including AIX 5.x's having been included. + Add DLT_DBUS, for raw D-Bus messages. + Treat either EPERM or EACCES as "no soup for you". + Changes to permissions on DLPI systems. + Add DLT_IEEE802_15_4_NOFCS for 802.15.4 interfaces. + +Fri. August 6, 2010. guy@alum.mit.edu. +Summary for 1.1.2 libpcap release + Return DLT_ values, not raw LINKTYPE_ values from + pcap_datalink() when reading pcap-ng files + Add support for "wlan ra" and "wlan ta", to check the RA and TA + of WLAN frames that have them + Don't crash if "wlan addr{1,2,3,4}" are used without 802.11 + headers + Do filtering on USB and Bluetooth capturing + On FreeBSD/SPARC64, use -fPIC - it's apparently necessary + Check for valid port numbers (fit in a 16-bit unsigned field) in + "port" filters + Reject attempts to put savefiles into non-blocking mode + Check for "no such device" for the "get the media types" ioctl + in *BSD + Improve error messages from bpf_open(), and let it do the error + handling + Return more specific errors from pcap_can_set_rfmon(); fix + documentation + Update description fetching code for FreeBSD, fix code for + OpenBSD + Ignore /sys/net/dev files if we get ENODEV for them, not just + ENXIO; fixes handling of bonding devices on Linux + Fix check for a constant 0 argument to BPF_DIV + Use the right version of ar when cross-building + Free any filter set on a savefile when the savefile is closed + Include the CFLAGS setting when configure was run in the + compiler flags + Add support for 802.15.4 interfaces on Linux + +Thu. April 1, 2010. guy@alum.mit.edu. +Summary for 1.1.1 libpcap release + Update CHANGES to reflect more of the changes in 1.1.0. + Fix build on RHEL5. + Fix shared library build on AIX. + +Thu. March 11, 2010. ken@netfunctional.ca/guy@alum.mit.edu. +Summary for 1.1.0 libpcap release + Add SocketCAN capture support + Add Myricom SNF API support + Update Endace DAG and ERF support + Add support for shared libraries on Solaris, HP-UX, and AIX + Build, install, and un-install shared libraries by default; + don't build/install shared libraries on platforms we don't support + Fix building from a directory other than the source directory + Fix compiler warnings and builds on some platforms + Update config.guess and config.sub + Support monitor mode on mac80211 devices on Linux + Fix USB memory-mapped capturing on Linux; it requires a new DLT_ + value + On Linux, scan /sys/class/net for devices if we have it; scan + it, or /proc/net/dev if we don't have /sys/class/net, even if + we have getifaddrs(), as it'll find interfaces with no + addresses + Add limited support for reading pcap-ng files + Fix BPF driver-loading error handling on AIX + Support getting the full-length interface description on FreeBSD + In the lexical analyzer, free up any addrinfo structure we got back + from getaddrinfo(). + Add support for BPF and libdlpi in OpenSolaris (and SXCE) + Hyphenate "link-layer" everywhere + Add /sys/kernel/debug/usb/usbmon to the list of usbmon locations + In pcap_read_linux_mmap(), if there are no frames available, call + poll() even if we're in non-blocking mode, so we pick up + errors, and check for the errors in question. + Note that poll() works on BPF devices is Snow Leopard + If an ENXIO or ENETDOWN is received, it may mean the device has + gone away. Deal with it. + For BPF, raise the default capture buffer size to from 32k to 512k + Support ps_ifdrop on Linux + Added a bunch of #ifdef directives to make wpcap.dll (WinPcap) compile + under cygwin. + Changes to Linux mmapped captures. + Fix bug where create_ring would fail for particular snaplen and + buffer size combinations + Update pcap-config so that it handles libpcap requiring + additional libraries + Add workaround for threadsafeness on Windows + Add missing mapping for DLT_ENC <-> LINKTYPE_ENC + DLT: Add DLT_CAN_SOCKETCAN + DLT: Add Solaris ipnet + Don't check for DLT_IPNET if it's not defined + Add link-layer types for Fibre Channel FC-2 + Add link-layer types for Wireless HART + Add link-layer types for AOS + Add link-layer types for DECT + Autoconf fixes (AIX, HP-UX, OSF/1, Tru64 cleanups) + Install headers unconditionally, and include vlan.h/bluetooth.h if + enabled + Autoconf fixes+cleanup + Support enabling/disabling bluetooth (--{en,dis}able-bluetooth) + Support disabling SITA support (--without-sita) + Return -1 on failure to create packet ring (if supported but + creation failed) + Fix handling of 'any' device, so that it can be opened, and no longer + attempt to open it in Monitor mode + Add support for snapshot length for USB Memory-Mapped Interface + Fix configure and build on recent Linux kernels + Fix memory-mapped Linux capture to support pcap_next() and + pcap_next_ex() + Fixes for Linux USB capture + DLT: Add DLT_LINUX_EVDEV + DLT: Add DLT_GSMTAP_UM + DLT: Add DLT_GSMTAP_ABIS + +Mon. October 27, 2008. ken@netfunctional.ca. Summary for 1.0.0 libpcap release + Compile with IPv6 support by default + Compile with large file support on by default + Add pcap-config script, which deals with -I/-L flags for compiling + DLT: Add IPMB + DLT: Add LAPD + DLT: Add AX25 (AX.25 w/KISS header) + DLT: Add JUNIPER_ST + 802.15.4 support + Variable length 802.11 header support + X2E data type support + SITA ACN Interface support - see README.sita + Support for memory-mapped capture on Linux + Support for zerocopy BPF on platforms that support it + Support for setting buffer size when opening devices + Support for setting monitor mode when opening 802.11 devices + Better support for dealing with VLAN tagging/stripping on Linux + Fix dynamic library support on OSX + Return PCAP_ERROR_IFACE_NOT_UP if the interface isn't 'UP', so applications + can print better diagnostic information + Return PCAP_ERROR_PERM_DENIED if we don't have permission to open a device, so + applications can tell the user they need to go play with permissions + On Linux, ignore ENETDOWN so we can continue to capture packets if the + interface goes down and comes back up again. + On Linux, support new tpacket frame headers (2.6.27+) + On Mac OS X, add scripts for changing permissions on /dev/bpf* and launchd plist + On Solaris, support 'passive mode' on systems that support it + Fixes to autoconf and general build environment + Man page reorganization + cleanup + Autogenerate VERSION numbers better + +Mon. September 10, 2007. ken@xelerance.com. Summary for 0.9.8 libpcap release + Change build process to put public libpcap headers into pcap subir + DLT: Add value for IPMI IPMB packets + DLT: Add value for u10 Networks boards + Require for pf definitions - allows reading of pflog formatted + libpcap files on an OS other than where the file was generated + +Wed. April 25, 2007. ken@xelerance.com. Summary for 0.9.6 libpcap release + + Put the public libpcap headers into a pcap subdirectory in both the + source directory and the target include directory, and have include + files at the top-level directory to include those headers, for + backwards compatibility. + Add Bluetooth support + Add USB capturing support on Linux + Add support for the binary USB sniffing interface in Linux + Add support for new FreeBSD BIOCSDIRECTION ioctl + Add additional filter operations for 802.11 frame types + Add support for filtering on MTP2 frame types + Propagate some changes from the main branch, so the x.9 branch has + all the DLT_ and LINKTYPE_ values that the main branch does + Reserved a DLT_ and SAVEFILE_ value for PPI (Per Packet Info) + encapsulated packets + Add LINKTYPE_ for IEEE 802.15.4, with address fields padded as done + by Linux drivers + Add LINKTYPE_ value corresponding to DLT_IEEE802_16_MAC_CPS. + Add DLT for IEEE 802.16 (WiMAX) MAC Common Part Sublayer + Add DLT for Bluetooth HCI UART transport layer + When building a shared library, build with "-fPIC" on Linux to support x86_64 + Link with "$(CC) -shared" rather than "ld -shared" when building a + ".so" shared library + Add support for autoconf 2.60 + Fixes to discard unread packets when changing filters + Changes to handle name changes in the DAG library resulting from + switching to libtool. + Add support for new DAG ERF types. + Add an explicit "-ldag" when building the shared library, so the DAG + library dependency is explicit. + Mac OSX fixes for dealing with "wlt" devices + Fixes in add_or_find_if() & pcap_findalldevs() to optimize generating + device lists + Fixed a bug in pcap_open_live(). The return value of PacketSetHwFilter + was not checked. + +Tue. September 19, 2006. ken@xelerance.com. Summary for 0.9.5 libpcap release + + Support for LAPD frames with vISDN + Support for ERF on channelized T1/E1 cards via DAG API + Fix capitalization that caused issues crossc compiling on Linux + Better failure detection on PacketGetAdapterNames() + Fixes for MPLS packet generation (link layer) + OP_PACKET now matches the beginning of the packet, instead of + beginning+link-layer + Add DLT/LINKTYPE for carrying FRF.16 Multi-link Frame Relay + Fix allocation of buffer for list of link-layer types + Added a new DLT and LINKTYPE value for ARINC 653 Interpartition Communcation Messages + Fixed a typo in a DLT value: it should start with DLT_ and not LINKTYPE_ + Redefined DLT_CAN20B and LINKTYPE_CAN20B as #190 (as this is the right value for CAN). + Added definition for DLT_A429 and LINKTYPE_A429 as #184. + Added a new DLT and LINKTYPE value for CAN v2.0B frames. + Add support for DLT_JUNIPER_VP. + Don't double-count received packets on Linux systems that + support the PACKET_STATISTICS getsockopt() argument on + PF_PACKET sockets. + Add support for DLT_IEEE802_11 and DLT_IEEE802_11_RADIO link + layers in Windows + Add support to build libpcap.lib and wpcap.dll under Cygnus and + MingW32. + +Mon. September 5, 2005. ken@xelerance.com. Summary for 0.9.4 libpcap release + + Support for radiotap on Linux (Mike Kershaw) + Fixes for HP-UX + Support for additional Juniper link-layer types + Fixes for filters on MPLS-encapsulated packets + "vlan" filter fixed + "pppoed" and "pppoes" filters added; the latter modifies later + parts of the filter expression to look at the PPP headers and + headers in the PPP payload + +Tue. July 5, 2005. ken@xelerance.com. Summary for 0.9.3 libpcap release + + Fixes for compiling on nearly every platform, + including improved 64bit support + MSDOS Support + Add support for sending packets + OpenBSD pf format support + IrDA capture (Linux only) + +Tue. March 30, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.3 release + + Fixed minor problem in gencode.c that would appear on 64-bit + platforms. + Version number is now sane. + +Mon. March 29, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.2 release + + updates for autoconf 2.5 + fixes for ppp interfaces for freebsd 4.1 + pcap gencode can generate code for 802.11, IEEE1394, and pflog. + +Wed. November 12, 2003. mcr@sandelman.ottawa.on.ca. Summary for 0.8 release + + added pcap_findalldevs() + Win32 patches from NetGroup, Politecnico di Torino (Italy) + OpenBSD pf, DLT_PFLOG added + Many changes to ATM support. + lookup pcap_lookupnet() + Added DLT_ARCNET_LINUX, DLT_ENC, DLT_IEEE802_11_RADIO, DLT_SUNATM, + DLT_IP_OVER_FC, DLT_FRELAY, others. + Sigh. More AIX wonderfulness. + Document updates. + Changes to API: pcap_next_ex(), pcap_breakloop(), pcap_dump_flush(), + pcap_list_datalinks(), pcap_set_datalink(), + pcap_lib_version(), pcap_datalink_val_to_name(), + pcap_datalink_name_to_val(), new error returns. + +Tuesday, February 25, 2003. fenner@research.att.com. 0.7.2 release + + Support link types that use 802.2 always, never, and sometimes. + Don't decrease the size of the BPF buffer from the default. + Support frame relay. + Handle 32-bit timestamps in DLPI, and pass the right buffer size. + Handle Linux systems with modern kernel but without + SOL_PACKET in the userland headers. + Linux support for ARPHRD_RAWHDLC. + Handle 32-bit timestamps in snoop. + Support eg (Octane/O2xxx/O3xxx Gigabit) devices. + Add new reserved DLT types. + +Monday October 23, 2001. mcr@sandelman.ottawa.on.ca. Summary for 0.7 release + + Added pcap_findalldevs() call to get list of interfaces in a MI way. + + pcap_stats() has been documented as to what its counters mean on + each platform. + +Tuesday January 9, 2001. guy@alum.mit.edu. Summary for 0.6 release + + New Linux libpcap implementation, which, in 2.2 and later + kernels, uses PF_PACKET sockets and supports kernel packet + filtering (if compiled into the kernel), and supports the "any" + device for capturing on all interfaces. Cleans up promiscuous + mode better on pre-2.2 kernels, and has various other fixes + (handles 2.4 ARPHRD_IEEE802_TR, handles ISDN devices better, + doesn't show duplicate packets on loopback interface, etc.). + + Fixed HP-UX libpcap implementation to correctly get the PPA for + an interface, to allow interfaces to be opened by interface name. + + libpcap savefiles have system-independent link-layer type values + in the header, rather than sometimes platform-dependent DLT_ + values, to make it easier to exchange capture files between + different OSes. + + Non-standard capture files produced by some Linux tcpdumps, e.g. + the one from Red Hat Linux 6.2 and later, can now be read. + + Updated autoconf stock files. + + Filter expressions can filter on VLAN IDs and various OSI + protocols, and work on Token Ring (with non-source-routed + packets). + + "pcap_open_dead()" added to allow compiling filter expressions + to pcap code without opening a capture device or capture file. + + Header files fixed to allow use in C++ programs. + + Removed dependancy on native headers for packet layout. + Removed Linux specific headers that were shipped. + + Security fixes: Strcpy replaced with strlcpy, sprintf replaced + with snprintf. + + Fixed bug that could cause subsequent "pcap_compile()"s to fail + erroneously after one compile failed. + + Assorted other bug fixes. + + README.aix and README.linux files added to describe + platform-specific issues. + + "getifaddrs()" rather than SIOCGIFCONF used, if available. + +v0.5 Sat Jun 10 11:09:15 PDT 2000 + +itojun@iijlab.net +- Brought in KAME IPv6/IPsec bpf compiler. +- Fixes for NetBSD. +- Support added for OpenBSD DLT_LOOP and BSD/OS DLT_C_HDLC (Cisco HDLC), + and changes to work around different BSDs having different DLT_ types + with the same numeric value. + +Assar Westerlund +- Building outside the source code tree fixed. +- Changed to write out time stamps with 32-bit seconds and microseconds + fields, regardless of whether those fields are 32 bits or 64 bits in + the OS's native "struct timeval". +- Changed "pcap_lookupdev()" to dynamically grow the buffer into which + the list of interfaces is read as necessary in order to hold the + entire list. + +Greg Troxel +- Added a new "pcap_compile_nopcap()", which lets you compile a filter + expression into a BPF program without having an open live capture or + capture file. + +v0.4 Sat Jul 25 12:40:09 PDT 1998 + +- Fix endian problem with DLT_NULL devices. From FreeBSD via Bill + Fenner (fenner@parc.xerox.com) + +- Fix alignment problem with FDDI under DLPI. This was causing core + dumps under Solaris. + +- Added configure options to disable flex and bison. Resulted from a + bug report by barnett@grymoire.crd.ge.com (Bruce Barnett). Also added + options to disable gcc and to force a particular packet capture type. + +- Added support for Fore ATM interfaces (qaa and fa) under IRIX. Thanks + to John Hawkinson (jhawk@mit.edu) + +- Change Linux PPP and SLIP to use DLT_RAW since the kernel does not + supply any "link layer" data. + +- Change Linux to use SIOCGIFHWADDR ioctl to determine link layer type. + Thanks to Thomas Sailer (sailer@ife.ee.ethz.ch) + +- Change IRIX PPP to use DLT_RAW since the kernel does not supply any + "link layer" data. + +- Modified to support the new BSD/OS 2.1 PPP and SLIP link layer header + formats. + +- Added some new SGI snoop interface types. Thanks to Steve Alexander + (sca@refugee.engr.sgi.com) + +- Fixes for HP-UX 10.20 (which is similar to HP-UX 9). Thanks to + Richard Allen (ra@hp.is) and Steinar Haug (sthaug@nethelp.no) + +- Fddi supports broadcast as reported by Jeff Macdonald + (jeff@iacnet.com). Also correct ieee802 and arcnet. + +- Determine Linux pcap buffer size at run time or else it might not be + big enough for some interface types (e.g. FDDI). Thanks to Jes + Sorensen (Jes.Sorensen@cern.ch) + +- Fix some linux alignment problems. + +- Document promisc argument to pcap_open_live(). Reported by Ian Marsh + (ianm@sics.se) + +- Support Metricom radio packets under Linux. Thanks to Kevin Lai + (laik@gunpowder.stanford.edu) + +- Bind to interface name under Linux to avoid packets from multiple + interfaces on multi-homed hosts. Thanks to Kevin Lai + (laik@gunpowder.stanford.edu) + +- Change L_SET to SEEK_SET for HP-UX. Thanks to Roland Roberts + (rroberts@muller.com) + +- Fixed an uninitialized memory reference found by Kent Vander Velden + (graphix@iastate.edu) + +- Fixed lex pattern for IDs to allow leading digits. As reported by + Theo de Raadt (deraadt@cvs.openbsd.org) + +- Fixed Linux include file problems when using GNU libc. + +- Ifdef ARPHRD_FDDI since not all versions of the Linux kernel have it. + Reported reported by Eric Jacksch (jacksch@tenebris.ca) + +- Fixed bug in pcap_dispatch() that kept it from returning on packet + timeouts. + +- Changed ISLOOPBACK() macro when IFF_LOOPBACK isn't available to check + for "lo" followed by an eos or digit (newer versions of Linux + apparently call the loopback "lo" instead of "lo0"). + +- Fixed Linux networking include files to use ints instead of longs to + avoid problems with 64 bit longs on the alpha. Thanks to Cristian + Gafton (gafton@redhat.com) + +v0.3 Sat Nov 30 20:56:27 PST 1996 + +- Added Linux support. + +- Fixed savefile bugs. + +- Solaris x86 fix from Tim Rylance (t.rylance@elsevier.nl) + +- Add support for bpf kernel port filters. + +- Remove duplicate atalk protocol table entry. Thanks to Christian + Hopps (chopps@water.emich.edu) + +- Fixed pcap_lookupdev() to ignore nonexistent devices. This was + reported to happen under BSD/OS by David Vincenzetti + (vince@cryptonet.it) + +- Avoid solaris compiler warnings. Thanks to Bruce Barnett + (barnett@grymoire.crd.ge.com) + +v0.2.1 Sun Jul 14 03:02:26 PDT 1996 + +- Fixes for HP-UX 10. Thanks in part to to Thomas Wolfram + (wolf@prz.tu-berlin.de) and Rick Jones (raj@hpisrdq.cup.hp.com) + +- Added support for SINIX. Thanks to Andrej Borsenkow + (borsenkow.msk@sni.de) + +- Fixes for AIX (although this system is not yet supported). Thanks to + John Hawkinson (jhawk@mit.edu) + +- Use autoconf's idea of the top level directory in install targets. + Thanks to John Hawkinson. + +- Add missing autoconf packet capture result message. Thanks to Bill + Fenner (fenner@parc.xerox.com) + +- Fixed padding problems in the pf module. + +- Fixed some more alignment problems on the alpha. + +- Added explicit netmask support. Thanks to Steve Nuchia + (steve@research.oknet.com) + +- Fixed to handle raw ip addresses such as 0.0.0.1 without "left + justifing" + +- Add "sca" keyword (for DEC cluster services) as suggested by Terry + Kennedy (terry@spcvxa.spc.edu) + +- Add "atalk" keyword as suggested by John Hawkinson. + +- Add "igrp" keyword. + +- Fixed HID definition in grammar.y to be a string, not a value. + +- Use $CC when checking gcc version. Thanks to Carl Lindberg + (carl_lindberg@blacksmith.com) + +- Removed obsolete reference to pcap_immediate() from the man page. + Michael Stolarchuk (mts@terminator.rs.itd.umich.edu) + +- DLT_NULL has a 4 byte family header. Thanks to Jeffrey Honig + (jch@bsdi.com) + +v0.2 Sun Jun 23 02:28:42 PDT 1996 + +- Add support for HP-UX. Resulted from code contributed by Tom Murray + (tmurray@hpindck.cup.hp.com) and Philippe-Andri Prindeville + (philipp@res.enst.fr) + +- Update INSTALL with a reminder to install include files. Thanks to + Mark Andrews (mandrews@aw.sgi.com) + +- Fix bpf compiler alignment bug on the alpha. + +- Use autoconf to detect architectures that can't handle misaligned + accesses. + +- Added loopback support for snoop. Resulted from report Steve + Alexander (sca@engr.sgi.com) + +v0.1 Fri Apr 28 18:11:03 PDT 1995 + +- Fixed compiler and optimizer bugs. The BPF filter engine uses unsigned + comparison operators, while the code generator and optimizer assumed + signed semantics in several places. Thanks to Charlie Slater + (cslater@imatek.com) for pointing this out. + +- Removed FDDI ifdef's, they aren't really needed. Resulted from report + by Gary Veum (veum@boa.gsfc.nasa.gov). + +- Add pcap-null.c which allows offline use of libpcap on systems that + don't support live package capture. This feature resulting from a + request from Jan van Oorschot (j.p.m.voorschot@et.tudelft.nl). + +- Make bpf_compile() reentrant. Fix thanks to Pascal Hennequin + (Pascal.Hennequin@hugo.int-evry.fr). + +- Port to GNU autoconf. + +- Fix pcap-dlpi.c to work with isdn. Resulted from report by Flemming + Johansen (fsj@csd.cri.dk). + +- Handle multi-digit interface unit numbers (aka ppa's) under dlpi. + Resulted from report by Daniel Ehrlich (ehrlich@cse.psu.edu). + +- Fix pcap-dlpi.c to work in non-promiscuous mode. Resulted from report + by Jeff Murphy (jcmurphy@acsu.buffalo.edu). + +- Add support for "long jumps". Thanks to Jeffrey Mogul + (mogul@pa.dec.com). + +- Fix minor problems when compiling with BDEBUG as noticed by Scott + Bertilson (scott@unet.umn.edu). + +- Declare sys_errlist "const char *const" to avoid problems under + FreeBSD. Resulted from report by jher@eden.com. + +v0.0.6 Fri Apr 28 04:07:13 PDT 1995 + +- Add missing variable declaration missing from 0.0.6 + +v0.0.5 Fri Apr 28 00:22:21 PDT 1995 + +- Workaround for problems when pcap_read() returns 0 due to the timeout + expiring. + +v0.0.4 Thu Apr 20 20:41:48 PDT 1995 + +- Change configuration to not use gcc v2 flags with gcc v1. + +- Fixed a bug in pcap_next(); if pcap_dispatch() returns 0, pcap_next() + should also return 0. Thanks to Richard Stevens (rstevens@noao.edu). + +- Fixed configure to test for snoop before dlpi to avoid problems under + IRIX 5. Thanks to J. Eric Townsend (jet@abulafia.genmagic.com). + +- Hack around deficiency in Ultrix's make. + +- Fix two bugs related to the Solaris pre-5.3.2 bufmod bug; handle + savefiles that have more than snapshot bytes of data in them (so we + can read old savefiles) and avoid writing such files. + +- Added checkioctl which is used with gcc to check that the + "fixincludes" script has been run. + +v0.0.3 Tue Oct 18 18:13:46 PDT 1994 + +- Fixed configure to test for snoop before dlpi to avoid problems under + IRIX 5. Thanks to J. Eric Townsend (jet@abulafia.genmagic.com). + +v0.0.2 Wed Oct 12 20:56:37 PDT 1994 + +- Implement timeout in the dlpi pcap_open_live(). Thanks to Richard + Stevens. + +- Determine pcap link type from dlpi media type. Resulted from report + by Mahesh Jethanandani (mahesh@npix.com). + +v0.0.1 Fri Jun 24 14:50:57 PDT 1994 + +- Fixed bug in nit_setflags() in pcap-snit.c. The streams ioctl timeout + wasn't being initialized sometimes resulting in an "NIOCSFLAGS: + Invalid argument" error under OSF/1. Reported by Matt Day + (mday@artisoft.com) and Danny Mitzel (dmitzel@whitney.hitc.com). + +- Turn on FDDI support by default. + +v0.0 Mon Jun 20 19:20:16 PDT 1994 + +- Initial release. + +- Fixed bug with greater/less keywords, reported by Mark Andrews + (mandrews@alias.com). + +- Fix bug where '|' was defined as BPF_AND instead of BPF_OR, reported + by Elan Amir (elan@leeb.cs.berkeley.edu). + +- Machines with little-endian byte ordering are supported thanks to + Jeff Mogul. + +- Add hack for version 2.3 savefiles which don't have caplen and len + swapped thanks to Vern Paxson. + +- Added "&&" and "||" aliases for "and" and "or" thanks to Vern Paxson. + +- Added length, inbound and outbound keywords. diff --git a/tcpdump/jni/libpcap/CREDITS b/tcpdump/jni/libpcap/CREDITS new file mode 100644 index 0000000..b40152f --- /dev/null +++ b/tcpdump/jni/libpcap/CREDITS @@ -0,0 +1,180 @@ +This file lists people who have contributed to libpcap: + +The current maintainers: + Bill Fenner + Denis Ovsienko + Fulvio Risso + Guy Harris + Hannes Gredler + Michael Richardson + Francois-Xavier Le Bail + +Additional people who have contributed patches: + + Akos Vandra + Alan Bawden + Albert Chin + Alexander 'Leo' Bergolth + Alexey Kuznetsov + Alon Bar-Lev + Andres Perera + Andrew Brown + + Ani Sinha + Antti Kantee + Arien Vijn + Arkadiusz Miskiewicz + Armando L. Caro Jr. + Assar Westerlund + Bill Parker + Brent Cook + Brian Ginsbach + Charles M. Hannum + Chris G. Demetriou + Chris Lightfoot + Chris Maynard + Chris Pepper + Christian Bell + Christian Peron + Christian Svensson + Daniele Orlandi + Darren Lim + Darren Reed + David Clark + David Kaelbling + David Ward + David Young + Dean Gaudet + dhruv + Don Ebright + Dug Song + Dustin Spicuzza + dzejarczech + Edward Sheldrake + Eric Anderson + Erik de Castro Lopo + Felix Obenhuber + Florent Drouin + Franz Schaefer + frederich + Fulko Hew + Fumiyuki Shimizu + Gabor Tatarka + Garrett Cooper + George Neville-Neil + Gianluca Varenni + Gilbert Hoyek + Gisle Vanem + Graeme Hewson + Gregor Maier + Greg Stark + Greg Troxel + Guillaume Pelat + Gustavo Zacarias + Hagen Paul Pfeifer + Henri Doreau + Hyung Sik Yoon + Igor Khristophorov + Jakub Zawadzki + Jan-Philip Velders + Jason R. Thorpe + Javier Achirica + Jean-Louis Charton + Jean Tourrilhes + Jefferson Ogata + Jesper Dangaard Brouer + Jesper Peterson + Jesse Gross + Jiri Slaby + Joerg Mayer + John Bankier + Jon Lindgren + Jon Smirl + Jorge Boncompte [DTI2] + Juergen Schoenwaelder + Julien Moutinho + Jung-uk Kim + Kazushi Sugyo + Klaus Klein + Koryn Grant + Kris Katterjohn + Krzysztof Halasa + Lorenzo Cavallaro + Loris Degioanni + Love Hörnquist-Ã…strand + Luis MartinGarcia + Maciej W. Rozycki + Mansour Behabadi + Marcus Felipe Pereira + Mark C. Brown + Mark Johnston + Mark Pizzolato + Markus Mayer + Martin Husemann + Márton Németh + Matthew Luckie + Max Laier + Michal Labedzki + Michal Sekletar + Mike Frysinger + Mike Kershaw + Mike Wiacek + Miroslav Lichvar + Monroe Williams + Nicolas Dade + Niko Delarich + N. Leiten + + Octavian Cerna + Olaf Kirch + Ollie Wild + Onno van der Linden + Paolo Abeni + Patrick Marie + Patrick McHardy + Paul Mundt + Pavel Kankovsky + Pawel Pokrywka + Peter Fales + Peter Jeremy + Peter Volkov + Phil Wood + Rafal Maszkowski + + Richard Stearn + Rick Jones + Robert Edmonds + Roberto Mariani + Romain Francoise + Sagun Shakya + Scott Barron + Scott Gifford + Scott Mcmillan + Sebastian Krahmer + Sebastien Roy + Sepherosa Ziehau + Shaun Clowes + Solomon Peachy + Stefan Hudson + Stephen Donnelly + Takashi Yamamoto + Tanaka Shin-ya + Tobias Poschwatta + Tony Li + Torsten Landschoff + Uns Lider + Uwe Girlich + Wesley Shields + Xianjie Zhang + Xin Li + Yen Yen Lim + Yoann Vandoorselaere + Yvan Vanhullebus + +The original LBL crew: + Steve McCanne + Craig Leres + Van Jacobson + +Past maintainers: + Jun-ichiro itojun Hagino Also see: http://www.wide.ad.jp/itojun-award/ diff --git a/tcpdump/jni/libpcap/ChmodBPF/ChmodBPF b/tcpdump/jni/libpcap/ChmodBPF/ChmodBPF new file mode 100755 index 0000000..ee37121 --- /dev/null +++ b/tcpdump/jni/libpcap/ChmodBPF/ChmodBPF @@ -0,0 +1,33 @@ +#! /bin/sh + +. /etc/rc.common + +StartService () +{ + # + # Unfortunately, Mac OS X's devfs is based on the old FreeBSD + # one, not the current one, so there's no way to configure it + # to create BPF devices with particular owners or groups. + # This startup item will make it owned by the admin group, + # with permissions rw-rw----, so that anybody in the admin + # group can use programs that capture or send raw packets. + # + # Change this as appropriate for your site, e.g. to make + # it owned by a particular user without changing the permissions, + # so only that user and the super-user can capture or send raw + # packets, or give it the permissions rw-r-----, so that + # only the super-user can send raw packets but anybody in the + # admin group can capture packets. + # + chgrp admin /dev/bpf* + chmod g+rw /dev/bpf* +} + +StopService () +{ + return 0; +} + +RestartService () { StartService; } + +RunService "$1" diff --git a/tcpdump/jni/libpcap/ChmodBPF/StartupParameters.plist b/tcpdump/jni/libpcap/ChmodBPF/StartupParameters.plist new file mode 100644 index 0000000..cba2166 --- /dev/null +++ b/tcpdump/jni/libpcap/ChmodBPF/StartupParameters.plist @@ -0,0 +1,4 @@ +{ + Description = "Change BPF permissions"; + Provides = ("ChmodBPF"); +} diff --git a/tcpdump/jni/libpcap/CleanSpec.mk b/tcpdump/jni/libpcap/CleanSpec.mk new file mode 100644 index 0000000..b84e1b6 --- /dev/null +++ b/tcpdump/jni/libpcap/CleanSpec.mk @@ -0,0 +1,49 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ diff --git a/tcpdump/jni/libpcap/INSTALL.txt b/tcpdump/jni/libpcap/INSTALL.txt new file mode 100644 index 0000000..18b489a --- /dev/null +++ b/tcpdump/jni/libpcap/INSTALL.txt @@ -0,0 +1,395 @@ +To build libpcap, run "./configure" (a shell script). The configure +script will determine your system attributes and generate an +appropriate Makefile from Makefile.in. Next run "make". If everything +goes well you can su to root and run "make install". However, you need +not install libpcap if you just want to build tcpdump; just make sure +the tcpdump and libpcap directory trees have the same parent +directory. + +If configure says: + + configure: warning: cannot determine packet capture interface + configure: warning: (see INSTALL for more info) + +then your system either does not support packet capture or your system +does support packet capture but libpcap does not support that +particular type. (If you have HP-UX, see below.) If your system uses a +packet capture not supported by libpcap, please send us patches; don't +forget to include an autoconf fragment suitable for use in +configure.in. + +It is possible to override the default packet capture type, although +the circumstance where this works are limited. For example if you have +installed bpf under SunOS 4 and wish to build a snit libpcap: + + ./configure --with-pcap=snit + +Another example is to force a supported packet capture type in the case +where the configure scripts fails to detect it. + +You will need an ANSI C compiler to build libpcap. The configure script +will abort if your compiler is not ANSI compliant. If this happens, use +the generally available GNU C compiler (GCC). + +If you use flex, you must use version 2.4.6 or higher. The configure +script automatically detects the version of flex and will not use it +unless it is new enough. You can use "flex -V" to see what version you +have (unless it's really old). The current version of flex is available +at flex.sourceforge.net and often comes packaged by means of the OS. +As of this writing, the current version is 2.5.37. + +If you use bison, you must use flex (and visa versa). The configure +script automatically falls back to lex and yacc if both flex and bison +are not found. + +Sometimes the stock C compiler does not interact well with flex and +bison. The list of problems includes undefined references for alloca. +You can get around this by installing gcc or manually disabling flex +and bison with: + + ./configure --without-flex --without-bison + +If your system only has AT&T lex, this is okay unless your libpcap +program uses other lex/yacc generated code. (Although it's possible to +map the yy* identifiers with a script, we use flex and bison so we +don't feel this is necessary.) + +Some systems support the Berkeley Packet Filter natively; for example +out of the box OSF and BSD/OS have bpf. If your system does not support +bpf, you will need to pick up: + + ftp://ftp.ee.lbl.gov/bpf-*.tar.Z + +Note well: you MUST have kernel source for your operating system in +order to install bpf. An exception is SunOS 4; the bpf distribution +includes replacement kernel objects for some of the standard SunOS 4 +network device drivers. See the bpf INSTALL document for more +information. + +If you use Solaris, there is a bug with bufmod(7) that is fixed in +Solaris 2.3.2 (aka SunOS 5.3.2). Setting a snapshot length with the +broken bufmod(7) results in data be truncated from the FRONT of the +packet instead of the end. The work around is to not set a snapshot +length but this results in performance problems since the entire packet +is copied to user space. If you must run an older version of Solaris, +there is a patch available from Sun; ask for bugid 1149065. After +installing the patch, use "setenv BUFMOD_FIXED" to enable use of +bufmod(7). However, we recommend you run a more current release of +Solaris. + +If you use the SPARCompiler, you must be careful to not use the +/usr/ucb/cc interface. If you do, you will get bogus warnings and +perhaps errors. Either make sure your path has /opt/SUNWspro/bin +before /usr/ucb or else: + + setenv CC /opt/SUNWspro/bin/cc + +before running configure. (You might have to do a "make distclean" +if you already ran configure once). + +Also note that "make depend" won't work; while all of the known +universe uses -M, the SPARCompiler uses -xM to generate makefile +dependencies. + +If you are trying to do packet capture with a FORE ATM card, you may or +may not be able to. They usually only release their driver in object +code so unless their driver supports packet capture, there's not much +libpcap can do. + +If you get an error like: + + tcpdump: recv_ack: bind error 0x??? + +when using DLPI, look for the DL_ERROR_ACK error return values, usually +in /usr/include/sys/dlpi.h, and find the corresponding value. + +Under {DEC OSF/1, Digital UNIX, Tru64 UNIX}, packet capture must be +enabled before it can be used. For instructions on how to enable packet +filter support, see: + + ftp://ftp.digital.com/pub/Digital/dec-faq/Digital-UNIX + +Look for the "How do I configure the Berkeley Packet Filter and capture +tcpdump traces?" item. + +Once you enable packet filter support, your OSF system will support bpf +natively. + +Under Ultrix, packet capture must be enabled before it can be used. For +instructions on how to enable packet filter support, see: + + ftp://ftp.digital.com/pub/Digital/dec-faq/ultrix + +If you use HP-UX, you must have at least version 9 and either the +version of cc that supports ANSI C (cc -Aa) or else use the GNU C +compiler. You must also buy the optional streams package. If you don't +have: + + /usr/include/sys/dlpi.h + /usr/include/sys/dlpi_ext.h + +then you don't have the streams package. In addition, we believe you +need to install the "9.X LAN and DLPI drivers cumulative" patch +(PHNE_6855) to make the version 9 DLPI work with libpcap. + +The DLPI streams package is standard starting with HP-UX 10. + +The HP implementation of DLPI is a little bit eccentric. Unlike +Solaris, you must attach /dev/dlpi instead of the specific /dev/* +network pseudo device entry in order to capture packets. The PPA is +based on the ifnet "index" number. Under HP-UX 9, it is necessary to +read /dev/kmem and the kernel symbol file (/hp-ux). Under HP-UX 10, +DLPI can provide information for determining the PPA. It does not seem +to be possible to trace the loopback interface. Unlike other DLPI +implementations, PHYS implies MULTI and SAP and you get an error if you +try to enable more than one promiscuous mode at a time. + +It is impossible to capture outbound packets on HP-UX 9. To do so on +HP-UX 10, you will, apparently, need a late "LAN products cumulative +patch" (at one point, it was claimed that this would be PHNE_18173 for +s700/10.20; at another point, it was claimed that the required patches +were PHNE_20892, PHNE_20725 and PHCO_10947, or newer patches), and to do +so on HP-UX 11 you will, apparently, need the latest lancommon/DLPI +patches and the latest driver patch for the interface(s) in use on HP-UX +11 (at one point, it was claimed that patches PHNE_19766, PHNE_19826, +PHNE_20008, and PHNE_20735 did the trick). + +Furthermore, on HP-UX 10, you will need to turn on a kernel switch by +doing + + echo 'lanc_outbound_promisc_flag/W 1' | adb -w /stand/vmunix /dev/mem + +You would have to arrange that this happen on reboots; the right way to +do that would probably be to put it into an executable script file +"/sbin/init.d/outbound_promisc" and making +"/sbin/rc2.d/S350outbound_promisc" a symbolic link to that script. + +Finally, testing shows that there can't be more than one simultaneous +DLPI user per network interface. + +If you use Linux, this version of libpcap is known to compile and run +under Red Hat 4.0 with the 2.0.25 kernel. It may work with earlier 2.X +versions but is guaranteed not to work with 1.X kernels. Running more +than one libpcap program at a time, on a system with a 2.0.X kernel, can +cause problems since promiscuous mode is implemented by twiddling the +interface flags from the libpcap application; the packet capture +mechanism in the 2.2 and later kernels doesn't have this problem. Also, +packet timestamps aren't very good. This appears to be due to haphazard +handling of the timestamp in the kernel. + +Note well: there is rumoured to be a version of tcpdump floating around +called 3.0.3 that includes libpcap and is supposed to support Linux. +You should be advised that neither the Network Research Group at LBNL +nor the Tcpdump Group ever generated a release with this version number. +The LBNL Network Research Group notes with interest that a standard +cracker trick to get people to install trojans is to distribute bogus +packages that have a version number higher than the current release. +They also noted with annoyance that 90% of the Linux related bug reports +they got are due to changes made to unofficial versions of their page. +If you are having trouble but aren't using a version that came from +tcpdump.org, please try that before submitting a bug report! + +On Linux, libpcap will not work if the kernel does not have the packet +socket option enabled; see the README.linux file for information about +this. + +If you use AIX, you may not be able to build libpcap from this release. +We do not have an AIX system in house so it's impossible for us to test +AIX patches submitted to us. We are told that you must link against +/lib/pse.exp, that you must use AIX cc or a GNU C compiler newer than +2.7.2, and that you may need to run strload before running a libpcap +application. + +Read the README.aix file for information on installing libpcap and +configuring your system to be able to support libpcap. + +If you use NeXTSTEP, you will not be able to build libpcap from this +release. + +If you use SINIX, you should be able to build libpcap from this +release. It is known to compile and run on SINIX-Y/N 5.42 with the C-DS +V1.0 or V1.1 compiler. But note that in some releases of SINIX, yacc +emits incorrect code; if grammar.y fails to compile, change every +occurence of: + + #ifdef YYDEBUG + +to: + #if YYDEBUG + +Another workaround is to use flex and bison. + +If you use SCO, you might have trouble building libpcap from this +release. We do not have a machine running SCO and have not had reports +of anyone successfully building on it; the current release of libpcap +does not compile on SCO OpenServer 5. Although SCO apparently supports +DLPI to some extent, the DLPI in OpenServer 5 is very non-standard, and +it appears that completely new code would need to be written to capture +network traffic. SCO do not appear to provide tcpdump binaries for +OpenServer 5 or OpenServer 6 as part of SCO Skunkware: + + http://www.sco.com/skunkware/ + +If you use UnixWare, you might be able to build libpcap from this +release, or you might not. We do not have a machine running UnixWare, +so we have not tested it; however, SCO provide packages for libpcap +0.6.2 and tcpdump 3.7.1 in the UnixWare 7/Open UNIX 8 part of SCO +Skunkware, and the source package for libpcap 0.6.2 is not changed from +the libpcap 0.6.2 source release, so this release of libpcap might also +build without changes on UnixWare 7. + +If linking tcpdump fails with "Undefined: _alloca" when using bison on +a Sun4, your version of bison is broken. In any case version 1.16 or +higher is recommended (1.14 is known to cause problems 1.16 is known to +work). Either pick up a current version from: + + ftp://ftp.gnu.org/pub/gnu/bison + +or hack around it by inserting the lines: + + #ifdef __GNUC__ + #define alloca __builtin_alloca + #else + #ifdef sparc + #include + #else + char *alloca (); + #endif + #endif + +right after the (100 line!) GNU license comment in bison.simple, remove +grammar.[co] and fire up make again. + +If you use SunOS 4, your kernel must support streams NIT. If you run a +libpcap program and it dies with: + + /dev/nit: No such device + +You must add streams NIT support to your kernel configuration, run +config and boot the new kernel. + +If you are running a version of SunOS earlier than 4.1, you will need +to replace the Sun supplied /sys/sun{3,4,4c}/OBJ/nit_if.o with the +appropriate version from this distribution's SUNOS4 subdirectory and +build a new kernel: + + nit_if.o.sun3-sunos4 (any flavor of sun3) + nit_if.o.sun4c-sunos4.0.3c (SS1, SS1+, IPC, SLC, etc.) + nit_if.o.sun4-sunos4 (Sun4's not covered by + nit_if.o.sun4c-sunos4.0.3c) + +These nit replacements fix a bug that makes nit essentially unusable in +pre-SunOS 4.1. In addition, our sun4c-sunos4.0.3c nit gives you +timestamps to the resolution of the SS-1 clock (1 us) rather than the +lousy 20ms timestamps Sun gives you (tcpdump will print out the full +timestamp resolution if it finds it's running on a SS-1). + +FILES +----- +CHANGES - description of differences between releases +ChmodBPF/* - Mac OS X startup item to set ownership and permissions + on /dev/bpf* +CREDITS - people that have helped libpcap along +INSTALL.txt - this file +LICENSE - the license under which tcpdump is distributed +Makefile.in - compilation rules (input to the configure script) +README - description of distribution +README.aix - notes on using libpcap on AIX +README.dag - notes on using libpcap to capture on Endace DAG devices +README.hpux - notes on using libpcap on HP-UX +README.linux - notes on using libpcap on Linux +README.macosx - notes on using libpcap on Mac OS X +README.septel - notes on using libpcap to capture on Intel/Septel devices +README.sita - notes on using libpcap to capture on SITA devices +README.tru64 - notes on using libpcap on Digital/Tru64 UNIX +README.Win32 - notes on using libpcap on Win32 systems (with WinPcap) +SUNOS4 - pre-SunOS 4.1 replacement kernel nit modules +VERSION - version of this release +acconfig.h - support for post-2.13 autoconf +aclocal.m4 - autoconf macros +arcnet.h - ARCNET definitions +atmuni31.h - ATM Q.2931 definitions +bpf/net - copy of bpf_filter.c +bpf_dump.c - BPF program printing routines +bpf_filter.c - symlink to bpf/net/bpf_filter.c +bpf_image.c - BPF disassembly routine +config.guess - autoconf support +config.h.in - autoconf input +config.sub - autoconf support +configure - configure script (run this first) +configure.in - configure script source +dlpisubs.c - DLPI-related functions for pcap-dlpi.c and pcap-libdlpi.c +dlpisubs.h - DLPI-related function declarations +etherent.c - /etc/ethers support routines +ethertype.h - Ethernet protocol types and names definitions +fad-getad.c - pcap_findalldevs() for systems with getifaddrs() +fad-gifc.c - pcap_findalldevs() for systems with only SIOCGIFLIST +fad-glifc.c - pcap_findalldevs() for systems with SIOCGLIFCONF +fad-null.c - pcap_findalldevs() for systems without capture support +fad-sita.c - pcap_findalldevs() for systems with SITA support +fad-win32.c - pcap_findalldevs() for WinPcap +filtertest.c - test program for BPF compiler +findalldevstest.c - test program for pcap_findalldevs() +gencode.c - BPF code generation routines +gencode.h - BPF code generation definitions +grammar.y - filter string grammar +ieee80211.h - 802.11 definitions +inet.c - network routines +install-sh - BSD style install script +lbl/os-*.h - OS-dependent defines and prototypes +llc.h - 802.2 LLC SAP definitions +missing/* - replacements for missing library functions +mkdep - construct Makefile dependency list +msdos/* - drivers for MS-DOS capture support +nametoaddr.c - hostname to address routines +nlpid.h - OSI network layer protocol identifier definitions +net - symlink to bpf/net +optimize.c - BPF optimization routines +pcap/bluetooth.h - public definition of DLT_BLUETOOTH_HCI_H4_WITH_PHDR header +pcap/bpf.h - BPF definitions +pcap/namedb.h - public libpcap name database definitions +pcap/pcap.h - public libpcap definitions +pcap/sll.h - public definition of DLT_LINUX_SLL header +pcap/usb.h - public definition of DLT_USB header +pcap-bpf.c - BSD Packet Filter support +pcap-bpf.h - header for backwards compatibility +pcap-bt-linux.c - Bluetooth capture support for Linux +pcap-bt-linux.h - Bluetooth capture support for Linux +pcap-dag.c - Endace DAG device capture support +pcap-dag.h - Endace DAG device capture support +pcap-dlpi.c - Data Link Provider Interface support +pcap-dos.c - MS-DOS capture support +pcap-dos.h - headers for MS-DOS capture support +pcap-enet.c - enet support +pcap-int.h - internal libpcap definitions +pcap-libdlpi.c - Data Link Provider Interface support for systems with libdlpi +pcap-linux.c - Linux packet socket support +pcap-namedb.h - header for backwards compatibility +pcap-nit.c - SunOS Network Interface Tap support +pcap-nit.h - SunOS Network Interface Tap definitions +pcap-null.c - dummy monitor support (allows offline use of libpcap) +pcap-pf.c - Ultrix and Digital/Tru64 UNIX Packet Filter support +pcap-pf.h - Ultrix and Digital/Tru64 UNIX Packet Filter definitions +pcap-septel.c - Intel/Septel device capture support +pcap-septel.h - Intel/Septel device capture support +pcap-sita.c - SITA device capture support +pcap-sita.h - SITA device capture support +pcap-sita.html - SITA device capture documentation +pcap-stdinc.h - includes and #defines for compiling on Win32 systems +pcap-snit.c - SunOS 4.x STREAMS-based Network Interface Tap support +pcap-snoop.c - IRIX Snoop network monitoring support +pcap-usb-linux.c - USB capture support for Linux +pcap-usb-linux.h - USB capture support for Linux +pcap-win32.c - WinPcap capture support +pcap.3pcap - manual entry for the library +pcap.c - pcap utility routines +pcap.h - header for backwards compatibility +pcap_*.3pcap - manual entries for library functions +pcap-filter.4 - manual entry for filter syntax +pcap-linktype.4 - manual entry for link-layer header types +ppp.h - Point to Point Protocol definitions +runlex.sh - wrapper for Lex/Flex +savefile.c - offline support +scanner.l - filter string scanner +sunatmpos.h - definitions for SunATM capturing +Win32 - headers and routines for building on Win32 systems diff --git a/tcpdump/jni/libpcap/LICENSE b/tcpdump/jni/libpcap/LICENSE new file mode 100644 index 0000000..a10474d --- /dev/null +++ b/tcpdump/jni/libpcap/LICENSE @@ -0,0 +1,19 @@ +License: BSD + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. diff --git a/tcpdump/jni/libpcap/Makefile-devel-adds b/tcpdump/jni/libpcap/Makefile-devel-adds new file mode 100644 index 0000000..7bf6420 --- /dev/null +++ b/tcpdump/jni/libpcap/Makefile-devel-adds @@ -0,0 +1,22 @@ +# +# Auto-regenerate configure script or Makefile when things change. +# From autoconf.info . Works best with GNU Make. +# +${srcdir}/configure: configure.in aclocal.m4 + cd ${srcdir} && autoconf + +# autoheader might not change config.h.in, so touch a stamp file. +${srcdir}/config.h.in: ${srcdir}/stamp-h.in +${srcdir}/stamp-h.in: configure.in aclocal.m4 + cd ${srcdir} && autoheader + echo timestamp > ${srcdir}/stamp-h.in + +config.h: stamp-h +stamp-h: ${srcdir}/config.h.in config.status + ./config.status + +Makefile: Makefile.in config.status + ./config.status + +config.status: ${srcdir}/configure + ./config.status --recheck diff --git a/tcpdump/jni/libpcap/Makefile.in b/tcpdump/jni/libpcap/Makefile.in new file mode 100644 index 0000000..4c35bde --- /dev/null +++ b/tcpdump/jni/libpcap/Makefile.in @@ -0,0 +1,748 @@ +# Copyright (c) 1993, 1994, 1995, 1996 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that: (1) source code distributions +# retain the above copyright notice and this paragraph in its entirety, (2) +# distributions including binary code include the above copyright notice and +# this paragraph in its entirety in the documentation or other materials +# provided with the distribution, and (3) all advertising materials mentioning +# features or use of this software display the following acknowledgement: +# ``This product includes software developed by the University of California, +# Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +# the University nor the names of its contributors may be used to endorse +# or promote products derived from this software without specific prior +# written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +# +# Various configurable paths (remember to edit Makefile.in, not Makefile) +# + +# Top level hierarchy +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +# Pathname of directory to install the configure program +bindir = @bindir@ +# Pathname of directory to install the include files +includedir = @includedir@ +# Pathname of directory to install the library +libdir = @libdir@ +# Pathname of directory to install the man pages +mandir = @mandir@ + +# VPATH +srcdir = @srcdir@ +VPATH = @srcdir@ + +# +# You shouldn't need to edit anything below. +# + +LD = /usr/bin/ld +CC = @CC@ +AR = @AR@ +LN_S = @LN_S@ +MKDEP = @MKDEP@ +CCOPT = @V_CCOPT@ +INCLS = -I. @V_INCLS@ +DEFS = @DEFS@ @V_DEFS@ +ADDLOBJS = @ADDLOBJS@ +ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ +LIBS = @LIBS@ +CROSSFLAGS= +CFLAGS = @CFLAGS@ ${CROSSFLAGS} +LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} +DYEXT = @DYEXT@ +V_RPATH_OPT = @V_RPATH_OPT@ +DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ +PROG=libpcap + +# Standard CFLAGS +FULL_CFLAGS = $(CCOPT) $(INCLS) $(DEFS) $(CFLAGS) + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +RANLIB = @RANLIB@ + +# +# Flex and bison allow you to specify the prefixes of the global symbols +# used by the generated parser. This allows programs to use lex/yacc +# and link against libpcap. If you don't have flex or bison, get them. +# +LEX = @V_LEX@ +YACC = @V_YACC@ + +# Explicitly define compilation rule since SunOS 4's make doesn't like gcc. +# Also, gcc does not remove the .o before forking 'as', which can be a +# problem if you don't own the file but can write to the directory. +.c.o: + @rm -f $@ + $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c + +PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @BT_MONITOR_SRC@ @CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@ +FSRC = fad-@V_FINDALLDEVS@.c +SSRC = @SSRC@ +CSRC = pcap.c inet.c gencode.c optimize.c nametoaddr.c etherent.c \ + savefile.c sf-pcap.c sf-pcap-ng.c pcap-common.c \ + bpf_image.c bpf_dump.c +GENSRC = scanner.c grammar.c bpf_filter.c version.c +LIBOBJS = @LIBOBJS@ + +SRC = $(PSRC) $(FSRC) $(CSRC) $(SSRC) $(GENSRC) + +# We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot +# hack the extra indirection +OBJ = $(PSRC:.c=.o) $(FSRC:.c=.o) $(CSRC:.c=.o) $(SSRC:.c=.o) $(GENSRC:.c=.o) $(LIBOBJS) +PUBHDR = \ + pcap.h \ + pcap-bpf.h \ + pcap-namedb.h \ + pcap/bpf.h \ + pcap/bluetooth.h \ + pcap/ipnet.h \ + pcap/namedb.h \ + pcap/nflog.h \ + pcap/pcap.h \ + pcap/sll.h \ + pcap/vlan.h \ + pcap/usb.h + +HDR = $(PUBHDR) \ + arcnet.h \ + atmuni31.h \ + ethertype.h \ + gencode.h \ + ieee80211.h \ + llc.h \ + nlpid.h \ + pcap-common.h \ + pcap-int.h \ + pcap-stdinc.h \ + ppp.h \ + sf-pcap.h \ + sf-pcap-ng.h \ + sunatmpos.h + +TESTS = \ + capturetest \ + filtertest \ + findalldevstest \ + opentest \ + selpolltest \ + valgrindtest + +TESTS_SRC = \ + tests/capturetest.c \ + tests/filtertest.c \ + tests/findalldevstest.c \ + tests/opentest.c \ + tests/reactivatetest.c \ + tests/selpolltest.c \ + tests/valgrindtest.c + +GENHDR = \ + scanner.h tokdefs.h version.h + +TAGFILES = \ + $(SRC) $(HDR) + +CLEANFILES = $(OBJ) libpcap.* $(TESTS) \ + $(PROG)-`cat $(srcdir)/VERSION`.tar.gz $(GENSRC) $(GENHDR) \ + lex.yy.c pcap-config + +MAN1 = pcap-config.1 + +MAN3PCAP_EXPAND = \ + pcap.3pcap.in \ + pcap_compile.3pcap.in \ + pcap_datalink.3pcap.in \ + pcap_dump_open.3pcap.in \ + pcap_get_tstamp_precision.3pcap.in \ + pcap_list_datalinks.3pcap.in \ + pcap_list_tstamp_types.3pcap.in \ + pcap_open_dead.3pcap.in \ + pcap_open_offline.3pcap.in \ + pcap_set_tstamp_precision.3pcap.in \ + pcap_set_tstamp_type.3pcap.in + +MAN3PCAP_NOEXPAND = \ + pcap_activate.3pcap \ + pcap_breakloop.3pcap \ + pcap_can_set_rfmon.3pcap \ + pcap_close.3pcap \ + pcap_create.3pcap \ + pcap_datalink_name_to_val.3pcap \ + pcap_datalink_val_to_name.3pcap \ + pcap_dump.3pcap \ + pcap_dump_close.3pcap \ + pcap_dump_file.3pcap \ + pcap_dump_flush.3pcap \ + pcap_dump_ftell.3pcap \ + pcap_file.3pcap \ + pcap_fileno.3pcap \ + pcap_findalldevs.3pcap \ + pcap_freecode.3pcap \ + pcap_get_selectable_fd.3pcap \ + pcap_geterr.3pcap \ + pcap_inject.3pcap \ + pcap_is_swapped.3pcap \ + pcap_lib_version.3pcap \ + pcap_lookupdev.3pcap \ + pcap_lookupnet.3pcap \ + pcap_loop.3pcap \ + pcap_major_version.3pcap \ + pcap_next_ex.3pcap \ + pcap_offline_filter.3pcap \ + pcap_open_live.3pcap \ + pcap_set_buffer_size.3pcap \ + pcap_set_datalink.3pcap \ + pcap_set_immediate_mode.3pcap \ + pcap_set_promisc.3pcap \ + pcap_set_rfmon.3pcap \ + pcap_set_snaplen.3pcap \ + pcap_set_timeout.3pcap \ + pcap_setdirection.3pcap \ + pcap_setfilter.3pcap \ + pcap_setnonblock.3pcap \ + pcap_snapshot.3pcap \ + pcap_stats.3pcap \ + pcap_statustostr.3pcap \ + pcap_strerror.3pcap \ + pcap_tstamp_type_name_to_val.3pcap \ + pcap_tstamp_type_val_to_name.3pcap + +MAN3PCAP = $(MAN3PCAP_NOEXPAND) $(MAN3PCAP_EXPAND:.in=) + +MANFILE = \ + pcap-savefile.manfile.in + +MANMISC = \ + pcap-filter.manmisc.in \ + pcap-linktype.manmisc.in \ + pcap-tstamp.manmisc.in + +EXTRA_DIST = \ + $(TESTS_SRC) \ + CHANGES \ + ChmodBPF/ChmodBPF \ + ChmodBPF/StartupParameters.plist \ + CREDITS \ + INSTALL.txt \ + LICENSE \ + Makefile.in \ + Makefile-devel-adds \ + README \ + README.aix \ + README.dag \ + README.hpux \ + README.linux \ + README.macosx \ + README.septel \ + README.sita \ + README.tru64 \ + README.Win32 \ + SUNOS4/nit_if.o.sparc \ + SUNOS4/nit_if.o.sun3 \ + SUNOS4/nit_if.o.sun4c.4.0.3c \ + TODO \ + VERSION \ + aclocal.m4 \ + bpf/net/bpf_filter.c \ + chmod_bpf \ + config.guess \ + config.h.in \ + config.sub \ + configure \ + configure.in \ + dlpisubs.c \ + dlpisubs.h \ + fad-getad.c \ + fad-gifc.c \ + fad-glifc.c \ + fad-null.c \ + fad-sita.c \ + fad-win32.c \ + grammar.y \ + install-sh \ + lbl/os-aix4.h \ + lbl/os-hpux11.h \ + lbl/os-osf4.h \ + lbl/os-osf5.h \ + lbl/os-solaris2.h \ + lbl/os-sunos4.h \ + lbl/os-ultrix4.h \ + missing/snprintf.c \ + mkdep \ + msdos/bin2c.c \ + msdos/common.dj \ + msdos/makefile \ + msdos/makefile.dj \ + msdos/makefile.wc \ + msdos/ndis2.c \ + msdos/ndis2.h \ + msdos/ndis_0.asm \ + msdos/pkt_rx0.asm \ + msdos/pkt_rx1.s \ + msdos/pktdrvr.c \ + msdos/pktdrvr.h \ + msdos/readme.dos \ + org.tcpdump.chmod_bpf.plist \ + pcap-bpf.c \ + pcap-bt-linux.c \ + pcap-bt-linux.h \ + pcap-bt-monitor-linux.c \ + pcap-bt-monitor-linux.h \ + pcap-can-linux.c \ + pcap-can-linux.h \ + pcap-canusb-linux.c \ + pcap-canusb-linux.h \ + pcap-config.in \ + pcap-dag.c \ + pcap-dag.h \ + pcap-dbus.c \ + pcap-dbus.h \ + pcap-dlpi.c \ + pcap-dos.c \ + pcap-dos.h \ + pcap-enet.c \ + pcap-int.h \ + pcap-libdlpi.c \ + pcap-linux.c \ + pcap-namedb.h \ + pcap-netfilter-linux.c \ + pcap-netfilter-linux.h \ + pcap-nit.c \ + pcap-null.c \ + pcap-pf.c \ + pcap-septel.c \ + pcap-septel.h \ + pcap-sita.h \ + pcap-sita.c \ + pcap-sita.html \ + pcap-snf.c \ + pcap-snf.h \ + pcap-snit.c \ + pcap-snoop.c \ + pcap-usb-linux.c \ + pcap-usb-linux.h \ + pcap-win32.c \ + runlex.sh \ + scanner.c.top \ + scanner.l \ + Win32/Include/Gnuc.h \ + Win32/Include/addrinfo.h \ + Win32/Include/bittypes.h \ + Win32/Include/cdecl_ext.h \ + Win32/Include/inetprivate.h \ + Win32/Include/ip6_misc.h \ + Win32/Include/sockstorage.h \ + Win32/Include/arpa/nameser.h \ + Win32/Include/net/if.h \ + Win32/Include/net/netdb.h \ + Win32/Include/net/paths.h \ + Win32/Prj/libpcap.dsp \ + Win32/Prj/libpcap.dsw \ + Win32/Src/ffs.c \ + Win32/Src/gai_strerror.c \ + Win32/Src/getaddrinfo.c \ + Win32/Src/getnetbynm.c \ + Win32/Src/getnetent.c \ + Win32/Src/getopt.c \ + Win32/Src/getservent.c \ + Win32/Src/inet_aton.c \ + Win32/Src/inet_net.c \ + Win32/Src/inet_pton.c + +all: libpcap.a shared pcap-config + +libpcap.a: $(OBJ) + @rm -f $@ + $(AR) rc $@ $(OBJ) $(ADDLARCHIVEOBJS) + $(RANLIB) $@ + +shared: libpcap.$(DYEXT) + +libpcap.so: $(OBJ) + @rm -f $@ + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + @V_SHLIB_CMD@ @V_SHLIB_OPT@ @V_SONAME_OPT@$@.$$MAJOR_VER $(LDFLAGS) \ + -o $@.$$VER $(OBJ) $(ADDLOBJS) $(LIBS) + +# +# The following rule succeeds, but the result is untested. +# +# In Mac OS X, the libpcap dylib has the name "libpcap.A.dylib", with +# its full path as the install_name, and with the compatibility and +# current version both set to 1. The compatibility version is set to +# 1 so that programs built with a newer version of the library will run +# against older versions; multi-platform software probably will fail if +# it uses APIs added in the newer version, but Mac OS X-specific software +# will use weak linking and check at run time whether those APIs are +# available. +# +# We also use "A" as the major version, and 1 as the compatibility version, +# but set the current version to the value in VERSION, with any non-numeric +# stuff stripped off (the compatibility and current version must be of the +# form X[.Y[.Z]], with Y and Z possibly absent, and with all components +# numeric). +# +libpcap.dylib: $(OBJ) + rm -f libpcap*.dylib + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=A; \ + COMPAT_VER=1; \ + CURRENT_VER=`sed 's/[^0-9.].*$$//' $(srcdir)/VERSION`; \ + $(CC) -dynamiclib -undefined error $(LDFLAGS) \ + -o libpcap.$$VER.dylib $(OBJ) $(ADDLOBJS) $(LIBS) \ + -install_name $(libdir)/libpcap.$$MAJOR_VER.dylib \ + -compatibility_version $$COMPAT_VER \ + -current_version $$CURRENT_VER + +# +# The HP-UX linker manual says that the convention for a versioned library +# is libXXX.{number}, not libXXX.sl.{number}. That appears to be the case +# on at least one HP-UX 11.00 system; libXXX.sl is a symlink to +# libXXX.{number}. +# +# The manual also says "library-level versioning" (think "sonames") was +# added in HP-UX 10.0. +# +# XXX - this assumes we're using the HP linker, rather than the GNU +# linker, even with GCC. +# +libpcap.sl: $(OBJ) + @MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + rm -f libpcap.$$MAJOR_VER + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + ld -b $(LDFLAGS) -o libpcap.$$MAJOR_VER +h libpcap.$$MAJOR_VER \ + $(OBJ) $(ADDLOBJS) $(LIBS) + +# +# AIX is different from everybody else. A shared library is an archive +# library with one or more shared-object components. We still build a +# normal static archive library on AIX, for the benefit of the traditional +# scheme of building libpcap and tcpdump in subdirectories of the +# same directory, with tcpdump statically linked with the libpcap +# in question, but we also build a shared library as "libpcap.shareda" +# and install *it*, rather than the static library, as "libpcap.a". +# +libpcap.shareda: $(OBJ) + @rm -f $@ shr.o + $(CC) @V_SHLIB_OPT@ -o shr.o $(OBJ) $(ADDLOBJS) $(LDFLAGS) $(LIBS) + $(AR) rc $@ shr.o + +# +# For platforms that don't support shared libraries (or on which we +# don't support shared libraries). +# +libpcap.none: + +scanner.c: $(srcdir)/scanner.l + @rm -f $@ $@.bottom + $(srcdir)/runlex.sh $(LEX) -o$@ $< + mv $@ $@.bottom + cat $(srcdir)/$@.top $@.bottom > $@ + @rm $@.bottom + +scanner.o: scanner.c tokdefs.h + $(CC) $(FULL_CFLAGS) -c scanner.c + +pcap.o: version.h + +tokdefs.h: grammar.c +grammar.c: $(srcdir)/grammar.y + @rm -f grammar.c tokdefs.h + $(YACC) -d $< + mv y.tab.c grammar.c + mv y.tab.h tokdefs.h + +grammar.o: grammar.c + @rm -f $@ + $(CC) $(FULL_CFLAGS) -Dyylval=pcap_lval -c grammar.c + +version.o: version.c + $(CC) $(FULL_CFLAGS) -c version.c + +snprintf.o: $(srcdir)/missing/snprintf.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/snprintf.c + +version.c: $(srcdir)/VERSION + @rm -f $@ + if grep GIT ${srcdir}/VERSION >/dev/null; then \ + read ver <${srcdir}/VERSION; \ + echo $$ver | tr -d '\012'; \ + date +_%Y_%m_%d; \ + else \ + cat ${srcdir}/VERSION; \ + fi | sed -e 's/.*/char pcap_version[] = "&";/' > $@ + +# +# NOTE: this really is supposed to be static; importing a string +# from a shared library does not work very well on many +# versions of UNIX (Solaris, Linux, and the BSDs, for example), +# so we make the version string static and return it from +# a function, which does work. +# +version.h: $(srcdir)/VERSION + @rm -f $@ + if grep GIT ${srcdir}/VERSION >/dev/null; then \ + read ver <${srcdir}/VERSION; \ + echo $$ver | tr -d '\012'; \ + date +_%Y_%m_%d; \ + else \ + cat ${srcdir}/VERSION; \ + fi | sed -e 's/.*/static const char pcap_version_string[] = "libpcap version &";/' > $@ + +bpf_filter.c: $(srcdir)/bpf/net/bpf_filter.c + rm -f bpf_filter.c + ln -s $(srcdir)/bpf/net/bpf_filter.c bpf_filter.c + +bpf_filter.o: bpf_filter.c + $(CC) $(FULL_CFLAGS) -c bpf_filter.c + +# +# Generate the pcap-config script. +# +# Some Makes, e.g. AIX Make and Solaris Make, can't handle "--file=$@.tmp:$<"; +# for example, the Solaris 9 make man page says +# +# Because make assigns $< and $* as it would for implicit rules +# (according to the suffixes list and the directory contents), +# they may be unreliable when used within explicit target entries. +# +# and this is an explicit target entry. +# +# Therefore, instead of using $<, we explicitly put in $(srcdir)/pcap-config.in. +# +pcap-config: $(srcdir)/pcap-config.in ./config.status + @rm -f $@ $@.tmp + ./config.status --file=$@.tmp:$(srcdir)/pcap-config.in + mv $@.tmp $@ + chmod a+x $@ + +# +# Test programs - not built by default, and not installed. +# +tests: $(TESTS) + +capturetest: tests/capturetest.c libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o capturetest $(srcdir)/tests/capturetest.c libpcap.a $(LIBS) + +filtertest: tests/filtertest.c libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o filtertest $(srcdir)/tests/filtertest.c libpcap.a $(LIBS) + +findalldevstest: tests/findalldevstest.c libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest $(srcdir)/tests/findalldevstest.c libpcap.a $(LIBS) + +opentest: tests/opentest.c libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o opentest $(srcdir)/tests/opentest.c libpcap.a $(LIBS) + +selpolltest: tests/selpolltest.c libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o selpolltest $(srcdir)/tests/selpolltest.c libpcap.a $(LIBS) + +valgrindtest: tests/valgrindtest.c libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o valgrindtest $(srcdir)/tests/valgrindtest.c libpcap.a $(LIBS) + +install: install-shared install-archive pcap-config + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + [ -d $(DESTDIR)$(includedir) ] || \ + (mkdir -p $(DESTDIR)$(includedir); chmod 755 $(DESTDIR)$(includedir)) + [ -d $(DESTDIR)$(includedir)/pcap ] || \ + (mkdir -p $(DESTDIR)$(includedir)/pcap; chmod 755 $(DESTDIR)$(includedir)/pcap) + [ -d $(DESTDIR)$(mandir)/man1 ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man1; chmod 755 $(DESTDIR)$(mandir)/man1) + [ -d $(DESTDIR)$(mandir)/man3 ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man3; chmod 755 $(DESTDIR)$(mandir)/man3) + [ -d $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@ ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@) + [ -d $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@ ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@) + for i in $(PUBHDR); do \ + $(INSTALL_DATA) $(srcdir)/$$i \ + $(DESTDIR)$(includedir)/$$i; done + [ -d $(DESTDIR)$(bindir) ] || \ + (mkdir -p $(DESTDIR)$(bindir); chmod 755 $(DESTDIR)$(bindir)) + $(INSTALL_PROGRAM) pcap-config $(DESTDIR)$(bindir)/pcap-config + for i in $(MAN1); do \ + $(INSTALL_DATA) $(srcdir)/$$i \ + $(DESTDIR)$(mandir)/man1/$$i; done + for i in $(MAN3PCAP_NOEXPAND); do \ + $(INSTALL_DATA) $(srcdir)/$$i \ + $(DESTDIR)$(mandir)/man3/$$i; done + for i in $(MAN3PCAP_EXPAND:.in=); do \ + $(INSTALL_DATA) $$i \ + $(DESTDIR)$(mandir)/man3/$$i; done + (cd $(DESTDIR)$(mandir)/man3 && \ + rm -f pcap_datalink_val_to_description.3pcap && \ + $(LN_S) pcap_datalink_val_to_name.3pcap \ + pcap_datalink_val_to_description.3pcap && \ + rm -f pcap_dump_fopen.3pcap && \ + $(LN_S) pcap_dump_open.3pcap pcap_dump_fopen.3pcap && \ + rm -f pcap_freealldevs.3pcap && \ + $(LN_S) pcap_findalldevs.3pcap pcap_freealldevs.3pcap && \ + rm -f pcap_perror.3pcap && \ + $(LN_S) pcap_geterr.3pcap pcap_perror.3pcap && \ + rm -f pcap_sendpacket.3pcap && \ + $(LN_S) pcap_inject.3pcap pcap_sendpacket.3pcap && \ + rm -f pcap_free_datalinks.3pcap && \ + $(LN_S) pcap_list_datalinks.3pcap pcap_free_datalinks.3pcap && \ + rm -f pcap_free_tstamp_types.3pcap && \ + $(LN_S) pcap_list_tstamp_types.3pcap pcap_free_tstamp_types.3pcap && \ + rm -f pcap_dispatch.3pcap && \ + $(LN_S) pcap_loop.3pcap pcap_dispatch.3pcap && \ + rm -f pcap_minor_version.3pcap && \ + $(LN_S) pcap_major_version.3pcap pcap_minor_version.3pcap && \ + rm -f pcap_next.3pcap && \ + $(LN_S) pcap_next_ex.3pcap pcap_next.3pcap && \ + rm -f pcap_open_dead_with_tstamp_precision.3pcap && \ + $(LN_S) pcap_open_dead.3pcap \ + pcap_open_dead_with_tstamp_precision.3pcap && \ + rm -f pcap_open_offline_with_tstamp_precision.3pcap && \ + $(LN_S) pcap_open_offline.3pcap pcap_open_offline_with_tstamp_precision.3pcap && \ + rm -f pcap_fopen_offline.3pcap && \ + $(LN_S) pcap_open_offline.3pcap pcap_fopen_offline.3pcap && \ + rm -f pcap_fopen_offline_with_tstamp_precision.3pcap && \ + $(LN_S) pcap_open_offline.3pcap pcap_fopen_offline_with_tstamp_precision.3pcap && \ + rm -f pcap_tstamp_type_val_to_description.3pcap && \ + $(LN_S) pcap_tstamp_type_val_to_name.3pcap pcap_tstamp_type_val_to_description.3pcap && \ + rm -f pcap_getnonblock.3pcap && \ + $(LN_S) pcap_setnonblock.3pcap pcap_getnonblock.3pcap) + for i in $(MANFILE); do \ + $(INSTALL_DATA) `echo $$i | sed 's/.manfile.in/.manfile/'` \ + $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done + for i in $(MANMISC); do \ + $(INSTALL_DATA) `echo $$i | sed 's/.manmisc.in/.manmisc/'` \ + $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@/`echo $$i | sed 's/.manmisc.in/.@MAN_MISC_INFO@/'`; done + +install-shared: install-shared-$(DYEXT) +install-shared-so: libpcap.so + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + $(INSTALL_PROGRAM) libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$VER; \ + ln -sf libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$MAJOR_VER; \ + ln -sf libpcap.so.$$MAJOR_VER $(DESTDIR)$(libdir)/libpcap.so +install-shared-dylib: libpcap.dylib + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=A; \ + $(INSTALL_PROGRAM) libpcap.$$VER.dylib $(DESTDIR)$(libdir)/libpcap.$$VER.dylib; \ + ln -sf libpcap.$$VER.dylib $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER.dylib; \ + ln -sf libpcap.$$MAJOR_VER.dylib $(DESTDIR)$(libdir)/libpcap.dylib +install-shared-sl: libpcap.sl + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + $(INSTALL_PROGRAM) libpcap.$$MAJOR_VER $(DESTDIR)$(libdir) + ln -sf libpcap.$$MAJOR_VER $(DESTDIR)$(libdir)/libpcap.sl +install-shared-shareda: libpcap.shareda + # + # AIX shared libraries are weird. They're archive libraries + # with one or more shared object components. + # + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + $(INSTALL_PROGRAM) libpcap.shareda $(DESTDIR)$(libdir)/libpcap.a +install-shared-none: + +install-archive: install-archive-$(DYEXT) +install-archive-so install-archive-dylib install-archive-sl install-archive-none: libpcap.a + # + # Most platforms have separate suffixes for shared and + # archive libraries, so we install both. + # + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + $(INSTALL_DATA) libpcap.a $(DESTDIR)$(libdir)/libpcap.a + $(RANLIB) $(DESTDIR)$(libdir)/libpcap.a +install-archive-shareda: + # + # AIX, however, doesn't, so we don't install the archive + # library on AIX. + # + +uninstall: uninstall-shared + rm -f $(DESTDIR)$(libdir)/libpcap.a + for i in $(PUBHDR); do \ + rm -f $(DESTDIR)$(includedir)/$$i; done + -rmdir $(DESTDIR)$(includedir)/pcap + rm -f $(DESTDIR)/$(bindir)/pcap-config + for i in $(MAN1); do \ + rm -f $(DESTDIR)$(mandir)/man1/$$i; done + for i in $(MAN3PCAP); do \ + rm -f $(DESTDIR)$(mandir)/man3/$$i; done + rm -f $(DESTDIR)$(mandir)/man3/pcap_datalink_val_to_description.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_dump_fopen.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_freealldevs.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_perror.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_sendpacket.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_free_datalinks.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_free_tstamp_types.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_dispatch.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_minor_version.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_next.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_open_dead_with_tstamp_precision.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_open_offline_with_tstamp_precision.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_fopen_offline.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_fopen_offline_with_tstamp_precision.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_getnonblock.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_tstamp_type_val_to_description.3pcap + for i in $(MANFILE); do \ + rm -f $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done + for i in $(MANMISC); do \ + rm -f $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@/`echo $$i | sed 's/.manmisc.in/.@MAN_MISC_INFO@/'`; done + +uninstall-shared: uninstall-shared-$(DYEXT) +uninstall-shared-so: + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + rm -f $(DESTDIR)$(libdir)/libpcap.so.$$VER; \ + rm -f $(DESTDIR)$(libdir)/libpcap.so.$$MAJOR_VER; \ + rm -f $(DESTDIR)$(libdir)/libpcap.so +uninstall-shared-dylib: + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=A; \ + rm -f $(DESTDIR)$(libdir)/libpcap.$$VER.dylib; \ + rm -f $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER.dylib; \ + rm -f $(DESTDIR)$(libdir)/libpcap.dylib +uninstall-shared-sl: + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + rm -f $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER; \ + rm -f $(DESTDIR)$(libdir)/libpcap.sl +uninstall-shared-shareda: + rm -f $(DESTDIR)$(libdir)/libpcap.a +uninstall-shared-none: + +clean: + rm -f $(CLEANFILES) + +distclean: clean + rm -f Makefile config.cache config.log config.status \ + config.h gnuc.h net os-proto.h bpf_filter.c pcap-config \ + stamp-h stamp-h.in + rm -f $(MAN3PCAP_EXPAND:.in=) $(MANFILE:.in=) $(MANMISC:.in=) + rm -rf autom4te.cache + +tags: $(TAGFILES) + ctags -wtd $(TAGFILES) + +releasetar: + @cwd=`pwd` ; dir=`basename $$cwd` ; name=$(PROG)-`cat VERSION` ; \ + mkdir $$name; \ + tar cf - $(CSRC) $(HDR) $(MAN1) $(MAN3PCAP_EXPAND) \ + $(MAN3PCAP_NOEXPAND) $(MANFILE) $(MANMISC) $(EXTRA_DIST) | \ + (cd $$name; tar xf -); \ + tar -c -z -f $$name.tar.gz $$name; \ + rm -rf $$name + +depend: $(GENSRC) $(GENHDR) bpf_filter.c + $(MKDEP) -c $(CC) -m $(CFLAGS) $(DEPENDENCY_CFLAG) $(DEFS) $(INCLS) $(SRC) diff --git a/tcpdump/jni/libpcap/README b/tcpdump/jni/libpcap/README new file mode 100644 index 0000000..9f65948 --- /dev/null +++ b/tcpdump/jni/libpcap/README @@ -0,0 +1,106 @@ +LIBPCAP 1.x.y + +www.tcpdump.org + +Please send inquiries/comments/reports to: + tcpdump-workers@lists.tcpdump.org + +Anonymous Git is available via: + git clone git://bpf.tcpdump.org/libpcap + +Please submit patches by forking the branch on GitHub at + + http://github.com/the-tcpdump-group/libpcap/tree/master + +and issuing a pull request. + +formerly from Lawrence Berkeley National Laboratory + Network Research Group + ftp://ftp.ee.lbl.gov/old/libpcap-0.4a7.tar.Z + +This directory contains source code for libpcap, a system-independent +interface for user-level packet capture. libpcap provides a portable +framework for low-level network monitoring. Applications include +network statistics collection, security monitoring, network debugging, +etc. Since almost every system vendor provides a different interface +for packet capture, and since we've developed several tools that +require this functionality, we've created this system-independent API +to ease in porting and to alleviate the need for several +system-dependent packet capture modules in each application. + +For some platforms there are README.{system} files that discuss issues +with the OS's interface for packet capture on those platforms, such as +how to enable support for that interface in the OS, if it's not built in +by default. + +The libpcap interface supports a filtering mechanism based on the +architecture in the BSD packet filter. BPF is described in the 1993 +Winter Usenix paper ``The BSD Packet Filter: A New Architecture for +User-level Packet Capture''. A compressed PostScript version can be +found at + + ftp://ftp.ee.lbl.gov/papers/bpf-usenix93.ps.Z + +or + + http://www.tcpdump.org/papers/bpf-usenix93.ps.Z + +and a gzipped version can be found at + + http://www.tcpdump.org/papers/bpf-usenix93.ps.gz + +A PDF version can be found at + + http://www.tcpdump.org/papers/bpf-usenix93.pdf + +Although most packet capture interfaces support in-kernel filtering, +libpcap utilizes in-kernel filtering only for the BPF interface. +On systems that don't have BPF, all packets are read into user-space +and the BPF filters are evaluated in the libpcap library, incurring +added overhead (especially, for selective filters). Ideally, libpcap +would translate BPF filters into a filter program that is compatible +with the underlying kernel subsystem, but this is not yet implemented. + +BPF is standard in 4.4BSD, BSD/OS, NetBSD, FreeBSD, OpenBSD, DragonFly +BSD, and Mac OS X; an older, modified and undocumented version is +standard in AIX. {DEC OSF/1, Digital UNIX, Tru64 UNIX} uses the +packetfilter interface but has been extended to accept BPF filters +(which libpcap utilizes). Also, you can add BPF filter support to +Ultrix using the kernel source and/or object patches available in: + + http://www.tcpdump.org/other/bpfext42.tar.Z + +Linux, in the 2.2 kernel and later kernels, has a "Socket Filter" +mechanism that accepts BPF filters; see the README.linux file for +information on configuring that option. + +Note to Linux distributions and *BSD systems that include libpcap: + +There's now a rule to make a shared library, which should work on Linux +and *BSD, among other platforms. + +It sets the soname of the library to "libpcap.so.1"; this is what it +should be, *NOT* libpcap.so.1.x or libpcap.so.1.x.y or something such as +that. + +We've been maintaining binary compatibility between libpcap releases for +quite a while; there's no reason to tie a binary linked with libpcap to +a particular release of libpcap. + +Problems, bugs, questions, desirable enhancements, etc. should be sent +to the address "tcpdump-workers@lists.tcpdump.org". Bugs, support +requests, and feature requests may also be submitted on the GitHub issue +tracker for libpcap at + + https://github.com/the-tcpdump-group/libpcap/issues + +Source code contributions, etc. should be sent to the email address +above or submitted by forking the branch on GitHub at + + http://github.com/the-tcpdump-group/libpcap/tree/master + +and issuing a pull request. + +Current versions can be found at www.tcpdump.org. + + - The TCPdump team diff --git a/tcpdump/jni/libpcap/README.Win32 b/tcpdump/jni/libpcap/README.Win32 new file mode 100644 index 0000000..0a42dab --- /dev/null +++ b/tcpdump/jni/libpcap/README.Win32 @@ -0,0 +1,46 @@ +Under Win32, libpcap is integrated in the WinPcap packet capture system. +WinPcap provides a framework that allows libpcap to capture the packets +under Windows 95, Windows 98, Windows ME, Windows NT 4, Windows 2000 +and Windows XP. +WinPcap binaries and source code can be found at http://winpcap.polito.it: +they include also a developer's pack with all the necessary to compile +libpcap-based applications under Windows. + +How to compile libpcap with Visual Studio +----------------------------------------- + +In order to compile libpcap you will need: + +- version 6 (or higher) of Microsoft Visual Studio +- The November 2001 (or later) edition of Microsoft Platform +Software Development Kit (SDK), that contains some necessary includes +for IPv6 support. You can download it from http://www.microsoft.com/sdk +- the latest WinPcap sources from http://winpcap.polito.it/install + +The WinPcap source code already contains a recent (usually the latest +stable) version of libpcap. If you need to compile a different one, +simply download it from www.tcpdump.org and copy the sources in the +winpcap\wpcap\libpcap folder of the WinPcap distribution. If you want to +compile a libpcap source retrieved from the tcpdump.org Git, you will +have to create the scanner and the grammar by hand (with lex and yacc) +or with the cygnus makefile, since The Visual Studio project is not able +to build them. + +Open the project file winpcap\wpcap\prj\wpcap.dsw with Visual Studio and +build wpcap.dll. wpcap.lib, the library file to link with the applications, +will be generated in winpcap\wpcap\lib\. wpcap.dll will be generated in +winpcap\wpcap\prj\release or winpcap\wpcap\prj\debug depending on the type +of binary that is being created. + +How to compile libpcap with Cygnus +---------------------------------- + +To build wpcap.dll, cd to the directory WPCAP/PRJ of the WinPcap source code +distribution and type "make". libwpcap.a, the library file to link with the +applications, will be generated in winpcap\wpcap\lib\. wpcap.dll will be +generated in winpcap\wpcap\prj. + +Remember, you CANNOT use the MSVC-generated .lib files with gcc, use +libwpcap.a instead. + +"make install" installs wpcap.dll in the Windows system folder. diff --git a/tcpdump/jni/libpcap/README.aix b/tcpdump/jni/libpcap/README.aix new file mode 100644 index 0000000..92e513f --- /dev/null +++ b/tcpdump/jni/libpcap/README.aix @@ -0,0 +1,88 @@ +Using BPF: + +(1) AIX 4.x's version of BPF is undocumented and somewhat unstandard; the + current BPF support code includes changes that should work around + that; it appears to compile and work on at least one AIX 4.3.3 + machine. + + Note that the BPF driver and the "/dev/bpf" devices might not exist + on your machine; AIX's tcpdump loads the driver and creates the + devices if they don't already exist. Our libpcap should do the + same, and the configure script should detect that it's on an AIX + system and choose BPF even if the devices aren't there. + + Also note that tcpdump _binary_ compiled on AIX 4 may have a problem + doing the initial loading of the BPF driver if copied to AIX 5 and + run there (GH #52). tcpdump binary natively compiled on AIX 5 should + not have this issue. + +(2) If libpcap doesn't compile on your machine when configured to use + BPF, or if the workarounds fail to make it work correctly, you + should send to tcpdump-workers@lists.tcpdump.org a detailed bug + report (if the compile fails, send us the compile error messages; + if it compiles but fails to work correctly, send us as detailed as + possible a description of the symptoms, including indications of the + network link-layer type being wrong or time stamps being wrong). + + If you fix the problems yourself, please submit a patch by forking + the branch at + + https://github.com/the-tcpdump-group/libpcap/issues + + and issuing a pull request, so we can incorporate the fixes into the + next release. + + If you don't fix the problems yourself, you can, as a workaround, + make libpcap use DLPI instead of BPF. + + This can be done by specifying the flag: + + --with-pcap=dlpi + + to the "configure" script for libpcap. + +If you use DLPI: + +(1) It is a good idea to have the latest version of the DLPI driver on + your system, since certain versions may be buggy and cause your AIX + system to crash. DLPI is included in the fileset bos.rte.tty. I + found that the DLPI driver that came with AIX 4.3.2 was buggy, and + had to upgrade to bos.rte.tty 4.3.2.4: + + lslpp -l bos.rte.tty + + bos.rte.tty 4.3.2.4 COMMITTED Base TTY Support and Commands + + Updates for AIX filesets can be obtained from: + ftp://service.software.ibm.com/aix/fixes/ + + These updates can be installed with the smit program. + +(2) After compiling libpcap, you need to make sure that the DLPI driver + is loaded. Type: + + strload -q -d dlpi + + If the result is: + + dlpi: yes + + then the DLPI driver is loaded correctly. + + If it is: + + dlpi: no + + Then you need to type: + + strload -f /etc/dlpi.conf + + Check again with strload -q -d dlpi that the dlpi driver is loaded. + + Alternatively, you can uncomment the lines for DLPI in + /etc/pse.conf and reboot the machine; this way DLPI will always + be loaded when you boot your system. + +(3) There appears to be a problem in the DLPI code in some versions of + AIX, causing a warning about DL_PROMISC_MULTI failing; this might + be responsible for DLPI not being able to capture outgoing packets. diff --git a/tcpdump/jni/libpcap/README.dag b/tcpdump/jni/libpcap/README.dag new file mode 100644 index 0000000..accae7c --- /dev/null +++ b/tcpdump/jni/libpcap/README.dag @@ -0,0 +1,122 @@ + +The following instructions apply if you have a Linux or FreeBSD platform and +want libpcap to support the DAG range of passive network monitoring cards from +Endace (http://www.endace.com, see below for further contact details). + +1) Install and build the DAG software distribution by following the +instructions supplied with that package. Current Endace customers can download +the DAG software distibution from https://www.endace.com + +2) Configure libcap. To allow the 'configure' script to locate the DAG +software distribution use the '--with-dag' option: + + ./configure --with-dag=DIR + +Where DIR is the root of the DAG software distribution, for example +/var/src/dag. If the DAG software is correctly detected 'configure' will +report: + + checking whether we have DAG API... yes + +If 'configure' reports that there is no DAG API, the directory may have been +incorrectly specified or the DAG software was not built before configuring +libpcap. + +See also the libpcap INSTALL.txt file for further libpcap configuration +options. + +Building libpcap at this stage will include support for both the native packet +capture stream (linux or bpf) and for capturing from DAG cards. To build +libpcap with only DAG support specify the capture type as 'dag' when +configuring libpcap: + + ./configure --with-dag=DIR --with-pcap=dag + +Applications built with libpcap configured in this way will only detect DAG +cards and will not capture from the native OS packet stream. + +---------------------------------------------------------------------- + +Libpcap when built for DAG cards against dag-2.5.1 or later releases: + +Timeouts are supported. pcap_dispatch() will return after to_ms milliseconds +regardless of how many packets are received. If to_ms is zero pcap_dispatch() +will block waiting for data indefinitely. + +pcap_dispatch() will block on and process a minimum of 64kB of data (before +filtering) for efficiency. This can introduce high latencies on quiet +interfaces unless a timeout value is set. The timeout expiring will override +the 64kB minimum causing pcap_dispatch() to process any available data and +return. + +pcap_setnonblock is supported. When nonblock is set, pcap_dispatch() will +check once for available data, process any data available up to count, then +return immediately. + +pcap_findalldevs() is supported, e.g. dag0, dag1... + +Some DAG cards can provide more than one 'stream' of received data. +This can be data from different physical ports, or separated by filtering +or load balancing mechanisms. Receive streams have even numbers, e.g. +dag0:0, dag0:2 etc. Specifying transmit streams for capture is not supported. + +pcap_setfilter() is supported, BPF programs run in userspace. + +pcap_setdirection() is not supported. Only received traffic is captured. +DAG cards normally do not have IP or link layer addresses assigned as +they are used to passively monitor links. + +pcap_breakloop() is supported. + +pcap_datalink() and pcap_list_datalinks() are supported. The DAG card does +not attempt to set the correct datalink type automatically where more than +one type is possible. + +pcap_stats() is supported. ps_drop is the number of packets dropped due to +RX stream buffer overflow, this count is before filters are applied (it will +include packets that would have been dropped by the filter). The RX stream +buffer size is user configurable outside libpcap, typically 16-512MB. + +pcap_get_selectable_fd() is not supported, as DAG cards do not support +poll/select methods. + +pcap_inject() and pcap_sendpacket() are not supported. + +Some DAG cards now support capturing to multiple virtual interfaces, called +streams. Capture streams have even numbers. These are available via libpcap +as separate interfaces, e.g. dag0:0, dag0:2, dag0:4 etc. dag0:0 is the same +as dag0. These are visible via pcap_findalldevs(). + +libpcap now does NOT set the card's hardware snaplen (slen). This must now be +set using the appropriate DAG coniguration program, e.g. dagthree, dagfour, +dagsix, dagconfig. This is because the snaplen is currently shared between +all of the streams. In future this may change if per-stream slen is +implemented. + +DAG cards by default capture entire packets including the L2 +CRC/FCS. If the card is not configured to discard the CRC/FCS, this +can confuse applications that use libpcap if they're not prepared for +packets to have an FCS. + +Libpcap now reads the environment variable ERF_FCS_BITS to determine +how many bits of CRC/FCS to strip from the end of the captured +frame. This defaults to 32 for use with Ethernet. If the card is +configured to strip the CRC/FCS, then set ERF_FCS_BITS=0. If used with +a HDLC/PoS/PPP/Frame Relay link with 16 bit CRC/FCS, then set +ERF_FCS_BITS=16. + +If you wish to create a pcap file that DOES contain the Ethernet FCS, +specify the environment variable ERF_DONT_STRIP_FCS. This will cause +the existing FCS to be captured into the pcap file. Note some +applications may incorrectly report capture errors or oversize packets +when reading these files. + +---------------------------------------------------------------------- + +Please submit bug reports via . + +Please also visit our Web site at: + + http://www.endace.com/ + +For more information about Endace DAG cards contact . diff --git a/tcpdump/jni/libpcap/README.hpux b/tcpdump/jni/libpcap/README.hpux new file mode 100644 index 0000000..65ecff9 --- /dev/null +++ b/tcpdump/jni/libpcap/README.hpux @@ -0,0 +1,254 @@ +For HP-UX 11i (11.11) and later, there are no known issues with +promiscuous mode under HP-UX. If you are using a earlier version of +HP-UX and cannot upgrade, please continue reading. + +HP-UX patches to fix packet capture problems + +Note that packet-capture programs such as tcpdump may, on HP-UX, not be +able to see packets sent from the machine on which they're running. +Some articles on groups.google.com discussing this are: + + http://groups.google.com/groups?selm=82ld3v%2480i%241%40mamenchi.zrz.TU-Berlin.DE + +which says: + + Newsgroups: comp.sys.hp.hpux + Subject: Re: Did someone made tcpdump working on 10.20 ? + Date: 12/08/1999 + From: Lutz Jaenicke + + In article <82ks5i$5vc$1@news1.dti.ne.jp>, mtsat + wrote: + >Hello, + > + >I downloaded and compiled tcpdump3.4 a couple of week ago. I tried to use + >it, but I can only see incoming data, never outgoing. + >Someone (raj) explained me that a patch was missing, and that this patch + >must me "patched" (poked) in order to see outbound data in promiscuous mode. + >Many things to do .... So the question is : did someone has already this + >"ready to use" PHNE_**** patch ? + + Two things: + 1. You do need a late "LAN products cumulative patch" (e.g. PHNE_18173 + for s700/10.20). + 2. You must use +echo 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem + You can insert this e.g. into /sbin/init.d/lan + + Best regards, + Lutz + +and + + http://groups.google.com/groups?selm=88cf4t%24p03%241%40web1.cup.hp.com + +which says: + + Newsgroups: comp.sys.hp.hpux + Subject: Re: tcpdump only shows incoming packets + Date: 02/15/2000 + From: Rick Jones + + Harald Skotnes wrote: + > I am running HPUX 11.0 on a C200 hanging on a 100Mb switch. I have + > compiled libpcap-0.4 an tcpdump-3.4 and it seems to work. But at a + > closer look I only get to see the incoming packets not the + > outgoing. I have tried tcpflow-0.12 which also uses libpcap and the + > same thing happens. Could someone please give me a hint on how to + > get this right? + + Search/Read the archives ?-) + + What you are seeing is expected, un-patched, behaviour for an HP-UX + system. On 11.00, you need to install the latest lancommon/DLPI + patches, and then the latest driver patch for the interface(s) in use. + At that point, a miracle happens and you should start seeing outbound + traffic. + +[That article also mentions the patch that appears below.] + +and + + http://groups.google.com/groups?selm=38AA973E.96BE7DF7%40cc.uit.no + +which says: + + Newsgroups: comp.sys.hp.hpux + Subject: Re: tcpdump only shows incoming packets + Date: 02/16/2000 + From: Harald Skotnes + + Rick Jones wrote: + + ... + + > What you are seeing is expected, un-patched, behaviour for an HP-UX + > system. On 11.00, you need to install the latest lancommon/DLPI + > patches, and then the latest driver patch for the interface(s) in + > use. At that point, a miracle happens and you should start seeing + > outbound traffic. + + Thanks a lot. I have this problem on several machines running HPUX + 10.20 and 11.00. The machines where patched up before y2k so did not + know what to think. Anyway I have now installed PHNE_19766, + PHNE_19826, PHNE_20008, PHNE_20735 on the C200 and now I can see the + outbound traffic too. Thanks again. + +(although those patches may not be the ones to install - there may be +later patches). + +And another message to tcpdump-workers@tcpdump.org, from Rick Jones: + + Date: Mon, 29 Apr 2002 15:59:55 -0700 + From: Rick Jones + To: tcpdump-workers@tcpdump.org + Subject: Re: [tcpdump-workers] I Can't Capture the Outbound Traffic + + ... + + http://itrc.hp.com/ would be one place to start in a search for the most + up-to-date patches for DLPI and the lan driver(s) used on your system (I + cannot guess because 9000/800 is too generic - one hs to use the "model" + command these days and/or an ioscan command (see manpage) to guess what + the drivers (btlan[3456], gelan, etc) might be involved in addition to + DLPI. + + Another option is to upgrade to 11i as outbound promiscuous mode support + is there in the base OS, no patches required. + +Another posting: + + http://groups.google.com/groups?selm=7d6gvn%24b3%241%40ocean.cup.hp.com + +indicates that you need to install the optional STREAMS product to do +captures on HP-UX 9.x: + + Newsgroups: comp.sys.hp.hpux + Subject: Re: tcpdump HP/UX 9.x + Date: 03/22/1999 + From: Rick Jones + + Dave Barr (barr@cis.ohio-state.edu) wrote: + : Has anyone ported tcpdump (or something similar) to HP/UX 9.x? + + I'm reasonably confident that any port of tcpdump to 9.X would require + the (then optional) STREAMS product. This would bring DLPI, which is + what one uses to access interfaces in promiscuous mode. + + I'm not sure that HP even sells the 9.X STREAMS product any longer, + since HP-UX 9.X is off the pricelist (well, maybe 9.10 for the old 68K + devices). + + Your best bet is to be up on 10.20 or better if that is at all + possible. If your hardware is supported by it, I'd go with HP-UX 11. + If you want to see the system's own outbound traffic, you'll never get + that functionality on 9.X, but it might happen at some point for 10.20 + and 11.X. + + rick jones + +(as per other messages cited here, the ability to see the system's own +outbound traffic did happen). + +Rick Jones reports that HP-UX 11i needs no patches for outbound +promiscuous mode support. + +An additional note, from Jost Martin, for HP-UX 10.20: + + Q: How do I get ethereral on HPUX to capture the _outgoing_ packets + of an interface + A: You need to get PHNE_20892,PHNE_20725 and PHCO_10947 (or + newer, this is as of 4.4.00) and its dependencies. Then you can + enable the feature as descibed below: + + Patch Name: PHNE_20892 + Patch Description: s700 10.20 PCI 100Base-T cumulative patch + To trace the outbound packets, please do the following + to turn on a global promiscuous switch before running + the promiscuous applications like snoop or tcpdump: + + adb -w /stand/vmunix /dev/mem + lanc_outbound_promisc_flag/W 1 + (adb will echo the result showing that the flag has + been changed) + $quit + (Thanks for this part to HP-support, Ratingen) + + The attached hack does this and some security-related stuff + (thanks to hildeb@www.stahl.bau.tu-bs.de (Ralf Hildebrandt) who + posted the security-part some time ago) + + <> + + (Don't switch IP-forwarding off, if you need it !) + Install the hack as /sbin/init.d/hacl_ip_stack (adjust + permissions !) and make a sequencing-symlink + /sbin/rc2.d/S350hack_ip_stack pointing to this script. + Now all this is done on every reboot. + +According to Rick Jones, the global promiscuous switch also has to be +turned on for HP-UX 11.00, but not for 11i - and, in fact, the switch +doesn't even exist on 11i. + +Here's the "hack_ip_stack" script: + +-----------------------------------Cut Here------------------------------------- +#!/sbin/sh +# +# nettune: hack kernel parms for safety + +OKAY=0 +ERROR=-1 + +# /usr/contrib/bin fuer nettune auf Pfad +PATH=/sbin:/usr/sbin:/usr/bin:/usr/contrib/bin +export PATH + + +########## +# main # +########## + +case $1 in + start_msg) + print "Tune IP-Stack for security" + exit $OKAY + ;; + + stop_msg) + print "This action is not applicable" + exit $OKAY + ;; + + stop) + exit $OKAY + ;; + + start) + ;; # fall through + + *) + print "USAGE: $0 {start_msg | stop_msg | start | stop}" >&2 + exit $ERROR + ;; + esac + +########### +# start # +########### + +# +# tcp-Sequence-Numbers nicht mehr inkrementieren sondern random +# Syn-Flood-Protection an +# ip_forwarding aus +# Source-Routing aus +# Ausgehende Packets an ethereal/tcpdump etc. + +/usr/contrib/bin/nettune -s tcp_random_seq 2 || exit $ERROR +/usr/contrib/bin/nettune -s hp_syn_protect 1 || exit $ERROR +/usr/contrib/bin/nettune -s ip_forwarding 0 || exit $ERROR +echo 'ip_block_source_routed/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem || exit $ERROR +echo 'lanc_outbound_promisc_flag/W 1' | adb -w /stand/vmunix /dev/mem || exit $ERROR + +exit $OKAY +-----------------------------------Cut Here------------------------------------- diff --git a/tcpdump/jni/libpcap/README.linux b/tcpdump/jni/libpcap/README.linux new file mode 100644 index 0000000..ffcb928 --- /dev/null +++ b/tcpdump/jni/libpcap/README.linux @@ -0,0 +1,108 @@ +In order for libpcap to be able to capture packets on a Linux system, +the "packet" protocol must be supported by your kernel. If it is not, +you may get error messages such as + + modprobe: can't locate module net-pf-17 + +in "/var/adm/messages", or may get messages such as + + socket: Address family not supported by protocol + +from applications using libpcap. + +You must configure the kernel with the CONFIG_PACKET option for this +protocol; the following note is from the Linux "Configure.help" file for +the 2.0[.x] kernel: + + Packet socket + CONFIG_PACKET + The Packet protocol is used by applications which communicate + directly with network devices without an intermediate network + protocol implemented in the kernel, e.g. tcpdump. If you want them + to work, choose Y. + + This driver is also available as a module called af_packet.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt; if you use modprobe or + kmod, you may also want to add "alias net-pf-17 af_packet" to + /etc/modules.conf. + +and the note for the 2.2[.x] kernel says: + + Packet socket + CONFIG_PACKET + The Packet protocol is used by applications which communicate + directly with network devices without an intermediate network + protocol implemented in the kernel, e.g. tcpdump. If you want them + to work, choose Y. This driver is also available as a module called + af_packet.o ( = code which can be inserted in and removed from the + running kernel whenever you want). If you want to compile it as a + module, say M here and read Documentation/modules.txt. You will + need to add 'alias net-pf-17 af_packet' to your /etc/conf.modules + file for the module version to function automatically. If unsure, + say Y. + +In addition, there is an option that, in 2.2 and later kernels, will +allow packet capture filters specified to programs such as tcpdump to be +executed in the kernel, so that packets that don't pass the filter won't +be copied from the kernel to the program, rather than having all packets +copied to the program and libpcap doing the filtering in user mode. + +Copying packets from the kernel to the program consumes a significant +amount of CPU, so filtering in the kernel can reduce the overhead of +capturing packets if a filter has been specified that discards a +significant number of packets. (If no filter is specified, it makes no +difference whether the filtering isn't performed in the kernel or isn't +performed in user mode. :-)) + +The option for this is the CONFIG_FILTER option; the "Configure.help" +file says: + + Socket filtering + CONFIG_FILTER + The Linux Socket Filter is derived from the Berkeley Packet Filter. + If you say Y here, user-space programs can attach a filter to any + socket and thereby tell the kernel that it should allow or disallow + certain types of data to get through the socket. Linux Socket + Filtering works on all socket types except TCP for now. See the text + file linux/Documentation/networking/filter.txt for more information. + If unsure, say N. + +Note that, by default, libpcap will, if libnl is present, build with it; +it uses libnl to support monitor mode on mac80211 devices. There is a +configuration option to disable building with libnl, but, if that option +is chosen, the monitor-mode APIs (as used by tcpdump's "-I" flag, and as +will probably be used by other applications in the future) won't work +properly on mac80211 devices. + +Linux's run-time linker allows shared libraries to be linked with other +shared libraries, which means that if an older version of a shared +library doesn't require routines from some other shared library, and a +later version of the shared library does require those routines, the +later version of the shared library can be linked with that other shared +library and, if it's otherwise binary-compatible with the older version, +can replace that older version without breaking applications built with +the older version, and without breaking configure scripts or the build +procedure for applications whose configure script doesn't use the +pcap-config script if they build with the shared library. (The build +procedure for applications whose configure scripts use the pcap-config +script if present will not break even if they build with the static +library.) + +Statistics: +Statistics reported by pcap are platform specific. The statistics +reported by pcap_stats on Linux are as follows: + +2.2.x +===== +ps_recv Number of packets that were accepted by the pcap filter +ps_drop Always 0, this statistic is not gatherd on this platform + +2.4.x +===== +ps_recv Number of packets that were accepted by the pcap filter +ps_drop Number of packets that had passed filtering but were not + passed on to pcap due to things like buffer shortage, etc. + This is useful because these are packets you are interested in + but won't be reported by, for example, tcpdump output. diff --git a/tcpdump/jni/libpcap/README.macosx b/tcpdump/jni/libpcap/README.macosx new file mode 100644 index 0000000..3dc9211 --- /dev/null +++ b/tcpdump/jni/libpcap/README.macosx @@ -0,0 +1,74 @@ +As with other systems using BPF, Mac OS X allows users with read access +to the BPF devices to capture packets with libpcap and allows users with +write access to the BPF devices to send packets with libpcap. + +On some systems that use BPF, the BPF devices live on the root file +system, and the permissions and/or ownership on those devices can be +changed to give users other than root permission to read or write those +devices. + +On newer versions of FreeBSD, the BPF devices live on devfs, and devfs +can be configured to set the permissions and/or ownership of those +devices to give users other than root permission to read or write those +devices. + +On Mac OS X, the BPF devices live on devfs, but the OS X version of +devfs is based on an older (non-default) FreeBSD devfs, and that version +of devfs cannot be configured to set the permissions and/or ownership of +those devices. + +Therefore, we supply: + + a "startup item" for older versions of Mac OS X; + + a launchd daemon for Tiger and later versions of Mac OS X; + +Both of them will change the ownership of the BPF devices so that the +"admin" group owns them, and will change the permission of the BPF +devices to rw-rw----, so that all users in the "admin" group - i.e., all +users with "Allow user to administer this computer" turned on - have +both read and write access to them. + +The startup item is in the ChmodBPF directory in the source tree. A +/Library/StartupItems directory should be created if it doesn't already +exist, and the ChmodBPF directory should be copied to the +/Library/StartupItems directory (copy the entire directory, so that +there's a /Library/StartupItems/ChmodBPF directory, containing all the +files in the source tree's ChmodBPF directory; don't copy the individual +items in that directory to /Library/StartupItems). The ChmodBPF +directory, and all files under it, must be owned by root. Installing +the files won't immediately cause the startup item to be executed; it +will be executed on the next reboot. To change the permissions before +the reboot, run + + sudo SystemStarter start ChmodBPF + +The launchd daemon is the chmod_bpf script, plus the +org.tcpdump.chmod_bpf.plist launchd plist file. chmod_bpf should be +installed in /usr/local/bin/chmod_bpf, and org.tcpdump.chmod_bpf.plist +should be installed in /Library/LaunchDaemons. chmod_bpf, and +org.tcpdump.chmod_bpf.plist, must be owned by root. Installing the +script and plist file won't immediately cause the script to be executed; +it will be executed on the next reboot. To change the permissions +before the reboot, run + + sudo /usr/local/bin/chmod_bpf + +or + + sudo launchctl load /Library/LaunchDaemons/org.tcpdump.chmod_bpf.plist + +If you want to give a particular user permission to access the BPF +devices, rather than giving all administrative users permission to +access them, you can have the ChmodBPF/ChmodBPF script change the +ownership of /dev/bpf* without changing the permissions. If you want to +give a particular user permission to read and write the BPF devices and +give the administrative users permission to read but not write the BPF +devices, you can have the script change the owner to that user, the +group to "admin", and the permissions to rw-r-----. Other possibilities +are left as an exercise for the reader. + +(NOTE: due to a bug in Snow Leopard, if you change the permissions not +to grant write permission to everybody who should be allowed to capture +traffic, non-root users who cannot open the BPF devices for writing will +not be able to capture outgoing packets.) diff --git a/tcpdump/jni/libpcap/README.septel b/tcpdump/jni/libpcap/README.septel new file mode 100644 index 0000000..483de6a --- /dev/null +++ b/tcpdump/jni/libpcap/README.septel @@ -0,0 +1,50 @@ +The following instructions apply if you have a Linux platform and want +libpcap to support the Septel range of passive network monitoring cards +from Intel (http://www.intel.com) + +1) Install and build the Septel software distribution by following the +instructions supplied with that package. + +2) Configure libcap. To allow the 'configure' script to locate the Septel +software distribution use the '--with-septel' option: + + ./configure --with-septel=DIR + +where DIR is the root of the Septel software distribution, for example +/var/src/septel. + +By default (if you write only ./configure --with-septel) it takes +./../septel as argument for DIR. + +If the Septel software is correctly detected 'configure' will +report: + + checking whether we have Septel API... yes + +If 'configure' reports that there is no Septel API, the directory may have been +incorrectly specified or the Septel software was not built before configuring +libpcap. + +See also the libpcap INSTALL.txt file for further libpcap configuration +options. + +Building libpcap at this stage will include support for both the native +packet capture stream and for capturing from Septel cards. To build +libpcap with only Septel support specify the capture type as 'septel' +when configuring libpcap: + + ./configure --with-septel=DIR --with-pcap=septel + +Applications built with libpcap configured in this way will only detect Septel +cards and will not capture from the native OS packet stream. + +Note: As mentioned in pcap-septel.c we should first edit the system.txt +file to change the user part example (UPE) module id to 0xdd instead of +0x2d for technical reason. So this change in system.txt is crutial and +things will go wrong if it's not done. System.txt along with config.txt +are configuration files that are edited by the user before running the +gctload program that uses these files for initialising modules and +configuring parameters. + +---------------------------------------------------------------------- +for more information please contact me : gil_hoyek@hotmail.com diff --git a/tcpdump/jni/libpcap/README.sita b/tcpdump/jni/libpcap/README.sita new file mode 100644 index 0000000..ee7a426 --- /dev/null +++ b/tcpdump/jni/libpcap/README.sita @@ -0,0 +1,64 @@ +The following instructions apply if you have a Linux platform and want +libpcap to support the 'ACN' WAN/LAN router product from from SITA +(http://www.sita.aero) + +This might also work on non-Linux Unix-compatible platforms, but that +has not been tested. + +See also the libpcap INSTALL.txt file for further libpcap configuration +options. + +These additions/extensions have been made to PCAP to allow it to +capture packets from a SITA ACN device (and potentially others). + +To enable its support you need to ensure that the distribution has +a correct configure.in file; that can be created if neccessay by +using the normal autoconf procedure of: + +aclocal +autoconf +autoheader +automake + +Then run configure with the 'sita' option: + +./configure --with-sita + +Applications built with libpcap configured in this way will only detect SITA +ACN interfaces and will not capture from the native OS packet stream. + +The SITA extension provides a remote datascope operation for capturing +both WAN and LAN protocols. It effectively splits the operation of +PCAP into two halves. The top layer performs the majority of the +work, but interfaces via a TCP session to remote agents that +provide the lower layer functionality of actual sniffing and +filtering. More detailed information regarding the functions and +inter-device protocol and naming conventions are described in detail +in 'pcap-sita.html'. + +pcap_findalldevs() reads the local system's /etc/hosts file looking +for host names that match the format of IOP type devices. ie. aaa_I_x_y +and then queries each associated IP address for a list of its WAN and +LAN devices. The local system the aggregates the lists obtained from +each IOP, sorts it, and provides it (to Wireshark et.al) as the +list of monitorable interfaces. + +Once a valid interface has been selected, pcap_open() is called +which opens a TCP session (to a well known port) on the target IOP +and tells it to start monitoring. + +All captured packets are then forwarded across that TCP session +back to the local 'top layer' for forwarding to the actual +sniffing program (wireshark...) + +Note that the DLT_SITA link-layer type includes a proprietary header +that is documented as part of the SITA dissector of Wireshark and is +also described in 'pcap-sita.html' for posterity sake. + +That header provides: +- Packet direction (in/out) (1 octet) +- Link layer hardware signal status (1 octet) +- Transmit/Receive error status (2 octets) +- Encapsulated WAN protocol ID (1 octet) + + diff --git a/tcpdump/jni/libpcap/README.tru64 b/tcpdump/jni/libpcap/README.tru64 new file mode 100644 index 0000000..2420d9e --- /dev/null +++ b/tcpdump/jni/libpcap/README.tru64 @@ -0,0 +1,49 @@ +The following instructions are applicable to Tru64 UNIX +(formerly Digital UNIX (formerly DEC OSF/1)) version 4.0, and +probably to later versions as well; at least some options apply to +Digital UNIX 3.2 - perhaps all do. + +In order to use kernel packet filtering on this system, you have +to configure it in such a way: + +Kernel configuration +-------------------- + +The packet filtering kernel option must be enabled at kernel +installation. If it was not the case, you can rebuild the kernel with +"doconfig -c" after adding the following line in the kernel +configuration file (/sys/conf/): + + option PACKETFILTER + +or use "doconfig" without any arguments to add the packet filter driver +option via the kernel option menu (see the system administration +documentation for information on how to do this). + +Device configuration +-------------------- + +Devices used for packet filtering must be created thanks to +the following command (executed in the /dev directory): + + ./MAKEDEV pfilt + +Interface configuration +----------------------- + +In order to capture all packets on a network, you may want to allow +applications to put the interface on that network into "local copy" +mode, so that tcpdump can see packets sent by the host on which it's +running as well as packets received by that host, and to put the +interface into "promiscuous" mode, so that tcpdump can see packets on +the network segment not sent to the host on which it's running, by using +the pfconfig(1) command: + + pfconfig +c +p + +or allow application to put any interface into "local copy" or +"promiscuous" mode by using the command: + + pfconfig +c +p -a + +Note: all instructions given require root privileges. diff --git a/tcpdump/jni/libpcap/SUNOS4/nit_if.o.sparc b/tcpdump/jni/libpcap/SUNOS4/nit_if.o.sparc new file mode 100644 index 0000000000000000000000000000000000000000..d05073eac7666b6a880f01c53c7077581fc9fac9 GIT binary patch literal 5212 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 literal 0 HcmV?d00001 diff --git a/tcpdump/jni/libpcap/SUNOS4/nit_if.o.sun3 b/tcpdump/jni/libpcap/SUNOS4/nit_if.o.sun3 new file mode 100644 index 0000000000000000000000000000000000000000..c393fc6ec79182d5146b988eaece342d257e893c GIT binary patch literal 4267 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 +#if (!defined(BSD)) || (BSD < 199306) +# include +#else +# include +#endif +#include +#else +#include +#define __LITTLE_ENDIAN 1 +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif + +/* + * revision information. this is the release date in YYYYMMDD format. + * it can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__BIND > 19931104)". do not + * compare for equality; rather, use it to determine whether your resolver + * is new enough to contain a certain feature. + */ + +#define __BIND 19940417 /* interface version stamp */ + +/* + * Define constants based on rfc883 + */ +#define PACKETSZ 512 /* maximum packet size */ +#define MAXDNAME 256 /* maximum domain name */ +#define MAXCDNAME 255 /* maximum compressed domain name */ +#define MAXLABEL 63 /* maximum length of domain label */ +#define HFIXEDSZ 12 /* #/bytes of fixed data in header */ +#define QFIXEDSZ 4 /* #/bytes of fixed data in query */ +#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ +#define INT32SZ 4 /* for systems without 32-bit ints */ +#define INT16SZ 2 /* for systems without 16-bit ints */ +#define INADDRSZ 4 /* for sizeof(struct inaddr) != 4 */ + +/* + * Internet nameserver port number + */ +#define NAMESERVER_PORT 53 + +/* + * Currently defined opcodes + */ +#define QUERY 0x0 /* standard query */ +#define IQUERY 0x1 /* inverse query */ +#define STATUS 0x2 /* nameserver status query */ +/*#define xxx 0x3 *//* 0x3 reserved */ +#define NS_NOTIFY_OP 0x4 /* notify secondary of SOA change */ +#ifdef ALLOW_UPDATES + /* non standard - supports ALLOW_UPDATES stuff from Mike Schwartz */ +# define UPDATEA 0x9 /* add resource record */ +# define UPDATED 0xa /* delete a specific resource record */ +# define UPDATEDA 0xb /* delete all named resource record */ +# define UPDATEM 0xc /* modify a specific resource record */ +# define UPDATEMA 0xd /* modify all named resource record */ +# define ZONEINIT 0xe /* initial zone transfer */ +# define ZONEREF 0xf /* incremental zone referesh */ +#endif + +/* + * Currently defined response codes + */ +#ifdef HAVE_ADDRINFO +#define NOERROR 0 /* no error */ +#endif /* HAVE_ADDRINFO */ +#define FORMERR 1 /* format error */ +#define SERVFAIL 2 /* server failure */ +#define NXDOMAIN 3 /* non existent domain */ +#define NOTIMP 4 /* not implemented */ +#define REFUSED 5 /* query refused */ +#ifdef ALLOW_UPDATES + /* non standard */ +# define NOCHANGE 0xf /* update failed to change db */ +#endif + +/* + * Type values for resources and queries + */ +#define T_A 1 /* host address */ +#define T_NS 2 /* authoritative server */ +#define T_MD 3 /* mail destination */ +#define T_MF 4 /* mail forwarder */ +#define T_CNAME 5 /* canonical name */ +#define T_SOA 6 /* start of authority zone */ +#define T_MB 7 /* mailbox domain name */ +#define T_MG 8 /* mail group member */ +#define T_MR 9 /* mail rename name */ +#define T_NULL 10 /* null resource record */ +#define T_WKS 11 /* well known service */ +#define T_PTR 12 /* domain name pointer */ +#define T_HINFO 13 /* host information */ +#define T_MINFO 14 /* mailbox information */ +#define T_MX 15 /* mail routing information */ +#define T_TXT 16 /* text strings */ +#define T_RP 17 /* responsible person */ +#define T_AFSDB 18 /* AFS cell database */ +#define T_X25 19 /* X_25 calling address */ +#define T_ISDN 20 /* ISDN calling address */ +#define T_RT 21 /* router */ +#define T_NSAP 22 /* NSAP address */ +#define T_NSAP_PTR 23 /* reverse NSAP lookup (deprecated) */ +#define T_SIG 24 /* security signature */ +#define T_KEY 25 /* security key */ +#define T_PX 26 /* X.400 mail mapping */ +#define T_GPOS 27 /* geographical position (withdrawn) */ +#define T_AAAA 28 /* IP6 Address */ +#define T_LOC 29 /* Location Information */ + /* non standard */ +#define T_UINFO 100 /* user (finger) information */ +#define T_UID 101 /* user ID */ +#define T_GID 102 /* group ID */ +#define T_UNSPEC 103 /* Unspecified format (binary data) */ + /* Query type values which do not appear in resource records */ +#define T_AXFR 252 /* transfer zone of authority */ +#define T_MAILB 253 /* transfer mailbox records */ +#define T_MAILA 254 /* transfer mail agent records */ +#define T_ANY 255 /* wildcard match */ + +/* + * Values for class field + */ + +#define C_IN 1 /* the arpa internet */ +#define C_CHAOS 3 /* for chaos net (MIT) */ +#define C_HS 4 /* for Hesiod name server (MIT) (XXX) */ + /* Query class values which do not appear in resource records */ +#define C_ANY 255 /* wildcard match */ + +/* + * Status return codes for T_UNSPEC conversion routines + */ +#define CONV_SUCCESS 0 +#define CONV_OVERFLOW (-1) +#define CONV_BADFMT (-2) +#define CONV_BADCKSUM (-3) +#define CONV_BADBUFLEN (-4) + +#ifndef __BYTE_ORDER +#if (BSD >= 199103) +# include +#else +#ifdef linux +# include +#else +#define __LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ +#define __BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ +#define __PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/ + +#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ + defined(__alpha__) || defined(__alpha) +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif + +#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || \ + defined (BIT_ZERO_ON_LEFT) || defined(m68k) +#define __BYTE_ORDER __BIG_ENDIAN +#endif +#endif /* linux */ +#endif /* BSD */ +#endif /* __BYTE_ORDER */ + +#if !defined(__BYTE_ORDER) || \ + (__BYTE_ORDER != __BIG_ENDIAN && __BYTE_ORDER != __LITTLE_ENDIAN && \ + __BYTE_ORDER != __PDP_ENDIAN) + /* you must determine what the correct bit order is for + * your compiler - the next line is an intentional error + * which will force your compiles to bomb until you fix + * the above macros. + */ + error "Undefined or invalid __BYTE_ORDER"; +#endif + +/* + * Structure for query header. The order of the fields is machine- and + * compiler-dependent, depending on the byte/bit order and the layout + * of bit fields. We use bit fields only in int variables, as this + * is all ANSI requires. This requires a somewhat confusing rearrangement. + */ + +typedef struct { + unsigned id :16; /* query identification number */ +#if __BYTE_ORDER == __BIG_ENDIAN + /* fields in third byte */ + unsigned qr: 1; /* response flag */ + unsigned opcode: 4; /* purpose of message */ + unsigned aa: 1; /* authoritive answer */ + unsigned tc: 1; /* truncated message */ + unsigned rd: 1; /* recursion desired */ + /* fields in fourth byte */ + unsigned ra: 1; /* recursion available */ + unsigned pr: 1; /* primary server req'd (!standard) */ + unsigned unused :2; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned rcode :4; /* response code */ +#endif +#if __BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __PDP_ENDIAN + /* fields in third byte */ + unsigned rd :1; /* recursion desired */ + unsigned tc :1; /* truncated message */ + unsigned aa :1; /* authoritive answer */ + unsigned opcode :4; /* purpose of message */ + unsigned qr :1; /* response flag */ + /* fields in fourth byte */ + unsigned rcode :4; /* response code */ + unsigned unused :2; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned pr :1; /* primary server req'd (!standard) */ + unsigned ra :1; /* recursion available */ +#endif + /* remaining bytes */ + unsigned qdcount :16; /* number of question entries */ + unsigned ancount :16; /* number of answer entries */ + unsigned nscount :16; /* number of authority entries */ + unsigned arcount :16; /* number of resource entries */ +} HEADER; + +/* + * Defines for handling compressed domain names + */ +#define INDIR_MASK 0xc0 + +/* + * Structure for passing resource records around. + */ +struct rrec { + int16_t r_zone; /* zone number */ + int16_t r_class; /* class number */ + int16_t r_type; /* type number */ + u_int32_t r_ttl; /* time to live */ + int r_size; /* size of data area */ + char *r_data; /* pointer to data */ +}; + +//extern u_int16_t _getshort __P((const u_char *)); +//extern u_int32_t _getlong __P((const u_char *)); + +/* + * Inline versions of get/put short/long. Pointer is advanced. + * + * These macros demonstrate the property of C whereby it can be + * portable or it can be elegant but rarely both. + */ +#define GETSHORT(s, cp) { \ + register u_char *t_cp = (u_char *)(cp); \ + (s) = ((u_int16_t)t_cp[0] << 8) \ + | ((u_int16_t)t_cp[1]) \ + ; \ + (cp) += INT16SZ; \ +} + +#define GETLONG(l, cp) { \ + register u_char *t_cp = (u_char *)(cp); \ + (l) = ((u_int32_t)t_cp[0] << 24) \ + | ((u_int32_t)t_cp[1] << 16) \ + | ((u_int32_t)t_cp[2] << 8) \ + | ((u_int32_t)t_cp[3]) \ + ; \ + (cp) += INT32SZ; \ +} + +#define PUTSHORT(s, cp) { \ + register u_int16_t t_s = (u_int16_t)(s); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += INT16SZ; \ +} + +#define PUTLONG(l, cp) { \ + register u_int32_t t_l = (u_int32_t)(l); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += INT32SZ; \ +} + +#endif /* !_NAMESER_H_ */ diff --git a/tcpdump/jni/libpcap/Win32/Include/bittypes.h b/tcpdump/jni/libpcap/Win32/Include/bittypes.h new file mode 100644 index 0000000..95aa9fa --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Include/bittypes.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _BITTYPES_H +#define _BITTYPES_H + +#ifndef HAVE_U_INT8_T +typedef unsigned char u_int8_t; +typedef signed char int8_t; +#endif /* HAVE_U_INT8_T */ + +#ifndef HAVE_U_INT16_T +typedef unsigned short u_int16_t; +typedef signed short int16_t; +#endif /* HAVE_U_INT16_T */ + +#ifndef HAVE_U_INT32_T +typedef unsigned int u_int32_t; +typedef signed int int32_t; +#endif /* HAVE_U_INT32_T */ + +#ifndef HAVE_U_INT64_T +#ifdef _MSC_EXTENSIONS +typedef unsigned _int64 u_int64_t; +typedef _int64 int64_t; +#else /* _MSC_EXTENSIONS */ +typedef unsigned long long u_int64_t; +typedef long long int64_t; +#endif /* _MSC_EXTENSIONS */ +#endif /* HAVE_U_INT64_T */ + +#ifndef PRId64 +#ifdef _MSC_EXTENSIONS +#define PRId64 "I64d" +#else /* _MSC_EXTENSIONS */ +#define PRId64 "lld" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRId64 */ + +#ifndef PRIo64 +#ifdef _MSC_EXTENSIONS +#define PRIo64 "I64o" +#else /* _MSC_EXTENSIONS */ +#define PRIo64 "llo" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIo64 */ + +#ifndef PRIx64 +#ifdef _MSC_EXTENSIONS +#define PRIx64 "I64x" +#else /* _MSC_EXTENSIONS */ +#define PRIx64 "llx" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIx64 */ + +#ifndef PRIu64 +#ifdef _MSC_EXTENSIONS +#define PRIu64 "I64u" +#else /* _MSC_EXTENSIONS */ +#define PRIu64 "llu" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIu64 */ + +#endif /* _BITTYPES_H */ diff --git a/tcpdump/jni/libpcap/Win32/Include/cdecl_ext.h b/tcpdump/jni/libpcap/Win32/Include/cdecl_ext.h new file mode 100644 index 0000000..9d40b84 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Include/cdecl_ext.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef HAVE_PORTABLE_PROTOTYPE + +#if defined(__STDC__) || defined(__cplusplus) +#define __P(protos) protos /* full-blown ANSI C */ +#else +#define __P(protos) () /* traditional C preprocessor */ +#endif + +#endif /* !HAVE_PORTABLE_PROTOTYPE */ diff --git a/tcpdump/jni/libpcap/Win32/Include/inetprivate.h b/tcpdump/jni/libpcap/Win32/Include/inetprivate.h new file mode 100644 index 0000000..e25ed3d --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Include/inetprivate.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1999 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +extern void _sethtent(int f); +extern void _endhtent(void); +extern struct hostent *_gethtent(void); +extern struct hostent *_gethtbyname(const char *name); +extern struct hostent *_gethtbyaddr(const char *addr, int len, + int type); +extern int _validuser(FILE *hostf, const char *rhost, + const char *luser, const char *ruser, int baselen); +extern int _checkhost(const char *rhost, const char *lhost, int len); +#if 0 +extern void putlong(u_long l, u_char *msgp); +extern void putshort(u_short l, u_char *msgp); +extern u_int32_t _getlong(register const u_char *msgp); +extern u_int16_t _getshort(register const u_char *msgp); +extern void p_query(char *msg); +extern void fp_query(char *msg, FILE *file); +extern char *p_cdname(char *cp, char *msg, FILE *file); +extern char *p_rr(char *cp, char *msg, FILE *file); +extern char *p_type(int type); +extern char * p_class(int class); +extern char *p_time(u_long value); +#endif +extern char * hostalias(const char *name); +extern void sethostfile(char *name); +extern void _res_close (void); +extern void ruserpass(const char *host, char **aname, char **apass); diff --git a/tcpdump/jni/libpcap/Win32/Include/ip6_misc.h b/tcpdump/jni/libpcap/Win32/Include/ip6_misc.h new file mode 100644 index 0000000..0b578c3 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Include/ip6_misc.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 1993, 1994, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows + */ + +#include + +#include + +#ifndef __MINGW32__ +#define IN_MULTICAST(a) IN_CLASSD(a) +#endif + +#define IN_EXPERIMENTAL(a) ((((u_int32_t) (a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +/* IPv6 address */ +struct in6_addr + { + union + { + u_int8_t u6_addr8[16]; + u_int16_t u6_addr16[8]; + u_int32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#define s6_addr64 in6_u.u6_addr64 + }; + +#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } +#endif /* __MINGW32__ */ + + +#if (defined _MSC_VER) || (defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)) +typedef unsigned short sa_family_t; +#endif + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) + +#define __SOCKADDR_COMMON(sa_prefix) \ + sa_family_t sa_prefix##family + +/* Ditto, for IPv6. */ +struct sockaddr_in6 + { + __SOCKADDR_COMMON (sin6_); + u_int16_t sin6_port; /* Transport layer port # */ + u_int32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + }; + +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ + (((u_int32_t *) (a))[2] == htonl (0xffff))) + +#define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ + ((((u_int32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000)) + +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \ + ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1)) +#endif /* __MINGW32__ */ + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] + +/* + * IPV6 extension headers + */ +#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ +#define IPPROTO_IPV6 41 /* IPv6 header. */ +#define IPPROTO_ROUTING 43 /* IPv6 routing header */ +#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IPPROTO_ESP 50 /* encapsulating security payload */ +#define IPPROTO_AH 51 /* authentication header */ +#define IPPROTO_ICMPV6 58 /* ICMPv6 */ +#define IPPROTO_NONE 59 /* IPv6 no next header */ +#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IPPROTO_PIM 103 /* Protocol Independent Multicast. */ + +#define IPV6_RTHDR_TYPE_0 0 + +/* Option types and related macros */ +#define IP6OPT_PAD1 0x00 /* 00 0 00000 */ +#define IP6OPT_PADN 0x01 /* 00 0 00001 */ +#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ +#define IP6OPT_JUMBO_LEN 6 +#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */ + +#define IP6OPT_RTALERT_LEN 4 +#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ +#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ +#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ +#define IP6OPT_MINLEN 2 + +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ + +#define IP6OPT_TYPE(o) ((o) & 0xC0) +#define IP6OPT_TYPE_SKIP 0x00 +#define IP6OPT_TYPE_DISCARD 0x40 +#define IP6OPT_TYPE_FORCEICMP 0x80 +#define IP6OPT_TYPE_ICMP 0xC0 + +#define IP6OPT_MUTABLE 0x20 + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +#ifndef EAI_ADDRFAMILY +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif +#endif /* __MINGW32__ */ diff --git a/tcpdump/jni/libpcap/Win32/Include/net/if.h b/tcpdump/jni/libpcap/Win32/Include/net/if.h new file mode 100644 index 0000000..58d3c16 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Include/net/if.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/if.h,v 1.49.2.1 1999/08/29 16:28:15 peter Exp $ + */ + +#ifndef _NET_IF_H_ +#define _NET_IF_H_ + +/* + * does not depend on on most other systems. This + * helps userland compatability. (struct timeval ifi_lastchange) + */ +#ifndef KERNEL +#include +#endif + +/* + * Structure describing information about an interface + * which may be of interest to management entities. + */ +struct if_data { + /* generic interface information */ + u_char ifi_type; /* ethernet, tokenring, etc */ + u_char ifi_physical; /* e.g., AUI, Thinnet, 10base-T, etc */ + u_char ifi_addrlen; /* media address length */ + u_char ifi_hdrlen; /* media header length */ + u_char ifi_recvquota; /* polling quota for receive intrs */ + u_char ifi_xmitquota; /* polling quota for xmit intrs */ + u_long ifi_mtu; /* maximum transmission unit */ + u_long ifi_metric; /* routing metric (external only) */ + u_long ifi_baudrate; /* linespeed */ + /* volatile statistics */ + u_long ifi_ipackets; /* packets received on interface */ + u_long ifi_ierrors; /* input errors on interface */ + u_long ifi_opackets; /* packets sent on interface */ + u_long ifi_oerrors; /* output errors on interface */ + u_long ifi_collisions; /* collisions on csma interfaces */ + u_long ifi_ibytes; /* total number of octets received */ + u_long ifi_obytes; /* total number of octets sent */ + u_long ifi_imcasts; /* packets received via multicast */ + u_long ifi_omcasts; /* packets sent via multicast */ + u_long ifi_iqdrops; /* dropped on input, this interface */ + u_long ifi_noproto; /* destined for unsupported protocol */ + u_long ifi_recvtiming; /* usec spent receiving when timing */ + u_long ifi_xmittiming; /* usec spent xmitting when timing */ + struct timeval ifi_lastchange; /* time of last administrative change */ +}; + +/* ws2tcpip.h has interface flags: IFF_* */ +#if 0 +#define IFF_UP 0x1 /* interface is up */ +#define IFF_BROADCAST 0x2 /* broadcast address valid */ +#define IFF_DEBUG 0x4 /* turn on debugging */ +#define IFF_LOOPBACK 0x8 /* is a loopback net */ +#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */ +/*#define IFF_NOTRAILERS 0x20 * obsolete: avoid use of trailers */ +#define IFF_RUNNING 0x40 /* resources allocated */ +#define IFF_NOARP 0x80 /* no address resolution protocol */ +#define IFF_PROMISC 0x100 /* receive all packets */ +#define IFF_ALLMULTI 0x200 /* receive all multicast packets */ +#define IFF_OACTIVE 0x400 /* transmission in progress */ +#define IFF_SIMPLEX 0x800 /* can't hear own transmissions */ +#define IFF_LINK0 0x1000 /* per link layer defined bit */ +#define IFF_LINK1 0x2000 /* per link layer defined bit */ +#define IFF_LINK2 0x4000 /* per link layer defined bit */ +#define IFF_ALTPHYS IFF_LINK2 /* use alternate physical connection */ +#define IFF_MULTICAST 0x8000 /* supports multicast */ +#endif /* 0 */ + +/* flags set internally only: */ +#define IFF_CANTCHANGE \ + (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\ + IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI) + +#define IFQ_MAXLEN 50 +#define IFNET_SLOWHZ 1 /* granularity is 1 second */ + +/* + * Message format for use in obtaining information about interfaces + * from getkerninfo and the routing socket + */ +struct if_msghdr { + u_short ifm_msglen; /* to skip over non-understood messages */ + u_char ifm_version; /* future binary compatability */ + u_char ifm_type; /* message type */ + int ifm_addrs; /* like rtm_addrs */ + int ifm_flags; /* value of if_flags */ + u_short ifm_index; /* index for associated ifp */ + struct if_data ifm_data;/* statistics and other data about if */ +}; + +/* + * Message format for use in obtaining information about interface addresses + * from getkerninfo and the routing socket + */ +struct ifa_msghdr { + u_short ifam_msglen; /* to skip over non-understood messages */ + u_char ifam_version; /* future binary compatability */ + u_char ifam_type; /* message type */ + int ifam_addrs; /* like rtm_addrs */ + int ifam_flags; /* value of ifa_flags */ + u_short ifam_index; /* index for associated ifp */ + int ifam_metric; /* value of ifa_metric */ +}; + +/* + * Message format for use in obtaining information about multicast addresses + * from the routing socket + */ +struct ifma_msghdr { + u_short ifmam_msglen; /* to skip over non-understood messages */ + u_char ifmam_version; /* future binary compatability */ + u_char ifmam_type; /* message type */ + int ifmam_addrs; /* like rtm_addrs */ + int ifmam_flags; /* value of ifa_flags */ + u_short ifmam_index; /* index for associated ifp */ +}; + +/* + * Interface request structure used for socket + * ioctl's. All interface ioctl's must have parameter + * definitions which begin with ifr_name. The + * remainder may be interface specific. + */ +struct ifreq { +#define IFNAMSIZ 16 + char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + short ifru_flags; + int ifru_metric; + int ifru_mtu; + int ifru_phys; + int ifru_media; + caddr_t ifru_data; + } ifr_ifru; +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ +#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_metric ifr_ifru.ifru_metric /* metric */ +#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ +#define ifr_phys ifr_ifru.ifru_phys /* physical wire */ +#define ifr_media ifr_ifru.ifru_media /* physical media */ +#define ifr_data ifr_ifru.ifru_data /* for use by interface */ +}; + +#define _SIZEOF_ADDR_IFREQ(ifr) \ + ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \ + (sizeof(struct ifreq) - sizeof(struct sockaddr) + \ + (ifr).ifr_addr.sa_len) : sizeof(struct ifreq)) + +struct ifaliasreq { + char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + struct sockaddr ifra_addr; + struct sockaddr ifra_broadaddr; + struct sockaddr ifra_mask; +}; + +struct ifmediareq { + char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + int ifm_current; /* current media options */ + int ifm_mask; /* don't care mask */ + int ifm_status; /* media status */ + int ifm_active; /* active options */ + int ifm_count; /* # entries in ifm_ulist array */ + int *ifm_ulist; /* media words */ +}; +/* + * Structure used in SIOCGIFCONF request. + * Used to retrieve interface configuration + * for machine (useful for programs which + * must know all networks accessible). + */ +struct ifconf { + int ifc_len; /* size of associated buffer */ + union { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ +}; + +#ifdef KERNEL +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_IFADDR); +MALLOC_DECLARE(M_IFMADDR); +#endif +#endif + +/* XXX - this should go away soon */ +#ifdef KERNEL +#include +#endif + +#endif /* !_NET_IF_H_ */ diff --git a/tcpdump/jni/libpcap/Win32/Include/net/netdb.h b/tcpdump/jni/libpcap/Win32/Include/net/netdb.h new file mode 100644 index 0000000..f7685d2 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Include/net/netdb.h @@ -0,0 +1,166 @@ +/*- + * Copyright (c) 1980, 1983, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)netdb.h 8.1 (Berkeley) 6/2/93 + * netdb.h,v 1.4 1995/08/14 04:05:04 hjl Exp + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#ifndef _NETDB_H_ +#define _NETDB_H_ + +/* MingW64 defines _POSIX_THREAD_SAFE_FUNCTIONS. + */ +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) || defined(_REENTRANT) && !defined(__MINGW64_VERSION_MAJOR) +#include +#include +#endif + +#include +#include + +#define _PATH_HEQUIV __PATH_ETC_INET"/hosts.equiv" +#define _PATH_HOSTS __PATH_ETC_INET"/hosts" +#define _PATH_NETWORKS __PATH_ETC_INET"/networks" +#define _PATH_PROTOCOLS __PATH_ETC_INET"/protocols" +#define _PATH_SERVICES __PATH_ETC_INET"/services" +#define _PATH_RESCONF __PATH_ETC_INET"/resolv.conf" +#define _PATH_RPC __PATH_ETC_INET"/rpc" + +struct rpcent { + char *r_name; /* name of server for this rpc program */ + char **r_aliases; /* alias list */ + int r_number; /* rpc program number */ +}; + +#ifndef WIN32 +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) || defined(_REENTRANT) + +#define __NETDB_MAXALIASES 35 +#define __NETDB_MAXADDRS 35 + +/* + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ +#define h_errno (*__h_errno_location ()) +#else +extern int h_errno; +#endif +#endif + +#define NETDB_INTERNAL -1 /* see errno */ +#define NETDB_SUCCESS 0 /* no problem */ + +//#include + +void endhostent (void); +void endnetent (void); +void endprotoent (void); +void endservent (void); +void endrpcent (void); +struct hostent *gethostent (void); +struct netent *getnetbyaddr (long, int); /* u_long? */ +struct netent *getnetbyname (const char *); +struct netent *getnetent (void); +struct protoent *getprotoent (void); +struct servent *getservent (void); +struct rpcent *getrpcent (void); +struct rpcent *getrpcbyname (const char *); +struct rpcent *getrpcbynumber (int); +void herror (const char *); +void sethostent (int); +/* void sethostfile (const char *); */ +void setnetent (int); +void setprotoent (int); +void setservent (int); +void setrpcent (int); + +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) || defined(_REENTRANT) +struct hostent *gethostbyaddr_r (const char *__addr, + int __length, int __type, + struct hostent *__result, + char *__buffer, int __buflen, int *__h_errnop); +struct hostent *gethostbyname_r (const char * __name, + struct hostent *__result, char *__buffer, + int __buflen, int *__h_errnop); +struct hostent *gethostent_r (struct hostent *__result, + char *__buffer, int __buflen, int *__h_errnop); +struct netent *getnetbyaddr_r (long __net, int __type, + struct netent *__result, char *__buffer, + int __buflen); +struct netent *getnetbyname_r (const char * __name, + struct netent *__result, char *__buffer, + int __buflen); +struct netent *getnetent_r (struct netent *__result, + char *__buffer, int __buflen); +struct protoent *getprotobyname_r (const char * __name, + struct protoent *__result, char *__buffer, + int __buflen); +struct protoent *getprotobynumber_r (int __proto, + struct protoent *__result, char *__buffer, + int __buflen); +struct protoent *getprotoent_r (struct protoent *__result, + char *__buffer, int __buflen); +struct servent *getservbyname_r (const char * __name, + const char *__proto, struct servent *__result, + char *__buffer, int __buflen); +struct servent *getservbyport_r (int __port, + const char *__proto, struct servent *__result, + char *__buffer, int __buflen); +struct servent *getservent_r (struct servent *__result, + char *__buffer, int __buflen); + +int *__h_errno_location (void); + +#endif + +#endif /* !_NETDB_H_ */ diff --git a/tcpdump/jni/libpcap/Win32/Include/net/paths.h b/tcpdump/jni/libpcap/Win32/Include/net/paths.h new file mode 100644 index 0000000..987de4f --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Include/net/paths.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)paths.h 5.15 (Berkeley) 5/29/91 + */ + +#ifndef _PATHS_H_ +#define _PATHS_H_ + +#if 0 +#define __PATH_ETC_INET "/usr/etc/inet" +#else +#define __PATH_ETC_INET "/etc" +#endif + +/* Default search path. */ +#define _PATH_DEFPATH "/usr/local/bin:/usr/bin:/bin:." +#define _PATH_DEFPATH_ROOT "/sbin:/bin:/usr/sbin:/usr/bin" + +#define _PATH_BSHELL "/bin/sh" +#define _PATH_CONSOLE "/dev/console" +#define _PATH_CSHELL "/bin/csh" +#define _PATH_DEVDB "/var/run/dev.db" +#define _PATH_DEVNULL "/dev/null" +#define _PATH_DRUM "/dev/drum" +#define _PATH_HEQUIV __PATH_ETC_INET"/hosts.equiv" +#define _PATH_KMEM "/dev/kmem" +#define _PATH_MAILDIR "/var/spool/mail" +#define _PATH_MAN "/usr/man" +#define _PATH_MEM "/dev/mem" +#define _PATH_LOGIN "/bin/login" +#define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_SENDMAIL "/usr/sbin/sendmail" +#define _PATH_SHELLS "/etc/shells" +#define _PATH_TTY "/dev/tty" +#define _PATH_UNIX "/vmlinux" +#define _PATH_VI "/usr/bin/vi" + +/* Provide trailing slash, since mostly used for building pathnames. */ +#define _PATH_DEV "/dev/" +#define _PATH_TMP "/tmp/" +#define _PATH_VARRUN "/var/run/" +#define _PATH_VARTMP "/var/tmp/" + +#define _PATH_KLOG "/proc/kmsg" +#define _PATH_LOGCONF __PATH_ETC_INET"/syslog.conf" +#if 0 +#define _PATH_LOGPID __PATH_ETC_INET"/syslog.pid" +#else +#define _PATH_LOGPID "/var/run/syslog.pid" +#endif +#define _PATH_LOG "/dev/log" +#define _PATH_CONSOLE "/dev/console" + +#if 0 +#define _PATH_UTMP "/var/adm/utmp" +#define _PATH_WTMP "/var/adm/wtmp" +#define _PATH_LASTLOG "/var/adm/lastlog" +#else +#define _PATH_UTMP "/var/run/utmp" +#define _PATH_WTMP "/var/log/wtmp" +#define _PATH_LASTLOG "/var/log/lastlog" +#endif + +#define _PATH_LOCALE "/usr/lib/locale" + +#define _PATH_RWHODIR "/var/spool/rwho" + +#if _MIT_POSIX_THREADS +/* For the MIT pthreads */ +#define _PATH_PTY "/dev/" +#define _PATH_TZDIR "/usr/lib/zoneinfo" +#define _PATH_TZFILE "/usr/lib/zoneinfo/localtime" +#endif + +#endif /* !_PATHS_H_ */ diff --git a/tcpdump/jni/libpcap/Win32/Include/sockstorage.h b/tcpdump/jni/libpcap/Win32/Include/sockstorage.h new file mode 100644 index 0000000..cbad190 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Include/sockstorage.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +struct sockaddr_storage { +#ifdef HAVE_SOCKADDR_SA_LEN + u_int8_t __ss_len; + u_int8_t __ss_family; + u_int8_t fill[126]; +#else + u_int8_t __ss_family; + u_int8_t fill[127]; +#endif /* HAVE_SOCKADDR_SA_LEN */ +}; diff --git a/tcpdump/jni/libpcap/Win32/Prj/libpcap.dsp b/tcpdump/jni/libpcap/Win32/Prj/libpcap.dsp new file mode 100644 index 0000000..7082122 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Prj/libpcap.dsp @@ -0,0 +1,168 @@ +# Microsoft Developer Studio Project File - Name="libpcap" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libpcap - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libpcap.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libpcap.mak" CFG="libpcap - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libpcap - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libpcap - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libpcap - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /I "../../lbl/" /I "../../bpf/" /I "../include/" /I "../../../../common" /I "../../../../dag/include" /I "../../../../dag/drv/windows" /D "NDEBUG" /D "YY_NEVER_INTERACTIVE" /D yylval=pcap_lval /D "_USRDLL" /D "LIBPCAP_EXPORTS" /D "HAVE_STRERROR" /D "__STDC__" /D "INET6" /D "_WINDOWS" /D "_MBCS" /D "HAVE_ADDRINFO" /D "WIN32" /D _U_= /D "HAVE_SNPRINTF" /D "HAVE_VSNPRINTF" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "libpcap - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /I "../../lbl/" /I "../../bpf/" /I "../include/" /I "../../../../common" /I "../../../../dag/include" /I "../../../../dag/drv/windows" /D "_DEBUG" /D "YY_NEVER_INTERACTIVE" /D yylval=pcap_lval /D "_USRDLL" /D "LIBPCAP_EXPORTS" /D "HAVE_STRERROR" /D "__STDC__" /D "INET6" /D "_WINDOWS" /D "_MBCS" /D "HAVE_ADDRINFO" /D "WIN32" /D _U_= /D "HAVE_SNPRINTF" /D "HAVE_VSNPRINTF" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "libpcap - Win32 Release" +# Name "libpcap - Win32 Debug" +# Begin Source File + +SOURCE=..\..\bpf_dump.c +# End Source File +# Begin Source File + +SOURCE=..\..\bpf\net\bpf_filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\bpf_image.c +# End Source File +# Begin Source File + +SOURCE=..\..\etherent.c +# End Source File +# Begin Source File + +SOURCE="..\..\fad-win32.c" +# End Source File +# Begin Source File + +SOURCE=..\Src\ffs.c +# End Source File +# Begin Source File + +SOURCE=..\..\gencode.c +# End Source File +# Begin Source File + +SOURCE=..\Src\getnetbynm.c +# End Source File +# Begin Source File + +SOURCE=..\Src\getnetent.c +# End Source File +# Begin Source File + +SOURCE=..\Src\getservent.c +# End Source File +# Begin Source File + +SOURCE=..\..\grammar.c +# End Source File +# Begin Source File + +SOURCE=..\..\inet.c +# End Source File +# Begin Source File + +SOURCE=..\Src\inet_aton.c +# End Source File +# Begin Source File + +SOURCE=..\Src\inet_net.c +# End Source File +# Begin Source File + +SOURCE=..\Src\inet_pton.c +# End Source File +# Begin Source File + +SOURCE=..\..\nametoaddr.c +# End Source File +# Begin Source File + +SOURCE=..\..\optimize.c +# End Source File +# Begin Source File + +SOURCE="..\..\Pcap-win32.c" +# End Source File +# Begin Source File + +SOURCE=..\..\pcap.c +# End Source File +# Begin Source File + +SOURCE=..\..\savefile.c +# End Source File +# Begin Source File + +SOURCE=..\..\scanner.c +# End Source File +# End Target +# End Project diff --git a/tcpdump/jni/libpcap/Win32/Prj/libpcap.dsw b/tcpdump/jni/libpcap/Win32/Prj/libpcap.dsw new file mode 100644 index 0000000..8cdff2d --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Prj/libpcap.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "libpcap"=".\libpcap.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tcpdump/jni/libpcap/Win32/Src/ffs.c b/tcpdump/jni/libpcap/Win32/Src/ffs.c new file mode 100644 index 0000000..099ff8e --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Src/ffs.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ffs.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include + +/* + * ffs -- vax ffs instruction + */ +int +ffs(mask) + register int mask; +{ + register int bit; + + if (mask == 0) + return(0); + for (bit = 1; !(mask & 1); bit++) + mask >>= 1; + return(bit); +} diff --git a/tcpdump/jni/libpcap/Win32/Src/gai_strerror.c b/tcpdump/jni/libpcap/Win32/Src/gai_strerror.c new file mode 100644 index 0000000..a36c35d --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Src/gai_strerror.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* +#include + +__FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/net/gai_strerror.c,v 1.1 2005/04/06 12:45:51 ume Exp $"); + +*/ + +#ifdef WIN32 + +#include + +#else + +#include + +#endif + +/* Entries EAI_ADDRFAMILY (1) and EAI_NODATA (7) are obsoleted, but left */ +/* for backward compatibility with userland code prior to 2553bis-02 */ +static char *ai_errlist[] = { + "Success", /* 0 */ + "Address family for hostname not supported", /* 1 */ + "Temporary failure in name resolution", /* EAI_AGAIN */ + "Invalid value for ai_flags", /* EAI_BADFLAGS */ + "Non-recoverable failure in name resolution", /* EAI_FAIL */ + "ai_family not supported", /* EAI_FAMILY */ + "Memory allocation failure", /* EAI_MEMORY */ + "No address associated with hostname", /* 7 */ + "hostname nor servname provided, or not known", /* EAI_NONAME */ + "servname not supported for ai_socktype", /* EAI_SERVICE */ + "ai_socktype not supported", /* EAI_SOCKTYPE */ + "System error returned in errno", /* EAI_SYSTEM */ + "Invalid value for hints", /* EAI_BADHINTS */ + "Resolved protocol is unknown" /* EAI_PROTOCOL */ +}; + +#ifndef EAI_MAX +#define EAI_MAX (sizeof(ai_errlist)/sizeof(ai_errlist[0])) +#endif + +/* on MingW, gai_strerror is available. + We need to compile gai_strerrorA only for Cygwin + */ +#ifndef gai_strerror + +char * +WSAAPI gai_strerrorA(int ecode) +{ + if (ecode >= 0 && ecode < EAI_MAX) + return ai_errlist[ecode]; + return "Unknown error"; +} + +#endif /* gai_strerror */ \ No newline at end of file diff --git a/tcpdump/jni/libpcap/Win32/Src/getaddrinfo.c b/tcpdump/jni/libpcap/Win32/Src/getaddrinfo.c new file mode 100644 index 0000000..d3ebda0 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Src/getaddrinfo.c @@ -0,0 +1,1124 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. + * + * Issues to be discussed: + * - Thread safe-ness must be checked. + * - Return values. There are nonstandard return values defined and used + * in the source code. This is because RFC2553 is silent about which error + * code must be returned for which situation. + * Note: + * - We use getipnodebyname() just for thread-safeness. There's no intent + * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to + * getipnodebyname(). + * - The code filters out AFs that are not supported by the kernel, + * when globbing NULL hostname (to loopback, or wildcard). Is it the right + * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG + * in ai_flags? + */ + +/* + * Mingw64 has its own implementation of getaddrinfo, mingw32 no + */ +#ifndef __MINGW64__ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#if 0 +#include +#endif +#ifndef __MINGW32__ +#include +#endif +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_PORTABLE_PROTOTYPE +#include "cdecl_ext.h" +#endif + +#ifndef HAVE_U_INT32_T +#include "bittypes.h" +#endif + +#ifndef HAVE_SOCKADDR_STORAGE +#ifndef __MINGW32__ +#include "sockstorage.h" +#endif +#endif + +#ifdef NEED_ADDRINFO_H +#include "addrinfo.h" +#ifdef WIN32 +#include "ip6_misc.h" +#endif +#endif + + +#if defined(__KAME__) && defined(INET6) +# define FAITH +#endif + +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 + +#ifdef FAITH +static int translate = NO; +static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT; +#endif + +static const char in_addrany[] = { 0, 0, 0, 0 }; +static const char in6_addrany[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const char in_loopback[] = { 127, 0, 0, 1 }; +static const char in6_loopback[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 +}; + +struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; + u_int32_t si_scope_id; +}; + +static const struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; + const char *a_addrany; + const char *a_loopback; + int a_scoped; +} afdl [] = { +#ifdef INET6 + {PF_INET6, sizeof(struct in6_addr), + sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr), + in6_addrany, in6_loopback, 1}, +#endif + {PF_INET, sizeof(struct in_addr), + sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr), + in_addrany, in_loopback, 0}, + {0, 0, 0, 0, NULL, NULL, 0}, +}; + +struct explore { + int e_af; + int e_socktype; + int e_protocol; + const char *e_protostr; + int e_wild; +#define WILD_AF(ex) ((ex)->e_wild & 0x01) +#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) +#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) +}; + +static const struct explore explore[] = { +#if 0 + { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, +#endif +#ifdef INET6 + { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, +#endif + { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, + { -1, 0, 0, NULL, 0 }, +}; + +#ifdef INET6 +#define PTON_MAX 16 +#else +#define PTON_MAX 4 +#endif + + +static int str_isnumber __P((const char *)); +static int explore_fqdn __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_null __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_numeric __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_numeric_scope __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int get_name __P((const char *, const struct afd *, struct addrinfo **, + char *, const struct addrinfo *, const char *)); +static int get_canonname __P((const struct addrinfo *, + struct addrinfo *, const char *)); +static struct addrinfo *get_ai __P((const struct addrinfo *, + const struct afd *, const char *)); +static int get_portmatch __P((const struct addrinfo *, const char *)); +static int get_port __P((struct addrinfo *, const char *, int)); +static const struct afd *find_afd __P((int)); + +static char *ai_errlist[] = { + "Success", + "Address family for hostname not supported", /* EAI_ADDRFAMILY */ + "Temporary failure in name resolution", /* EAI_AGAIN */ + "Invalid value for ai_flags", /* EAI_BADFLAGS */ + "Non-recoverable failure in name resolution", /* EAI_FAIL */ + "ai_family not supported", /* EAI_FAMILY */ + "Memory allocation failure", /* EAI_MEMORY */ + "No address associated with hostname", /* EAI_NODATA */ + "hostname nor servname provided, or not known", /* EAI_NONAME */ + "servname not supported for ai_socktype", /* EAI_SERVICE */ + "ai_socktype not supported", /* EAI_SOCKTYPE */ + "System error returned in errno", /* EAI_SYSTEM */ + "Invalid value for hints", /* EAI_BADHINTS */ + "Resolved protocol is unknown", /* EAI_PROTOCOL */ + "Unknown error", /* EAI_MAX */ +}; + +/* XXX macros that make external reference is BAD. */ + +#define GET_AI(ai, afd, addr) \ +do { \ + /* external reference: pai, error, and label free */ \ + (ai) = get_ai(pai, (afd), (addr)); \ + if ((ai) == NULL) { \ + error = EAI_MEMORY; \ + goto free; \ + } \ +} while (0) + +#define GET_PORT(ai, serv) \ +do { \ + /* external reference: error and label free */ \ + error = get_port((ai), (serv), 0); \ + if (error != 0) \ + goto free; \ +} while (0) + +#define GET_CANONNAME(ai, str) \ +do { \ + /* external reference: pai, error and label free */ \ + error = get_canonname(pai, (ai), (str)); \ + if (error != 0) \ + goto free; \ +} while (0) + +#define ERR(err) \ +do { \ + /* external reference: error, and label bad */ \ + error = (err); \ + goto bad; \ +} while (0) + +#define MATCH_FAMILY(x, y, w) \ + ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) +#define MATCH(x, y, w) \ + ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY))) + +#if defined(DEFINE_ADDITIONAL_IPV6_STUFF) +char * +gai_strerror(ecode) + int ecode; +{ + if (ecode < 0 || ecode > EAI_MAX) + ecode = EAI_MAX; + return ai_errlist[ecode]; +} +#endif + +void +freeaddrinfo(ai) + struct addrinfo *ai; +{ + struct addrinfo *next; + + do { + next = ai->ai_next; + if (ai->ai_canonname) + free(ai->ai_canonname); + /* no need to free(ai->ai_addr) */ + free(ai); + } while ((ai = next) != NULL); +} + +static int +str_isnumber(p) + const char *p; +{ + char *q = (char *)p; + while (*q) { + if (! isdigit(*q)) + return NO; + q++; + } + return YES; +} + +int +getaddrinfo(hostname, servname, hints, res) + const char *hostname, *servname; + const struct addrinfo *hints; + struct addrinfo **res; +{ + struct addrinfo sentinel; + struct addrinfo *cur; + int error = 0; + struct addrinfo ai; + struct addrinfo ai0; + struct addrinfo *pai; + const struct afd *afd; + const struct explore *ex; + +#ifdef FAITH + static int firsttime = 1; + + if (firsttime) { + /* translator hack */ + char *q = getenv("GAI"); + if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) + translate = YES; + firsttime = 0; + } +#endif + + sentinel.ai_next = NULL; + cur = &sentinel; + pai = &ai; + pai->ai_flags = 0; + pai->ai_family = PF_UNSPEC; + pai->ai_socktype = ANY; + pai->ai_protocol = ANY; + pai->ai_addrlen = 0; + pai->ai_canonname = NULL; + pai->ai_addr = NULL; + pai->ai_next = NULL; + + if (hostname == NULL && servname == NULL) + return EAI_NONAME; + if (hints) { + /* error check for hints */ + if (hints->ai_addrlen || hints->ai_canonname || + hints->ai_addr || hints->ai_next) + ERR(EAI_BADHINTS); /* xxx */ + if (hints->ai_flags & ~AI_MASK) + ERR(EAI_BADFLAGS); + switch (hints->ai_family) { + case PF_UNSPEC: + case PF_INET: +#ifdef INET6 + case PF_INET6: +#endif + break; + default: + ERR(EAI_FAMILY); + } + memcpy(pai, hints, sizeof(*pai)); + + /* + * if both socktype/protocol are specified, check if they + * are meaningful combination. + */ + if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { + for (ex = explore; ex->e_af >= 0; ex++) { + if (pai->ai_family != ex->e_af) + continue; + if (ex->e_socktype == ANY) + continue; + if (ex->e_protocol == ANY) + continue; + if (pai->ai_socktype == ex->e_socktype + && pai->ai_protocol != ex->e_protocol) { + ERR(EAI_BADHINTS); + } + } + } + } + + /* + * check for special cases. (1) numeric servname is disallowed if + * socktype/protocol are left unspecified. (2) servname is disallowed + * for raw and other inet{,6} sockets. + */ + if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) +#ifdef PF_INET6 + || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) +#endif + ) { + ai0 = *pai; + + if (pai->ai_family == PF_UNSPEC) { +#ifdef PF_INET6 + pai->ai_family = PF_INET6; +#else + pai->ai_family = PF_INET; +#endif + } + error = get_portmatch(pai, servname); + if (error) + ERR(error); + + *pai = ai0; + } + + ai0 = *pai; + + /* NULL hostname, or numeric hostname */ + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) + continue; + if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) + continue; + if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) + continue; + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + if (hostname == NULL) + error = explore_null(pai, hostname, servname, &cur->ai_next); + else + error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); + + if (error) + goto free; + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + + /* + * XXX + * If numreic representation of AF1 can be interpreted as FQDN + * representation of AF2, we need to think again about the code below. + */ + if (sentinel.ai_next) + goto good; + + if (pai->ai_flags & AI_NUMERICHOST) + ERR(EAI_NONAME); + if (hostname == NULL) + ERR(EAI_NONAME); + + /* + * hostname as alphabetical name. + * we would like to prefer AF_INET6 than AF_INET, so we'll make a + * outer loop by AFs. + */ + for (afd = afdl; afd->a_af; afd++) { + *pai = ai0; + + if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) + continue; + + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = afd->a_af; + + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) + continue; + if (!MATCH(pai->ai_socktype, ex->e_socktype, + WILD_SOCKTYPE(ex))) { + continue; + } + if (!MATCH(pai->ai_protocol, ex->e_protocol, + WILD_PROTOCOL(ex))) { + continue; + } + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + error = explore_fqdn(pai, hostname, servname, + &cur->ai_next); + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + } + + /* XXX */ + if (sentinel.ai_next) + error = 0; + + if (error) + goto free; + if (error == 0) { + if (sentinel.ai_next) { + good: + *res = sentinel.ai_next; + return SUCCESS; + } else + error = EAI_FAIL; + } + free: + bad: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + *res = NULL; + return error; +} + +/* + * FQDN hostname, DNS lookup + */ +static int +explore_fqdn(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + struct hostent *hp; + int h_error; + int af; + char **aplist = NULL, *apbuf = NULL; + char *ap; + struct addrinfo sentinel, *cur; + int i; +#ifndef USE_GETIPNODEBY + int naddrs; +#endif + const struct afd *afd; + int error; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * Do not filter unsupported AFs here. We need to honor content of + * databases (/etc/hosts, DNS and others). Otherwise we cannot + * replace gethostbyname() by getaddrinfo(). + */ + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + + /* + * post-RFC2553: should look at (pai->ai_flags & AI_ADDRCONFIG) + * rather than hardcoding it. we may need to add AI_ADDRCONFIG + * handling code by ourselves in case we don't have getipnodebyname(). + */ +#ifdef USE_GETIPNODEBY + hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, &h_error); +#else +#ifdef HAVE_GETHOSTBYNAME2 + hp = gethostbyname2(hostname, pai->ai_family); +#else + if (pai->ai_family != AF_INET) + return 0; + hp = gethostbyname(hostname); +#ifdef HAVE_H_ERRNO + h_error = h_errno; +#else + h_error = EINVAL; +#endif +#endif /*HAVE_GETHOSTBYNAME2*/ +#endif /*USE_GETIPNODEBY*/ + + if (hp == NULL) { + switch (h_error) { + case HOST_NOT_FOUND: + case NO_DATA: + error = EAI_NODATA; + break; + case TRY_AGAIN: + error = EAI_AGAIN; + break; + case NO_RECOVERY: + case NETDB_INTERNAL: + default: + error = EAI_FAIL; + break; + } + } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0) + || (hp->h_addr_list[0] == NULL)) { +#ifdef USE_GETIPNODEBY + freehostent(hp); +#endif + hp = NULL; + error = EAI_FAIL; + } + + if (hp == NULL) + goto free; + +#ifdef USE_GETIPNODEBY + aplist = hp->h_addr_list; +#else + /* + * hp will be overwritten if we use gethostbyname2(). + * always deep copy for simplification. + */ + for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++) + ; + naddrs++; + aplist = (char **)malloc(sizeof(aplist[0]) * naddrs); + apbuf = (char *)malloc(hp->h_length * naddrs); + if (aplist == NULL || apbuf == NULL) { + error = EAI_MEMORY; + goto free; + } + memset(aplist, 0, sizeof(aplist[0]) * naddrs); + for (i = 0; i < naddrs; i++) { + if (hp->h_addr_list[i] == NULL) { + aplist[i] = NULL; + continue; + } + memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i], + hp->h_length); + aplist[i] = &apbuf[i * hp->h_length]; + } +#endif + + for (i = 0; aplist[i] != NULL; i++) { + af = hp->h_addrtype; + ap = aplist[i]; +#ifdef AF_INET6 + if (af == AF_INET6 + && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { + af = AF_INET; + ap = ap + sizeof(struct in6_addr) + - sizeof(struct in_addr); + } +#endif + + if (af != pai->ai_family) + continue; + + if ((pai->ai_flags & AI_CANONNAME) == 0) { + GET_AI(cur->ai_next, afd, ap); + GET_PORT(cur->ai_next, servname); + } else { + /* + * if AI_CANONNAME and if reverse lookup + * fail, return ai anyway to pacify + * calling application. + * + * XXX getaddrinfo() is a name->address + * translation function, and it looks + * strange that we do addr->name + * translation here. + */ + get_name(ap, afd, &cur->ai_next, + ap, pai, servname); + } + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + + *res = sentinel.ai_next; + return 0; + +free: +#ifdef USE_GETIPNODEBY + if (hp) + freehostent(hp); +#endif + if (aplist) + free(aplist); + if (apbuf) + free(apbuf); + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * hostname == NULL. + * passive socket -> anyaddr (0.0.0.0 or ::) + * non-passive socket -> localhost (127.0.0.1 or ::1) + */ +static int +explore_null(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + int s; + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * filter out AFs that are not supported by the kernel + * XXX errno? + */ + s = socket(pai->ai_family, SOCK_DGRAM, 0); + if (s < 0) { + if (errno != EMFILE) + return 0; + } else + close(s); + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + + if (pai->ai_flags & AI_PASSIVE) { + GET_AI(cur->ai_next, afd, afd->a_addrany); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "anyaddr"); + */ + GET_PORT(cur->ai_next, servname); + } else { + GET_AI(cur->ai_next, afd, afd->a_loopback); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "localhost"); + */ + GET_PORT(cur->ai_next, servname); + } + cur = cur->ai_next; + + *res = sentinel.ai_next; + return 0; + +free: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * numeric hostname + */ +static int +explore_numeric(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + char pton[PTON_MAX]; + int flags; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + flags = pai->ai_flags; + + if (inet_pton(afd->a_af, hostname, pton) == 1) { + u_int32_t v4a; +#ifdef INET6 + u_char pfx; +#endif + + switch (afd->a_af) { + case AF_INET: + v4a = (u_int32_t)ntohl(((struct in_addr *)pton)->s_addr); + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags &= ~AI_CANONNAME; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + flags &= ~AI_CANONNAME; + break; +#ifdef INET6 + case AF_INET6: + pfx = ((struct in6_addr *)pton)->s6_addr[0]; + if (pfx == 0 || pfx == 0xfe || pfx == 0xff) + flags &= ~AI_CANONNAME; + break; +#endif + } + + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + if ((flags & AI_CANONNAME) == 0) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + } else { + /* + * if AI_CANONNAME and if reverse lookup + * fail, return ai anyway to pacify + * calling application. + * + * XXX getaddrinfo() is a name->address + * translation function, and it looks + * strange that we do addr->name + * translation here. + */ + get_name(pton, afd, &cur->ai_next, + pton, pai, servname); + } + while (cur && cur->ai_next) + cur = cur->ai_next; + } else + ERR(EAI_FAMILY); /*xxx*/ + } + + *res = sentinel.ai_next; + return 0; + +free: +bad: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * numeric hostname with scope + */ +static int +explore_numeric_scope(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ +#ifndef SCOPE_DELIMITER + return explore_numeric(pai, hostname, servname, res); +#else + const struct afd *afd; + struct addrinfo *cur; + int error; + char *cp, *hostname2 = NULL; + int scope; + struct sockaddr_in6 *sin6; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + if (!afd->a_scoped) + return explore_numeric(pai, hostname, servname, res); + + cp = strchr(hostname, SCOPE_DELIMITER); + if (cp == NULL) + return explore_numeric(pai, hostname, servname, res); + + /* + * Handle special case of + */ + hostname2 = strdup(hostname); + if (hostname2 == NULL) + return EAI_MEMORY; + /* terminate at the delimiter */ + hostname2[cp - hostname] = '\0'; + + cp++; + switch (pai->ai_family) { +#ifdef INET6 + case AF_INET6: + scope = if_nametoindex(cp); + if (scope == 0) { + free(hostname2); + return (EAI_NONAME); + } + break; +#endif + } + + error = explore_numeric(pai, hostname2, servname, res); + if (error == 0) { + for (cur = *res; cur; cur = cur->ai_next) { + if (cur->ai_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)cur->ai_addr; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) + sin6->sin6_scope_id = scope; + } + } + + free(hostname2); + + return error; +#endif +} + +static int +get_name(addr, afd, res, numaddr, pai, servname) + const char *addr; + const struct afd *afd; + struct addrinfo **res; + char *numaddr; + const struct addrinfo *pai; + const char *servname; +{ + struct hostent *hp = NULL; + struct addrinfo *cur = NULL; + int error = 0; + char *ap = NULL, *cn = NULL; +#ifdef USE_GETIPNODEBY + int h_error; + + hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); +#else + hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); +#endif + if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { +#ifdef USE_GETIPNODEBY + GET_AI(cur, afd, hp->h_addr_list[0]); + GET_PORT(cur, servname); + GET_CANONNAME(cur, hp->h_name); +#else + /* hp will be damaged if we use gethostbyaddr() */ + if ((ap = (char *)malloc(hp->h_length)) == NULL) { + error = EAI_MEMORY; + goto free; + } + memcpy(ap, hp->h_addr_list[0], hp->h_length); + if ((cn = strdup(hp->h_name)) == NULL) { + error = EAI_MEMORY; + goto free; + } + + GET_AI(cur, afd, ap); + GET_PORT(cur, servname); + GET_CANONNAME(cur, cn); + free(ap); ap = NULL; + free(cn); cn = NULL; +#endif + } else { + GET_AI(cur, afd, numaddr); + GET_PORT(cur, servname); + } + +#ifdef USE_GETIPNODEBY + if (hp) + freehostent(hp); +#endif + *res = cur; + return SUCCESS; + free: + if (cur) + freeaddrinfo(cur); + if (ap) + free(ap); + if (cn) + free(cn); +#ifdef USE_GETIPNODEBY + if (hp) + freehostent(hp); +#endif + *res = NULL; + return error; +} + +static int +get_canonname(pai, ai, str) + const struct addrinfo *pai; + struct addrinfo *ai; + const char *str; +{ + if ((pai->ai_flags & AI_CANONNAME) != 0) { + ai->ai_canonname = strdup(str); + if (ai->ai_canonname == NULL) + return EAI_MEMORY; + } + return 0; +} + +static struct addrinfo * +get_ai(pai, afd, addr) + const struct addrinfo *pai; + const struct afd *afd; + const char *addr; +{ + char *p; + struct addrinfo *ai; + + ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + + (afd->a_socklen)); + if (ai == NULL) + return NULL; + + memcpy(ai, pai, sizeof(struct addrinfo)); + ai->ai_addr = (struct sockaddr *)(ai + 1); + memset(ai->ai_addr, 0, afd->a_socklen); +#ifdef HAVE_SOCKADDR_SA_LEN + ai->ai_addr->sa_len = afd->a_socklen; +#endif + ai->ai_addrlen = afd->a_socklen; + ai->ai_addr->sa_family = ai->ai_family = afd->a_af; + p = (char *)(ai->ai_addr); + memcpy(p + afd->a_off, addr, afd->a_addrlen); + return ai; +} + +static int +get_portmatch(ai, servname) + const struct addrinfo *ai; + const char *servname; +{ + + /* get_port does not touch first argument. when matchonly == 1. */ + return get_port((struct addrinfo *)ai, servname, 1); +} + +static int +get_port(ai, servname, matchonly) + struct addrinfo *ai; + const char *servname; + int matchonly; +{ + const char *proto; + struct servent *sp; + int port; + int allownumeric; + + if (servname == NULL) + return 0; + switch (ai->ai_family) { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + break; + default: + return 0; + } + + switch (ai->ai_socktype) { + case SOCK_RAW: + return EAI_SERVICE; + case SOCK_DGRAM: + case SOCK_STREAM: + allownumeric = 1; + break; + case ANY: + allownumeric = 0; + break; + default: + return EAI_SOCKTYPE; + } + + if (str_isnumber(servname)) { + if (!allownumeric) + return EAI_SERVICE; + port = htons(atoi(servname)); + if (port < 0 || port > 65535) + return EAI_SERVICE; + } else { + switch (ai->ai_socktype) { + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_STREAM: + proto = "tcp"; + break; + default: + proto = NULL; + break; + } + + if ((sp = getservbyname(servname, proto)) == NULL) + return EAI_SERVICE; + port = sp->s_port; + } + + if (!matchonly) { + switch (ai->ai_family) { + case AF_INET: + ((struct sockaddr_in *)ai->ai_addr)->sin_port = port; + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port; + break; +#endif + } + } + + return 0; +} + +static const struct afd * +find_afd(af) + int af; +{ + const struct afd *afd; + + if (af == PF_UNSPEC) + return NULL; + for (afd = afdl; afd->a_af; afd++) { + if (afd->a_af == af) + return afd; + } + return NULL; +} + + +#endif /*__MING64__*/ diff --git a/tcpdump/jni/libpcap/Win32/Src/getnetbynm.c b/tcpdump/jni/libpcap/Win32/Src/getnetbynm.c new file mode 100644 index 0000000..fa4d398 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Src/getnetbynm.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getnetbyname.c 5.5 (Berkeley) 6/27/88"; +#endif /* LIBC_SCCS and not lint */ + +#include "inetprivate.h" + +extern int _net_stayopen; + +struct netent * +getnetbyname(const char *name) +{ + register struct netent *p; + register char **cp; + + setnetent(_net_stayopen); + while (p = getnetent()) { + if (strcmp(p->n_name, name) == 0) + break; + for (cp = p->n_aliases; *cp != 0; cp++) + if (strcmp(*cp, name) == 0) + goto found; + } +found: + if (!_net_stayopen) + endnetent(); + return (p); +} diff --git a/tcpdump/jni/libpcap/Win32/Src/getnetent.c b/tcpdump/jni/libpcap/Win32/Src/getnetent.c new file mode 100644 index 0000000..95281a5 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Src/getnetent.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getnetent.c 5.5 (Berkeley) 6/27/88"; +#endif /* LIBC_SCCS and not lint */ + +#include "inetprivate.h" + +#define MAXALIASES 35 + +static char NETDB[] = _PATH_NETWORKS; +static FILE *netf = NULL; +static char line[BUFSIZ+1]; +static struct netent net; +static char *net_aliases[MAXALIASES]; +static char *any(char *, char *); + +int _net_stayopen; +extern u_int32_t inet_network(const char *cp); + +void +setnetent(f) + int f; +{ + if (netf == NULL) + netf = fopen(NETDB, "r" ); + else + rewind(netf); + _net_stayopen |= f; +} + +void +endnetent() +{ + if (netf) { + fclose(netf); + netf = NULL; + } + _net_stayopen = 0; +} + +struct netent * +getnetent() +{ + char *p; + register char *cp, **q; + + if (netf == NULL && (netf = fopen(NETDB, "r" )) == NULL) + return (NULL); +again: + p = fgets(line, BUFSIZ, netf); + if (p == NULL) + return (NULL); + if (*p == '#') + goto again; + cp = any(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + net.n_name = p; + cp = any(p, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + while (*cp == ' ' || *cp == '\t') + cp++; + p = any(cp, " \t"); + if (p != NULL) + *p++ = '\0'; + net.n_net = inet_network(cp); + net.n_addrtype = AF_INET; + q = net.n_aliases = net_aliases; + if (p != NULL) + cp = p; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &net_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&net); +} + +static char * +any(cp, match) + register char *cp; + char *match; +{ + register char *mp, c; + + while (c = *cp) { + for (mp = match; *mp; mp++) + if (*mp == c) + return (cp); + cp++; + } + return ((char *)0); +} diff --git a/tcpdump/jni/libpcap/Win32/Src/getopt.c b/tcpdump/jni/libpcap/Win32/Src/getopt.c new file mode 100644 index 0000000..03c2086 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Src/getopt.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ +#ifdef WIN32 + char *__progname="windump"; +#else + extern char *__progname; +#endif + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/tcpdump/jni/libpcap/Win32/Src/getservent.c b/tcpdump/jni/libpcap/Win32/Src/getservent.c new file mode 100644 index 0000000..61b8cb0 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Src/getservent.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MAXALIASES 35 + +static char SERVDB[] = _PATH_SERVICES; +static FILE *servf = NULL; +static char line[BUFSIZ+1]; +static struct servent serv; +static char *serv_aliases[MAXALIASES]; +int _serv_stayopen; + +void +setservent(f) + int f; +{ + if (servf == NULL) + servf = fopen(SERVDB, "r" ); + else + rewind(servf); + _serv_stayopen |= f; +} + +void +endservent() +{ + if (servf) { + fclose(servf); + servf = NULL; + } + _serv_stayopen = 0; +} + +struct servent * +getservent() +{ + char *p; + register char *cp, **q; + + if (servf == NULL && (servf = fopen(SERVDB, "r" )) == NULL) + return (NULL); +again: + if ((p = fgets(line, BUFSIZ, servf)) == NULL) + return (NULL); + if (*p == '#') + goto again; + cp = strpbrk(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + serv.s_name = p; + p = strpbrk(p, " \t"); + if (p == NULL) + goto again; + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + cp = strpbrk(p, ",/"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + serv.s_port = htons((u_short)atoi(p)); + serv.s_proto = cp; + q = serv.s_aliases = serv_aliases; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &serv_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&serv); +} diff --git a/tcpdump/jni/libpcap/Win32/Src/inet_aton.c b/tcpdump/jni/libpcap/Win32/Src/inet_aton.c new file mode 100644 index 0000000..db97bce --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Src/inet_aton.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* Minimal implementation of inet_aton. + * Cannot distinguish between failure and a local broadcast address. */ + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +int +inet_aton(const char *cp, struct in_addr *addr) +{ + addr->s_addr = inet_addr(cp); + return (addr->s_addr == INADDR_NONE) ? 0 : 1; +} diff --git a/tcpdump/jni/libpcap/Win32/Src/inet_net.c b/tcpdump/jni/libpcap/Win32/Src/inet_net.c new file mode 100644 index 0000000..5bbe391 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Src/inet_net.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)inet_network.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include "inetprivate.h" + +/* + * Internet network address interpretation routine. + * The library routines call this routine to interpret + * network numbers. + */ +u_int32_t +inet_network(const char *cp) +{ + register u_long val, base, n; + register char c; + u_long parts[4], *pp = parts; + register int i; + +again: + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, other=decimal. + */ + val = 0; base = 10; + /* + * The 4.4BSD version of this file also accepts 'x__' as a hexa + * number. I don't think this is correct. -- Uli + */ + if (*cp == '0') { + if (*++cp == 'x' || *cp == 'X') + base = 16, cp++; + else + base = 8; + } + while ((c = *cp)) { + if (isdigit(c)) { + val = (val * base) + (c - '0'); + cp++; + continue; + } + if (base == 16 && isxdigit(c)) { + val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); + cp++; + continue; + } + break; + } + if (*cp == '.') { + if (pp >= parts + 4) + return (INADDR_NONE); + *pp++ = val, cp++; + goto again; + } + if (*cp && !isspace(*cp)) + return (INADDR_NONE); + *pp++ = val; + n = pp - parts; + if (n > 4) + return (INADDR_NONE); + for (val = 0, i = 0; i < (int)n; i++) { + val <<= 8; + val |= parts[i] & 0xff; + } + return (val); +} diff --git a/tcpdump/jni/libpcap/Win32/Src/inet_pton.c b/tcpdump/jni/libpcap/Win32/Src/inet_pton.c new file mode 100644 index 0000000..7fe3813 --- /dev/null +++ b/tcpdump/jni/libpcap/Win32/Src/inet_pton.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#ifdef WIN32 +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT 97 /* not present in errno.h provided with VC */ +#endif +#endif + +#ifdef __MINGW32__ +int* _errno(); +#define errno (*_errno()) +#endif /* __MINGW32__ */ + +#include + +int inet_aton(const char *cp, struct in_addr *addr); + +int +inet_pton(int af, const char *src, void *dst) +{ + if (af != AF_INET) { + errno = EAFNOSUPPORT; + return -1; + } + return inet_aton (src, dst); +} diff --git a/tcpdump/jni/libpcap/aclocal.m4 b/tcpdump/jni/libpcap/aclocal.m4 new file mode 100644 index 0000000..02502b2 --- /dev/null +++ b/tcpdump/jni/libpcap/aclocal.m4 @@ -0,0 +1,1293 @@ +dnl Copyright (c) 1995, 1996, 1997, 1998 +dnl The Regents of the University of California. All rights reserved. +dnl +dnl Redistribution and use in source and binary forms, with or without +dnl modification, are permitted provided that: (1) source code distributions +dnl retain the above copyright notice and this paragraph in its entirety, (2) +dnl distributions including binary code include the above copyright notice and +dnl this paragraph in its entirety in the documentation or other materials +dnl provided with the distribution, and (3) all advertising materials mentioning +dnl features or use of this software display the following acknowledgement: +dnl ``This product includes software developed by the University of California, +dnl Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +dnl the University nor the names of its contributors may be used to endorse +dnl or promote products derived from this software without specific prior +dnl written permission. +dnl THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +dnl WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +dnl MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +dnl +dnl LBL autoconf macros +dnl + +dnl +dnl Do whatever AC_LBL_C_INIT work is necessary before using AC_PROG_CC. +dnl +dnl It appears that newer versions of autoconf (2.64 and later) will, +dnl if you use AC_TRY_COMPILE in a macro, stick AC_PROG_CC at the +dnl beginning of the macro, even if the macro itself calls AC_PROG_CC. +dnl See the "Prerequisite Macros" and "Expanded Before Required" sections +dnl in the Autoconf documentation. +dnl +dnl This causes a steaming heap of fail in our case, as we were, in +dnl AC_LBL_C_INIT, doing the tests we now do in AC_LBL_C_INIT_BEFORE_CC, +dnl calling AC_PROG_CC, and then doing the tests we now do in +dnl AC_LBL_C_INIT. Now, we run AC_LBL_C_INIT_BEFORE_CC, AC_PROG_CC, +dnl and AC_LBL_C_INIT at the top level. +dnl +AC_DEFUN(AC_LBL_C_INIT_BEFORE_CC, +[ + AC_BEFORE([$0], [AC_LBL_C_INIT]) + AC_BEFORE([$0], [AC_PROG_CC]) + AC_BEFORE([$0], [AC_LBL_FIXINCLUDES]) + AC_BEFORE([$0], [AC_LBL_DEVEL]) + AC_ARG_WITH(gcc, [ --without-gcc don't use gcc]) + $1="" + if test "${srcdir}" != "." ; then + $1="-I\$(srcdir)" + fi + if test "${CFLAGS+set}" = set; then + LBL_CFLAGS="$CFLAGS" + fi + if test -z "$CC" ; then + case "$host_os" in + + bsdi*) + AC_CHECK_PROG(SHLICC2, shlicc2, yes, no) + if test $SHLICC2 = yes ; then + CC=shlicc2 + export CC + fi + ;; + esac + fi + if test -z "$CC" -a "$with_gcc" = no ; then + CC=cc + export CC + fi +]) + +dnl +dnl Determine which compiler we're using (cc or gcc) +dnl If using gcc, determine the version number +dnl If using cc: +dnl require that it support ansi prototypes +dnl use -O (AC_PROG_CC will use -g -O2 on gcc, so we don't need to +dnl do that ourselves for gcc) +dnl add -g flags, as appropriate +dnl explicitly specify /usr/local/include +dnl +dnl NOTE WELL: with newer versions of autoconf, "gcc" means any compiler +dnl that defines __GNUC__, which means clang, for example, counts as "gcc". +dnl +dnl usage: +dnl +dnl AC_LBL_C_INIT(copt, incls) +dnl +dnl results: +dnl +dnl $1 (copt set) +dnl $2 (incls set) +dnl CC +dnl LDFLAGS +dnl LBL_CFLAGS +dnl +AC_DEFUN(AC_LBL_C_INIT, +[ + AC_BEFORE([$0], [AC_LBL_FIXINCLUDES]) + AC_BEFORE([$0], [AC_LBL_DEVEL]) + AC_BEFORE([$0], [AC_LBL_SHLIBS_INIT]) + if test "$GCC" = yes ; then + # + # -Werror forces warnings to be errors. + # + ac_lbl_cc_force_warning_errors=-Werror + else + $2="$$2 -I/usr/local/include" + LDFLAGS="$LDFLAGS -L/usr/local/lib" + + case "$host_os" in + + darwin*) + # + # This is assumed either to be GCC or clang, both + # of which use -Werror to force warnings to be errors. + # + ac_lbl_cc_force_warning_errors=-Werror + ;; + + hpux*) + # + # HP C, which is what we presume we're using, doesn't + # exit with a non-zero exit status if we hand it an + # invalid -W flag, can't be forced to do so even with + # +We, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + ;; + + irix*) + # + # MIPS C, which is what we presume we're using, doesn't + # necessarily exit with a non-zero exit status if we + # hand it an invalid -W flag, can't be forced to do + # so, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + # + # It also, apparently, defaults to "char" being + # unsigned, unlike most other C implementations; + # I suppose we could say "signed char" whenever + # we want to guarantee a signed "char", but let's + # just force signed chars. + # + # -xansi is normally the default, but the + # configure script was setting it; perhaps -cckr + # was the default in the Old Days. (Then again, + # that would probably be for backwards compatibility + # in the days when ANSI C was Shiny and New, i.e. + # 1989 and the early '90's, so maybe we can just + # drop support for those compilers.) + # + # -g is equivalent to -g2, which turns off + # optimization; we choose -g3, which generates + # debugging information but doesn't turn off + # optimization (even if the optimization would + # cause inaccuracies in debugging). + # + $1="$$1 -xansi -signed -g3" + ;; + + osf*) + # + # Presumed to be DEC OSF/1, Digital UNIX, or + # Tru64 UNIX. + # + # The DEC C compiler, which is what we presume we're + # using, doesn't exit with a non-zero exit status if we + # hand it an invalid -W flag, can't be forced to do + # so, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + # + # -g is equivalent to -g2, which turns off + # optimization; we choose -g3, which generates + # debugging information but doesn't turn off + # optimization (even if the optimization would + # cause inaccuracies in debugging). + # + $1="$$1 -g3" + ;; + + solaris*) + # + # Assumed to be Sun C, which requires -errwarn to force + # warnings to be treated as errors. + # + ac_lbl_cc_force_warning_errors=-errwarn + ;; + + ultrix*) + AC_MSG_CHECKING(that Ultrix $CC hacks const in prototypes) + AC_CACHE_VAL(ac_cv_lbl_cc_const_proto, + AC_TRY_COMPILE( + [#include ], + [struct a { int b; }; + void c(const struct a *)], + ac_cv_lbl_cc_const_proto=yes, + ac_cv_lbl_cc_const_proto=no)) + AC_MSG_RESULT($ac_cv_lbl_cc_const_proto) + if test $ac_cv_lbl_cc_const_proto = no ; then + AC_DEFINE(const,[], + [to handle Ultrix compilers that don't support const in prototypes]) + fi + ;; + esac + $1="$$1 -O" + fi +]) + +dnl +dnl Check whether, if you pass an unknown warning option to the +dnl compiler, it fails or just prints a warning message and succeeds. +dnl Set ac_lbl_unknown_warning_option_error to the appropriate flag +dnl to force an error if it would otherwise just print a warning message +dnl and succeed. +dnl +AC_DEFUN(AC_LBL_CHECK_UNKNOWN_WARNING_OPTION_ERROR, + [ + AC_MSG_CHECKING([whether the compiler fails when given an unknown warning option]) + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wxyzzy-this-will-never-succeed-xyzzy" + AC_TRY_COMPILE( + [], + [return 0], + [ + AC_MSG_RESULT([no]) + # + # We're assuming this is clang, where + # -Werror=unknown-warning-option is the appropriate + # option to force the compiler to fail. + # + ac_lbl_unknown_warning_option_error="-Werror=unknown-warning-option" + ], + [ + AC_MSG_RESULT([yes]) + ]) + CFLAGS="$save_CFLAGS" + ]) + +dnl +dnl Check whether the compiler option specified as the second argument +dnl is supported by the compiler and, if so, add it to the macro +dnl specified as the first argument +dnl +AC_DEFUN(AC_LBL_CHECK_COMPILER_OPT, + [ + AC_MSG_CHECKING([whether the compiler supports the $2 option]) + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error $2" + AC_TRY_COMPILE( + [], + [return 0], + [ + AC_MSG_RESULT([yes]) + CFLAGS="$save_CFLAGS" + $1="$$1 $2" + ], + [ + AC_MSG_RESULT([no]) + CFLAGS="$save_CFLAGS" + ]) + ]) + +dnl +dnl Check whether the compiler supports an option to generate +dnl Makefile-style dependency lines +dnl +dnl GCC uses -M for this. Non-GCC compilers that support this +dnl use a variety of flags, including but not limited to -M. +dnl +dnl We test whether the flag in question is supported, as older +dnl versions of compilers might not support it. +dnl +dnl We don't try all the possible flags, just in case some flag means +dnl "generate dependencies" on one compiler but means something else +dnl on another compiler. +dnl +dnl Most compilers that support this send the output to the standard +dnl output by default. IBM's XLC, however, supports -M but sends +dnl the output to {sourcefile-basename}.u, and AIX has no /dev/stdout +dnl to work around that, so we don't bother with XLC. +dnl +AC_DEFUN(AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT, + [ + AC_MSG_CHECKING([whether the compiler supports generating dependencies]) + if test "$GCC" = yes ; then + # + # GCC, or a compiler deemed to be GCC by AC_PROG_CC (even + # though it's not); we assume that, in this case, the flag + # would be -M. + # + ac_lbl_dependency_flag="-M" + else + # + # Not GCC or a compiler deemed to be GCC; what platform is + # this? (We're assuming that if the compiler isn't GCC + # it's the compiler from the vendor of the OS; that won't + # necessarily be true for x86 platforms, where it might be + # the Intel C compiler.) + # + case "$host_os" in + + irix*|osf*|darwin*) + # + # MIPS C for IRIX, DEC C, and clang all use -M. + # + ac_lbl_dependency_flag="-M" + ;; + + solaris*) + # + # Sun C uses -xM. + # + ac_lbl_dependency_flag="-xM" + ;; + + hpux*) + # + # HP's older C compilers don't support this. + # HP's newer C compilers support this with + # either +M or +Make; the older compilers + # interpret +M as something completely + # different, so we use +Make so we don't + # think it works with the older compilers. + # + ac_lbl_dependency_flag="+Make" + ;; + + *) + # + # Not one of the above; assume no support for + # generating dependencies. + # + ac_lbl_dependency_flag="" + ;; + esac + fi + + # + # Is ac_lbl_dependency_flag defined and, if so, does the compiler + # complain about it? + # + # Note: clang doesn't seem to exit with an error status when handed + # an unknown non-warning error, even if you pass it + # -Werror=unknown-warning-option. However, it always supports + # -M, so the fact that this test always succeeds with clang + # isn't an issue. + # + if test ! -z "$ac_lbl_dependency_flag"; then + AC_LANG_CONFTEST( + [AC_LANG_SOURCE([[int main(void) { return 0; }]])]) + echo "$CC" $ac_lbl_dependency_flag conftest.c >&5 + if "$CC" $ac_lbl_dependency_flag conftest.c >/dev/null 2>&1; then + AC_MSG_RESULT([yes, with $ac_lbl_dependency_flag]) + DEPENDENCY_CFLAG="$ac_lbl_dependency_flag" + MKDEP='${srcdir}/mkdep' + else + AC_MSG_RESULT([no]) + # + # We can't run mkdep, so have "make depend" do + # nothing. + # + MKDEP=: + fi + rm -rf conftest* + else + AC_MSG_RESULT([no]) + # + # We can't run mkdep, so have "make depend" do + # nothing. + # + MKDEP=: + fi + AC_SUBST(DEPENDENCY_CFLAG) + AC_SUBST(MKDEP) + ]) + +dnl +dnl Determine what options are needed to build a shared library +dnl +dnl usage: +dnl +dnl AC_LBL_SHLIBS_INIT +dnl +dnl results: +dnl +dnl V_CCOPT (modified to build position-independent code) +dnl V_SHLIB_CMD +dnl V_SHLIB_OPT +dnl V_SONAME_OPT +dnl V_RPATH_OPT +dnl +AC_DEFUN(AC_LBL_SHLIBS_INIT, + [AC_PREREQ(2.50) + if test "$GCC" = yes ; then + # + # On platforms where we build a shared library: + # + # add options to generate position-independent code, + # if necessary (it's the default in AIX and Darwin/OS X); + # + # define option to set the soname of the shared library, + # if the OS supports that; + # + # add options to specify, at link time, a directory to + # add to the run-time search path, if that's necessary. + # + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + case "$host_os" in + + aix*) + ;; + + freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*) + # + # Platforms where the linker is the GNU linker + # or accepts command-line arguments like + # those the GNU linker accepts. + # + # Some instruction sets require -fPIC on some + # operating systems. Check for them. If you + # have a combination that requires it, add it + # here. + # + PIC_OPT=-fpic + case "$host_cpu" in + + sparc64*) + case "$host_os" in + + freebsd*|openbsd*) + PIC_OPT=-fPIC + ;; + esac + ;; + esac + V_CCOPT="$V_CCOPT $PIC_OPT" + V_SONAME_OPT="-Wl,-soname," + V_RPATH_OPT="-Wl,-rpath," + ;; + + hpux*) + V_CCOPT="$V_CCOPT -fpic" + # + # XXX - this assumes GCC is using the HP linker, + # rather than the GNU linker, and that the "+h" + # option is used on all HP-UX platforms, both .sl + # and .so. + # + V_SONAME_OPT="-Wl,+h," + # + # By default, directories specifed with -L + # are added to the run-time search path, so + # we don't add them in pcap-config. + # + ;; + + solaris*) + V_CCOPT="$V_CCOPT -fpic" + # + # XXX - this assumes GCC is using the Sun linker, + # rather than the GNU linker. + # + V_SONAME_OPT="-Wl,-h," + V_RPATH_OPT="-Wl,-R," + ;; + esac + else + # + # Set the appropriate compiler flags and, on platforms + # where we build a shared library: + # + # add options to generate position-independent code, + # if necessary (it's the default in Darwin/OS X); + # + # if we generate ".so" shared libraries, define the + # appropriate options for building the shared library; + # + # add options to specify, at link time, a directory to + # add to the run-time search path, if that's necessary. + # + # Note: spaces after V_SONAME_OPT are significant; on + # some platforms the soname is passed with a GCC-like + # "-Wl,-soname,{soname}" option, with the soname part + # of the option, while on other platforms the C compiler + # driver takes it as a regular option with the soname + # following the option. The same applies to V_RPATH_OPT. + # + case "$host_os" in + + aix*) + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-G -bnoentry -bexpall" + ;; + + freebsd*|netbsd*|openbsd*|dragonfly*|linux*) + # + # "cc" is GCC. + # + V_CCOPT="$V_CCOPT -fpic" + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + V_SONAME_OPT="-Wl,-soname," + V_RPATH_OPT="-Wl,-rpath," + ;; + + hpux*) + V_CCOPT="$V_CCOPT +z" + V_SHLIB_CMD="\$(LD)" + V_SHLIB_OPT="-b" + V_SONAME_OPT="+h " + # + # By default, directories specifed with -L + # are added to the run-time search path, so + # we don't add them in pcap-config. + # + ;; + + osf*) + # + # Presumed to be DEC OSF/1, Digital UNIX, or + # Tru64 UNIX. + # + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + V_SONAME_OPT="-soname " + V_RPATH_OPT="-rpath " + ;; + + solaris*) + V_CCOPT="$V_CCOPT -Kpic" + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-G" + V_SONAME_OPT="-h " + V_RPATH_OPT="-R" + ;; + esac + fi +]) + +# +# Try compiling a sample of the type of code that appears in +# gencode.c with "inline", "__inline__", and "__inline". +# +# Autoconf's AC_C_INLINE, at least in autoconf 2.13, isn't good enough, +# as it just tests whether a function returning "int" can be inlined; +# at least some versions of HP's C compiler can inline that, but can't +# inline a function that returns a struct pointer. +# +# Make sure we use the V_CCOPT flags, because some of those might +# disable inlining. +# +AC_DEFUN(AC_LBL_C_INLINE, + [AC_MSG_CHECKING(for inline) + save_CFLAGS="$CFLAGS" + CFLAGS="$V_CCOPT" + AC_CACHE_VAL(ac_cv_lbl_inline, [ + ac_cv_lbl_inline="" + ac_lbl_cc_inline=no + for ac_lbl_inline in inline __inline__ __inline + do + AC_TRY_COMPILE( + [#define inline $ac_lbl_inline + static inline struct iltest *foo(void); + struct iltest { + int iltest1; + int iltest2; + }; + + static inline struct iltest * + foo() + { + static struct iltest xxx; + + return &xxx; + }],,ac_lbl_cc_inline=yes,) + if test "$ac_lbl_cc_inline" = yes ; then + break; + fi + done + if test "$ac_lbl_cc_inline" = yes ; then + ac_cv_lbl_inline=$ac_lbl_inline + fi]) + CFLAGS="$save_CFLAGS" + if test ! -z "$ac_cv_lbl_inline" ; then + AC_MSG_RESULT($ac_cv_lbl_inline) + else + AC_MSG_RESULT(no) + fi + AC_DEFINE_UNQUOTED(inline, $ac_cv_lbl_inline, [Define as token for inline if inlining supported])]) + +dnl +dnl If using gcc, make sure we have ANSI ioctl definitions +dnl +dnl usage: +dnl +dnl AC_LBL_FIXINCLUDES +dnl +AC_DEFUN(AC_LBL_FIXINCLUDES, + [if test "$GCC" = yes ; then + AC_MSG_CHECKING(for ANSI ioctl definitions) + AC_CACHE_VAL(ac_cv_lbl_gcc_fixincludes, + AC_TRY_COMPILE( + [/* + * This generates a "duplicate case value" when fixincludes + * has not be run. + */ +# include +# include +# include +# ifdef HAVE_SYS_IOCCOM_H +# include +# endif], + [switch (0) { + case _IO('A', 1):; + case _IO('B', 1):; + }], + ac_cv_lbl_gcc_fixincludes=yes, + ac_cv_lbl_gcc_fixincludes=no)) + AC_MSG_RESULT($ac_cv_lbl_gcc_fixincludes) + if test $ac_cv_lbl_gcc_fixincludes = no ; then + # Don't cache failure + unset ac_cv_lbl_gcc_fixincludes + AC_MSG_ERROR(see the INSTALL for more info) + fi + fi]) + +dnl +dnl Check for flex, default to lex +dnl Require flex 2.4 or higher +dnl Check for bison, default to yacc +dnl Default to lex/yacc if both flex and bison are not available +dnl +dnl If we're using flex and bison, pass -P to flex and -p to bison +dnl to define a prefix string for the lexer and parser +dnl +dnl If we're not using flex and bison, don't pass those options +dnl (as they might not work - although if "lex" is a wrapper for +dnl Flex and "yacc" is a wrapper for Bison, they will work), and +dnl define NEED_YYPARSE_WRAPPER (we *CANNOT* use YYBISON to check +dnl whether the wrapper is needed, as some people apparently, for +dnl some unknown reason, choose to use --without-flex and +dnl --without-bison on systems that have Flex and Bison, which +dnl means that the "yacc" they end up using is a wrapper that +dnl runs "bison -y", and at least some versions of Bison define +dnl YYBISON even if run with "-y", so we end up not compiling +dnl the yyparse wrapper and end up with a libpcap that doesn't +dnl define pcap_parse()) +dnl +dnl usage: +dnl +dnl AC_LBL_LEX_AND_YACC(lex, yacc, yyprefix) +dnl +dnl results: +dnl +dnl $1 (lex set) +dnl $2 (yacc appended) +dnl $3 (optional flex and bison -P prefix) +dnl +AC_DEFUN(AC_LBL_LEX_AND_YACC, + [AC_ARG_WITH(flex, [ --without-flex don't use flex]) + AC_ARG_WITH(bison, [ --without-bison don't use bison]) + if test "$with_flex" = no ; then + $1=lex + else + AC_CHECK_PROGS($1, flex, lex) + fi + if test "$$1" = flex ; then + # The -V flag was added in 2.4 + AC_MSG_CHECKING(for flex 2.4 or higher) + AC_CACHE_VAL(ac_cv_lbl_flex_v24, + if flex -V >/dev/null 2>&1; then + ac_cv_lbl_flex_v24=yes + else + ac_cv_lbl_flex_v24=no + fi) + AC_MSG_RESULT($ac_cv_lbl_flex_v24) + if test $ac_cv_lbl_flex_v24 = no ; then + s="2.4 or higher required" + AC_MSG_WARN(ignoring obsolete flex executable ($s)) + $1=lex + fi + fi + if test "$with_bison" = no ; then + $2=yacc + else + AC_CHECK_PROGS($2, bison, yacc) + fi + if test "$$2" = bison ; then + $2="$$2 -y" + fi + if test "$$1" != lex -a "$$2" = yacc -o "$$1" = lex -a "$$2" != yacc ; then + AC_MSG_WARN(don't have both flex and bison; reverting to lex/yacc) + $1=lex + $2=yacc + fi + if test "$$1" = flex -a -n "$3" ; then + $1="$$1 -P$3" + $2="$$2 -p $3" + else + AC_DEFINE(NEED_YYPARSE_WRAPPER,1,[if we need a pcap_parse wrapper around yyparse]) + fi]) + +dnl +dnl Checks to see if union wait is used with WEXITSTATUS() +dnl +dnl usage: +dnl +dnl AC_LBL_UNION_WAIT +dnl +dnl results: +dnl +dnl DECLWAITSTATUS (defined) +dnl +AC_DEFUN(AC_LBL_UNION_WAIT, + [AC_MSG_CHECKING(if union wait is used) + AC_CACHE_VAL(ac_cv_lbl_union_wait, + AC_TRY_COMPILE([ +# include +# include ], + [int status; + u_int i = WEXITSTATUS(status); + u_int j = waitpid(0, &status, 0);], + ac_cv_lbl_union_wait=no, + ac_cv_lbl_union_wait=yes)) + AC_MSG_RESULT($ac_cv_lbl_union_wait) + if test $ac_cv_lbl_union_wait = yes ; then + AC_DEFINE(DECLWAITSTATUS,union wait,[type for wait]) + else + AC_DEFINE(DECLWAITSTATUS,int,[type for wait]) + fi]) + +dnl +dnl Checks to see if the sockaddr struct has the 4.4 BSD sa_len member +dnl +dnl usage: +dnl +dnl AC_LBL_SOCKADDR_SA_LEN +dnl +dnl results: +dnl +dnl HAVE_SOCKADDR_SA_LEN (defined) +dnl +AC_DEFUN(AC_LBL_SOCKADDR_SA_LEN, + [AC_MSG_CHECKING(if sockaddr struct has the sa_len member) + AC_CACHE_VAL(ac_cv_lbl_sockaddr_has_sa_len, + AC_TRY_COMPILE([ +# include +# include ], + [u_int i = sizeof(((struct sockaddr *)0)->sa_len)], + ac_cv_lbl_sockaddr_has_sa_len=yes, + ac_cv_lbl_sockaddr_has_sa_len=no)) + AC_MSG_RESULT($ac_cv_lbl_sockaddr_has_sa_len) + if test $ac_cv_lbl_sockaddr_has_sa_len = yes ; then + AC_DEFINE(HAVE_SOCKADDR_SA_LEN,1,[if struct sockaddr has the sa_len member]) + fi]) + +dnl +dnl Checks to see if there's a sockaddr_storage structure +dnl +dnl usage: +dnl +dnl AC_LBL_SOCKADDR_STORAGE +dnl +dnl results: +dnl +dnl HAVE_SOCKADDR_STORAGE (defined) +dnl +AC_DEFUN(AC_LBL_SOCKADDR_STORAGE, + [AC_MSG_CHECKING(if sockaddr_storage struct exists) + AC_CACHE_VAL(ac_cv_lbl_has_sockaddr_storage, + AC_TRY_COMPILE([ +# include +# include ], + [u_int i = sizeof (struct sockaddr_storage)], + ac_cv_lbl_has_sockaddr_storage=yes, + ac_cv_lbl_has_sockaddr_storage=no)) + AC_MSG_RESULT($ac_cv_lbl_has_sockaddr_storage) + if test $ac_cv_lbl_has_sockaddr_storage = yes ; then + AC_DEFINE(HAVE_SOCKADDR_STORAGE,1,[if struct sockaddr_storage exists]) + fi]) + +dnl +dnl Checks to see if the dl_hp_ppa_info_t struct has the HP-UX 11.00 +dnl dl_module_id_1 member +dnl +dnl usage: +dnl +dnl AC_LBL_HP_PPA_INFO_T_DL_MODULE_ID_1 +dnl +dnl results: +dnl +dnl HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 (defined) +dnl +dnl NOTE: any compile failure means we conclude that it doesn't have +dnl that member, so if we don't have DLPI, don't have a +dnl header, or have one that doesn't declare a dl_hp_ppa_info_t type, +dnl we conclude it doesn't have that member (which is OK, as either we +dnl won't be using code that would use that member, or we wouldn't +dnl compile in any case). +dnl +AC_DEFUN(AC_LBL_HP_PPA_INFO_T_DL_MODULE_ID_1, + [AC_MSG_CHECKING(if dl_hp_ppa_info_t struct has dl_module_id_1 member) + AC_CACHE_VAL(ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1, + AC_TRY_COMPILE([ +# include +# include +# include ], + [u_int i = sizeof(((dl_hp_ppa_info_t *)0)->dl_module_id_1)], + ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1=yes, + ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1=no)) + AC_MSG_RESULT($ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1) + if test $ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1 = yes ; then + AC_DEFINE(HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1,1,[if ppa_info_t_dl_module_id exists]) + fi]) + +dnl +dnl Checks to see if -R is used +dnl +dnl usage: +dnl +dnl AC_LBL_HAVE_RUN_PATH +dnl +dnl results: +dnl +dnl ac_cv_lbl_have_run_path (yes or no) +dnl +AC_DEFUN(AC_LBL_HAVE_RUN_PATH, + [AC_MSG_CHECKING(for ${CC-cc} -R) + AC_CACHE_VAL(ac_cv_lbl_have_run_path, + [echo 'main(){}' > conftest.c + ${CC-cc} -o conftest conftest.c -R/a1/b2/c3 >conftest.out 2>&1 + if test ! -s conftest.out ; then + ac_cv_lbl_have_run_path=yes + else + ac_cv_lbl_have_run_path=no + fi + rm -f -r conftest*]) + AC_MSG_RESULT($ac_cv_lbl_have_run_path) + ]) + +dnl +dnl Checks to see if unaligned memory accesses fail +dnl +dnl usage: +dnl +dnl AC_LBL_UNALIGNED_ACCESS +dnl +dnl results: +dnl +dnl LBL_ALIGN (DEFINED) +dnl +AC_DEFUN(AC_LBL_UNALIGNED_ACCESS, + [AC_MSG_CHECKING(if unaligned accesses fail) + AC_CACHE_VAL(ac_cv_lbl_unaligned_fail, + [case "$host_cpu" in + + # + # These are CPU types where: + # + # the CPU faults on an unaligned access, but at least some + # OSes that support that CPU catch the fault and simulate + # the unaligned access (e.g., Alpha/{Digital,Tru64} UNIX) - + # the simulation is slow, so we don't want to use it; + # + # the CPU, I infer (from the old + # + # XXX: should also check that they don't do weird things (like on arm) + # + # comment) doesn't fault on unaligned accesses, but doesn't + # do a normal unaligned fetch, either (e.g., presumably, ARM); + # + # for whatever reason, the test program doesn't work + # (this has been claimed to be the case for several of those + # CPUs - I don't know what the problem is; the problem + # was reported as "the test program dumps core" for SuperH, + # but that's what the test program is *supposed* to do - + # it dumps core before it writes anything, so the test + # for an empty output file should find an empty output + # file and conclude that unaligned accesses don't work). + # + # This run-time test won't work if you're cross-compiling, so + # in order to support cross-compiling for a particular CPU, + # we have to wire in the list of CPU types anyway, as far as + # I know, so perhaps we should just have a set of CPUs on + # which we know it doesn't work, a set of CPUs on which we + # know it does work, and have the script just fail on other + # cpu types and update it when such a failure occurs. + # + alpha*|arm*|bfin*|hp*|mips*|sh*|sparc*|ia64|nv1) + ac_cv_lbl_unaligned_fail=yes + ;; + + *) + cat >conftest.c < +# include +# include + unsigned char a[[5]] = { 1, 2, 3, 4, 5 }; + main() { + unsigned int i; + pid_t pid; + int status; + /* avoid "core dumped" message */ + pid = fork(); + if (pid < 0) + exit(2); + if (pid > 0) { + /* parent */ + pid = waitpid(pid, &status, 0); + if (pid < 0) + exit(3); + exit(!WIFEXITED(status)); + } + /* child */ + i = *(unsigned int *)&a[[1]]; + printf("%d\n", i); + exit(0); + } +EOF + ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \ + conftest.c $LIBS >/dev/null 2>&1 + if test ! -x conftest ; then + dnl failed to compile for some reason + ac_cv_lbl_unaligned_fail=yes + else + ./conftest >conftest.out + if test ! -s conftest.out ; then + ac_cv_lbl_unaligned_fail=yes + else + ac_cv_lbl_unaligned_fail=no + fi + fi + rm -f -r conftest* core core.conftest + ;; + esac]) + AC_MSG_RESULT($ac_cv_lbl_unaligned_fail) + if test $ac_cv_lbl_unaligned_fail = yes ; then + AC_DEFINE(LBL_ALIGN,1,[if unaligned access fails]) + fi]) + +dnl +dnl If the file .devel exists: +dnl Add some warning flags if the compiler supports them +dnl If an os prototype include exists, symlink os-proto.h to it +dnl +dnl usage: +dnl +dnl AC_LBL_DEVEL(copt) +dnl +dnl results: +dnl +dnl $1 (copt appended) +dnl HAVE_OS_PROTO_H (defined) +dnl os-proto.h (symlinked) +dnl +AC_DEFUN(AC_LBL_DEVEL, + [rm -f os-proto.h + if test "${LBL_CFLAGS+set}" = set; then + $1="$$1 ${LBL_CFLAGS}" + fi + if test -f .devel ; then + # + # Skip all the warning option stuff on some compilers. + # + if test "$ac_lbl_cc_dont_try_gcc_dashW" != yes; then + AC_LBL_CHECK_UNKNOWN_WARNING_OPTION_ERROR() + AC_LBL_CHECK_COMPILER_OPT($1, -Wall) + AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-prototypes) + AC_LBL_CHECK_COMPILER_OPT($1, -Wstrict-prototypes) + fi + AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT() + # + # We used to set -n32 for IRIX 6 when not using GCC (presumed + # to mean that we're using MIPS C or MIPSpro C); it specified + # the "new" faster 32-bit ABI, introduced in IRIX 6.2. I'm + # not sure why that would be something to do *only* with a + # .devel file; why should the ABI for which we produce code + # depend on .devel? + # + os=`echo $host_os | sed -e 's/\([[0-9]][[0-9]]*\)[[^0-9]].*$/\1/'` + name="lbl/os-$os.h" + if test -f $name ; then + ln -s $name os-proto.h + AC_DEFINE(HAVE_OS_PROTO_H, 1, + [if there's an os_proto.h for this platform, to use additional prototypes]) + else + AC_MSG_WARN(can't find $name) + fi + fi]) + +dnl +dnl Improved version of AC_CHECK_LIB +dnl +dnl Thanks to John Hawkinson (jhawk@mit.edu) +dnl +dnl usage: +dnl +dnl AC_LBL_CHECK_LIB(LIBRARY, FUNCTION [, ACTION-IF-FOUND [, +dnl ACTION-IF-NOT-FOUND [, OTHER-LIBRARIES]]]) +dnl +dnl results: +dnl +dnl LIBS +dnl +dnl XXX - "AC_LBL_LIBRARY_NET" was redone to use "AC_SEARCH_LIBS" +dnl rather than "AC_LBL_CHECK_LIB", so this isn't used any more. +dnl We keep it around for reference purposes in case it's ever +dnl useful in the future. +dnl + +define(AC_LBL_CHECK_LIB, +[AC_MSG_CHECKING([for $2 in -l$1]) +dnl Use a cache variable name containing the library, function +dnl name, and extra libraries to link with, because the test really is +dnl for library $1 defining function $2, when linked with potinal +dnl library $5, not just for library $1. Separate tests with the same +dnl $1 and different $2's or $5's may have different results. +ac_lib_var=`echo $1['_']$2['_']$5 | sed 'y%./+- %__p__%'` +AC_CACHE_VAL(ac_cv_lbl_lib_$ac_lib_var, +[ac_save_LIBS="$LIBS" +LIBS="-l$1 $5 $LIBS" +AC_TRY_LINK(dnl +ifelse([$2], [main], , dnl Avoid conflicting decl of main. +[/* Override any gcc2 internal prototype to avoid an error. */ +]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus +extern "C" +#endif +])dnl +[/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $2(); +]), + [$2()], + eval "ac_cv_lbl_lib_$ac_lib_var=yes", + eval "ac_cv_lbl_lib_$ac_lib_var=no") +LIBS="$ac_save_LIBS" +])dnl +if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$3], , +[changequote(, )dnl + ac_tr_lib=HAVE_LIB`echo $1 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_lib) + LIBS="-l$1 $LIBS" +], [$3]) +else + AC_MSG_RESULT(no) +ifelse([$4], , , [$4 +])dnl +fi +]) + +dnl +dnl AC_LBL_LIBRARY_NET +dnl +dnl This test is for network applications that need socket() and +dnl gethostbyname() -ish functions. Under Solaris, those applications +dnl need to link with "-lsocket -lnsl". Under IRIX, they need to link +dnl with "-lnsl" but should *not* link with "-lsocket" because +dnl libsocket.a breaks a number of things (for instance: +dnl gethostbyname() under IRIX 5.2, and snoop sockets under most +dnl versions of IRIX). +dnl +dnl Unfortunately, many application developers are not aware of this, +dnl and mistakenly write tests that cause -lsocket to be used under +dnl IRIX. It is also easy to write tests that cause -lnsl to be used +dnl under operating systems where neither are necessary (or useful), +dnl such as SunOS 4.1.4, which uses -lnsl for TLI. +dnl +dnl This test exists so that every application developer does not test +dnl this in a different, and subtly broken fashion. + +dnl It has been argued that this test should be broken up into two +dnl seperate tests, one for the resolver libraries, and one for the +dnl libraries necessary for using Sockets API. Unfortunately, the two +dnl are carefully intertwined and allowing the autoconf user to use +dnl them independantly potentially results in unfortunate ordering +dnl dependancies -- as such, such component macros would have to +dnl carefully use indirection and be aware if the other components were +dnl executed. Since other autoconf macros do not go to this trouble, +dnl and almost no applications use sockets without the resolver, this +dnl complexity has not been implemented. +dnl +dnl The check for libresolv is in case you are attempting to link +dnl statically and happen to have a libresolv.a lying around (and no +dnl libnsl.a). +dnl +AC_DEFUN(AC_LBL_LIBRARY_NET, [ + # Most operating systems have gethostbyname() in the default searched + # libraries (i.e. libc): + # Some OSes (eg. Solaris) place it in libnsl + # Some strange OSes (SINIX) have it in libsocket: + AC_SEARCH_LIBS(gethostbyname, nsl socket resolv) + # Unfortunately libsocket sometimes depends on libnsl and + # AC_SEARCH_LIBS isn't up to the task of handling dependencies like this. + if test "$ac_cv_search_gethostbyname" = "no" + then + AC_CHECK_LIB(socket, gethostbyname, + LIBS="-lsocket -lnsl $LIBS", , -lnsl) + fi + AC_SEARCH_LIBS(socket, socket, , + AC_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", , -lnsl)) + # DLPI needs putmsg under HPUX so test for -lstr while we're at it + AC_SEARCH_LIBS(putmsg, str) + ]) + +dnl +dnl Test for __attribute__ +dnl + +AC_DEFUN(AC_C___ATTRIBUTE__, [ +AC_MSG_CHECKING(for __attribute__) +AC_CACHE_VAL(ac_cv___attribute__, [ +AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ +#include + +static void foo(void) __attribute__ ((noreturn)); + +static void +foo(void) +{ + exit(1); +} + +int +main(int argc, char **argv) +{ + foo(); +} + ]])], +ac_cv___attribute__=yes, +ac_cv___attribute__=no)]) +if test "$ac_cv___attribute__" = "yes"; then + AC_DEFINE(HAVE___ATTRIBUTE__, 1, [define if your compiler has __attribute__]) +else + # + # We can't use __attribute__, so we can't use __attribute__((unused)), + # so we define _U_ to an empty string. + # + V_DEFS="$V_DEFS -D_U_=\"\"" +fi +AC_MSG_RESULT($ac_cv___attribute__) +]) + +dnl +dnl Test whether __attribute__((unused)) can be used without warnings +dnl + +AC_DEFUN(AC_C___ATTRIBUTE___UNUSED, [ +AC_MSG_CHECKING([whether __attribute__((unused)) can be used without warnings]) +AC_CACHE_VAL(ac_cv___attribute___unused, [ +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" +AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ +#include +#include + +int +main(int argc __attribute((unused)), char **argv __attribute((unused))) +{ + printf("Hello, world!\n"); + return 0; +} + ]])], +ac_cv___attribute___unused=yes, +ac_cv___attribute___unused=no)]) +CFLAGS="$save_CFLAGS" +if test "$ac_cv___attribute___unused" = "yes"; then + V_DEFS="$V_DEFS -D_U_=\"__attribute__((unused))\"" +else + V_DEFS="$V_DEFS -D_U_=\"\"" +fi +AC_MSG_RESULT($ac_cv___attribute___unused) +]) + +dnl +dnl Test whether __attribute__((format)) can be used without warnings +dnl + +AC_DEFUN(AC_C___ATTRIBUTE___FORMAT, [ +AC_MSG_CHECKING([whether __attribute__((format)) can be used without warnings]) +AC_CACHE_VAL(ac_cv___attribute___format, [ +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" +AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ +#include + +extern int foo(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +int +main(int argc, char **argv) +{ + foo("%s", "test"); +} + ]])], +ac_cv___attribute___format=yes, +ac_cv___attribute___format=no)]) +CFLAGS="$save_CFLAGS" +if test "$ac_cv___attribute___format" = "yes"; then + AC_DEFINE(__ATTRIBUTE___FORMAT_OK, 1, + [define if your compiler allows __attribute__((format)) without a warning]) +fi +AC_MSG_RESULT($ac_cv___attribute___format) +]) + +dnl +dnl Checks to see if tpacket_stats is defined in linux/if_packet.h +dnl If so then pcap-linux.c can use this to report proper statistics. +dnl +dnl -Scott Barron +dnl +AC_DEFUN(AC_LBL_TPACKET_STATS, + [AC_MSG_CHECKING(if if_packet.h has tpacket_stats defined) + AC_CACHE_VAL(ac_cv_lbl_tpacket_stats, + AC_TRY_COMPILE([ +# include ], + [struct tpacket_stats stats], + ac_cv_lbl_tpacket_stats=yes, + ac_cv_lbl_tpacket_stats=no)) + AC_MSG_RESULT($ac_cv_lbl_tpacket_stats) + if test $ac_cv_lbl_tpacket_stats = yes; then + AC_DEFINE(HAVE_TPACKET_STATS,1,[if if_packet.h has tpacket_stats defined]) + fi]) + +dnl +dnl Checks to see if the tpacket_auxdata struct has a tp_vlan_tci member. +dnl +dnl usage: +dnl +dnl AC_LBL_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI +dnl +dnl results: +dnl +dnl HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI (defined) +dnl +dnl NOTE: any compile failure means we conclude that it doesn't have +dnl that member, so if we don't have tpacket_auxdata, we conclude it +dnl doesn't have that member (which is OK, as either we won't be using +dnl code that would use that member, or we wouldn't compile in any case). +dnl +AC_DEFUN(AC_LBL_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI, + [AC_MSG_CHECKING(if tpacket_auxdata struct has tp_vlan_tci member) + AC_CACHE_VAL(ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci, + AC_TRY_COMPILE([ +# include +# include ], + [u_int i = sizeof(((struct tpacket_auxdata *)0)->tp_vlan_tci)], + ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci=yes, + ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci=no)) + AC_MSG_RESULT($ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci) + if test $ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci = yes ; then + HAVE_LINUX_TPACKET_AUXDATA=tp_vlan_tci + AC_SUBST(HAVE_LINUX_TPACKET_AUXDATA) + AC_DEFINE(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI,1,[if tp_vlan_tci exists]) + fi]) + +dnl +dnl Checks to see if Solaris has the dl_passive_req_t struct defined +dnl in . +dnl +dnl usage: +dnl +dnl AC_LBL_DL_PASSIVE_REQ_T +dnl +dnl results: +dnl +dnl HAVE_DLPI_PASSIVE (defined) +dnl +AC_DEFUN(AC_LBL_DL_PASSIVE_REQ_T, + [AC_MSG_CHECKING(if dl_passive_req_t struct exists) + AC_CACHE_VAL(ac_cv_lbl_has_dl_passive_req_t, + AC_TRY_COMPILE([ +# include +# include ], + [u_int i = sizeof(dl_passive_req_t)], + ac_cv_lbl_has_dl_passive_req_t=yes, + ac_cv_lbl_has_dl_passive_req_t=no)) + AC_MSG_RESULT($ac_cv_lbl_has_dl_passive_req_t) + if test $ac_cv_lbl_has_dl_passive_req_t = yes ; then + AC_DEFINE(HAVE_DLPI_PASSIVE,1,[if passive_req_t primitive + exists]) + fi]) diff --git a/tcpdump/jni/libpcap/arcnet.h b/tcpdump/jni/libpcap/arcnet.h new file mode 100644 index 0000000..5869098 --- /dev/null +++ b/tcpdump/jni/libpcap/arcnet.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp + */ + +/* RFC 1051 */ +#define ARCTYPE_IP_OLD 240 /* IP protocol */ +#define ARCTYPE_ARP_OLD 241 /* address resolution protocol */ + +/* RFC 1201 */ +#define ARCTYPE_IP 212 /* IP protocol */ +#define ARCTYPE_ARP 213 /* address resolution protocol */ +#define ARCTYPE_REVARP 214 /* reverse addr resolution protocol */ + +#define ARCTYPE_ATALK 221 /* Appletalk */ +#define ARCTYPE_BANIAN 247 /* Banyan Vines */ +#define ARCTYPE_IPX 250 /* Novell IPX */ + +#define ARCTYPE_INET6 0xc4 /* IPng */ +#define ARCTYPE_DIAGNOSE 0x80 /* as per ANSI/ATA 878.1 */ diff --git a/tcpdump/jni/libpcap/atmuni31.h b/tcpdump/jni/libpcap/atmuni31.h new file mode 100644 index 0000000..0f85430 --- /dev/null +++ b/tcpdump/jni/libpcap/atmuni31.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1997 Yen Yen Lim and North Dakota State University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Yen Yen Lim and + North Dakota State University + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Based on UNI3.1 standard by ATM Forum */ + +/* ATM traffic types based on VPI=0 and (the following VCI */ +#define VCI_PPC 0x05 /* Point-to-point signal msg */ +#define VCI_BCC 0x02 /* Broadcast signal msg */ +#define VCI_OAMF4SC 0x03 /* Segment OAM F4 flow cell */ +#define VCI_OAMF4EC 0x04 /* End-to-end OAM F4 flow cell */ +#define VCI_METAC 0x01 /* Meta signal msg */ +#define VCI_ILMIC 0x10 /* ILMI msg */ + +/* Q.2931 signalling messages */ +#define CALL_PROCEED 0x02 /* call proceeding */ +#define CONNECT 0x07 /* connect */ +#define CONNECT_ACK 0x0f /* connect_ack */ +#define SETUP 0x05 /* setup */ +#define RELEASE 0x4d /* release */ +#define RELEASE_DONE 0x5a /* release_done */ +#define RESTART 0x46 /* restart */ +#define RESTART_ACK 0x4e /* restart ack */ +#define STATUS 0x7d /* status */ +#define STATUS_ENQ 0x75 /* status ack */ +#define ADD_PARTY 0x80 /* add party */ +#define ADD_PARTY_ACK 0x81 /* add party ack */ +#define ADD_PARTY_REJ 0x82 /* add party rej */ +#define DROP_PARTY 0x83 /* drop party */ +#define DROP_PARTY_ACK 0x84 /* drop party ack */ + +/* Information Element Parameters in the signalling messages */ +#define CAUSE 0x08 /* cause */ +#define ENDPT_REF 0x54 /* endpoint reference */ +#define AAL_PARA 0x58 /* ATM adaptation layer parameters */ +#define TRAFF_DESCRIP 0x59 /* atm traffic descriptors */ +#define CONNECT_ID 0x5a /* connection identifier */ +#define QOS_PARA 0x5c /* quality of service parameters */ +#define B_HIGHER 0x5d /* broadband higher layer information */ +#define B_BEARER 0x5e /* broadband bearer capability */ +#define B_LOWER 0x5f /* broadband lower information */ +#define CALLING_PARTY 0x6c /* calling party number */ +#define CALLED_PARTY 0x70 /* called party nmber */ + +#define Q2931 0x09 + +/* Q.2931 signalling general messages format */ +#define PROTO_POS 0 /* offset of protocol discriminator */ +#define CALL_REF_POS 2 /* offset of call reference value */ +#define MSG_TYPE_POS 5 /* offset of message type */ +#define MSG_LEN_POS 7 /* offset of mesage length */ +#define IE_BEGIN_POS 9 /* offset of first information element */ + +/* format of signalling messages */ +#define TYPE_POS 0 +#define LEN_POS 2 +#define FIELD_BEGIN_POS 4 diff --git a/tcpdump/jni/libpcap/bpf/net/bpf_filter.c b/tcpdump/jni/libpcap/bpf/net/bpf_filter.c new file mode 100644 index 0000000..ffe04ce --- /dev/null +++ b/tcpdump/jni/libpcap/bpf/net/bpf_filter.c @@ -0,0 +1,759 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bpf.c 7.5 (Berkeley) 7/15/91 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 + +#include + +#else /* WIN32 */ + +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif + +#include +#include +#include + +#define SOLARIS (defined(sun) && (defined(__SVR4) || defined(__svr4__))) +#if defined(__hpux) || SOLARIS +# include +# include +# define mbuf msgb +# define m_next b_cont +# define MLEN(m) ((m)->b_wptr - (m)->b_rptr) +# define mtod(m,t) ((t)(m)->b_rptr) +#else /* defined(__hpux) || SOLARIS */ +# define MLEN(m) ((m)->m_len) +#endif /* defined(__hpux) || SOLARIS */ + +#endif /* WIN32 */ + +#include + +#if !defined(KERNEL) && !defined(_KERNEL) +#include +#endif + +#define int32 bpf_int32 +#define u_int32 bpf_u_int32 + +#ifndef LBL_ALIGN +/* + * XXX - IA-64? If not, this probably won't work on Win64 IA-64 + * systems, unless LBL_ALIGN is defined elsewhere for them. + * XXX - SuperH? If not, this probably won't work on WinCE SuperH + * systems, unless LBL_ALIGN is defined elsewhere for them. + */ +#if defined(sparc) || defined(__sparc__) || defined(mips) || \ + defined(ibm032) || defined(__alpha) || defined(__hpux) || \ + defined(__arm__) +#define LBL_ALIGN +#endif +#endif + +#ifndef LBL_ALIGN +#ifndef WIN32 +#include +#endif + +#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p)) +#define EXTRACT_LONG(p) (ntohl(*(u_int32 *)p)) +#else +#define EXTRACT_SHORT(p)\ + ((u_short)\ + ((u_short)*((u_char *)p+0)<<8|\ + (u_short)*((u_char *)p+1)<<0)) +#define EXTRACT_LONG(p)\ + ((u_int32)*((u_char *)p+0)<<24|\ + (u_int32)*((u_char *)p+1)<<16|\ + (u_int32)*((u_char *)p+2)<<8|\ + (u_int32)*((u_char *)p+3)<<0) +#endif + +#if defined(KERNEL) || defined(_KERNEL) +# if !defined(__hpux) && !SOLARIS +#include +# endif +#define MINDEX(len, _m, _k) \ +{ \ + len = MLEN(m); \ + while ((_k) >= len) { \ + (_k) -= len; \ + (_m) = (_m)->m_next; \ + if ((_m) == 0) \ + return 0; \ + len = MLEN(m); \ + } \ +} + +static int +m_xword(m, k, err) + register struct mbuf *m; + register int k, *err; +{ + register int len; + register u_char *cp, *np; + register struct mbuf *m0; + + MINDEX(len, m, k); + cp = mtod(m, u_char *) + k; + if (len - k >= 4) { + *err = 0; + return EXTRACT_LONG(cp); + } + m0 = m->m_next; + if (m0 == 0 || MLEN(m0) + len - k < 4) + goto bad; + *err = 0; + np = mtod(m0, u_char *); + switch (len - k) { + + case 1: + return (cp[0] << 24) | (np[0] << 16) | (np[1] << 8) | np[2]; + + case 2: + return (cp[0] << 24) | (cp[1] << 16) | (np[0] << 8) | np[1]; + + default: + return (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | np[0]; + } + bad: + *err = 1; + return 0; +} + +static int +m_xhalf(m, k, err) + register struct mbuf *m; + register int k, *err; +{ + register int len; + register u_char *cp; + register struct mbuf *m0; + + MINDEX(len, m, k); + cp = mtod(m, u_char *) + k; + if (len - k >= 2) { + *err = 0; + return EXTRACT_SHORT(cp); + } + m0 = m->m_next; + if (m0 == 0) + goto bad; + *err = 0; + return (cp[0] << 8) | mtod(m0, u_char *)[0]; + bad: + *err = 1; + return 0; +} +#endif + +#ifdef __linux__ +#include +#include +#include +#endif + +enum { + BPF_S_ANC_NONE, + BPF_S_ANC_VLAN_TAG, + BPF_S_ANC_VLAN_TAG_PRESENT, +}; + +/* + * Execute the filter program starting at pc on the packet p + * wirelen is the length of the original packet + * buflen is the amount of data present + * aux_data is auxiliary data, currently used only when interpreting + * filters intended for the Linux kernel in cases where the kernel + * rejects the filter; it contains VLAN tag information + * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0, + * in all other cases, p is a pointer to a buffer and buflen is its size. + */ +u_int +bpf_filter_with_aux_data(pc, p, wirelen, buflen, aux_data) + register const struct bpf_insn *pc; + register const u_char *p; + u_int wirelen; + register u_int buflen; + register const struct bpf_aux_data *aux_data; +{ + register u_int32 A, X; + register bpf_u_int32 k; + u_int32 mem[BPF_MEMWORDS]; +#if defined(KERNEL) || defined(_KERNEL) + struct mbuf *m, *n; + int merr, len; + + if (buflen == 0) { + m = (struct mbuf *)p; + p = mtod(m, u_char *); + buflen = MLEN(m); + } else + m = NULL; +#endif + + if (pc == 0) + /* + * No filter means accept all. + */ + return (u_int)-1; + A = 0; + X = 0; + --pc; + while (1) { + ++pc; + switch (pc->code) { + + default: +#if defined(KERNEL) || defined(_KERNEL) + return 0; +#else + abort(); +#endif + case BPF_RET|BPF_K: + return (u_int)pc->k; + + case BPF_RET|BPF_A: + return (u_int)A; + + case BPF_LD|BPF_W|BPF_ABS: + k = pc->k; + if (k > buflen || sizeof(int32_t) > buflen - k) { +#if defined(KERNEL) || defined(_KERNEL) + if (m == NULL) + return 0; + A = m_xword(m, k, &merr); + if (merr != 0) + return 0; + continue; +#else + return 0; +#endif + } + A = EXTRACT_LONG(&p[k]); + continue; + + case BPF_LD|BPF_H|BPF_ABS: + k = pc->k; + if (k > buflen || sizeof(int16_t) > buflen - k) { +#if defined(KERNEL) || defined(_KERNEL) + if (m == NULL) + return 0; + A = m_xhalf(m, k, &merr); + if (merr != 0) + return 0; + continue; +#else + return 0; +#endif + } + A = EXTRACT_SHORT(&p[k]); + continue; + + case BPF_LD|BPF_B|BPF_ABS: + { +#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) + int code = BPF_S_ANC_NONE; +#define ANCILLARY(CODE) case SKF_AD_OFF + SKF_AD_##CODE: \ + code = BPF_S_ANC_##CODE; \ + if (!aux_data) \ + return 0; \ + break; + + switch (pc->k) { + ANCILLARY(VLAN_TAG); + ANCILLARY(VLAN_TAG_PRESENT); + default : +#endif + k = pc->k; + if (k >= buflen) { +#if defined(KERNEL) || defined(_KERNEL) + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + A = mtod(n, u_char *)[k]; + continue; +#else + return 0; +#endif + } + A = p[k]; +#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) + } + switch (code) { + case BPF_S_ANC_VLAN_TAG: + if (aux_data) + A = aux_data->vlan_tag; + break; + + case BPF_S_ANC_VLAN_TAG_PRESENT: + if (aux_data) + A = aux_data->vlan_tag_present; + break; + } +#endif + continue; + } + case BPF_LD|BPF_W|BPF_LEN: + A = wirelen; + continue; + + case BPF_LDX|BPF_W|BPF_LEN: + X = wirelen; + continue; + + case BPF_LD|BPF_W|BPF_IND: + k = X + pc->k; + if (pc->k > buflen || X > buflen - pc->k || + sizeof(int32_t) > buflen - k) { +#if defined(KERNEL) || defined(_KERNEL) + if (m == NULL) + return 0; + A = m_xword(m, k, &merr); + if (merr != 0) + return 0; + continue; +#else + return 0; +#endif + } + A = EXTRACT_LONG(&p[k]); + continue; + + case BPF_LD|BPF_H|BPF_IND: + k = X + pc->k; + if (X > buflen || pc->k > buflen - X || + sizeof(int16_t) > buflen - k) { +#if defined(KERNEL) || defined(_KERNEL) + if (m == NULL) + return 0; + A = m_xhalf(m, k, &merr); + if (merr != 0) + return 0; + continue; +#else + return 0; +#endif + } + A = EXTRACT_SHORT(&p[k]); + continue; + + case BPF_LD|BPF_B|BPF_IND: + k = X + pc->k; + if (pc->k >= buflen || X >= buflen - pc->k) { +#if defined(KERNEL) || defined(_KERNEL) + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + A = mtod(n, u_char *)[k]; + continue; +#else + return 0; +#endif + } + A = p[k]; + continue; + + case BPF_LDX|BPF_MSH|BPF_B: + k = pc->k; + if (k >= buflen) { +#if defined(KERNEL) || defined(_KERNEL) + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + X = (mtod(n, char *)[k] & 0xf) << 2; + continue; +#else + return 0; +#endif + } + X = (p[pc->k] & 0xf) << 2; + continue; + + case BPF_LD|BPF_IMM: + A = pc->k; + continue; + + case BPF_LDX|BPF_IMM: + X = pc->k; + continue; + + case BPF_LD|BPF_MEM: + A = mem[pc->k]; + continue; + + case BPF_LDX|BPF_MEM: + X = mem[pc->k]; + continue; + + case BPF_ST: + mem[pc->k] = A; + continue; + + case BPF_STX: + mem[pc->k] = X; + continue; + + case BPF_JMP|BPF_JA: +#if defined(KERNEL) || defined(_KERNEL) + /* + * No backward jumps allowed. + */ + pc += pc->k; +#else + /* + * XXX - we currently implement "ip6 protochain" + * with backward jumps, so sign-extend pc->k. + */ + pc += (bpf_int32)pc->k; +#endif + continue; + + case BPF_JMP|BPF_JGT|BPF_K: + pc += (A > pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_K: + pc += (A >= pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_K: + pc += (A == pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_K: + pc += (A & pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGT|BPF_X: + pc += (A > X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_X: + pc += (A >= X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_X: + pc += (A == X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_X: + pc += (A & X) ? pc->jt : pc->jf; + continue; + + case BPF_ALU|BPF_ADD|BPF_X: + A += X; + continue; + + case BPF_ALU|BPF_SUB|BPF_X: + A -= X; + continue; + + case BPF_ALU|BPF_MUL|BPF_X: + A *= X; + continue; + + case BPF_ALU|BPF_DIV|BPF_X: + if (X == 0) + return 0; + A /= X; + continue; + + case BPF_ALU|BPF_MOD|BPF_X: + if (X == 0) + return 0; + A %= X; + continue; + + case BPF_ALU|BPF_AND|BPF_X: + A &= X; + continue; + + case BPF_ALU|BPF_OR|BPF_X: + A |= X; + continue; + + case BPF_ALU|BPF_XOR|BPF_X: + A ^= X; + continue; + + case BPF_ALU|BPF_LSH|BPF_X: + A <<= X; + continue; + + case BPF_ALU|BPF_RSH|BPF_X: + A >>= X; + continue; + + case BPF_ALU|BPF_ADD|BPF_K: + A += pc->k; + continue; + + case BPF_ALU|BPF_SUB|BPF_K: + A -= pc->k; + continue; + + case BPF_ALU|BPF_MUL|BPF_K: + A *= pc->k; + continue; + + case BPF_ALU|BPF_DIV|BPF_K: + A /= pc->k; + continue; + + case BPF_ALU|BPF_MOD|BPF_K: + A %= pc->k; + continue; + + case BPF_ALU|BPF_AND|BPF_K: + A &= pc->k; + continue; + + case BPF_ALU|BPF_OR|BPF_K: + A |= pc->k; + continue; + + case BPF_ALU|BPF_XOR|BPF_K: + A ^= pc->k; + continue; + + case BPF_ALU|BPF_LSH|BPF_K: + A <<= pc->k; + continue; + + case BPF_ALU|BPF_RSH|BPF_K: + A >>= pc->k; + continue; + + case BPF_ALU|BPF_NEG: + A = -A; + continue; + + case BPF_MISC|BPF_TAX: + X = A; + continue; + + case BPF_MISC|BPF_TXA: + A = X; + continue; + } + } +} + +u_int +bpf_filter(pc, p, wirelen, buflen) + register const struct bpf_insn *pc; + register const u_char *p; + u_int wirelen; + register u_int buflen; +{ + return bpf_filter_with_aux_data(pc, p, wirelen, buflen, NULL); +} + + +/* + * Return true if the 'fcode' is a valid filter program. + * The constraints are that each jump be forward and to a valid + * code, that memory accesses are within valid ranges (to the + * extent that this can be checked statically; loads of packet + * data have to be, and are, also checked at run time), and that + * the code terminates with either an accept or reject. + * + * The kernel needs to be able to verify an application's filter code. + * Otherwise, a bogus program could easily crash the system. + */ +int +bpf_validate(f, len) + const struct bpf_insn *f; + int len; +{ + u_int i, from; + const struct bpf_insn *p; + + if (len < 1) + return 0; + /* + * There's no maximum program length in userland. + */ +#if defined(KERNEL) || defined(_KERNEL) + if (len > BPF_MAXINSNS) + return 0; +#endif + + for (i = 0; i < len; ++i) { + p = &f[i]; + switch (BPF_CLASS(p->code)) { + /* + * Check that memory operations use valid addresses. + */ + case BPF_LD: + case BPF_LDX: + switch (BPF_MODE(p->code)) { + case BPF_IMM: + break; + case BPF_ABS: + case BPF_IND: + case BPF_MSH: + /* + * There's no maximum packet data size + * in userland. The runtime packet length + * check suffices. + */ +#if defined(KERNEL) || defined(_KERNEL) + /* + * More strict check with actual packet length + * is done runtime. + */ + if (p->k >= bpf_maxbufsize) + return 0; +#endif + break; + case BPF_MEM: + if (p->k >= BPF_MEMWORDS) + return 0; + break; + case BPF_LEN: + break; + default: + return 0; + } + break; + case BPF_ST: + case BPF_STX: + if (p->k >= BPF_MEMWORDS) + return 0; + break; + case BPF_ALU: + switch (BPF_OP(p->code)) { + case BPF_ADD: + case BPF_SUB: + case BPF_MUL: + case BPF_OR: + case BPF_AND: + case BPF_XOR: + case BPF_LSH: + case BPF_RSH: + case BPF_NEG: + break; + case BPF_DIV: + case BPF_MOD: + /* + * Check for constant division or modulus + * by 0. + */ + if (BPF_SRC(p->code) == BPF_K && p->k == 0) + return 0; + break; + default: + return 0; + } + break; + case BPF_JMP: + /* + * Check that jumps are within the code block, + * and that unconditional branches don't go + * backwards as a result of an overflow. + * Unconditional branches have a 32-bit offset, + * so they could overflow; we check to make + * sure they don't. Conditional branches have + * an 8-bit offset, and the from address is <= + * BPF_MAXINSNS, and we assume that BPF_MAXINSNS + * is sufficiently small that adding 255 to it + * won't overflow. + * + * We know that len is <= BPF_MAXINSNS, and we + * assume that BPF_MAXINSNS is < the maximum size + * of a u_int, so that i + 1 doesn't overflow. + * + * For userland, we don't know that the from + * or len are <= BPF_MAXINSNS, but we know that + * from <= len, and, except on a 64-bit system, + * it's unlikely that len, if it truly reflects + * the size of the program we've been handed, + * will be anywhere near the maximum size of + * a u_int. We also don't check for backward + * branches, as we currently support them in + * userland for the protochain operation. + */ + from = i + 1; + switch (BPF_OP(p->code)) { + case BPF_JA: +#if defined(KERNEL) || defined(_KERNEL) + if (from + p->k < from || from + p->k >= len) +#else + if (from + p->k >= len) +#endif + return 0; + break; + case BPF_JEQ: + case BPF_JGT: + case BPF_JGE: + case BPF_JSET: + if (from + p->jt >= len || from + p->jf >= len) + return 0; + break; + default: + return 0; + } + break; + case BPF_RET: + break; + case BPF_MISC: + break; + default: + return 0; + } + } + return BPF_CLASS(f[len - 1].code) == BPF_RET; +} diff --git a/tcpdump/jni/libpcap/bpf_dump.c b/tcpdump/jni/libpcap/bpf_dump.c new file mode 100644 index 0000000..5eaadc0 --- /dev/null +++ b/tcpdump/jni/libpcap/bpf_dump.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +void +bpf_dump(const struct bpf_program *p, int option) +{ + const struct bpf_insn *insn; + int i; + int n = p->bf_len; + + insn = p->bf_insns; + if (option > 2) { + printf("%d\n", n); + for (i = 0; i < n; ++insn, ++i) { + printf("%u %u %u %u\n", insn->code, + insn->jt, insn->jf, insn->k); + } + return ; + } + if (option > 1) { + for (i = 0; i < n; ++insn, ++i) + printf("{ 0x%x, %d, %d, 0x%08x },\n", + insn->code, insn->jt, insn->jf, insn->k); + return; + } + for (i = 0; i < n; ++insn, ++i) { +#ifdef BDEBUG + extern int bids[]; + printf(bids[i] > 0 ? "[%02d]" : " -- ", bids[i] - 1); +#endif + puts(bpf_image(insn, i)); + } +} diff --git a/tcpdump/jni/libpcap/bpf_filter.c b/tcpdump/jni/libpcap/bpf_filter.c new file mode 100644 index 0000000..cba6a0a --- /dev/null +++ b/tcpdump/jni/libpcap/bpf_filter.c @@ -0,0 +1 @@ +#include "bpf/net/bpf_filter.c" diff --git a/tcpdump/jni/libpcap/bpf_image.c b/tcpdump/jni/libpcap/bpf_image.c new file mode 100644 index 0000000..3e9a23f --- /dev/null +++ b/tcpdump/jni/libpcap/bpf_image.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#endif /* WIN32 */ + +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +char * +bpf_image(p, n) + const struct bpf_insn *p; + int n; +{ + int v; + const char *fmt, *op; + static char image[256]; + char operand[64]; + + v = p->k; + switch (p->code) { + + default: + op = "unimp"; + fmt = "0x%x"; + v = p->code; + break; + + case BPF_RET|BPF_K: + op = "ret"; + fmt = "#%d"; + break; + + case BPF_RET|BPF_A: + op = "ret"; + fmt = ""; + break; + + case BPF_LD|BPF_W|BPF_ABS: + op = "ld"; + fmt = "[%d]"; + break; + + case BPF_LD|BPF_H|BPF_ABS: + op = "ldh"; + fmt = "[%d]"; + break; + + case BPF_LD|BPF_B|BPF_ABS: + op = "ldb"; + fmt = "[%d]"; + break; + + case BPF_LD|BPF_W|BPF_LEN: + op = "ld"; + fmt = "#pktlen"; + break; + + case BPF_LD|BPF_W|BPF_IND: + op = "ld"; + fmt = "[x + %d]"; + break; + + case BPF_LD|BPF_H|BPF_IND: + op = "ldh"; + fmt = "[x + %d]"; + break; + + case BPF_LD|BPF_B|BPF_IND: + op = "ldb"; + fmt = "[x + %d]"; + break; + + case BPF_LD|BPF_IMM: + op = "ld"; + fmt = "#0x%x"; + break; + + case BPF_LDX|BPF_IMM: + op = "ldx"; + fmt = "#0x%x"; + break; + + case BPF_LDX|BPF_MSH|BPF_B: + op = "ldxb"; + fmt = "4*([%d]&0xf)"; + break; + + case BPF_LD|BPF_MEM: + op = "ld"; + fmt = "M[%d]"; + break; + + case BPF_LDX|BPF_MEM: + op = "ldx"; + fmt = "M[%d]"; + break; + + case BPF_ST: + op = "st"; + fmt = "M[%d]"; + break; + + case BPF_STX: + op = "stx"; + fmt = "M[%d]"; + break; + + case BPF_JMP|BPF_JA: + op = "ja"; + fmt = "%d"; + v = n + 1 + p->k; + break; + + case BPF_JMP|BPF_JGT|BPF_K: + op = "jgt"; + fmt = "#0x%x"; + break; + + case BPF_JMP|BPF_JGE|BPF_K: + op = "jge"; + fmt = "#0x%x"; + break; + + case BPF_JMP|BPF_JEQ|BPF_K: + op = "jeq"; + fmt = "#0x%x"; + break; + + case BPF_JMP|BPF_JSET|BPF_K: + op = "jset"; + fmt = "#0x%x"; + break; + + case BPF_JMP|BPF_JGT|BPF_X: + op = "jgt"; + fmt = "x"; + break; + + case BPF_JMP|BPF_JGE|BPF_X: + op = "jge"; + fmt = "x"; + break; + + case BPF_JMP|BPF_JEQ|BPF_X: + op = "jeq"; + fmt = "x"; + break; + + case BPF_JMP|BPF_JSET|BPF_X: + op = "jset"; + fmt = "x"; + break; + + case BPF_ALU|BPF_ADD|BPF_X: + op = "add"; + fmt = "x"; + break; + + case BPF_ALU|BPF_SUB|BPF_X: + op = "sub"; + fmt = "x"; + break; + + case BPF_ALU|BPF_MUL|BPF_X: + op = "mul"; + fmt = "x"; + break; + + case BPF_ALU|BPF_DIV|BPF_X: + op = "div"; + fmt = "x"; + break; + + case BPF_ALU|BPF_MOD|BPF_X: + op = "mod"; + fmt = "x"; + break; + + case BPF_ALU|BPF_AND|BPF_X: + op = "and"; + fmt = "x"; + break; + + case BPF_ALU|BPF_OR|BPF_X: + op = "or"; + fmt = "x"; + break; + + case BPF_ALU|BPF_XOR|BPF_X: + op = "xor"; + fmt = "x"; + break; + + case BPF_ALU|BPF_LSH|BPF_X: + op = "lsh"; + fmt = "x"; + break; + + case BPF_ALU|BPF_RSH|BPF_X: + op = "rsh"; + fmt = "x"; + break; + + case BPF_ALU|BPF_ADD|BPF_K: + op = "add"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_SUB|BPF_K: + op = "sub"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_MUL|BPF_K: + op = "mul"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_DIV|BPF_K: + op = "div"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_MOD|BPF_K: + op = "mod"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_AND|BPF_K: + op = "and"; + fmt = "#0x%x"; + break; + + case BPF_ALU|BPF_OR|BPF_K: + op = "or"; + fmt = "#0x%x"; + break; + + case BPF_ALU|BPF_XOR|BPF_K: + op = "xor"; + fmt = "#0x%x"; + break; + + case BPF_ALU|BPF_LSH|BPF_K: + op = "lsh"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_RSH|BPF_K: + op = "rsh"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_NEG: + op = "neg"; + fmt = ""; + break; + + case BPF_MISC|BPF_TAX: + op = "tax"; + fmt = ""; + break; + + case BPF_MISC|BPF_TXA: + op = "txa"; + fmt = ""; + break; + } + (void)snprintf(operand, sizeof operand, fmt, v); + if (BPF_CLASS(p->code) == BPF_JMP && BPF_OP(p->code) != BPF_JA) { + (void)snprintf(image, sizeof image, + "(%03d) %-8s %-16s jt %d\tjf %d", + n, op, operand, n + 1 + p->jt, n + 1 + p->jf); + } else { + (void)snprintf(image, sizeof image, + "(%03d) %-8s %s", + n, op, operand); + } + return image; +} diff --git a/tcpdump/jni/libpcap/chmod_bpf b/tcpdump/jni/libpcap/chmod_bpf new file mode 100755 index 0000000..0a30d99 --- /dev/null +++ b/tcpdump/jni/libpcap/chmod_bpf @@ -0,0 +1,19 @@ +#! /bin/sh + +# +# Unfortunately, Mac OS X's devfs is based on the old FreeBSD +# one, not the current one, so there's no way to configure it +# to create BPF devices with particular owners or groups. +# This startup item will make it owned by the admin group, +# with permissions rw-rw----, so that anybody in the admin +# group can use programs that capture or send raw packets. +# +# Change this as appropriate for your site, e.g. to make +# it owned by a particular user without changing the permissions, +# so only that user and the super-user can capture or send raw +# packets, or give it the permissions rw-r-----, so that +# only the super-user can send raw packets but anybody in the +# admin group can capture packets. +# +chgrp admin /dev/bpf* +chmod g+rw /dev/bpf* diff --git a/tcpdump/jni/libpcap/config.guess b/tcpdump/jni/libpcap/config.guess new file mode 100644 index 0000000..44290b8 --- /dev/null +++ b/tcpdump/jni/libpcap/config.guess @@ -0,0 +1,1435 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2015 Free Software Foundation, Inc. + +timestamp='2015-02-23' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2015 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/tcpdump/jni/libpcap/config.h b/tcpdump/jni/libpcap/config.h new file mode 100644 index 0000000..bd622ba --- /dev/null +++ b/tcpdump/jni/libpcap/config.h @@ -0,0 +1,338 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Enable optimizer debugging */ +/* #undef BDEBUG */ + +/* define if you have a cloning BPF device */ +/* #undef HAVE_CLONING_BPF */ + +/* define if you have the DAG API */ +/* #undef HAVE_DAG_API */ + +/* define if you have dag_get_erf_types() */ +/* #undef HAVE_DAG_GET_ERF_TYPES */ + +/* define if you have dag_get_stream_erf_types() */ +/* #undef HAVE_DAG_GET_STREAM_ERF_TYPES */ + +/* define if you have streams capable DAG API */ +/* #undef HAVE_DAG_STREAMS_API */ + +/* define if you have vdag_set_device_info() */ +/* #undef HAVE_DAG_VDAG */ + +/* Define to 1 if you have the declaration of `ether_hostton', and to 0 if you + don't. */ +/* #undef HAVE_DECL_ETHER_HOSTTON */ + +/* define if you have a /dev/dlpi */ +/* #undef HAVE_DEV_DLPI */ + +/* if passive_req_t primitive exists */ +/* #undef HAVE_DLPI_PASSIVE */ + +/* Define to 1 if you have the `ether_hostton' function. */ +/* #undef HAVE_ETHER_HOSTTON */ + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#define HAVE_FSEEKO 1 + +/* on HP-UX 10.20 or later */ +/* #undef HAVE_HPUX10_20_OR_LATER */ + +/* on HP-UX 9.x */ +/* #undef HAVE_HPUX9 */ + +/* if ppa_info_t_dl_module_id exists */ +/* #undef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* if libdlpi exists */ +/* #undef HAVE_LIBDLPI */ + +/* if libnl exists */ +/* #undef HAVE_LIBNL */ + +/* if libnl exists and is version 2.x */ +/* #undef HAVE_LIBNL_2_x */ + +/* if libnl exists and is version 3.x */ +/* #undef HAVE_LIBNL_3_x */ + +/* libnl has NLE_FAILURE */ +/* #undef HAVE_LIBNL_NLE */ + +/* libnl has new-style socket api */ +/* #undef HAVE_LIBNL_SOCKETS */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_COMPILER_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_ETHTOOL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_IF_PACKET_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_NET_TSTAMP_H */ + +/* if tp_vlan_tci exists */ +/* #undef HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_TYPES_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_USBDEVICE_FS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_WIRELESS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_ETHER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IF_ETHER_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETPACKET_IF_PACKET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETPACKET_PACKET_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NET_IF_MEDIA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NET_PFVAR_H */ + +/* if there's an os_proto.h for this platform, to use additional prototypes */ +/* #undef HAVE_OS_PROTO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PATHS_H 1 + +/* define if net/pfvar.h defines PF_NAT through PF_NORDR */ +/* #undef HAVE_PF_NAT_THROUGH_PF_NORDR */ + +/* define if you have a Septel API */ +/* #undef HAVE_SEPTEL_API */ + +/* define if you have Myricom SNF API */ +/* #undef HAVE_SNF_API */ + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* if struct sockaddr has the sa_len member */ +/* #undef HAVE_SOCKADDR_SA_LEN */ + +/* if struct sockaddr_storage exists */ +#define HAVE_SOCKADDR_STORAGE 1 + +/* define if socklen_t is defined */ +#define HAVE_SOCKLEN_T 1 + +/* On solaris */ +/* #undef HAVE_SOLARIS */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +/* #undef HAVE_STRLCPY */ + +/* Define to 1 if the system has the type `struct BPF_TIMEVAL'. */ +/* #undef HAVE_STRUCT_BPF_TIMEVAL */ + +/* Define to 1 if the system has the type `struct ether_addr'. */ +/* #undef HAVE_STRUCT_ETHER_ADDR */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BITYPES_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BUFMOD_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DLPI_EXT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_IOCCOM_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SOCKIO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* if if_packet.h has tpacket_stats defined */ +#define HAVE_TPACKET_STATS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* if struct usbdevfs_ctrltransfer has bRequestType */ +/* #undef HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE */ + +/* define if version.h is generated in the build procedure */ +#define HAVE_VERSION_H 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* define if the system supports zerocopy BPF */ +/* #undef HAVE_ZEROCOPY_BPF */ + +/* define if your compiler has __attribute__ */ +#define HAVE___ATTRIBUTE__ 1 + +/* IPv6 */ +#define INET6 1 + +/* if unaligned access fails */ +/* #undef LBL_ALIGN */ + +/* path for device for USB sniffing */ +#define LINUX_USB_MON_DEV "/dev/usbmon" + +/* if we need a pcap_parse wrapper around yyparse */ +/* #undef NEED_YYPARSE_WRAPPER */ + +/* Define to 1 if netinet/ether.h declares `ether_hostton' */ +/* #undef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON */ + +/* Define to 1 if netinet/if_ether.h declares `ether_hostton' */ +/* #undef NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON */ + +/* do not use protochain */ +/* #undef NO_PROTOCHAIN */ + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* /dev/dlpi directory */ +/* #undef PCAP_DEV_PREFIX */ + +/* target host supports Bluetooth sniffing */ +/* #undef PCAP_SUPPORT_BT */ + +/* target host supports CAN sniffing */ +/* #undef PCAP_SUPPORT_CAN */ + +/* target host supports canusb */ +/* #undef PCAP_SUPPORT_CANUSB */ + +/* support D-Bus sniffing */ +/* #undef PCAP_SUPPORT_DBUS */ + +/* target host supports netfilter sniffing */ +/* #undef PCAP_SUPPORT_NETFILTER */ + +/* target host supports USB sniffing */ +/* #undef PCAP_SUPPORT_USB */ + +/* include ACN support */ +/* #undef SITA */ + +/* if struct sockaddr_hci has hci_channel member */ +/* #undef SOCKADDR_HCI_HAS_HCI_CHANNEL */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Enable parser debugging */ +/* #undef YYDEBUG */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +/* #undef _LARGEFILE_SOURCE */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* define on AIX to get certain functions */ +/* #undef _SUN */ + +/* define if your compiler allows __attribute__((format)) without a warning */ +#define __ATTRIBUTE___FORMAT_OK 1 + +/* to handle Ultrix compilers that don't support const in prototypes */ +/* #undef const */ + +/* Define as token for inline if inlining supported */ +#define inline inline + +/* Define to `short' if int16_t not defined. */ +/* #undef int16_t */ + +/* Define to `int' if int32_t not defined. */ +/* #undef int32_t */ + +/* Define to `long long' if int64_t not defined. */ +/* #undef int64_t */ + +/* Define to `signed char' if int8_t not defined. */ +/* #undef int8_t */ + +/* on sinix */ +/* #undef sinix */ + +/* Define to `unsigned short' if u_int16_t not defined. */ +/* #undef u_int16_t */ + +/* Define to `unsigned int' if u_int32_t not defined. */ +/* #undef u_int32_t */ + +/* Define to `unsigned long long' if u_int64_t not defined. */ +/* #undef u_int64_t */ + +/* Define to `unsigned char' if u_int8_t not defined. */ +/* #undef u_int8_t */ diff --git a/tcpdump/jni/libpcap/config.h.in b/tcpdump/jni/libpcap/config.h.in new file mode 100644 index 0000000..3b9f90a --- /dev/null +++ b/tcpdump/jni/libpcap/config.h.in @@ -0,0 +1,349 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Enable optimizer debugging */ +#undef BDEBUG + +/* define if you have a cloning BPF device */ +#undef HAVE_CLONING_BPF + +/* define if you have the DAG API */ +#undef HAVE_DAG_API + +/* define if you have dag_get_erf_types() */ +#undef HAVE_DAG_GET_ERF_TYPES + +/* define if you have dag_get_stream_erf_types() */ +#undef HAVE_DAG_GET_STREAM_ERF_TYPES + +/* define if you have streams capable DAG API */ +#undef HAVE_DAG_STREAMS_API + +/* define if you have vdag_set_device_info() */ +#undef HAVE_DAG_VDAG + +/* Define to 1 if you have the declaration of `ether_hostton', and to 0 if you + don't. */ +#undef HAVE_DECL_ETHER_HOSTTON + +/* define if you have a /dev/dlpi */ +#undef HAVE_DEV_DLPI + +/* if passive_req_t primitive exists */ +#undef HAVE_DLPI_PASSIVE + +/* Define to 1 if you have the `ether_hostton' function. */ +#undef HAVE_ETHER_HOSTTON + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#undef HAVE_FSEEKO + +/* on HP-UX 10.20 or later */ +#undef HAVE_HPUX10_20_OR_LATER + +/* on HP-UX 9.x */ +#undef HAVE_HPUX9 + +/* if ppa_info_t_dl_module_id exists */ +#undef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* if libdlpi exists */ +#undef HAVE_LIBDLPI + +/* if libnl exists */ +#undef HAVE_LIBNL + +/* if libnl exists and is version 2.x */ +#undef HAVE_LIBNL_2_x + +/* if libnl exists and is version 3.x */ +#undef HAVE_LIBNL_3_x + +/* libnl has NLE_FAILURE */ +#undef HAVE_LIBNL_NLE + +/* libnl has new-style socket api */ +#undef HAVE_LIBNL_SOCKETS + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_COMPILER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_ETHTOOL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_IF_BONDING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_IF_PACKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_NET_TSTAMP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_SOCKIOS_H + +/* if tp_vlan_tci exists */ +#undef HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_USBDEVICE_FS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_WIRELESS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_ETHER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IF_ETHER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETPACKET_IF_PACKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETPACKET_PACKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_MEDIA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_PFVAR_H + +/* if there's an os_proto.h for this platform, to use additional prototypes */ +#undef HAVE_OS_PROTO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PATHS_H + +/* define if net/pfvar.h defines PF_NAT through PF_NORDR */ +#undef HAVE_PF_NAT_THROUGH_PF_NORDR + +/* define if you have a Septel API */ +#undef HAVE_SEPTEL_API + +/* define if you have Myricom SNF API */ +#undef HAVE_SNF_API + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* if struct sockaddr has the sa_len member */ +#undef HAVE_SOCKADDR_SA_LEN + +/* if struct sockaddr_storage exists */ +#undef HAVE_SOCKADDR_STORAGE + +/* define if socklen_t is defined */ +#undef HAVE_SOCKLEN_T + +/* On solaris */ +#undef HAVE_SOLARIS + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if the system has the type `struct BPF_TIMEVAL'. */ +#undef HAVE_STRUCT_BPF_TIMEVAL + +/* Define to 1 if the system has the type `struct ether_addr'. */ +#undef HAVE_STRUCT_ETHER_ADDR + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_BITYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_BUFMOD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DLPI_EXT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCCOM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* if if_packet.h has tpacket_stats defined */ +#undef HAVE_TPACKET_STATS + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* if struct usbdevfs_ctrltransfer has bRequestType */ +#undef HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE + +/* define if version.h is generated in the build procedure */ +#undef HAVE_VERSION_H + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* define if the system supports zerocopy BPF */ +#undef HAVE_ZEROCOPY_BPF + +/* define if your compiler has __attribute__ */ +#undef HAVE___ATTRIBUTE__ + +/* IPv6 */ +#undef INET6 + +/* if unaligned access fails */ +#undef LBL_ALIGN + +/* path for device for USB sniffing */ +#undef LINUX_USB_MON_DEV + +/* if we need a pcap_parse wrapper around yyparse */ +#undef NEED_YYPARSE_WRAPPER + +/* Define to 1 if netinet/ether.h declares `ether_hostton' */ +#undef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON + +/* Define to 1 if netinet/if_ether.h declares `ether_hostton' */ +#undef NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON + +/* do not use protochain */ +#undef NO_PROTOCHAIN + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* /dev/dlpi directory */ +#undef PCAP_DEV_PREFIX + +/* target host supports Bluetooth sniffing */ +#undef PCAP_SUPPORT_BT + +/* target host supports Bluetooth Monitor */ +#undef PCAP_SUPPORT_BT_MONITOR + +/* target host supports CAN sniffing */ +#undef PCAP_SUPPORT_CAN + +/* target host supports canusb */ +#undef PCAP_SUPPORT_CANUSB + +/* support D-Bus sniffing */ +#undef PCAP_SUPPORT_DBUS + +/* target host supports netfilter sniffing */ +#undef PCAP_SUPPORT_NETFILTER + +/* use Linux packet ring capture if available */ +#undef PCAP_SUPPORT_PACKET_RING + +/* target host supports USB sniffing */ +#undef PCAP_SUPPORT_USB + +/* include ACN support */ +#undef SITA + +/* if struct sockaddr_hci has hci_channel member */ +#undef SOCKADDR_HCI_HAS_HCI_CHANNEL + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Enable parser debugging */ +#undef YYDEBUG + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +#undef _LARGEFILE_SOURCE + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* define on AIX to get certain functions */ +#undef _SUN + +/* define if your compiler allows __attribute__((format)) without a warning */ +#undef __ATTRIBUTE___FORMAT_OK + +/* to handle Ultrix compilers that don't support const in prototypes */ +#undef const + +/* Define as token for inline if inlining supported */ +#undef inline + +/* Define to `short' if int16_t not defined. */ +#undef int16_t + +/* Define to `int' if int32_t not defined. */ +#undef int32_t + +/* Define to `long long' if int64_t not defined. */ +#undef int64_t + +/* Define to `signed char' if int8_t not defined. */ +#undef int8_t + +/* on sinix */ +#undef sinix + +/* Define to `unsigned short' if u_int16_t not defined. */ +#undef u_int16_t + +/* Define to `unsigned int' if u_int32_t not defined. */ +#undef u_int32_t + +/* Define to `unsigned long long' if u_int64_t not defined. */ +#undef u_int64_t + +/* Define to `unsigned char' if u_int8_t not defined. */ +#undef u_int8_t diff --git a/tcpdump/jni/libpcap/config.sub b/tcpdump/jni/libpcap/config.sub new file mode 100644 index 0000000..bc855a2 --- /dev/null +++ b/tcpdump/jni/libpcap/config.sub @@ -0,0 +1,1807 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2015 Free Software Foundation, Inc. + +timestamp='2015-02-22' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2015 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/tcpdump/jni/libpcap/configure b/tcpdump/jni/libpcap/configure new file mode 100755 index 0000000..2b69b6d --- /dev/null +++ b/tcpdump/jni/libpcap/configure @@ -0,0 +1,9914 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="pcap.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +PCAP_SUPPORT_PACKET_RING +DBUS_SRC +PCAP_SUPPORT_DBUS +PKGCONFIG +CAN_SRC +PCAP_SUPPORT_CAN +CANUSB_SRC +PCAP_SUPPORT_CANUSB +BT_MONITOR_SRC +BT_SRC +PCAP_SUPPORT_BT +NETFILTER_SRC +PCAP_SUPPORT_NETFILTER +USB_SRC +PCAP_SUPPORT_USB +MAN_MISC_INFO +MAN_FILE_FORMATS +DYEXT +SSRC +ADDLARCHIVEOBJS +ADDLOBJS +V_RPATH_OPT +V_SONAME_OPT +V_SHLIB_OPT +V_SHLIB_CMD +V_PCAP +V_INCLS +V_FINDALLDEVS +V_DEFS +V_CCOPT +MKDEP +DEPENDENCY_CFLAG +LN_S +AR +RANLIB +V_YACC +V_LEX +HAVE_LINUX_TPACKET_AUXDATA +LIBOBJS +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +SHLICC2 +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_gcc +enable_largefile +enable_protochain +with_sita +with_pcap +with_libnl +enable_ipv6 +enable_optimizer_dbg +enable_yydebug +with_dag +with_dag_includes +with_dag_libraries +with_septel +with_snf +with_snf_includes +with_snf_libraries +with_flex +with_bison +enable_universal +enable_shared +enable_usb +enable_bluetooth +enable_canusb +enable_can +enable_dbus +enable_packet_ring +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-largefile omit support for large files + --disable-protochain disable \"protochain\" insn + --enable-ipv6 build IPv6-capable version [default=yes, if + getaddrinfo available] + --enable-optimizer-dbg build optimizer debugging code + --enable-yydebug build parser debugging code + --disable-universal don't build universal on OS X + --enable-shared build shared libraries [default=yes, if support + available] + --enable-usb enable nusb support [default=yes, if support + available] + --enable-bluetooth enable Bluetooth support [default=yes, if support + available] + --enable-canusb enable canusb support [default=yes, if support + available] + --enable-can enable CAN support [default=yes, if support + available] + --enable-dbus enable D-Bus capture support [default=yes, if + support available] + --enable-packet-ring enable Linux packet ring support [default=yes] + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --without-gcc don't use gcc + --with-sita include SITA support + --with-pcap=TYPE use packet capture TYPE + --without-libnl disable libnl support [default=yes, on Linux, if + present] + --with-dag[=DIR] include Endace DAG support ["yes", "no" or DIR; + default="yes" on BSD and Linux if present] + --with-dag-includes=DIR Endace DAG include directory + --with-dag-libraries=DIR + Endace DAG library directory + --with-septel[=DIR] include Septel support (located in directory DIR, if + supplied). [default=yes, on Linux, if present] + --with-snf[=DIR] include Myricom SNF support ["yes", "no" or DIR; + default="yes" on BSD and Linux if present] + --with-snf-includes=DIR Myricom SNF include directory + --with-snf-libraries=DIR + Myricom SNF library directory + --without-flex don't use flex + --without-bison don't use bison + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if ${ac_cv_target+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + + + + + + + +# Check whether --with-gcc was given. +if test "${with_gcc+set}" = set; then : + withval=$with_gcc; +fi + + V_CCOPT="" + if test "${srcdir}" != "." ; then + V_CCOPT="-I\$(srcdir)" + fi + if test "${CFLAGS+set}" = set; then + LBL_CFLAGS="$CFLAGS" + fi + if test -z "$CC" ; then + case "$host_os" in + + bsdi*) + # Extract the first word of "shlicc2", so it can be a program name with args. +set dummy shlicc2; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_SHLICC2+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$SHLICC2"; then + ac_cv_prog_SHLICC2="$SHLICC2" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_SHLICC2="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_SHLICC2" && ac_cv_prog_SHLICC2="no" +fi +fi +SHLICC2=$ac_cv_prog_SHLICC2 +if test -n "$SHLICC2"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SHLICC2" >&5 +$as_echo "$SHLICC2" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test $SHLICC2 = yes ; then + CC=shlicc2 + export CC + fi + ;; + esac + fi + if test -z "$CC" -a "$with_gcc" = no ; then + CC=cc + export CC + fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + if test "$GCC" = yes ; then + # + # -Werror forces warnings to be errors. + # + ac_lbl_cc_force_warning_errors=-Werror + else + V_INCLS="$V_INCLS -I/usr/local/include" + LDFLAGS="$LDFLAGS -L/usr/local/lib" + + case "$host_os" in + + darwin*) + # + # This is assumed either to be GCC or clang, both + # of which use -Werror to force warnings to be errors. + # + ac_lbl_cc_force_warning_errors=-Werror + ;; + + hpux*) + # + # HP C, which is what we presume we're using, doesn't + # exit with a non-zero exit status if we hand it an + # invalid -W flag, can't be forced to do so even with + # +We, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + ;; + + irix*) + # + # MIPS C, which is what we presume we're using, doesn't + # necessarily exit with a non-zero exit status if we + # hand it an invalid -W flag, can't be forced to do + # so, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + # + # It also, apparently, defaults to "char" being + # unsigned, unlike most other C implementations; + # I suppose we could say "signed char" whenever + # we want to guarantee a signed "char", but let's + # just force signed chars. + # + # -xansi is normally the default, but the + # configure script was setting it; perhaps -cckr + # was the default in the Old Days. (Then again, + # that would probably be for backwards compatibility + # in the days when ANSI C was Shiny and New, i.e. + # 1989 and the early '90's, so maybe we can just + # drop support for those compilers.) + # + # -g is equivalent to -g2, which turns off + # optimization; we choose -g3, which generates + # debugging information but doesn't turn off + # optimization (even if the optimization would + # cause inaccuracies in debugging). + # + V_CCOPT="$V_CCOPT -xansi -signed -g3" + ;; + + osf*) + # + # Presumed to be DEC OSF/1, Digital UNIX, or + # Tru64 UNIX. + # + # The DEC C compiler, which is what we presume we're + # using, doesn't exit with a non-zero exit status if we + # hand it an invalid -W flag, can't be forced to do + # so, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + # + # -g is equivalent to -g2, which turns off + # optimization; we choose -g3, which generates + # debugging information but doesn't turn off + # optimization (even if the optimization would + # cause inaccuracies in debugging). + # + V_CCOPT="$V_CCOPT -g3" + ;; + + solaris*) + # + # Assumed to be Sun C, which requires -errwarn to force + # warnings to be treated as errors. + # + ac_lbl_cc_force_warning_errors=-errwarn + ;; + + ultrix*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking that Ultrix $CC hacks const in prototypes" >&5 +$as_echo_n "checking that Ultrix $CC hacks const in prototypes... " >&6; } + if ${ac_cv_lbl_cc_const_proto+:} false; then : + $as_echo_n "(cached) " >&6 +else + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct a { int b; }; + void c(const struct a *) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_cc_const_proto=yes +else + ac_cv_lbl_cc_const_proto=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_cc_const_proto" >&5 +$as_echo "$ac_cv_lbl_cc_const_proto" >&6; } + if test $ac_cv_lbl_cc_const_proto = no ; then + +$as_echo "#define const /**/" >>confdefs.h + + fi + ;; + esac + V_CCOPT="$V_CCOPT -O" + fi + + + if test "$GCC" = yes ; then + # + # On platforms where we build a shared library: + # + # add options to generate position-independent code, + # if necessary (it's the default in AIX and Darwin/OS X); + # + # define option to set the soname of the shared library, + # if the OS supports that; + # + # add options to specify, at link time, a directory to + # add to the run-time search path, if that's necessary. + # + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + case "$host_os" in + + aix*) + ;; + + freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*) + # + # Platforms where the linker is the GNU linker + # or accepts command-line arguments like + # those the GNU linker accepts. + # + # Some instruction sets require -fPIC on some + # operating systems. Check for them. If you + # have a combination that requires it, add it + # here. + # + PIC_OPT=-fpic + case "$host_cpu" in + + sparc64*) + case "$host_os" in + + freebsd*|openbsd*) + PIC_OPT=-fPIC + ;; + esac + ;; + esac + V_CCOPT="$V_CCOPT $PIC_OPT" + V_SONAME_OPT="-Wl,-soname," + V_RPATH_OPT="-Wl,-rpath," + ;; + + hpux*) + V_CCOPT="$V_CCOPT -fpic" + # + # XXX - this assumes GCC is using the HP linker, + # rather than the GNU linker, and that the "+h" + # option is used on all HP-UX platforms, both .sl + # and .so. + # + V_SONAME_OPT="-Wl,+h," + # + # By default, directories specifed with -L + # are added to the run-time search path, so + # we don't add them in pcap-config. + # + ;; + + solaris*) + V_CCOPT="$V_CCOPT -fpic" + # + # XXX - this assumes GCC is using the Sun linker, + # rather than the GNU linker. + # + V_SONAME_OPT="-Wl,-h," + V_RPATH_OPT="-Wl,-R," + ;; + esac + else + # + # Set the appropriate compiler flags and, on platforms + # where we build a shared library: + # + # add options to generate position-independent code, + # if necessary (it's the default in Darwin/OS X); + # + # if we generate ".so" shared libraries, define the + # appropriate options for building the shared library; + # + # add options to specify, at link time, a directory to + # add to the run-time search path, if that's necessary. + # + # Note: spaces after V_SONAME_OPT are significant; on + # some platforms the soname is passed with a GCC-like + # "-Wl,-soname,{soname}" option, with the soname part + # of the option, while on other platforms the C compiler + # driver takes it as a regular option with the soname + # following the option. The same applies to V_RPATH_OPT. + # + case "$host_os" in + + aix*) + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-G -bnoentry -bexpall" + ;; + + freebsd*|netbsd*|openbsd*|dragonfly*|linux*) + # + # "cc" is GCC. + # + V_CCOPT="$V_CCOPT -fpic" + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + V_SONAME_OPT="-Wl,-soname," + V_RPATH_OPT="-Wl,-rpath," + ;; + + hpux*) + V_CCOPT="$V_CCOPT +z" + V_SHLIB_CMD="\$(LD)" + V_SHLIB_OPT="-b" + V_SONAME_OPT="+h " + # + # By default, directories specifed with -L + # are added to the run-time search path, so + # we don't add them in pcap-config. + # + ;; + + osf*) + # + # Presumed to be DEC OSF/1, Digital UNIX, or + # Tru64 UNIX. + # + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + V_SONAME_OPT="-soname " + V_RPATH_OPT="-rpath " + ;; + + solaris*) + V_CCOPT="$V_CCOPT -Kpic" + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-G" + V_SONAME_OPT="-h " + V_RPATH_OPT="-R" + ;; + esac + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$V_CCOPT" + if ${ac_cv_lbl_inline+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ac_cv_lbl_inline="" + ac_lbl_cc_inline=no + for ac_lbl_inline in inline __inline__ __inline + do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define inline $ac_lbl_inline + static inline struct iltest *foo(void); + struct iltest { + int iltest1; + int iltest2; + }; + + static inline struct iltest * + foo() + { + static struct iltest xxx; + + return &xxx; + } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lbl_cc_inline=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$ac_lbl_cc_inline" = yes ; then + break; + fi + done + if test "$ac_lbl_cc_inline" = yes ; then + ac_cv_lbl_inline=$ac_lbl_inline + fi +fi + + CFLAGS="$save_CFLAGS" + if test ! -z "$ac_cv_lbl_inline" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_inline" >&5 +$as_echo "$ac_cv_lbl_inline" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + +cat >>confdefs.h <<_ACEOF +#define inline $ac_cv_lbl_inline +_ACEOF + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__" >&5 +$as_echo_n "checking for __attribute__... " >&6; } +if ${ac_cv___attribute__+:} false; then : + $as_echo_n "(cached) " >&6 +else + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +static void foo(void) __attribute__ ((noreturn)); + +static void +foo(void) +{ + exit(1); +} + +int +main(int argc, char **argv) +{ + foo(); +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv___attribute__=yes +else + ac_cv___attribute__=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +if test "$ac_cv___attribute__" = "yes"; then + +$as_echo "#define HAVE___ATTRIBUTE__ 1" >>confdefs.h + +else + # + # We can't use __attribute__, so we can't use __attribute__((unused)), + # so we define _U_ to an empty string. + # + V_DEFS="$V_DEFS -D_U_=\"\"" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv___attribute__" >&5 +$as_echo "$ac_cv___attribute__" >&6; } + +if test "$ac_cv___attribute__" = "yes"; then + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __attribute__((unused)) can be used without warnings" >&5 +$as_echo_n "checking whether __attribute__((unused)) can be used without warnings... " >&6; } +if ${ac_cv___attribute___unused+:} false; then : + $as_echo_n "(cached) " >&6 +else + +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include +#include + +int +main(int argc __attribute((unused)), char **argv __attribute((unused))) +{ + printf("Hello, world!\n"); + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv___attribute___unused=yes +else + ac_cv___attribute___unused=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +CFLAGS="$save_CFLAGS" +if test "$ac_cv___attribute___unused" = "yes"; then + V_DEFS="$V_DEFS -D_U_=\"__attribute__((unused))\"" +else + V_DEFS="$V_DEFS -D_U_=\"\"" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv___attribute___unused" >&5 +$as_echo "$ac_cv___attribute___unused" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __attribute__((format)) can be used without warnings" >&5 +$as_echo_n "checking whether __attribute__((format)) can be used without warnings... " >&6; } +if ${ac_cv___attribute___format+:} false; then : + $as_echo_n "(cached) " >&6 +else + +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +extern int foo(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +int +main(int argc, char **argv) +{ + foo("%s", "test"); +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv___attribute___format=yes +else + ac_cv___attribute___format=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +CFLAGS="$save_CFLAGS" +if test "$ac_cv___attribute___format" = "yes"; then + +$as_echo "#define __ATTRIBUTE___FORMAT_OK 1" >>confdefs.h + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv___attribute___format" >&5 +$as_echo "$ac_cv___attribute___format" >&6; } + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in sys/bitypes.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/bitypes.h" "ac_cv_header_sys_bitypes_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_bitypes_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_BITYPES_H 1 +_ACEOF + +fi + +done + + +ac_fn_c_check_type "$LINENO" "int8_t" "ac_cv_type_int8_t" "$ac_includes_default +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +" +if test "x$ac_cv_type_int8_t" = xyes; then : + +else + +$as_echo "#define int8_t signed char" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "u_int8_t" "ac_cv_type_u_int8_t" "$ac_includes_default +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +" +if test "x$ac_cv_type_u_int8_t" = xyes; then : + +else + +$as_echo "#define u_int8_t unsigned char" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "int16_t" "ac_cv_type_int16_t" "$ac_includes_default" +if test "x$ac_cv_type_int16_t" = xyes; then : + +else + +$as_echo "#define int16_t short" >>confdefs.h + + $ac_includes_default +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +fi + +ac_fn_c_check_type "$LINENO" "u_int16_t" "ac_cv_type_u_int16_t" "$ac_includes_default +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +" +if test "x$ac_cv_type_u_int16_t" = xyes; then : + +else + +$as_echo "#define u_int16_t unsigned short" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "int32_t" "ac_cv_type_int32_t" "$ac_includes_default +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +" +if test "x$ac_cv_type_int32_t" = xyes; then : + +else + +$as_echo "#define int32_t int" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "u_int32_t" "ac_cv_type_u_int32_t" "$ac_includes_default +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +" +if test "x$ac_cv_type_u_int32_t" = xyes; then : + +else + +$as_echo "#define u_int32_t unsigned int" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "int64_t" "ac_cv_type_int64_t" "$ac_includes_default +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +" +if test "x$ac_cv_type_int64_t" = xyes; then : + +else + +$as_echo "#define int64_t long long" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "u_int64_t" "ac_cv_type_u_int64_t" "$ac_includes_default +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +" +if test "x$ac_cv_type_u_int64_t" = xyes; then : + +else + +$as_echo "#define u_int64_t unsigned long long" >>confdefs.h + +fi + + +# +# Try to arrange for large file support. +# +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if ${ac_cv_sys_file_offset_bits+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if ${ac_cv_sys_large_files+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi + + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 +$as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } +if ${ac_cv_sys_largefile_source+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include /* for off_t */ + #include +int +main () +{ +int (*fp) (FILE *, off_t, int) = fseeko; + return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_sys_largefile_source=no; break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGEFILE_SOURCE 1 +#include /* for off_t */ + #include +int +main () +{ +int (*fp) (FILE *, off_t, int) = fseeko; + return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_sys_largefile_source=1; break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_cv_sys_largefile_source=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 +$as_echo "$ac_cv_sys_largefile_source" >&6; } +case $ac_cv_sys_largefile_source in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source +_ACEOF +;; +esac +rm -rf conftest* + +# We used to try defining _XOPEN_SOURCE=500 too, to work around a bug +# in glibc 2.1.3, but that breaks too many other things. +# If you want fseeko and ftello with glibc, upgrade to a fixed glibc. +if test $ac_cv_sys_largefile_source != unknown; then + +$as_echo "#define HAVE_FSEEKO 1" >>confdefs.h + +fi + + +for ac_header in sys/ioccom.h sys/sockio.h limits.h paths.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for ac_header in linux/types.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_types_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_TYPES_H 1 +_ACEOF + +fi + +done + +for ac_header in linux/if_packet.h netpacket/packet.h netpacket/if_packet.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for ac_header in net/pfvar.h +do : + ac_fn_c_check_header_compile "$LINENO" "net/pfvar.h" "ac_cv_header_net_pfvar_h" "#include +#include +#include +" +if test "x$ac_cv_header_net_pfvar_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NET_PFVAR_H 1 +_ACEOF + +fi + +done + +if test "$ac_cv_header_net_pfvar_h" = yes; then + # + # Check for various PF actions. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether net/pfvar.h defines PF_NAT through PF_NORDR" >&5 +$as_echo_n "checking whether net/pfvar.h defines PF_NAT through PF_NORDR... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + #include +int +main () +{ +return PF_NAT+PF_NONAT+PF_BINAT+PF_NOBINAT+PF_RDR+PF_NORDR; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_PF_NAT_THROUGH_PF_NORDR 1" >>confdefs.h + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +for ac_header in netinet/if_ether.h +do : + ac_fn_c_check_header_compile "$LINENO" "netinet/if_ether.h" "ac_cv_header_netinet_if_ether_h" "#include +#include +" +if test "x$ac_cv_header_netinet_if_ether_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NETINET_IF_ETHER_H 1 +_ACEOF + +fi + +done + +if test "$ac_cv_header_netinet_if_ether_h" != yes; then + # + # The simple test didn't work. + # Do we need to include first? + # Unset ac_cv_header_netinet_if_ether_h so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: Rechecking with some additional includes" >&5 +$as_echo "$as_me: Rechecking with some additional includes" >&6;} + unset ac_cv_header_netinet_if_ether_h + for ac_header in netinet/if_ether.h +do : + ac_fn_c_check_header_compile "$LINENO" "netinet/if_ether.h" "ac_cv_header_netinet_if_ether_h" "#include +#include +#include +struct mbuf; +struct rtentry; +#include +" +if test "x$ac_cv_header_netinet_if_ether_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NETINET_IF_ETHER_H 1 +_ACEOF + +fi + +done + +fi + +case "$host_os" in +linux*) + for ac_header in linux/sockios.h linux/if_bonding.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" " +#include +#include + +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + ;; +esac + +if test "$GCC" = yes ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI ioctl definitions" >&5 +$as_echo_n "checking for ANSI ioctl definitions... " >&6; } + if ${ac_cv_lbl_gcc_fixincludes+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* + * This generates a "duplicate case value" when fixincludes + * has not be run. + */ +# include +# include +# include +# ifdef HAVE_SYS_IOCCOM_H +# include +# endif +int +main () +{ +switch (0) { + case _IO('A', 1):; + case _IO('B', 1):; + } + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_gcc_fixincludes=yes +else + ac_cv_lbl_gcc_fixincludes=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_gcc_fixincludes" >&5 +$as_echo "$ac_cv_lbl_gcc_fixincludes" >&6; } + if test $ac_cv_lbl_gcc_fixincludes = no ; then + # Don't cache failure + unset ac_cv_lbl_gcc_fixincludes + as_fn_error $? "see the INSTALL for more info" "$LINENO" 5 + fi + fi + +for ac_func in strerror strlcpy +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +needsnprintf=no +for ac_func in vsnprintf snprintf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + needsnprintf=yes +fi +done + +if test $needsnprintf = yes; then + case " $LIBOBJS " in + *" snprintf.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS snprintf.$ac_objext" + ;; +esac + +fi + +# +# Do this before checking for ether_hostton(), as it's a +# "gethostbyname() -ish function". +# + + # Most operating systems have gethostbyname() in the default searched + # libraries (i.e. libc): + # Some OSes (eg. Solaris) place it in libnsl + # Some strange OSes (SINIX) have it in libsocket: + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5 +$as_echo_n "checking for library containing gethostbyname... " >&6; } +if ${ac_cv_search_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +for ac_lib in '' nsl socket resolv; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_gethostbyname=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_gethostbyname+:} false; then : + break +fi +done +if ${ac_cv_search_gethostbyname+:} false; then : + +else + ac_cv_search_gethostbyname=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5 +$as_echo "$ac_cv_search_gethostbyname" >&6; } +ac_res=$ac_cv_search_gethostbyname +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + # Unfortunately libsocket sometimes depends on libnsl and + # AC_SEARCH_LIBS isn't up to the task of handling dependencies like this. + if test "$ac_cv_search_gethostbyname" = "no" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lsocket" >&5 +$as_echo_n "checking for gethostbyname in -lsocket... " >&6; } +if ${ac_cv_lib_socket_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket -lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_gethostbyname=yes +else + ac_cv_lib_socket_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_gethostbyname" >&5 +$as_echo "$ac_cv_lib_socket_gethostbyname" >&6; } +if test "x$ac_cv_lib_socket_gethostbyname" = xyes; then : + LIBS="-lsocket -lnsl $LIBS" +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5 +$as_echo_n "checking for library containing socket... " >&6; } +if ${ac_cv_search_socket+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char socket (); +int +main () +{ +return socket (); + ; + return 0; +} +_ACEOF +for ac_lib in '' socket; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_socket=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_socket+:} false; then : + break +fi +done +if ${ac_cv_search_socket+:} false; then : + +else + ac_cv_search_socket=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 +$as_echo "$ac_cv_search_socket" >&6; } +ac_res=$ac_cv_search_socket +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 +$as_echo_n "checking for socket in -lsocket... " >&6; } +if ${ac_cv_lib_socket_socket+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket -lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char socket (); +int +main () +{ +return socket (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_socket=yes +else + ac_cv_lib_socket_socket=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 +$as_echo "$ac_cv_lib_socket_socket" >&6; } +if test "x$ac_cv_lib_socket_socket" = xyes; then : + LIBS="-lsocket -lnsl $LIBS" +fi + +fi + + # DLPI needs putmsg under HPUX so test for -lstr while we're at it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing putmsg" >&5 +$as_echo_n "checking for library containing putmsg... " >&6; } +if ${ac_cv_search_putmsg+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char putmsg (); +int +main () +{ +return putmsg (); + ; + return 0; +} +_ACEOF +for ac_lib in '' str; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_putmsg=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_putmsg+:} false; then : + break +fi +done +if ${ac_cv_search_putmsg+:} false; then : + +else + ac_cv_search_putmsg=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_putmsg" >&5 +$as_echo "$ac_cv_search_putmsg" >&6; } +ac_res=$ac_cv_search_putmsg +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + + +# +# You are in a twisty little maze of UN*Xes, all different. +# Some might not have ether_hostton(). +# Some might have it, but not declare it in any header file. +# Some might have it, but declare it in . +# Some might have it, but declare it in +# (And some might have it but document it as something declared in +# , although appears to work.) +# +# Before you is a C compiler. +# +for ac_func in ether_hostton +do : + ac_fn_c_check_func "$LINENO" "ether_hostton" "ac_cv_func_ether_hostton" +if test "x$ac_cv_func_ether_hostton" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ETHER_HOSTTON 1 +_ACEOF + +fi +done + +if test "$ac_cv_func_ether_hostton" = yes; then + # + # OK, we have ether_hostton(). Do we have ? + # + if test "$ac_cv_header_netinet_if_ether_h" = yes; then + # + # Yes. Does it declare ether_hostton()? + # + ac_fn_c_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " +#include +#include +#include +#include +struct mbuf; +struct rtentry; +#include +#include + +" +if test "x$ac_cv_have_decl_ether_hostton" = xyes; then : + + +$as_echo "#define NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h + + +fi + + fi + # + # Did that succeed? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, how about , as on Linux? + # + for ac_header in netinet/ether.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "netinet/ether.h" "ac_cv_header_netinet_ether_h" "$ac_includes_default" +if test "x$ac_cv_header_netinet_ether_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NETINET_ETHER_H 1 +_ACEOF + +fi + +done + + if test "$ac_cv_header_netinet_ether_h" = yes; then + # + # We have it - does it declare ether_hostton()? + # Unset ac_cv_have_decl_ether_hostton so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + unset ac_cv_have_decl_ether_hostton + ac_fn_c_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " +#include + +" +if test "x$ac_cv_have_decl_ether_hostton" = xyes; then : + + +$as_echo "#define NETINET_ETHER_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h + + +fi + + fi + fi + # + # Is ether_hostton() declared? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, we'll have to declare it ourselves. + # Do we have "struct ether_addr"? + # + ac_fn_c_check_type "$LINENO" "struct ether_addr" "ac_cv_type_struct_ether_addr" " +#include +#include +#include +#include +struct mbuf; +struct rtentry; +#include +#include + +" +if test "x$ac_cv_type_struct_ether_addr" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_ETHER_ADDR 1 +_ACEOF + + +fi + + +$as_echo "#define HAVE_DECL_ETHER_HOSTTON 0" >>confdefs.h + + else + +$as_echo "#define HAVE_DECL_ETHER_HOSTTON 1" >>confdefs.h + + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if --disable-protochain option is specified" >&5 +$as_echo_n "checking if --disable-protochain option is specified... " >&6; } +# Check whether --enable-protochain was given. +if test "${enable_protochain+set}" = set; then : + enableval=$enable_protochain; +fi + +case "x$enable_protochain" in +xyes) enable_protochain=enabled ;; +xno) enable_protochain=disabled ;; +x) enable_protochain=enabled ;; +esac + +if test "$enable_protochain" = "disabled"; then + +$as_echo "#define NO_PROTOCHAIN 1" >>confdefs.h + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_protochain}" >&5 +$as_echo "${enable_protochain}" >&6; } + +# +# SITA support is mutually exclusive with native capture support; +# "--with-sita" selects SITA support. +# + +# Check whether --with-sita was given. +if test "${with_sita+set}" = set; then : + withval=$with_sita; + if test ! "x$withval" = "xno" ; then + +$as_echo "#define SITA 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: Enabling SITA ACN support" >&5 +$as_echo "$as_me: Enabling SITA ACN support" >&6;} + V_PCAP=sita + V_FINDALLDEVS=sita + fi + +else + +if test -z "$with_pcap" && test "$cross_compiling" = yes; then + as_fn_error $? "pcap type not determined when cross-compiling; use --with-pcap=..." "$LINENO" 5 +fi + +# Check whether --with-pcap was given. +if test "${with_pcap+set}" = set; then : + withval=$with_pcap; +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking packet capture type" >&5 +$as_echo_n "checking packet capture type... " >&6; } +if test ! -z "$with_pcap" ; then + V_PCAP="$withval" +elif test -r /dev/bpf -o -h /dev/bpf ; then + # + # Cloning BPF device. + # + V_PCAP=bpf + +$as_echo "#define HAVE_CLONING_BPF 1" >>confdefs.h + +elif test -r /dev/bpf0 ; then + V_PCAP=bpf +elif test -r /usr/include/net/pfilt.h ; then + V_PCAP=pf +elif test -r /dev/enet ; then + V_PCAP=enet +elif test -r /dev/nit ; then + V_PCAP=snit +elif test -r /usr/include/sys/net/nit.h ; then + V_PCAP=nit +elif test -r /usr/include/linux/socket.h ; then + V_PCAP=linux +elif test -r /usr/include/net/raw.h ; then + V_PCAP=snoop +elif test -r /usr/include/odmi.h ; then + # + # On AIX, the BPF devices might not yet be present - they're + # created the first time libpcap runs after booting. + # We check for odmi.h instead. + # + V_PCAP=bpf +elif test -c /dev/bpf0 ; then # check again in case not readable + V_PCAP=bpf +elif test -r /usr/include/sys/dlpi.h ; then + V_PCAP=dlpi +elif test -c /dev/enet ; then # check again in case not readable + V_PCAP=enet +elif test -c /dev/nit ; then # check again in case not readable + V_PCAP=snit +else + V_PCAP=null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $V_PCAP" >&5 +$as_echo "$V_PCAP" >&6; } + +# +# Do capture-mechanism-dependent tests. +# +case "$V_PCAP" in +dlpi) + # + # Needed for common functions used by pcap-[dlpi,libdlpi].c + # + SSRC="dlpisubs.c" + + # + # Checks for some header files. + # + for ac_header in sys/bufmod.h sys/dlpi_ext.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + # + # Checks to see if Solaris has the public libdlpi(3LIB) library. + # Note: The existence of /usr/include/libdlpi.h does not mean it is the + # public libdlpi(3LIB) version. Before libdlpi was made public, a + # private version also existed, which did not have the same APIs. + # Due to a gcc bug, the default search path for 32-bit libraries does + # not include /lib, we add it explicitly here. + # [http://bugs.opensolaris.org/view_bug.do?bug_id=6619485]. + # Also, due to the bug above applications that link to libpcap with + # libdlpi will have to add "-L/lib" option to "configure". + # + saved_ldflags=$LDFLAGS + LDFLAGS="$LIBS -L/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlpi_walk in -ldlpi" >&5 +$as_echo_n "checking for dlpi_walk in -ldlpi... " >&6; } +if ${ac_cv_lib_dlpi_dlpi_walk+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldlpi $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlpi_walk (); +int +main () +{ +return dlpi_walk (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dlpi_dlpi_walk=yes +else + ac_cv_lib_dlpi_dlpi_walk=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dlpi_dlpi_walk" >&5 +$as_echo "$ac_cv_lib_dlpi_dlpi_walk" >&6; } +if test "x$ac_cv_lib_dlpi_dlpi_walk" = xyes; then : + + LIBS="-ldlpi $LIBS" + V_PCAP=libdlpi + +$as_echo "#define HAVE_LIBDLPI 1" >>confdefs.h + + +else + V_PCAP=dlpi +fi + + LDFLAGS=$saved_ldflags + + # + # Checks whether is usable, to catch weird SCO + # versions of DLPI. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether is usable" >&5 +$as_echo_n "checking whether is usable... " >&6; } + if ${ac_cv_sys_dlpi_usable+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + #include + +int +main () +{ +int i = DL_PROMISC_PHYS; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_dlpi_usable=yes +else + ac_cv_sys_dlpi_usable=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_dlpi_usable" >&5 +$as_echo "$ac_cv_sys_dlpi_usable" >&6; } + if test $ac_cv_sys_dlpi_usable = no ; then + as_fn_error $? " is not usable on this system; it probably has a non-standard DLPI" "$LINENO" 5 + fi + + # + # Check whether we have a /dev/dlpi device or have multiple devices. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/dlpi device" >&5 +$as_echo_n "checking for /dev/dlpi device... " >&6; } + if test -c /dev/dlpi ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_DEV_DLPI 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + dir="/dev/dlpi" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $dir directory" >&5 +$as_echo_n "checking for $dir directory... " >&6; } + if test -d $dir ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +cat >>confdefs.h <<_ACEOF +#define PCAP_DEV_PREFIX "$dir" +_ACEOF + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + fi + + # + # This check is for Solaris with DLPI support for passive modes. + # See dlpi(7P) for more details. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if dl_passive_req_t struct exists" >&5 +$as_echo_n "checking if dl_passive_req_t struct exists... " >&6; } + if ${ac_cv_lbl_has_dl_passive_req_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# include +# include +int +main () +{ +u_int i = sizeof(dl_passive_req_t) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_has_dl_passive_req_t=yes +else + ac_cv_lbl_has_dl_passive_req_t=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_has_dl_passive_req_t" >&5 +$as_echo "$ac_cv_lbl_has_dl_passive_req_t" >&6; } + if test $ac_cv_lbl_has_dl_passive_req_t = yes ; then + +$as_echo "#define HAVE_DLPI_PASSIVE 1" >>confdefs.h + + fi + ;; + +linux) + # + # Do we have the wireless extensions? + # + for ac_header in linux/wireless.h +do : + ac_fn_c_check_header_compile "$LINENO" "linux/wireless.h" "ac_cv_header_linux_wireless_h" " +#include +#include +#include + +" +if test "x$ac_cv_header_linux_wireless_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_WIRELESS_H 1 +_ACEOF + +fi + +done + + + # + # Do we have libnl? + # + +# Check whether --with-libnl was given. +if test "${with_libnl+set}" = set; then : + withval=$with_libnl; with_libnl=$withval +fi + + + if test x$with_libnl != xno ; then + have_any_nl="no" + + incdir=-I/usr/include/libnl3 + libnldir= + if test x$withval != x ; then + libnldir=-L${withval}/lib/.libs + incdir=-I${withval}/include + fi + + # + # Try libnl 3.x first. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl-3" >&5 +$as_echo_n "checking for nl_socket_alloc in -lnl-3... " >&6; } +if ${ac_cv_lib_nl_3_nl_socket_alloc+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnl-3 ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char nl_socket_alloc (); +int +main () +{ +return nl_socket_alloc (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nl_3_nl_socket_alloc=yes +else + ac_cv_lib_nl_3_nl_socket_alloc=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_3_nl_socket_alloc" >&5 +$as_echo "$ac_cv_lib_nl_3_nl_socket_alloc" >&6; } +if test "x$ac_cv_lib_nl_3_nl_socket_alloc" = xyes; then : + + # + # Yes, we have libnl 3.x. + # + LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS" + +$as_echo "#define HAVE_LIBNL 1" >>confdefs.h + + +$as_echo "#define HAVE_LIBNL_3_x 1" >>confdefs.h + + +$as_echo "#define HAVE_LIBNL_NLE 1" >>confdefs.h + + +$as_echo "#define HAVE_LIBNL_SOCKETS 1" >>confdefs.h + + V_INCLS="$V_INCLS ${incdir}" + have_any_nl="yes" + +fi + + + if test x$have_any_nl = xno ; then + # + # Try libnl 2.x + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl" >&5 +$as_echo_n "checking for nl_socket_alloc in -lnl... " >&6; } +if ${ac_cv_lib_nl_nl_socket_alloc+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char nl_socket_alloc (); +int +main () +{ +return nl_socket_alloc (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nl_nl_socket_alloc=yes +else + ac_cv_lib_nl_nl_socket_alloc=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_nl_socket_alloc" >&5 +$as_echo "$ac_cv_lib_nl_nl_socket_alloc" >&6; } +if test "x$ac_cv_lib_nl_nl_socket_alloc" = xyes; then : + + # + # Yes, we have libnl 2.x. + # + LIBS="${libnldir} -lnl-genl -lnl $LIBS" + +$as_echo "#define HAVE_LIBNL 1" >>confdefs.h + + +$as_echo "#define HAVE_LIBNL_2_x 1" >>confdefs.h + + +$as_echo "#define HAVE_LIBNL_NLE 1" >>confdefs.h + + +$as_echo "#define HAVE_LIBNL_SOCKETS 1" >>confdefs.h + + have_any_nl="yes" + +fi + + fi + + if test x$have_any_nl = xno ; then + # + # No, we don't; do we have libnl 1.x? + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_handle_alloc in -lnl" >&5 +$as_echo_n "checking for nl_handle_alloc in -lnl... " >&6; } +if ${ac_cv_lib_nl_nl_handle_alloc+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char nl_handle_alloc (); +int +main () +{ +return nl_handle_alloc (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nl_nl_handle_alloc=yes +else + ac_cv_lib_nl_nl_handle_alloc=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_nl_handle_alloc" >&5 +$as_echo "$ac_cv_lib_nl_nl_handle_alloc" >&6; } +if test "x$ac_cv_lib_nl_nl_handle_alloc" = xyes; then : + + # + # Yes. + # + LIBS="${libnldir} -lnl $LIBS" + +$as_echo "#define HAVE_LIBNL 1" >>confdefs.h + + have_any_nl="yes" + +fi + + fi + + if test x$have_any_nl = xno ; then + # + # No, we don't have libnl at all. + # + if test x$with_libnl = xyes ; then + as_fn_error $? "libnl support requested but libnl not found" "$LINENO" 5 + fi + fi + fi + + for ac_header in linux/ethtool.h +do : + ac_fn_c_check_header_compile "$LINENO" "linux/ethtool.h" "ac_cv_header_linux_ethtool_h" " +$ac_includes_default +#include + +" +if test "x$ac_cv_header_linux_ethtool_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_ETHTOOL_H 1 +_ACEOF + +fi + +done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if if_packet.h has tpacket_stats defined" >&5 +$as_echo_n "checking if if_packet.h has tpacket_stats defined... " >&6; } + if ${ac_cv_lbl_tpacket_stats+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# include +int +main () +{ +struct tpacket_stats stats + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_tpacket_stats=yes +else + ac_cv_lbl_tpacket_stats=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_tpacket_stats" >&5 +$as_echo "$ac_cv_lbl_tpacket_stats" >&6; } + if test $ac_cv_lbl_tpacket_stats = yes; then + +$as_echo "#define HAVE_TPACKET_STATS 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if tpacket_auxdata struct has tp_vlan_tci member" >&5 +$as_echo_n "checking if tpacket_auxdata struct has tp_vlan_tci member... " >&6; } + if ${ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# include +# include +int +main () +{ +u_int i = sizeof(((struct tpacket_auxdata *)0)->tp_vlan_tci) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci=yes +else + ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci" >&5 +$as_echo "$ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci" >&6; } + if test $ac_cv_lbl_linux_tpacket_auxdata_tp_vlan_tci = yes ; then + HAVE_LINUX_TPACKET_AUXDATA=tp_vlan_tci + + +$as_echo "#define HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI 1" >>confdefs.h + + fi + ;; + +bpf) + # + # Check whether we have the *BSD-style ioctls. + # + for ac_header in net/if_media.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "net/if_media.h" "ac_cv_header_net_if_media_h" "$ac_includes_default" +if test "x$ac_cv_header_net_if_media_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NET_IF_MEDIA_H 1 +_ACEOF + +fi + +done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the system supports zerocopy BPF" >&5 +$as_echo_n "checking whether the system supports zerocopy BPF... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + #include +int +main () +{ +return (BIOCROTZBUF + BPF_BUFMODE_ZBUF); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_ZEROCOPY_BPF 1" >>confdefs.h + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + # + # Check whether we have struct BPF_TIMEVAL. + # + ac_fn_c_check_type "$LINENO" "struct BPF_TIMEVAL" "ac_cv_type_struct_BPF_TIMEVAL" " +#include +#include +#ifdef HAVE_SYS_IOCCOM_H +#include +#endif +#include + +" +if test "x$ac_cv_type_struct_BPF_TIMEVAL" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_BPF_TIMEVAL 1 +_ACEOF + + +fi + + ;; + +dag) + V_DEFS="$V_DEFS -DDAG_ONLY" + ;; + +septel) + V_DEFS="$V_DEFS -DSEPTEL_ONLY" + ;; + +snf) + V_DEFS="$V_DEFS -DSNF_ONLY" + ;; + +null) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot determine packet capture interface" >&5 +$as_echo "$as_me: WARNING: cannot determine packet capture interface" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: (see the INSTALL doc for more info)" >&5 +$as_echo "$as_me: WARNING: (see the INSTALL doc for more info)" >&2;} + ;; +esac + +if test "$V_PCAP" = null +then + # + # We can't capture, so we can't open any capture + # devices, so we won't return any interfaces. + # + V_FINDALLDEVS=null +else + ac_fn_c_check_func "$LINENO" "getifaddrs" "ac_cv_func_getifaddrs" +if test "x$ac_cv_func_getifaddrs" = xyes; then : + + # + # We have "getifaddrs()"; make sure we have + # as well, just in case some platform is really weird. + # + ac_fn_c_check_header_mongrel "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "$ac_includes_default" +if test "x$ac_cv_header_ifaddrs_h" = xyes; then : + + # + # We have the header, so we use "getifaddrs()" to + # get the list of interfaces. + # + V_FINDALLDEVS=getad + +else + + # + # We don't have the header - give up. + # XXX - we could also fall back on some other + # mechanism, but, for now, this'll catch this + # problem so that we can at least try to figure + # out something to do on systems with "getifaddrs()" + # but without "ifaddrs.h", if there is something + # we can do on those systems. + # + as_fn_error $? "Your system has getifaddrs() but doesn't have a usable ." "$LINENO" 5 + +fi + + + +else + + # + # Well, we don't have "getifaddrs()", so we have to use + # some other mechanism; determine what that mechanism is. + # + # The first thing we use is the type of capture mechanism, + # which is somewhat of a proxy for the OS we're using. + # + case "$V_PCAP" in + + dlpi|libdlpi) + # + # This might be Solaris 8 or later, with + # SIOCGLIFCONF, or it might be some other OS + # or some older version of Solaris, with + # just SIOCGIFCONF. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have SIOCGLIFCONF" >&5 +$as_echo_n "checking whether we have SIOCGLIFCONF... " >&6; } + if ${ac_cv_lbl_have_siocglifconf+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + #include + #include +int +main () +{ +ioctl(0, SIOCGLIFCONF, (char *)0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_have_siocglifconf=yes +else + ac_cv_lbl_have_siocglifconf=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_have_siocglifconf" >&5 +$as_echo "$ac_cv_lbl_have_siocglifconf" >&6; } + if test $ac_cv_lbl_have_siocglifconf = yes ; then + V_FINDALLDEVS=glifc + else + V_FINDALLDEVS=gifc + fi + ;; + + *) + # + # Assume we just have SIOCGIFCONF. + # (XXX - on at least later Linux kernels, there's + # another mechanism, and we should be using that + # instead.) + # + V_FINDALLDEVS=gifc + ;; + esac +fi + +fi + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5 +$as_echo_n "checking for socklen_t... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + socklen_t x; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_socklen_t=yes +else + have_socklen_t=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +if test "x$have_socklen_t" = "xyes"; then + +$as_echo "#define HAVE_SOCKLEN_T 1" >>confdefs.h + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_socklen_t" >&5 +$as_echo "$have_socklen_t" >&6; } + +# Check whether --enable-ipv6 was given. +if test "${enable_ipv6+set}" = set; then : + enableval=$enable_ipv6; +else + enable_ipv6=ifavailable +fi + +if test "$enable_ipv6" != "no"; then + ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" +if test "x$ac_cv_func_getaddrinfo" = xyes; then : + + +$as_echo "#define INET6 1" >>confdefs.h + + +else + + if test "$enable_ipv6" != "ifavailable"; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "--enable-ipv6 was given, but getaddrinfo isn't available +See \`config.log' for more details" "$LINENO" 5; } + fi + +fi + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build optimizer debugging code" >&5 +$as_echo_n "checking whether to build optimizer debugging code... " >&6; } +# Check whether --enable-optimizer-dbg was given. +if test "${enable_optimizer_dbg+set}" = set; then : + enableval=$enable_optimizer_dbg; +fi + +if test "$enable_optimizer_dbg" = "yes"; then + +$as_echo "#define BDEBUG 1" >>confdefs.h + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_optimizer_dbg-no}" >&5 +$as_echo "${enable_optimizer_dbg-no}" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build parser debugging code" >&5 +$as_echo_n "checking whether to build parser debugging code... " >&6; } +# Check whether --enable-yydebug was given. +if test "${enable_yydebug+set}" = set; then : + enableval=$enable_yydebug; +fi + +if test "$enable_yydebug" = "yes"; then + +$as_echo "#define YYDEBUG 1" >>confdefs.h + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_yydebug-no}" >&5 +$as_echo "${enable_yydebug-no}" >&6; } + +# Check for Endace DAG card support. + +# Check whether --with-dag was given. +if test "${with_dag+set}" = set; then : + withval=$with_dag; + if test "$withval" = no + then + # User doesn't want DAG support. + want_dag=no + elif test "$withval" = yes + then + # User wants DAG support but hasn't specified a directory. + want_dag=yes + else + # User wants DAG support and has specified a directory, so use the provided value. + want_dag=yes + dag_root=$withval + fi + +else + + # + # Use DAG API if present, otherwise don't + # + want_dag=ifpresent + +fi + + + +# Check whether --with-dag-includes was given. +if test "${with_dag_includes+set}" = set; then : + withval=$with_dag_includes; + # User wants DAG support and has specified a header directory, so use the provided value. + want_dag=yes + dag_include_dir=$withval + +fi + + + +# Check whether --with-dag-libraries was given. +if test "${with_dag_libraries+set}" = set; then : + withval=$with_dag_libraries; + # User wants DAG support and has specified a library directory, so use the provided value. + want_dag=yes + dag_lib_dir=$withval + +fi + + +case "$V_PCAP" in +linux|bpf|dag) + # + # We support the DAG API if we're on Linux or BSD, or if we're + # building a DAG-only libpcap. + # + ;; +*) + # + # If the user explicitly requested DAG, tell them it's not + # supported. + # + # If they expressed no preference, don't include it. + # + if test $want_dag = yes; then + as_fn_error $? "DAG support is only available with 'linux' 'bpf' and 'dag' packet capture types" "$LINENO" 5 + elif test $want_dag = yes; then + want_dag=no + fi + ;; +esac + +ac_cv_lbl_dag_api=no +if test "$want_dag" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have DAG API headers" >&5 +$as_echo_n "checking whether we have DAG API headers... " >&6; } + + # If necessary, set default paths for DAG API headers and libraries. + if test -z "$dag_root"; then + dag_root=/usr/local + fi + + if test -z "$dag_include_dir"; then + dag_include_dir="$dag_root/include" + fi + + if test -z "$dag_lib_dir"; then + dag_lib_dir="$dag_root/lib" + fi + + if test -z "$dag_tools_dir"; then + dag_tools_dir="$dag_root/tools" + fi + + if test -r $dag_include_dir/dagapi.h; then + ac_cv_lbl_dag_api=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_dag_api ($dag_include_dir)" >&5 +$as_echo "$ac_cv_lbl_dag_api ($dag_include_dir)" >&6; } +fi + +if test $ac_cv_lbl_dag_api = yes; then + V_INCLS="$V_INCLS -I$dag_include_dir" + + if test $V_PCAP != dag ; then + SSRC="pcap-dag.c" + fi + + # See if we can find a general version string. + # Don't need to save and restore LIBS to prevent -ldag being + # included if there's a found-action (arg 3). + saved_ldflags=$LDFLAGS + LDFLAGS="-L$dag_lib_dir" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dag_attach_stream in -ldag" >&5 +$as_echo_n "checking for dag_attach_stream in -ldag... " >&6; } +if ${ac_cv_lib_dag_dag_attach_stream+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldag $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dag_attach_stream (); +int +main () +{ +return dag_attach_stream (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dag_dag_attach_stream=yes +else + ac_cv_lib_dag_dag_attach_stream=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_attach_stream" >&5 +$as_echo "$ac_cv_lib_dag_dag_attach_stream" >&6; } +if test "x$ac_cv_lib_dag_dag_attach_stream" = xyes; then : + dag_streams="1" +else + dag_streams="0" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dag_get_erf_types in -ldag" >&5 +$as_echo_n "checking for dag_get_erf_types in -ldag... " >&6; } +if ${ac_cv_lib_dag_dag_get_erf_types+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldag $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dag_get_erf_types (); +int +main () +{ +return dag_get_erf_types (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dag_dag_get_erf_types=yes +else + ac_cv_lib_dag_dag_get_erf_types=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_get_erf_types" >&5 +$as_echo "$ac_cv_lib_dag_dag_get_erf_types" >&6; } +if test "x$ac_cv_lib_dag_dag_get_erf_types" = xyes; then : + + +$as_echo "#define HAVE_DAG_GET_ERF_TYPES 1" >>confdefs.h + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dag_get_stream_erf_types in -ldag" >&5 +$as_echo_n "checking for dag_get_stream_erf_types in -ldag... " >&6; } +if ${ac_cv_lib_dag_dag_get_stream_erf_types+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldag $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dag_get_stream_erf_types (); +int +main () +{ +return dag_get_stream_erf_types (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dag_dag_get_stream_erf_types=yes +else + ac_cv_lib_dag_dag_get_stream_erf_types=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_get_stream_erf_types" >&5 +$as_echo "$ac_cv_lib_dag_dag_get_stream_erf_types" >&6; } +if test "x$ac_cv_lib_dag_dag_get_stream_erf_types" = xyes; then : + + +$as_echo "#define HAVE_DAG_GET_STREAM_ERF_TYPES 1" >>confdefs.h + +fi + + + LDFLAGS=$saved_ldflags + + if test "$dag_streams" = 1; then + +$as_echo "#define HAVE_DAG_STREAMS_API 1" >>confdefs.h + + LIBS="$LIBS -ldag" + LDFLAGS="$LDFLAGS -L$dag_lib_dir" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for vdag_set_device_info in -lvdag" >&5 +$as_echo_n "checking for vdag_set_device_info in -lvdag... " >&6; } +if ${ac_cv_lib_vdag_vdag_set_device_info+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lvdag $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char vdag_set_device_info (); +int +main () +{ +return vdag_set_device_info (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_vdag_vdag_set_device_info=yes +else + ac_cv_lib_vdag_vdag_set_device_info=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_vdag_vdag_set_device_info" >&5 +$as_echo "$ac_cv_lib_vdag_vdag_set_device_info" >&6; } +if test "x$ac_cv_lib_vdag_vdag_set_device_info" = xyes; then : + ac_dag_have_vdag="1" +else + ac_dag_have_vdag="0" +fi + + if test "$ac_dag_have_vdag" = 1; then + +$as_echo "#define HAVE_DAG_VDAG 1" >>confdefs.h + + LIBS="$LIBS -lpthread" + fi + fi + + +$as_echo "#define HAVE_DAG_API 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have the DAG API" >&5 +$as_echo_n "checking whether we have the DAG API... " >&6; } + +if test $ac_cv_lbl_dag_api = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + if test "$want_dag" = yes; then + # User wanted DAG support but we couldn't find it. + as_fn_error $? "DAG API requested, but not found at $dag_root: use --without-dag" "$LINENO" 5 + fi + + if test "$V_PCAP" = dag; then + # User requested "dag" capture type but the DAG API wasn't + # found. + as_fn_error $? "Specifying the capture type as \"dag\" requires the DAG API to be present; use the --with-dag options to specify the location. (Try \"./configure --help\" for more information.)" "$LINENO" 5 + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi + + +# Check whether --with-septel was given. +if test "${with_septel+set}" = set; then : + withval=$with_septel; + if test "$withval" = no + then + want_septel=no + elif test "$withval" = yes + then + want_septel=yes + septel_root= + else + want_septel=yes + septel_root=$withval + fi + +else + + # + # Use Septel API if present, otherwise don't + # + want_septel=ifpresent + septel_root=./../septel + +fi + +ac_cv_lbl_septel_api=no +case "$V_PCAP" in +linux|septel) + # + # We support the Septel API if we're on Linux, or if we're building + # a Septel-only libpcap. + # + ;; +*) + # + # If the user explicitly requested Septel, tell them it's not + # supported. + # + # If they expressed no preference, don't include it. + # + if test $want_septel = yes; then + as_fn_error $? "Septel support only available with 'linux' and 'septel' packet capture types" "$LINENO" 5 + elif test $want_septel = yes; then + want_septel=no + fi + ;; +esac + +if test "$with_septel" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have Septel API" >&5 +$as_echo_n "checking whether we have Septel API... " >&6; } + + if test -z "$septel_root"; then + septel_root=$srcdir/../septel + fi + + septel_tools_dir="$septel_root" + septel_include_dir="$septel_root/INC" + + ac_cv_lbl_septel_api=no + if test -r "$septel_include_dir/msg.h"; then + V_INCLS="$V_INCLS -I$septel_include_dir" + ADDLOBJS="$ADDLOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" + ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" + + if test "$V_PCAP" != septel ; then + SSRC="pcap-septel.c" + fi + ac_cv_lbl_septel_api=yes + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_septel_api" >&5 +$as_echo "$ac_cv_lbl_septel_api" >&6; } + if test $ac_cv_lbl_septel_api = no; then + if test "$want_septel" = yes; then + as_fn_error $? "Septel API not found under directory $septel_root; use --without-septel" "$LINENO" 5 + fi + else + +$as_echo "#define HAVE_SEPTEL_API 1" >>confdefs.h + + fi +fi + +if test "$V_PCAP" = septel -a "$ac_cv_lbl_septel_api" = no; then + as_fn_error $? "Specifying the capture type as 'septel' requires the Septel API to be present; use --with-septel=DIR" "$LINENO" 5 +fi + +# Check for Myricom SNF support. + +# Check whether --with-snf was given. +if test "${with_snf+set}" = set; then : + withval=$with_snf; + if test "$withval" = no + then + # User explicitly doesn't want SNF + want_snf=no + elif test "$withval" = yes + then + # User wants SNF support but hasn't specific a directory. + want_snf=yes + else + # User wants SNF support with a specified directory. + want_snf=yes + snf_root=$withval + fi + +else + + # + # Use Sniffer API if present, otherwise don't + # + want_snf=ifpresent + +fi + + + +# Check whether --with-snf-includes was given. +if test "${with_snf_includes+set}" = set; then : + withval=$with_snf_includes; + # User wants SNF with specific header directory + want_snf=yes + snf_include_dir=$withval + +fi + + + +# Check whether --with-snf-libraries was given. +if test "${with_snf_libraries+set}" = set; then : + withval=$with_snf_libraries; + # User wants SNF with specific lib directory + want_snf=yes + snf_lib_dir=$withval + +fi + + +case "$V_PCAP" in +bpf|linux|snf) + # + # We support the Sniffer API if we're on BSD, Linux, or if we're + # building a Sniffer-only libpcap. + # + ;; +*) + # + # If the user explicitly requested Sniffer, tell them it's not + # supported. + # + # If they expressed no preference, don't include it. + # + if test $want_snf = yes; then + as_fn_error $? "Myricom SNF support only available with 'bpf' 'linux' and 'snf' packet capture types" "$LINENO" 5 + elif test $want_snf = yes; then + want_snf=no + fi + ;; +esac + +ac_cv_lbl_snf_api=no +if test "$with_snf" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have Myricom Sniffer API" >&5 +$as_echo_n "checking whether we have Myricom Sniffer API... " >&6; } + + if test -z "$snf_root"; then + snf_root=/opt/snf + fi + + if test -z "$snf_include_dir"; then + snf_include_dir="$snf_root/include" + fi + + if test -z "$snf_lib_dir"; then + snf_lib_dir="$snf_root/lib" + fi + + if test -f "$snf_include_dir/snf.h"; then + ac_cv_lbl_snf_api=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_snf_api ($snf_root)" >&5 +$as_echo "$ac_cv_lbl_snf_api ($snf_root)" >&6; } + + if test $ac_cv_lbl_snf_api = no; then + if test "$want_snf" = yes; then + as_fn_error $? "SNF API headers not found under $snf_include_dir; use --without-snf" "$LINENO" 5 + fi + else + saved_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -L$snf_lib_dir" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snf_init in -lsnf" >&5 +$as_echo_n "checking for snf_init in -lsnf... " >&6; } +if ${ac_cv_lib_snf_snf_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsnf $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char snf_init (); +int +main () +{ +return snf_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_snf_snf_init=yes +else + ac_cv_lib_snf_snf_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_snf_snf_init" >&5 +$as_echo "$ac_cv_lib_snf_snf_init" >&6; } +if test "x$ac_cv_lib_snf_snf_init" = xyes; then : + ac_cv_lbl_snf_api="yes" +else + ac_cv_lbl_snf_api="no" +fi + + LDFLAGS="$saved_ldflags" + + if test $ac_cv_lbl_snf_api = no; then + if test "$want_snf" = yes; then + as_fn_error $? "SNF API cannot correctly be linked check config.log; use --without-snf" "$LINENO" 5 + fi + else + V_INCLS="$V_INCLS -I$snf_include_dir" + LIBS="$LIBS -lsnf" + LDFLAGS="$LDFLAGS -L$snf_lib_dir" + if test "$V_PCAP" != snf ; then + SSRC="pcap-snf.c" + fi + +$as_echo "#define HAVE_SNF_API 1" >>confdefs.h + + fi + fi +fi + +if test "$V_PCAP" = snf -a "$ac_cv_lbl_snf_api" = no; then + as_fn_error $? "Specifying the capture type as 'snf' requires the Myricom Sniffer API to be present; use --with-snf=DIR" "$LINENO" 5 +fi + + +# Check whether --with-flex was given. +if test "${with_flex+set}" = set; then : + withval=$with_flex; +fi + + +# Check whether --with-bison was given. +if test "${with_bison+set}" = set; then : + withval=$with_bison; +fi + + if test "$with_flex" = no ; then + V_LEX=lex + else + for ac_prog in flex +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_V_LEX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$V_LEX"; then + ac_cv_prog_V_LEX="$V_LEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_V_LEX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +V_LEX=$ac_cv_prog_V_LEX +if test -n "$V_LEX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $V_LEX" >&5 +$as_echo "$V_LEX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$V_LEX" && break +done +test -n "$V_LEX" || V_LEX="lex" + + fi + if test "$V_LEX" = flex ; then + # The -V flag was added in 2.4 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flex 2.4 or higher" >&5 +$as_echo_n "checking for flex 2.4 or higher... " >&6; } + if ${ac_cv_lbl_flex_v24+:} false; then : + $as_echo_n "(cached) " >&6 +else + if flex -V >/dev/null 2>&1; then + ac_cv_lbl_flex_v24=yes + else + ac_cv_lbl_flex_v24=no + fi +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_flex_v24" >&5 +$as_echo "$ac_cv_lbl_flex_v24" >&6; } + if test $ac_cv_lbl_flex_v24 = no ; then + s="2.4 or higher required" + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ignoring obsolete flex executable ($s)" >&5 +$as_echo "$as_me: WARNING: ignoring obsolete flex executable ($s)" >&2;} + V_LEX=lex + fi + fi + if test "$with_bison" = no ; then + V_YACC=yacc + else + for ac_prog in bison +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_V_YACC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$V_YACC"; then + ac_cv_prog_V_YACC="$V_YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_V_YACC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +V_YACC=$ac_cv_prog_V_YACC +if test -n "$V_YACC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $V_YACC" >&5 +$as_echo "$V_YACC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$V_YACC" && break +done +test -n "$V_YACC" || V_YACC="yacc" + + fi + if test "$V_YACC" = bison ; then + V_YACC="$V_YACC -y" + fi + if test "$V_LEX" != lex -a "$V_YACC" = yacc -o "$V_LEX" = lex -a "$V_YACC" != yacc ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: don't have both flex and bison; reverting to lex/yacc" >&5 +$as_echo "$as_me: WARNING: don't have both flex and bison; reverting to lex/yacc" >&2;} + V_LEX=lex + V_YACC=yacc + fi + if test "$V_LEX" = flex -a -n "pcap_" ; then + V_LEX="$V_LEX -Ppcap_" + V_YACC="$V_YACC -p pcap_" + else + +$as_echo "#define NEED_YYPARSE_WRAPPER 1" >>confdefs.h + + fi +if test "$V_LEX" = lex ; then +# Some versions of lex can't handle the definitions section of scanner.l . +# Try lexing it and complain if it can't deal. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for capable lex" >&5 +$as_echo_n "checking for capable lex... " >&6; } +if ${tcpdump_cv_capable_lex+:} false; then : + $as_echo_n "(cached) " >&6 +else + if lex -t scanner.l > /dev/null 2>&1; then + tcpdump_cv_capable_lex=yes + else + tcpdump_cv_capable_lex=insufficient + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcpdump_cv_capable_lex" >&5 +$as_echo "$tcpdump_cv_capable_lex" >&6; } + if test $tcpdump_cv_capable_lex = insufficient ; then + as_fn_error $? "Your operating system's lex is insufficient to compile + libpcap. flex is a lex replacement that has many advantages, including + being able to compile libpcap. For more information, see + http://www.gnu.org/software/flex/flex.html ." "$LINENO" 5 + fi +fi + +# +# Assume, by default, no support for shared libraries and V7/BSD convention +# for man pages (file formats in section 5, miscellaneous info in section 7). +# Individual cases can override this. +# +DYEXT="none" +MAN_FILE_FORMATS=5 +MAN_MISC_INFO=7 +case "$host_os" in + +aix*) + +$as_echo "#define _SUN 1" >>confdefs.h + + + # + # AIX makes it fun to build shared and static libraries, + # because they're *both* ".a" archive libraries. We + # build the static library for the benefit of the traditional + # scheme of building libpcap and tcpdump in subdirectories of + # the same directory, with tcpdump statically linked with the + # libpcap in question, but we also build a shared library as + # "libpcap.shareda" and install *it*, rather than the static + # library, as "libpcap.a". + # + DYEXT="shareda" + + case "$V_PCAP" in + + dlpi) + # + # If we're using DLPI, applications will need to + # use /lib/pse.exp if present, as we use the + # STREAMS routines. + # + pseexe="/lib/pse.exp" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $pseexe" >&5 +$as_echo_n "checking for $pseexe... " >&6; } + if test -f $pseexe ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + LIBS="-I:$pseexe" + fi + ;; + + bpf) + # + # If we're using BPF, we need "-lodm" and "-lcfg", as + # we use them to load the BPF module. + # + LIBS="-lodm -lcfg" + ;; + esac + ;; + +darwin*) + DYEXT="dylib" + V_CCOPT="$V_CCOPT -fno-common" + # Check whether --enable-universal was given. +if test "${enable_universal+set}" = set; then : + enableval=$enable_universal; +fi + + if test "$enable_universal" != "no"; then + case "$host_os" in + + darwin0-7.*) + # + # Pre-Tiger. Build only for 32-bit PowerPC; no + # need for any special compiler or linker flags. + # + ;; + + darwin8.0123*) + # + # Tiger, prior to Intel support. Build for 32-bit + # PowerPC and 64-bit PowerPC, with 32-bit PowerPC + # first. (I'm guessing that's what Apple does.) + # + V_CCOPT="$V_CCOPT -arch ppc -arch ppc64" + LDFLAGS="$LDFLAGS -arch ppc -arch ppc64" + ;; + + darwin8.456*) + # + # Tiger, subsequent to Intel support but prior to + # x86-64 support. Build for 32-bit PowerPC, 64-bit + # PowerPC, and x86, with 32-bit PowerPC first. + # (I'm guessing that's what Apple does.) + # + V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386" + LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386" + ;; + + darwin8.*) + # + # All other Tiger, so subsequent to x86-64 + # support. Build for 32-bit PowerPC, 64-bit + # PowerPC, x86, and x86-64, and with 32-bit PowerPC + # first. (I'm guessing that's what Apple does.) + # + V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386 -arch x86_64" + LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386 -arch x86_64" + ;; + + darwin9.*) + # + # Leopard. Build for 32-bit PowerPC, 64-bit + # PowerPC, x86, and x86-64, with 32-bit PowerPC + # first. (That's what Apple does.) + # + V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386 -arch x86_64" + LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386 -arch x86_64" + ;; + + darwin10.*) + # + # Snow Leopard. Build for x86-64, x86, and + # 32-bit PowerPC, with x86-64 first. (That's + # what Apple does, even though Snow Leopard + # doesn't run on PPC, so PPC libpcap runs under + # Rosetta, and Rosetta doesn't support BPF + # ioctls, so PPC programs can't do live + # captures.) + # + V_CCOPT="$V_CCOPT -arch x86_64 -arch i386 -arch ppc" + LDFLAGS="$LDFLAGS -arch x86_64 -arch i386 -arch ppc" + ;; + + darwin*) + # + # Post-Snow Leopard. Build for x86-64 and + # x86, with x86-64 first. (That's probably what + # Apple does, given that Rosetta is gone.) + # XXX - update if and when Apple drops support + # for 32-bit x86 code. + # + V_CCOPT="$V_CCOPT -arch x86_64 -arch i386" + LDFLAGS="$LDFLAGS -arch x86_64 -arch i386" + ;; + esac + fi + ;; + +hpux9*) + +$as_echo "#define HAVE_HPUX9 1" >>confdefs.h + + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux10.0*) + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux10.1*) + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux*) + +$as_echo "#define HAVE_HPUX10_20_OR_LATER 1" >>confdefs.h + + if test "`uname -m`" = "ia64"; then + DYEXT="so" + else + DYEXT="sl" + fi + + # + # "-b" builds a shared library; "+h" sets the soname. + # + SHLIB_OPT="-b" + SONAME_OPT="+h" + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +irix*) + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*) + DYEXT="so" + + # + # Compiler assumed to be GCC; run-time linker may require a -R + # flag. + # + if test "$libdir" != "/usr/lib"; then + V_RFLAGS=-Wl,-R$libdir + fi + ;; + +osf*) + DYEXT="so" + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +sinix*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if SINIX compiler defines sinix" >&5 +$as_echo_n "checking if SINIX compiler defines sinix... " >&6; } + if ${ac_cv_cc_sinix_defined+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int i = sinix; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_cc_sinix_defined=yes +else + ac_cv_cc_sinix_defined=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_sinix_defined" >&5 +$as_echo "$ac_cv_cc_sinix_defined" >&6; } + if test $ac_cv_cc_sinix_defined = no ; then + +$as_echo "#define sinix 1" >>confdefs.h + + fi + ;; + +solaris*) + +$as_echo "#define HAVE_SOLARIS 1" >>confdefs.h + + + DYEXT="so" + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; +esac + +# Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; +fi + +test "x$enable_shared" = "xno" && DYEXT="none" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + + + +rm -f os-proto.h + if test "${LBL_CFLAGS+set}" = set; then + V_CCOPT="$V_CCOPT ${LBL_CFLAGS}" + fi + if test -f .devel ; then + # + # Skip all the warning option stuff on some compilers. + # + if test "$ac_lbl_cc_dont_try_gcc_dashW" != yes; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler fails when given an unknown warning option" >&5 +$as_echo_n "checking whether the compiler fails when given an unknown warning option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wxyzzy-this-will-never-succeed-xyzzy" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + # + # We're assuming this is clang, where + # -Werror=unknown-warning-option is the appropriate + # option to force the compiler to fail. + # + ac_lbl_unknown_warning_option_error="-Werror=unknown-warning-option" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wall option" >&5 +$as_echo_n "checking whether the compiler supports the -Wall option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wall" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + CFLAGS="$save_CFLAGS" + V_CCOPT="$V_CCOPT -Wall" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-prototypes option" >&5 +$as_echo_n "checking whether the compiler supports the -Wmissing-prototypes option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-prototypes" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + CFLAGS="$save_CFLAGS" + V_CCOPT="$V_CCOPT -Wmissing-prototypes" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wstrict-prototypes option" >&5 +$as_echo_n "checking whether the compiler supports the -Wstrict-prototypes option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wstrict-prototypes" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + CFLAGS="$save_CFLAGS" + V_CCOPT="$V_CCOPT -Wstrict-prototypes" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports generating dependencies" >&5 +$as_echo_n "checking whether the compiler supports generating dependencies... " >&6; } + if test "$GCC" = yes ; then + # + # GCC, or a compiler deemed to be GCC by AC_PROG_CC (even + # though it's not); we assume that, in this case, the flag + # would be -M. + # + ac_lbl_dependency_flag="-M" + else + # + # Not GCC or a compiler deemed to be GCC; what platform is + # this? (We're assuming that if the compiler isn't GCC + # it's the compiler from the vendor of the OS; that won't + # necessarily be true for x86 platforms, where it might be + # the Intel C compiler.) + # + case "$host_os" in + + irix*|osf*|darwin*) + # + # MIPS C for IRIX, DEC C, and clang all use -M. + # + ac_lbl_dependency_flag="-M" + ;; + + solaris*) + # + # Sun C uses -xM. + # + ac_lbl_dependency_flag="-xM" + ;; + + hpux*) + # + # HP's older C compilers don't support this. + # HP's newer C compilers support this with + # either +M or +Make; the older compilers + # interpret +M as something completely + # different, so we use +Make so we don't + # think it works with the older compilers. + # + ac_lbl_dependency_flag="+Make" + ;; + + *) + # + # Not one of the above; assume no support for + # generating dependencies. + # + ac_lbl_dependency_flag="" + ;; + esac + fi + + # + # Is ac_lbl_dependency_flag defined and, if so, does the compiler + # complain about it? + # + # Note: clang doesn't seem to exit with an error status when handed + # an unknown non-warning error, even if you pass it + # -Werror=unknown-warning-option. However, it always supports + # -M, so the fact that this test always succeeds with clang + # isn't an issue. + # + if test ! -z "$ac_lbl_dependency_flag"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF + echo "$CC" $ac_lbl_dependency_flag conftest.c >&5 + if "$CC" $ac_lbl_dependency_flag conftest.c >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, with $ac_lbl_dependency_flag" >&5 +$as_echo "yes, with $ac_lbl_dependency_flag" >&6; } + DEPENDENCY_CFLAG="$ac_lbl_dependency_flag" + MKDEP='${srcdir}/mkdep' + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + # + # We can't run mkdep, so have "make depend" do + # nothing. + # + MKDEP=: + fi + rm -rf conftest* + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + # + # We can't run mkdep, so have "make depend" do + # nothing. + # + MKDEP=: + fi + + + + # + # We used to set -n32 for IRIX 6 when not using GCC (presumed + # to mean that we're using MIPS C or MIPSpro C); it specified + # the "new" faster 32-bit ABI, introduced in IRIX 6.2. I'm + # not sure why that would be something to do *only* with a + # .devel file; why should the ABI for which we produce code + # depend on .devel? + # + os=`echo $host_os | sed -e 's/\([0-9][0-9]*\)[^0-9].*$/\1/'` + name="lbl/os-$os.h" + if test -f $name ; then + ln -s $name os-proto.h + +$as_echo "#define HAVE_OS_PROTO_H 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: can't find $name" >&5 +$as_echo "$as_me: WARNING: can't find $name" >&2;} + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if sockaddr struct has the sa_len member" >&5 +$as_echo_n "checking if sockaddr struct has the sa_len member... " >&6; } + if ${ac_cv_lbl_sockaddr_has_sa_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# include +# include +int +main () +{ +u_int i = sizeof(((struct sockaddr *)0)->sa_len) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_sockaddr_has_sa_len=yes +else + ac_cv_lbl_sockaddr_has_sa_len=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_sockaddr_has_sa_len" >&5 +$as_echo "$ac_cv_lbl_sockaddr_has_sa_len" >&6; } + if test $ac_cv_lbl_sockaddr_has_sa_len = yes ; then + +$as_echo "#define HAVE_SOCKADDR_SA_LEN 1" >>confdefs.h + + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if sockaddr_storage struct exists" >&5 +$as_echo_n "checking if sockaddr_storage struct exists... " >&6; } + if ${ac_cv_lbl_has_sockaddr_storage+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# include +# include +int +main () +{ +u_int i = sizeof (struct sockaddr_storage) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_has_sockaddr_storage=yes +else + ac_cv_lbl_has_sockaddr_storage=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_has_sockaddr_storage" >&5 +$as_echo "$ac_cv_lbl_has_sockaddr_storage" >&6; } + if test $ac_cv_lbl_has_sockaddr_storage = yes ; then + +$as_echo "#define HAVE_SOCKADDR_STORAGE 1" >>confdefs.h + + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if dl_hp_ppa_info_t struct has dl_module_id_1 member" >&5 +$as_echo_n "checking if dl_hp_ppa_info_t struct has dl_module_id_1 member... " >&6; } + if ${ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# include +# include +# include +int +main () +{ +u_int i = sizeof(((dl_hp_ppa_info_t *)0)->dl_module_id_1) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1=yes +else + ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1" >&5 +$as_echo "$ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1" >&6; } + if test $ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1 = yes ; then + +$as_echo "#define HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 1" >>confdefs.h + + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if unaligned accesses fail" >&5 +$as_echo_n "checking if unaligned accesses fail... " >&6; } + if ${ac_cv_lbl_unaligned_fail+:} false; then : + $as_echo_n "(cached) " >&6 +else + case "$host_cpu" in + + # + # These are CPU types where: + # + # the CPU faults on an unaligned access, but at least some + # OSes that support that CPU catch the fault and simulate + # the unaligned access (e.g., Alpha/{Digital,Tru64} UNIX) - + # the simulation is slow, so we don't want to use it; + # + # the CPU, I infer (from the old + # + # XXX: should also check that they don't do weird things (like on arm) + # + # comment) doesn't fault on unaligned accesses, but doesn't + # do a normal unaligned fetch, either (e.g., presumably, ARM); + # + # for whatever reason, the test program doesn't work + # (this has been claimed to be the case for several of those + # CPUs - I don't know what the problem is; the problem + # was reported as "the test program dumps core" for SuperH, + # but that's what the test program is *supposed* to do - + # it dumps core before it writes anything, so the test + # for an empty output file should find an empty output + # file and conclude that unaligned accesses don't work). + # + # This run-time test won't work if you're cross-compiling, so + # in order to support cross-compiling for a particular CPU, + # we have to wire in the list of CPU types anyway, as far as + # I know, so perhaps we should just have a set of CPUs on + # which we know it doesn't work, a set of CPUs on which we + # know it does work, and have the script just fail on other + # cpu types and update it when such a failure occurs. + # + alpha*|arm*|bfin*|hp*|mips*|sh*|sparc*|ia64|nv1) + ac_cv_lbl_unaligned_fail=yes + ;; + + *) + cat >conftest.c < +# include +# include + unsigned char a[5] = { 1, 2, 3, 4, 5 }; + main() { + unsigned int i; + pid_t pid; + int status; + /* avoid "core dumped" message */ + pid = fork(); + if (pid < 0) + exit(2); + if (pid > 0) { + /* parent */ + pid = waitpid(pid, &status, 0); + if (pid < 0) + exit(3); + exit(!WIFEXITED(status)); + } + /* child */ + i = *(unsigned int *)&a[1]; + printf("%d\n", i); + exit(0); + } +EOF + ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \ + conftest.c $LIBS >/dev/null 2>&1 + if test ! -x conftest ; then + ac_cv_lbl_unaligned_fail=yes + else + ./conftest >conftest.out + if test ! -s conftest.out ; then + ac_cv_lbl_unaligned_fail=yes + else + ac_cv_lbl_unaligned_fail=no + fi + fi + rm -f -r conftest* core core.conftest + ;; + esac +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_unaligned_fail" >&5 +$as_echo "$ac_cv_lbl_unaligned_fail" >&6; } + if test $ac_cv_lbl_unaligned_fail = yes ; then + +$as_echo "#define LBL_ALIGN 1" >>confdefs.h + + fi + +# +# Makefile.in includes rules to generate version.h, so we assume +# that it will be generated if autoconf is used. +# + +$as_echo "#define HAVE_VERSION_H 1" >>confdefs.h + + +rm -f net +ln -s ${srcdir}/bpf/net net + + + + + + + + + + + + + + + + + + + +# Check whether --enable-usb was given. +if test "${enable_usb+set}" = set; then : + enableval=$enable_usb; +else + enable_usb=yes +fi + + +if test "x$enable_usb" != "xno" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for USB sniffing support" >&5 +$as_echo_n "checking for USB sniffing support... " >&6; } + case "$host_os" in + linux*) + +$as_echo "#define PCAP_SUPPORT_USB 1" >>confdefs.h + + USB_SRC=pcap-usb-linux.c + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null` + if test $? -ne 0 ; then + ac_usb_dev_name="usbmon" + fi + +cat >>confdefs.h <<_ACEOF +#define LINUX_USB_MON_DEV "/dev/$ac_usb_dev_name" +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: Device for USB sniffing is /dev/$ac_usb_dev_name" >&5 +$as_echo "$as_me: Device for USB sniffing is /dev/$ac_usb_dev_name" >&6;} + # + # Do we have a version of available? + # If so, we might need it for . + # + for ac_header in linux/compiler.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "linux/compiler.h" "ac_cv_header_linux_compiler_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_compiler_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_COMPILER_H 1 +_ACEOF + +fi + +done + + if test "$ac_cv_header_linux_compiler_h" = yes; then + # + # Yes - include it when testing for . + # + for ac_header in linux/usbdevice_fs.h +do : + ac_fn_c_check_header_compile "$LINENO" "linux/usbdevice_fs.h" "ac_cv_header_linux_usbdevice_fs_h" "#include +" +if test "x$ac_cv_header_linux_usbdevice_fs_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_USBDEVICE_FS_H 1 +_ACEOF + +fi + +done + + else + for ac_header in linux/usbdevice_fs.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "linux/usbdevice_fs.h" "ac_cv_header_linux_usbdevice_fs_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_usbdevice_fs_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_USBDEVICE_FS_H 1 +_ACEOF + +fi + +done + + fi + if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then + # + # OK, does it define bRequestType? Older versions of the kernel + # define fields with names like "requesttype, "request", and + # "value", rather than "bRequestType", "bRequest", and + # "wValue". + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if usbdevfs_ctrltransfer struct has bRequestType member" >&5 +$as_echo_n "checking if usbdevfs_ctrltransfer struct has bRequestType member... " >&6; } + if ${ac_cv_usbdevfs_ctrltransfer_has_bRequestType+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +$ac_includes_default +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#ifdef HAVE_LINUX_COMPILER_H +#include +#endif +#include +int +main () +{ +u_int i = sizeof(((struct usbdevfs_ctrltransfer *)0)->bRequestType) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_usbdevfs_ctrltransfer_has_bRequestType=yes +else + ac_cv_usbdevfs_ctrltransfer_has_bRequestType=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_usbdevfs_ctrltransfer_has_bRequestType" >&5 +$as_echo "$ac_cv_usbdevfs_ctrltransfer_has_bRequestType" >&6; } + if test $ac_cv_usbdevfs_ctrltransfer_has_bRequestType = yes ; then + +$as_echo "#define HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE 1" >>confdefs.h + + fi + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; +esac +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the platform could support netfilter sniffing" >&5 +$as_echo_n "checking whether the platform could support netfilter sniffing... " >&6; } +case "$host_os" in +linux*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + # + # Life's too short to deal with trying to get this to compile + # if you don't get the right types defined with + # __KERNEL_STRICT_NAMES getting defined by some other include. + # + # Check whether the includes Just Work. If not, don't turn on + # netfilter support. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can compile the netfilter support" >&5 +$as_echo_n "checking whether we can compile the netfilter support... " >&6; } + if ${ac_cv_netfilter_can_compile+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +$ac_includes_default +#include +#include +#include + +#include +#include +#include +#include +#include +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_netfilter_can_compile=yes +else + ac_cv_netfilter_can_compile=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_netfilter_can_compile" >&5 +$as_echo "$ac_cv_netfilter_can_compile" >&6; } + if test $ac_cv_netfilter_can_compile = yes ; then + +$as_echo "#define PCAP_SUPPORT_NETFILTER 1" >>confdefs.h + + NETFILTER_SRC=pcap-netfilter-linux.c + fi + ;; +*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; +esac + + + +# Check whether --enable-bluetooth was given. +if test "${enable_bluetooth+set}" = set; then : + enableval=$enable_bluetooth; +else + enable_bluetooth=ifsupportavailable +fi + + +if test "x$enable_bluetooth" != "xno" ; then + case "$host_os" in + linux*) + ac_fn_c_check_header_mongrel "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default" +if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes; then : + + +$as_echo "#define PCAP_SUPPORT_BT 1" >>confdefs.h + + BT_SRC=pcap-bt-linux.c + { $as_echo "$as_me:${as_lineno-$LINENO}: Bluetooth sniffing is supported" >&5 +$as_echo "$as_me: Bluetooth sniffing is supported" >&6;} + + # + # OK, does struct sockaddr_hci have an hci_channel + # member? + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if struct sockaddr_hci has hci_channel member" >&5 +$as_echo_n "checking if struct sockaddr_hci has hci_channel member... " >&6; } + if ${ac_cv_lbl_sockaddr_hci_has_hci_channel+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +int +main () +{ +u_int i = sizeof(((struct sockaddr_hci *)0)->hci_channel) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_sockaddr_hci_has_hci_channel=yes +else + ac_cv_lbl_sockaddr_hci_has_hci_channel=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_sockaddr_hci_has_hci_channel" >&5 +$as_echo "$ac_cv_lbl_sockaddr_hci_has_hci_channel" >&6; } + if test $ac_cv_lbl_sockaddr_hci_has_hci_channel = yes ; then + +$as_echo "#define SOCKADDR_HCI_HAS_HCI_CHANNEL /**/" >>confdefs.h + + + # + # OK, is HCI_CHANNEL_MONITOR defined? + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if HCI_CHANNEL_MONITOR is defined" >&5 +$as_echo_n "checking if HCI_CHANNEL_MONITOR is defined... " >&6; } + if ${ac_cv_lbl_hci_channel_monitor_is_defined+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +int +main () +{ +u_int i = HCI_CHANNEL_MONITOR + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_lbl_hci_channel_monitor_is_defined=yes +else + ac_cv_lbl_hci_channel_monitor_is_defined=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_hci_channel_monitor_is_defined" >&5 +$as_echo "$ac_cv_lbl_hci_channel_monitor_is_defined" >&6; } + if test $ac_cv_lbl_hci_channel_monitor_is_defined = yes ; then + +$as_echo "#define PCAP_SUPPORT_BT_MONITOR /**/" >>confdefs.h + + BT_MONITOR_SRC=pcap-bt-monitor-linux.c + fi + fi + ac_lbl_bluetooth_available=yes + +else + ac_lbl_bluetooth_available=no + +fi + + + if test "x$ac_lbl_bluetooth_available" == "xno" ; then + if test "x$enable_bluetooth" = "xyes" ; then + as_fn_error $? "Bluetooth sniffing is not supported; install bluez-lib devel to enable it" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: Bluetooth sniffing is not supported; install bluez-lib devel to enable it" >&5 +$as_echo "$as_me: Bluetooth sniffing is not supported; install bluez-lib devel to enable it" >&6;} + fi + fi + ;; + *) + if test "x$enable_bluetooth" = "xyes" ; then + as_fn_error $? "no Bluetooth sniffing support implemented for $host_os" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: no Bluetooth sniffing support implemented for $host_os" >&5 +$as_echo "$as_me: no Bluetooth sniffing support implemented for $host_os" >&6;} + fi + ;; + esac + + + +fi + +# Check whether --enable-canusb was given. +if test "${enable_canusb+set}" = set; then : + enableval=$enable_canusb; +else + enable_canusb=ifsupportavailable +fi + + +if test "x$enable_canusb" != "xno" ; then + case "$host_os" in + linux*|uclinux*) + ac_fn_c_check_header_mongrel "$LINENO" "libusb-1.0/libusb.h" "ac_cv_header_libusb_1_0_libusb_h" "$ac_includes_default" +if test "x$ac_cv_header_libusb_1_0_libusb_h" = xyes; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libusb_init in -lusb-1.0" >&5 +$as_echo_n "checking for libusb_init in -lusb-1.0... " >&6; } +if ${ac_cv_lib_usb_1_0_libusb_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lusb-1.0 -lpthread + $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char libusb_init (); +int +main () +{ +return libusb_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_usb_1_0_libusb_init=yes +else + ac_cv_lib_usb_1_0_libusb_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_usb_1_0_libusb_init" >&5 +$as_echo "$ac_cv_lib_usb_1_0_libusb_init" >&6; } +if test "x$ac_cv_lib_usb_1_0_libusb_init" = xyes; then : + + +$as_echo "#define PCAP_SUPPORT_CANUSB 1" >>confdefs.h + + CANUSB_SRC=pcap-canusb-linux.c + LIBS="-lusb-1.0 -lpthread $LIBS" + ac_lbl_has_libusb=yes + +else + ac_lbl_has_libusb=no +fi + + +else + ac_lbl_has_libusb=no + +fi + + + if test "x$ac_lbl_has_libusb" = "xyes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: canusb sniffing is supported" >&5 +$as_echo "$as_me: canusb sniffing is supported" >&6;} + else + if test "x$enable_canusb" = "xyes" ; then + as_fn_error $? "canusb sniffing is not supported; install libusb1.0 lib devel to enable it" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: canusb sniffing is not supported; install libusb1.0 lib devel to enable it" >&5 +$as_echo "$as_me: canusb sniffing is not supported; install libusb1.0 lib devel to enable it" >&6;} + fi + fi + ;; + *) + if test "x$enable_canusb" = "xyes" ; then + as_fn_error $? "no canusb support implemented for $host_os" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: no canusb support implemented for $host_os" >&5 +$as_echo "$as_me: no canusb support implemented for $host_os" >&6;} + fi + ;; + esac + + +fi + +# Check whether --enable-can was given. +if test "${enable_can+set}" = set; then : + enableval=$enable_can; +else + enable_can=ifsupportavailable +fi + + +if test "x$enable_can" != "xno" ; then + case "$host_os" in + linux*) + ac_fn_c_check_header_compile "$LINENO" "linux/can.h" "ac_cv_header_linux_can_h" "#include + +" +if test "x$ac_cv_header_linux_can_h" = xyes; then : + + +$as_echo "#define PCAP_SUPPORT_CAN 1" >>confdefs.h + + CAN_SRC=pcap-can-linux.c + { $as_echo "$as_me:${as_lineno-$LINENO}: CAN sniffing is supported" >&5 +$as_echo "$as_me: CAN sniffing is supported" >&6;} + +else + + if test "x$enable_can" = "xyes" ; then + as_fn_error $? "CAN sniffing is not supported" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: CAN sniffing is not supported" >&5 +$as_echo "$as_me: CAN sniffing is not supported" >&6;} + fi + +fi + + + ;; + *) + if test "x$enable_can" = "xyes" ; then + as_fn_error $? "no CAN sniffing support implemented for $host_os" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: no CAN sniffing support implemented for $host_os" >&5 +$as_echo "$as_me: no CAN sniffing support implemented for $host_os" >&6;} + fi + ;; + esac + + +fi + +# Check whether --enable-dbus was given. +if test "${enable_dbus+set}" = set; then : + enableval=$enable_dbus; +else + enable_dbus=ifavailable +fi + + +if test "x$enable_dbus" != "xno"; then + if test "x$enable_dbus" = "xyes"; then + case "$host_os" in + + darwin*) + # + # We don't support D-Bus sniffing on OS X; see + # + # https://bugs.freedesktop.org/show_bug.cgi?id=74029 + # + # The user requested it, so fail. + # + as_fn_error $? "Due to freedesktop.org bug 74029, D-Bus capture support is not available on OS X" "$LINENO" 5 + esac + else + case "$host_os" in + + darwin*) + # + # We don't support D-Bus sniffing on OS X; see + # + # https://bugs.freedesktop.org/show_bug.cgi?id=74029 + # + # The user dind't explicitly request it, so just + # silently refuse to enable it. + # + enable_dbus="no" + ;; + esac + fi +fi + +if test "x$enable_dbus" != "xno"; then + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PKGCONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PKGCONFIG"; then + ac_cv_prog_PKGCONFIG="$PKGCONFIG" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PKGCONFIG="pkg-config" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_PKGCONFIG" && ac_cv_prog_PKGCONFIG="no" +fi +fi +PKGCONFIG=$ac_cv_prog_PKGCONFIG +if test -n "$PKGCONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 +$as_echo "$PKGCONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$PKGCONFIG" != "xno"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for D-Bus" >&5 +$as_echo_n "checking for D-Bus... " >&6; } + if "$PKGCONFIG" dbus-1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + DBUS_CFLAGS=`"$PKGCONFIG" --cflags dbus-1` + DBUS_LIBS=`"$PKGCONFIG" --libs dbus-1` + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + CFLAGS="$CFLAGS $DBUS_CFLAGS" + LIBS="$LIBS $DBUS_LIBS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the D-Bus library defines dbus_connection_read_write" >&5 +$as_echo_n "checking whether the D-Bus library defines dbus_connection_read_write... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + + #include + #include + + #include +int +main () +{ +return dbus_connection_read_write(NULL, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define PCAP_SUPPORT_DBUS 1" >>confdefs.h + + DBUS_SRC=pcap-dbus.c + V_INCLS="$V_INCLS $DBUS_CFLAGS" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + if test "x$enable_dbus" = "xyes"; then + as_fn_error $? "--enable-dbus was given, but the D-Bus library doesn't define dbus_connection_read_write()" "$LINENO" 5 + fi + LIBS="$save_LIBS" + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + if test "x$enable_dbus" = "xyes"; then + as_fn_error $? "--enable-dbus was given, but the dbus-1 package is not installed" "$LINENO" 5 + fi + fi + fi + + +fi + +case "$host_os" in +linux*) + for ac_header in linux/net_tstamp.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "linux/net_tstamp.h" "ac_cv_header_linux_net_tstamp_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_net_tstamp_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_NET_TSTAMP_H 1 +_ACEOF + +fi + +done + + ;; +*) + { $as_echo "$as_me:${as_lineno-$LINENO}: no hardware timestamp support implemented for $host_os" >&5 +$as_echo "$as_me: no hardware timestamp support implemented for $host_os" >&6;} + ;; +esac + +# Check whether --enable-packet-ring was given. +if test "${enable_packet_ring+set}" = set; then : + enableval=$enable_packet_ring; +else + enable_packet_ring=yes +fi + + +if test "x$enable_packet_ring" != "xno" ; then + +$as_echo "#define PCAP_SUPPORT_PACKET_RING 1" >>confdefs.h + + +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +ac_config_headers="$ac_config_headers config.h" + + +ac_config_commands="$ac_config_commands default-1" + +ac_config_files="$ac_config_files Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "pcap-filter.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-filter.manmisc" ;; + "pcap-linktype.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-linktype.manmisc" ;; + "pcap-tstamp.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-tstamp.manmisc" ;; + "pcap-savefile.manfile") CONFIG_FILES="$CONFIG_FILES pcap-savefile.manfile" ;; + "pcap.3pcap") CONFIG_FILES="$CONFIG_FILES pcap.3pcap" ;; + "pcap_compile.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_compile.3pcap" ;; + "pcap_datalink.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_datalink.3pcap" ;; + "pcap_dump_open.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_dump_open.3pcap" ;; + "pcap_get_tstamp_precision.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_get_tstamp_precision.3pcap" ;; + "pcap_list_datalinks.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_list_datalinks.3pcap" ;; + "pcap_list_tstamp_types.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_list_tstamp_types.3pcap" ;; + "pcap_open_dead.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_dead.3pcap" ;; + "pcap_open_offline.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_offline.3pcap" ;; + "pcap_set_tstamp_precision.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_precision.3pcap" ;; + "pcap_set_tstamp_type.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_type.3pcap" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "default-1":C) if test -f .devel; then + echo timestamp > stamp-h + cat Makefile-devel-adds >> Makefile + make depend +fi ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + +exit 0 diff --git a/tcpdump/jni/libpcap/configure.in b/tcpdump/jni/libpcap/configure.in new file mode 100644 index 0000000..be4b29e --- /dev/null +++ b/tcpdump/jni/libpcap/configure.in @@ -0,0 +1,1768 @@ +dnl +dnl Copyright (c) 1994, 1995, 1996, 1997 +dnl The Regents of the University of California. All rights reserved. +dnl +dnl Process this file with autoconf to produce a configure script. +dnl + +# +# See +# +# http://ftp.gnu.org/gnu/config/README +# +# for the URLs to use to fetch new versions of config.guess and +# config.sub. +# + +AC_PREREQ(2.61) +AC_INIT(pcap.c) + +AC_CANONICAL_SYSTEM + +AC_LBL_C_INIT_BEFORE_CC(V_CCOPT, V_INCLS) +AC_PROG_CC +AC_LBL_C_INIT(V_CCOPT, V_INCLS) +AC_LBL_SHLIBS_INIT +AC_LBL_C_INLINE +AC_C___ATTRIBUTE__ +if test "$ac_cv___attribute__" = "yes"; then + AC_C___ATTRIBUTE___UNUSED + AC_C___ATTRIBUTE___FORMAT +fi + +AC_CHECK_HEADERS(sys/bitypes.h) + +AC_CHECK_TYPE([int8_t], , + [AC_DEFINE([int8_t], [signed char], + [Define to `signed char' if int8_t not defined.])], + [AC_INCLUDES_DEFAULT +#ifdef HAVE_SYS_BITYPES_H +#include +#endif]) +AC_CHECK_TYPE([u_int8_t], , + [AC_DEFINE([u_int8_t], [unsigned char], + [Define to `unsigned char' if u_int8_t not defined.])], + [AC_INCLUDES_DEFAULT +#ifdef HAVE_SYS_BITYPES_H +#include +#endif]) +AC_CHECK_TYPE([int16_t], , + [AC_DEFINE([int16_t], [short], + [Define to `short' if int16_t not defined.])] + [AC_INCLUDES_DEFAULT +#ifdef HAVE_SYS_BITYPES_H +#include +#endif]) +AC_CHECK_TYPE([u_int16_t], , + [AC_DEFINE([u_int16_t], [unsigned short], + [Define to `unsigned short' if u_int16_t not defined.])], + [AC_INCLUDES_DEFAULT +#ifdef HAVE_SYS_BITYPES_H +#include +#endif]) +AC_CHECK_TYPE([int32_t], , + [AC_DEFINE([int32_t], [int], + [Define to `int' if int32_t not defined.])], + [AC_INCLUDES_DEFAULT +#ifdef HAVE_SYS_BITYPES_H +#include +#endif]) +AC_CHECK_TYPE([u_int32_t], , + [AC_DEFINE([u_int32_t], [unsigned int], + [Define to `unsigned int' if u_int32_t not defined.])], + [AC_INCLUDES_DEFAULT +#ifdef HAVE_SYS_BITYPES_H +#include +#endif]) +AC_CHECK_TYPE([int64_t], , + [AC_DEFINE([int64_t], [long long], + [Define to `long long' if int64_t not defined.])], + [AC_INCLUDES_DEFAULT +#ifdef HAVE_SYS_BITYPES_H +#include +#endif]) +AC_CHECK_TYPE([u_int64_t], , + [AC_DEFINE([u_int64_t], [unsigned long long], + [Define to `unsigned long long' if u_int64_t not defined.])], + [AC_INCLUDES_DEFAULT +#ifdef HAVE_SYS_BITYPES_H +#include +#endif]) + +# +# Try to arrange for large file support. +# +AC_SYS_LARGEFILE +AC_FUNC_FSEEKO + +dnl +dnl Even if were, on all OSes that support BPF, fixed to +dnl include , and we were to drop support for older +dnl releases without that fix, so that pcap-bpf.c doesn't need to +dnl include , the test program in "AC_LBL_FIXINCLUDES" +dnl in "aclocal.m4" uses it, so we would still have to test for it +dnl and set "HAVE_SYS_IOCCOM_H" if we have it, otherwise +dnl "AC_LBL_FIXINCLUDES" wouldn't work on some platforms such as Solaris. +dnl +AC_CHECK_HEADERS(sys/ioccom.h sys/sockio.h limits.h paths.h) +AC_CHECK_HEADERS(linux/types.h) +AC_CHECK_HEADERS(linux/if_packet.h netpacket/packet.h netpacket/if_packet.h) +AC_CHECK_HEADERS(net/pfvar.h, , , [#include +#include +#include ]) +if test "$ac_cv_header_net_pfvar_h" = yes; then + # + # Check for various PF actions. + # + AC_MSG_CHECKING(whether net/pfvar.h defines PF_NAT through PF_NORDR) + AC_TRY_COMPILE( + [#include + #include + #include + #include ], + [return PF_NAT+PF_NONAT+PF_BINAT+PF_NOBINAT+PF_RDR+PF_NORDR;], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PF_NAT_THROUGH_PF_NORDR, 1, + [define if net/pfvar.h defines PF_NAT through PF_NORDR]) + ], + AC_MSG_RESULT(no)) +fi +AC_CHECK_HEADERS(netinet/if_ether.h, , , [#include +#include ]) +if test "$ac_cv_header_netinet_if_ether_h" != yes; then + # + # The simple test didn't work. + # Do we need to include first? + # Unset ac_cv_header_netinet_if_ether_h so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + AC_MSG_NOTICE([Rechecking with some additional includes]) + unset ac_cv_header_netinet_if_ether_h + AC_CHECK_HEADERS(netinet/if_ether.h, , , [#include +#include +#include +struct mbuf; +struct rtentry; +#include ]) +fi + +case "$host_os" in +linux*) + AC_CHECK_HEADERS(linux/sockios.h linux/if_bonding.h,,, + [ +#include +#include + ]) + ;; +esac + +AC_LBL_FIXINCLUDES + +AC_CHECK_FUNCS(strerror strlcpy) + +needsnprintf=no +AC_CHECK_FUNCS(vsnprintf snprintf,, + [needsnprintf=yes]) +if test $needsnprintf = yes; then + AC_LIBOBJ([snprintf]) +fi + +# +# Do this before checking for ether_hostton(), as it's a +# "gethostbyname() -ish function". +# +AC_LBL_LIBRARY_NET + +# +# You are in a twisty little maze of UN*Xes, all different. +# Some might not have ether_hostton(). +# Some might have it, but not declare it in any header file. +# Some might have it, but declare it in . +# Some might have it, but declare it in +# (And some might have it but document it as something declared in +# , although appears to work.) +# +# Before you is a C compiler. +# +AC_CHECK_FUNCS(ether_hostton) +if test "$ac_cv_func_ether_hostton" = yes; then + # + # OK, we have ether_hostton(). Do we have ? + # + if test "$ac_cv_header_netinet_if_ether_h" = yes; then + # + # Yes. Does it declare ether_hostton()? + # + AC_CHECK_DECL(ether_hostton, + [ + AC_DEFINE(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON,, + [Define to 1 if netinet/if_ether.h declares `ether_hostton']) + ],, + [ +#include +#include +#include +#include +struct mbuf; +struct rtentry; +#include +#include + ]) + fi + # + # Did that succeed? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, how about , as on Linux? + # + AC_CHECK_HEADERS(netinet/ether.h) + if test "$ac_cv_header_netinet_ether_h" = yes; then + # + # We have it - does it declare ether_hostton()? + # Unset ac_cv_have_decl_ether_hostton so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + unset ac_cv_have_decl_ether_hostton + AC_CHECK_DECL(ether_hostton, + [ + AC_DEFINE(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON,, + [Define to 1 if netinet/ether.h declares `ether_hostton']) + ],, + [ +#include + ]) + fi + fi + # + # Is ether_hostton() declared? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, we'll have to declare it ourselves. + # Do we have "struct ether_addr"? + # + AC_CHECK_TYPES(struct ether_addr,,, + [ +#include +#include +#include +#include +struct mbuf; +struct rtentry; +#include +#include + ]) + AC_DEFINE(HAVE_DECL_ETHER_HOSTTON, 0, + [Define to 1 if you have the declaration of `ether_hostton', and to 0 if you +don't.]) + else + AC_DEFINE(HAVE_DECL_ETHER_HOSTTON, 1, + [Define to 1 if you have the declaration of `ether_hostton', and to 0 if you +don't.]) + fi +fi + +dnl to pacify those who hate protochain insn +AC_MSG_CHECKING(if --disable-protochain option is specified) +AC_ARG_ENABLE(protochain, +AC_HELP_STRING([--disable-protochain],[disable \"protochain\" insn])) +case "x$enable_protochain" in +xyes) enable_protochain=enabled ;; +xno) enable_protochain=disabled ;; +x) enable_protochain=enabled ;; +esac + +if test "$enable_protochain" = "disabled"; then + AC_DEFINE(NO_PROTOCHAIN,1,[do not use protochain]) +fi +AC_MSG_RESULT(${enable_protochain}) + +# +# SITA support is mutually exclusive with native capture support; +# "--with-sita" selects SITA support. +# +AC_ARG_WITH(sita, +AC_HELP_STRING([--with-sita],[include SITA support]), +[ + if test ! "x$withval" = "xno" ; then + AC_DEFINE(SITA,1,[include ACN support]) + AC_MSG_NOTICE(Enabling SITA ACN support) + V_PCAP=sita + V_FINDALLDEVS=sita + fi +], +[ +dnl +dnl Not all versions of test support -c (character special) but it's a +dnl better way of testing since the device might be protected. So we +dnl check in our normal order using -r and then check the for the /dev +dnl guys again using -c. +dnl +dnl XXX This could be done for cross-compiling, but for now it's not. +dnl +if test -z "$with_pcap" && test "$cross_compiling" = yes; then + AC_MSG_ERROR(pcap type not determined when cross-compiling; use --with-pcap=...) +fi +AC_ARG_WITH(pcap, +AC_HELP_STRING([--with-pcap=TYPE],[use packet capture TYPE])) +AC_MSG_CHECKING(packet capture type) +if test ! -z "$with_pcap" ; then + V_PCAP="$withval" +elif test -r /dev/bpf -o -h /dev/bpf ; then + # + # Cloning BPF device. + # + V_PCAP=bpf + AC_DEFINE(HAVE_CLONING_BPF,1,[define if you have a cloning BPF device]) +elif test -r /dev/bpf0 ; then + V_PCAP=bpf +elif test -r /usr/include/net/pfilt.h ; then + V_PCAP=pf +elif test -r /dev/enet ; then + V_PCAP=enet +elif test -r /dev/nit ; then + V_PCAP=snit +elif test -r /usr/include/sys/net/nit.h ; then + V_PCAP=nit +elif test -r /usr/include/linux/socket.h ; then + V_PCAP=linux +elif test -r /usr/include/net/raw.h ; then + V_PCAP=snoop +elif test -r /usr/include/odmi.h ; then + # + # On AIX, the BPF devices might not yet be present - they're + # created the first time libpcap runs after booting. + # We check for odmi.h instead. + # + V_PCAP=bpf +elif test -c /dev/bpf0 ; then # check again in case not readable + V_PCAP=bpf +elif test -r /usr/include/sys/dlpi.h ; then + V_PCAP=dlpi +elif test -c /dev/enet ; then # check again in case not readable + V_PCAP=enet +elif test -c /dev/nit ; then # check again in case not readable + V_PCAP=snit +else + V_PCAP=null +fi +AC_MSG_RESULT($V_PCAP) + +# +# Do capture-mechanism-dependent tests. +# +case "$V_PCAP" in +dlpi) + # + # Needed for common functions used by pcap-[dlpi,libdlpi].c + # + SSRC="dlpisubs.c" + + # + # Checks for some header files. + # + AC_CHECK_HEADERS(sys/bufmod.h sys/dlpi_ext.h) + + # + # Checks to see if Solaris has the public libdlpi(3LIB) library. + # Note: The existence of /usr/include/libdlpi.h does not mean it is the + # public libdlpi(3LIB) version. Before libdlpi was made public, a + # private version also existed, which did not have the same APIs. + # Due to a gcc bug, the default search path for 32-bit libraries does + # not include /lib, we add it explicitly here. + # [http://bugs.opensolaris.org/view_bug.do?bug_id=6619485]. + # Also, due to the bug above applications that link to libpcap with + # libdlpi will have to add "-L/lib" option to "configure". + # + saved_ldflags=$LDFLAGS + LDFLAGS="$LIBS -L/lib" + AC_CHECK_LIB(dlpi, dlpi_walk, + [ + LIBS="-ldlpi $LIBS" + V_PCAP=libdlpi + AC_DEFINE(HAVE_LIBDLPI,1,[if libdlpi exists]) + ], + V_PCAP=dlpi) + LDFLAGS=$saved_ldflags + + # + # Checks whether is usable, to catch weird SCO + # versions of DLPI. + # + AC_MSG_CHECKING(whether is usable) + AC_CACHE_VAL(ac_cv_sys_dlpi_usable, + AC_TRY_COMPILE( + [ + #include + #include + #include + ], + [int i = DL_PROMISC_PHYS;], + ac_cv_sys_dlpi_usable=yes, + ac_cv_sys_dlpi_usable=no)) + AC_MSG_RESULT($ac_cv_sys_dlpi_usable) + if test $ac_cv_sys_dlpi_usable = no ; then + AC_MSG_ERROR( is not usable on this system; it probably has a non-standard DLPI) + fi + + # + # Check whether we have a /dev/dlpi device or have multiple devices. + # + AC_MSG_CHECKING(for /dev/dlpi device) + if test -c /dev/dlpi ; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_DEV_DLPI, 1, [define if you have a /dev/dlpi]) + else + AC_MSG_RESULT(no) + dir="/dev/dlpi" + AC_MSG_CHECKING(for $dir directory) + if test -d $dir ; then + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(PCAP_DEV_PREFIX, "$dir", [/dev/dlpi directory]) + else + AC_MSG_RESULT(no) + fi + fi + + # + # This check is for Solaris with DLPI support for passive modes. + # See dlpi(7P) for more details. + # + AC_LBL_DL_PASSIVE_REQ_T + ;; + +linux) + # + # Do we have the wireless extensions? + # + AC_CHECK_HEADERS(linux/wireless.h, [], [], + [ +#include +#include +#include + ]) + + # + # Do we have libnl? + # + AC_ARG_WITH(libnl, + AC_HELP_STRING([--without-libnl],[disable libnl support @<:@default=yes, on Linux, if present@:>@]), + with_libnl=$withval,,) + + if test x$with_libnl != xno ; then + have_any_nl="no" + + incdir=-I/usr/include/libnl3 + libnldir= + if test x$withval != x ; then + libnldir=-L${withval}/lib/.libs + incdir=-I${withval}/include + fi + + # + # Try libnl 3.x first. + # + AC_CHECK_LIB(nl-3, nl_socket_alloc, + [ + # + # Yes, we have libnl 3.x. + # + LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS" + AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]) + AC_DEFINE(HAVE_LIBNL_3_x,1,[if libnl exists and is version 3.x]) + AC_DEFINE(HAVE_LIBNL_NLE,1,[libnl has NLE_FAILURE]) + AC_DEFINE(HAVE_LIBNL_SOCKETS,1,[libnl has new-style socket api]) + V_INCLS="$V_INCLS ${incdir}" + have_any_nl="yes" + ],[], ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 ) + + if test x$have_any_nl = xno ; then + # + # Try libnl 2.x + # + AC_CHECK_LIB(nl, nl_socket_alloc, + [ + # + # Yes, we have libnl 2.x. + # + LIBS="${libnldir} -lnl-genl -lnl $LIBS" + AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]) + AC_DEFINE(HAVE_LIBNL_2_x,1,[if libnl exists and is version 2.x]) + AC_DEFINE(HAVE_LIBNL_NLE,1,[libnl has NLE_FAILURE]) + AC_DEFINE(HAVE_LIBNL_SOCKETS,1,[libnl has new-style socket api]) + have_any_nl="yes" + ]) + fi + + if test x$have_any_nl = xno ; then + # + # No, we don't; do we have libnl 1.x? + # + AC_CHECK_LIB(nl, nl_handle_alloc, + [ + # + # Yes. + # + LIBS="${libnldir} -lnl $LIBS" + AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]) + have_any_nl="yes" + ]) + fi + + if test x$have_any_nl = xno ; then + # + # No, we don't have libnl at all. + # + if test x$with_libnl = xyes ; then + AC_MSG_ERROR([libnl support requested but libnl not found]) + fi + fi + fi + + AC_CHECK_HEADERS(linux/ethtool.h,,, + [ +AC_INCLUDES_DEFAULT +#include + ]) + AC_LBL_TPACKET_STATS + AC_LBL_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI + ;; + +bpf) + # + # Check whether we have the *BSD-style ioctls. + # + AC_CHECK_HEADERS(net/if_media.h) + + AC_MSG_CHECKING(whether the system supports zerocopy BPF) + AC_TRY_COMPILE( + [#include + #include + #include + #include ], + [return (BIOCROTZBUF + BPF_BUFMODE_ZBUF);], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_ZEROCOPY_BPF, 1, + [define if the system supports zerocopy BPF]) + ], + AC_MSG_RESULT(no)) + + # + # Check whether we have struct BPF_TIMEVAL. + # + AC_CHECK_TYPES(struct BPF_TIMEVAL,,, + [ +#include +#include +#ifdef HAVE_SYS_IOCCOM_H +#include +#endif +#include + ]) + ;; + +dag) + V_DEFS="$V_DEFS -DDAG_ONLY" + ;; + +septel) + V_DEFS="$V_DEFS -DSEPTEL_ONLY" + ;; + +snf) + V_DEFS="$V_DEFS -DSNF_ONLY" + ;; + +null) + AC_MSG_WARN(cannot determine packet capture interface) + AC_MSG_WARN((see the INSTALL doc for more info)) + ;; +esac + +dnl +dnl Now figure out how we get a list of interfaces and addresses, +dnl if we support capturing. Don't bother if we don't support +dnl capturing. +dnl +if test "$V_PCAP" = null +then + # + # We can't capture, so we can't open any capture + # devices, so we won't return any interfaces. + # + V_FINDALLDEVS=null +else + AC_CHECK_FUNC(getifaddrs,[ + # + # We have "getifaddrs()"; make sure we have + # as well, just in case some platform is really weird. + # + AC_CHECK_HEADER(ifaddrs.h,[ + # + # We have the header, so we use "getifaddrs()" to + # get the list of interfaces. + # + V_FINDALLDEVS=getad + ],[ + # + # We don't have the header - give up. + # XXX - we could also fall back on some other + # mechanism, but, for now, this'll catch this + # problem so that we can at least try to figure + # out something to do on systems with "getifaddrs()" + # but without "ifaddrs.h", if there is something + # we can do on those systems. + # + AC_MSG_ERROR([Your system has getifaddrs() but doesn't have a usable .]) + ]) + ],[ + # + # Well, we don't have "getifaddrs()", so we have to use + # some other mechanism; determine what that mechanism is. + # + # The first thing we use is the type of capture mechanism, + # which is somewhat of a proxy for the OS we're using. + # + case "$V_PCAP" in + + dlpi|libdlpi) + # + # This might be Solaris 8 or later, with + # SIOCGLIFCONF, or it might be some other OS + # or some older version of Solaris, with + # just SIOCGIFCONF. + # + AC_MSG_CHECKING(whether we have SIOCGLIFCONF) + AC_CACHE_VAL(ac_cv_lbl_have_siocglifconf, + AC_TRY_COMPILE( + [#include + #include + #include + #include + #include ], + [ioctl(0, SIOCGLIFCONF, (char *)0);], + ac_cv_lbl_have_siocglifconf=yes, + ac_cv_lbl_have_siocglifconf=no)) + AC_MSG_RESULT($ac_cv_lbl_have_siocglifconf) + if test $ac_cv_lbl_have_siocglifconf = yes ; then + V_FINDALLDEVS=glifc + else + V_FINDALLDEVS=gifc + fi + ;; + + *) + # + # Assume we just have SIOCGIFCONF. + # (XXX - on at least later Linux kernels, there's + # another mechanism, and we should be using that + # instead.) + # + V_FINDALLDEVS=gifc + ;; + esac]) +fi +]) + +AC_MSG_CHECKING(for socklen_t) +AC_TRY_COMPILE([ + #include + #include + ], + [ socklen_t x; ], + have_socklen_t=yes, + have_socklen_t=no) +if test "x$have_socklen_t" = "xyes"; then + AC_DEFINE(HAVE_SOCKLEN_T, 1, [define if socklen_t is defined]) +fi +AC_MSG_RESULT($have_socklen_t) + +AC_ARG_ENABLE(ipv6, +AC_HELP_STRING([--enable-ipv6],[build IPv6-capable version @<:@default=yes, if getaddrinfo available@:>@]), + [], + [enable_ipv6=ifavailable]) +if test "$enable_ipv6" != "no"; then + AC_CHECK_FUNC(getaddrinfo, + [ + AC_DEFINE(INET6,1,[IPv6]) + ], + [ + if test "$enable_ipv6" != "ifavailable"; then + AC_MSG_FAILURE([--enable-ipv6 was given, but getaddrinfo isn't available]) + fi + ]) +fi + +AC_MSG_CHECKING(whether to build optimizer debugging code) +AC_ARG_ENABLE(optimizer-dbg, +AC_HELP_STRING([--enable-optimizer-dbg],[build optimizer debugging code])) +if test "$enable_optimizer_dbg" = "yes"; then + AC_DEFINE(BDEBUG,1,[Enable optimizer debugging]) +fi +AC_MSG_RESULT(${enable_optimizer_dbg-no}) + +AC_MSG_CHECKING(whether to build parser debugging code) +AC_ARG_ENABLE(yydebug, +AC_HELP_STRING([--enable-yydebug],[build parser debugging code])) +if test "$enable_yydebug" = "yes"; then + AC_DEFINE(YYDEBUG,1,[Enable parser debugging]) +fi +AC_MSG_RESULT(${enable_yydebug-no}) + +# Check for Endace DAG card support. +AC_ARG_WITH([dag], +AC_HELP_STRING([--with-dag@<:@=DIR@:>@],[include Endace DAG support @<:@"yes", "no" or DIR; default="yes" on BSD and Linux if present@:>@]), +[ + if test "$withval" = no + then + # User doesn't want DAG support. + want_dag=no + elif test "$withval" = yes + then + # User wants DAG support but hasn't specified a directory. + want_dag=yes + else + # User wants DAG support and has specified a directory, so use the provided value. + want_dag=yes + dag_root=$withval + fi +],[ + # + # Use DAG API if present, otherwise don't + # + want_dag=ifpresent +]) + +AC_ARG_WITH([dag-includes], +AC_HELP_STRING([--with-dag-includes=DIR],[Endace DAG include directory]), +[ + # User wants DAG support and has specified a header directory, so use the provided value. + want_dag=yes + dag_include_dir=$withval +],[]) + +AC_ARG_WITH([dag-libraries], +AC_HELP_STRING([--with-dag-libraries=DIR],[Endace DAG library directory]), +[ + # User wants DAG support and has specified a library directory, so use the provided value. + want_dag=yes + dag_lib_dir=$withval +],[]) + +case "$V_PCAP" in +linux|bpf|dag) + # + # We support the DAG API if we're on Linux or BSD, or if we're + # building a DAG-only libpcap. + # + ;; +*) + # + # If the user explicitly requested DAG, tell them it's not + # supported. + # + # If they expressed no preference, don't include it. + # + if test $want_dag = yes; then + AC_MSG_ERROR([DAG support is only available with 'linux' 'bpf' and 'dag' packet capture types]) + elif test $want_dag = yes; then + want_dag=no + fi + ;; +esac + +ac_cv_lbl_dag_api=no +if test "$want_dag" != no; then + + AC_MSG_CHECKING([whether we have DAG API headers]) + + # If necessary, set default paths for DAG API headers and libraries. + if test -z "$dag_root"; then + dag_root=/usr/local + fi + + if test -z "$dag_include_dir"; then + dag_include_dir="$dag_root/include" + fi + + if test -z "$dag_lib_dir"; then + dag_lib_dir="$dag_root/lib" + fi + + if test -z "$dag_tools_dir"; then + dag_tools_dir="$dag_root/tools" + fi + + if test -r $dag_include_dir/dagapi.h; then + ac_cv_lbl_dag_api=yes + fi + AC_MSG_RESULT([$ac_cv_lbl_dag_api ($dag_include_dir)]) +fi + +if test $ac_cv_lbl_dag_api = yes; then + V_INCLS="$V_INCLS -I$dag_include_dir" + + if test $V_PCAP != dag ; then + SSRC="pcap-dag.c" + fi + + # See if we can find a general version string. + # Don't need to save and restore LIBS to prevent -ldag being + # included if there's a found-action (arg 3). + saved_ldflags=$LDFLAGS + LDFLAGS="-L$dag_lib_dir" + AC_CHECK_LIB([dag], [dag_attach_stream], [dag_streams="1"], [dag_streams="0"]) + AC_CHECK_LIB([dag],[dag_get_erf_types], [ + AC_DEFINE(HAVE_DAG_GET_ERF_TYPES, 1, [define if you have dag_get_erf_types()])]) + AC_CHECK_LIB([dag],[dag_get_stream_erf_types], [ + AC_DEFINE(HAVE_DAG_GET_STREAM_ERF_TYPES, 1, [define if you have dag_get_stream_erf_types()])]) + + LDFLAGS=$saved_ldflags + + if test "$dag_streams" = 1; then + AC_DEFINE(HAVE_DAG_STREAMS_API, 1, [define if you have streams capable DAG API]) + LIBS="$LIBS -ldag" + LDFLAGS="$LDFLAGS -L$dag_lib_dir" + + AC_CHECK_LIB([vdag],[vdag_set_device_info], [ac_dag_have_vdag="1"], [ac_dag_have_vdag="0"]) + if test "$ac_dag_have_vdag" = 1; then + AC_DEFINE(HAVE_DAG_VDAG, 1, [define if you have vdag_set_device_info()]) + LIBS="$LIBS -lpthread" + fi + fi + + AC_DEFINE(HAVE_DAG_API, 1, [define if you have the DAG API]) +fi + +AC_MSG_CHECKING(whether we have the DAG API) + +if test $ac_cv_lbl_dag_api = no; then + AC_MSG_RESULT(no) + if test "$want_dag" = yes; then + # User wanted DAG support but we couldn't find it. + AC_MSG_ERROR([DAG API requested, but not found at $dag_root: use --without-dag]) + fi + + if test "$V_PCAP" = dag; then + # User requested "dag" capture type but the DAG API wasn't + # found. + AC_MSG_ERROR([Specifying the capture type as "dag" requires the DAG API to be present; use the --with-dag options to specify the location. (Try "./configure --help" for more information.)]) + fi +else + AC_MSG_RESULT(yes) +fi + +AC_ARG_WITH(septel, +AC_HELP_STRING([--with-septel@<:@=DIR@:>@],[include Septel support (located in directory DIR, if supplied). @<:@default=yes, on Linux, if present@:>@]), +[ + if test "$withval" = no + then + want_septel=no + elif test "$withval" = yes + then + want_septel=yes + septel_root= + else + want_septel=yes + septel_root=$withval + fi +],[ + # + # Use Septel API if present, otherwise don't + # + want_septel=ifpresent + septel_root=./../septel +]) +ac_cv_lbl_septel_api=no +case "$V_PCAP" in +linux|septel) + # + # We support the Septel API if we're on Linux, or if we're building + # a Septel-only libpcap. + # + ;; +*) + # + # If the user explicitly requested Septel, tell them it's not + # supported. + # + # If they expressed no preference, don't include it. + # + if test $want_septel = yes; then + AC_MSG_ERROR(Septel support only available with 'linux' and 'septel' packet capture types) + elif test $want_septel = yes; then + want_septel=no + fi + ;; +esac + +if test "$with_septel" != no; then + AC_MSG_CHECKING(whether we have Septel API) + + if test -z "$septel_root"; then + septel_root=$srcdir/../septel + fi + + septel_tools_dir="$septel_root" + septel_include_dir="$septel_root/INC" + + ac_cv_lbl_septel_api=no + if test -r "$septel_include_dir/msg.h"; then + V_INCLS="$V_INCLS -I$septel_include_dir" + ADDLOBJS="$ADDLOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" + ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" + + if test "$V_PCAP" != septel ; then + SSRC="pcap-septel.c" + fi + ac_cv_lbl_septel_api=yes + fi + + AC_MSG_RESULT($ac_cv_lbl_septel_api) + if test $ac_cv_lbl_septel_api = no; then + if test "$want_septel" = yes; then + AC_MSG_ERROR(Septel API not found under directory $septel_root; use --without-septel) + fi + else + AC_DEFINE(HAVE_SEPTEL_API, 1, [define if you have a Septel API]) + fi +fi + +if test "$V_PCAP" = septel -a "$ac_cv_lbl_septel_api" = no; then + AC_MSG_ERROR(Specifying the capture type as 'septel' requires the Septel API to be present; use --with-septel=DIR) +fi + +# Check for Myricom SNF support. +AC_ARG_WITH([snf], +AC_HELP_STRING([--with-snf@<:@=DIR@:>@],[include Myricom SNF support @<:@"yes", "no" or DIR; default="yes" on BSD and Linux if present@:>@]), +[ + if test "$withval" = no + then + # User explicitly doesn't want SNF + want_snf=no + elif test "$withval" = yes + then + # User wants SNF support but hasn't specific a directory. + want_snf=yes + else + # User wants SNF support with a specified directory. + want_snf=yes + snf_root=$withval + fi +],[ + # + # Use Sniffer API if present, otherwise don't + # + want_snf=ifpresent +]) + +AC_ARG_WITH([snf-includes], +AC_HELP_STRING([--with-snf-includes=DIR],[Myricom SNF include directory]), +[ + # User wants SNF with specific header directory + want_snf=yes + snf_include_dir=$withval +],[]) + +AC_ARG_WITH([snf-libraries], +AC_HELP_STRING([--with-snf-libraries=DIR],[Myricom SNF library directory]), +[ + # User wants SNF with specific lib directory + want_snf=yes + snf_lib_dir=$withval +],[]) + +case "$V_PCAP" in +bpf|linux|snf) + # + # We support the Sniffer API if we're on BSD, Linux, or if we're + # building a Sniffer-only libpcap. + # + ;; +*) + # + # If the user explicitly requested Sniffer, tell them it's not + # supported. + # + # If they expressed no preference, don't include it. + # + if test $want_snf = yes; then + AC_MSG_ERROR(Myricom SNF support only available with 'bpf' 'linux' and 'snf' packet capture types) + elif test $want_snf = yes; then + want_snf=no + fi + ;; +esac + +ac_cv_lbl_snf_api=no +if test "$with_snf" != no; then + + AC_MSG_CHECKING(whether we have Myricom Sniffer API) + + if test -z "$snf_root"; then + snf_root=/opt/snf + fi + + if test -z "$snf_include_dir"; then + snf_include_dir="$snf_root/include" + fi + + if test -z "$snf_lib_dir"; then + snf_lib_dir="$snf_root/lib" + fi + + if test -f "$snf_include_dir/snf.h"; then + ac_cv_lbl_snf_api=yes + fi + AC_MSG_RESULT([$ac_cv_lbl_snf_api ($snf_root)]) + + if test $ac_cv_lbl_snf_api = no; then + if test "$want_snf" = yes; then + AC_MSG_ERROR(SNF API headers not found under $snf_include_dir; use --without-snf) + fi + else + saved_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -L$snf_lib_dir" + AC_CHECK_LIB([snf], [snf_init], [ac_cv_lbl_snf_api="yes"], [ac_cv_lbl_snf_api="no"]) + LDFLAGS="$saved_ldflags" + + if test $ac_cv_lbl_snf_api = no; then + if test "$want_snf" = yes; then + AC_MSG_ERROR(SNF API cannot correctly be linked check config.log; use --without-snf) + fi + else + V_INCLS="$V_INCLS -I$snf_include_dir" + LIBS="$LIBS -lsnf" + LDFLAGS="$LDFLAGS -L$snf_lib_dir" + if test "$V_PCAP" != snf ; then + SSRC="pcap-snf.c" + fi + AC_DEFINE(HAVE_SNF_API, 1, [define if you have Myricom SNF API]) + fi + fi +fi + +if test "$V_PCAP" = snf -a "$ac_cv_lbl_snf_api" = no; then + AC_MSG_ERROR(Specifying the capture type as 'snf' requires the Myricom Sniffer API to be present; use --with-snf=DIR) +fi + +AC_LBL_LEX_AND_YACC(V_LEX, V_YACC, pcap_) +if test "$V_LEX" = lex ; then +# Some versions of lex can't handle the definitions section of scanner.l . +# Try lexing it and complain if it can't deal. + AC_CACHE_CHECK([for capable lex], tcpdump_cv_capable_lex, + if lex -t scanner.l > /dev/null 2>&1; then + tcpdump_cv_capable_lex=yes + else + tcpdump_cv_capable_lex=insufficient + fi) + if test $tcpdump_cv_capable_lex = insufficient ; then + AC_MSG_ERROR([Your operating system's lex is insufficient to compile + libpcap. flex is a lex replacement that has many advantages, including + being able to compile libpcap. For more information, see + http://www.gnu.org/software/flex/flex.html .]) + fi +fi + +# +# Assume, by default, no support for shared libraries and V7/BSD convention +# for man pages (file formats in section 5, miscellaneous info in section 7). +# Individual cases can override this. +# +DYEXT="none" +MAN_FILE_FORMATS=5 +MAN_MISC_INFO=7 +case "$host_os" in + +aix*) + dnl Workaround to enable certain features + AC_DEFINE(_SUN,1,[define on AIX to get certain functions]) + + # + # AIX makes it fun to build shared and static libraries, + # because they're *both* ".a" archive libraries. We + # build the static library for the benefit of the traditional + # scheme of building libpcap and tcpdump in subdirectories of + # the same directory, with tcpdump statically linked with the + # libpcap in question, but we also build a shared library as + # "libpcap.shareda" and install *it*, rather than the static + # library, as "libpcap.a". + # + DYEXT="shareda" + + case "$V_PCAP" in + + dlpi) + # + # If we're using DLPI, applications will need to + # use /lib/pse.exp if present, as we use the + # STREAMS routines. + # + pseexe="/lib/pse.exp" + AC_MSG_CHECKING(for $pseexe) + if test -f $pseexe ; then + AC_MSG_RESULT(yes) + LIBS="-I:$pseexe" + fi + ;; + + bpf) + # + # If we're using BPF, we need "-lodm" and "-lcfg", as + # we use them to load the BPF module. + # + LIBS="-lodm -lcfg" + ;; + esac + ;; + +darwin*) + DYEXT="dylib" + V_CCOPT="$V_CCOPT -fno-common" + AC_ARG_ENABLE(universal, + AC_HELP_STRING([--disable-universal],[don't build universal on OS X])) + if test "$enable_universal" != "no"; then + case "$host_os" in + + darwin[0-7].*) + # + # Pre-Tiger. Build only for 32-bit PowerPC; no + # need for any special compiler or linker flags. + # + ;; + + darwin8.[0123]*) + # + # Tiger, prior to Intel support. Build for 32-bit + # PowerPC and 64-bit PowerPC, with 32-bit PowerPC + # first. (I'm guessing that's what Apple does.) + # + V_CCOPT="$V_CCOPT -arch ppc -arch ppc64" + LDFLAGS="$LDFLAGS -arch ppc -arch ppc64" + ;; + + darwin8.[456]*) + # + # Tiger, subsequent to Intel support but prior to + # x86-64 support. Build for 32-bit PowerPC, 64-bit + # PowerPC, and x86, with 32-bit PowerPC first. + # (I'm guessing that's what Apple does.) + # + V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386" + LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386" + ;; + + darwin8.*) + # + # All other Tiger, so subsequent to x86-64 + # support. Build for 32-bit PowerPC, 64-bit + # PowerPC, x86, and x86-64, and with 32-bit PowerPC + # first. (I'm guessing that's what Apple does.) + # + V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386 -arch x86_64" + LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386 -arch x86_64" + ;; + + darwin9.*) + # + # Leopard. Build for 32-bit PowerPC, 64-bit + # PowerPC, x86, and x86-64, with 32-bit PowerPC + # first. (That's what Apple does.) + # + V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386 -arch x86_64" + LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386 -arch x86_64" + ;; + + darwin10.*) + # + # Snow Leopard. Build for x86-64, x86, and + # 32-bit PowerPC, with x86-64 first. (That's + # what Apple does, even though Snow Leopard + # doesn't run on PPC, so PPC libpcap runs under + # Rosetta, and Rosetta doesn't support BPF + # ioctls, so PPC programs can't do live + # captures.) + # + V_CCOPT="$V_CCOPT -arch x86_64 -arch i386 -arch ppc" + LDFLAGS="$LDFLAGS -arch x86_64 -arch i386 -arch ppc" + ;; + + darwin*) + # + # Post-Snow Leopard. Build for x86-64 and + # x86, with x86-64 first. (That's probably what + # Apple does, given that Rosetta is gone.) + # XXX - update if and when Apple drops support + # for 32-bit x86 code. + # + V_CCOPT="$V_CCOPT -arch x86_64 -arch i386" + LDFLAGS="$LDFLAGS -arch x86_64 -arch i386" + ;; + esac + fi + ;; + +hpux9*) + AC_DEFINE(HAVE_HPUX9,1,[on HP-UX 9.x]) + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux10.0*) + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux10.1*) + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux*) + dnl HPUX 10.20 and above is similar to HPUX 9, but + dnl not the same.... + dnl + dnl XXX - DYEXT should be set to "sl" if this is building + dnl for 32-bit PA-RISC, but should be left as "so" for + dnl 64-bit PA-RISC or, I suspect, IA-64. + AC_DEFINE(HAVE_HPUX10_20_OR_LATER,1,[on HP-UX 10.20 or later]) + if test "`uname -m`" = "ia64"; then + DYEXT="so" + else + DYEXT="sl" + fi + + # + # "-b" builds a shared library; "+h" sets the soname. + # + SHLIB_OPT="-b" + SONAME_OPT="+h" + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +irix*) + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*) + DYEXT="so" + + # + # Compiler assumed to be GCC; run-time linker may require a -R + # flag. + # + if test "$libdir" != "/usr/lib"; then + V_RFLAGS=-Wl,-R$libdir + fi + ;; + +osf*) + DYEXT="so" + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +sinix*) + AC_MSG_CHECKING(if SINIX compiler defines sinix) + AC_CACHE_VAL(ac_cv_cc_sinix_defined, + AC_TRY_COMPILE( + [], + [int i = sinix;], + ac_cv_cc_sinix_defined=yes, + ac_cv_cc_sinix_defined=no)) + AC_MSG_RESULT($ac_cv_cc_sinix_defined) + if test $ac_cv_cc_sinix_defined = no ; then + AC_DEFINE(sinix,1,[on sinix]) + fi + ;; + +solaris*) + AC_DEFINE(HAVE_SOLARIS,1,[On solaris]) + + DYEXT="so" + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; +esac + +AC_ARG_ENABLE(shared, +AC_HELP_STRING([--enable-shared],[build shared libraries @<:@default=yes, if support available@:>@])) +test "x$enable_shared" = "xno" && DYEXT="none" + +AC_PROG_RANLIB +AC_CHECK_TOOL([AR], [ar]) + +AC_PROG_LN_S +AC_SUBST(LN_S) + +AC_LBL_DEVEL(V_CCOPT) + +AC_LBL_SOCKADDR_SA_LEN + +AC_LBL_SOCKADDR_STORAGE + +AC_LBL_HP_PPA_INFO_T_DL_MODULE_ID_1 + +AC_LBL_UNALIGNED_ACCESS + +# +# Makefile.in includes rules to generate version.h, so we assume +# that it will be generated if autoconf is used. +# +AC_DEFINE(HAVE_VERSION_H, 1, [define if version.h is generated in the build procedure]) + +rm -f net +ln -s ${srcdir}/bpf/net net + +AC_SUBST(V_CCOPT) +AC_SUBST(V_DEFS) +AC_SUBST(V_FINDALLDEVS) +AC_SUBST(V_INCLS) +AC_SUBST(V_LEX) +AC_SUBST(V_PCAP) +AC_SUBST(V_SHLIB_CMD) +AC_SUBST(V_SHLIB_OPT) +AC_SUBST(V_SONAME_OPT) +AC_SUBST(V_RPATH_OPT) +AC_SUBST(V_YACC) +AC_SUBST(ADDLOBJS) +AC_SUBST(ADDLARCHIVEOBJS) +AC_SUBST(SSRC) +AC_SUBST(DYEXT) +AC_SUBST(MAN_FILE_FORMATS) +AC_SUBST(MAN_MISC_INFO) + +AC_ARG_ENABLE([usb], +[AC_HELP_STRING([--enable-usb],[enable nusb support @<:@default=yes, if support available@:>@])], + [], + [enable_usb=yes]) + +if test "x$enable_usb" != "xno" ; then + dnl check for USB sniffing support + AC_MSG_CHECKING(for USB sniffing support) + case "$host_os" in + linux*) + AC_DEFINE(PCAP_SUPPORT_USB, 1, [target host supports USB sniffing]) + USB_SRC=pcap-usb-linux.c + AC_MSG_RESULT(yes) + ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null` + if test $? -ne 0 ; then + ac_usb_dev_name="usbmon" + fi + AC_DEFINE_UNQUOTED(LINUX_USB_MON_DEV, "/dev/$ac_usb_dev_name", [path for device for USB sniffing]) + AC_MSG_NOTICE(Device for USB sniffing is /dev/$ac_usb_dev_name) + # + # Do we have a version of available? + # If so, we might need it for . + # + AC_CHECK_HEADERS(linux/compiler.h) + if test "$ac_cv_header_linux_compiler_h" = yes; then + # + # Yes - include it when testing for . + # + AC_CHECK_HEADERS(linux/usbdevice_fs.h,,,[#include ]) + else + AC_CHECK_HEADERS(linux/usbdevice_fs.h) + fi + if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then + # + # OK, does it define bRequestType? Older versions of the kernel + # define fields with names like "requesttype, "request", and + # "value", rather than "bRequestType", "bRequest", and + # "wValue". + # + AC_MSG_CHECKING(if usbdevfs_ctrltransfer struct has bRequestType member) + AC_CACHE_VAL(ac_cv_usbdevfs_ctrltransfer_has_bRequestType, + AC_TRY_COMPILE([ +AC_INCLUDES_DEFAULT +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#ifdef HAVE_LINUX_COMPILER_H +#include +#endif +#include ], + [u_int i = sizeof(((struct usbdevfs_ctrltransfer *)0)->bRequestType)], + ac_cv_usbdevfs_ctrltransfer_has_bRequestType=yes, + ac_cv_usbdevfs_ctrltransfer_has_bRequestType=no)) + AC_MSG_RESULT($ac_cv_usbdevfs_ctrltransfer_has_bRequestType) + if test $ac_cv_usbdevfs_ctrltransfer_has_bRequestType = yes ; then + AC_DEFINE(HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE,1, + [if struct usbdevfs_ctrltransfer has bRequestType]) + fi + fi + ;; + *) + AC_MSG_RESULT(no) + ;; +esac +fi +AC_SUBST(PCAP_SUPPORT_USB) +AC_SUBST(USB_SRC) + +dnl check for netfilter sniffing support +AC_MSG_CHECKING(whether the platform could support netfilter sniffing) +case "$host_os" in +linux*) + AC_MSG_RESULT(yes) + # + # Life's too short to deal with trying to get this to compile + # if you don't get the right types defined with + # __KERNEL_STRICT_NAMES getting defined by some other include. + # + # Check whether the includes Just Work. If not, don't turn on + # netfilter support. + # + AC_MSG_CHECKING(whether we can compile the netfilter support) + AC_CACHE_VAL(ac_cv_netfilter_can_compile, + AC_TRY_COMPILE([ +AC_INCLUDES_DEFAULT +#include +#include +#include + +#include +#include +#include +#include +#include ], + [], + ac_cv_netfilter_can_compile=yes, + ac_cv_netfilter_can_compile=no)) + AC_MSG_RESULT($ac_cv_netfilter_can_compile) + if test $ac_cv_netfilter_can_compile = yes ; then + AC_DEFINE(PCAP_SUPPORT_NETFILTER, 1, + [target host supports netfilter sniffing]) + NETFILTER_SRC=pcap-netfilter-linux.c + fi + ;; +*) + AC_MSG_RESULT(no) + ;; +esac +AC_SUBST(PCAP_SUPPORT_NETFILTER) +AC_SUBST(NETFILTER_SRC) + +AC_ARG_ENABLE([bluetooth], +[AC_HELP_STRING([--enable-bluetooth],[enable Bluetooth support @<:@default=yes, if support available@:>@])], + [], + [enable_bluetooth=ifsupportavailable]) + +if test "x$enable_bluetooth" != "xno" ; then + dnl check for Bluetooth sniffing support + case "$host_os" in + linux*) + AC_CHECK_HEADER(bluetooth/bluetooth.h, + [ + AC_DEFINE(PCAP_SUPPORT_BT, 1, [target host supports Bluetooth sniffing]) + BT_SRC=pcap-bt-linux.c + AC_MSG_NOTICE(Bluetooth sniffing is supported) + + # + # OK, does struct sockaddr_hci have an hci_channel + # member? + # + AC_MSG_CHECKING(if struct sockaddr_hci has hci_channel member) + AC_CACHE_VAL(ac_cv_lbl_sockaddr_hci_has_hci_channel, + AC_TRY_COMPILE( +[ +#include +#include +], + [u_int i = sizeof(((struct sockaddr_hci *)0)->hci_channel)], + ac_cv_lbl_sockaddr_hci_has_hci_channel=yes, + ac_cv_lbl_sockaddr_hci_has_hci_channel=no)) + AC_MSG_RESULT($ac_cv_lbl_sockaddr_hci_has_hci_channel) + if test $ac_cv_lbl_sockaddr_hci_has_hci_channel = yes ; then + AC_DEFINE(SOCKADDR_HCI_HAS_HCI_CHANNEL,, + [if struct sockaddr_hci has hci_channel member]) + + # + # OK, is HCI_CHANNEL_MONITOR defined? + # + AC_MSG_CHECKING(if HCI_CHANNEL_MONITOR is defined) + AC_CACHE_VAL(ac_cv_lbl_hci_channel_monitor_is_defined, + AC_TRY_COMPILE( +[ +#include +#include +], + [u_int i = HCI_CHANNEL_MONITOR], + ac_cv_lbl_hci_channel_monitor_is_defined=yes, + ac_cv_lbl_hci_channel_monitor_is_defined=no)) + AC_MSG_RESULT($ac_cv_lbl_hci_channel_monitor_is_defined) + if test $ac_cv_lbl_hci_channel_monitor_is_defined = yes ; then + AC_DEFINE(PCAP_SUPPORT_BT_MONITOR,, + [target host supports Bluetooth Monitor]) + BT_MONITOR_SRC=pcap-bt-monitor-linux.c + fi + fi + ac_lbl_bluetooth_available=yes + ], + ac_lbl_bluetooth_available=no + ) + if test "x$ac_lbl_bluetooth_available" == "xno" ; then + if test "x$enable_bluetooth" = "xyes" ; then + AC_MSG_ERROR(Bluetooth sniffing is not supported; install bluez-lib devel to enable it) + else + AC_MSG_NOTICE(Bluetooth sniffing is not supported; install bluez-lib devel to enable it) + fi + fi + ;; + *) + if test "x$enable_bluetooth" = "xyes" ; then + AC_MSG_ERROR(no Bluetooth sniffing support implemented for $host_os) + else + AC_MSG_NOTICE(no Bluetooth sniffing support implemented for $host_os) + fi + ;; + esac + AC_SUBST(PCAP_SUPPORT_BT) + AC_SUBST(BT_SRC) + AC_SUBST(BT_MONITOR_SRC) +fi + +AC_ARG_ENABLE([canusb], +[AC_HELP_STRING([--enable-canusb],[enable canusb support @<:@default=yes, if support available@:>@])], + [], + [enable_canusb=ifsupportavailable]) + +if test "x$enable_canusb" != "xno" ; then + dnl check for canusb support + case "$host_os" in + linux*|uclinux*) + AC_CHECK_HEADER(libusb-1.0/libusb.h, + [ + AC_CHECK_LIB(usb-1.0, libusb_init, + [ + AC_DEFINE(PCAP_SUPPORT_CANUSB, 1, [target host supports canusb]) + CANUSB_SRC=pcap-canusb-linux.c + LIBS="-lusb-1.0 -lpthread $LIBS" + ac_lbl_has_libusb=yes + ], + ac_lbl_has_libusb=no, + -lpthread + ) + ], + ac_lbl_has_libusb=no + ) + if test "x$ac_lbl_has_libusb" = "xyes" ; then + AC_MSG_NOTICE(canusb sniffing is supported) + else + if test "x$enable_canusb" = "xyes" ; then + AC_MSG_ERROR(canusb sniffing is not supported; install libusb1.0 lib devel to enable it) + else + AC_MSG_NOTICE(canusb sniffing is not supported; install libusb1.0 lib devel to enable it) + fi + fi + ;; + *) + if test "x$enable_canusb" = "xyes" ; then + AC_MSG_ERROR(no canusb support implemented for $host_os) + else + AC_MSG_NOTICE(no canusb support implemented for $host_os) + fi + ;; + esac + AC_SUBST(PCAP_SUPPORT_CANUSB) + AC_SUBST(CANUSB_SRC) +fi + +AC_ARG_ENABLE([can], +[AC_HELP_STRING([--enable-can],[enable CAN support @<:@default=yes, if support available@:>@])], + [], + [enable_can=ifsupportavailable]) + +if test "x$enable_can" != "xno" ; then + dnl check for CAN sniffing support + case "$host_os" in + linux*) + AC_CHECK_HEADER(linux/can.h, + [ + AC_DEFINE(PCAP_SUPPORT_CAN, 1, [target host supports CAN sniffing]) + CAN_SRC=pcap-can-linux.c + AC_MSG_NOTICE(CAN sniffing is supported) + ], + [ + if test "x$enable_can" = "xyes" ; then + AC_MSG_ERROR(CAN sniffing is not supported) + else + AC_MSG_NOTICE(CAN sniffing is not supported) + fi + ], + [#include ] + ) + ;; + *) + if test "x$enable_can" = "xyes" ; then + AC_MSG_ERROR(no CAN sniffing support implemented for $host_os) + else + AC_MSG_NOTICE(no CAN sniffing support implemented for $host_os) + fi + ;; + esac + AC_SUBST(PCAP_SUPPORT_CAN) + AC_SUBST(CAN_SRC) +fi + +AC_ARG_ENABLE([dbus], +[AC_HELP_STRING([--enable-dbus],[enable D-Bus capture support @<:@default=yes, if support available@:>@])], + [], + [enable_dbus=ifavailable]) + +if test "x$enable_dbus" != "xno"; then + if test "x$enable_dbus" = "xyes"; then + case "$host_os" in + + darwin*) + # + # We don't support D-Bus sniffing on OS X; see + # + # https://bugs.freedesktop.org/show_bug.cgi?id=74029 + # + # The user requested it, so fail. + # + AC_MSG_ERROR([Due to freedesktop.org bug 74029, D-Bus capture support is not available on OS X]) + esac + else + case "$host_os" in + + darwin*) + # + # We don't support D-Bus sniffing on OS X; see + # + # https://bugs.freedesktop.org/show_bug.cgi?id=74029 + # + # The user dind't explicitly request it, so just + # silently refuse to enable it. + # + enable_dbus="no" + ;; + esac + fi +fi + +if test "x$enable_dbus" != "xno"; then + AC_CHECK_PROG([PKGCONFIG], [pkg-config], [pkg-config], [no]) + if test "x$PKGCONFIG" != "xno"; then + AC_MSG_CHECKING([for D-Bus]) + if "$PKGCONFIG" dbus-1; then + AC_MSG_RESULT([yes]) + DBUS_CFLAGS=`"$PKGCONFIG" --cflags dbus-1` + DBUS_LIBS=`"$PKGCONFIG" --libs dbus-1` + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + CFLAGS="$CFLAGS $DBUS_CFLAGS" + LIBS="$LIBS $DBUS_LIBS" + AC_MSG_CHECKING(whether the D-Bus library defines dbus_connection_read_write) + AC_TRY_LINK( + [#include + + #include + #include + + #include ], + [return dbus_connection_read_write(NULL, 0);], + [ + AC_MSG_RESULT([yes]) + AC_DEFINE(PCAP_SUPPORT_DBUS, 1, [support D-Bus sniffing]) + DBUS_SRC=pcap-dbus.c + V_INCLS="$V_INCLS $DBUS_CFLAGS" + ], + [ + AC_MSG_RESULT([no]) + if test "x$enable_dbus" = "xyes"; then + AC_MSG_ERROR([--enable-dbus was given, but the D-Bus library doesn't define dbus_connection_read_write()]) + fi + LIBS="$save_LIBS" + ]) + CFLAGS="$save_CFLAGS" + else + AC_MSG_RESULT([no]) + if test "x$enable_dbus" = "xyes"; then + AC_MSG_ERROR([--enable-dbus was given, but the dbus-1 package is not installed]) + fi + fi + fi + AC_SUBST(PCAP_SUPPORT_DBUS) + AC_SUBST(DBUS_SRC) +fi + +dnl check for hardware timestamp support +case "$host_os" in +linux*) + AC_CHECK_HEADERS([linux/net_tstamp.h]) + ;; +*) + AC_MSG_NOTICE(no hardware timestamp support implemented for $host_os) + ;; +esac + +dnl The packet ring capture facility of Linux, described in +dnl Documentation/networking/packet_mmap.txt, is not 32/64-bit compatible before +dnl version 2.6.27. A 32-bit kernel requires a 32-bit userland, and likewise for +dnl 64-bit. The effect of this is that a 32-bit libpcap binary will not run +dnl correctly on a 64-bit kernel (the binary will use the wrong offsets into a +dnl kernel struct). This problem was solved in Linux 2.6.27. Use +dnl --disable-packet-ring whenever a 32-bit application must run on a 64-bit +dnl target host, and either the build host or the target host run Linux 2.6.26 +dnl or earlier. +AC_ARG_ENABLE([packet-ring], +[AC_HELP_STRING([--enable-packet-ring],[enable Linux packet ring support @<:@default=yes@:>@])], +,enable_packet_ring=yes) + +if test "x$enable_packet_ring" != "xno" ; then + AC_DEFINE(PCAP_SUPPORT_PACKET_RING, 1, [use Linux packet ring capture if available]) + AC_SUBST(PCAP_SUPPORT_PACKET_RING) +fi + +AC_PROG_INSTALL + +AC_CONFIG_HEADER(config.h) + +AC_OUTPUT_COMMANDS([if test -f .devel; then + echo timestamp > stamp-h + cat Makefile-devel-adds >> Makefile + make depend +fi]) +AC_OUTPUT(Makefile pcap-filter.manmisc pcap-linktype.manmisc + pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap + pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap + pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap + pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap + pcap_open_offline.3pcap pcap_set_tstamp_precision.3pcap + pcap_set_tstamp_type.3pcap) +exit 0 diff --git a/tcpdump/jni/libpcap/dlpisubs.c b/tcpdump/jni/libpcap/dlpisubs.c new file mode 100644 index 0000000..131fa27 --- /dev/null +++ b/tcpdump/jni/libpcap/dlpisubs.c @@ -0,0 +1,367 @@ +/* + * This code is derived from code formerly in pcap-dlpi.c, originally + * contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), University College + * London, and subsequently modified by Guy Harris (guy@alum.mit.edu), + * Mark Pizzolato , + * Mark C. Brown (mbrown@hp.com), and Sagun Shakya . + */ + +/* + * This file contains dlpi/libdlpi related common functions used + * by pcap-[dlpi,libdlpi].c. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef DL_IPATM +#define DL_IPATM 0x12 /* ATM Classical IP interface */ +#endif + +#ifdef HAVE_SYS_BUFMOD_H + /* + * Size of a bufmod chunk to pass upstream; that appears to be the + * biggest value to which you can set it, and setting it to that value + * (which is bigger than what appears to be the Solaris default of 8192) + * reduces the number of packet drops. + */ +#define CHUNKSIZE 65536 + + /* + * Size of the buffer to allocate for packet data we read; it must be + * large enough to hold a chunk. + */ +#define PKTBUFSIZE CHUNKSIZE + +#else /* HAVE_SYS_BUFMOD_H */ + + /* + * Size of the buffer to allocate for packet data we read; this is + * what the value used to be - there's no particular reason why it + * should be tied to MAXDLBUF, but we'll leave it as this for now. + */ +#define MAXDLBUF 8192 +#define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32)) + +#endif + +#include +#include +#ifdef HAVE_SYS_BUFMOD_H +#include +#endif +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBDLPI +#include +#endif + +#include "pcap-int.h" +#include "dlpisubs.h" + +#ifdef HAVE_SYS_BUFMOD_H +static void pcap_stream_err(const char *, int, char *); +#endif + +/* + * Get the packet statistics. + */ +int +pcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_dlpi *pd = p->priv; + + /* + * "ps_recv" counts packets handed to the filter, not packets + * that passed the filter. As filtering is done in userland, + * this would not include packets dropped because we ran out + * of buffer space; in order to make this more like other + * platforms (Linux 2.4 and later, BSDs with BPF), where the + * "packets received" count includes packets received but dropped + * due to running out of buffer space, and to keep from confusing + * applications that, for example, compute packet drop percentages, + * we also make it count packets dropped by "bufmod" (otherwise we + * might run the risk of the packet drop count being bigger than + * the received-packet count). + * + * "ps_drop" counts packets dropped by "bufmod" because of + * flow control requirements or resource exhaustion; it doesn't + * count packets dropped by the interface driver, or packets + * dropped upstream. As filtering is done in userland, it counts + * packets regardless of whether they would've passed the filter. + * + * These statistics don't include packets not yet read from + * the kernel by libpcap, but they may include packets not + * yet read from libpcap by the application. + */ + *ps = pd->stat; + + /* + * Add in the drop count, as per the above comment. + */ + ps->ps_recv += ps->ps_drop; + return (0); +} + +/* + * Loop through the packets and call the callback for each packet. + * Return the number of packets read. + */ +int +pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user, + int count, u_char *bufp, int len) +{ + struct pcap_dlpi *pd = p->priv; + int n, caplen, origlen; + u_char *ep, *pk; + struct pcap_pkthdr pkthdr; +#ifdef HAVE_SYS_BUFMOD_H + struct sb_hdr *sbp; +#ifdef LBL_ALIGN + struct sb_hdr sbhdr; +#endif +#endif + + /* Loop through packets */ + ep = bufp + len; + n = 0; + +#ifdef HAVE_SYS_BUFMOD_H + while (bufp < ep) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->bp = bufp; + p->cc = ep - bufp; + return (n); + } + } +#ifdef LBL_ALIGN + if ((long)bufp & 3) { + sbp = &sbhdr; + memcpy(sbp, bufp, sizeof(*sbp)); + } else +#endif + sbp = (struct sb_hdr *)bufp; + pd->stat.ps_drop = sbp->sbh_drops; + pk = bufp + sizeof(*sbp); + bufp += sbp->sbh_totlen; + origlen = sbp->sbh_origlen; + caplen = sbp->sbh_msglen; +#else + origlen = len; + caplen = min(p->snapshot, len); + pk = bufp; + bufp += caplen; +#endif + ++pd->stat.ps_recv; + if (bpf_filter(p->fcode.bf_insns, pk, origlen, caplen)) { +#ifdef HAVE_SYS_BUFMOD_H + pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; + pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; +#else + (void) gettimeofday(&pkthdr.ts, NULL); +#endif + pkthdr.len = origlen; + pkthdr.caplen = caplen; + /* Insure caplen does not exceed snapshot */ + if (pkthdr.caplen > p->snapshot) + pkthdr.caplen = p->snapshot; + (*callback)(user, &pkthdr, pk); + if (++n >= count && !PACKET_COUNT_IS_UNLIMITED(count)) { + p->cc = ep - bufp; + p->bp = bufp; + return (n); + } + } +#ifdef HAVE_SYS_BUFMOD_H + } +#endif + p->cc = 0; + return (n); +} + +/* + * Process the mac type. Returns -1 if no matching mac type found, otherwise 0. + */ +int +pcap_process_mactype(pcap_t *p, u_int mactype) +{ + int retv = 0; + + switch (mactype) { + + case DL_CSMACD: + case DL_ETHER: + p->linktype = DLT_EN10MB; + p->offset = 2; + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *)malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (p->dlt_list != NULL) { + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + } + break; + + case DL_FDDI: + p->linktype = DLT_FDDI; + p->offset = 3; + break; + + case DL_TPR: + /* XXX - what about DL_TPB? Is that Token Bus? */ + p->linktype = DLT_IEEE802; + p->offset = 2; + break; + +#ifdef HAVE_SOLARIS + case DL_IPATM: + p->linktype = DLT_SUNATM; + p->offset = 0; /* works for LANE and LLC encapsulation */ + break; +#endif + + default: + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype %u", + mactype); + retv = -1; + } + + return (retv); +} + +#ifdef HAVE_SYS_BUFMOD_H +/* + * Push and configure the buffer module. Returns -1 for error, otherwise 0. + */ +int +pcap_conf_bufmod(pcap_t *p, int snaplen) +{ + struct timeval to; + bpf_u_int32 ss, chunksize; + + /* Non-standard call to get the data nicely buffered. */ + if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { + pcap_stream_err("I_PUSH bufmod", errno, p->errbuf); + return (-1); + } + + ss = snaplen; + if (ss > 0 && + strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { + pcap_stream_err("SBIOCSSNAP", errno, p->errbuf); + return (-1); + } + + if (p->opt.immediate) { + /* Set the timeout to zero, for immediate delivery. */ + to.tv_sec = 0; + to.tv_usec = 0; + if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { + pcap_stream_err("SBIOCSTIME", errno, p->errbuf); + return (-1); + } + } else { + /* Set up the bufmod timeout. */ + if (p->opt.timeout != 0) { + to.tv_sec = p->opt.timeout / 1000; + to.tv_usec = (p->opt.timeout * 1000) % 1000000; + if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { + pcap_stream_err("SBIOCSTIME", errno, p->errbuf); + return (-1); + } + } + + /* Set the chunk length. */ + chunksize = CHUNKSIZE; + if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) + != 0) { + pcap_stream_err("SBIOCSCHUNKP", errno, p->errbuf); + return (-1); + } + } + + return (0); +} +#endif /* HAVE_SYS_BUFMOD_H */ + +/* + * Allocate data buffer. Returns -1 if memory allocation fails, else 0. + */ +int +pcap_alloc_databuf(pcap_t *p) +{ + p->bufsize = PKTBUFSIZE; + p->buffer = (u_char *)malloc(p->bufsize + p->offset); + if (p->buffer == NULL) { + strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); + return (-1); + } + + return (0); +} + +/* + * Issue a STREAMS I_STR ioctl. Returns -1 on error, otherwise + * length of returned data on success. + */ +int +strioctl(int fd, int cmd, int len, char *dp) +{ + struct strioctl str; + int retv; + + str.ic_cmd = cmd; + str.ic_timout = -1; + str.ic_len = len; + str.ic_dp = dp; + if ((retv = ioctl(fd, I_STR, &str)) < 0) + return (retv); + + return (str.ic_len); +} + +#ifdef HAVE_SYS_BUFMOD_H +/* + * Write stream error message to errbuf. + */ +static void +pcap_stream_err(const char *func, int err, char *errbuf) +{ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", func, pcap_strerror(err)); +} +#endif diff --git a/tcpdump/jni/libpcap/dlpisubs.h b/tcpdump/jni/libpcap/dlpisubs.h new file mode 100644 index 0000000..cdc531c --- /dev/null +++ b/tcpdump/jni/libpcap/dlpisubs.h @@ -0,0 +1,38 @@ +#ifndef dlpisubs_h +#define dlpisubs_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Private data for capturing on DLPI devices. + */ +struct pcap_dlpi { +#ifdef HAVE_LIBDLPI + dlpi_handle_t dlpi_hd; +#endif /* HAVE_LIBDLPI */ +#ifdef DL_HP_RAWDLS + int send_fd; +#endif /* DL_HP_RAWDLS */ + + struct pcap_stat stat; +}; + +/* + * Functions defined by dlpisubs.c. + */ +int pcap_stats_dlpi(pcap_t *, struct pcap_stat *); +int pcap_process_pkts(pcap_t *, pcap_handler, u_char *, int, u_char *, int); +int pcap_process_mactype(pcap_t *, u_int); +#ifdef HAVE_SYS_BUFMOD_H +int pcap_conf_bufmod(pcap_t *, int); +#endif +int pcap_alloc_databuf(pcap_t *); +int strioctl(int, int, int, char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tcpdump/jni/libpcap/doc/pcap.html b/tcpdump/jni/libpcap/doc/pcap.html new file mode 100644 index 0000000..cb6abe5 --- /dev/null +++ b/tcpdump/jni/libpcap/doc/pcap.html @@ -0,0 +1,997 @@ + +PCAP New Generation Dump File Format + + + + + + +
     TOC 
    +
    + + + + +
    Network Working GroupL. Degioanni
    Internet-DraftF. Risso
    Expires: August 30, 2004Politecnico di Torino
     March 2004
    +

    +

    pcap
    + +

    Status of this Memo

    +

    +This document is an Internet-Draft and is +in full conformance with all provisions of Section 10 of RFC2026.

    +

    +Internet-Drafts are working documents of the Internet Engineering +Task Force (IETF), its areas, and its working groups. +Note that other groups may also distribute working documents as +Internet-Drafts.

    +

    +Internet-Drafts are draft documents valid for a maximum of six months +and may be updated, replaced, or obsoleted by other documents at any time. +It is inappropriate to use Internet-Drafts as reference material or to cite +them other than as "work in progress."

    +

    +The list of current Internet-Drafts can be accessed at +http://www.ietf.org/ietf/1id-abstracts.txt.

    +

    +The list of Internet-Draft Shadow Directories can be accessed at +http://www.ietf.org/shadow.html.

    +

    +This Internet-Draft will expire on August 30, 2004.

    + +

    Copyright Notice

    +

    +Copyright (C) The Internet Society (2004). All Rights Reserved.

    + +

    Abstract

    + +

    This document describes a format to dump captured packets on a file. This format is extensible and it is currently proposed for implementation in the libpcap/WinPcap packet capture library. +



    +

    Table of Contents

    +

    +1.  +Objectives
    +2.  +General File Structure
    +2.1  +General Block Structure
    +2.2  +Block Types
    +2.3  +Block Hierarchy and Precedence
    +2.4  +Data format
    +3.  +Block Definition
    +3.1  +Section Header Block (mandatory)
    +3.2  +Interface Description Block (mandatory)
    +3.3  +Packet Block (optional)
    +3.4  +Simple Packet Block (optional)
    +3.5  +Name Resolution Block (optional)
    +3.6  +Interface Statistics Block (optional)
    +4.  +Options
    +5.  +Experimental Blocks (deserved to a further investigation)
    +5.1  +Other Packet Blocks (experimental)
    +5.2  +Compression Block (experimental)
    +5.3  +Encryption Block (experimental)
    +5.4  +Fixed Length Block (experimental)
    +5.5  +Directory Block (experimental)
    +5.6  +Traffic Statistics and Monitoring Blocks (experimental)
    +5.7  +Event/Security Block (experimental)
    +6.  +Conclusions
    +7.  +Most important open issues
    +§  +Intellectual Property and Copyright Statements
    +

    +
    + +

    +
     TOC 
    +

    1. Objectives

    + +

    The problem of exchanging packet traces becomes more and more critical every day; unfortunately, no standard solutions exist for this task right now. One of the most accepted packet interchange formats is the one defined by libpcap, which is rather old and does not fit for some of the nowadays applications especially in terms of extensibility. +

    +

    This document proposes a new format for dumping packet traces. The following goals are being pursued: +

    +
      +
    • Extensibility: aside of some common functionalities, third parties should be able to enrich the information embedded in the file with proprietary extensions, which will be ignored by tools that are not able to understand them. +
    • +
    • Portability: a capture trace must contain all the information needed to read data independently from network, hardware and operating system of the machine that made the capture. +
    • +
    • Merge/Append data: it should be possible to add data at the end of a given file, and the resulting file must still be readable. +
    • +
    +

    +
     TOC 
    +

    2. General File Structure

    + +

    2.1 General Block Structure

    + +

    A capture file is organized in blocks, that are appended one to another to form the file. All the blocks share a common format, which is shown in Figure 1. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                          Block Type                           |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                      Block Total Length                       |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   /                          Block Body                           /
    +   /          /* variable length, aligned to 32 bits */            /
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                      Block Total Length                       |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +
    +
     Basic block structure. 

    + +

    The fields have the following meaning: +

    +
      +
    • Block Type (32 bits): unique value that identifies the block. Values whose Most Significant Bit (MSB) is equal to 1 are reserved for local use. They allow to save private data to the file and to extend the file format. +
    • +
    • Block Total Length: total size of this block, in bytes. For instance, a block that does not have a body has a length of 12 bytes. +
    • +
    • Block Body: content of the block. +
    • +
    • Block Total Length: total size of this block, in bytes. This field is duplicated for permitting backward file navigation. +
    • +
    +

    This structure, shared among all blocks, makes easy to process a file and to skip unneeded or unknown blocks. Blocks can be nested one inside the others (NOTE: needed?). Some of the blocks are mandatory, i.e. a dump file is not valid if they are not present, other are optional. +

    +

    The structure of the blocks allows to define other blocks if needed. A parser that does non understand them can simply ignore their content. +

    +

    2.2 Block Types

    + +

    The currently defined blocks are the following: +

    +
      +
    1. Section Header Block: it defines the most important characteristics of the capture file. +
    2. +
    3. Interface Description Block: it defines the most important characteristics of the interface(s) used for capturing traffic. +
    4. +
    5. Packet Block: it contains a single captured packet, or a portion of it. +
    6. +
    7. Simple Packet Block: it contains a single captured packet, or a portion of it, with only a minimal set of information about it. +
    8. +
    9. Name Resolution Block: it defines the mapping from numeric addresses present in the packet dump and the canonical name counterpart. +
    10. +
    11. Capture Statistics Block: it defines how to store some statistical data (e.g. packet dropped, etc) which can be useful to undestand the conditions in which the capture has been made. +
    12. +
    13. Compression Marker Block: TODO +
    14. +
    15. Encryption Marker Block: TODO +
    16. +
    17. Fixed Length Marker Block: TODO +
    18. +
    +

    The following blocks instead are considered interesting but the authors believe that they deserve more in-depth discussion before being defined: +

    +
      +
    1. Further Packet Blocks +
    2. +
    3. Directory Block +
    4. +
    5. Traffic Statistics and Monitoring Blocks +
    6. +
    7. Alert and Security Blocks +
    8. +
    +

    TODO Currently standardized Block Type codes are specified in Appendix 1. +

    +

    2.3 Block Hierarchy and Precedence

    + +

    The file must begin with a Section Header Block. However, more than one Section Header Block can be present on the dump, each one covering the data following it till the next one (or the end of file). A Section includes the data delimited by two Section Header Blocks (or by a Section Header Block and the end of the file), including the first Section Header Block. +

    +

    In case an application cannot read a Section because of different version number, it must skip everything until the next Section Header Block. Note that, in order to properly skip the blocks until the next section, all blocks must have the fields Type and Length at the beginning. This is a mandatory requirement that must be maintained in future versions of the block format. +

    +

    Figure 2 shows two valid files: the first has a typical configuration, with a single Section Header that covers the whole file. The second one contains three headers, and is normally the result of file concatenation. An application that understands only version 1.0 of the file format skips the intermediate section and restart processing the packets after the third Section Header. +



    + +
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   | SHB v1.0  |                      Data                         |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   Typical configuration with a single Section Header Block
    +
    +
    +   |--   1st Section   --|--   2nd Section   --|--  3rd Section  --|
    +   |                                                               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   | SHB v1.0  |  Data   | SHB V1.1  |  Data   | SHB V1.0  |  Data |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   Configuration with three different Section Header Blocks
    +
    +
     File structure example: the Section Header Block. 

    + +

    NOTE: TO BE COMPLETED with some examples of other blocks +

    +

    2.4 Data format

    + +

    Data contained in each section will always be saved according to the characteristics (little endian / big endian) of the dumping machine. This refers to all fields that are saved as numbers and that span over two or more bytes. +

    +

    The approach of having each section saved in the native format of the generating host is more efficient because it avoids translation of data when reading / writing on the host itself, which is the most common case when generating/processing capture dumps. +

    +

    TODO Probably we have to specify something more here. Is what we're saying enough to avoid any kind of ambiguity?. +

    +

    +
     TOC 
    +

    3. Block Definition

    + +

    This section details the format of the body of the blocks currently defined. +

    +

    3.1 Section Header Block (mandatory)

    + +

    The Section Header Block is mandatory. It identifies the beginning of a section of the capture dump file. Its format is shown in Figure 3. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                            Magic                              |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |              Major            |             Minor             |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   /                                                               /
    +   /                      Options (variable)                       /
    +   /                                                               /
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +
    +
     Section Header Block format. 

    + +

    The meaning of the fields is: +

    +
      +
    • Magic: magic number, whose value is the hexadecimal number 0x1A2B3C4D. This number can be used to distinguish section that have been saved on little-endian machines from the one saved on big-endian machines. +
    • +
    • Major: number of the current mayor version of the format. Current value is 1. +
    • +
    • Minor: number of the current minor version of the format. Current value is 0. +
    • +
    • Options: optionally, a list of options (formatted according to the rules defined in Section 4) can be present. +
    • +
    +

    Aside form the options defined in Section 4, the following options are valid within this block: +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameCodeLengthDescription
    Hardware2variableAn ascii string containing the description of the hardware used to create this section.
    Operating System3variableAn ascii string containing the name of the operating system used to create this section.
    User Application3variableAn ascii string containing the name of the application used to create this section.
    + +

    The Section Header Block does not contain data but it rather identifies a list of blocks (interfaces, packets) that are logically correlated. This block does not contain any reference to the size of the section it is currently delimiting, therefore the reader cannot skip a whole section at once. In case a section must be skipped, the user has to repeatedly skip all the blocks contained within it; this makes the parsing of the file slower but it permits to append several capture dumps at the same file. +

    +

    3.2 Interface Description Block (mandatory)

    + +

    The Interface Description Block is mandatory. This block is needed to specify the characteristics of the network interface on which the capture has been made. In order to properly associate the captured data to the corresponding interface, the Interface Description Block must be defined before any other block that uses it; therefore, this block is usually placed immediately after the Section Header Block. +

    +

    An Interface Description Block is valid only inside the section which it belongs to. The structure of a Interface Description Block is shown in Figure 4. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |          Interface ID         |           LinkType            |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                            SnapLen                            |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   /                                                               /
    +   /                      Options (variable)                       /
    +   /                                                               /
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + 
    +
     Interface Description Block format. 

    + +

    The meaning of the fields is: +

    +
      +
    • Interface ID: a progressive number that identifies uniquely any interface inside current section. Two Interface Description Blocks can have the same Interface ID only if they are in different sections of the file. The Interface ID is referenced by the packet blocks. +
    • +
    • LinkType: a value that defines the link layer type of this interface. +
    • +
    • SnapLen: maximum number of bytes dumped from each packet. The portion of each packet that exceeds this value will not be stored in the file. +
    • +
    • Options: optionally, a list of options (formatted according to the rules defined in Section 4) can be present. +
    • +
    +

    In addition to the options defined in Section 4, the following options are valid within this block: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameCodeLengthDescription
    if_name2VariableName of the device used to capture data.
    if_IPv4addr38Interface network address and netmask.
    if_IPv6addr417Interface network address and prefix length (stored in the last byte).
    if_MACaddr56Interface Hardware MAC address (48 bits).
    if_EUIaddr68Interface Hardware EUI address (64 bits), if available.
    if_speed78Interface speed (in bps).
    if_tsaccur81Precision of timestamps. If the Most Significant Bit is equal to zero, the remaining bits indicates the accuracy as as a negative power of 10 (e.g. 6 means microsecond accuracy). If the Most Significant Bit is equal to zero, the remaining bits indicates the accuracy as as negative power of 2 (e.g. 10 means 1/1024 of second). If this option is not present, a precision of 10^-6 is assumed.
    if_tzone94Time zone for GMT support (TODO: specify better).
    if_flags104Interface flags. (TODO: specify better. Possible flags: promiscuous, inbound/outbound, traffic filtered during capture).
    if_filter11variableThe filter (e.g. "capture only TCP traffic") used to capture traffic. The first byte of the Option Data keeps a code of the filter used (e.g. if this is a libpcap string, or BPF bytecode, and more). More details about this format will be presented in Appendix XXX (TODO).
    if_opersystem12variableAn ascii string containing the name of the operating system of the machine that hosts this interface. This can be different from the same information that can be contained by the Section Header Block (Section 3.1) because the capture can have been done on a remote machine.
    + +

    3.3 Packet Block (optional)

    + +

    A Packet Block is the standard container for storing the packets coming from the network. The Packet Block is optional because packets can be stored either by means of this block or the Simple Packet Block, which can be used to speed up dump generation. The format of a packet block is shown in Figure 5. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |         Interface ID          |          Drops Count          |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                        Timestamp (High)                       |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                        Timestamp (Low)                        |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                         Captured Len                          |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                          Packet Len                           |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                                                               |
    +   |                          Packet Data                          |
    +   |                                                               |
    +   |              /* variable length, byte-aligned */              |
    +   |                                                               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   /                                                               /
    +   /                      Options (variable)                       /
    +   /                                                               /
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +
    +
     Packet Block format. 

    + +

    The Packet Block has the following fields: +

    +
      +
    • Interface ID: Specifies the interface this packet comes from, and corresponds to the ID of one of the Interface Description Blocks present in this section of the file (see Figure 4). +
    • +
    • Drops Count: a local drop counter. It specified the number of packets lost (by the interface and the operating system) between this packet and the preceding one. The value xFFFF (in hexadecimal) is reserved for those systems in which this information is not available. +
    • +
    • Timestamp (High): the most significative part of the timestamp. in standard Unix format, i.e. from 1/1/1970. +
    • +
    • Timestamp (Low): the less significative part of the timestamp. The way to interpret this field is specified by the 'ts_accur' option (see Figure 4) of the Interface Description block referenced by this packet. If the Interface Description block does not contain a 'ts_accur' option, then this field is expressed in microseconds. +
    • +
    • Captured Len: number of bytes captured from the packet (i.e. the length of the Packet Data field). It will be the minimum value among the actual Packet Length and the snapshot length (defined in Figure 4). +
    • +
    • Packet Len: actual length of the packet when it was transmitted on the network. Can be different from Captured Len if the user wants only a snapshot of the packet. +
    • +
    • Packet Data: the data coming from the network, including link-layer headers. The length of this field is Captured Len. The format of the link-layer headers depends on the LinkType field specified in the Interface Description Block (see Section 3.2) and it is specified in Appendix XXX (TODO). +
    • +
    • Options: optionally, a list of options (formatted according to the rules defined in Section 4) can be present. +
    • +
    +

    +

    +

    3.4 Simple Packet Block (optional)

    + +

    The Simple Packet Block is a lightweight container for storing the packets coming from the network. Its presence is optional. +

    +

    A Simple Packet Block is similar to a Packet Block (see Section 3.3), but it is smaller, simpler to process and contains only a minimal set of information. This block is preferred to the standard Packet Block when performance or space occupation are critical factors, such as in sustained traffic dump applications. A capture file can contain both Packet Blocks and Simple Packet Blocks: for example, a capture tool could switch from Packet Blocks to Simple Packet Blocks when the hardware resources become critical. +

    +

    The Simple Packet Block does not contain the Interface ID field. Therefore, it must be assumed that all the Simple Packet Blocks have been captured on the interface previously specified in the Interface Description Block. +

    +

    Figure 6 shows the format of the Simple Packet Block. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                          Packet Len                           |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                                                               |
    +   |                          Packet Data                          |
    +   |                                                               |
    +   |              /* variable length, byte-aligned */              |
    +   |                                                               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + 
    +
     Simple Packet Block format. 

    + +

    The Packet Block has the following fields: +

    +
      +
    • Packet Len: actual length of the packet when it was transmitted on the network. Can be different from captured len if the packet has been truncated. +
    • +
    • Packet data: the data coming from the network, including link-layers headers. The length of this field can be derived from the field Block Total Length, present in the Block Header. +
    • +
    +

    The Simple Packet Block does not contain the timestamp because this is one of the most costly operations on PCs. Additionally, there are applications that do not require it; e.g. an Intrusion Detection System is interested in packets, not in their timestamp. +

    +

    The Simple Packet Block is very efficient in term of disk space: a snapshot of length 100 bytes requires only 16 bytes of overhead, which corresponds to an efficiency of more than 86%. +

    +

    3.5 Name Resolution Block (optional)

    + +

    The Name Resolution Block is used to support the correlation of numeric addresses (present in the captured packets) and their corresponding canonical names and it is optional. Having the literal names saved in the file, this prevents the need of a name resolution in a delayed time, when the association between names and addresses can be different from the one in use at capture time. Moreover, The Name Resolution Block avoids the need of issuing a lot of DNS requests every time the trace capture is opened, and allows to have name resolution also when reading the capture with a machine not connected to the network. +

    +

    The format of the Name Resolution Block is shown in Figure 7. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |      Record Type              |         Record Length         |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                       Record Value                            |
    +   |              /* variable length, byte-aligned */              |
    +   |               + + + + + + + + + + + + + + + + + + + + + + + + +
    +   |               |               |               |               |
    +   +-+-+-+-+-+-+-+-+ + + + + + + + + + + + + + + + + + + + + + + + +
    +             . . . other records . . .
    +   |  Record Type == end_of_recs   |  Record Length == 00          |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   /                                                               /
    +   /                      Options (variable)                       /
    +   /                                                               /
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + 
    +
     Name Resolution Block format. 

    + +

    A Name Resolution Block is a zero-terminated list of records (in the TLV format), each of which contains an association between a network address and a name. There are three possible types of records: +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameCodeLengthDescription
    end_of_recs00End of records
    ip4_rec1VariableSpecifies an IPv4 address (contained in the first 4 bytes), followed by one or more zero-terminated strings containing the DNS entries for that address.
    ip6_rec1VariableSpecifies an IPv6 address (contained in the first 16 bytes), followed by one or more zero-terminated strings containing the DNS entries for that address.
    + +

    After the list or Name Resolution Records, optionally, a list of options (formatted according to the rules defined in Section 4) can be present. +

    +

    A Name Resolution Block is normally placed at the beginning of the file, but no assumptions can be taken about its position. Name Resolution Blocks can be added in a second time by tools that process the file, like network analyzers. +

    +

    In addiction to the options defined in Section 4, the following options are valid within this block: +

    + + + + + + + + + + + + +
    NameCodeLengthDescription
    ns_dnsname2VariableAn ascii string containing the name of the machine (DNS server) used to perform the name resolution.
    + +

    3.6 Interface Statistics Block (optional)

    + +

    The Interface Statistics Block contains the capture statistics for a given interface and it is optional. The statistics are referred to the interface defined in the current Section identified by the Interface ID field. +

    +

    The format of the Interface Statistics Block is shown in Figure 8. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                         IfRecv                                |
    +   |                          (high + low)                         |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                         IfDrop                                |
    +   |                          (high + low)                         |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                         FilterAccept                          |
    +   |                          (high + low)                         |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                         OSDrop                                |
    +   |                          (high + low)                         |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                         UsrDelivered                          |
    +   |                          (high + low)                         |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |          Interface ID         |           Reserved            |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   /                                                               /
    +   /                      Options (variable)                       /
    +   /                                                               /
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + 
    +
     Interface Statistics Block format. 

    + +

    The fields have the following meaning: +

    +
      +
    • IfRecv: number of packets received from the interface during the capture. This number is reported as a 64 bits value, in which the most significat bits are located in the first four bytes of the field. +
    • +
    • IfDrop: number of packets dropped by the interface during the capture due to lack of resources. +
    • +
    • FilterAccept: number of packets accepeted by filter during current capture. +
    • +
    • OSDrop: number of packets dropped by the operating system during the capture. +
    • +
    • UsrDelivered: number of packets delivered to the user. UsrDelivered can be different from the value 'FilterAccept - OSDropped' because some packets could still lay in the OS buffers when the capture ended. +
    • +
    • Interface ID: reference to an Interface Description Block. +
    • +
    • Reserved: Reserved to future use. +
    • +
    • Options: optionally, a list of options (formatted according to the rules defined in Section 4) can be present. +
    • +
    +

    In addiction to the options defined in Section 4, the following options are valid within this block: +

    + + + + + + + + + + + + + + + + + + +
    NameCodeLengthDescription
    isb_starttime28Time in which the capture started; time will be stored in two blocks of four bytes each, containing the timestamp in seconds and nanoseconds.
    isb_endtime38Time in which the capture started; time will be stored in two blocks of four bytes each, containing the timestamp in seconds and nanoseconds.
    + +

    +
     TOC 
    +

    4. Options

    + +

    Almost all blocks have the possibility to embed optional fields. Optional fields can be used to insert some information that may be useful when reading data, but that it is not really needed for packet processing. Therefore, each tool can be either read the content of the optional fields (if any), or skip them at once. +

    +

    Skipping all the optional fields at once is straightforward because most of the blocks have a fixed length, therefore the field Block Length (present in the General Block Structure, see Section 2.1) can be used to skip everything till the next block. +

    +

    Options are a list of Type - Length - Value fields, each one containing a single value: +

    +
      +
    • Option Type (2 bytes): it contains the code that specifies the type of the current TLV record. Option types whose Most Significant Bit is equal to one are reserved for local use; therefore, there is no guarantee that the code used is unique among all capture files (generated by other applications). In case of vendor-specific extensions that have to be identified uniquely, vendors must request an Option Code whose MSB is equal to zero. +
    • +
    • Option Length (2 bytes): it contains the length of the following 'Option Value' field. +
    • +
    • Option Value (variable length): it contains the value of the given option. The length of this field as been specified by the Option Length field. +
    • +
    +

    Options may be repeated several times (e.g. an interface that has several IP addresses associated to it). The option list is terminated by a special code which is the 'End of Option'. +

    +

    The format of the optional fields is shown in Figure 9. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |      Option Code              |         Option Length         |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                       Option Value                            |
    +   |              /* variable length, byte-aligned */              |
    +   |               + + + + + + + + + + + + + + + + + + + + + + + + +
    +   |               /               /               /               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   /                                                               /
    +   /                 . . . other options . . .                     /
    +   /                                                               /
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |   Option Code == opt_endofopt  |  Option Length == 0          |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + 
    +
     Options format. 

    + +

    The following codes can always be present in any optional field: +

    + + + + + + + + + + + + + + + + + + +
    NameCodeLengthDescription
    opt_endofopt00End of options: it is used to delimit the end of the optional fields. This block cannot be repeated within a given list of options.
    opt_comment1variableComment: it is an ascii string containing a comment that is associated to the current block.
    + +

    +
     TOC 
    +

    5. Experimental Blocks (deserved to a further investigation)

    + +

    5.1 Other Packet Blocks (experimental)

    + +

    Can some other packet blocks (besides the two described in the previous paragraphs) be useful? +

    +

    5.2 Compression Block (experimental)

    + +

    The Compression Block is optional. A file can contain an arbitrary number of these blocks. A Compression Block, as the name says, is used to store compressed data. Its format is shown in Figure 10. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |  Compr. Type  |                                               |
    +   +-+-+-+-+-+-+-+-+                                               |
    +   |                                                               |
    +   |                       Compressed Data                         |
    +   |                                                               |
    +   |              /* variable length, byte-aligned */              |
    +   |                                                               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + 
    +
     Compression Block format. 

    + +

    The fields have the following meaning: +

    +
      +
    • Compression Type: specifies the compression algorithm. Possible values for this field are 0 (uncompressed), 1 (Lempel Ziv), 2 (Gzip), other?? Probably some kind of dumb and fast compression algorithm could be effective with some types of traffic (for example web), but which? +
    • +
    • Compressed Data: data of this block. Once decompressed, it is made of other blocks. +
    • +
    +

    5.3 Encryption Block (experimental)

    + +

    The Encryption Block is optional. A file can contain an arbitrary number of these blocks. An Encryption Block is used to sotre encrypted data. Its format is shown in Figure 11. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |   Encr. Type  |                                               |
    +   +-+-+-+-+-+-+-+-+                                               |
    +   |                                                               |
    +   |                       Compressed Data                         |
    +   |                                                               |
    +   |              /* variable length, byte-aligned */              |
    +   |                                                               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + 
    +
     Encryption Block format. 

    + +

    The fields have the following meaning: +

    +
      +
    • Compression Type: specifies the encryption algorithm. Possible values for this field are ??? NOTE: this block should probably contain other fields, depending on the encryption algorithm. To be define precisely. +
    • +
    • Encrypted Data: data of this block. Once decripted, it consists of other blocks. +
    • +
    +

    5.4 Fixed Length Block (experimental)

    + +

    The Fixed Length Block is optional. A file can contain an arbitrary number of these blocks. A Fixed Length Block can be used to optimize the access to the file. Its format is shown in Figure 12. +A Fixed Length Block stores records with constant size. It contains a set of Blocks (normally Packet Blocks or Simple Packet Blocks), of wihich it specifies the size. Knowing this size a priori helps to scan the file and to load some portions of it without truncating a block, and is particularly useful with cell-based networks like ATM. +



    + +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |          Cell Size            |                               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
    +   |                                                               |
    +   |                        Fixed Size Data                        |
    +   |                                                               |
    +   |              /* variable length, byte-aligned */              |
    +   |                                                               |
    +   |                                                               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + 
    +
     Fixed Length Block format. 

    + +

    The fields have the following meaning: +

    +
      +
    • Cell size: the size of the blocks contained in the data field. +
    • +
    • Fixed Size Data: data of this block. +
    • +
    +

    5.5 Directory Block (experimental)

    + +

    If present, this block contains the following information: +

    +
      +
    • number of indexed packets (N) +
    • +
    • table with position and length of any indexed packet (N entries) +
    • +
    +

    A directory block must be followed by at least N packets, otherwise it must be considered invalid. It can be used to efficiently load portions of the file to memory and to support operations on memory mapped files. This block can be added by tools like network analyzers as a consequence of file processing. +

    +

    5.6 Traffic Statistics and Monitoring Blocks (experimental)

    + +

    One or more blocks could be defined to contain network statistics or traffic monitoring information. They could be use to store data collected from RMON or Netflow probes, or from other network monitoring tools. +

    +

    5.7 Event/Security Block (experimental)

    + +

    This block could be used to store events. Events could contain generic information (for example network load over 50%, server down...) or security alerts. An event could be: +

    +
      +
    • skipped, if the application doesn't know how to do with it +
    • +
    • processed independently by the packets. In other words, the applications skips the packets and processes only the alerts +
    • +
    • processed in relation to packets: for example, a security tool could load only the packets of the file that are near a security alert; a monitorg tool could skip the packets captured while the server was down. +
    • +
    +

    +
     TOC 
    +

    6. Conclusions

    + +

    The file format proposed in this document should be very versatile and satisfy a wide range of applications. +In the simplest case, it can contain a raw dump of the network data, made of a series of Simple Packet Blocks. +In the most complex case, it can be used as a repository for heterogeneous information. +In every case, the file remains easy to parse and an application can always skip the data it is not interested in; at the same time, different applications can share the file, and each of them can benfit of the information produced by the others. +Two or more files can be concatenated obtaining another valid file. +

    +

    +
     TOC 
    +

    7. Most important open issues

    + +
      +
    • Data, in the file, must be byte or word aligned? Currently, the structure of this document is not consistent with respect to this point. +
    • +


    +
     TOC 
    +

    Intellectual Property Statement

    + + +

    Full Copyright Statement

    + + + + +

    Acknowledgment

    + + diff --git a/tcpdump/jni/libpcap/doc/pcap.txt b/tcpdump/jni/libpcap/doc/pcap.txt new file mode 100644 index 0000000..cfa6645 --- /dev/null +++ b/tcpdump/jni/libpcap/doc/pcap.txt @@ -0,0 +1,1680 @@ + + +Network Working Group L. Degioanni +Internet-Draft F. Risso +Expires: August 30, 2004 Politecnico di Torino + March 2004 + + + PCAP New Generation Dump File Format + pcap + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that other + groups may also distribute working documents as Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on August 30, 2004. + +Copyright Notice + + Copyright (C) The Internet Society (2004). All Rights Reserved. + +Abstract + + This document describes a format to dump captured packets on a file. + This format is extensible and it is currently proposed for + implementation in the libpcap/WinPcap packet capture library. + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 1] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + +Table of Contents + + 1. Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. General File Structure . . . . . . . . . . . . . . . . . . . . 4 + 2.1 General Block Structure . . . . . . . . . . . . . . . . . . . 4 + 2.2 Block Types . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 2.3 Block Hierarchy and Precedence . . . . . . . . . . . . . . . . 5 + 2.4 Data format . . . . . . . . . . . . . . . . . . . . . . . . . 6 + 3. Block Definition . . . . . . . . . . . . . . . . . . . . . . . 8 + 3.1 Section Header Block (mandatory) . . . . . . . . . . . . . . . 8 + 3.2 Interface Description Block (mandatory) . . . . . . . . . . . 9 + 3.3 Packet Block (optional) . . . . . . . . . . . . . . . . . . . 13 + 3.4 Simple Packet Block (optional) . . . . . . . . . . . . . . . . 15 + 3.5 Name Resolution Block (optional) . . . . . . . . . . . . . . . 16 + 3.6 Interface Statistics Block (optional) . . . . . . . . . . . . 18 + 4. Options . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 + 5. Experimental Blocks (deserved to a further investigation) . . 23 + 5.1 Other Packet Blocks (experimental) . . . . . . . . . . . . . . 23 + 5.2 Compression Block (experimental) . . . . . . . . . . . . . . . 23 + 5.3 Encryption Block (experimental) . . . . . . . . . . . . . . . 23 + 5.4 Fixed Length Block (experimental) . . . . . . . . . . . . . . 24 + 5.5 Directory Block (experimental) . . . . . . . . . . . . . . . . 25 + 5.6 Traffic Statistics and Monitoring Blocks (experimental) . . . 25 + 5.7 Event/Security Block (experimental) . . . . . . . . . . . . . 25 + 6. Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . 27 + 7. Most important open issues . . . . . . . . . . . . . . . . . . 28 + Intellectual Property and Copyright Statements . . . . . . . . 29 + + + + + + + + + + + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 2] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + +1. Objectives + + The problem of exchanging packet traces becomes more and more + critical every day; unfortunately, no standard solutions exist for + this task right now. One of the most accepted packet interchange + formats is the one defined by libpcap, which is rather old and does + not fit for some of the nowadays applications especially in terms of + extensibility. + + This document proposes a new format for dumping packet traces. The + following goals are being pursued: + + o Extensibility: aside of some common functionalities, third parties + should be able to enrich the information embedded in the file with + proprietary extensions, which will be ignored by tools that are + not able to understand them. + + o Portability: a capture trace must contain all the information + needed to read data independently from network, hardware and + operating system of the machine that made the capture. + + o Merge/Append data: it should be possible to add data at the end of + a given file, and the resulting file must still be readable. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 3] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + +2. General File Structure + +2.1 General Block Structure + + A capture file is organized in blocks, that are appended one to + another to form the file. All the blocks share a common format, which + is shown in Figure 1. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Block Type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Block Total Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / Block Body / + / /* variable length, aligned to 32 bits */ / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Block Total Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 1: Basic block structure. + + The fields have the following meaning: + + o Block Type (32 bits): unique value that identifies the block. + Values whose Most Significant Bit (MSB) is equal to 1 are reserved + for local use. They allow to save private data to the file and to + extend the file format. + + o Block Total Length: total size of this block, in bytes. For + instance, a block that does not have a body has a length of 12 + bytes. + + o Block Body: content of the block. + + o Block Total Length: total size of this block, in bytes. This field + is duplicated for permitting backward file navigation. + + This structure, shared among all blocks, makes easy to process a file + and to skip unneeded or unknown blocks. Blocks can be nested one + inside the others (NOTE: needed?). Some of the blocks are mandatory, + i.e. a dump file is not valid if they are not present, other are + optional. + + The structure of the blocks allows to define other blocks if needed. + A parser that does non understand them can simply ignore their + content. + + + +Degioanni & Risso Expires August 30, 2004 [Page 4] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + +2.2 Block Types + + The currently defined blocks are the following: + + 1. Section Header Block: it defines the most important + characteristics of the capture file. + + 2. Interface Description Block: it defines the most important + characteristics of the interface(s) used for capturing traffic. + + 3. Packet Block: it contains a single captured packet, or a portion + of it. + + 4. Simple Packet Block: it contains a single captured packet, or a + portion of it, with only a minimal set of information about it. + + 5. Name Resolution Block: it defines the mapping from numeric + addresses present in the packet dump and the canonical name + counterpart. + + 6. Capture Statistics Block: it defines how to store some + statistical data (e.g. packet dropped, etc) which can be useful + to undestand the conditions in which the capture has been made. + + 7. Compression Marker Block: TODO + + 8. Encryption Marker Block: TODO + + 9. Fixed Length Marker Block: TODO + + The following blocks instead are considered interesting but the + authors believe that they deserve more in-depth discussion before + being defined: + + 1. Further Packet Blocks + + 2. Directory Block + + 3. Traffic Statistics and Monitoring Blocks + + 4. Alert and Security Blocks + + TODO Currently standardized Block Type codes are specified in + Appendix 1. + +2.3 Block Hierarchy and Precedence + + The file must begin with a Section Header Block. However, more than + + + +Degioanni & Risso Expires August 30, 2004 [Page 5] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + one Section Header Block can be present on the dump, each one + covering the data following it till the next one (or the end of + file). A Section includes the data delimited by two Section Header + Blocks (or by a Section Header Block and the end of the file), + including the first Section Header Block. + + In case an application cannot read a Section because of different + version number, it must skip everything until the next Section Header + Block. Note that, in order to properly skip the blocks until the next + section, all blocks must have the fields Type and Length at the + beginning. This is a mandatory requirement that must be maintained in + future versions of the block format. + + Figure 2 shows two valid files: the first has a typical + configuration, with a single Section Header that covers the whole + file. The second one contains three headers, and is normally the + result of file concatenation. An application that understands only + version 1.0 of the file format skips the intermediate section and + restart processing the packets after the third Section Header. + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SHB v1.0 | Data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Typical configuration with a single Section Header Block + + + |-- 1st Section --|-- 2nd Section --|-- 3rd Section --| + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SHB v1.0 | Data | SHB V1.1 | Data | SHB V1.0 | Data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Configuration with three different Section Header Blocks + + Figure 2: File structure example: the Section Header Block. + + NOTE: TO BE COMPLETED with some examples of other blocks + +2.4 Data format + + Data contained in each section will always be saved according to the + characteristics (little endian / big endian) of the dumping machine. + This refers to all fields that are saved as numbers and that span + over two or more bytes. + + The approach of having each section saved in the native format of the + generating host is more efficient because it avoids translation of + data when reading / writing on the host itself, which is the most + common case when generating/processing capture dumps. + + + +Degioanni & Risso Expires August 30, 2004 [Page 6] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + TODO Probably we have to specify something more here. Is what we're + saying enough to avoid any kind of ambiguity?. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 7] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + +3. Block Definition + + This section details the format of the body of the blocks currently + defined. + +3.1 Section Header Block (mandatory) + + The Section Header Block is mandatory. It identifies the beginning of + a section of the capture dump file. Its format is shown in Figure 3. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Magic | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Major | Minor | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 3: Section Header Block format. + + The meaning of the fields is: + + o Magic: magic number, whose value is the hexadecimal number + 0x1A2B3C4D. This number can be used to distinguish section that + have been saved on little-endian machines from the one saved on + big-endian machines. + + o Major: number of the current mayor version of the format. Current + value is 1. + + o Minor: number of the current minor version of the format. Current + value is 0. + + o Options: optionally, a list of options (formatted according to the + rules defined in Section 4) can be present. + + Aside form the options defined in Section 4, the following options + are valid within this block: + + +----------------+----------------+----------------+----------------+ + | Name | Code | Length | Description | + +----------------+----------------+----------------+----------------+ + | Hardware | 2 | variable | An ascii | + | | | | string | + + + +Degioanni & Risso Expires August 30, 2004 [Page 8] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + | | | | containing the | + | | | | description of | + | | | | the hardware | + | | | | used to create | + | | | | this section. | + | | | | | + | Operating | 3 | variable | An ascii | + | System | | | string | + | | | | containing the | + | | | | name of the | + | | | | operating | + | | | | system used to | + | | | | create this | + | | | | section. | + | | | | | + | User | 3 | variable | An ascii | + | Application | | | string | + | | | | containing the | + | | | | name of the | + | | | | application | + | | | | used to create | + | | | | this section. | + +----------------+----------------+----------------+----------------+ + + Table 1 + + The Section Header Block does not contain data but it rather + identifies a list of blocks (interfaces, packets) that are logically + correlated. This block does not contain any reference to the size of + the section it is currently delimiting, therefore the reader cannot + skip a whole section at once. In case a section must be skipped, the + user has to repeatedly skip all the blocks contained within it; this + makes the parsing of the file slower but it permits to append several + capture dumps at the same file. + +3.2 Interface Description Block (mandatory) + + The Interface Description Block is mandatory. This block is needed to + specify the characteristics of the network interface on which the + capture has been made. In order to properly associate the captured + data to the corresponding interface, the Interface Description Block + must be defined before any other block that uses it; therefore, this + block is usually placed immediately after the Section Header Block. + + An Interface Description Block is valid only inside the section which + it belongs to. The structure of a Interface Description Block is + shown in Figure 4. + + + + +Degioanni & Risso Expires August 30, 2004 [Page 9] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Interface ID | LinkType | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SnapLen | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 4: Interface Description Block format. + + The meaning of the fields is: + + o Interface ID: a progressive number that identifies uniquely any + interface inside current section. Two Interface Description Blocks + can have the same Interface ID only if they are in different + sections of the file. The Interface ID is referenced by the packet + blocks. + + o LinkType: a value that defines the link layer type of this + interface. + + o SnapLen: maximum number of bytes dumped from each packet. The + portion of each packet that exceeds this value will not be stored + in the file. + + o Options: optionally, a list of options (formatted according to the + rules defined in Section 4) can be present. + + In addition to the options defined in Section 4, the following + options are valid within this block: + + +----------------+----------------+----------------+----------------+ + | Name | Code | Length | Description | + +----------------+----------------+----------------+----------------+ + | if_name | 2 | Variable | Name of the | + | | | | device used to | + | | | | capture data. | + | | | | | + | if_IPv4addr | 3 | 8 | Interface | + | | | | network | + | | | | address and | + | | | | netmask. | + | | | | | + | if_IPv6addr | 4 | 17 | Interface | + + + +Degioanni & Risso Expires August 30, 2004 [Page 10] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + | | | | network | + | | | | address and | + | | | | prefix length | + | | | | (stored in the | + | | | | last byte). | + | | | | | + | if_MACaddr | 5 | 6 | Interface | + | | | | Hardware MAC | + | | | | address (48 | + | | | | bits). | + | | | | | + | if_EUIaddr | 6 | 8 | Interface | + | | | | Hardware EUI | + | | | | address (64 | + | | | | bits), if | + | | | | available. | + | | | | | + | if_speed | 7 | 8 | Interface | + | | | | speed (in | + | | | | bps). | + | | | | | + | if_tsaccur | 8 | 1 | Precision of | + | | | | timestamps. If | + | | | | the Most | + | | | | Significant | + | | | | Bit is equal | + | | | | to zero, the | + | | | | remaining bits | + | | | | indicates the | + | | | | accuracy as as | + | | | | a negative | + | | | | power of 10 | + | | | | (e.g. 6 means | + | | | | microsecond | + | | | | accuracy). If | + | | | | the Most | + | | | | Significant | + | | | | Bit is equal | + | | | | to zero, the | + | | | | remaining bits | + | | | | indicates the | + | | | | accuracy as as | + | | | | negative power | + | | | | of 2 (e.g. 10 | + | | | | means 1/1024 | + | | | | of second). If | + | | | | this option is | + | | | | not present, a | + + + +Degioanni & Risso Expires August 30, 2004 [Page 11] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + | | | | precision of | + | | | | 10^-6 is | + | | | | assumed. | + | | | | | + | if_tzone | 9 | 4 | Time zone for | + | | | | GMT support | + | | | | (TODO: specify | + | | | | better). | + | | | | | + | if_flags | 10 | 4 | Interface | + | | | | flags. (TODO: | + | | | | specify | + | | | | better. | + | | | | Possible | + | | | | flags: | + | | | | promiscuous, | + | | | | inbound/outbou | + | | | | nd, traffic | + | | | | filtered | + | | | | during | + | | | | capture). | + | | | | | + | if_filter | 11 | variable | The filter | + | | | | (e.g. "capture | + | | | | only TCP | + | | | | traffic") used | + | | | | to capture | + | | | | traffic. The | + | | | | first byte of | + | | | | the Option | + | | | | Data keeps a | + | | | | code of the | + | | | | filter used | + | | | | (e.g. if this | + | | | | is a libpcap | + | | | | string, or BPF | + | | | | bytecode, and | + | | | | more). More | + | | | | details about | + | | | | this format | + | | | | will be | + | | | | presented in | + | | | | Appendix XXX | + | | | | (TODO). | + | | | | | + | if_opersystem | 12 | variable | An ascii | + | | | | string | + | | | | containing the | + + + +Degioanni & Risso Expires August 30, 2004 [Page 12] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + | | | | name of the | + | | | | operating | + | | | | system of the | + | | | | machine that | + | | | | hosts this | + | | | | interface. | + | | | | This can be | + | | | | different from | + | | | | the same | + | | | | information | + | | | | that can be | + | | | | contained by | + | | | | the Section | + | | | | Header Block | + | | | | (Section 3.1) | + | | | | because the | + | | | | capture can | + | | | | have been done | + | | | | on a remote | + | | | | machine. | + +----------------+----------------+----------------+----------------+ + + Table 2 + + +3.3 Packet Block (optional) + + A Packet Block is the standard container for storing the packets + coming from the network. The Packet Block is optional because packets + can be stored either by means of this block or the Simple Packet + Block, which can be used to speed up dump generation. The format of a + packet block is shown in Figure 5. + + + + + + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 13] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Interface ID | Drops Count | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Timestamp (High) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Timestamp (Low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Captured Len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Packet Len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | Packet Data | + | | + | /* variable length, byte-aligned */ | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 5: Packet Block format. + + The Packet Block has the following fields: + + o Interface ID: Specifies the interface this packet comes from, and + corresponds to the ID of one of the Interface Description Blocks + present in this section of the file (see Figure 4). + + o Drops Count: a local drop counter. It specified the number of + packets lost (by the interface and the operating system) between + this packet and the preceding one. The value xFFFF (in + hexadecimal) is reserved for those systems in which this + information is not available. + + o Timestamp (High): the most significative part of the timestamp. in + standard Unix format, i.e. from 1/1/1970. + + o Timestamp (Low): the less significative part of the timestamp. The + way to interpret this field is specified by the 'ts_accur' option + (see Figure 4) of the Interface Description block referenced by + this packet. If the Interface Description block does not contain a + 'ts_accur' option, then this field is expressed in microseconds. + + o Captured Len: number of bytes captured from the packet (i.e. the + + + +Degioanni & Risso Expires August 30, 2004 [Page 14] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + length of the Packet Data field). It will be the minimum value + among the actual Packet Length and the snapshot length (defined in + Figure 4). + + o Packet Len: actual length of the packet when it was transmitted on + the network. Can be different from Captured Len if the user wants + only a snapshot of the packet. + + o Packet Data: the data coming from the network, including + link-layer headers. The length of this field is Captured Len. The + format of the link-layer headers depends on the LinkType field + specified in the Interface Description Block (see Section 3.2) and + it is specified in Appendix XXX (TODO). + + o Options: optionally, a list of options (formatted according to the + rules defined in Section 4) can be present. + + +3.4 Simple Packet Block (optional) + + The Simple Packet Block is a lightweight container for storing the + packets coming from the network. Its presence is optional. + + A Simple Packet Block is similar to a Packet Block (see Section 3.3), + but it is smaller, simpler to process and contains only a minimal set + of information. This block is preferred to the standard Packet Block + when performance or space occupation are critical factors, such as in + sustained traffic dump applications. A capture file can contain both + Packet Blocks and Simple Packet Blocks: for example, a capture tool + could switch from Packet Blocks to Simple Packet Blocks when the + hardware resources become critical. + + The Simple Packet Block does not contain the Interface ID field. + Therefore, it must be assumed that all the Simple Packet Blocks have + been captured on the interface previously specified in the Interface + Description Block. + + Figure 6 shows the format of the Simple Packet Block. + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 15] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Packet Len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | Packet Data | + | | + | /* variable length, byte-aligned */ | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 6: Simple Packet Block format. + + The Packet Block has the following fields: + + o Packet Len: actual length of the packet when it was transmitted on + the network. Can be different from captured len if the packet has + been truncated. + + o Packet data: the data coming from the network, including + link-layers headers. The length of this field can be derived from + the field Block Total Length, present in the Block Header. + + The Simple Packet Block does not contain the timestamp because this + is one of the most costly operations on PCs. Additionally, there are + applications that do not require it; e.g. an Intrusion Detection + System is interested in packets, not in their timestamp. + + The Simple Packet Block is very efficient in term of disk space: a + snapshot of length 100 bytes requires only 16 bytes of overhead, + which corresponds to an efficiency of more than 86%. + +3.5 Name Resolution Block (optional) + + The Name Resolution Block is used to support the correlation of + numeric addresses (present in the captured packets) and their + corresponding canonical names and it is optional. Having the literal + names saved in the file, this prevents the need of a name resolution + in a delayed time, when the association between names and addresses + can be different from the one in use at capture time. Moreover, The + Name Resolution Block avoids the need of issuing a lot of DNS + requests every time the trace capture is opened, and allows to have + name resolution also when reading the capture with a machine not + connected to the network. + + The format of the Name Resolution Block is shown in Figure 7. + + + + +Degioanni & Risso Expires August 30, 2004 [Page 16] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Record Type | Record Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Record Value | + | /* variable length, byte-aligned */ | + | + + + + + + + + + + + + + + + + + + + + + + + + + + | | | | | + +-+-+-+-+-+-+-+-+ + + + + + + + + + + + + + + + + + + + + + + + + + . . . other records . . . + | Record Type == end_of_recs | Record Length == 00 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 7: Name Resolution Block format. + + A Name Resolution Block is a zero-terminated list of records (in the + TLV format), each of which contains an association between a network + address and a name. There are three possible types of records: + + +----------------+----------------+----------------+----------------+ + | Name | Code | Length | Description | + +----------------+----------------+----------------+----------------+ + | end_of_recs | 0 | 0 | End of records | + | | | | | + | ip4_rec | 1 | Variable | Specifies an | + | | | | IPv4 address | + | | | | (contained in | + | | | | the first 4 | + | | | | bytes), | + | | | | followed by | + | | | | one or more | + | | | | zero-terminate | + | | | | d strings | + | | | | containing the | + | | | | DNS entries | + | | | | for that | + | | | | address. | + | | | | | + | ip6_rec | 1 | Variable | Specifies an | + | | | | IPv6 address | + | | | | (contained in | + | | | | the first 16 | + | | | | bytes), | + + + +Degioanni & Risso Expires August 30, 2004 [Page 17] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + | | | | followed by | + | | | | one or more | + | | | | zero-terminate | + | | | | d strings | + | | | | containing the | + | | | | DNS entries | + | | | | for that | + | | | | address. | + +----------------+----------------+----------------+----------------+ + + Table 3 + + After the list or Name Resolution Records, optionally, a list of + options (formatted according to the rules defined in Section 4) can + be present. + + A Name Resolution Block is normally placed at the beginning of the + file, but no assumptions can be taken about its position. Name + Resolution Blocks can be added in a second time by tools that process + the file, like network analyzers. + + In addiction to the options defined in Section 4, the following + options are valid within this block: + + +----------------+----------------+----------------+----------------+ + | Name | Code | Length | Description | + +----------------+----------------+----------------+----------------+ + | ns_dnsname | 2 | Variable | An ascii | + | | | | string | + | | | | containing the | + | | | | name of the | + | | | | machine (DNS | + | | | | server) used | + | | | | to perform the | + | | | | name | + | | | | resolution. | + +----------------+----------------+----------------+----------------+ + + +3.6 Interface Statistics Block (optional) + + The Interface Statistics Block contains the capture statistics for a + given interface and it is optional. The statistics are referred to + the interface defined in the current Section identified by the + Interface ID field. + + The format of the Interface Statistics Block is shown in Figure 8. + + + + +Degioanni & Risso Expires August 30, 2004 [Page 18] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IfRecv | + | (high + low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IfDrop | + | (high + low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | FilterAccept | + | (high + low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OSDrop | + | (high + low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | UsrDelivered | + | (high + low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Interface ID | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 8: Interface Statistics Block format. + + The fields have the following meaning: + + o IfRecv: number of packets received from the interface during the + capture. This number is reported as a 64 bits value, in which the + most significat bits are located in the first four bytes of the + field. + + o IfDrop: number of packets dropped by the interface during the + capture due to lack of resources. + + o FilterAccept: number of packets accepeted by filter during current + capture. + + o OSDrop: number of packets dropped by the operating system during + the capture. + + o UsrDelivered: number of packets delivered to the user. + UsrDelivered can be different from the value 'FilterAccept - + OSDropped' because some packets could still lay in the OS buffers + when the capture ended. + + + + +Degioanni & Risso Expires August 30, 2004 [Page 19] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + o Interface ID: reference to an Interface Description Block. + + o Reserved: Reserved to future use. + + o Options: optionally, a list of options (formatted according to the + rules defined in Section 4) can be present. + + In addiction to the options defined in Section 4, the following + options are valid within this block: + + +----------------+----------------+----------------+----------------+ + | Name | Code | Length | Description | + +----------------+----------------+----------------+----------------+ + | isb_starttime | 2 | 8 | Time in which | + | | | | the capture | + | | | | started; time | + | | | | will be stored | + | | | | in two blocks | + | | | | of four bytes | + | | | | each, | + | | | | containing the | + | | | | timestamp in | + | | | | seconds and | + | | | | nanoseconds. | + | | | | | + | isb_endtime | 3 | 8 | Time in which | + | | | | the capture | + | | | | started; time | + | | | | will be stored | + | | | | in two blocks | + | | | | of four bytes | + | | | | each, | + | | | | containing the | + | | | | timestamp in | + | | | | seconds and | + | | | | nanoseconds. | + +----------------+----------------+----------------+----------------+ + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 20] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + +4. Options + + Almost all blocks have the possibility to embed optional fields. + Optional fields can be used to insert some information that may be + useful when reading data, but that it is not really needed for packet + processing. Therefore, each tool can be either read the content of + the optional fields (if any), or skip them at once. + + Skipping all the optional fields at once is straightforward because + most of the blocks have a fixed length, therefore the field Block + Length (present in the General Block Structure, see Section 2.1) can + be used to skip everything till the next block. + + Options are a list of Type - Length - Value fields, each one + containing a single value: + + o Option Type (2 bytes): it contains the code that specifies the + type of the current TLV record. Option types whose Most + Significant Bit is equal to one are reserved for local use; + therefore, there is no guarantee that the code used is unique + among all capture files (generated by other applications). In case + of vendor-specific extensions that have to be identified uniquely, + vendors must request an Option Code whose MSB is equal to zero. + + o Option Length (2 bytes): it contains the length of the following + 'Option Value' field. + + o Option Value (variable length): it contains the value of the given + option. The length of this field as been specified by the Option + Length field. + + Options may be repeated several times (e.g. an interface that has + several IP addresses associated to it). The option list is terminated + by a special code which is the 'End of Option'. + + The format of the optional fields is shown in Figure 9. + + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 21] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Code | Option Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Value | + | /* variable length, byte-aligned */ | + | + + + + + + + + + + + + + + + + + + + + + + + + + + | / / / | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / . . . other options . . . / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Code == opt_endofopt | Option Length == 0 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 9: Options format. + + The following codes can always be present in any optional field: + + +----------------+----------------+----------------+----------------+ + | Name | Code | Length | Description | + +----------------+----------------+----------------+----------------+ + | opt_endofopt | 0 | 0 | End of | + | | | | options: it is | + | | | | used to | + | | | | delimit the | + | | | | end of the | + | | | | optional | + | | | | fields. This | + | | | | block cannot | + | | | | be repeated | + | | | | within a given | + | | | | list of | + | | | | options. | + | | | | | + | opt_comment | 1 | variable | Comment: it is | + | | | | an ascii | + | | | | string | + | | | | containing a | + | | | | comment that | + | | | | is associated | + | | | | to the current | + | | | | block. | + +----------------+----------------+----------------+----------------+ + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 22] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + +5. Experimental Blocks (deserved to a further investigation) + +5.1 Other Packet Blocks (experimental) + + Can some other packet blocks (besides the two described in the + previous paragraphs) be useful? + +5.2 Compression Block (experimental) + + The Compression Block is optional. A file can contain an arbitrary + number of these blocks. A Compression Block, as the name says, is + used to store compressed data. Its format is shown in Figure 10. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Compr. Type | | + +-+-+-+-+-+-+-+-+ | + | | + | Compressed Data | + | | + | /* variable length, byte-aligned */ | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 10: Compression Block format. + + The fields have the following meaning: + + o Compression Type: specifies the compression algorithm. Possible + values for this field are 0 (uncompressed), 1 (Lempel Ziv), 2 + (Gzip), other?? Probably some kind of dumb and fast compression + algorithm could be effective with some types of traffic (for + example web), but which? + + o Compressed Data: data of this block. Once decompressed, it is made + of other blocks. + + +5.3 Encryption Block (experimental) + + The Encryption Block is optional. A file can contain an arbitrary + number of these blocks. An Encryption Block is used to sotre + encrypted data. Its format is shown in Figure 11. + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 23] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Encr. Type | | + +-+-+-+-+-+-+-+-+ | + | | + | Compressed Data | + | | + | /* variable length, byte-aligned */ | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 11: Encryption Block format. + + The fields have the following meaning: + + o Compression Type: specifies the encryption algorithm. Possible + values for this field are ??? NOTE: this block should probably + contain other fields, depending on the encryption algorithm. To be + define precisely. + + o Encrypted Data: data of this block. Once decripted, it consists of + other blocks. + + +5.4 Fixed Length Block (experimental) + + The Fixed Length Block is optional. A file can contain an arbitrary + number of these blocks. A Fixed Length Block can be used to optimize + the access to the file. Its format is shown in Figure 12. A Fixed + Length Block stores records with constant size. It contains a set of + Blocks (normally Packet Blocks or Simple Packet Blocks), of wihich it + specifies the size. Knowing this size a priori helps to scan the file + and to load some portions of it without truncating a block, and is + particularly useful with cell-based networks like ATM. + + + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 24] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Cell Size | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + | | + | Fixed Size Data | + | | + | /* variable length, byte-aligned */ | + | | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 12: Fixed Length Block format. + + The fields have the following meaning: + + o Cell size: the size of the blocks contained in the data field. + + o Fixed Size Data: data of this block. + + +5.5 Directory Block (experimental) + + If present, this block contains the following information: + + o number of indexed packets (N) + + o table with position and length of any indexed packet (N entries) + + A directory block must be followed by at least N packets, otherwise + it must be considered invalid. It can be used to efficiently load + portions of the file to memory and to support operations on memory + mapped files. This block can be added by tools like network analyzers + as a consequence of file processing. + +5.6 Traffic Statistics and Monitoring Blocks (experimental) + + One or more blocks could be defined to contain network statistics or + traffic monitoring information. They could be use to store data + collected from RMON or Netflow probes, or from other network + monitoring tools. + +5.7 Event/Security Block (experimental) + + This block could be used to store events. Events could contain + generic information (for example network load over 50%, server + down...) or security alerts. An event could be: + + + +Degioanni & Risso Expires August 30, 2004 [Page 25] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + o skipped, if the application doesn't know how to do with it + + o processed independently by the packets. In other words, the + applications skips the packets and processes only the alerts + + o processed in relation to packets: for example, a security tool + could load only the packets of the file that are near a security + alert; a monitorg tool could skip the packets captured while the + server was down. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 26] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + +6. Conclusions + + The file format proposed in this document should be very versatile + and satisfy a wide range of applications. In the simplest case, it + can contain a raw dump of the network data, made of a series of + Simple Packet Blocks. In the most complex case, it can be used as a + repository for heterogeneous information. In every case, the file + remains easy to parse and an application can always skip the data it + is not interested in; at the same time, different applications can + share the file, and each of them can benfit of the information + produced by the others. Two or more files can be concatenated + obtaining another valid file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 27] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + +7. Most important open issues + + o Data, in the file, must be byte or word aligned? Currently, the + structure of this document is not consistent with respect to this + point. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 28] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + +Full Copyright Statement + + Copyright (C) The Internet Society (2004). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assignees. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + + + +Degioanni & Risso Expires August 30, 2004 [Page 29] + +Internet-Draft PCAP New Generation Dump File Format March 2004 + + + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Acknowledgment + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Degioanni & Risso Expires August 30, 2004 [Page 30] + diff --git a/tcpdump/jni/libpcap/doc/pcap.xml b/tcpdump/jni/libpcap/doc/pcap.xml new file mode 100644 index 0000000..1fb0eb7 --- /dev/null +++ b/tcpdump/jni/libpcap/doc/pcap.xml @@ -0,0 +1,746 @@ + + + + + + + + PCAP New Generation Dump File Format + + Politecnico di Torino +
    + + Corso Duca degli Abruzzi, 24 + Torino + 10129 + Italy + + +39 011 564 7008 + loris.degioanni@polito.it + http://netgroup.polito.it/loris/ +
    +
    + + Politecnico di Torino +
    + + Corso Duca degli Abruzzi, 24 + Torino + 10129 + Italy + + +39 011 564 7008 + fulvio.risso@polito.it + http://netgroup.polito.it/fulvio.risso/ +
    +
    + + + + + General + + Internet-Draft + Libpcap, dump file format + +This document describes a format to dump captured packets on a file. This format is extensible and it is currently proposed for implementation in the libpcap/WinPcap packet capture library. + + +
    + + +
    +The problem of exchanging packet traces becomes more and more critical every day; unfortunately, no standard solutions exist for this task right now. One of the most accepted packet interchange formats is the one defined by libpcap, which is rather old and does not fit for some of the nowadays applications especially in terms of extensibility. +This document proposes a new format for dumping packet traces. The following goals are being pursued: + +Extensibility: aside of some common functionalities, third parties should be able to enrich the information embedded in the file with proprietary extensions, which will be ignored by tools that are not able to understand them. +Portability: a capture trace must contain all the information needed to read data independently from network, hardware and operating system of the machine that made the capture. +Merge/Append data: it should be possible to add data at the end of a given file, and the resulting file must still be readable. + + +
    + + +
    + +
    +A capture file is organized in blocks, that are appended one to another to form the file. All the blocks share a common format, which is shown in . + +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Block Type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Block Total Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / Block Body / + / /* variable length, aligned to 32 bits */ / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Block Total Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +The fields have the following meaning: + + +Block Type (32 bits): unique value that identifies the block. Values whose Most Significant Bit (MSB) is equal to 1 are reserved for local use. They allow to save private data to the file and to extend the file format. +Block Total Length: total size of this block, in bytes. For instance, a block that does not have a body has a length of 12 bytes. +Block Body: content of the block. +Block Total Length: total size of this block, in bytes. This field is duplicated for permitting backward file navigation. + + +This structure, shared among all blocks, makes easy to process a file and to skip unneeded or unknown blocks. Blocks can be nested one inside the others (NOTE: needed?). Some of the blocks are mandatory, i.e. a dump file is not valid if they are not present, other are optional. +The structure of the blocks allows to define other blocks if needed. A parser that does non understand them can simply ignore their content. +
    + +
    +The currently defined blocks are the following: + +Section Header Block: it defines the most important characteristics of the capture file. +Interface Description Block: it defines the most important characteristics of the interface(s) used for capturing traffic. +Packet Block: it contains a single captured packet, or a portion of it. +Simple Packet Block: it contains a single captured packet, or a portion of it, with only a minimal set of information about it. +Name Resolution Block: it defines the mapping from numeric addresses present in the packet dump and the canonical name counterpart. +Capture Statistics Block: it defines how to store some statistical data (e.g. packet dropped, etc) which can be useful to undestand the conditions in which the capture has been made. +Compression Marker Block: TODO +Encryption Marker Block: TODO +Fixed Length Marker Block: TODO + + +The following blocks instead are considered interesting but the authors believe that they deserve more in-depth discussion before being defined: + +Further Packet Blocks +Directory Block +Traffic Statistics and Monitoring Blocks +Alert and Security Blocks + + +TODO Currently standardized Block Type codes are specified in Appendix 1. + +
    + +
    +The file must begin with a Section Header Block. However, more than one Section Header Block can be present on the dump, each one covering the data following it till the next one (or the end of file). A Section includes the data delimited by two Section Header Blocks (or by a Section Header Block and the end of the file), including the first Section Header Block. +In case an application cannot read a Section because of different version number, it must skip everything until the next Section Header Block. Note that, in order to properly skip the blocks until the next section, all blocks must have the fields Type and Length at the beginning. This is a mandatory requirement that must be maintained in future versions of the block format. + shows two valid files: the first has a typical configuration, with a single Section Header that covers the whole file. The second one contains three headers, and is normally the result of file concatenation. An application that understands only version 1.0 of the file format skips the intermediate section and restart processing the packets after the third Section Header. + +
    + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SHB v1.0 | Data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Typical configuration with a single Section Header Block + + + |-- 1st Section --|-- 2nd Section --|-- 3rd Section --| + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SHB v1.0 | Data | SHB V1.1 | Data | SHB V1.0 | Data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Configuration with three different Section Header Blocks + +
    + +NOTE: TO BE COMPLETED with some examples of other blocks + +
    + +
    +Data contained in each section will always be saved according to the characteristics (little endian / big endian) of the dumping machine. This refers to all fields that are saved as numbers and that span over two or more bytes. +The approach of having each section saved in the native format of the generating host is more efficient because it avoids translation of data when reading / writing on the host itself, which is the most common case when generating/processing capture dumps. +TODO Probably we have to specify something more here. Is what we're saying enough to avoid any kind of ambiguity?. +
    + +
    + + + + +
    +This section details the format of the body of the blocks currently defined. + +
    +The Section Header Block is mandatory. It identifies the beginning of a section of the capture dump file. Its format is shown in . +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Magic | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Major | Minor | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +The meaning of the fields is: + +Magic: magic number, whose value is the hexadecimal number 0x1A2B3C4D. This number can be used to distinguish section that have been saved on little-endian machines from the one saved on big-endian machines. +Major: number of the current mayor version of the format. Current value is 1. +Minor: number of the current minor version of the format. Current value is 0. +Options: optionally, a list of options (formatted according to the rules defined in ) can be present. + + +Aside form the options defined in , the following options are valid within this block: + + + Name + Code + Length + Description + + Hardware + 2 + variable + An ascii string containing the description of the hardware used to create this section. + + Operating System + 3 + variable + An ascii string containing the name of the operating system used to create this section. + + User Application + 3 + variable + An ascii string containing the name of the application used to create this section. + + + +The Section Header Block does not contain data but it rather identifies a list of blocks (interfaces, packets) that are logically correlated. This block does not contain any reference to the size of the section it is currently delimiting, therefore the reader cannot skip a whole section at once. In case a section must be skipped, the user has to repeatedly skip all the blocks contained within it; this makes the parsing of the file slower but it permits to append several capture dumps at the same file. +
    + +
    +The Interface Description Block is mandatory. This block is needed to specify the characteristics of the network interface on which the capture has been made. In order to properly associate the captured data to the corresponding interface, the Interface Description Block must be defined before any other block that uses it; therefore, this block is usually placed immediately after the Section Header Block. + +An Interface Description Block is valid only inside the section which it belongs to. The structure of a Interface Description Block is shown in . + +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Interface ID | LinkType | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SnapLen | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +The meaning of the fields is: + +Interface ID: a progressive number that identifies uniquely any interface inside current section. Two Interface Description Blocks can have the same Interface ID only if they are in different sections of the file. The Interface ID is referenced by the packet blocks. +LinkType: a value that defines the link layer type of this interface. +SnapLen: maximum number of bytes dumped from each packet. The portion of each packet that exceeds this value will not be stored in the file. +Options: optionally, a list of options (formatted according to the rules defined in ) can be present. + + +In addition to the options defined in , the following options are valid within this block: + + + Name + Code + Length + Description + + if_name + 2 + Variable + Name of the device used to capture data. + + if_IPv4addr + 3 + 8 + Interface network address and netmask. + + if_IPv6addr + 4 + 17 + Interface network address and prefix length (stored in the last byte). + + if_MACaddr + 5 + 6 + Interface Hardware MAC address (48 bits). + + if_EUIaddr + 6 + 8 + Interface Hardware EUI address (64 bits), if available. + + if_speed + 7 + 8 + Interface speed (in bps). + + if_tsaccur + 8 + 1 + Precision of timestamps. If the Most Significant Bit is equal to zero, the remaining bits indicates the accuracy as as a negative power of 10 (e.g. 6 means microsecond accuracy). If the Most Significant Bit is equal to zero, the remaining bits indicates the accuracy as as negative power of 2 (e.g. 10 means 1/1024 of second). If this option is not present, a precision of 10^-6 is assumed. + + if_tzone + 9 + 4 + Time zone for GMT support (TODO: specify better). + + if_flags + 10 + 4 + Interface flags. (TODO: specify better. Possible flags: promiscuous, inbound/outbound, traffic filtered during capture). + + if_filter + 11 + variable + The filter (e.g. "capture only TCP traffic") used to capture traffic. The first byte of the Option Data keeps a code of the filter used (e.g. if this is a libpcap string, or BPF bytecode, and more). More details about this format will be presented in Appendix XXX (TODO). + + if_opersystem + 12 + variable + An ascii string containing the name of the operating system of the machine that hosts this interface. This can be different from the same information that can be contained by the Section Header Block () because the capture can have been done on a remote machine. + + + +
    + + + +
    +A Packet Block is the standard container for storing the packets coming from the network. The Packet Block is optional because packets can be stored either by means of this block or the Simple Packet Block, which can be used to speed up dump generation. The format of a packet block is shown in . + +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Interface ID | Drops Count | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Timestamp (High) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Timestamp (Low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Captured Len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Packet Len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | Packet Data | + | | + | /* variable length, byte-aligned */ | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +The Packet Block has the following fields: + + +Interface ID: Specifies the interface this packet comes from, and corresponds to the ID of one of the Interface Description Blocks present in this section of the file (see ). +Drops Count: a local drop counter. It specified the number of packets lost (by the interface and the operating system) between this packet and the preceding one. The value xFFFF (in hexadecimal) is reserved for those systems in which this information is not available. +Timestamp (High): the most significative part of the timestamp. in standard Unix format, i.e. from 1/1/1970. +Timestamp (Low): the less significative part of the timestamp. The way to interpret this field is specified by the 'ts_accur' option (see ) of the Interface Description block referenced by this packet. If the Interface Description block does not contain a 'ts_accur' option, then this field is expressed in microseconds. +Captured Len: number of bytes captured from the packet (i.e. the length of the Packet Data field). It will be the minimum value among the actual Packet Length and the snapshot length (defined in ). +Packet Len: actual length of the packet when it was transmitted on the network. Can be different from Captured Len if the user wants only a snapshot of the packet. +Packet Data: the data coming from the network, including link-layer headers. The length of this field is Captured Len. The format of the link-layer headers depends on the LinkType field specified in the Interface Description Block (see ) and it is specified in Appendix XXX (TODO). +Options: optionally, a list of options (formatted according to the rules defined in ) can be present. + + + +
    + + +
    +The Simple Packet Block is a lightweight container for storing the packets coming from the network. Its presence is optional. +A Simple Packet Block is similar to a Packet Block (see ), but it is smaller, simpler to process and contains only a minimal set of information. This block is preferred to the standard Packet Block when performance or space occupation are critical factors, such as in sustained traffic dump applications. A capture file can contain both Packet Blocks and Simple Packet Blocks: for example, a capture tool could switch from Packet Blocks to Simple Packet Blocks when the hardware resources become critical. +The Simple Packet Block does not contain the Interface ID field. Therefore, it must be assumed that all the Simple Packet Blocks have been captured on the interface previously specified in the Interface Description Block. + shows the format of the Simple Packet Block. + +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Packet Len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | Packet Data | + | | + | /* variable length, byte-aligned */ | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +The Packet Block has the following fields: + +Packet Len: actual length of the packet when it was transmitted on the network. Can be different from captured len if the packet has been truncated. +Packet data: the data coming from the network, including link-layers headers. The length of this field can be derived from the field Block Total Length, present in the Block Header. + + +The Simple Packet Block does not contain the timestamp because this is one of the most costly operations on PCs. Additionally, there are applications that do not require it; e.g. an Intrusion Detection System is interested in packets, not in their timestamp. + +The Simple Packet Block is very efficient in term of disk space: a snapshot of length 100 bytes requires only 16 bytes of overhead, which corresponds to an efficiency of more than 86%. + +
    + + + +
    +The Name Resolution Block is used to support the correlation of numeric addresses (present in the captured packets) and their corresponding canonical names and it is optional. Having the literal names saved in the file, this prevents the need of a name resolution in a delayed time, when the association between names and addresses can be different from the one in use at capture time. Moreover, The Name Resolution Block avoids the need of issuing a lot of DNS requests every time the trace capture is opened, and allows to have name resolution also when reading the capture with a machine not connected to the network. +The format of the Name Resolution Block is shown in . + +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Record Type | Record Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Record Value | + | /* variable length, byte-aligned */ | + | + + + + + + + + + + + + + + + + + + + + + + + + + + | | | | | + +-+-+-+-+-+-+-+-+ + + + + + + + + + + + + + + + + + + + + + + + + + . . . other records . . . + | Record Type == end_of_recs | Record Length == 00 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +A Name Resolution Block is a zero-terminated list of records (in the TLV format), each of which contains an association between a network address and a name. There are three possible types of records: + + + Name + Code + Length + Description + + end_of_recs + 0 + 0 + End of records + + ip4_rec + 1 + Variable + Specifies an IPv4 address (contained in the first 4 bytes), followed by one or more zero-terminated strings containing the DNS entries for that address. + + ip6_rec + 1 + Variable + Specifies an IPv6 address (contained in the first 16 bytes), followed by one or more zero-terminated strings containing the DNS entries for that address. + + +After the list or Name Resolution Records, optionally, a list of options (formatted according to the rules defined in ) can be present. + +A Name Resolution Block is normally placed at the beginning of the file, but no assumptions can be taken about its position. Name Resolution Blocks can be added in a second time by tools that process the file, like network analyzers. + +In addiction to the options defined in , the following options are valid within this block: + + + Name + Code + Length + Description + + ns_dnsname + 2 + Variable + An ascii string containing the name of the machine (DNS server) used to perform the name resolution. + + +
    + + +
    +The Interface Statistics Block contains the capture statistics for a given interface and it is optional. The statistics are referred to the interface defined in the current Section identified by the Interface ID field. +The format of the Interface Statistics Block is shown in . + +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IfRecv | + | (high + low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IfDrop | + | (high + low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | FilterAccept | + | (high + low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OSDrop | + | (high + low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | UsrDelivered | + | (high + low) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Interface ID | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +The fields have the following meaning: + + +IfRecv: number of packets received from the interface during the capture. This number is reported as a 64 bits value, in which the most significat bits are located in the first four bytes of the field. +IfDrop: number of packets dropped by the interface during the capture due to lack of resources. +FilterAccept: number of packets accepeted by filter during current capture. +OSDrop: number of packets dropped by the operating system during the capture. +UsrDelivered: number of packets delivered to the user. UsrDelivered can be different from the value 'FilterAccept - OSDropped' because some packets could still lay in the OS buffers when the capture ended. +Interface ID: reference to an Interface Description Block. +Reserved: Reserved to future use. +Options: optionally, a list of options (formatted according to the rules defined in ) can be present. + + +In addiction to the options defined in , the following options are valid within this block: + + + Name + Code + Length + Description + + isb_starttime + 2 + 8 + Time in which the capture started; time will be stored in two blocks of four bytes each, containing the timestamp in seconds and nanoseconds. + + isb_endtime + 3 + 8 + Time in which the capture started; time will be stored in two blocks of four bytes each, containing the timestamp in seconds and nanoseconds. + + +
    +
    + + + +
    +Almost all blocks have the possibility to embed optional fields. Optional fields can be used to insert some information that may be useful when reading data, but that it is not really needed for packet processing. Therefore, each tool can be either read the content of the optional fields (if any), or skip them at once. +Skipping all the optional fields at once is straightforward because most of the blocks have a fixed length, therefore the field Block Length (present in the General Block Structure, see ) can be used to skip everything till the next block. + +Options are a list of Type - Length - Value fields, each one containing a single value: + + +Option Type (2 bytes): it contains the code that specifies the type of the current TLV record. Option types whose Most Significant Bit is equal to one are reserved for local use; therefore, there is no guarantee that the code used is unique among all capture files (generated by other applications). In case of vendor-specific extensions that have to be identified uniquely, vendors must request an Option Code whose MSB is equal to zero. +Option Length (2 bytes): it contains the length of the following 'Option Value' field. +Option Value (variable length): it contains the value of the given option. The length of this field as been specified by the Option Length field. + + +Options may be repeated several times (e.g. an interface that has several IP addresses associated to it). The option list is terminated by a special code which is the 'End of Option'. + +The format of the optional fields is shown in . + +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Code | Option Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Value | + | /* variable length, byte-aligned */ | + | + + + + + + + + + + + + + + + + + + + + + + + + + + | / / / | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / . . . other options . . . / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Code == opt_endofopt | Option Length == 0 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +The following codes can always be present in any optional field: + + + Name + Code + Length + Description + + opt_endofopt + 0 + 0 + End of options: it is used to delimit the end of the optional fields. This block cannot be repeated within a given list of options. + + opt_comment + 1 + variable + Comment: it is an ascii string containing a comment that is associated to the current block. + + +
    + + + + +
    + +
    +Can some other packet blocks (besides the two described in the previous paragraphs) be useful? +
    + +
    +The Compression Block is optional. A file can contain an arbitrary number of these blocks. A Compression Block, as the name says, is used to store compressed data. Its format is shown in . + +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Compr. Type | | + +-+-+-+-+-+-+-+-+ | + | | + | Compressed Data | + | | + | /* variable length, byte-aligned */ | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +The fields have the following meaning: + + +Compression Type: specifies the compression algorithm. Possible values for this field are 0 (uncompressed), 1 (Lempel Ziv), 2 (Gzip), other?? Probably some kind of dumb and fast compression algorithm could be effective with some types of traffic (for example web), but which? +Compressed Data: data of this block. Once decompressed, it is made of other blocks. + + +
    + + +
    +The Encryption Block is optional. A file can contain an arbitrary number of these blocks. An Encryption Block is used to sotre encrypted data. Its format is shown in . + +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Encr. Type | | + +-+-+-+-+-+-+-+-+ | + | | + | Compressed Data | + | | + | /* variable length, byte-aligned */ | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +The fields have the following meaning: + +Compression Type: specifies the encryption algorithm. Possible values for this field are ??? NOTE: this block should probably contain other fields, depending on the encryption algorithm. To be define precisely. +Encrypted Data: data of this block. Once decripted, it consists of other blocks. + + +
    + + +
    +The Fixed Length Block is optional. A file can contain an arbitrary number of these blocks. A Fixed Length Block can be used to optimize the access to the file. Its format is shown in . +A Fixed Length Block stores records with constant size. It contains a set of Blocks (normally Packet Blocks or Simple Packet Blocks), of wihich it specifies the size. Knowing this size a priori helps to scan the file and to load some portions of it without truncating a block, and is particularly useful with cell-based networks like ATM. + +
    + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Cell Size | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + | | + | Fixed Size Data | + | | + | /* variable length, byte-aligned */ | + | | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +
    + +The fields have the following meaning: + +Cell size: the size of the blocks contained in the data field. +Fixed Size Data: data of this block. + + +
    + +
    +If present, this block contains the following information: + +number of indexed packets (N) +table with position and length of any indexed packet (N entries) + + +A directory block must be followed by at least N packets, otherwise it must be considered invalid. It can be used to efficiently load portions of the file to memory and to support operations on memory mapped files. This block can be added by tools like network analyzers as a consequence of file processing. +
    + +
    +One or more blocks could be defined to contain network statistics or traffic monitoring information. They could be use to store data collected from RMON or Netflow probes, or from other network monitoring tools. +
    + +
    +This block could be used to store events. Events could contain generic information (for example network load over 50%, server down...) or security alerts. An event could be: + + +skipped, if the application doesn't know how to do with it +processed independently by the packets. In other words, the applications skips the packets and processes only the alerts +processed in relation to packets: for example, a security tool could load only the packets of the file that are near a security alert; a monitorg tool could skip the packets captured while the server was down. + + +
    + +
    + + + + +
    +The file format proposed in this document should be very versatile and satisfy a wide range of applications. +In the simplest case, it can contain a raw dump of the network data, made of a series of Simple Packet Blocks. +In the most complex case, it can be used as a repository for heterogeneous information. +In every case, the file remains easy to parse and an application can always skip the data it is not interested in; at the same time, different applications can share the file, and each of them can benfit of the information produced by the others. +Two or more files can be concatenated obtaining another valid file. +
    + + +
    + +Data, in the file, must be byte or word aligned? Currently, the structure of this document is not consistent with respect to this point. + +
    + +
    + +
    diff --git a/tcpdump/jni/libpcap/etherent.c b/tcpdump/jni/libpcap/etherent.c new file mode 100644 index 0000000..707fd9d --- /dev/null +++ b/tcpdump/jni/libpcap/etherent.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#endif /* WIN32 */ + +#include +#include +#include +#include + +#include "pcap-int.h" + +#include + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +static inline int xdtoi(int); +static inline int skip_space(FILE *); +static inline int skip_line(FILE *); + +/* Hex digit to integer. */ +static inline int +xdtoi(c) + register int c; +{ + if (isdigit(c)) + return c - '0'; + else if (islower(c)) + return c - 'a' + 10; + else + return c - 'A' + 10; +} + +static inline int +skip_space(f) + FILE *f; +{ + int c; + + do { + c = getc(f); + } while (isspace(c) && c != '\n'); + + return c; +} + +static inline int +skip_line(f) + FILE *f; +{ + int c; + + do + c = getc(f); + while (c != '\n' && c != EOF); + + return c; +} + +struct pcap_etherent * +pcap_next_etherent(FILE *fp) +{ + register int c, d, i; + char *bp; + static struct pcap_etherent e; + + memset((char *)&e, 0, sizeof(e)); + do { + /* Find addr */ + c = skip_space(fp); + if (c == '\n') + continue; + + /* If this is a comment, or first thing on line + cannot be etehrnet address, skip the line. */ + if (!isxdigit(c)) { + c = skip_line(fp); + continue; + } + + /* must be the start of an address */ + for (i = 0; i < 6; i += 1) { + d = xdtoi(c); + c = getc(fp); + if (isxdigit(c)) { + d <<= 4; + d |= xdtoi(c); + c = getc(fp); + } + e.addr[i] = d; + if (c != ':') + break; + c = getc(fp); + } + if (c == EOF) + break; + + /* Must be whitespace */ + if (!isspace(c)) { + c = skip_line(fp); + continue; + } + c = skip_space(fp); + + /* hit end of line... */ + if (c == '\n') + continue; + + if (c == '#') { + c = skip_line(fp); + continue; + } + + /* pick up name */ + bp = e.name; + /* Use 'd' to prevent buffer overflow. */ + d = sizeof(e.name) - 1; + do { + *bp++ = c; + c = getc(fp); + } while (!isspace(c) && c != EOF && --d > 0); + *bp = '\0'; + + /* Eat trailing junk */ + if (c != '\n') + (void)skip_line(fp); + + return &e; + + } while (c != EOF); + + return (NULL); +} diff --git a/tcpdump/jni/libpcap/ethertype.h b/tcpdump/jni/libpcap/ethertype.h new file mode 100644 index 0000000..8bab881 --- /dev/null +++ b/tcpdump/jni/libpcap/ethertype.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1993, 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Ethernet types. + * + * We wrap the declarations with #ifdef, so that if a file includes + * , which may declare some of these, we don't + * get a bunch of complaints from the C compiler about redefinitions + * of these values. + * + * We declare all of them here so that no file has to include + * if all it needs are ETHERTYPE_ values. + */ + +#ifndef ETHERTYPE_PUP +#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */ +#endif +#ifndef ETHERTYPE_REVARP +#define ETHERTYPE_REVARP 0x8035 /* reverse Addr. resolution protocol */ +#endif +#ifndef ETHERTYPE_NS +#define ETHERTYPE_NS 0x0600 +#endif +#ifndef ETHERTYPE_SPRITE +#define ETHERTYPE_SPRITE 0x0500 +#endif +#ifndef ETHERTYPE_TRAIL +#define ETHERTYPE_TRAIL 0x1000 +#endif +#ifndef ETHERTYPE_MOPDL +#define ETHERTYPE_MOPDL 0x6001 +#endif +#ifndef ETHERTYPE_MOPRC +#define ETHERTYPE_MOPRC 0x6002 +#endif +#ifndef ETHERTYPE_DN +#define ETHERTYPE_DN 0x6003 +#endif +#ifndef ETHERTYPE_LAT +#define ETHERTYPE_LAT 0x6004 +#endif +#ifndef ETHERTYPE_SCA +#define ETHERTYPE_SCA 0x6007 +#endif +#ifndef ETHERTYPE_REVARP +#define ETHERTYPE_REVARP 0x8035 +#endif +#ifndef ETHERTYPE_LANBRIDGE +#define ETHERTYPE_LANBRIDGE 0x8038 +#endif +#ifndef ETHERTYPE_DECDNS +#define ETHERTYPE_DECDNS 0x803c +#endif +#ifndef ETHERTYPE_DECDTS +#define ETHERTYPE_DECDTS 0x803e +#endif +#ifndef ETHERTYPE_VEXP +#define ETHERTYPE_VEXP 0x805b +#endif +#ifndef ETHERTYPE_VPROD +#define ETHERTYPE_VPROD 0x805c +#endif +#ifndef ETHERTYPE_ATALK +#define ETHERTYPE_ATALK 0x809b +#endif +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 +#endif +#ifndef ETHERTYPE_8021Q +#define ETHERTYPE_8021Q 0x8100 +#endif +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 +#endif +#ifndef ETHERTYPE_IPV6 +#define ETHERTYPE_IPV6 0x86dd +#endif +#ifndef ETHERTYPE_MPLS +#define ETHERTYPE_MPLS 0x8847 +#endif +#ifndef ETHERTYPE_MPLS_MULTI +#define ETHERTYPE_MPLS_MULTI 0x8848 +#endif +#ifndef ETHERTYPE_PPPOED +#define ETHERTYPE_PPPOED 0x8863 +#endif +#ifndef ETHERTYPE_PPPOES +#define ETHERTYPE_PPPOES 0x8864 +#endif +#ifndef ETHERTYPE_LOOPBACK +#define ETHERTYPE_LOOPBACK 0x9000 +#endif +#ifndef ETHERTYPE_8021QINQ +#define ETHERTYPE_8021QINQ 0x9100 +#endif diff --git a/tcpdump/jni/libpcap/fad-getad.c b/tcpdump/jni/libpcap/fad-getad.c new file mode 100644 index 0000000..6fd3360 --- /dev/null +++ b/tcpdump/jni/libpcap/fad-getad.c @@ -0,0 +1,280 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * We don't do this on Solaris 11 and later, as it appears there aren't + * any AF_PACKET addresses on interfaces, so we don't need this, and + * we end up including both the OS's and our , + * and their definitions of some data structures collide. + */ +#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) +# ifdef HAVE_NETPACKET_PACKET_H +/* Linux distributions with newer glibc */ +# include +# else /* HAVE_NETPACKET_PACKET_H */ +/* LynxOS, Linux distributions with older glibc */ +# ifdef __Lynx__ +/* LynxOS */ +# include +# else /* __Lynx__ */ +/* Linux */ +# include +# include +# endif /* __Lynx__ */ +# endif /* HAVE_NETPACKET_PACKET_H */ +#endif /* (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) */ + +/* + * This is fun. + * + * In older BSD systems, socket addresses were fixed-length, and + * "sizeof (struct sockaddr)" gave the size of the structure. + * All addresses fit within a "struct sockaddr". + * + * In newer BSD systems, the socket address is variable-length, and + * there's an "sa_len" field giving the length of the structure; + * this allows socket addresses to be longer than 2 bytes of family + * and 14 bytes of data. + * + * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553 + * variant of the old BSD scheme (with "struct sockaddr_storage" rather + * than "struct sockaddr"), and some use the new BSD scheme. + * + * Some versions of GNU libc use neither scheme, but has an "SA_LEN()" + * macro that determines the size based on the address family. Other + * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553 + * but not in the final version). On the latter systems, we explicitly + * check the AF_ type to determine the length; we assume that on + * all those systems we have "struct sockaddr_storage". + */ +#ifndef SA_LEN +#ifdef HAVE_SOCKADDR_SA_LEN +#define SA_LEN(addr) ((addr)->sa_len) +#else /* HAVE_SOCKADDR_SA_LEN */ +#ifdef HAVE_SOCKADDR_STORAGE +static size_t +get_sa_len(struct sockaddr *addr) +{ + switch (addr->sa_family) { + +#ifdef AF_INET + case AF_INET: + return (sizeof (struct sockaddr_in)); +#endif + +#ifdef AF_INET6 + case AF_INET6: + return (sizeof (struct sockaddr_in6)); +#endif + +#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) + case AF_PACKET: + return (sizeof (struct sockaddr_ll)); +#endif + + default: + return (sizeof (struct sockaddr)); + } +} +#define SA_LEN(addr) (get_sa_len(addr)) +#else /* HAVE_SOCKADDR_STORAGE */ +#define SA_LEN(addr) (sizeof (struct sockaddr)) +#endif /* HAVE_SOCKADDR_STORAGE */ +#endif /* HAVE_SOCKADDR_SA_LEN */ +#endif /* SA_LEN */ + +/* + * Get a list of all interfaces that are up and that we can open. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * could be opened. + */ +int +pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) +{ + pcap_if_t *devlist = NULL; + struct ifaddrs *ifap, *ifa; + struct sockaddr *addr, *netmask, *broadaddr, *dstaddr; + size_t addr_size, broadaddr_size, dstaddr_size; + int ret = 0; + char *p, *q; + + /* + * Get the list of interface addresses. + * + * Note: this won't return information about interfaces + * with no addresses, so, if a platform has interfaces + * with no interfaces on which traffic can be captured, + * we must check for those interfaces as well (see, for + * example, what's done on Linux). + * + * LAN interfaces will probably have link-layer + * addresses; I don't know whether all implementations + * of "getifaddrs()" now, or in the future, will return + * those. + */ + if (getifaddrs(&ifap) != 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "getifaddrs: %s", pcap_strerror(errno)); + return (-1); + } + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + /* + * "ifa_addr" was apparently null on at least one + * interface on some system. Therefore, we supply + * the address and netmask only if "ifa_addr" is + * non-null (if there's no address, there's obviously + * no netmask). + */ + if (ifa->ifa_addr != NULL) { + addr = ifa->ifa_addr; + addr_size = SA_LEN(addr); + netmask = ifa->ifa_netmask; + } else { + addr = NULL; + addr_size = 0; + netmask = NULL; + } + + /* + * Note that, on some platforms, ifa_broadaddr and + * ifa_dstaddr could be the same field (true on at + * least some versions of *BSD and OS X), so we + * can't just check whether the broadcast address + * is null and add it if so and check whether the + * destination address is null and add it if so. + * + * Therefore, we must also check the IFF_BROADCAST + * flag, and only add a broadcast address if it's + * set, and check the IFF_POINTTOPOINT flag, and + * only add a destination address if it's set (as + * per man page recommendations on some of those + * platforms). + */ + if (ifa->ifa_flags & IFF_BROADCAST && + ifa->ifa_broadaddr != NULL) { + broadaddr = ifa->ifa_broadaddr; + broadaddr_size = SA_LEN(broadaddr); + } else { + broadaddr = NULL; + broadaddr_size = 0; + } + if (ifa->ifa_flags & IFF_POINTOPOINT && + ifa->ifa_dstaddr != NULL) { + dstaddr = ifa->ifa_dstaddr; + dstaddr_size = SA_LEN(ifa->ifa_dstaddr); + } else { + dstaddr = NULL; + dstaddr_size = 0; + } + + /* + * If this entry has a colon followed by a number at + * the end, we assume it's a logical interface. Those + * are just the way you assign multiple IP addresses to + * a real interface on Linux, so an entry for a logical + * interface should be treated like the entry for the + * real interface; we do that by stripping off the ":" + * and the number. + * + * XXX - should we do this only on Linux? + */ + p = strchr(ifa->ifa_name, ':'); + if (p != NULL) { + /* + * We have a ":"; is it followed by a number? + */ + q = p + 1; + while (isdigit((unsigned char)*q)) + q++; + if (*q == '\0') { + /* + * All digits after the ":" until the end. + * Strip off the ":" and everything after + * it. + */ + *p = '\0'; + } + } + + /* + * Add information for this address to the list. + */ + if (add_addr_to_iflist(&devlist, ifa->ifa_name, + ifa->ifa_flags, addr, addr_size, netmask, addr_size, + broadaddr, broadaddr_size, dstaddr, dstaddr_size, + errbuf) < 0) { + ret = -1; + break; + } + } + + freeifaddrs(ifap); + + if (ret == -1) { + /* + * We had an error; free the list we've been constructing. + */ + if (devlist != NULL) { + pcap_freealldevs(devlist); + devlist = NULL; + } + } + + *alldevsp = devlist; + return (ret); +} diff --git a/tcpdump/jni/libpcap/fad-gifc.c b/tcpdump/jni/libpcap/fad-gifc.c new file mode 100644 index 0000000..b0a4105 --- /dev/null +++ b/tcpdump/jni/libpcap/fad-gifc.c @@ -0,0 +1,417 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif +#include /* concession to AIX */ + +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * This is fun. + * + * In older BSD systems, socket addresses were fixed-length, and + * "sizeof (struct sockaddr)" gave the size of the structure. + * All addresses fit within a "struct sockaddr". + * + * In newer BSD systems, the socket address is variable-length, and + * there's an "sa_len" field giving the length of the structure; + * this allows socket addresses to be longer than 2 bytes of family + * and 14 bytes of data. + * + * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553 + * variant of the old BSD scheme (with "struct sockaddr_storage" rather + * than "struct sockaddr"), and some use the new BSD scheme. + * + * Some versions of GNU libc use neither scheme, but has an "SA_LEN()" + * macro that determines the size based on the address family. Other + * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553 + * but not in the final version). + * + * We assume that a UNIX that doesn't have "getifaddrs()" and doesn't have + * SIOCGLIFCONF, but has SIOCGIFCONF, uses "struct sockaddr" for the + * address in an entry returned by SIOCGIFCONF. + */ +#ifndef SA_LEN +#ifdef HAVE_SOCKADDR_SA_LEN +#define SA_LEN(addr) ((addr)->sa_len) +#else /* HAVE_SOCKADDR_SA_LEN */ +#define SA_LEN(addr) (sizeof (struct sockaddr)) +#endif /* HAVE_SOCKADDR_SA_LEN */ +#endif /* SA_LEN */ + +/* + * This is also fun. + * + * There is no ioctl that returns the amount of space required for all + * the data that SIOCGIFCONF could return, and if a buffer is supplied + * that's not large enough for all the data SIOCGIFCONF could return, + * on at least some platforms it just returns the data that'd fit with + * no indication that there wasn't enough room for all the data, much + * less an indication of how much more room is required. + * + * The only way to ensure that we got all the data is to pass a buffer + * large enough that the amount of space in the buffer *not* filled in + * is greater than the largest possible entry. + * + * We assume that's "sizeof(ifreq.ifr_name)" plus 255, under the assumption + * that no address is more than 255 bytes (on systems where the "sa_len" + * field in a "struct sockaddr" is 1 byte, e.g. newer BSDs, that's the + * case, and addresses are unlikely to be bigger than that in any case). + */ +#define MAX_SA_LEN 255 + +/* + * Get a list of all interfaces that are up and that we can open. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * were up and could be opened. + * + * This is the implementation used on platforms that have SIOCGIFCONF but + * don't have any other mechanism for getting a list of interfaces. + * + * XXX - or platforms that have other, better mechanisms but for which + * we don't yet have code to use that mechanism; I think there's a better + * way on Linux, for example, but if that better way is "getifaddrs()", + * we already have that. + */ +int +pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) +{ + pcap_if_t *devlist = NULL; + register int fd; + register struct ifreq *ifrp, *ifend, *ifnext; + int n; + struct ifconf ifc; + char *buf = NULL; + unsigned buf_size; +#if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER) + char *p, *q; +#endif + struct ifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr; + struct sockaddr *netmask, *broadaddr, *dstaddr; + size_t netmask_size, broadaddr_size, dstaddr_size; + int ret = 0; + + /* + * Create a socket from which to fetch the list of interfaces. + */ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + return (-1); + } + + /* + * Start with an 8K buffer, and keep growing the buffer until + * we have more than "sizeof(ifrp->ifr_name) + MAX_SA_LEN" + * bytes left over in the buffer or we fail to get the + * interface list for some reason other than EINVAL (which is + * presumed here to mean "buffer is too small"). + */ + buf_size = 8192; + for (;;) { + buf = malloc(buf_size); + if (buf == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + (void)close(fd); + return (-1); + } + + ifc.ifc_len = buf_size; + ifc.ifc_buf = buf; + memset(buf, 0, buf_size); + if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 + && errno != EINVAL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFCONF: %s", pcap_strerror(errno)); + (void)close(fd); + free(buf); + return (-1); + } + if (ifc.ifc_len < buf_size && + (buf_size - ifc.ifc_len) > sizeof(ifrp->ifr_name) + MAX_SA_LEN) + break; + free(buf); + buf_size *= 2; + } + + ifrp = (struct ifreq *)buf; + ifend = (struct ifreq *)(buf + ifc.ifc_len); + + for (; ifrp < ifend; ifrp = ifnext) { + /* + * XXX - what if this isn't an IPv4 address? Can + * we still get the netmask, etc. with ioctls on + * an IPv4 socket? + * + * The answer is probably platform-dependent, and + * if the answer is "no" on more than one platform, + * the way you work around it is probably platform- + * dependent as well. + */ + n = SA_LEN(&ifrp->ifr_addr) + sizeof(ifrp->ifr_name); + if (n < sizeof(*ifrp)) + ifnext = ifrp + 1; + else + ifnext = (struct ifreq *)((char *)ifrp + n); + + /* + * XXX - The 32-bit compatibility layer for Linux on IA-64 + * is slightly broken. It correctly converts the structures + * to and from kernel land from 64 bit to 32 bit but + * doesn't update ifc.ifc_len, leaving it larger than the + * amount really used. This means we read off the end + * of the buffer and encounter an interface with an + * "empty" name. Since this is highly unlikely to ever + * occur in a valid case we can just finish looking for + * interfaces if we see an empty name. + */ + if (!(*ifrp->ifr_name)) + break; + + /* + * Skip entries that begin with "dummy". + * XXX - what are these? Is this Linux-specific? + * Are there platforms on which we shouldn't do this? + */ + if (strncmp(ifrp->ifr_name, "dummy", 5) == 0) + continue; + + /* + * Get the flags for this interface. + */ + strncpy(ifrflags.ifr_name, ifrp->ifr_name, + sizeof(ifrflags.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) { + if (errno == ENXIO) + continue; + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFFLAGS: %.*s: %s", + (int)sizeof(ifrflags.ifr_name), + ifrflags.ifr_name, + pcap_strerror(errno)); + ret = -1; + break; + } + + /* + * Get the netmask for this address on this interface. + */ + strncpy(ifrnetmask.ifr_name, ifrp->ifr_name, + sizeof(ifrnetmask.ifr_name)); + memcpy(&ifrnetmask.ifr_addr, &ifrp->ifr_addr, + sizeof(ifrnetmask.ifr_addr)); + if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifrnetmask) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + netmask = NULL; + netmask_size = 0; + } else { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFNETMASK: %.*s: %s", + (int)sizeof(ifrnetmask.ifr_name), + ifrnetmask.ifr_name, + pcap_strerror(errno)); + ret = -1; + break; + } + } else { + netmask = &ifrnetmask.ifr_addr; + netmask_size = SA_LEN(netmask); + } + + /* + * Get the broadcast address for this address on this + * interface (if any). + */ + if (ifrflags.ifr_flags & IFF_BROADCAST) { + strncpy(ifrbroadaddr.ifr_name, ifrp->ifr_name, + sizeof(ifrbroadaddr.ifr_name)); + memcpy(&ifrbroadaddr.ifr_addr, &ifrp->ifr_addr, + sizeof(ifrbroadaddr.ifr_addr)); + if (ioctl(fd, SIOCGIFBRDADDR, + (char *)&ifrbroadaddr) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + broadaddr = NULL; + broadaddr_size = 0; + } else { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFBRDADDR: %.*s: %s", + (int)sizeof(ifrbroadaddr.ifr_name), + ifrbroadaddr.ifr_name, + pcap_strerror(errno)); + ret = -1; + break; + } + } else { + broadaddr = &ifrbroadaddr.ifr_broadaddr; + broadaddr_size = SA_LEN(broadaddr); + } + } else { + /* + * Not a broadcast interface, so no broadcast + * address. + */ + broadaddr = NULL; + broadaddr_size = 0; + } + + /* + * Get the destination address for this address on this + * interface (if any). + */ + if (ifrflags.ifr_flags & IFF_POINTOPOINT) { + strncpy(ifrdstaddr.ifr_name, ifrp->ifr_name, + sizeof(ifrdstaddr.ifr_name)); + memcpy(&ifrdstaddr.ifr_addr, &ifrp->ifr_addr, + sizeof(ifrdstaddr.ifr_addr)); + if (ioctl(fd, SIOCGIFDSTADDR, + (char *)&ifrdstaddr) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + dstaddr = NULL; + dstaddr_size = 0; + } else { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFDSTADDR: %.*s: %s", + (int)sizeof(ifrdstaddr.ifr_name), + ifrdstaddr.ifr_name, + pcap_strerror(errno)); + ret = -1; + break; + } + } else { + dstaddr = &ifrdstaddr.ifr_dstaddr; + dstaddr_size = SA_LEN(dstaddr); + } + } else { + /* + * Not a point-to-point interface, so no destination + * address. + */ + dstaddr = NULL; + dstaddr_size = 0; + } + +#if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER) + /* + * If this entry has a colon followed by a number at + * the end, it's a logical interface. Those are just + * the way you assign multiple IP addresses to a real + * interface, so an entry for a logical interface should + * be treated like the entry for the real interface; + * we do that by stripping off the ":" and the number. + */ + p = strchr(ifrp->ifr_name, ':'); + if (p != NULL) { + /* + * We have a ":"; is it followed by a number? + */ + q = p + 1; + while (isdigit((unsigned char)*q)) + q++; + if (*q == '\0') { + /* + * All digits after the ":" until the end. + * Strip off the ":" and everything after + * it. + */ + *p = '\0'; + } + } +#endif + + /* + * Add information for this address to the list. + */ + if (add_addr_to_iflist(&devlist, ifrp->ifr_name, + ifrflags.ifr_flags, &ifrp->ifr_addr, + SA_LEN(&ifrp->ifr_addr), netmask, netmask_size, + broadaddr, broadaddr_size, dstaddr, dstaddr_size, + errbuf) < 0) { + ret = -1; + break; + } + } + free(buf); + (void)close(fd); + + if (ret == -1) { + /* + * We had an error; free the list we've been constructing. + */ + if (devlist != NULL) { + pcap_freealldevs(devlist); + devlist = NULL; + } + } + + *alldevsp = devlist; + return (ret); +} diff --git a/tcpdump/jni/libpcap/fad-glifc.c b/tcpdump/jni/libpcap/fad-glifc.c new file mode 100644 index 0000000..1a820ad --- /dev/null +++ b/tcpdump/jni/libpcap/fad-glifc.c @@ -0,0 +1,369 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif +#include /* concession to AIX */ + +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * Get a list of all interfaces that are up and that we can open. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * were up and could be opened. + * + * This is the implementation used on platforms that have SIOCGLIFCONF + * but don't have "getifaddrs()". (Solaris 8 and later; we use + * SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.) + */ +int +pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) +{ + pcap_if_t *devlist = NULL; + register int fd4, fd6, fd; + register struct lifreq *ifrp, *ifend; + struct lifnum ifn; + struct lifconf ifc; + char *buf = NULL; + unsigned buf_size; +#ifdef HAVE_SOLARIS + char *p, *q; +#endif + struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr; + struct sockaddr *netmask, *broadaddr, *dstaddr; + int ret = 0; + + /* + * Create a socket from which to fetch the list of interfaces, + * and from which to fetch IPv4 information. + */ + fd4 = socket(AF_INET, SOCK_DGRAM, 0); + if (fd4 < 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + return (-1); + } + + /* + * Create a socket from which to fetch IPv6 information. + */ + fd6 = socket(AF_INET6, SOCK_DGRAM, 0); + if (fd6 < 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + (void)close(fd4); + return (-1); + } + + /* + * How many entries will SIOCGLIFCONF return? + */ + ifn.lifn_family = AF_UNSPEC; + ifn.lifn_flags = 0; + ifn.lifn_count = 0; + if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGLIFNUM: %s", pcap_strerror(errno)); + (void)close(fd6); + (void)close(fd4); + return (-1); + } + + /* + * Allocate a buffer for those entries. + */ + buf_size = ifn.lifn_count * sizeof (struct lifreq); + buf = malloc(buf_size); + if (buf == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + (void)close(fd6); + (void)close(fd4); + return (-1); + } + + /* + * Get the entries. + */ + ifc.lifc_len = buf_size; + ifc.lifc_buf = buf; + ifc.lifc_family = AF_UNSPEC; + ifc.lifc_flags = 0; + memset(buf, 0, buf_size); + if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGLIFCONF: %s", pcap_strerror(errno)); + (void)close(fd6); + (void)close(fd4); + free(buf); + return (-1); + } + + /* + * Loop over the entries. + */ + ifrp = (struct lifreq *)buf; + ifend = (struct lifreq *)(buf + ifc.lifc_len); + + for (; ifrp < ifend; ifrp++) { + /* + * IPv6 or not? + */ + if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6) + fd = fd6; + else + fd = fd4; + + /* + * Skip entries that begin with "dummy". + * XXX - what are these? Is this Linux-specific? + * Are there platforms on which we shouldn't do this? + */ + if (strncmp(ifrp->lifr_name, "dummy", 5) == 0) + continue; + +#ifdef HAVE_SOLARIS + /* + * Skip entries that have a ":" followed by a number + * at the end - those are Solaris virtual interfaces + * on which you can't capture. + */ + p = strchr(ifrp->lifr_name, ':'); + if (p != NULL) { + /* + * We have a ":"; is it followed by a number? + */ + while (isdigit((unsigned char)*p)) + p++; + if (*p == '\0') { + /* + * All digits after the ":" until the end. + */ + continue; + } + } +#endif + + /* + * Get the flags for this interface. + */ + strncpy(ifrflags.lifr_name, ifrp->lifr_name, + sizeof(ifrflags.lifr_name)); + if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) { + if (errno == ENXIO) + continue; + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGLIFFLAGS: %.*s: %s", + (int)sizeof(ifrflags.lifr_name), + ifrflags.lifr_name, + pcap_strerror(errno)); + ret = -1; + break; + } + + /* + * Get the netmask for this address on this interface. + */ + strncpy(ifrnetmask.lifr_name, ifrp->lifr_name, + sizeof(ifrnetmask.lifr_name)); + memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr, + sizeof(ifrnetmask.lifr_addr)); + if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + netmask = NULL; + } else { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGLIFNETMASK: %.*s: %s", + (int)sizeof(ifrnetmask.lifr_name), + ifrnetmask.lifr_name, + pcap_strerror(errno)); + ret = -1; + break; + } + } else + netmask = (struct sockaddr *)&ifrnetmask.lifr_addr; + + /* + * Get the broadcast address for this address on this + * interface (if any). + */ + if (ifrflags.lifr_flags & IFF_BROADCAST) { + strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name, + sizeof(ifrbroadaddr.lifr_name)); + memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr, + sizeof(ifrbroadaddr.lifr_addr)); + if (ioctl(fd, SIOCGLIFBRDADDR, + (char *)&ifrbroadaddr) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + broadaddr = NULL; + } else { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGLIFBRDADDR: %.*s: %s", + (int)sizeof(ifrbroadaddr.lifr_name), + ifrbroadaddr.lifr_name, + pcap_strerror(errno)); + ret = -1; + break; + } + } else + broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr; + } else { + /* + * Not a broadcast interface, so no broadcast + * address. + */ + broadaddr = NULL; + } + + /* + * Get the destination address for this address on this + * interface (if any). + */ + if (ifrflags.lifr_flags & IFF_POINTOPOINT) { + strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name, + sizeof(ifrdstaddr.lifr_name)); + memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr, + sizeof(ifrdstaddr.lifr_addr)); + if (ioctl(fd, SIOCGLIFDSTADDR, + (char *)&ifrdstaddr) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + dstaddr = NULL; + } else { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGLIFDSTADDR: %.*s: %s", + (int)sizeof(ifrdstaddr.lifr_name), + ifrdstaddr.lifr_name, + pcap_strerror(errno)); + ret = -1; + break; + } + } else + dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr; + } else + dstaddr = NULL; + +#ifdef HAVE_SOLARIS + /* + * If this entry has a colon followed by a number at + * the end, it's a logical interface. Those are just + * the way you assign multiple IP addresses to a real + * interface, so an entry for a logical interface should + * be treated like the entry for the real interface; + * we do that by stripping off the ":" and the number. + */ + p = strchr(ifrp->lifr_name, ':'); + if (p != NULL) { + /* + * We have a ":"; is it followed by a number? + */ + q = p + 1; + while (isdigit((unsigned char)*q)) + q++; + if (*q == '\0') { + /* + * All digits after the ":" until the end. + * Strip off the ":" and everything after + * it. + */ + *p = '\0'; + } + } +#endif + + /* + * Add information for this address to the list. + */ + if (add_addr_to_iflist(&devlist, ifrp->lifr_name, + ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr, + sizeof (struct sockaddr_storage), + netmask, sizeof (struct sockaddr_storage), + broadaddr, sizeof (struct sockaddr_storage), + dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) { + ret = -1; + break; + } + } + free(buf); + (void)close(fd6); + (void)close(fd4); + + if (ret == -1) { + /* + * We had an error; free the list we've been constructing. + */ + if (devlist != NULL) { + pcap_freealldevs(devlist); + devlist = NULL; + } + } + + *alldevsp = devlist; + return (ret); +} diff --git a/tcpdump/jni/libpcap/fad-null.c b/tcpdump/jni/libpcap/fad-null.c new file mode 100644 index 0000000..cecfbcb --- /dev/null +++ b/tcpdump/jni/libpcap/fad-null.c @@ -0,0 +1,60 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +/* + * Get a list of all interfaces that are up and that we can open. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * were up and could be opened. + * + * This is the implementation used on platforms that have no support for + * packet capture. + */ +int +pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) +{ + /* + * Succeed, but don't return any interfaces; we return only those + * we can open, and we can't open any if there's no support + * for packet capture. + */ + *alldevsp = NULL; + return (0); +} diff --git a/tcpdump/jni/libpcap/fad-sita.c b/tcpdump/jni/libpcap/fad-sita.c new file mode 100644 index 0000000..34ddf1d --- /dev/null +++ b/tcpdump/jni/libpcap/fad-sita.c @@ -0,0 +1,59 @@ +/* + * fad-sita.c: Packet capture interface additions for SITA ACN devices + * + * Copyright (c) 2007 Fulko Hew, SITA INC Canada, Inc + * + * License: BSD + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "pcap-int.h" + +#include "pcap-sita.h" + +extern pcap_if_t *acn_if_list; /* pcap's list of available interfaces */ + +int pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) { + + //printf("pcap_findalldevs()\n"); // fulko + + *alldevsp = 0; /* initialize the returned variables before we do anything */ + strcpy(errbuf, ""); + if (acn_parse_hosts_file(errbuf)) /* scan the hosts file for potential IOPs */ + { + //printf("pcap_findalldevs() returning BAD after parsehosts\n"); // fulko + return -1; + } + //printf("pcap_findalldevs() got hostlist now finding devs\n"); // fulko + if (acn_findalldevs(errbuf)) /* then ask the IOPs for their monitorable devices */ + { + //printf("pcap_findalldevs() returning BAD after findalldevs\n"); // fulko + return -1; + } + *alldevsp = acn_if_list; + acn_if_list = 0; /* then forget our list head, because someone will call pcap_freealldevs() to empty the malloc'ed stuff */ + //printf("pcap_findalldevs() returning ZERO OK\n"); // fulko + return 0; +} diff --git a/tcpdump/jni/libpcap/fad-win32.c b/tcpdump/jni/libpcap/fad-win32.c new file mode 100644 index 0000000..0c856b1 --- /dev/null +++ b/tcpdump/jni/libpcap/fad-win32.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include + +static int +pcap_add_if_win32(pcap_if_t **devlist, char *name, const char *desc, + char *errbuf) +{ + pcap_if_t *curdev; + npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; + LONG if_addr_size; + int res = 0; + + if_addr_size = MAX_NETWORK_ADDRESSES; + + /* + * Add an entry for this interface, with no addresses. + */ + if (add_or_find_if(&curdev, devlist, name, 0, desc, errbuf) == -1) { + /* + * Failure. + */ + return (-1); + } + + /* + * Get the list of addresses for the interface. + */ + if (!PacketGetNetInfoEx((void *)name, if_addrs, &if_addr_size)) { + /* + * Failure. + * + * We don't return an error, because this can happen with + * NdisWan interfaces, and we want to supply them even + * if we can't supply their addresses. + * + * We return an entry with an empty address list. + */ + return (0); + } + + /* + * Now add the addresses. + */ + while (if_addr_size-- > 0) { + /* + * "curdev" is an entry for this interface; add an entry for + * this address to its list of addresses. + */ + if(curdev == NULL) + break; + res = add_addr_to_dev(curdev, + (struct sockaddr *)&if_addrs[if_addr_size].IPAddress, + sizeof (struct sockaddr_storage), + (struct sockaddr *)&if_addrs[if_addr_size].SubnetMask, + sizeof (struct sockaddr_storage), + (struct sockaddr *)&if_addrs[if_addr_size].Broadcast, + sizeof (struct sockaddr_storage), + NULL, + 0, + errbuf); + if (res == -1) { + /* + * Failure. + */ + break; + } + } + + return (res); +} + + +/* + * Get a list of all interfaces that are up and that we can open. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * were up and could be opened. + * + * Win32 implementation, based on WinPcap + */ +int +pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) +{ + pcap_if_t *devlist = NULL; + int ret = 0; + const char *desc; + char *AdaptersName; + ULONG NameLength; + char *name; + + /* + * Find out how big a buffer we need. + * + * This call should always return FALSE; if the error is + * ERROR_INSUFFICIENT_BUFFER, NameLength will be set to + * the size of the buffer we need, otherwise there's a + * problem, and NameLength should be set to 0. + * + * It shouldn't require NameLength to be set, but, + * at least as of WinPcap 4.1.3, it checks whether + * NameLength is big enough before it checks for a + * NULL buffer argument, so, while it'll still do + * the right thing if NameLength is uninitialized and + * whatever junk happens to be there is big enough + * (because the pointer argument will be null), it's + * still reading an uninitialized variable. + */ + NameLength = 0; + if (!PacketGetAdapterNames(NULL, &NameLength)) + { + DWORD last_error = GetLastError(); + + if (last_error != ERROR_INSUFFICIENT_BUFFER) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "PacketGetAdapterNames: %s", + pcap_win32strerror()); + return (-1); + } + } + + if (NameLength > 0) + AdaptersName = (char*) malloc(NameLength); + else + { + *alldevsp = NULL; + return 0; + } + if (AdaptersName == NULL) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters."); + return (-1); + } + + if (!PacketGetAdapterNames(AdaptersName, &NameLength)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "PacketGetAdapterNames: %s", + pcap_win32strerror()); + free(AdaptersName); + return (-1); + } + + /* + * "PacketGetAdapterNames()" returned a list of + * null-terminated ASCII interface name strings, + * terminated by a null string, followed by a list + * of null-terminated ASCII interface description + * strings, terminated by a null string. + * This means there are two ASCII nulls at the end + * of the first list. + * + * Find the end of the first list; that's the + * beginning of the second list. + */ + desc = &AdaptersName[0]; + while (*desc != '\0' || *(desc + 1) != '\0') + desc++; + + /* + * Found it - "desc" points to the first of the two + * nulls at the end of the list of names, so the + * first byte of the list of descriptions is two bytes + * after it. + */ + desc += 2; + + /* + * Loop over the elements in the first list. + */ + name = &AdaptersName[0]; + while (*name != '\0') { + /* + * Add an entry for this interface. + */ + if (pcap_add_if_win32(&devlist, name, desc, errbuf) == -1) { + /* + * Failure. + */ + ret = -1; + break; + } + name += strlen(name) + 1; + desc += strlen(desc) + 1; + } + + if (ret != -1) { + /* + * We haven't had any errors yet; do any platform-specific + * operations to add devices. + */ + if (pcap_platform_finddevs(&devlist, errbuf) < 0) + ret = -1; + } + + if (ret == -1) { + /* + * We had an error; free the list we've been constructing. + */ + if (devlist != NULL) { + pcap_freealldevs(devlist); + devlist = NULL; + } + } + + *alldevsp = devlist; + free(AdaptersName); + return (ret); +} diff --git a/tcpdump/jni/libpcap/gencode.c b/tcpdump/jni/libpcap/gencode.c new file mode 100644 index 0000000..ad938d4 --- /dev/null +++ b/tcpdump/jni/libpcap/gencode.c @@ -0,0 +1,8904 @@ +/*#define CHASE_CHAIN*/ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#include +#endif /* WIN32 */ + +/* + * XXX - why was this included even on UNIX? + */ +#ifdef __MINGW32__ +#include "ip6_misc.h" +#endif + +#ifndef WIN32 + +#ifdef __NetBSD__ +#include +#endif + +#include +#include + +#endif /* WIN32 */ + +#include +#include +#include +#include +#include + +#ifdef MSDOS +#include "pcap-dos.h" +#endif + +#include "pcap-int.h" + +#include "ethertype.h" +#include "nlpid.h" +#include "llc.h" +#include "gencode.h" +#include "ieee80211.h" +#include "atmuni31.h" +#include "sunatmpos.h" +#include "ppp.h" +#include "pcap/sll.h" +#include "pcap/ipnet.h" +#include "arcnet.h" +#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) +#include +#include +#include +#endif +#ifdef HAVE_NET_PFVAR_H +#include +#include +#include +#include +#endif +#ifndef offsetof +#define offsetof(s, e) ((size_t)&((s *)0)->e) +#endif +#ifdef INET6 +#ifndef WIN32 +#include /* for "struct addrinfo" */ +#endif /* WIN32 */ +#endif /*INET6*/ +#include + +#define ETHERMTU 1500 + +#ifndef ETHERTYPE_TEB +#define ETHERTYPE_TEB 0x6558 +#endif + +#ifndef IPPROTO_HOPOPTS +#define IPPROTO_HOPOPTS 0 +#endif +#ifndef IPPROTO_ROUTING +#define IPPROTO_ROUTING 43 +#endif +#ifndef IPPROTO_FRAGMENT +#define IPPROTO_FRAGMENT 44 +#endif +#ifndef IPPROTO_DSTOPTS +#define IPPROTO_DSTOPTS 60 +#endif +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif + +#define GENEVE_PORT 6081 + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#define JMP(c) ((c)|BPF_JMP|BPF_K) + +/* Locals */ +static jmp_buf top_ctx; +static pcap_t *bpf_pcap; + +/* Hack for handling VLAN and MPLS stacks. */ +#ifdef WIN32 +static u_int label_stack_depth = (u_int)-1, vlan_stack_depth = (u_int)-1; +#else +static u_int label_stack_depth = -1U, vlan_stack_depth = -1U; +#endif + +/* XXX */ +static int pcap_fddipad; + +/* VARARGS */ +void +bpf_error(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (bpf_pcap != NULL) + (void)vsnprintf(pcap_geterr(bpf_pcap), PCAP_ERRBUF_SIZE, + fmt, ap); + va_end(ap); + longjmp(top_ctx, 1); + /* NOTREACHED */ +} + +static void init_linktype(pcap_t *); + +static void init_regs(void); +static int alloc_reg(void); +static void free_reg(int); + +static struct block *root; + +/* + * Absolute offsets, which are offsets from the beginning of the raw + * packet data, are, in the general case, the sum of a variable value + * and a constant value; the variable value may be absent, in which + * case the offset is only the constant value, and the constant value + * may be zero, in which case the offset is only the variable value. + * + * bpf_abs_offset is a structure containing all that information: + * + * is_variable is 1 if there's a variable part. + * + * constant_part is the constant part of the value, possibly zero; + * + * if is_variable is 1, reg is the register number for a register + * containing the variable value if the register has been assigned, + * and -1 otherwise. + */ +typedef struct { + int is_variable; + u_int constant_part; + int reg; +} bpf_abs_offset; + +/* + * Value passed to gen_load_a() to indicate what the offset argument + * is relative to the beginning of. + */ +enum e_offrel { + OR_PACKET, /* full packet data */ + OR_LINKHDR, /* link-layer header */ + OR_PREVLINKHDR, /* previous link-layer header */ + OR_LLC, /* 802.2 LLC header */ + OR_PREVMPLSHDR, /* previous MPLS header */ + OR_LINKTYPE, /* link-layer type */ + OR_LINKPL, /* link-layer payload */ + OR_LINKPL_NOSNAP, /* link-layer payload, with no SNAP header at the link layer */ + OR_TRAN_IPV4, /* transport-layer header, with IPv4 network layer */ + OR_TRAN_IPV6 /* transport-layer header, with IPv6 network layer */ +}; + +#ifdef INET6 +/* + * As errors are handled by a longjmp, anything allocated must be freed + * in the longjmp handler, so it must be reachable from that handler. + * One thing that's allocated is the result of pcap_nametoaddrinfo(); + * it must be freed with freeaddrinfo(). This variable points to any + * addrinfo structure that would need to be freed. + */ +static struct addrinfo *ai; +#endif + +/* + * We divy out chunks of memory rather than call malloc each time so + * we don't have to worry about leaking memory. It's probably + * not a big deal if all this memory was wasted but if this ever + * goes into a library that would probably not be a good idea. + * + * XXX - this *is* in a library.... + */ +#define NCHUNKS 16 +#define CHUNK0SIZE 1024 +struct chunk { + u_int n_left; + void *m; +}; + +static struct chunk chunks[NCHUNKS]; +static int cur_chunk; + +static void *newchunk(u_int); +static void freechunks(void); +static inline struct block *new_block(int); +static inline struct slist *new_stmt(int); +static struct block *gen_retblk(int); +static inline void syntax(void); + +static void backpatch(struct block *, struct block *); +static void merge(struct block *, struct block *); +static struct block *gen_cmp(enum e_offrel, u_int, u_int, bpf_int32); +static struct block *gen_cmp_gt(enum e_offrel, u_int, u_int, bpf_int32); +static struct block *gen_cmp_ge(enum e_offrel, u_int, u_int, bpf_int32); +static struct block *gen_cmp_lt(enum e_offrel, u_int, u_int, bpf_int32); +static struct block *gen_cmp_le(enum e_offrel, u_int, u_int, bpf_int32); +static struct block *gen_mcmp(enum e_offrel, u_int, u_int, bpf_int32, + bpf_u_int32); +static struct block *gen_bcmp(enum e_offrel, u_int, u_int, const u_char *); +static struct block *gen_ncmp(enum e_offrel, bpf_u_int32, bpf_u_int32, + bpf_u_int32, bpf_u_int32, int, bpf_int32); +static struct slist *gen_load_absoffsetrel(bpf_abs_offset *, u_int, u_int); +static struct slist *gen_load_a(enum e_offrel, u_int, u_int); +static struct slist *gen_loadx_iphdrlen(void); +static struct block *gen_uncond(int); +static inline struct block *gen_true(void); +static inline struct block *gen_false(void); +static struct block *gen_ether_linktype(int); +static struct block *gen_ipnet_linktype(int); +static struct block *gen_linux_sll_linktype(int); +static struct slist *gen_load_prism_llprefixlen(void); +static struct slist *gen_load_avs_llprefixlen(void); +static struct slist *gen_load_radiotap_llprefixlen(void); +static struct slist *gen_load_ppi_llprefixlen(void); +static void insert_compute_vloffsets(struct block *); +static struct slist *gen_abs_offset_varpart(bpf_abs_offset *); +static int ethertype_to_ppptype(int); +static struct block *gen_linktype(int); +static struct block *gen_snap(bpf_u_int32, bpf_u_int32); +static struct block *gen_llc_linktype(int); +static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int); +#ifdef INET6 +static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, u_int, u_int); +#endif +static struct block *gen_ahostop(const u_char *, int); +static struct block *gen_ehostop(const u_char *, int); +static struct block *gen_fhostop(const u_char *, int); +static struct block *gen_thostop(const u_char *, int); +static struct block *gen_wlanhostop(const u_char *, int); +static struct block *gen_ipfchostop(const u_char *, int); +static struct block *gen_dnhostop(bpf_u_int32, int); +static struct block *gen_mpls_linktype(int); +static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int, int); +#ifdef INET6 +static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int, int); +#endif +#ifndef INET6 +static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int); +#endif +static struct block *gen_ipfrag(void); +static struct block *gen_portatom(int, bpf_int32); +static struct block *gen_portrangeatom(int, bpf_int32, bpf_int32); +static struct block *gen_portatom6(int, bpf_int32); +static struct block *gen_portrangeatom6(int, bpf_int32, bpf_int32); +struct block *gen_portop(int, int, int); +static struct block *gen_port(int, int, int); +struct block *gen_portrangeop(int, int, int, int); +static struct block *gen_portrange(int, int, int, int); +struct block *gen_portop6(int, int, int); +static struct block *gen_port6(int, int, int); +struct block *gen_portrangeop6(int, int, int, int); +static struct block *gen_portrange6(int, int, int, int); +static int lookup_proto(const char *, int); +static struct block *gen_protochain(int, int, int); +static struct block *gen_proto(int, int, int); +static struct slist *xfer_to_x(struct arth *); +static struct slist *xfer_to_a(struct arth *); +static struct block *gen_mac_multicast(int); +static struct block *gen_len(int, int); +static struct block *gen_check_802_11_data_frame(void); +static struct block *gen_geneve_ll_check(void); + +static struct block *gen_ppi_dlt_check(void); +static struct block *gen_msg_abbrev(int type); + +static void * +newchunk(n) + u_int n; +{ + struct chunk *cp; + int k; + size_t size; + +#ifndef __NetBSD__ + /* XXX Round up to nearest long. */ + n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1); +#else + /* XXX Round up to structure boundary. */ + n = ALIGN(n); +#endif + + cp = &chunks[cur_chunk]; + if (n > cp->n_left) { + ++cp, k = ++cur_chunk; + if (k >= NCHUNKS) + bpf_error("out of memory"); + size = CHUNK0SIZE << k; + cp->m = (void *)malloc(size); + if (cp->m == NULL) + bpf_error("out of memory"); + memset((char *)cp->m, 0, size); + cp->n_left = size; + if (n > size) + bpf_error("out of memory"); + } + cp->n_left -= n; + return (void *)((char *)cp->m + cp->n_left); +} + +static void +freechunks() +{ + int i; + + cur_chunk = 0; + for (i = 0; i < NCHUNKS; ++i) + if (chunks[i].m != NULL) { + free(chunks[i].m); + chunks[i].m = NULL; + } +} + +/* + * A strdup whose allocations are freed after code generation is over. + */ +char * +sdup(s) + register const char *s; +{ + int n = strlen(s) + 1; + char *cp = newchunk(n); + + strlcpy(cp, s, n); + return (cp); +} + +static inline struct block * +new_block(code) + int code; +{ + struct block *p; + + p = (struct block *)newchunk(sizeof(*p)); + p->s.code = code; + p->head = p; + + return p; +} + +static inline struct slist * +new_stmt(code) + int code; +{ + struct slist *p; + + p = (struct slist *)newchunk(sizeof(*p)); + p->s.code = code; + + return p; +} + +static struct block * +gen_retblk(v) + int v; +{ + struct block *b = new_block(BPF_RET|BPF_K); + + b->s.k = v; + return b; +} + +static inline void +syntax() +{ + bpf_error("syntax error in filter expression"); +} + +static bpf_u_int32 netmask; +static int snaplen; +int no_optimize; + +int +pcap_compile(pcap_t *p, struct bpf_program *program, + const char *buf, int optimize, bpf_u_int32 mask) +{ + extern int n_errors; + const char * volatile xbuf = buf; + u_int len; + int rc; + + /* + * XXX - single-thread this code path with pthread calls on + * UN*X, if the platform supports pthreads? If that requires + * a separate -lpthread, we might not want to do that. + */ +#ifdef WIN32 + extern int wsockinit (void); + static int done = 0; + + if (!done) + wsockinit(); + done = 1; + EnterCriticalSection(&g_PcapCompileCriticalSection); +#endif + + /* + * If this pcap_t hasn't been activated, it doesn't have a + * link-layer type, so we can't use it. + */ + if (!p->activated) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "not-yet-activated pcap_t passed to pcap_compile"); + rc = -1; + goto quit; + } + no_optimize = 0; + n_errors = 0; + root = NULL; + bpf_pcap = p; + init_regs(); + + if (setjmp(top_ctx)) { +#ifdef INET6 + if (ai != NULL) { + freeaddrinfo(ai); + ai = NULL; + } +#endif + lex_cleanup(); + freechunks(); + rc = -1; + goto quit; + } + + netmask = mask; + + snaplen = pcap_snapshot(p); + if (snaplen == 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snaplen of 0 rejects all packets"); + rc = -1; + goto quit; + } + + lex_init(xbuf ? xbuf : ""); + init_linktype(p); + (void)pcap_parse(); + + if (n_errors) + syntax(); + + if (root == NULL) + root = gen_retblk(snaplen); + + if (optimize && !no_optimize) { + bpf_optimize(&root); + if (root == NULL || + (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0)) + bpf_error("expression rejects all packets"); + } + program->bf_insns = icode_to_fcode(root, &len); + program->bf_len = len; + + lex_cleanup(); + freechunks(); + + rc = 0; /* We're all okay */ + +quit: + +#ifdef WIN32 + LeaveCriticalSection(&g_PcapCompileCriticalSection); +#endif + + return (rc); +} + +/* + * entry point for using the compiler with no pcap open + * pass in all the stuff that is needed explicitly instead. + */ +int +pcap_compile_nopcap(int snaplen_arg, int linktype_arg, + struct bpf_program *program, + const char *buf, int optimize, bpf_u_int32 mask) +{ + pcap_t *p; + int ret; + + p = pcap_open_dead(linktype_arg, snaplen_arg); + if (p == NULL) + return (-1); + ret = pcap_compile(p, program, buf, optimize, mask); + pcap_close(p); + return (ret); +} + +/* + * Clean up a "struct bpf_program" by freeing all the memory allocated + * in it. + */ +void +pcap_freecode(struct bpf_program *program) +{ + program->bf_len = 0; + if (program->bf_insns != NULL) { + free((char *)program->bf_insns); + program->bf_insns = NULL; + } +} + +/* + * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates + * which of the jt and jf fields has been resolved and which is a pointer + * back to another unresolved block (or nil). At least one of the fields + * in each block is already resolved. + */ +static void +backpatch(list, target) + struct block *list, *target; +{ + struct block *next; + + while (list) { + if (!list->sense) { + next = JT(list); + JT(list) = target; + } else { + next = JF(list); + JF(list) = target; + } + list = next; + } +} + +/* + * Merge the lists in b0 and b1, using the 'sense' field to indicate + * which of jt and jf is the link. + */ +static void +merge(b0, b1) + struct block *b0, *b1; +{ + register struct block **p = &b0; + + /* Find end of list. */ + while (*p) + p = !((*p)->sense) ? &JT(*p) : &JF(*p); + + /* Concatenate the lists. */ + *p = b1; +} + +void +finish_parse(p) + struct block *p; +{ + struct block *ppi_dlt_check; + + /* + * Insert before the statements of the first (root) block any + * statements needed to load the lengths of any variable-length + * headers into registers. + * + * XXX - a fancier strategy would be to insert those before the + * statements of all blocks that use those lengths and that + * have no predecessors that use them, so that we only compute + * the lengths if we need them. There might be even better + * approaches than that. + * + * However, those strategies would be more complicated, and + * as we don't generate code to compute a length if the + * program has no tests that use the length, and as most + * tests will probably use those lengths, we would just + * postpone computing the lengths so that it's not done + * for tests that fail early, and it's not clear that's + * worth the effort. + */ + insert_compute_vloffsets(p->head); + + /* + * For DLT_PPI captures, generate a check of the per-packet + * DLT value to make sure it's DLT_IEEE802_11. + */ + ppi_dlt_check = gen_ppi_dlt_check(); + if (ppi_dlt_check != NULL) + gen_and(ppi_dlt_check, p); + + backpatch(p, gen_retblk(snaplen)); + p->sense = !p->sense; + backpatch(p, gen_retblk(0)); + root = p->head; +} + +void +gen_and(b0, b1) + struct block *b0, *b1; +{ + backpatch(b0, b1->head); + b0->sense = !b0->sense; + b1->sense = !b1->sense; + merge(b1, b0); + b1->sense = !b1->sense; + b1->head = b0->head; +} + +void +gen_or(b0, b1) + struct block *b0, *b1; +{ + b0->sense = !b0->sense; + backpatch(b0, b1->head); + b0->sense = !b0->sense; + merge(b1, b0); + b1->head = b0->head; +} + +void +gen_not(b) + struct block *b; +{ + b->sense = !b->sense; +} + +static struct block * +gen_cmp(offrel, offset, size, v) + enum e_offrel offrel; + u_int offset, size; + bpf_int32 v; +{ + return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v); +} + +static struct block * +gen_cmp_gt(offrel, offset, size, v) + enum e_offrel offrel; + u_int offset, size; + bpf_int32 v; +{ + return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGT, 0, v); +} + +static struct block * +gen_cmp_ge(offrel, offset, size, v) + enum e_offrel offrel; + u_int offset, size; + bpf_int32 v; +{ + return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGE, 0, v); +} + +static struct block * +gen_cmp_lt(offrel, offset, size, v) + enum e_offrel offrel; + u_int offset, size; + bpf_int32 v; +{ + return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGE, 1, v); +} + +static struct block * +gen_cmp_le(offrel, offset, size, v) + enum e_offrel offrel; + u_int offset, size; + bpf_int32 v; +{ + return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGT, 1, v); +} + +static struct block * +gen_mcmp(offrel, offset, size, v, mask) + enum e_offrel offrel; + u_int offset, size; + bpf_int32 v; + bpf_u_int32 mask; +{ + return gen_ncmp(offrel, offset, size, mask, BPF_JEQ, 0, v); +} + +static struct block * +gen_bcmp(offrel, offset, size, v) + enum e_offrel offrel; + register u_int offset, size; + register const u_char *v; +{ + register struct block *b, *tmp; + + b = NULL; + while (size >= 4) { + register const u_char *p = &v[size - 4]; + bpf_int32 w = ((bpf_int32)p[0] << 24) | + ((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3]; + + tmp = gen_cmp(offrel, offset + size - 4, BPF_W, w); + if (b != NULL) + gen_and(b, tmp); + b = tmp; + size -= 4; + } + while (size >= 2) { + register const u_char *p = &v[size - 2]; + bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1]; + + tmp = gen_cmp(offrel, offset + size - 2, BPF_H, w); + if (b != NULL) + gen_and(b, tmp); + b = tmp; + size -= 2; + } + if (size > 0) { + tmp = gen_cmp(offrel, offset, BPF_B, (bpf_int32)v[0]); + if (b != NULL) + gen_and(b, tmp); + b = tmp; + } + return b; +} + +/* + * AND the field of size "size" at offset "offset" relative to the header + * specified by "offrel" with "mask", and compare it with the value "v" + * with the test specified by "jtype"; if "reverse" is true, the test + * should test the opposite of "jtype". + */ +static struct block * +gen_ncmp(offrel, offset, size, mask, jtype, reverse, v) + enum e_offrel offrel; + bpf_int32 v; + bpf_u_int32 offset, size, mask, jtype; + int reverse; +{ + struct slist *s, *s2; + struct block *b; + + s = gen_load_a(offrel, offset, size); + + if (mask != 0xffffffff) { + s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K); + s2->s.k = mask; + sappend(s, s2); + } + + b = new_block(JMP(jtype)); + b->stmts = s; + b->s.k = v; + if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE)) + gen_not(b); + return b; +} + +/* + * Various code constructs need to know the layout of the packet. + * These variables give the necessary offsets from the beginning + * of the packet data. + */ + +/* + * Absolute offset of the beginning of the link-layer header. + */ +static bpf_abs_offset off_linkhdr; + +/* + * If we're checking a link-layer header for a packet encapsulated in + * another protocol layer, this is the equivalent information for the + * previous layers' link-layer header from the beginning of the raw + * packet data. + */ +static bpf_abs_offset off_prevlinkhdr; + +/* + * This is the equivalent information for the outermost layers' link-layer + * header. + */ +static bpf_abs_offset off_outermostlinkhdr; + +/* + * "Push" the current value of the link-layer header type and link-layer + * header offset onto a "stack", and set a new value. (It's not a + * full-blown stack; we keep only the top two items.) + */ +#define PUSH_LINKHDR(new_linktype, new_is_variable, new_constant_part, new_reg) \ +{ \ + prevlinktype = new_linktype; \ + off_prevlinkhdr = off_linkhdr; \ + linktype = new_linktype; \ + off_linkhdr.is_variable = new_is_variable; \ + off_linkhdr.constant_part = new_constant_part; \ + off_linkhdr.reg = new_reg; \ + is_geneve = 0; \ +} + +/* + * Absolute offset of the beginning of the link-layer payload. + */ +static bpf_abs_offset off_linkpl; + +/* + * "off_linktype" is the offset to information in the link-layer header + * giving the packet type. This is an absolute offset from the beginning + * of the packet. + * + * For Ethernet, it's the offset of the Ethernet type field; this + * means that it must have a value that skips VLAN tags. + * + * For link-layer types that always use 802.2 headers, it's the + * offset of the LLC header; this means that it must have a value + * that skips VLAN tags. + * + * For PPP, it's the offset of the PPP type field. + * + * For Cisco HDLC, it's the offset of the CHDLC type field. + * + * For BSD loopback, it's the offset of the AF_ value. + * + * For Linux cooked sockets, it's the offset of the type field. + * + * off_linktype.constant_part is set to -1 for no encapsulation, + * in which case, IP is assumed. + */ +static bpf_abs_offset off_linktype; + +/* + * TRUE if the link layer includes an ATM pseudo-header. + */ +static int is_atm = 0; + +/* + * TRUE if "geneve" appeared in the filter; it causes us to generate + * code that checks for a Geneve header and assume that later filters + * apply to the encapsulated payload. + */ +static int is_geneve = 0; + +/* + * These are offsets for the ATM pseudo-header. + */ +static u_int off_vpi; +static u_int off_vci; +static u_int off_proto; + +/* + * These are offsets for the MTP2 fields. + */ +static u_int off_li; +static u_int off_li_hsl; + +/* + * These are offsets for the MTP3 fields. + */ +static u_int off_sio; +static u_int off_opc; +static u_int off_dpc; +static u_int off_sls; + +/* + * This is the offset of the first byte after the ATM pseudo_header, + * or -1 if there is no ATM pseudo-header. + */ +static u_int off_payload; + +/* + * These are offsets to the beginning of the network-layer header. + * They are relative to the beginning of the link-layer payload (i.e., + * they don't include off_linkhdr.constant_part or off_linkpl.constant_part). + * + * If the link layer never uses 802.2 LLC: + * + * "off_nl" and "off_nl_nosnap" are the same. + * + * If the link layer always uses 802.2 LLC: + * + * "off_nl" is the offset if there's a SNAP header following + * the 802.2 header; + * + * "off_nl_nosnap" is the offset if there's no SNAP header. + * + * If the link layer is Ethernet: + * + * "off_nl" is the offset if the packet is an Ethernet II packet + * (we assume no 802.3+802.2+SNAP); + * + * "off_nl_nosnap" is the offset if the packet is an 802.3 packet + * with an 802.2 header following it. + */ +static u_int off_nl; +static u_int off_nl_nosnap; + +static int linktype; +static int prevlinktype; +static int outermostlinktype; + +static void +init_linktype(p) + pcap_t *p; +{ + pcap_fddipad = p->fddipad; + + /* + * We start out with only one link-layer header. + */ + outermostlinktype = pcap_datalink(p); + off_outermostlinkhdr.constant_part = 0; + off_outermostlinkhdr.is_variable = 0; + off_outermostlinkhdr.reg = -1; + + prevlinktype = outermostlinktype; + off_prevlinkhdr.constant_part = 0; + off_prevlinkhdr.is_variable = 0; + off_prevlinkhdr.reg = -1; + + linktype = outermostlinktype; + off_linkhdr.constant_part = 0; + off_linkhdr.is_variable = 0; + off_linkhdr.reg = -1; + + /* + * XXX + */ + off_linkpl.constant_part = 0; + off_linkpl.is_variable = 0; + off_linkpl.reg = -1; + + off_linktype.constant_part = 0; + off_linktype.is_variable = 0; + off_linktype.reg = -1; + + /* + * Assume it's not raw ATM with a pseudo-header, for now. + */ + is_atm = 0; + off_vpi = -1; + off_vci = -1; + off_proto = -1; + off_payload = -1; + + /* + * And not Geneve. + */ + is_geneve = 0; + + /* + * And assume we're not doing SS7. + */ + off_li = -1; + off_li_hsl = -1; + off_sio = -1; + off_opc = -1; + off_dpc = -1; + off_sls = -1; + + label_stack_depth = 0; + vlan_stack_depth = 0; + + switch (linktype) { + + case DLT_ARCNET: + off_linktype.constant_part = 2; + off_linkpl.constant_part = 6; + off_nl = 0; /* XXX in reality, variable! */ + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_ARCNET_LINUX: + off_linktype.constant_part = 4; + off_linkpl.constant_part = 8; + off_nl = 0; /* XXX in reality, variable! */ + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_EN10MB: + off_linktype.constant_part = 12; + off_linkpl.constant_part = 14; /* Ethernet header length */ + off_nl = 0; /* Ethernet II */ + off_nl_nosnap = 3; /* 802.3+802.2 */ + break; + + case DLT_SLIP: + /* + * SLIP doesn't have a link level type. The 16 byte + * header is hacked into our SLIP driver. + */ + off_linktype.constant_part = -1; + off_linkpl.constant_part = 16; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_SLIP_BSDOS: + /* XXX this may be the same as the DLT_PPP_BSDOS case */ + off_linktype.constant_part = -1; + /* XXX end */ + off_linkpl.constant_part = 24; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_NULL: + case DLT_LOOP: + off_linktype.constant_part = 0; + off_linkpl.constant_part = 4; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_ENC: + off_linktype.constant_part = 0; + off_linkpl.constant_part = 12; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_PPP: + case DLT_PPP_PPPD: + case DLT_C_HDLC: /* BSD/OS Cisco HDLC */ + case DLT_PPP_SERIAL: /* NetBSD sync/async serial PPP */ + off_linktype.constant_part = 2; /* skip HDLC-like framing */ + off_linkpl.constant_part = 4; /* skip HDLC-like framing and protocol field */ + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_PPP_ETHER: + /* + * This does no include the Ethernet header, and + * only covers session state. + */ + off_linktype.constant_part = 6; + off_linkpl.constant_part = 8; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_PPP_BSDOS: + off_linktype.constant_part = 5; + off_linkpl.constant_part = 24; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_FDDI: + /* + * FDDI doesn't really have a link-level type field. + * We set "off_linktype" to the offset of the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? + */ + off_linktype.constant_part = 13; + off_linktype.constant_part += pcap_fddipad; + off_linkpl.constant_part = 13; /* FDDI MAC header length */ + off_linkpl.constant_part += pcap_fddipad; + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_IEEE802: + /* + * Token Ring doesn't really have a link-level type field. + * We set "off_linktype" to the offset of the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? + * + * XXX - the header is actually variable-length. + * Some various Linux patched versions gave 38 + * as "off_linktype" and 40 as "off_nl"; however, + * if a token ring packet has *no* routing + * information, i.e. is not source-routed, the correct + * values are 20 and 22, as they are in the vanilla code. + * + * A packet is source-routed iff the uppermost bit + * of the first byte of the source address, at an + * offset of 8, has the uppermost bit set. If the + * packet is source-routed, the total number of bytes + * of routing information is 2 plus bits 0x1F00 of + * the 16-bit value at an offset of 14 (shifted right + * 8 - figure out which byte that is). + */ + off_linktype.constant_part = 14; + off_linkpl.constant_part = 14; /* Token Ring MAC header length */ + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + off_linkhdr.is_variable = 1; + /* Fall through, 802.11 doesn't have a variable link + * prefix but is otherwise the same. */ + + case DLT_IEEE802_11: + /* + * 802.11 doesn't really have a link-level type field. + * We set "off_linktype.constant_part" to the offset of + * the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? + * + * We also handle variable-length radio headers here. + * The Prism header is in theory variable-length, but in + * practice it's always 144 bytes long. However, some + * drivers on Linux use ARPHRD_IEEE80211_PRISM, but + * sometimes or always supply an AVS header, so we + * have to check whether the radio header is a Prism + * header or an AVS header, so, in practice, it's + * variable-length. + */ + off_linktype.constant_part = 24; + off_linkpl.constant_part = 0; /* link-layer header is variable-length */ + off_linkpl.is_variable = 1; + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_PPI: + /* + * At the moment we treat PPI the same way that we treat + * normal Radiotap encoded packets. The difference is in + * the function that generates the code at the beginning + * to compute the header length. Since this code generator + * of PPI supports bare 802.11 encapsulation only (i.e. + * the encapsulated DLT should be DLT_IEEE802_11) we + * generate code to check for this too. + */ + off_linktype.constant_part = 24; + off_linkpl.constant_part = 0; /* link-layer header is variable-length */ + off_linkpl.is_variable = 1; + off_linkhdr.is_variable = 1; + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_ATM_RFC1483: + case DLT_ATM_CLIP: /* Linux ATM defines this */ + /* + * assume routed, non-ISO PDUs + * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00) + * + * XXX - what about ISO PDUs, e.g. CLNP, ISIS, ESIS, + * or PPP with the PPP NLPID (e.g., PPPoA)? The + * latter would presumably be treated the way PPPoE + * should be, so you can do "pppoe and udp port 2049" + * or "pppoa and tcp port 80" and have it check for + * PPPo{A,E} and a PPP protocol of IP and.... + */ + off_linktype.constant_part = 0; + off_linkpl.constant_part = 0; /* packet begins with LLC header */ + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_SUNATM: + /* + * Full Frontal ATM; you get AALn PDUs with an ATM + * pseudo-header. + */ + is_atm = 1; + off_vpi = SUNATM_VPI_POS; + off_vci = SUNATM_VCI_POS; + off_proto = PROTO_POS; + off_payload = SUNATM_PKT_BEGIN_POS; + off_linktype.constant_part = off_payload; + off_linkpl.constant_part = off_payload; /* if LLC-encapsulated */ + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_RAW: + case DLT_IPV4: + case DLT_IPV6: + off_linktype.constant_part = -1; + off_linkpl.constant_part = 0; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_LINUX_SLL: /* fake header for Linux cooked socket */ + off_linktype.constant_part = 14; + off_linkpl.constant_part = 16; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_LTALK: + /* + * LocalTalk does have a 1-byte type field in the LLAP header, + * but really it just indicates whether there is a "short" or + * "long" DDP packet following. + */ + off_linktype.constant_part = -1; + off_linkpl.constant_part = 0; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_IP_OVER_FC: + /* + * RFC 2625 IP-over-Fibre-Channel doesn't really have a + * link-level type field. We set "off_linktype" to the + * offset of the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? RFC + * 2625 says SNAP should be used. + */ + off_linktype.constant_part = 16; + off_linkpl.constant_part = 16; + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_FRELAY: + /* + * XXX - we should set this to handle SNAP-encapsulated + * frames (NLPID of 0x80). + */ + off_linktype.constant_part = -1; + off_linkpl.constant_part = 0; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + /* + * the only BPF-interesting FRF.16 frames are non-control frames; + * Frame Relay has a variable length link-layer + * so lets start with offset 4 for now and increments later on (FIXME); + */ + case DLT_MFR: + off_linktype.constant_part = -1; + off_linkpl.constant_part = 0; + off_nl = 4; + off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */ + break; + + case DLT_APPLE_IP_OVER_IEEE1394: + off_linktype.constant_part = 16; + off_linkpl.constant_part = 18; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_SYMANTEC_FIREWALL: + off_linktype.constant_part = 6; + off_linkpl.constant_part = 44; + off_nl = 0; /* Ethernet II */ + off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */ + break; + +#ifdef HAVE_NET_PFVAR_H + case DLT_PFLOG: + off_linktype.constant_part = 0; + off_linkpl.constant_part = PFLOG_HDRLEN; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + break; +#endif + + case DLT_JUNIPER_MFR: + case DLT_JUNIPER_MLFR: + case DLT_JUNIPER_MLPPP: + case DLT_JUNIPER_PPP: + case DLT_JUNIPER_CHDLC: + case DLT_JUNIPER_FRELAY: + off_linktype.constant_part = 4; + off_linkpl.constant_part = 4; + off_nl = 0; + off_nl_nosnap = -1; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_ATM1: + off_linktype.constant_part = 4; /* in reality variable between 4-8 */ + off_linkpl.constant_part = 4; /* in reality variable between 4-8 */ + off_nl = 0; + off_nl_nosnap = 10; + break; + + case DLT_JUNIPER_ATM2: + off_linktype.constant_part = 8; /* in reality variable between 8-12 */ + off_linkpl.constant_part = 8; /* in reality variable between 8-12 */ + off_nl = 0; + off_nl_nosnap = 10; + break; + + /* frames captured on a Juniper PPPoE service PIC + * contain raw ethernet frames */ + case DLT_JUNIPER_PPPOE: + case DLT_JUNIPER_ETHER: + off_linkpl.constant_part = 14; + off_linktype.constant_part = 16; + off_nl = 18; /* Ethernet II */ + off_nl_nosnap = 21; /* 802.3+802.2 */ + break; + + case DLT_JUNIPER_PPPOE_ATM: + off_linktype.constant_part = 4; + off_linkpl.constant_part = 6; + off_nl = 0; + off_nl_nosnap = -1; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_GGSN: + off_linktype.constant_part = 6; + off_linkpl.constant_part = 12; + off_nl = 0; + off_nl_nosnap = -1; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_ES: + off_linktype.constant_part = 6; + off_linkpl.constant_part = -1; /* not really a network layer but raw IP addresses */ + off_nl = -1; /* not really a network layer but raw IP addresses */ + off_nl_nosnap = -1; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_MONITOR: + off_linktype.constant_part = 12; + off_linkpl.constant_part = 12; + off_nl = 0; /* raw IP/IP6 header */ + off_nl_nosnap = -1; /* no 802.2 LLC */ + break; + + case DLT_BACNET_MS_TP: + off_linktype.constant_part = -1; + off_linkpl.constant_part = -1; + off_nl = -1; + off_nl_nosnap = -1; + break; + + case DLT_JUNIPER_SERVICES: + off_linktype.constant_part = 12; + off_linkpl.constant_part = -1; /* L3 proto location dep. on cookie type */ + off_nl = -1; /* L3 proto location dep. on cookie type */ + off_nl_nosnap = -1; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_VP: + off_linktype.constant_part = 18; + off_linkpl.constant_part = -1; + off_nl = -1; + off_nl_nosnap = -1; + break; + + case DLT_JUNIPER_ST: + off_linktype.constant_part = 18; + off_linkpl.constant_part = -1; + off_nl = -1; + off_nl_nosnap = -1; + break; + + case DLT_JUNIPER_ISM: + off_linktype.constant_part = 8; + off_linkpl.constant_part = -1; + off_nl = -1; + off_nl_nosnap = -1; + break; + + case DLT_JUNIPER_VS: + case DLT_JUNIPER_SRX_E2E: + case DLT_JUNIPER_FIBRECHANNEL: + case DLT_JUNIPER_ATM_CEMIC: + off_linktype.constant_part = 8; + off_linkpl.constant_part = -1; + off_nl = -1; + off_nl_nosnap = -1; + break; + + case DLT_MTP2: + off_li = 2; + off_li_hsl = 4; + off_sio = 3; + off_opc = 4; + off_dpc = 4; + off_sls = 7; + off_linktype.constant_part = -1; + off_linkpl.constant_part = -1; + off_nl = -1; + off_nl_nosnap = -1; + break; + + case DLT_MTP2_WITH_PHDR: + off_li = 6; + off_li_hsl = 8; + off_sio = 7; + off_opc = 8; + off_dpc = 8; + off_sls = 11; + off_linktype.constant_part = -1; + off_linkpl.constant_part = -1; + off_nl = -1; + off_nl_nosnap = -1; + break; + + case DLT_ERF: + off_li = 22; + off_li_hsl = 24; + off_sio = 23; + off_opc = 24; + off_dpc = 24; + off_sls = 27; + off_linktype.constant_part = -1; + off_linkpl.constant_part = -1; + off_nl = -1; + off_nl_nosnap = -1; + break; + + case DLT_PFSYNC: + off_linktype.constant_part = -1; + off_linkpl.constant_part = 4; + off_nl = 0; + off_nl_nosnap = 0; + break; + + case DLT_AX25_KISS: + /* + * Currently, only raw "link[N:M]" filtering is supported. + */ + off_linktype.constant_part = -1; /* variable, min 15, max 71 steps of 7 */ + off_linkpl.constant_part = -1; + off_nl = -1; /* variable, min 16, max 71 steps of 7 */ + off_nl_nosnap = -1; /* no 802.2 LLC */ + break; + + case DLT_IPNET: + off_linktype.constant_part = 1; + off_linkpl.constant_part = 24; /* ipnet header length */ + off_nl = 0; + off_nl_nosnap = -1; + break; + + case DLT_NETANALYZER: + off_linkhdr.constant_part = 4; /* Ethernet header is past 4-byte pseudo-header */ + off_linktype.constant_part = off_linkhdr.constant_part + 12; + off_linkpl.constant_part = off_linkhdr.constant_part + 14; /* pseudo-header+Ethernet header length */ + off_nl = 0; /* Ethernet II */ + off_nl_nosnap = 3; /* 802.3+802.2 */ + break; + + case DLT_NETANALYZER_TRANSPARENT: + off_linkhdr.constant_part = 12; /* MAC header is past 4-byte pseudo-header, preamble, and SFD */ + off_linktype.constant_part = off_linkhdr.constant_part + 12; + off_linkpl.constant_part = off_linkhdr.constant_part + 14; /* pseudo-header+preamble+SFD+Ethernet header length */ + off_nl = 0; /* Ethernet II */ + off_nl_nosnap = 3; /* 802.3+802.2 */ + break; + + default: + /* + * For values in the range in which we've assigned new + * DLT_ values, only raw "link[N:M]" filtering is supported. + */ + if (linktype >= DLT_MATCHING_MIN && + linktype <= DLT_MATCHING_MAX) { + off_linktype.constant_part = -1; + off_linkpl.constant_part = -1; + off_nl = -1; + off_nl_nosnap = -1; + } else { + bpf_error("unknown data link type %d", linktype); + } + break; + } + + off_outermostlinkhdr = off_prevlinkhdr = off_linkhdr; +} + +/* + * Load a value relative to the specified absolute offset. + */ +static struct slist * +gen_load_absoffsetrel(bpf_abs_offset *abs_offset, u_int offset, u_int size) +{ + struct slist *s, *s2; + + s = gen_abs_offset_varpart(abs_offset); + + /* + * If "s" is non-null, it has code to arrange that the X register + * contains the variable part of the absolute offset, so we + * generate a load relative to that, with an offset of + * abs_offset->constant_part + offset. + * + * Otherwise, we can do an absolute load with an offset of + * abs_offset->constant_part + offset. + */ + if (s != NULL) { + /* + * "s" points to a list of statements that puts the + * variable part of the absolute offset into the X register. + * Do an indirect load, to use the X register as an offset. + */ + s2 = new_stmt(BPF_LD|BPF_IND|size); + s2->s.k = abs_offset->constant_part + offset; + sappend(s, s2); + } else { + /* + * There is no variable part of the absolute offset, so + * just do an absolute load. + */ + s = new_stmt(BPF_LD|BPF_ABS|size); + s->s.k = abs_offset->constant_part + offset; + } + return s; +} + +/* + * Load a value relative to the beginning of the specified header. + */ +static struct slist * +gen_load_a(offrel, offset, size) + enum e_offrel offrel; + u_int offset, size; +{ + struct slist *s, *s2; + + switch (offrel) { + + case OR_PACKET: + s = new_stmt(BPF_LD|BPF_ABS|size); + s->s.k = offset; + break; + + case OR_LINKHDR: + s = gen_load_absoffsetrel(&off_linkhdr, offset, size); + break; + + case OR_PREVLINKHDR: + s = gen_load_absoffsetrel(&off_prevlinkhdr, offset, size); + break; + + case OR_LLC: + s = gen_load_absoffsetrel(&off_linkpl, offset, size); + break; + + case OR_PREVMPLSHDR: + s = gen_load_absoffsetrel(&off_linkpl, off_nl - 4 + offset, size); + break; + + case OR_LINKPL: + s = gen_load_absoffsetrel(&off_linkpl, off_nl + offset, size); + break; + + case OR_LINKPL_NOSNAP: + s = gen_load_absoffsetrel(&off_linkpl, off_nl_nosnap + offset, size); + break; + + case OR_LINKTYPE: + s = gen_load_absoffsetrel(&off_linktype, offset, size); + break; + + case OR_TRAN_IPV4: + /* + * Load the X register with the length of the IPv4 header + * (plus the offset of the link-layer header, if it's + * preceded by a variable-length header such as a radio + * header), in bytes. + */ + s = gen_loadx_iphdrlen(); + + /* + * Load the item at {offset of the link-layer payload} + + * {offset, relative to the start of the link-layer + * paylod, of the IPv4 header} + {length of the IPv4 header} + + * {specified offset}. + * + * If the offset of the link-layer payload is variable, + * the variable part of that offset is included in the + * value in the X register, and we include the constant + * part in the offset of the load. + */ + s2 = new_stmt(BPF_LD|BPF_IND|size); + s2->s.k = off_linkpl.constant_part + off_nl + offset; + sappend(s, s2); + break; + + case OR_TRAN_IPV6: + s = gen_load_absoffsetrel(&off_linkpl, off_nl + 40 + offset, size); + break; + + default: + abort(); + return NULL; + } + return s; +} + +/* + * Generate code to load into the X register the sum of the length of + * the IPv4 header and the variable part of the offset of the link-layer + * payload. + */ +static struct slist * +gen_loadx_iphdrlen() +{ + struct slist *s, *s2; + + s = gen_abs_offset_varpart(&off_linkpl); + if (s != NULL) { + /* + * The offset of the link-layer payload has a variable + * part. "s" points to a list of statements that put + * the variable part of that offset into the X register. + * + * The 4*([k]&0xf) addressing mode can't be used, as we + * don't have a constant offset, so we have to load the + * value in question into the A register and add to it + * the value from the X register. + */ + s2 = new_stmt(BPF_LD|BPF_IND|BPF_B); + s2->s.k = off_linkpl.constant_part + off_nl; + sappend(s, s2); + s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K); + s2->s.k = 0xf; + sappend(s, s2); + s2 = new_stmt(BPF_ALU|BPF_LSH|BPF_K); + s2->s.k = 2; + sappend(s, s2); + + /* + * The A register now contains the length of the IP header. + * We need to add to it the variable part of the offset of + * the link-layer payload, which is still in the X + * register, and move the result into the X register. + */ + sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(BPF_MISC|BPF_TAX)); + } else { + /* + * The offset of the link-layer payload is a constant, + * so no code was generated to load the (non-existent) + * variable part of that offset. + * + * This means we can use the 4*([k]&0xf) addressing + * mode. Load the length of the IPv4 header, which + * is at an offset of off_nl from the beginning of + * the link-layer payload, and thus at an offset of + * off_linkpl.constant_part + off_nl from the beginning + * of the raw packet data, using that addressing mode. + */ + s = new_stmt(BPF_LDX|BPF_MSH|BPF_B); + s->s.k = off_linkpl.constant_part + off_nl; + } + return s; +} + +static struct block * +gen_uncond(rsense) + int rsense; +{ + struct block *b; + struct slist *s; + + s = new_stmt(BPF_LD|BPF_IMM); + s->s.k = !rsense; + b = new_block(JMP(BPF_JEQ)); + b->stmts = s; + + return b; +} + +static inline struct block * +gen_true() +{ + return gen_uncond(1); +} + +static inline struct block * +gen_false() +{ + return gen_uncond(0); +} + +/* + * Byte-swap a 32-bit number. + * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on + * big-endian platforms.) + */ +#define SWAPLONG(y) \ +((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) + +/* + * Generate code to match a particular packet type. + * + * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP + * value, if <= ETHERMTU. We use that to determine whether to + * match the type/length field or to check the type/length field for + * a value <= ETHERMTU to see whether it's a type field and then do + * the appropriate test. + */ +static struct block * +gen_ether_linktype(proto) + register int proto; +{ + struct block *b0, *b1; + + switch (proto) { + + case LLCSAP_ISONS: + case LLCSAP_IP: + case LLCSAP_NETBEUI: + /* + * OSI protocols and NetBEUI always use 802.2 encapsulation, + * so we check the DSAP and SSAP. + * + * LLCSAP_IP checks for IP-over-802.2, rather + * than IP-over-Ethernet or IP-over-SNAP. + * + * XXX - should we check both the DSAP and the + * SSAP, like this, or should we check just the + * DSAP, as we do for other types <= ETHERMTU + * (i.e., other SAP values)? + */ + b0 = gen_cmp_gt(OR_LINKTYPE, 0, BPF_H, ETHERMTU); + gen_not(b0); + b1 = gen_cmp(OR_LLC, 0, BPF_H, (bpf_int32) + ((proto << 8) | proto)); + gen_and(b0, b1); + return b1; + + case LLCSAP_IPX: + /* + * Check for; + * + * Ethernet_II frames, which are Ethernet + * frames with a frame type of ETHERTYPE_IPX; + * + * Ethernet_802.3 frames, which are 802.3 + * frames (i.e., the type/length field is + * a length field, <= ETHERMTU, rather than + * a type field) with the first two bytes + * after the Ethernet/802.3 header being + * 0xFFFF; + * + * Ethernet_802.2 frames, which are 802.3 + * frames with an 802.2 LLC header and + * with the IPX LSAP as the DSAP in the LLC + * header; + * + * Ethernet_SNAP frames, which are 802.3 + * frames with an LLC header and a SNAP + * header and with an OUI of 0x000000 + * (encapsulated Ethernet) and a protocol + * ID of ETHERTYPE_IPX in the SNAP header. + * + * XXX - should we generate the same code both + * for tests for LLCSAP_IPX and for ETHERTYPE_IPX? + */ + + /* + * This generates code to check both for the + * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3. + */ + b0 = gen_cmp(OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX); + b1 = gen_cmp(OR_LLC, 0, BPF_H, (bpf_int32)0xFFFF); + gen_or(b0, b1); + + /* + * Now we add code to check for SNAP frames with + * ETHERTYPE_IPX, i.e. Ethernet_SNAP. + */ + b0 = gen_snap(0x000000, ETHERTYPE_IPX); + gen_or(b0, b1); + + /* + * Now we generate code to check for 802.3 + * frames in general. + */ + b0 = gen_cmp_gt(OR_LINKTYPE, 0, BPF_H, ETHERMTU); + gen_not(b0); + + /* + * Now add the check for 802.3 frames before the + * check for Ethernet_802.2 and Ethernet_802.3, + * as those checks should only be done on 802.3 + * frames, not on Ethernet frames. + */ + gen_and(b0, b1); + + /* + * Now add the check for Ethernet_II frames, and + * do that before checking for the other frame + * types. + */ + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX); + gen_or(b0, b1); + return b1; + + case ETHERTYPE_ATALK: + case ETHERTYPE_AARP: + /* + * EtherTalk (AppleTalk protocols on Ethernet link + * layer) may use 802.2 encapsulation. + */ + + /* + * Check for 802.2 encapsulation (EtherTalk phase 2?); + * we check for an Ethernet type field less than + * 1500, which means it's an 802.3 length field. + */ + b0 = gen_cmp_gt(OR_LINKTYPE, 0, BPF_H, ETHERMTU); + gen_not(b0); + + /* + * 802.2-encapsulated ETHERTYPE_ATALK packets are + * SNAP packets with an organization code of + * 0x080007 (Apple, for Appletalk) and a protocol + * type of ETHERTYPE_ATALK (Appletalk). + * + * 802.2-encapsulated ETHERTYPE_AARP packets are + * SNAP packets with an organization code of + * 0x000000 (encapsulated Ethernet) and a protocol + * type of ETHERTYPE_AARP (Appletalk ARP). + */ + if (proto == ETHERTYPE_ATALK) + b1 = gen_snap(0x080007, ETHERTYPE_ATALK); + else /* proto == ETHERTYPE_AARP */ + b1 = gen_snap(0x000000, ETHERTYPE_AARP); + gen_and(b0, b1); + + /* + * Check for Ethernet encapsulation (Ethertalk + * phase 1?); we just check for the Ethernet + * protocol type. + */ + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); + + gen_or(b0, b1); + return b1; + + default: + if (proto <= ETHERMTU) { + /* + * This is an LLC SAP value, so the frames + * that match would be 802.2 frames. + * Check that the frame is an 802.2 frame + * (i.e., that the length/type field is + * a length field, <= ETHERMTU) and + * then check the DSAP. + */ + b0 = gen_cmp_gt(OR_LINKTYPE, 0, BPF_H, ETHERMTU); + gen_not(b0); + b1 = gen_cmp(OR_LINKTYPE, 2, BPF_B, (bpf_int32)proto); + gen_and(b0, b1); + return b1; + } else { + /* + * This is an Ethernet type, so compare + * the length/type field with it (if + * the frame is an 802.2 frame, the length + * field will be <= ETHERMTU, and, as + * "proto" is > ETHERMTU, this test + * will fail and the frame won't match, + * which is what we want). + */ + return gen_cmp(OR_LINKTYPE, 0, BPF_H, + (bpf_int32)proto); + } + } +} + +/* + * "proto" is an Ethernet type value and for IPNET, if it is not IPv4 + * or IPv6 then we have an error. + */ +static struct block * +gen_ipnet_linktype(proto) + register int proto; +{ + switch (proto) { + + case ETHERTYPE_IP: + return gen_cmp(OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET); + /* NOTREACHED */ + + case ETHERTYPE_IPV6: + return gen_cmp(OR_LINKTYPE, 0, BPF_B, + (bpf_int32)IPH_AF_INET6); + /* NOTREACHED */ + + default: + break; + } + + return gen_false(); +} + +/* + * Generate code to match a particular packet type. + * + * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP + * value, if <= ETHERMTU. We use that to determine whether to + * match the type field or to check the type field for the special + * LINUX_SLL_P_802_2 value and then do the appropriate test. + */ +static struct block * +gen_linux_sll_linktype(proto) + register int proto; +{ + struct block *b0, *b1; + + switch (proto) { + + case LLCSAP_ISONS: + case LLCSAP_IP: + case LLCSAP_NETBEUI: + /* + * OSI protocols and NetBEUI always use 802.2 encapsulation, + * so we check the DSAP and SSAP. + * + * LLCSAP_IP checks for IP-over-802.2, rather + * than IP-over-Ethernet or IP-over-SNAP. + * + * XXX - should we check both the DSAP and the + * SSAP, like this, or should we check just the + * DSAP, as we do for other types <= ETHERMTU + * (i.e., other SAP values)? + */ + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); + b1 = gen_cmp(OR_LLC, 0, BPF_H, (bpf_int32) + ((proto << 8) | proto)); + gen_and(b0, b1); + return b1; + + case LLCSAP_IPX: + /* + * Ethernet_II frames, which are Ethernet + * frames with a frame type of ETHERTYPE_IPX; + * + * Ethernet_802.3 frames, which have a frame + * type of LINUX_SLL_P_802_3; + * + * Ethernet_802.2 frames, which are 802.3 + * frames with an 802.2 LLC header (i.e, have + * a frame type of LINUX_SLL_P_802_2) and + * with the IPX LSAP as the DSAP in the LLC + * header; + * + * Ethernet_SNAP frames, which are 802.3 + * frames with an LLC header and a SNAP + * header and with an OUI of 0x000000 + * (encapsulated Ethernet) and a protocol + * ID of ETHERTYPE_IPX in the SNAP header. + * + * First, do the checks on LINUX_SLL_P_802_2 + * frames; generate the check for either + * Ethernet_802.2 or Ethernet_SNAP frames, and + * then put a check for LINUX_SLL_P_802_2 frames + * before it. + */ + b0 = gen_cmp(OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX); + b1 = gen_snap(0x000000, ETHERTYPE_IPX); + gen_or(b0, b1); + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); + gen_and(b0, b1); + + /* + * Now check for 802.3 frames and OR that with + * the previous test. + */ + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_3); + gen_or(b0, b1); + + /* + * Now add the check for Ethernet_II frames, and + * do that before checking for the other frame + * types. + */ + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX); + gen_or(b0, b1); + return b1; + + case ETHERTYPE_ATALK: + case ETHERTYPE_AARP: + /* + * EtherTalk (AppleTalk protocols on Ethernet link + * layer) may use 802.2 encapsulation. + */ + + /* + * Check for 802.2 encapsulation (EtherTalk phase 2?); + * we check for the 802.2 protocol type in the + * "Ethernet type" field. + */ + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); + + /* + * 802.2-encapsulated ETHERTYPE_ATALK packets are + * SNAP packets with an organization code of + * 0x080007 (Apple, for Appletalk) and a protocol + * type of ETHERTYPE_ATALK (Appletalk). + * + * 802.2-encapsulated ETHERTYPE_AARP packets are + * SNAP packets with an organization code of + * 0x000000 (encapsulated Ethernet) and a protocol + * type of ETHERTYPE_AARP (Appletalk ARP). + */ + if (proto == ETHERTYPE_ATALK) + b1 = gen_snap(0x080007, ETHERTYPE_ATALK); + else /* proto == ETHERTYPE_AARP */ + b1 = gen_snap(0x000000, ETHERTYPE_AARP); + gen_and(b0, b1); + + /* + * Check for Ethernet encapsulation (Ethertalk + * phase 1?); we just check for the Ethernet + * protocol type. + */ + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); + + gen_or(b0, b1); + return b1; + + default: + if (proto <= ETHERMTU) { + /* + * This is an LLC SAP value, so the frames + * that match would be 802.2 frames. + * Check for the 802.2 protocol type + * in the "Ethernet type" field, and + * then check the DSAP. + */ + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); + b1 = gen_cmp(OR_LINKHDR, off_linkpl.constant_part, BPF_B, + (bpf_int32)proto); + gen_and(b0, b1); + return b1; + } else { + /* + * This is an Ethernet type, so compare + * the length/type field with it (if + * the frame is an 802.2 frame, the length + * field will be <= ETHERMTU, and, as + * "proto" is > ETHERMTU, this test + * will fail and the frame won't match, + * which is what we want). + */ + return gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); + } + } +} + +static struct slist * +gen_load_prism_llprefixlen() +{ + struct slist *s1, *s2; + struct slist *sjeq_avs_cookie; + struct slist *sjcommon; + + /* + * This code is not compatible with the optimizer, as + * we are generating jmp instructions within a normal + * slist of instructions + */ + no_optimize = 1; + + /* + * Generate code to load the length of the radio header into + * the register assigned to hold that length, if one has been + * assigned. (If one hasn't been assigned, no code we've + * generated uses that prefix, so we don't need to generate any + * code to load it.) + * + * Some Linux drivers use ARPHRD_IEEE80211_PRISM but sometimes + * or always use the AVS header rather than the Prism header. + * We load a 4-byte big-endian value at the beginning of the + * raw packet data, and see whether, when masked with 0xFFFFF000, + * it's equal to 0x80211000. If so, that indicates that it's + * an AVS header (the masked-out bits are the version number). + * Otherwise, it's a Prism header. + * + * XXX - the Prism header is also, in theory, variable-length, + * but no known software generates headers that aren't 144 + * bytes long. + */ + if (off_linkhdr.reg != -1) { + /* + * Load the cookie. + */ + s1 = new_stmt(BPF_LD|BPF_W|BPF_ABS); + s1->s.k = 0; + + /* + * AND it with 0xFFFFF000. + */ + s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K); + s2->s.k = 0xFFFFF000; + sappend(s1, s2); + + /* + * Compare with 0x80211000. + */ + sjeq_avs_cookie = new_stmt(JMP(BPF_JEQ)); + sjeq_avs_cookie->s.k = 0x80211000; + sappend(s1, sjeq_avs_cookie); + + /* + * If it's AVS: + * + * The 4 bytes at an offset of 4 from the beginning of + * the AVS header are the length of the AVS header. + * That field is big-endian. + */ + s2 = new_stmt(BPF_LD|BPF_W|BPF_ABS); + s2->s.k = 4; + sappend(s1, s2); + sjeq_avs_cookie->s.jt = s2; + + /* + * Now jump to the code to allocate a register + * into which to save the header length and + * store the length there. (The "jump always" + * instruction needs to have the k field set; + * it's added to the PC, so, as we're jumping + * over a single instruction, it should be 1.) + */ + sjcommon = new_stmt(JMP(BPF_JA)); + sjcommon->s.k = 1; + sappend(s1, sjcommon); + + /* + * Now for the code that handles the Prism header. + * Just load the length of the Prism header (144) + * into the A register. Have the test for an AVS + * header branch here if we don't have an AVS header. + */ + s2 = new_stmt(BPF_LD|BPF_W|BPF_IMM); + s2->s.k = 144; + sappend(s1, s2); + sjeq_avs_cookie->s.jf = s2; + + /* + * Now allocate a register to hold that value and store + * it. The code for the AVS header will jump here after + * loading the length of the AVS header. + */ + s2 = new_stmt(BPF_ST); + s2->s.k = off_linkhdr.reg; + sappend(s1, s2); + sjcommon->s.jf = s2; + + /* + * Now move it into the X register. + */ + s2 = new_stmt(BPF_MISC|BPF_TAX); + sappend(s1, s2); + + return (s1); + } else + return (NULL); +} + +static struct slist * +gen_load_avs_llprefixlen() +{ + struct slist *s1, *s2; + + /* + * Generate code to load the length of the AVS header into + * the register assigned to hold that length, if one has been + * assigned. (If one hasn't been assigned, no code we've + * generated uses that prefix, so we don't need to generate any + * code to load it.) + */ + if (off_linkhdr.reg != -1) { + /* + * The 4 bytes at an offset of 4 from the beginning of + * the AVS header are the length of the AVS header. + * That field is big-endian. + */ + s1 = new_stmt(BPF_LD|BPF_W|BPF_ABS); + s1->s.k = 4; + + /* + * Now allocate a register to hold that value and store + * it. + */ + s2 = new_stmt(BPF_ST); + s2->s.k = off_linkhdr.reg; + sappend(s1, s2); + + /* + * Now move it into the X register. + */ + s2 = new_stmt(BPF_MISC|BPF_TAX); + sappend(s1, s2); + + return (s1); + } else + return (NULL); +} + +static struct slist * +gen_load_radiotap_llprefixlen() +{ + struct slist *s1, *s2; + + /* + * Generate code to load the length of the radiotap header into + * the register assigned to hold that length, if one has been + * assigned. (If one hasn't been assigned, no code we've + * generated uses that prefix, so we don't need to generate any + * code to load it.) + */ + if (off_linkhdr.reg != -1) { + /* + * The 2 bytes at offsets of 2 and 3 from the beginning + * of the radiotap header are the length of the radiotap + * header; unfortunately, it's little-endian, so we have + * to load it a byte at a time and construct the value. + */ + + /* + * Load the high-order byte, at an offset of 3, shift it + * left a byte, and put the result in the X register. + */ + s1 = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s1->s.k = 3; + s2 = new_stmt(BPF_ALU|BPF_LSH|BPF_K); + sappend(s1, s2); + s2->s.k = 8; + s2 = new_stmt(BPF_MISC|BPF_TAX); + sappend(s1, s2); + + /* + * Load the next byte, at an offset of 2, and OR the + * value from the X register into it. + */ + s2 = new_stmt(BPF_LD|BPF_B|BPF_ABS); + sappend(s1, s2); + s2->s.k = 2; + s2 = new_stmt(BPF_ALU|BPF_OR|BPF_X); + sappend(s1, s2); + + /* + * Now allocate a register to hold that value and store + * it. + */ + s2 = new_stmt(BPF_ST); + s2->s.k = off_linkhdr.reg; + sappend(s1, s2); + + /* + * Now move it into the X register. + */ + s2 = new_stmt(BPF_MISC|BPF_TAX); + sappend(s1, s2); + + return (s1); + } else + return (NULL); +} + +/* + * At the moment we treat PPI as normal Radiotap encoded + * packets. The difference is in the function that generates + * the code at the beginning to compute the header length. + * Since this code generator of PPI supports bare 802.11 + * encapsulation only (i.e. the encapsulated DLT should be + * DLT_IEEE802_11) we generate code to check for this too; + * that's done in finish_parse(). + */ +static struct slist * +gen_load_ppi_llprefixlen() +{ + struct slist *s1, *s2; + + /* + * Generate code to load the length of the radiotap header + * into the register assigned to hold that length, if one has + * been assigned. + */ + if (off_linkhdr.reg != -1) { + /* + * The 2 bytes at offsets of 2 and 3 from the beginning + * of the radiotap header are the length of the radiotap + * header; unfortunately, it's little-endian, so we have + * to load it a byte at a time and construct the value. + */ + + /* + * Load the high-order byte, at an offset of 3, shift it + * left a byte, and put the result in the X register. + */ + s1 = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s1->s.k = 3; + s2 = new_stmt(BPF_ALU|BPF_LSH|BPF_K); + sappend(s1, s2); + s2->s.k = 8; + s2 = new_stmt(BPF_MISC|BPF_TAX); + sappend(s1, s2); + + /* + * Load the next byte, at an offset of 2, and OR the + * value from the X register into it. + */ + s2 = new_stmt(BPF_LD|BPF_B|BPF_ABS); + sappend(s1, s2); + s2->s.k = 2; + s2 = new_stmt(BPF_ALU|BPF_OR|BPF_X); + sappend(s1, s2); + + /* + * Now allocate a register to hold that value and store + * it. + */ + s2 = new_stmt(BPF_ST); + s2->s.k = off_linkhdr.reg; + sappend(s1, s2); + + /* + * Now move it into the X register. + */ + s2 = new_stmt(BPF_MISC|BPF_TAX); + sappend(s1, s2); + + return (s1); + } else + return (NULL); +} + +/* + * Load a value relative to the beginning of the link-layer header after the 802.11 + * header, i.e. LLC_SNAP. + * The link-layer header doesn't necessarily begin at the beginning + * of the packet data; there might be a variable-length prefix containing + * radio information. + */ +static struct slist * +gen_load_802_11_header_len(struct slist *s, struct slist *snext) +{ + struct slist *s2; + struct slist *sjset_data_frame_1; + struct slist *sjset_data_frame_2; + struct slist *sjset_qos; + struct slist *sjset_radiotap_flags; + struct slist *sjset_radiotap_tsft; + struct slist *sjset_tsft_datapad, *sjset_notsft_datapad; + struct slist *s_roundup; + + if (off_linkpl.reg == -1) { + /* + * No register has been assigned to the offset of + * the link-layer payload, which means nobody needs + * it; don't bother computing it - just return + * what we already have. + */ + return (s); + } + + /* + * This code is not compatible with the optimizer, as + * we are generating jmp instructions within a normal + * slist of instructions + */ + no_optimize = 1; + + /* + * If "s" is non-null, it has code to arrange that the X register + * contains the length of the prefix preceding the link-layer + * header. + * + * Otherwise, the length of the prefix preceding the link-layer + * header is "off_outermostlinkhdr.constant_part". + */ + if (s == NULL) { + /* + * There is no variable-length header preceding the + * link-layer header. + * + * Load the length of the fixed-length prefix preceding + * the link-layer header (if any) into the X register, + * and store it in the off_linkpl.reg register. + * That length is off_outermostlinkhdr.constant_part. + */ + s = new_stmt(BPF_LDX|BPF_IMM); + s->s.k = off_outermostlinkhdr.constant_part; + } + + /* + * The X register contains the offset of the beginning of the + * link-layer header; add 24, which is the minimum length + * of the MAC header for a data frame, to that, and store it + * in off_linkpl.reg, and then load the Frame Control field, + * which is at the offset in the X register, with an indexed load. + */ + s2 = new_stmt(BPF_MISC|BPF_TXA); + sappend(s, s2); + s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s2->s.k = 24; + sappend(s, s2); + s2 = new_stmt(BPF_ST); + s2->s.k = off_linkpl.reg; + sappend(s, s2); + + s2 = new_stmt(BPF_LD|BPF_IND|BPF_B); + s2->s.k = 0; + sappend(s, s2); + + /* + * Check the Frame Control field to see if this is a data frame; + * a data frame has the 0x08 bit (b3) in that field set and the + * 0x04 bit (b2) clear. + */ + sjset_data_frame_1 = new_stmt(JMP(BPF_JSET)); + sjset_data_frame_1->s.k = 0x08; + sappend(s, sjset_data_frame_1); + + /* + * If b3 is set, test b2, otherwise go to the first statement of + * the rest of the program. + */ + sjset_data_frame_1->s.jt = sjset_data_frame_2 = new_stmt(JMP(BPF_JSET)); + sjset_data_frame_2->s.k = 0x04; + sappend(s, sjset_data_frame_2); + sjset_data_frame_1->s.jf = snext; + + /* + * If b2 is not set, this is a data frame; test the QoS bit. + * Otherwise, go to the first statement of the rest of the + * program. + */ + sjset_data_frame_2->s.jt = snext; + sjset_data_frame_2->s.jf = sjset_qos = new_stmt(JMP(BPF_JSET)); + sjset_qos->s.k = 0x80; /* QoS bit */ + sappend(s, sjset_qos); + + /* + * If it's set, add 2 to off_linkpl.reg, to skip the QoS + * field. + * Otherwise, go to the first statement of the rest of the + * program. + */ + sjset_qos->s.jt = s2 = new_stmt(BPF_LD|BPF_MEM); + s2->s.k = off_linkpl.reg; + sappend(s, s2); + s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM); + s2->s.k = 2; + sappend(s, s2); + s2 = new_stmt(BPF_ST); + s2->s.k = off_linkpl.reg; + sappend(s, s2); + + /* + * If we have a radiotap header, look at it to see whether + * there's Atheros padding between the MAC-layer header + * and the payload. + * + * Note: all of the fields in the radiotap header are + * little-endian, so we byte-swap all of the values + * we test against, as they will be loaded as big-endian + * values. + */ + if (linktype == DLT_IEEE802_11_RADIO) { + /* + * Is the IEEE80211_RADIOTAP_FLAGS bit (0x0000002) set + * in the presence flag? + */ + sjset_qos->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_W); + s2->s.k = 4; + sappend(s, s2); + + sjset_radiotap_flags = new_stmt(JMP(BPF_JSET)); + sjset_radiotap_flags->s.k = SWAPLONG(0x00000002); + sappend(s, sjset_radiotap_flags); + + /* + * If not, skip all of this. + */ + sjset_radiotap_flags->s.jf = snext; + + /* + * Otherwise, is the IEEE80211_RADIOTAP_TSFT bit set? + */ + sjset_radiotap_tsft = sjset_radiotap_flags->s.jt = + new_stmt(JMP(BPF_JSET)); + sjset_radiotap_tsft->s.k = SWAPLONG(0x00000001); + sappend(s, sjset_radiotap_tsft); + + /* + * If IEEE80211_RADIOTAP_TSFT is set, the flags field is + * at an offset of 16 from the beginning of the raw packet + * data (8 bytes for the radiotap header and 8 bytes for + * the TSFT field). + * + * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) + * is set. + */ + sjset_radiotap_tsft->s.jt = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B); + s2->s.k = 16; + sappend(s, s2); + + sjset_tsft_datapad = new_stmt(JMP(BPF_JSET)); + sjset_tsft_datapad->s.k = 0x20; + sappend(s, sjset_tsft_datapad); + + /* + * If IEEE80211_RADIOTAP_TSFT is not set, the flags field is + * at an offset of 8 from the beginning of the raw packet + * data (8 bytes for the radiotap header). + * + * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) + * is set. + */ + sjset_radiotap_tsft->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B); + s2->s.k = 8; + sappend(s, s2); + + sjset_notsft_datapad = new_stmt(JMP(BPF_JSET)); + sjset_notsft_datapad->s.k = 0x20; + sappend(s, sjset_notsft_datapad); + + /* + * In either case, if IEEE80211_RADIOTAP_F_DATAPAD is + * set, round the length of the 802.11 header to + * a multiple of 4. Do that by adding 3 and then + * dividing by and multiplying by 4, which we do by + * ANDing with ~3. + */ + s_roundup = new_stmt(BPF_LD|BPF_MEM); + s_roundup->s.k = off_linkpl.reg; + sappend(s, s_roundup); + s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM); + s2->s.k = 3; + sappend(s, s2); + s2 = new_stmt(BPF_ALU|BPF_AND|BPF_IMM); + s2->s.k = ~3; + sappend(s, s2); + s2 = new_stmt(BPF_ST); + s2->s.k = off_linkpl.reg; + sappend(s, s2); + + sjset_tsft_datapad->s.jt = s_roundup; + sjset_tsft_datapad->s.jf = snext; + sjset_notsft_datapad->s.jt = s_roundup; + sjset_notsft_datapad->s.jf = snext; + } else + sjset_qos->s.jf = snext; + + return s; +} + +static void +insert_compute_vloffsets(b) + struct block *b; +{ + struct slist *s; + + /* There is an implicit dependency between the link + * payload and link header since the payload computation + * includes the variable part of the header. Therefore, + * if nobody else has allocated a register for the link + * header and we need it, do it now. */ + if (off_linkpl.reg != -1 && off_linkhdr.is_variable && + off_linkhdr.reg == -1) + off_linkhdr.reg = alloc_reg(); + + /* + * For link-layer types that have a variable-length header + * preceding the link-layer header, generate code to load + * the offset of the link-layer header into the register + * assigned to that offset, if any. + * + * XXX - this, and the next switch statement, won't handle + * encapsulation of 802.11 or 802.11+radio information in + * some other protocol stack. That's significantly more + * complicated. + */ + switch (outermostlinktype) { + + case DLT_PRISM_HEADER: + s = gen_load_prism_llprefixlen(); + break; + + case DLT_IEEE802_11_RADIO_AVS: + s = gen_load_avs_llprefixlen(); + break; + + case DLT_IEEE802_11_RADIO: + s = gen_load_radiotap_llprefixlen(); + break; + + case DLT_PPI: + s = gen_load_ppi_llprefixlen(); + break; + + default: + s = NULL; + break; + } + + /* + * For link-layer types that have a variable-length link-layer + * header, generate code to load the offset of the link-layer + * payload into the register assigned to that offset, if any. + */ + switch (outermostlinktype) { + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + s = gen_load_802_11_header_len(s, b->stmts); + break; + } + + /* + * If we have any offset-loading code, append all the + * existing statements in the block to those statements, + * and make the resulting list the list of statements + * for the block. + */ + if (s != NULL) { + sappend(s, b->stmts); + b->stmts = s; + } +} + +static struct block * +gen_ppi_dlt_check(void) +{ + struct slist *s_load_dlt; + struct block *b; + + if (linktype == DLT_PPI) + { + /* Create the statements that check for the DLT + */ + s_load_dlt = new_stmt(BPF_LD|BPF_W|BPF_ABS); + s_load_dlt->s.k = 4; + + b = new_block(JMP(BPF_JEQ)); + + b->stmts = s_load_dlt; + b->s.k = SWAPLONG(DLT_IEEE802_11); + } + else + { + b = NULL; + } + + return b; +} + +/* + * Take an absolute offset, and: + * + * if it has no variable part, return NULL; + * + * if it has a variable part, generate code to load the register + * containing that variable part into the X register, returning + * a pointer to that code - if no register for that offset has + * been allocated, allocate it first. + * + * (The code to set that register will be generated later, but will + * be placed earlier in the code sequence.) + */ +static struct slist * +gen_abs_offset_varpart(bpf_abs_offset *off) +{ + struct slist *s; + + if (off->is_variable) { + if (off->reg == -1) { + /* + * We haven't yet assigned a register for the + * variable part of the offset of the link-layer + * header; allocate one. + */ + off->reg = alloc_reg(); + } + + /* + * Load the register containing the variable part of the + * offset of the link-layer header into the X register. + */ + s = new_stmt(BPF_LDX|BPF_MEM); + s->s.k = off->reg; + return s; + } else { + /* + * That offset isn't variable, there's no variable part, + * so we don't need to generate any code. + */ + return NULL; + } +} + +/* + * Map an Ethernet type to the equivalent PPP type. + */ +static int +ethertype_to_ppptype(proto) + int proto; +{ + switch (proto) { + + case ETHERTYPE_IP: + proto = PPP_IP; + break; + + case ETHERTYPE_IPV6: + proto = PPP_IPV6; + break; + + case ETHERTYPE_DN: + proto = PPP_DECNET; + break; + + case ETHERTYPE_ATALK: + proto = PPP_APPLE; + break; + + case ETHERTYPE_NS: + proto = PPP_NS; + break; + + case LLCSAP_ISONS: + proto = PPP_OSI; + break; + + case LLCSAP_8021D: + /* + * I'm assuming the "Bridging PDU"s that go + * over PPP are Spanning Tree Protocol + * Bridging PDUs. + */ + proto = PPP_BRPDU; + break; + + case LLCSAP_IPX: + proto = PPP_IPX; + break; + } + return (proto); +} + +/* + * Generate any tests that, for encapsulation of a link-layer packet + * inside another protocol stack, need to be done to check for those + * link-layer packets (and that haven't already been done by a check + * for that encapsulation). + */ +static struct block * +gen_prevlinkhdr_check(void) +{ + struct block *b0; + + if (is_geneve) + return gen_geneve_ll_check(); + + switch (prevlinktype) { + + case DLT_SUNATM: + /* + * This is LANE-encapsulated Ethernet; check that the LANE + * packet doesn't begin with an LE Control marker, i.e. + * that it's data, not a control message. + * + * (We've already generated a test for LANE.) + */ + b0 = gen_cmp(OR_PREVLINKHDR, SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00); + gen_not(b0); + return b0; + + default: + /* + * No such tests are necessary. + */ + return NULL; + } + /*NOTREACHED*/ +} + +/* + * Generate code to match a particular packet type by matching the + * link-layer type field or fields in the 802.2 LLC header. + * + * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP + * value, if <= ETHERMTU. + */ +static struct block * +gen_linktype(proto) + register int proto; +{ + struct block *b0, *b1, *b2; + const char *description; + + /* are we checking MPLS-encapsulated packets? */ + if (label_stack_depth > 0) { + switch (proto) { + case ETHERTYPE_IP: + case PPP_IP: + /* FIXME add other L3 proto IDs */ + return gen_mpls_linktype(Q_IP); + + case ETHERTYPE_IPV6: + case PPP_IPV6: + /* FIXME add other L3 proto IDs */ + return gen_mpls_linktype(Q_IPV6); + + default: + bpf_error("unsupported protocol over mpls"); + /* NOTREACHED */ + } + } + + switch (linktype) { + + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + /* Geneve has an EtherType regardless of whether there is an + * L2 header. */ + if (!is_geneve) + b0 = gen_prevlinkhdr_check(); + else + b0 = NULL; + + b1 = gen_ether_linktype(proto); + if (b0 != NULL) + gen_and(b0, b1); + return b1; + /*NOTREACHED*/ + break; + + case DLT_C_HDLC: + switch (proto) { + + case LLCSAP_ISONS: + proto = (proto << 8 | LLCSAP_ISONS); + /* fall through */ + + default: + return gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); + /*NOTREACHED*/ + break; + } + break; + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + /* + * Check that we have a data frame. + */ + b0 = gen_check_802_11_data_frame(); + + /* + * Now check for the specified link-layer type. + */ + b1 = gen_llc_linktype(proto); + gen_and(b0, b1); + return b1; + /*NOTREACHED*/ + break; + + case DLT_FDDI: + /* + * XXX - check for LLC frames. + */ + return gen_llc_linktype(proto); + /*NOTREACHED*/ + break; + + case DLT_IEEE802: + /* + * XXX - check for LLC PDUs, as per IEEE 802.5. + */ + return gen_llc_linktype(proto); + /*NOTREACHED*/ + break; + + case DLT_ATM_RFC1483: + case DLT_ATM_CLIP: + case DLT_IP_OVER_FC: + return gen_llc_linktype(proto); + /*NOTREACHED*/ + break; + + case DLT_SUNATM: + /* + * Check for an LLC-encapsulated version of this protocol; + * if we were checking for LANE, linktype would no longer + * be DLT_SUNATM. + * + * Check for LLC encapsulation and then check the protocol. + */ + b0 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); + b1 = gen_llc_linktype(proto); + gen_and(b0, b1); + return b1; + /*NOTREACHED*/ + break; + + case DLT_LINUX_SLL: + return gen_linux_sll_linktype(proto); + /*NOTREACHED*/ + break; + + case DLT_SLIP: + case DLT_SLIP_BSDOS: + case DLT_RAW: + /* + * These types don't provide any type field; packets + * are always IPv4 or IPv6. + * + * XXX - for IPv4, check for a version number of 4, and, + * for IPv6, check for a version number of 6? + */ + switch (proto) { + + case ETHERTYPE_IP: + /* Check for a version number of 4. */ + return gen_mcmp(OR_LINKHDR, 0, BPF_B, 0x40, 0xF0); + + case ETHERTYPE_IPV6: + /* Check for a version number of 6. */ + return gen_mcmp(OR_LINKHDR, 0, BPF_B, 0x60, 0xF0); + + default: + return gen_false(); /* always false */ + } + /*NOTREACHED*/ + break; + + case DLT_IPV4: + /* + * Raw IPv4, so no type field. + */ + if (proto == ETHERTYPE_IP) + return gen_true(); /* always true */ + + /* Checking for something other than IPv4; always false */ + return gen_false(); + /*NOTREACHED*/ + break; + + case DLT_IPV6: + /* + * Raw IPv6, so no type field. + */ + if (proto == ETHERTYPE_IPV6) + return gen_true(); /* always true */ + + /* Checking for something other than IPv6; always false */ + return gen_false(); + /*NOTREACHED*/ + break; + + case DLT_PPP: + case DLT_PPP_PPPD: + case DLT_PPP_SERIAL: + case DLT_PPP_ETHER: + /* + * We use Ethernet protocol types inside libpcap; + * map them to the corresponding PPP protocol types. + */ + proto = ethertype_to_ppptype(proto); + return gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); + /*NOTREACHED*/ + break; + + case DLT_PPP_BSDOS: + /* + * We use Ethernet protocol types inside libpcap; + * map them to the corresponding PPP protocol types. + */ + switch (proto) { + + case ETHERTYPE_IP: + /* + * Also check for Van Jacobson-compressed IP. + * XXX - do this for other forms of PPP? + */ + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, PPP_IP); + b1 = gen_cmp(OR_LINKTYPE, 0, BPF_H, PPP_VJC); + gen_or(b0, b1); + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, PPP_VJNC); + gen_or(b1, b0); + return b0; + + default: + proto = ethertype_to_ppptype(proto); + return gen_cmp(OR_LINKTYPE, 0, BPF_H, + (bpf_int32)proto); + } + /*NOTREACHED*/ + break; + + case DLT_NULL: + case DLT_LOOP: + case DLT_ENC: + /* + * For DLT_NULL, the link-layer header is a 32-bit + * word containing an AF_ value in *host* byte order, + * and for DLT_ENC, the link-layer header begins + * with a 32-bit work containing an AF_ value in + * host byte order. + * + * In addition, if we're reading a saved capture file, + * the host byte order in the capture may not be the + * same as the host byte order on this machine. + * + * For DLT_LOOP, the link-layer header is a 32-bit + * word containing an AF_ value in *network* byte order. + * + * XXX - AF_ values may, unfortunately, be platform- + * dependent; for example, FreeBSD's AF_INET6 is 24 + * whilst NetBSD's and OpenBSD's is 26. + * + * This means that, when reading a capture file, just + * checking for our AF_INET6 value won't work if the + * capture file came from another OS. + */ + switch (proto) { + + case ETHERTYPE_IP: + proto = AF_INET; + break; + +#ifdef INET6 + case ETHERTYPE_IPV6: + proto = AF_INET6; + break; +#endif + + default: + /* + * Not a type on which we support filtering. + * XXX - support those that have AF_ values + * #defined on this platform, at least? + */ + return gen_false(); + } + + if (linktype == DLT_NULL || linktype == DLT_ENC) { + /* + * The AF_ value is in host byte order, but + * the BPF interpreter will convert it to + * network byte order. + * + * If this is a save file, and it's from a + * machine with the opposite byte order to + * ours, we byte-swap the AF_ value. + * + * Then we run it through "htonl()", and + * generate code to compare against the result. + */ + if (bpf_pcap->rfile != NULL && bpf_pcap->swapped) + proto = SWAPLONG(proto); + proto = htonl(proto); + } + return (gen_cmp(OR_LINKHDR, 0, BPF_W, (bpf_int32)proto)); + +#ifdef HAVE_NET_PFVAR_H + case DLT_PFLOG: + /* + * af field is host byte order in contrast to the rest of + * the packet. + */ + if (proto == ETHERTYPE_IP) + return (gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, af), + BPF_B, (bpf_int32)AF_INET)); + else if (proto == ETHERTYPE_IPV6) + return (gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, af), + BPF_B, (bpf_int32)AF_INET6)); + else + return gen_false(); + /*NOTREACHED*/ + break; +#endif /* HAVE_NET_PFVAR_H */ + + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + /* + * XXX should we check for first fragment if the protocol + * uses PHDS? + */ + switch (proto) { + + default: + return gen_false(); + + case ETHERTYPE_IPV6: + return (gen_cmp(OR_LINKTYPE, 0, BPF_B, + (bpf_int32)ARCTYPE_INET6)); + + case ETHERTYPE_IP: + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_B, + (bpf_int32)ARCTYPE_IP); + b1 = gen_cmp(OR_LINKTYPE, 0, BPF_B, + (bpf_int32)ARCTYPE_IP_OLD); + gen_or(b0, b1); + return (b1); + + case ETHERTYPE_ARP: + b0 = gen_cmp(OR_LINKTYPE, 0, BPF_B, + (bpf_int32)ARCTYPE_ARP); + b1 = gen_cmp(OR_LINKTYPE, 0, BPF_B, + (bpf_int32)ARCTYPE_ARP_OLD); + gen_or(b0, b1); + return (b1); + + case ETHERTYPE_REVARP: + return (gen_cmp(OR_LINKTYPE, 0, BPF_B, + (bpf_int32)ARCTYPE_REVARP)); + + case ETHERTYPE_ATALK: + return (gen_cmp(OR_LINKTYPE, 0, BPF_B, + (bpf_int32)ARCTYPE_ATALK)); + } + /*NOTREACHED*/ + break; + + case DLT_LTALK: + switch (proto) { + case ETHERTYPE_ATALK: + return gen_true(); + default: + return gen_false(); + } + /*NOTREACHED*/ + break; + + case DLT_FRELAY: + /* + * XXX - assumes a 2-byte Frame Relay header with + * DLCI and flags. What if the address is longer? + */ + switch (proto) { + + case ETHERTYPE_IP: + /* + * Check for the special NLPID for IP. + */ + return gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0xcc); + + case ETHERTYPE_IPV6: + /* + * Check for the special NLPID for IPv6. + */ + return gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0x8e); + + case LLCSAP_ISONS: + /* + * Check for several OSI protocols. + * + * Frame Relay packets typically have an OSI + * NLPID at the beginning; we check for each + * of them. + * + * What we check for is the NLPID and a frame + * control field of UI, i.e. 0x03 followed + * by the NLPID. + */ + b0 = gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO8473_CLNP); + b1 = gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO9542_ESIS); + b2 = gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO10589_ISIS); + gen_or(b1, b2); + gen_or(b0, b2); + return b2; + + default: + return gen_false(); + } + /*NOTREACHED*/ + break; + + case DLT_MFR: + bpf_error("Multi-link Frame Relay link-layer type filtering not implemented"); + + case DLT_JUNIPER_MFR: + case DLT_JUNIPER_MLFR: + case DLT_JUNIPER_MLPPP: + case DLT_JUNIPER_ATM1: + case DLT_JUNIPER_ATM2: + case DLT_JUNIPER_PPPOE: + case DLT_JUNIPER_PPPOE_ATM: + case DLT_JUNIPER_GGSN: + case DLT_JUNIPER_ES: + case DLT_JUNIPER_MONITOR: + case DLT_JUNIPER_SERVICES: + case DLT_JUNIPER_ETHER: + case DLT_JUNIPER_PPP: + case DLT_JUNIPER_FRELAY: + case DLT_JUNIPER_CHDLC: + case DLT_JUNIPER_VP: + case DLT_JUNIPER_ST: + case DLT_JUNIPER_ISM: + case DLT_JUNIPER_VS: + case DLT_JUNIPER_SRX_E2E: + case DLT_JUNIPER_FIBRECHANNEL: + case DLT_JUNIPER_ATM_CEMIC: + + /* just lets verify the magic number for now - + * on ATM we may have up to 6 different encapsulations on the wire + * and need a lot of heuristics to figure out that the payload + * might be; + * + * FIXME encapsulation specific BPF_ filters + */ + return gen_mcmp(OR_LINKHDR, 0, BPF_W, 0x4d474300, 0xffffff00); /* compare the magic number */ + + case DLT_BACNET_MS_TP: + return gen_mcmp(OR_LINKHDR, 0, BPF_W, 0x55FF0000, 0xffff0000); + + case DLT_IPNET: + return gen_ipnet_linktype(proto); + + case DLT_LINUX_IRDA: + bpf_error("IrDA link-layer type filtering not implemented"); + + case DLT_DOCSIS: + bpf_error("DOCSIS link-layer type filtering not implemented"); + + case DLT_MTP2: + case DLT_MTP2_WITH_PHDR: + bpf_error("MTP2 link-layer type filtering not implemented"); + + case DLT_ERF: + bpf_error("ERF link-layer type filtering not implemented"); + + case DLT_PFSYNC: + bpf_error("PFSYNC link-layer type filtering not implemented"); + + case DLT_LINUX_LAPD: + bpf_error("LAPD link-layer type filtering not implemented"); + + case DLT_USB: + case DLT_USB_LINUX: + case DLT_USB_LINUX_MMAPPED: + bpf_error("USB link-layer type filtering not implemented"); + + case DLT_BLUETOOTH_HCI_H4: + case DLT_BLUETOOTH_HCI_H4_WITH_PHDR: + bpf_error("Bluetooth link-layer type filtering not implemented"); + + case DLT_CAN20B: + case DLT_CAN_SOCKETCAN: + bpf_error("CAN link-layer type filtering not implemented"); + + case DLT_IEEE802_15_4: + case DLT_IEEE802_15_4_LINUX: + case DLT_IEEE802_15_4_NONASK_PHY: + case DLT_IEEE802_15_4_NOFCS: + bpf_error("IEEE 802.15.4 link-layer type filtering not implemented"); + + case DLT_IEEE802_16_MAC_CPS_RADIO: + bpf_error("IEEE 802.16 link-layer type filtering not implemented"); + + case DLT_SITA: + bpf_error("SITA link-layer type filtering not implemented"); + + case DLT_RAIF1: + bpf_error("RAIF1 link-layer type filtering not implemented"); + + case DLT_IPMB: + bpf_error("IPMB link-layer type filtering not implemented"); + + case DLT_AX25_KISS: + bpf_error("AX.25 link-layer type filtering not implemented"); + + case DLT_NFLOG: + /* Using the fixed-size NFLOG header it is possible to tell only + * the address family of the packet, other meaningful data is + * either missing or behind TLVs. + */ + bpf_error("NFLOG link-layer type filtering not implemented"); + + default: + /* + * Does this link-layer header type have a field + * indicating the type of the next protocol? If + * so, off_linktype.constant_part will be the offset of that + * field in the packet; if not, it will be -1. + */ + if (off_linktype.constant_part != (u_int)-1) { + /* + * Yes; assume it's an Ethernet type. (If + * it's not, it needs to be handled specially + * above.) + */ + return gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); + } else { + /* + * No; report an error. + */ + description = pcap_datalink_val_to_description(linktype); + if (description != NULL) { + bpf_error("%s link-layer type filtering not implemented", + description); + } else { + bpf_error("DLT %u link-layer type filtering not implemented", + linktype); + } + } + break; + } +} + +/* + * Check for an LLC SNAP packet with a given organization code and + * protocol type; we check the entire contents of the 802.2 LLC and + * snap headers, checking for DSAP and SSAP of SNAP and a control + * field of 0x03 in the LLC header, and for the specified organization + * code and protocol type in the SNAP header. + */ +static struct block * +gen_snap(orgcode, ptype) + bpf_u_int32 orgcode; + bpf_u_int32 ptype; +{ + u_char snapblock[8]; + + snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */ + snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */ + snapblock[2] = 0x03; /* control = UI */ + snapblock[3] = (orgcode >> 16); /* upper 8 bits of organization code */ + snapblock[4] = (orgcode >> 8); /* middle 8 bits of organization code */ + snapblock[5] = (orgcode >> 0); /* lower 8 bits of organization code */ + snapblock[6] = (ptype >> 8); /* upper 8 bits of protocol type */ + snapblock[7] = (ptype >> 0); /* lower 8 bits of protocol type */ + return gen_bcmp(OR_LLC, 0, 8, snapblock); +} + +/* + * Generate code to match frames with an LLC header. + */ +struct block * +gen_llc(void) +{ + struct block *b0, *b1; + + switch (linktype) { + + case DLT_EN10MB: + /* + * We check for an Ethernet type field less than + * 1500, which means it's an 802.3 length field. + */ + b0 = gen_cmp_gt(OR_LINKTYPE, 0, BPF_H, ETHERMTU); + gen_not(b0); + + /* + * Now check for the purported DSAP and SSAP not being + * 0xFF, to rule out NetWare-over-802.3. + */ + b1 = gen_cmp(OR_LLC, 0, BPF_H, (bpf_int32)0xFFFF); + gen_not(b1); + gen_and(b0, b1); + return b1; + + case DLT_SUNATM: + /* + * We check for LLC traffic. + */ + b0 = gen_atmtype_abbrev(A_LLC); + return b0; + + case DLT_IEEE802: /* Token Ring */ + /* + * XXX - check for LLC frames. + */ + return gen_true(); + + case DLT_FDDI: + /* + * XXX - check for LLC frames. + */ + return gen_true(); + + case DLT_ATM_RFC1483: + /* + * For LLC encapsulation, these are defined to have an + * 802.2 LLC header. + * + * For VC encapsulation, they don't, but there's no + * way to check for that; the protocol used on the VC + * is negotiated out of band. + */ + return gen_true(); + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_PPI: + /* + * Check that we have a data frame. + */ + b0 = gen_check_802_11_data_frame(); + return b0; + + default: + bpf_error("'llc' not supported for linktype %d", linktype); + /* NOTREACHED */ + } +} + +struct block * +gen_llc_i(void) +{ + struct block *b0, *b1; + struct slist *s; + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc(); + + /* + * Load the control byte and test the low-order bit; it must + * be clear for I frames. + */ + s = gen_load_a(OR_LLC, 2, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x01; + b1->stmts = s; + gen_not(b1); + gen_and(b0, b1); + return b1; +} + +struct block * +gen_llc_s(void) +{ + struct block *b0, *b1; + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc(); + + /* + * Now compare the low-order 2 bit of the control byte against + * the appropriate value for S frames. + */ + b1 = gen_mcmp(OR_LLC, 2, BPF_B, LLC_S_FMT, 0x03); + gen_and(b0, b1); + return b1; +} + +struct block * +gen_llc_u(void) +{ + struct block *b0, *b1; + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc(); + + /* + * Now compare the low-order 2 bit of the control byte against + * the appropriate value for U frames. + */ + b1 = gen_mcmp(OR_LLC, 2, BPF_B, LLC_U_FMT, 0x03); + gen_and(b0, b1); + return b1; +} + +struct block * +gen_llc_s_subtype(bpf_u_int32 subtype) +{ + struct block *b0, *b1; + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc(); + + /* + * Now check for an S frame with the appropriate type. + */ + b1 = gen_mcmp(OR_LLC, 2, BPF_B, subtype, LLC_S_CMD_MASK); + gen_and(b0, b1); + return b1; +} + +struct block * +gen_llc_u_subtype(bpf_u_int32 subtype) +{ + struct block *b0, *b1; + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc(); + + /* + * Now check for a U frame with the appropriate type. + */ + b1 = gen_mcmp(OR_LLC, 2, BPF_B, subtype, LLC_U_CMD_MASK); + gen_and(b0, b1); + return b1; +} + +/* + * Generate code to match a particular packet type, for link-layer types + * using 802.2 LLC headers. + * + * This is *NOT* used for Ethernet; "gen_ether_linktype()" is used + * for that - it handles the D/I/X Ethernet vs. 802.3+802.2 issues. + * + * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP + * value, if <= ETHERMTU. We use that to determine whether to + * match the DSAP or both DSAP and LSAP or to check the OUI and + * protocol ID in a SNAP header. + */ +static struct block * +gen_llc_linktype(proto) + int proto; +{ + /* + * XXX - handle token-ring variable-length header. + */ + switch (proto) { + + case LLCSAP_IP: + case LLCSAP_ISONS: + case LLCSAP_NETBEUI: + /* + * XXX - should we check both the DSAP and the + * SSAP, like this, or should we check just the + * DSAP, as we do for other SAP values? + */ + return gen_cmp(OR_LLC, 0, BPF_H, (bpf_u_int32) + ((proto << 8) | proto)); + + case LLCSAP_IPX: + /* + * XXX - are there ever SNAP frames for IPX on + * non-Ethernet 802.x networks? + */ + return gen_cmp(OR_LLC, 0, BPF_B, + (bpf_int32)LLCSAP_IPX); + + case ETHERTYPE_ATALK: + /* + * 802.2-encapsulated ETHERTYPE_ATALK packets are + * SNAP packets with an organization code of + * 0x080007 (Apple, for Appletalk) and a protocol + * type of ETHERTYPE_ATALK (Appletalk). + * + * XXX - check for an organization code of + * encapsulated Ethernet as well? + */ + return gen_snap(0x080007, ETHERTYPE_ATALK); + + default: + /* + * XXX - we don't have to check for IPX 802.3 + * here, but should we check for the IPX Ethertype? + */ + if (proto <= ETHERMTU) { + /* + * This is an LLC SAP value, so check + * the DSAP. + */ + return gen_cmp(OR_LLC, 0, BPF_B, (bpf_int32)proto); + } else { + /* + * This is an Ethernet type; we assume that it's + * unlikely that it'll appear in the right place + * at random, and therefore check only the + * location that would hold the Ethernet type + * in a SNAP frame with an organization code of + * 0x000000 (encapsulated Ethernet). + * + * XXX - if we were to check for the SNAP DSAP and + * LSAP, as per XXX, and were also to check for an + * organization code of 0x000000 (encapsulated + * Ethernet), we'd do + * + * return gen_snap(0x000000, proto); + * + * here; for now, we don't, as per the above. + * I don't know whether it's worth the extra CPU + * time to do the right check or not. + */ + return gen_cmp(OR_LLC, 6, BPF_H, (bpf_int32)proto); + } + } +} + +static struct block * +gen_hostop(addr, mask, dir, proto, src_off, dst_off) + bpf_u_int32 addr; + bpf_u_int32 mask; + int dir, proto; + u_int src_off, dst_off; +{ + struct block *b0, *b1; + u_int offset; + + switch (dir) { + + case Q_SRC: + offset = src_off; + break; + + case Q_DST: + offset = dst_off; + break; + + case Q_AND: + b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); + b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); + gen_and(b0, b1); + return b1; + + case Q_OR: + case Q_DEFAULT: + b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); + b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); + gen_or(b0, b1); + return b1; + + default: + abort(); + } + b0 = gen_linktype(proto); + b1 = gen_mcmp(OR_LINKPL, offset, BPF_W, (bpf_int32)addr, mask); + gen_and(b0, b1); + return b1; +} + +#ifdef INET6 +static struct block * +gen_hostop6(addr, mask, dir, proto, src_off, dst_off) + struct in6_addr *addr; + struct in6_addr *mask; + int dir, proto; + u_int src_off, dst_off; +{ + struct block *b0, *b1; + u_int offset; + u_int32_t *a, *m; + + switch (dir) { + + case Q_SRC: + offset = src_off; + break; + + case Q_DST: + offset = dst_off; + break; + + case Q_AND: + b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off); + b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off); + gen_and(b0, b1); + return b1; + + case Q_OR: + case Q_DEFAULT: + b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off); + b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off); + gen_or(b0, b1); + return b1; + + default: + abort(); + } + /* this order is important */ + a = (u_int32_t *)addr; + m = (u_int32_t *)mask; + b1 = gen_mcmp(OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3])); + b0 = gen_mcmp(OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2])); + gen_and(b0, b1); + b0 = gen_mcmp(OR_LINKPL, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1])); + gen_and(b0, b1); + b0 = gen_mcmp(OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0])); + gen_and(b0, b1); + b0 = gen_linktype(proto); + gen_and(b0, b1); + return b1; +} +#endif + +static struct block * +gen_ehostop(eaddr, dir) + register const u_char *eaddr; + register int dir; +{ + register struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(OR_LINKHDR, 6, 6, eaddr); + + case Q_DST: + return gen_bcmp(OR_LINKHDR, 0, 6, eaddr); + + case Q_AND: + b0 = gen_ehostop(eaddr, Q_SRC); + b1 = gen_ehostop(eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_ehostop(eaddr, Q_SRC); + b1 = gen_ehostop(eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error("'addr1' is only supported on 802.11 with 802.11 headers"); + break; + + case Q_ADDR2: + bpf_error("'addr2' is only supported on 802.11 with 802.11 headers"); + break; + + case Q_ADDR3: + bpf_error("'addr3' is only supported on 802.11 with 802.11 headers"); + break; + + case Q_ADDR4: + bpf_error("'addr4' is only supported on 802.11 with 802.11 headers"); + break; + + case Q_RA: + bpf_error("'ra' is only supported on 802.11 with 802.11 headers"); + break; + + case Q_TA: + bpf_error("'ta' is only supported on 802.11 with 802.11 headers"); + break; + } + abort(); + /* NOTREACHED */ +} + +/* + * Like gen_ehostop, but for DLT_FDDI + */ +static struct block * +gen_fhostop(eaddr, dir) + register const u_char *eaddr; + register int dir; +{ + struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(OR_LINKHDR, 6 + 1 + pcap_fddipad, 6, eaddr); + + case Q_DST: + return gen_bcmp(OR_LINKHDR, 0 + 1 + pcap_fddipad, 6, eaddr); + + case Q_AND: + b0 = gen_fhostop(eaddr, Q_SRC); + b1 = gen_fhostop(eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_fhostop(eaddr, Q_SRC); + b1 = gen_fhostop(eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error("'addr1' is only supported on 802.11"); + break; + + case Q_ADDR2: + bpf_error("'addr2' is only supported on 802.11"); + break; + + case Q_ADDR3: + bpf_error("'addr3' is only supported on 802.11"); + break; + + case Q_ADDR4: + bpf_error("'addr4' is only supported on 802.11"); + break; + + case Q_RA: + bpf_error("'ra' is only supported on 802.11"); + break; + + case Q_TA: + bpf_error("'ta' is only supported on 802.11"); + break; + } + abort(); + /* NOTREACHED */ +} + +/* + * Like gen_ehostop, but for DLT_IEEE802 (Token Ring) + */ +static struct block * +gen_thostop(eaddr, dir) + register const u_char *eaddr; + register int dir; +{ + register struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(OR_LINKHDR, 8, 6, eaddr); + + case Q_DST: + return gen_bcmp(OR_LINKHDR, 2, 6, eaddr); + + case Q_AND: + b0 = gen_thostop(eaddr, Q_SRC); + b1 = gen_thostop(eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_thostop(eaddr, Q_SRC); + b1 = gen_thostop(eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error("'addr1' is only supported on 802.11"); + break; + + case Q_ADDR2: + bpf_error("'addr2' is only supported on 802.11"); + break; + + case Q_ADDR3: + bpf_error("'addr3' is only supported on 802.11"); + break; + + case Q_ADDR4: + bpf_error("'addr4' is only supported on 802.11"); + break; + + case Q_RA: + bpf_error("'ra' is only supported on 802.11"); + break; + + case Q_TA: + bpf_error("'ta' is only supported on 802.11"); + break; + } + abort(); + /* NOTREACHED */ +} + +/* + * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and + * various 802.11 + radio headers. + */ +static struct block * +gen_wlanhostop(eaddr, dir) + register const u_char *eaddr; + register int dir; +{ + register struct block *b0, *b1, *b2; + register struct slist *s; + +#ifdef ENABLE_WLAN_FILTERING_PATCH + /* + * TODO GV 20070613 + * We need to disable the optimizer because the optimizer is buggy + * and wipes out some LD instructions generated by the below + * code to validate the Frame Control bits + */ + no_optimize = 1; +#endif /* ENABLE_WLAN_FILTERING_PATCH */ + + switch (dir) { + case Q_SRC: + /* + * Oh, yuk. + * + * For control frames, there is no SA. + * + * For management frames, SA is at an + * offset of 10 from the beginning of + * the packet. + * + * For data frames, SA is at an offset + * of 10 from the beginning of the packet + * if From DS is clear, at an offset of + * 16 from the beginning of the packet + * if From DS is set and To DS is clear, + * and an offset of 24 from the beginning + * of the packet if From DS is set and To DS + * is set. + */ + + /* + * Generate the tests to be done for data frames + * with From DS set. + * + * First, check for To DS set, i.e. check "link[1] & 0x01". + */ + s = gen_load_a(OR_LINKHDR, 1, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x01; /* To DS */ + b1->stmts = s; + + /* + * If To DS is set, the SA is at 24. + */ + b0 = gen_bcmp(OR_LINKHDR, 24, 6, eaddr); + gen_and(b1, b0); + + /* + * Now, check for To DS not set, i.e. check + * "!(link[1] & 0x01)". + */ + s = gen_load_a(OR_LINKHDR, 1, BPF_B); + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x01; /* To DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If To DS is not set, the SA is at 16. + */ + b1 = gen_bcmp(OR_LINKHDR, 16, 6, eaddr); + gen_and(b2, b1); + + /* + * Now OR together the last two checks. That gives + * the complete set of checks for data frames with + * From DS set. + */ + gen_or(b1, b0); + + /* + * Now check for From DS being set, and AND that with + * the ORed-together checks. + */ + s = gen_load_a(OR_LINKHDR, 1, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x02; /* From DS */ + b1->stmts = s; + gen_and(b1, b0); + + /* + * Now check for data frames with From DS not set. + */ + s = gen_load_a(OR_LINKHDR, 1, BPF_B); + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x02; /* From DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If From DS isn't set, the SA is at 10. + */ + b1 = gen_bcmp(OR_LINKHDR, 10, 6, eaddr); + gen_and(b2, b1); + + /* + * Now OR together the checks for data frames with + * From DS not set and for data frames with From DS + * set; that gives the checks done for data frames. + */ + gen_or(b1, b0); + + /* + * Now check for a data frame. + * I.e, check "link[0] & 0x08". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the checks done for data frames. + */ + gen_and(b1, b0); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "!(link[0] & 0x08)". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x08; + b2->stmts = s; + gen_not(b2); + + /* + * For management frames, the SA is at 10. + */ + b1 = gen_bcmp(OR_LINKHDR, 10, 6, eaddr); + gen_and(b2, b1); + + /* + * OR that with the checks done for data frames. + * That gives the checks done for management and + * data frames. + */ + gen_or(b1, b0); + + /* + * If the low-order bit of the type value is 1, + * this is either a control frame or a frame + * with a reserved type, and thus not a + * frame with an SA. + * + * I.e., check "!(link[0] & 0x04)". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + /* + * AND that with the checks for data and management + * frames. + */ + gen_and(b1, b0); + return b0; + + case Q_DST: + /* + * Oh, yuk. + * + * For control frames, there is no DA. + * + * For management frames, DA is at an + * offset of 4 from the beginning of + * the packet. + * + * For data frames, DA is at an offset + * of 4 from the beginning of the packet + * if To DS is clear and at an offset of + * 16 from the beginning of the packet + * if To DS is set. + */ + + /* + * Generate the tests to be done for data frames. + * + * First, check for To DS set, i.e. "link[1] & 0x01". + */ + s = gen_load_a(OR_LINKHDR, 1, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x01; /* To DS */ + b1->stmts = s; + + /* + * If To DS is set, the DA is at 16. + */ + b0 = gen_bcmp(OR_LINKHDR, 16, 6, eaddr); + gen_and(b1, b0); + + /* + * Now, check for To DS not set, i.e. check + * "!(link[1] & 0x01)". + */ + s = gen_load_a(OR_LINKHDR, 1, BPF_B); + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x01; /* To DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If To DS is not set, the DA is at 4. + */ + b1 = gen_bcmp(OR_LINKHDR, 4, 6, eaddr); + gen_and(b2, b1); + + /* + * Now OR together the last two checks. That gives + * the complete set of checks for data frames. + */ + gen_or(b1, b0); + + /* + * Now check for a data frame. + * I.e, check "link[0] & 0x08". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the checks done for data frames. + */ + gen_and(b1, b0); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "!(link[0] & 0x08)". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x08; + b2->stmts = s; + gen_not(b2); + + /* + * For management frames, the DA is at 4. + */ + b1 = gen_bcmp(OR_LINKHDR, 4, 6, eaddr); + gen_and(b2, b1); + + /* + * OR that with the checks done for data frames. + * That gives the checks done for management and + * data frames. + */ + gen_or(b1, b0); + + /* + * If the low-order bit of the type value is 1, + * this is either a control frame or a frame + * with a reserved type, and thus not a + * frame with an SA. + * + * I.e., check "!(link[0] & 0x04)". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + /* + * AND that with the checks for data and management + * frames. + */ + gen_and(b1, b0); + return b0; + + case Q_RA: + /* + * Not present in management frames; addr1 in other + * frames. + */ + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "(link[0] & 0x08)". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * Check addr1. + */ + b0 = gen_bcmp(OR_LINKHDR, 4, 6, eaddr); + + /* + * AND that with the check of addr1. + */ + gen_and(b1, b0); + return (b0); + + case Q_TA: + /* + * Not present in management frames; addr2, if present, + * in other frames. + */ + + /* + * Not present in CTS or ACK control frames. + */ + b0 = gen_mcmp(OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_mcmp(OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b1); + b2 = gen_mcmp(OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b2); + gen_and(b1, b2); + gen_or(b0, b2); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "(link[0] & 0x08)". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the check for frames other than + * CTS and ACK frames. + */ + gen_and(b1, b2); + + /* + * Check addr2. + */ + b1 = gen_bcmp(OR_LINKHDR, 10, 6, eaddr); + gen_and(b2, b1); + return b1; + + /* + * XXX - add BSSID keyword? + */ + case Q_ADDR1: + return (gen_bcmp(OR_LINKHDR, 4, 6, eaddr)); + + case Q_ADDR2: + /* + * Not present in CTS or ACK control frames. + */ + b0 = gen_mcmp(OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_mcmp(OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b1); + b2 = gen_mcmp(OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b2); + gen_and(b1, b2); + gen_or(b0, b2); + b1 = gen_bcmp(OR_LINKHDR, 10, 6, eaddr); + gen_and(b2, b1); + return b1; + + case Q_ADDR3: + /* + * Not present in control frames. + */ + b0 = gen_mcmp(OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_bcmp(OR_LINKHDR, 16, 6, eaddr); + gen_and(b0, b1); + return b1; + + case Q_ADDR4: + /* + * Present only if the direction mask has both "From DS" + * and "To DS" set. Neither control frames nor management + * frames should have both of those set, so we don't + * check the frame type. + */ + b0 = gen_mcmp(OR_LINKHDR, 1, BPF_B, + IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK); + b1 = gen_bcmp(OR_LINKHDR, 24, 6, eaddr); + gen_and(b0, b1); + return b1; + + case Q_AND: + b0 = gen_wlanhostop(eaddr, Q_SRC); + b1 = gen_wlanhostop(eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_wlanhostop(eaddr, Q_SRC); + b1 = gen_wlanhostop(eaddr, Q_DST); + gen_or(b0, b1); + return b1; + } + abort(); + /* NOTREACHED */ +} + +/* + * Like gen_ehostop, but for RFC 2625 IP-over-Fibre-Channel. + * (We assume that the addresses are IEEE 48-bit MAC addresses, + * as the RFC states.) + */ +static struct block * +gen_ipfchostop(eaddr, dir) + register const u_char *eaddr; + register int dir; +{ + register struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(OR_LINKHDR, 10, 6, eaddr); + + case Q_DST: + return gen_bcmp(OR_LINKHDR, 2, 6, eaddr); + + case Q_AND: + b0 = gen_ipfchostop(eaddr, Q_SRC); + b1 = gen_ipfchostop(eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_ipfchostop(eaddr, Q_SRC); + b1 = gen_ipfchostop(eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error("'addr1' is only supported on 802.11"); + break; + + case Q_ADDR2: + bpf_error("'addr2' is only supported on 802.11"); + break; + + case Q_ADDR3: + bpf_error("'addr3' is only supported on 802.11"); + break; + + case Q_ADDR4: + bpf_error("'addr4' is only supported on 802.11"); + break; + + case Q_RA: + bpf_error("'ra' is only supported on 802.11"); + break; + + case Q_TA: + bpf_error("'ta' is only supported on 802.11"); + break; + } + abort(); + /* NOTREACHED */ +} + +/* + * This is quite tricky because there may be pad bytes in front of the + * DECNET header, and then there are two possible data packet formats that + * carry both src and dst addresses, plus 5 packet types in a format that + * carries only the src node, plus 2 types that use a different format and + * also carry just the src node. + * + * Yuck. + * + * Instead of doing those all right, we just look for data packets with + * 0 or 1 bytes of padding. If you want to look at other packets, that + * will require a lot more hacking. + * + * To add support for filtering on DECNET "areas" (network numbers) + * one would want to add a "mask" argument to this routine. That would + * make the filter even more inefficient, although one could be clever + * and not generate masking instructions if the mask is 0xFFFF. + */ +static struct block * +gen_dnhostop(addr, dir) + bpf_u_int32 addr; + int dir; +{ + struct block *b0, *b1, *b2, *tmp; + u_int offset_lh; /* offset if long header is received */ + u_int offset_sh; /* offset if short header is received */ + + switch (dir) { + + case Q_DST: + offset_sh = 1; /* follows flags */ + offset_lh = 7; /* flgs,darea,dsubarea,HIORD */ + break; + + case Q_SRC: + offset_sh = 3; /* follows flags, dstnode */ + offset_lh = 15; /* flgs,darea,dsubarea,did,sarea,ssub,HIORD */ + break; + + case Q_AND: + /* Inefficient because we do our Calvinball dance twice */ + b0 = gen_dnhostop(addr, Q_SRC); + b1 = gen_dnhostop(addr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_OR: + case Q_DEFAULT: + /* Inefficient because we do our Calvinball dance twice */ + b0 = gen_dnhostop(addr, Q_SRC); + b1 = gen_dnhostop(addr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ISO: + bpf_error("ISO host filtering not implemented"); + + default: + abort(); + } + b0 = gen_linktype(ETHERTYPE_DN); + /* Check for pad = 1, long header case */ + tmp = gen_mcmp(OR_LINKPL, 2, BPF_H, + (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF)); + b1 = gen_cmp(OR_LINKPL, 2 + 1 + offset_lh, + BPF_H, (bpf_int32)ntohs((u_short)addr)); + gen_and(tmp, b1); + /* Check for pad = 0, long header case */ + tmp = gen_mcmp(OR_LINKPL, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7); + b2 = gen_cmp(OR_LINKPL, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr)); + gen_and(tmp, b2); + gen_or(b2, b1); + /* Check for pad = 1, short header case */ + tmp = gen_mcmp(OR_LINKPL, 2, BPF_H, + (bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF)); + b2 = gen_cmp(OR_LINKPL, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr)); + gen_and(tmp, b2); + gen_or(b2, b1); + /* Check for pad = 0, short header case */ + tmp = gen_mcmp(OR_LINKPL, 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7); + b2 = gen_cmp(OR_LINKPL, 2 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr)); + gen_and(tmp, b2); + gen_or(b2, b1); + + /* Combine with test for linktype */ + gen_and(b0, b1); + return b1; +} + +/* + * Generate a check for IPv4 or IPv6 for MPLS-encapsulated packets; + * test the bottom-of-stack bit, and then check the version number + * field in the IP header. + */ +static struct block * +gen_mpls_linktype(proto) + int proto; +{ + struct block *b0, *b1; + + switch (proto) { + + case Q_IP: + /* match the bottom-of-stack bit */ + b0 = gen_mcmp(OR_LINKPL, -2, BPF_B, 0x01, 0x01); + /* match the IPv4 version number */ + b1 = gen_mcmp(OR_LINKPL, 0, BPF_B, 0x40, 0xf0); + gen_and(b0, b1); + return b1; + + case Q_IPV6: + /* match the bottom-of-stack bit */ + b0 = gen_mcmp(OR_LINKPL, -2, BPF_B, 0x01, 0x01); + /* match the IPv4 version number */ + b1 = gen_mcmp(OR_LINKPL, 0, BPF_B, 0x60, 0xf0); + gen_and(b0, b1); + return b1; + + default: + abort(); + } +} + +static struct block * +gen_host(addr, mask, proto, dir, type) + bpf_u_int32 addr; + bpf_u_int32 mask; + int proto; + int dir; + int type; +{ + struct block *b0, *b1; + const char *typestr; + + if (type == Q_NET) + typestr = "net"; + else + typestr = "host"; + + switch (proto) { + + case Q_DEFAULT: + b0 = gen_host(addr, mask, Q_IP, dir, type); + /* + * Only check for non-IPv4 addresses if we're not + * checking MPLS-encapsulated packets. + */ + if (label_stack_depth == 0) { + b1 = gen_host(addr, mask, Q_ARP, dir, type); + gen_or(b0, b1); + b0 = gen_host(addr, mask, Q_RARP, dir, type); + gen_or(b1, b0); + } + return b0; + + case Q_IP: + return gen_hostop(addr, mask, dir, ETHERTYPE_IP, 12, 16); + + case Q_RARP: + return gen_hostop(addr, mask, dir, ETHERTYPE_REVARP, 14, 24); + + case Q_ARP: + return gen_hostop(addr, mask, dir, ETHERTYPE_ARP, 14, 24); + + case Q_TCP: + bpf_error("'tcp' modifier applied to %s", typestr); + + case Q_SCTP: + bpf_error("'sctp' modifier applied to %s", typestr); + + case Q_UDP: + bpf_error("'udp' modifier applied to %s", typestr); + + case Q_ICMP: + bpf_error("'icmp' modifier applied to %s", typestr); + + case Q_IGMP: + bpf_error("'igmp' modifier applied to %s", typestr); + + case Q_IGRP: + bpf_error("'igrp' modifier applied to %s", typestr); + + case Q_PIM: + bpf_error("'pim' modifier applied to %s", typestr); + + case Q_VRRP: + bpf_error("'vrrp' modifier applied to %s", typestr); + + case Q_CARP: + bpf_error("'carp' modifier applied to %s", typestr); + + case Q_ATALK: + bpf_error("ATALK host filtering not implemented"); + + case Q_AARP: + bpf_error("AARP host filtering not implemented"); + + case Q_DECNET: + return gen_dnhostop(addr, dir); + + case Q_SCA: + bpf_error("SCA host filtering not implemented"); + + case Q_LAT: + bpf_error("LAT host filtering not implemented"); + + case Q_MOPDL: + bpf_error("MOPDL host filtering not implemented"); + + case Q_MOPRC: + bpf_error("MOPRC host filtering not implemented"); + + case Q_IPV6: + bpf_error("'ip6' modifier applied to ip host"); + + case Q_ICMPV6: + bpf_error("'icmp6' modifier applied to %s", typestr); + + case Q_AH: + bpf_error("'ah' modifier applied to %s", typestr); + + case Q_ESP: + bpf_error("'esp' modifier applied to %s", typestr); + + case Q_ISO: + bpf_error("ISO host filtering not implemented"); + + case Q_ESIS: + bpf_error("'esis' modifier applied to %s", typestr); + + case Q_ISIS: + bpf_error("'isis' modifier applied to %s", typestr); + + case Q_CLNP: + bpf_error("'clnp' modifier applied to %s", typestr); + + case Q_STP: + bpf_error("'stp' modifier applied to %s", typestr); + + case Q_IPX: + bpf_error("IPX host filtering not implemented"); + + case Q_NETBEUI: + bpf_error("'netbeui' modifier applied to %s", typestr); + + case Q_RADIO: + bpf_error("'radio' modifier applied to %s", typestr); + + default: + abort(); + } + /* NOTREACHED */ +} + +#ifdef INET6 +static struct block * +gen_host6(addr, mask, proto, dir, type) + struct in6_addr *addr; + struct in6_addr *mask; + int proto; + int dir; + int type; +{ + const char *typestr; + + if (type == Q_NET) + typestr = "net"; + else + typestr = "host"; + + switch (proto) { + + case Q_DEFAULT: + return gen_host6(addr, mask, Q_IPV6, dir, type); + + case Q_LINK: + bpf_error("link-layer modifier applied to ip6 %s", typestr); + + case Q_IP: + bpf_error("'ip' modifier applied to ip6 %s", typestr); + + case Q_RARP: + bpf_error("'rarp' modifier applied to ip6 %s", typestr); + + case Q_ARP: + bpf_error("'arp' modifier applied to ip6 %s", typestr); + + case Q_SCTP: + bpf_error("'sctp' modifier applied to %s", typestr); + + case Q_TCP: + bpf_error("'tcp' modifier applied to %s", typestr); + + case Q_UDP: + bpf_error("'udp' modifier applied to %s", typestr); + + case Q_ICMP: + bpf_error("'icmp' modifier applied to %s", typestr); + + case Q_IGMP: + bpf_error("'igmp' modifier applied to %s", typestr); + + case Q_IGRP: + bpf_error("'igrp' modifier applied to %s", typestr); + + case Q_PIM: + bpf_error("'pim' modifier applied to %s", typestr); + + case Q_VRRP: + bpf_error("'vrrp' modifier applied to %s", typestr); + + case Q_CARP: + bpf_error("'carp' modifier applied to %s", typestr); + + case Q_ATALK: + bpf_error("ATALK host filtering not implemented"); + + case Q_AARP: + bpf_error("AARP host filtering not implemented"); + + case Q_DECNET: + bpf_error("'decnet' modifier applied to ip6 %s", typestr); + + case Q_SCA: + bpf_error("SCA host filtering not implemented"); + + case Q_LAT: + bpf_error("LAT host filtering not implemented"); + + case Q_MOPDL: + bpf_error("MOPDL host filtering not implemented"); + + case Q_MOPRC: + bpf_error("MOPRC host filtering not implemented"); + + case Q_IPV6: + return gen_hostop6(addr, mask, dir, ETHERTYPE_IPV6, 8, 24); + + case Q_ICMPV6: + bpf_error("'icmp6' modifier applied to %s", typestr); + + case Q_AH: + bpf_error("'ah' modifier applied to %s", typestr); + + case Q_ESP: + bpf_error("'esp' modifier applied to %s", typestr); + + case Q_ISO: + bpf_error("ISO host filtering not implemented"); + + case Q_ESIS: + bpf_error("'esis' modifier applied to %s", typestr); + + case Q_ISIS: + bpf_error("'isis' modifier applied to %s", typestr); + + case Q_CLNP: + bpf_error("'clnp' modifier applied to %s", typestr); + + case Q_STP: + bpf_error("'stp' modifier applied to %s", typestr); + + case Q_IPX: + bpf_error("IPX host filtering not implemented"); + + case Q_NETBEUI: + bpf_error("'netbeui' modifier applied to %s", typestr); + + case Q_RADIO: + bpf_error("'radio' modifier applied to %s", typestr); + + default: + abort(); + } + /* NOTREACHED */ +} +#endif + +#ifndef INET6 +static struct block * +gen_gateway(eaddr, alist, proto, dir) + const u_char *eaddr; + bpf_u_int32 **alist; + int proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + if (dir != 0) + bpf_error("direction applied to 'gateway'"); + + switch (proto) { + case Q_DEFAULT: + case Q_IP: + case Q_ARP: + case Q_RARP: + switch (linktype) { + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + b1 = gen_prevlinkhdr_check(); + b0 = gen_ehostop(eaddr, Q_OR); + if (b1 != NULL) + gen_and(b1, b0); + break; + case DLT_FDDI: + b0 = gen_fhostop(eaddr, Q_OR); + break; + case DLT_IEEE802: + b0 = gen_thostop(eaddr, Q_OR); + break; + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + b0 = gen_wlanhostop(eaddr, Q_OR); + break; + case DLT_SUNATM: + /* + * This is LLC-multiplexed traffic; if it were + * LANE, linktype would have been set to + * DLT_EN10MB. + */ + bpf_error( + "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + break; + case DLT_IP_OVER_FC: + b0 = gen_ipfchostop(eaddr, Q_OR); + break; + default: + bpf_error( + "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + } + b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR, Q_HOST); + while (*alist) { + tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR, + Q_HOST); + gen_or(b1, tmp); + b1 = tmp; + } + gen_not(b1); + gen_and(b0, b1); + return b1; + } + bpf_error("illegal modifier of 'gateway'"); + /* NOTREACHED */ +} +#endif + +struct block * +gen_proto_abbrev(proto) + int proto; +{ + struct block *b0; + struct block *b1; + + switch (proto) { + + case Q_SCTP: + b1 = gen_proto(IPPROTO_SCTP, Q_IP, Q_DEFAULT); + b0 = gen_proto(IPPROTO_SCTP, Q_IPV6, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_TCP: + b1 = gen_proto(IPPROTO_TCP, Q_IP, Q_DEFAULT); + b0 = gen_proto(IPPROTO_TCP, Q_IPV6, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_UDP: + b1 = gen_proto(IPPROTO_UDP, Q_IP, Q_DEFAULT); + b0 = gen_proto(IPPROTO_UDP, Q_IPV6, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ICMP: + b1 = gen_proto(IPPROTO_ICMP, Q_IP, Q_DEFAULT); + break; + +#ifndef IPPROTO_IGMP +#define IPPROTO_IGMP 2 +#endif + + case Q_IGMP: + b1 = gen_proto(IPPROTO_IGMP, Q_IP, Q_DEFAULT); + break; + +#ifndef IPPROTO_IGRP +#define IPPROTO_IGRP 9 +#endif + case Q_IGRP: + b1 = gen_proto(IPPROTO_IGRP, Q_IP, Q_DEFAULT); + break; + +#ifndef IPPROTO_PIM +#define IPPROTO_PIM 103 +#endif + + case Q_PIM: + b1 = gen_proto(IPPROTO_PIM, Q_IP, Q_DEFAULT); + b0 = gen_proto(IPPROTO_PIM, Q_IPV6, Q_DEFAULT); + gen_or(b0, b1); + break; + +#ifndef IPPROTO_VRRP +#define IPPROTO_VRRP 112 +#endif + + case Q_VRRP: + b1 = gen_proto(IPPROTO_VRRP, Q_IP, Q_DEFAULT); + break; + +#ifndef IPPROTO_CARP +#define IPPROTO_CARP 112 +#endif + + case Q_CARP: + b1 = gen_proto(IPPROTO_CARP, Q_IP, Q_DEFAULT); + break; + + case Q_IP: + b1 = gen_linktype(ETHERTYPE_IP); + break; + + case Q_ARP: + b1 = gen_linktype(ETHERTYPE_ARP); + break; + + case Q_RARP: + b1 = gen_linktype(ETHERTYPE_REVARP); + break; + + case Q_LINK: + bpf_error("link layer applied in wrong context"); + + case Q_ATALK: + b1 = gen_linktype(ETHERTYPE_ATALK); + break; + + case Q_AARP: + b1 = gen_linktype(ETHERTYPE_AARP); + break; + + case Q_DECNET: + b1 = gen_linktype(ETHERTYPE_DN); + break; + + case Q_SCA: + b1 = gen_linktype(ETHERTYPE_SCA); + break; + + case Q_LAT: + b1 = gen_linktype(ETHERTYPE_LAT); + break; + + case Q_MOPDL: + b1 = gen_linktype(ETHERTYPE_MOPDL); + break; + + case Q_MOPRC: + b1 = gen_linktype(ETHERTYPE_MOPRC); + break; + + case Q_IPV6: + b1 = gen_linktype(ETHERTYPE_IPV6); + break; + +#ifndef IPPROTO_ICMPV6 +#define IPPROTO_ICMPV6 58 +#endif + case Q_ICMPV6: + b1 = gen_proto(IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT); + break; + +#ifndef IPPROTO_AH +#define IPPROTO_AH 51 +#endif + case Q_AH: + b1 = gen_proto(IPPROTO_AH, Q_IP, Q_DEFAULT); + b0 = gen_proto(IPPROTO_AH, Q_IPV6, Q_DEFAULT); + gen_or(b0, b1); + break; + +#ifndef IPPROTO_ESP +#define IPPROTO_ESP 50 +#endif + case Q_ESP: + b1 = gen_proto(IPPROTO_ESP, Q_IP, Q_DEFAULT); + b0 = gen_proto(IPPROTO_ESP, Q_IPV6, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISO: + b1 = gen_linktype(LLCSAP_ISONS); + break; + + case Q_ESIS: + b1 = gen_proto(ISO9542_ESIS, Q_ISO, Q_DEFAULT); + break; + + case Q_ISIS: + b1 = gen_proto(ISO10589_ISIS, Q_ISO, Q_DEFAULT); + break; + + case Q_ISIS_L1: /* all IS-IS Level1 PDU-Types */ + b0 = gen_proto(ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ + gen_or(b0, b1); + b0 = gen_proto(ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_L2: /* all IS-IS Level2 PDU-Types */ + b0 = gen_proto(ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ + gen_or(b0, b1); + b0 = gen_proto(ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_IIH: /* all IS-IS Hello PDU-Types */ + b0 = gen_proto(ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_LSP: + b0 = gen_proto(ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_SNP: + b0 = gen_proto(ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_CSNP: + b0 = gen_proto(ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_PSNP: + b0 = gen_proto(ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_CLNP: + b1 = gen_proto(ISO8473_CLNP, Q_ISO, Q_DEFAULT); + break; + + case Q_STP: + b1 = gen_linktype(LLCSAP_8021D); + break; + + case Q_IPX: + b1 = gen_linktype(LLCSAP_IPX); + break; + + case Q_NETBEUI: + b1 = gen_linktype(LLCSAP_NETBEUI); + break; + + case Q_RADIO: + bpf_error("'radio' is not a valid protocol type"); + + default: + abort(); + } + return b1; +} + +static struct block * +gen_ipfrag() +{ + struct slist *s; + struct block *b; + + /* not IPv4 frag other than the first frag */ + s = gen_load_a(OR_LINKPL, 6, BPF_H); + b = new_block(JMP(BPF_JSET)); + b->s.k = 0x1fff; + b->stmts = s; + gen_not(b); + + return b; +} + +/* + * Generate a comparison to a port value in the transport-layer header + * at the specified offset from the beginning of that header. + * + * XXX - this handles a variable-length prefix preceding the link-layer + * header, such as the radiotap or AVS radio prefix, but doesn't handle + * variable-length link-layer headers (such as Token Ring or 802.11 + * headers). + */ +static struct block * +gen_portatom(off, v) + int off; + bpf_int32 v; +{ + return gen_cmp(OR_TRAN_IPV4, off, BPF_H, v); +} + +static struct block * +gen_portatom6(off, v) + int off; + bpf_int32 v; +{ + return gen_cmp(OR_TRAN_IPV6, off, BPF_H, v); +} + +struct block * +gen_portop(port, proto, dir) + int port, proto, dir; +{ + struct block *b0, *b1, *tmp; + + /* ip proto 'proto' and not a fragment other than the first fragment */ + tmp = gen_cmp(OR_LINKPL, 9, BPF_B, (bpf_int32)proto); + b0 = gen_ipfrag(); + gen_and(tmp, b0); + + switch (dir) { + case Q_SRC: + b1 = gen_portatom(0, (bpf_int32)port); + break; + + case Q_DST: + b1 = gen_portatom(2, (bpf_int32)port); + break; + + case Q_OR: + case Q_DEFAULT: + tmp = gen_portatom(0, (bpf_int32)port); + b1 = gen_portatom(2, (bpf_int32)port); + gen_or(tmp, b1); + break; + + case Q_AND: + tmp = gen_portatom(0, (bpf_int32)port); + b1 = gen_portatom(2, (bpf_int32)port); + gen_and(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_port(port, ip_proto, dir) + int port; + int ip_proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* + * ether proto ip + * + * For FDDI, RFC 1188 says that SNAP encapsulation is used, + * not LLC encapsulation with LLCSAP_IP. + * + * For IEEE 802 networks - which includes 802.5 token ring + * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042 + * says that SNAP encapsulation is used, not LLC encapsulation + * with LLCSAP_IP. + * + * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and + * RFC 2225 say that SNAP encapsulation is used, not LLC + * encapsulation with LLCSAP_IP. + * + * So we always check for ETHERTYPE_IP. + */ + b0 = gen_linktype(ETHERTYPE_IP); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + b1 = gen_portop(port, ip_proto, dir); + break; + + case PROTO_UNDEF: + tmp = gen_portop(port, IPPROTO_TCP, dir); + b1 = gen_portop(port, IPPROTO_UDP, dir); + gen_or(tmp, b1); + tmp = gen_portop(port, IPPROTO_SCTP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} + +struct block * +gen_portop6(port, proto, dir) + int port, proto, dir; +{ + struct block *b0, *b1, *tmp; + + /* ip6 proto 'proto' */ + /* XXX - catch the first fragment of a fragmented packet? */ + b0 = gen_cmp(OR_LINKPL, 6, BPF_B, (bpf_int32)proto); + + switch (dir) { + case Q_SRC: + b1 = gen_portatom6(0, (bpf_int32)port); + break; + + case Q_DST: + b1 = gen_portatom6(2, (bpf_int32)port); + break; + + case Q_OR: + case Q_DEFAULT: + tmp = gen_portatom6(0, (bpf_int32)port); + b1 = gen_portatom6(2, (bpf_int32)port); + gen_or(tmp, b1); + break; + + case Q_AND: + tmp = gen_portatom6(0, (bpf_int32)port); + b1 = gen_portatom6(2, (bpf_int32)port); + gen_and(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_port6(port, ip_proto, dir) + int port; + int ip_proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* link proto ip6 */ + b0 = gen_linktype(ETHERTYPE_IPV6); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + b1 = gen_portop6(port, ip_proto, dir); + break; + + case PROTO_UNDEF: + tmp = gen_portop6(port, IPPROTO_TCP, dir); + b1 = gen_portop6(port, IPPROTO_UDP, dir); + gen_or(tmp, b1); + tmp = gen_portop6(port, IPPROTO_SCTP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} + +/* gen_portrange code */ +static struct block * +gen_portrangeatom(off, v1, v2) + int off; + bpf_int32 v1, v2; +{ + struct block *b1, *b2; + + if (v1 > v2) { + /* + * Reverse the order of the ports, so v1 is the lower one. + */ + bpf_int32 vtemp; + + vtemp = v1; + v1 = v2; + v2 = vtemp; + } + + b1 = gen_cmp_ge(OR_TRAN_IPV4, off, BPF_H, v1); + b2 = gen_cmp_le(OR_TRAN_IPV4, off, BPF_H, v2); + + gen_and(b1, b2); + + return b2; +} + +struct block * +gen_portrangeop(port1, port2, proto, dir) + int port1, port2; + int proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* ip proto 'proto' and not a fragment other than the first fragment */ + tmp = gen_cmp(OR_LINKPL, 9, BPF_B, (bpf_int32)proto); + b0 = gen_ipfrag(); + gen_and(tmp, b0); + + switch (dir) { + case Q_SRC: + b1 = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2); + break; + + case Q_DST: + b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2); + break; + + case Q_OR: + case Q_DEFAULT: + tmp = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2); + gen_or(tmp, b1); + break; + + case Q_AND: + tmp = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2); + gen_and(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_portrange(port1, port2, ip_proto, dir) + int port1, port2; + int ip_proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* link proto ip */ + b0 = gen_linktype(ETHERTYPE_IP); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + b1 = gen_portrangeop(port1, port2, ip_proto, dir); + break; + + case PROTO_UNDEF: + tmp = gen_portrangeop(port1, port2, IPPROTO_TCP, dir); + b1 = gen_portrangeop(port1, port2, IPPROTO_UDP, dir); + gen_or(tmp, b1); + tmp = gen_portrangeop(port1, port2, IPPROTO_SCTP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} + +static struct block * +gen_portrangeatom6(off, v1, v2) + int off; + bpf_int32 v1, v2; +{ + struct block *b1, *b2; + + if (v1 > v2) { + /* + * Reverse the order of the ports, so v1 is the lower one. + */ + bpf_int32 vtemp; + + vtemp = v1; + v1 = v2; + v2 = vtemp; + } + + b1 = gen_cmp_ge(OR_TRAN_IPV6, off, BPF_H, v1); + b2 = gen_cmp_le(OR_TRAN_IPV6, off, BPF_H, v2); + + gen_and(b1, b2); + + return b2; +} + +struct block * +gen_portrangeop6(port1, port2, proto, dir) + int port1, port2; + int proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* ip6 proto 'proto' */ + /* XXX - catch the first fragment of a fragmented packet? */ + b0 = gen_cmp(OR_LINKPL, 6, BPF_B, (bpf_int32)proto); + + switch (dir) { + case Q_SRC: + b1 = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2); + break; + + case Q_DST: + b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2); + break; + + case Q_OR: + case Q_DEFAULT: + tmp = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2); + gen_or(tmp, b1); + break; + + case Q_AND: + tmp = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2); + gen_and(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_portrange6(port1, port2, ip_proto, dir) + int port1, port2; + int ip_proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* link proto ip6 */ + b0 = gen_linktype(ETHERTYPE_IPV6); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + b1 = gen_portrangeop6(port1, port2, ip_proto, dir); + break; + + case PROTO_UNDEF: + tmp = gen_portrangeop6(port1, port2, IPPROTO_TCP, dir); + b1 = gen_portrangeop6(port1, port2, IPPROTO_UDP, dir); + gen_or(tmp, b1); + tmp = gen_portrangeop6(port1, port2, IPPROTO_SCTP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} + +static int +lookup_proto(name, proto) + register const char *name; + register int proto; +{ + register int v; + + switch (proto) { + + case Q_DEFAULT: + case Q_IP: + case Q_IPV6: + v = pcap_nametoproto(name); + if (v == PROTO_UNDEF) + bpf_error("unknown ip proto '%s'", name); + break; + + case Q_LINK: + /* XXX should look up h/w protocol type based on linktype */ + v = pcap_nametoeproto(name); + if (v == PROTO_UNDEF) { + v = pcap_nametollc(name); + if (v == PROTO_UNDEF) + bpf_error("unknown ether proto '%s'", name); + } + break; + + case Q_ISO: + if (strcmp(name, "esis") == 0) + v = ISO9542_ESIS; + else if (strcmp(name, "isis") == 0) + v = ISO10589_ISIS; + else if (strcmp(name, "clnp") == 0) + v = ISO8473_CLNP; + else + bpf_error("unknown osi proto '%s'", name); + break; + + default: + v = PROTO_UNDEF; + break; + } + return v; +} + +#if 0 +struct stmt * +gen_joinsp(s, n) + struct stmt **s; + int n; +{ + return NULL; +} +#endif + +static struct block * +gen_protochain(v, proto, dir) + int v; + int proto; + int dir; +{ +#ifdef NO_PROTOCHAIN + return gen_proto(v, proto, dir); +#else + struct block *b0, *b; + struct slist *s[100]; + int fix2, fix3, fix4, fix5; + int ahcheck, again, end; + int i, max; + int reg2 = alloc_reg(); + + memset(s, 0, sizeof(s)); + fix2 = fix3 = fix4 = fix5 = 0; + + switch (proto) { + case Q_IP: + case Q_IPV6: + break; + case Q_DEFAULT: + b0 = gen_protochain(v, Q_IP, dir); + b = gen_protochain(v, Q_IPV6, dir); + gen_or(b0, b); + return b; + default: + bpf_error("bad protocol applied for 'protochain'"); + /*NOTREACHED*/ + } + + /* + * We don't handle variable-length prefixes before the link-layer + * header, or variable-length link-layer headers, here yet. + * We might want to add BPF instructions to do the protochain + * work, to simplify that and, on platforms that have a BPF + * interpreter with the new instructions, let the filtering + * be done in the kernel. (We already require a modified BPF + * engine to do the protochain stuff, to support backward + * branches, and backward branch support is unlikely to appear + * in kernel BPF engines.) + */ + if (off_linkpl.is_variable) + bpf_error("'protochain' not supported with variable length headers"); + + no_optimize = 1; /*this code is not compatible with optimzer yet */ + + /* + * s[0] is a dummy entry to protect other BPF insn from damage + * by s[fix] = foo with uninitialized variable "fix". It is somewhat + * hard to find interdependency made by jump table fixup. + */ + i = 0; + s[i] = new_stmt(0); /*dummy*/ + i++; + + switch (proto) { + case Q_IP: + b0 = gen_linktype(ETHERTYPE_IP); + + /* A = ip->ip_p */ + s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B); + s[i]->s.k = off_linkpl.constant_part + off_nl + 9; + i++; + /* X = ip->ip_hl << 2 */ + s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B); + s[i]->s.k = off_linkpl.constant_part + off_nl; + i++; + break; + + case Q_IPV6: + b0 = gen_linktype(ETHERTYPE_IPV6); + + /* A = ip6->ip_nxt */ + s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B); + s[i]->s.k = off_linkpl.constant_part + off_nl + 6; + i++; + /* X = sizeof(struct ip6_hdr) */ + s[i] = new_stmt(BPF_LDX|BPF_IMM); + s[i]->s.k = 40; + i++; + break; + + default: + bpf_error("unsupported proto to gen_protochain"); + /*NOTREACHED*/ + } + + /* again: if (A == v) goto end; else fall through; */ + again = i; + s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.k = v; + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*update in next stmt*/ + fix5 = i; + i++; + +#ifndef IPPROTO_NONE +#define IPPROTO_NONE 59 +#endif + /* if (A == IPPROTO_NONE) goto end */ + s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*update in next stmt*/ + s[i]->s.k = IPPROTO_NONE; + s[fix5]->s.jf = s[i]; + fix2 = i; + i++; + + if (proto == Q_IPV6) { + int v6start, v6end, v6advance, j; + + v6start = i; + /* if (A == IPPROTO_HOPOPTS) goto v6advance */ + s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*update in next stmt*/ + s[i]->s.k = IPPROTO_HOPOPTS; + s[fix2]->s.jf = s[i]; + i++; + /* if (A == IPPROTO_DSTOPTS) goto v6advance */ + s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*update in next stmt*/ + s[i]->s.k = IPPROTO_DSTOPTS; + i++; + /* if (A == IPPROTO_ROUTING) goto v6advance */ + s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*update in next stmt*/ + s[i]->s.k = IPPROTO_ROUTING; + i++; + /* if (A == IPPROTO_FRAGMENT) goto v6advance; else goto ahcheck; */ + s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*later*/ + s[i]->s.k = IPPROTO_FRAGMENT; + fix3 = i; + v6end = i; + i++; + + /* v6advance: */ + v6advance = i; + + /* + * in short, + * A = P[X + packet head]; + * X = X + (P[X + packet head + 1] + 1) * 8; + */ + /* A = P[X + packet head] */ + s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); + s[i]->s.k = off_linkpl.constant_part + off_nl; + i++; + /* MEM[reg2] = A */ + s[i] = new_stmt(BPF_ST); + s[i]->s.k = reg2; + i++; + /* A = P[X + packet head + 1]; */ + s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); + s[i]->s.k = off_linkpl.constant_part + off_nl + 1; + i++; + /* A += 1 */ + s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 1; + i++; + /* A *= 8 */ + s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K); + s[i]->s.k = 8; + i++; + /* A += X */ + s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_X); + s[i]->s.k = 0; + i++; + /* X = A; */ + s[i] = new_stmt(BPF_MISC|BPF_TAX); + i++; + /* A = MEM[reg2] */ + s[i] = new_stmt(BPF_LD|BPF_MEM); + s[i]->s.k = reg2; + i++; + + /* goto again; (must use BPF_JA for backward jump) */ + s[i] = new_stmt(BPF_JMP|BPF_JA); + s[i]->s.k = again - i - 1; + s[i - 1]->s.jf = s[i]; + i++; + + /* fixup */ + for (j = v6start; j <= v6end; j++) + s[j]->s.jt = s[v6advance]; + } else { + /* nop */ + s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 0; + s[fix2]->s.jf = s[i]; + i++; + } + + /* ahcheck: */ + ahcheck = i; + /* if (A == IPPROTO_AH) then fall through; else goto end; */ + s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*later*/ + s[i]->s.k = IPPROTO_AH; + if (fix3) + s[fix3]->s.jf = s[ahcheck]; + fix4 = i; + i++; + + /* + * in short, + * A = P[X]; + * X = X + (P[X + 1] + 2) * 4; + */ + /* A = X */ + s[i - 1]->s.jt = s[i] = new_stmt(BPF_MISC|BPF_TXA); + i++; + /* A = P[X + packet head]; */ + s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); + s[i]->s.k = off_linkpl.constant_part + off_nl; + i++; + /* MEM[reg2] = A */ + s[i] = new_stmt(BPF_ST); + s[i]->s.k = reg2; + i++; + /* A = X */ + s[i - 1]->s.jt = s[i] = new_stmt(BPF_MISC|BPF_TXA); + i++; + /* A += 1 */ + s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 1; + i++; + /* X = A */ + s[i] = new_stmt(BPF_MISC|BPF_TAX); + i++; + /* A = P[X + packet head] */ + s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); + s[i]->s.k = off_linkpl.constant_part + off_nl; + i++; + /* A += 2 */ + s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 2; + i++; + /* A *= 4 */ + s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K); + s[i]->s.k = 4; + i++; + /* X = A; */ + s[i] = new_stmt(BPF_MISC|BPF_TAX); + i++; + /* A = MEM[reg2] */ + s[i] = new_stmt(BPF_LD|BPF_MEM); + s[i]->s.k = reg2; + i++; + + /* goto again; (must use BPF_JA for backward jump) */ + s[i] = new_stmt(BPF_JMP|BPF_JA); + s[i]->s.k = again - i - 1; + i++; + + /* end: nop */ + end = i; + s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 0; + s[fix2]->s.jt = s[end]; + s[fix4]->s.jf = s[end]; + s[fix5]->s.jt = s[end]; + i++; + + /* + * make slist chain + */ + max = i; + for (i = 0; i < max - 1; i++) + s[i]->next = s[i + 1]; + s[max - 1]->next = NULL; + + /* + * emit final check + */ + b = new_block(JMP(BPF_JEQ)); + b->stmts = s[1]; /*remember, s[0] is dummy*/ + b->s.k = v; + + free_reg(reg2); + + gen_and(b0, b); + return b; +#endif +} + +static struct block * +gen_check_802_11_data_frame() +{ + struct slist *s; + struct block *b0, *b1; + + /* + * A data frame has the 0x08 bit (b3) in the frame control field set + * and the 0x04 bit (b2) clear. + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b0 = new_block(JMP(BPF_JSET)); + b0->s.k = 0x08; + b0->stmts = s; + + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + gen_and(b1, b0); + + return b0; +} + +/* + * Generate code that checks whether the packet is a packet for protocol + * and whether the type field in that protocol's header has + * the value , e.g. if is Q_IP, it checks whether it's an + * IP packet and checks the protocol number in the IP header against . + * + * If is Q_DEFAULT, i.e. just "proto" was specified, it checks + * against Q_IP and Q_IPV6. + */ +static struct block * +gen_proto(v, proto, dir) + int v; + int proto; + int dir; +{ + struct block *b0, *b1; +#ifndef CHASE_CHAIN + struct block *b2; +#endif + + if (dir != Q_DEFAULT) + bpf_error("direction applied to 'proto'"); + + switch (proto) { + case Q_DEFAULT: + b0 = gen_proto(v, Q_IP, dir); + b1 = gen_proto(v, Q_IPV6, dir); + gen_or(b0, b1); + return b1; + + case Q_IP: + /* + * For FDDI, RFC 1188 says that SNAP encapsulation is used, + * not LLC encapsulation with LLCSAP_IP. + * + * For IEEE 802 networks - which includes 802.5 token ring + * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042 + * says that SNAP encapsulation is used, not LLC encapsulation + * with LLCSAP_IP. + * + * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and + * RFC 2225 say that SNAP encapsulation is used, not LLC + * encapsulation with LLCSAP_IP. + * + * So we always check for ETHERTYPE_IP. + */ + b0 = gen_linktype(ETHERTYPE_IP); +#ifndef CHASE_CHAIN + b1 = gen_cmp(OR_LINKPL, 9, BPF_B, (bpf_int32)v); +#else + b1 = gen_protochain(v, Q_IP); +#endif + gen_and(b0, b1); + return b1; + + case Q_ISO: + switch (linktype) { + + case DLT_FRELAY: + /* + * Frame Relay packets typically have an OSI + * NLPID at the beginning; "gen_linktype(LLCSAP_ISONS)" + * generates code to check for all the OSI + * NLPIDs, so calling it and then adding a check + * for the particular NLPID for which we're + * looking is bogus, as we can just check for + * the NLPID. + * + * What we check for is the NLPID and a frame + * control field value of UI, i.e. 0x03 followed + * by the NLPID. + * + * XXX - assumes a 2-byte Frame Relay header with + * DLCI and flags. What if the address is longer? + * + * XXX - what about SNAP-encapsulated frames? + */ + return gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | v); + /*NOTREACHED*/ + break; + + case DLT_C_HDLC: + /* + * Cisco uses an Ethertype lookalike - for OSI, + * it's 0xfefe. + */ + b0 = gen_linktype(LLCSAP_ISONS<<8 | LLCSAP_ISONS); + /* OSI in C-HDLC is stuffed with a fudge byte */ + b1 = gen_cmp(OR_LINKPL_NOSNAP, 1, BPF_B, (long)v); + gen_and(b0, b1); + return b1; + + default: + b0 = gen_linktype(LLCSAP_ISONS); + b1 = gen_cmp(OR_LINKPL_NOSNAP, 0, BPF_B, (long)v); + gen_and(b0, b1); + return b1; + } + + case Q_ISIS: + b0 = gen_proto(ISO10589_ISIS, Q_ISO, Q_DEFAULT); + /* + * 4 is the offset of the PDU type relative to the IS-IS + * header. + */ + b1 = gen_cmp(OR_LINKPL_NOSNAP, 4, BPF_B, (long)v); + gen_and(b0, b1); + return b1; + + case Q_ARP: + bpf_error("arp does not encapsulate another protocol"); + /* NOTREACHED */ + + case Q_RARP: + bpf_error("rarp does not encapsulate another protocol"); + /* NOTREACHED */ + + case Q_ATALK: + bpf_error("atalk encapsulation is not specifiable"); + /* NOTREACHED */ + + case Q_DECNET: + bpf_error("decnet encapsulation is not specifiable"); + /* NOTREACHED */ + + case Q_SCA: + bpf_error("sca does not encapsulate another protocol"); + /* NOTREACHED */ + + case Q_LAT: + bpf_error("lat does not encapsulate another protocol"); + /* NOTREACHED */ + + case Q_MOPRC: + bpf_error("moprc does not encapsulate another protocol"); + /* NOTREACHED */ + + case Q_MOPDL: + bpf_error("mopdl does not encapsulate another protocol"); + /* NOTREACHED */ + + case Q_LINK: + return gen_linktype(v); + + case Q_UDP: + bpf_error("'udp proto' is bogus"); + /* NOTREACHED */ + + case Q_TCP: + bpf_error("'tcp proto' is bogus"); + /* NOTREACHED */ + + case Q_SCTP: + bpf_error("'sctp proto' is bogus"); + /* NOTREACHED */ + + case Q_ICMP: + bpf_error("'icmp proto' is bogus"); + /* NOTREACHED */ + + case Q_IGMP: + bpf_error("'igmp proto' is bogus"); + /* NOTREACHED */ + + case Q_IGRP: + bpf_error("'igrp proto' is bogus"); + /* NOTREACHED */ + + case Q_PIM: + bpf_error("'pim proto' is bogus"); + /* NOTREACHED */ + + case Q_VRRP: + bpf_error("'vrrp proto' is bogus"); + /* NOTREACHED */ + + case Q_CARP: + bpf_error("'carp proto' is bogus"); + /* NOTREACHED */ + + case Q_IPV6: + b0 = gen_linktype(ETHERTYPE_IPV6); +#ifndef CHASE_CHAIN + /* + * Also check for a fragment header before the final + * header. + */ + b2 = gen_cmp(OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT); + b1 = gen_cmp(OR_LINKPL, 40, BPF_B, (bpf_int32)v); + gen_and(b2, b1); + b2 = gen_cmp(OR_LINKPL, 6, BPF_B, (bpf_int32)v); + gen_or(b2, b1); +#else + b1 = gen_protochain(v, Q_IPV6); +#endif + gen_and(b0, b1); + return b1; + + case Q_ICMPV6: + bpf_error("'icmp6 proto' is bogus"); + + case Q_AH: + bpf_error("'ah proto' is bogus"); + + case Q_ESP: + bpf_error("'ah proto' is bogus"); + + case Q_STP: + bpf_error("'stp proto' is bogus"); + + case Q_IPX: + bpf_error("'ipx proto' is bogus"); + + case Q_NETBEUI: + bpf_error("'netbeui proto' is bogus"); + + case Q_RADIO: + bpf_error("'radio proto' is bogus"); + + default: + abort(); + /* NOTREACHED */ + } + /* NOTREACHED */ +} + +struct block * +gen_scode(name, q) + register const char *name; + struct qual q; +{ + int proto = q.proto; + int dir = q.dir; + int tproto; + u_char *eaddr; + bpf_u_int32 mask, addr; +#ifndef INET6 + bpf_u_int32 **alist; +#else + int tproto6; + struct sockaddr_in *sin4; + struct sockaddr_in6 *sin6; + struct addrinfo *res, *res0; + struct in6_addr mask128; +#endif /*INET6*/ + struct block *b, *tmp; + int port, real_proto; + int port1, port2; + + switch (q.addr) { + + case Q_NET: + addr = pcap_nametonetaddr(name); + if (addr == 0) + bpf_error("unknown network '%s'", name); + /* Left justify network addr and calculate its network mask */ + mask = 0xffffffff; + while (addr && (addr & 0xff000000) == 0) { + addr <<= 8; + mask <<= 8; + } + return gen_host(addr, mask, proto, dir, q.addr); + + case Q_DEFAULT: + case Q_HOST: + if (proto == Q_LINK) { + switch (linktype) { + + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error( + "unknown ether host '%s'", name); + tmp = gen_prevlinkhdr_check(); + b = gen_ehostop(eaddr, dir); + if (tmp != NULL) + gen_and(tmp, b); + free(eaddr); + return b; + + case DLT_FDDI: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error( + "unknown FDDI host '%s'", name); + b = gen_fhostop(eaddr, dir); + free(eaddr); + return b; + + case DLT_IEEE802: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error( + "unknown token ring host '%s'", name); + b = gen_thostop(eaddr, dir); + free(eaddr); + return b; + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error( + "unknown 802.11 host '%s'", name); + b = gen_wlanhostop(eaddr, dir); + free(eaddr); + return b; + + case DLT_IP_OVER_FC: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error( + "unknown Fibre Channel host '%s'", name); + b = gen_ipfchostop(eaddr, dir); + free(eaddr); + return b; + } + + bpf_error("only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name"); + } else if (proto == Q_DECNET) { + unsigned short dn_addr = __pcap_nametodnaddr(name); + /* + * I don't think DECNET hosts can be multihomed, so + * there is no need to build up a list of addresses + */ + return (gen_host(dn_addr, 0, proto, dir, q.addr)); + } else { +#ifndef INET6 + alist = pcap_nametoaddr(name); + if (alist == NULL || *alist == NULL) + bpf_error("unknown host '%s'", name); + tproto = proto; + if (off_linktype.constant_part == (u_int)-1 && + tproto == Q_DEFAULT) + tproto = Q_IP; + b = gen_host(**alist++, 0xffffffff, tproto, dir, q.addr); + while (*alist) { + tmp = gen_host(**alist++, 0xffffffff, + tproto, dir, q.addr); + gen_or(b, tmp); + b = tmp; + } + return b; +#else + memset(&mask128, 0xff, sizeof(mask128)); + res0 = res = pcap_nametoaddrinfo(name); + if (res == NULL) + bpf_error("unknown host '%s'", name); + ai = res; + b = tmp = NULL; + tproto = tproto6 = proto; + if (off_linktype.constant_part == -1 && + tproto == Q_DEFAULT) { + tproto = Q_IP; + tproto6 = Q_IPV6; + } + for (res = res0; res; res = res->ai_next) { + switch (res->ai_family) { + case AF_INET: + if (tproto == Q_IPV6) + continue; + + sin4 = (struct sockaddr_in *) + res->ai_addr; + tmp = gen_host(ntohl(sin4->sin_addr.s_addr), + 0xffffffff, tproto, dir, q.addr); + break; + case AF_INET6: + if (tproto6 == Q_IP) + continue; + + sin6 = (struct sockaddr_in6 *) + res->ai_addr; + tmp = gen_host6(&sin6->sin6_addr, + &mask128, tproto6, dir, q.addr); + break; + default: + continue; + } + if (b) + gen_or(b, tmp); + b = tmp; + } + ai = NULL; + freeaddrinfo(res0); + if (b == NULL) { + bpf_error("unknown host '%s'%s", name, + (proto == Q_DEFAULT) + ? "" + : " for specified address family"); + } + return b; +#endif /*INET6*/ + } + + case Q_PORT: + if (proto != Q_DEFAULT && + proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) + bpf_error("illegal qualifier of 'port'"); + if (pcap_nametoport(name, &port, &real_proto) == 0) + bpf_error("unknown port '%s'", name); + if (proto == Q_UDP) { + if (real_proto == IPPROTO_TCP) + bpf_error("port '%s' is tcp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error("port '%s' is sctp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_UDP; + } + if (proto == Q_TCP) { + if (real_proto == IPPROTO_UDP) + bpf_error("port '%s' is udp", name); + + else if (real_proto == IPPROTO_SCTP) + bpf_error("port '%s' is sctp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_TCP; + } + if (proto == Q_SCTP) { + if (real_proto == IPPROTO_UDP) + bpf_error("port '%s' is udp", name); + + else if (real_proto == IPPROTO_TCP) + bpf_error("port '%s' is tcp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_SCTP; + } + if (port < 0) + bpf_error("illegal port number %d < 0", port); + if (port > 65535) + bpf_error("illegal port number %d > 65535", port); + b = gen_port(port, real_proto, dir); + gen_or(gen_port6(port, real_proto, dir), b); + return b; + + case Q_PORTRANGE: + if (proto != Q_DEFAULT && + proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) + bpf_error("illegal qualifier of 'portrange'"); + if (pcap_nametoportrange(name, &port1, &port2, &real_proto) == 0) + bpf_error("unknown port in range '%s'", name); + if (proto == Q_UDP) { + if (real_proto == IPPROTO_TCP) + bpf_error("port in range '%s' is tcp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error("port in range '%s' is sctp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_UDP; + } + if (proto == Q_TCP) { + if (real_proto == IPPROTO_UDP) + bpf_error("port in range '%s' is udp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error("port in range '%s' is sctp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_TCP; + } + if (proto == Q_SCTP) { + if (real_proto == IPPROTO_UDP) + bpf_error("port in range '%s' is udp", name); + else if (real_proto == IPPROTO_TCP) + bpf_error("port in range '%s' is tcp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_SCTP; + } + if (port1 < 0) + bpf_error("illegal port number %d < 0", port1); + if (port1 > 65535) + bpf_error("illegal port number %d > 65535", port1); + if (port2 < 0) + bpf_error("illegal port number %d < 0", port2); + if (port2 > 65535) + bpf_error("illegal port number %d > 65535", port2); + + b = gen_portrange(port1, port2, real_proto, dir); + gen_or(gen_portrange6(port1, port2, real_proto, dir), b); + return b; + + case Q_GATEWAY: +#ifndef INET6 + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error("unknown ether host: %s", name); + + alist = pcap_nametoaddr(name); + if (alist == NULL || *alist == NULL) + bpf_error("unknown host '%s'", name); + b = gen_gateway(eaddr, alist, proto, dir); + free(eaddr); + return b; +#else + bpf_error("'gateway' not supported in this configuration"); +#endif /*INET6*/ + + case Q_PROTO: + real_proto = lookup_proto(name, proto); + if (real_proto >= 0) + return gen_proto(real_proto, proto, dir); + else + bpf_error("unknown protocol: %s", name); + + case Q_PROTOCHAIN: + real_proto = lookup_proto(name, proto); + if (real_proto >= 0) + return gen_protochain(real_proto, proto, dir); + else + bpf_error("unknown protocol: %s", name); + + case Q_UNDEF: + syntax(); + /* NOTREACHED */ + } + abort(); + /* NOTREACHED */ +} + +struct block * +gen_mcode(s1, s2, masklen, q) + register const char *s1, *s2; + register unsigned int masklen; + struct qual q; +{ + register int nlen, mlen; + bpf_u_int32 n, m; + + nlen = __pcap_atoin(s1, &n); + /* Promote short ipaddr */ + n <<= 32 - nlen; + + if (s2 != NULL) { + mlen = __pcap_atoin(s2, &m); + /* Promote short ipaddr */ + m <<= 32 - mlen; + if ((n & ~m) != 0) + bpf_error("non-network bits set in \"%s mask %s\"", + s1, s2); + } else { + /* Convert mask len to mask */ + if (masklen > 32) + bpf_error("mask length must be <= 32"); + if (masklen == 0) { + /* + * X << 32 is not guaranteed by C to be 0; it's + * undefined. + */ + m = 0; + } else + m = 0xffffffff << (32 - masklen); + if ((n & ~m) != 0) + bpf_error("non-network bits set in \"%s/%d\"", + s1, masklen); + } + + switch (q.addr) { + + case Q_NET: + return gen_host(n, m, q.proto, q.dir, q.addr); + + default: + bpf_error("Mask syntax for networks only"); + /* NOTREACHED */ + } + /* NOTREACHED */ + return NULL; +} + +struct block * +gen_ncode(s, v, q) + register const char *s; + bpf_u_int32 v; + struct qual q; +{ + bpf_u_int32 mask; + int proto = q.proto; + int dir = q.dir; + register int vlen; + + if (s == NULL) + vlen = 32; + else if (q.proto == Q_DECNET) + vlen = __pcap_atodn(s, &v); + else + vlen = __pcap_atoin(s, &v); + + switch (q.addr) { + + case Q_DEFAULT: + case Q_HOST: + case Q_NET: + if (proto == Q_DECNET) + return gen_host(v, 0, proto, dir, q.addr); + else if (proto == Q_LINK) { + bpf_error("illegal link layer address"); + } else { + mask = 0xffffffff; + if (s == NULL && q.addr == Q_NET) { + /* Promote short net number */ + while (v && (v & 0xff000000) == 0) { + v <<= 8; + mask <<= 8; + } + } else { + /* Promote short ipaddr */ + v <<= 32 - vlen; + mask <<= 32 - vlen; + } + return gen_host(v, mask, proto, dir, q.addr); + } + + case Q_PORT: + if (proto == Q_UDP) + proto = IPPROTO_UDP; + else if (proto == Q_TCP) + proto = IPPROTO_TCP; + else if (proto == Q_SCTP) + proto = IPPROTO_SCTP; + else if (proto == Q_DEFAULT) + proto = PROTO_UNDEF; + else + bpf_error("illegal qualifier of 'port'"); + + if (v > 65535) + bpf_error("illegal port number %u > 65535", v); + + { + struct block *b; + b = gen_port((int)v, proto, dir); + gen_or(gen_port6((int)v, proto, dir), b); + return b; + } + + case Q_PORTRANGE: + if (proto == Q_UDP) + proto = IPPROTO_UDP; + else if (proto == Q_TCP) + proto = IPPROTO_TCP; + else if (proto == Q_SCTP) + proto = IPPROTO_SCTP; + else if (proto == Q_DEFAULT) + proto = PROTO_UNDEF; + else + bpf_error("illegal qualifier of 'portrange'"); + + if (v > 65535) + bpf_error("illegal port number %u > 65535", v); + + { + struct block *b; + b = gen_portrange((int)v, (int)v, proto, dir); + gen_or(gen_portrange6((int)v, (int)v, proto, dir), b); + return b; + } + + case Q_GATEWAY: + bpf_error("'gateway' requires a name"); + /* NOTREACHED */ + + case Q_PROTO: + return gen_proto((int)v, proto, dir); + + case Q_PROTOCHAIN: + return gen_protochain((int)v, proto, dir); + + case Q_UNDEF: + syntax(); + /* NOTREACHED */ + + default: + abort(); + /* NOTREACHED */ + } + /* NOTREACHED */ +} + +#ifdef INET6 +struct block * +gen_mcode6(s1, s2, masklen, q) + register const char *s1, *s2; + register unsigned int masklen; + struct qual q; +{ + struct addrinfo *res; + struct in6_addr *addr; + struct in6_addr mask; + struct block *b; + u_int32_t *a, *m; + + if (s2) + bpf_error("no mask %s supported", s2); + + res = pcap_nametoaddrinfo(s1); + if (!res) + bpf_error("invalid ip6 address %s", s1); + ai = res; + if (res->ai_next) + bpf_error("%s resolved to multiple address", s1); + addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; + + if (sizeof(mask) * 8 < masklen) + bpf_error("mask length must be <= %u", (unsigned int)(sizeof(mask) * 8)); + memset(&mask, 0, sizeof(mask)); + memset(&mask, 0xff, masklen / 8); + if (masklen % 8) { + mask.s6_addr[masklen / 8] = + (0xff << (8 - masklen % 8)) & 0xff; + } + + a = (u_int32_t *)addr; + m = (u_int32_t *)&mask; + if ((a[0] & ~m[0]) || (a[1] & ~m[1]) + || (a[2] & ~m[2]) || (a[3] & ~m[3])) { + bpf_error("non-network bits set in \"%s/%d\"", s1, masklen); + } + + switch (q.addr) { + + case Q_DEFAULT: + case Q_HOST: + if (masklen != 128) + bpf_error("Mask syntax for networks only"); + /* FALLTHROUGH */ + + case Q_NET: + b = gen_host6(addr, &mask, q.proto, q.dir, q.addr); + ai = NULL; + freeaddrinfo(res); + return b; + + default: + bpf_error("invalid qualifier against IPv6 address"); + /* NOTREACHED */ + } + return NULL; +} +#endif /*INET6*/ + +struct block * +gen_ecode(eaddr, q) + register const u_char *eaddr; + struct qual q; +{ + struct block *b, *tmp; + + if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { + switch (linktype) { + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + tmp = gen_prevlinkhdr_check(); + b = gen_ehostop(eaddr, (int)q.dir); + if (tmp != NULL) + gen_and(tmp, b); + return b; + case DLT_FDDI: + return gen_fhostop(eaddr, (int)q.dir); + case DLT_IEEE802: + return gen_thostop(eaddr, (int)q.dir); + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + return gen_wlanhostop(eaddr, (int)q.dir); + case DLT_IP_OVER_FC: + return gen_ipfchostop(eaddr, (int)q.dir); + default: + bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + break; + } + } + bpf_error("ethernet address used in non-ether expression"); + /* NOTREACHED */ + return NULL; +} + +void +sappend(s0, s1) + struct slist *s0, *s1; +{ + /* + * This is definitely not the best way to do this, but the + * lists will rarely get long. + */ + while (s0->next) + s0 = s0->next; + s0->next = s1; +} + +static struct slist * +xfer_to_x(a) + struct arth *a; +{ + struct slist *s; + + s = new_stmt(BPF_LDX|BPF_MEM); + s->s.k = a->regno; + return s; +} + +static struct slist * +xfer_to_a(a) + struct arth *a; +{ + struct slist *s; + + s = new_stmt(BPF_LD|BPF_MEM); + s->s.k = a->regno; + return s; +} + +/* + * Modify "index" to use the value stored into its register as an + * offset relative to the beginning of the header for the protocol + * "proto", and allocate a register and put an item "size" bytes long + * (1, 2, or 4) at that offset into that register, making it the register + * for "index". + */ +struct arth * +gen_load(proto, inst, size) + int proto; + struct arth *inst; + int size; +{ + struct slist *s, *tmp; + struct block *b; + int regno = alloc_reg(); + + free_reg(inst->regno); + switch (size) { + + default: + bpf_error("data size must be 1, 2, or 4"); + + case 1: + size = BPF_B; + break; + + case 2: + size = BPF_H; + break; + + case 4: + size = BPF_W; + break; + } + switch (proto) { + default: + bpf_error("unsupported index operation"); + + case Q_RADIO: + /* + * The offset is relative to the beginning of the packet + * data, if we have a radio header. (If we don't, this + * is an error.) + */ + if (linktype != DLT_IEEE802_11_RADIO_AVS && + linktype != DLT_IEEE802_11_RADIO && + linktype != DLT_PRISM_HEADER) + bpf_error("radio information not present in capture"); + + /* + * Load into the X register the offset computed into the + * register specified by "index". + */ + s = xfer_to_x(inst); + + /* + * Load the item at that offset. + */ + tmp = new_stmt(BPF_LD|BPF_IND|size); + sappend(s, tmp); + sappend(inst->s, s); + break; + + case Q_LINK: + /* + * The offset is relative to the beginning of + * the link-layer header. + * + * XXX - what about ATM LANE? Should the index be + * relative to the beginning of the AAL5 frame, so + * that 0 refers to the beginning of the LE Control + * field, or relative to the beginning of the LAN + * frame, so that 0 refers, for Ethernet LANE, to + * the beginning of the destination address? + */ + s = gen_abs_offset_varpart(&off_linkhdr); + + /* + * If "s" is non-null, it has code to arrange that the + * X register contains the length of the prefix preceding + * the link-layer header. Add to it the offset computed + * into the register specified by "index", and move that + * into the X register. Otherwise, just load into the X + * register the offset computed into the register specified + * by "index". + */ + if (s != NULL) { + sappend(s, xfer_to_a(inst)); + sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(BPF_MISC|BPF_TAX)); + } else + s = xfer_to_x(inst); + + /* + * Load the item at the sum of the offset we've put in the + * X register and the offset of the start of the link + * layer header (which is 0 if the radio header is + * variable-length; that header length is what we put + * into the X register and then added to the index). + */ + tmp = new_stmt(BPF_LD|BPF_IND|size); + tmp->s.k = off_linkhdr.constant_part; + sappend(s, tmp); + sappend(inst->s, s); + break; + + case Q_IP: + case Q_ARP: + case Q_RARP: + case Q_ATALK: + case Q_DECNET: + case Q_SCA: + case Q_LAT: + case Q_MOPRC: + case Q_MOPDL: + case Q_IPV6: + /* + * The offset is relative to the beginning of + * the network-layer header. + * XXX - are there any cases where we want + * off_nl_nosnap? + */ + s = gen_abs_offset_varpart(&off_linkpl); + + /* + * If "s" is non-null, it has code to arrange that the + * X register contains the variable part of the offset + * of the link-layer payload. Add to it the offset + * computed into the register specified by "index", + * and move that into the X register. Otherwise, just + * load into the X register the offset computed into + * the register specified by "index". + */ + if (s != NULL) { + sappend(s, xfer_to_a(inst)); + sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(BPF_MISC|BPF_TAX)); + } else + s = xfer_to_x(inst); + + /* + * Load the item at the sum of the offset we've put in the + * X register, the offset of the start of the network + * layer header from the beginning of the link-layer + * payload, and the constant part of the offset of the + * start of the link-layer payload. + */ + tmp = new_stmt(BPF_LD|BPF_IND|size); + tmp->s.k = off_linkpl.constant_part + off_nl; + sappend(s, tmp); + sappend(inst->s, s); + + /* + * Do the computation only if the packet contains + * the protocol in question. + */ + b = gen_proto_abbrev(proto); + if (inst->b) + gen_and(inst->b, b); + inst->b = b; + break; + + case Q_SCTP: + case Q_TCP: + case Q_UDP: + case Q_ICMP: + case Q_IGMP: + case Q_IGRP: + case Q_PIM: + case Q_VRRP: + case Q_CARP: + /* + * The offset is relative to the beginning of + * the transport-layer header. + * + * Load the X register with the length of the IPv4 header + * (plus the offset of the link-layer header, if it's + * a variable-length header), in bytes. + * + * XXX - are there any cases where we want + * off_nl_nosnap? + * XXX - we should, if we're built with + * IPv6 support, generate code to load either + * IPv4, IPv6, or both, as appropriate. + */ + s = gen_loadx_iphdrlen(); + + /* + * The X register now contains the sum of the variable + * part of the offset of the link-layer payload and the + * length of the network-layer header. + * + * Load into the A register the offset relative to + * the beginning of the transport layer header, + * add the X register to that, move that to the + * X register, and load with an offset from the + * X register equal to the sum of the constant part of + * the offset of the link-layer payload and the offset, + * relative to the beginning of the link-layer payload, + * of the network-layer header. + */ + sappend(s, xfer_to_a(inst)); + sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(BPF_MISC|BPF_TAX)); + sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size)); + tmp->s.k = off_linkpl.constant_part + off_nl; + sappend(inst->s, s); + + /* + * Do the computation only if the packet contains + * the protocol in question - which is true only + * if this is an IP datagram and is the first or + * only fragment of that datagram. + */ + gen_and(gen_proto_abbrev(proto), b = gen_ipfrag()); + if (inst->b) + gen_and(inst->b, b); + gen_and(gen_proto_abbrev(Q_IP), b); + inst->b = b; + break; + case Q_ICMPV6: + bpf_error("IPv6 upper-layer protocol is not supported by proto[x]"); + /*NOTREACHED*/ + } + inst->regno = regno; + s = new_stmt(BPF_ST); + s->s.k = regno; + sappend(inst->s, s); + + return inst; +} + +struct block * +gen_relation(code, a0, a1, reversed) + int code; + struct arth *a0, *a1; + int reversed; +{ + struct slist *s0, *s1, *s2; + struct block *b, *tmp; + + s0 = xfer_to_x(a1); + s1 = xfer_to_a(a0); + if (code == BPF_JEQ) { + s2 = new_stmt(BPF_ALU|BPF_SUB|BPF_X); + b = new_block(JMP(code)); + sappend(s1, s2); + } + else + b = new_block(BPF_JMP|code|BPF_X); + if (reversed) + gen_not(b); + + sappend(s0, s1); + sappend(a1->s, s0); + sappend(a0->s, a1->s); + + b->stmts = a0->s; + + free_reg(a0->regno); + free_reg(a1->regno); + + /* 'and' together protocol checks */ + if (a0->b) { + if (a1->b) { + gen_and(a0->b, tmp = a1->b); + } + else + tmp = a0->b; + } else + tmp = a1->b; + + if (tmp) + gen_and(tmp, b); + + return b; +} + +struct arth * +gen_loadlen() +{ + int regno = alloc_reg(); + struct arth *a = (struct arth *)newchunk(sizeof(*a)); + struct slist *s; + + s = new_stmt(BPF_LD|BPF_LEN); + s->next = new_stmt(BPF_ST); + s->next->s.k = regno; + a->s = s; + a->regno = regno; + + return a; +} + +struct arth * +gen_loadi(val) + int val; +{ + struct arth *a; + struct slist *s; + int reg; + + a = (struct arth *)newchunk(sizeof(*a)); + + reg = alloc_reg(); + + s = new_stmt(BPF_LD|BPF_IMM); + s->s.k = val; + s->next = new_stmt(BPF_ST); + s->next->s.k = reg; + a->s = s; + a->regno = reg; + + return a; +} + +struct arth * +gen_neg(a) + struct arth *a; +{ + struct slist *s; + + s = xfer_to_a(a); + sappend(a->s, s); + s = new_stmt(BPF_ALU|BPF_NEG); + s->s.k = 0; + sappend(a->s, s); + s = new_stmt(BPF_ST); + s->s.k = a->regno; + sappend(a->s, s); + + return a; +} + +struct arth * +gen_arth(code, a0, a1) + int code; + struct arth *a0, *a1; +{ + struct slist *s0, *s1, *s2; + + s0 = xfer_to_x(a1); + s1 = xfer_to_a(a0); + s2 = new_stmt(BPF_ALU|BPF_X|code); + + sappend(s1, s2); + sappend(s0, s1); + sappend(a1->s, s0); + sappend(a0->s, a1->s); + + free_reg(a0->regno); + free_reg(a1->regno); + + s0 = new_stmt(BPF_ST); + a0->regno = s0->s.k = alloc_reg(); + sappend(a0->s, s0); + + return a0; +} + +/* + * Here we handle simple allocation of the scratch registers. + * If too many registers are alloc'd, the allocator punts. + */ +static int regused[BPF_MEMWORDS]; +static int curreg; + +/* + * Initialize the table of used registers and the current register. + */ +static void +init_regs() +{ + curreg = 0; + memset(regused, 0, sizeof regused); +} + +/* + * Return the next free register. + */ +static int +alloc_reg() +{ + int n = BPF_MEMWORDS; + + while (--n >= 0) { + if (regused[curreg]) + curreg = (curreg + 1) % BPF_MEMWORDS; + else { + regused[curreg] = 1; + return curreg; + } + } + bpf_error("too many registers needed to evaluate expression"); + /* NOTREACHED */ + return 0; +} + +/* + * Return a register to the table so it can + * be used later. + */ +static void +free_reg(n) + int n; +{ + regused[n] = 0; +} + +static struct block * +gen_len(jmp, n) + int jmp, n; +{ + struct slist *s; + struct block *b; + + s = new_stmt(BPF_LD|BPF_LEN); + b = new_block(JMP(jmp)); + b->stmts = s; + b->s.k = n; + + return b; +} + +struct block * +gen_greater(n) + int n; +{ + return gen_len(BPF_JGE, n); +} + +/* + * Actually, this is less than or equal. + */ +struct block * +gen_less(n) + int n; +{ + struct block *b; + + b = gen_len(BPF_JGT, n); + gen_not(b); + + return b; +} + +/* + * This is for "byte {idx} {op} {val}"; "idx" is treated as relative to + * the beginning of the link-layer header. + * XXX - that means you can't test values in the radiotap header, but + * as that header is difficult if not impossible to parse generally + * without a loop, that might not be a severe problem. A new keyword + * "radio" could be added for that, although what you'd really want + * would be a way of testing particular radio header values, which + * would generate code appropriate to the radio header in question. + */ +struct block * +gen_byteop(op, idx, val) + int op, idx, val; +{ + struct block *b; + struct slist *s; + + switch (op) { + default: + abort(); + + case '=': + return gen_cmp(OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val); + + case '<': + b = gen_cmp_lt(OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val); + return b; + + case '>': + b = gen_cmp_gt(OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val); + return b; + + case '|': + s = new_stmt(BPF_ALU|BPF_OR|BPF_K); + break; + + case '&': + s = new_stmt(BPF_ALU|BPF_AND|BPF_K); + break; + } + s->s.k = val; + b = new_block(JMP(BPF_JEQ)); + b->stmts = s; + gen_not(b); + + return b; +} + +static u_char abroadcast[] = { 0x0 }; + +struct block * +gen_broadcast(proto) + int proto; +{ + bpf_u_int32 hostmask; + struct block *b0, *b1, *b2; + static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + switch (proto) { + + case Q_DEFAULT: + case Q_LINK: + switch (linktype) { + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + return gen_ahostop(abroadcast, Q_DST); + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + b1 = gen_prevlinkhdr_check(); + b0 = gen_ehostop(ebroadcast, Q_DST); + if (b1 != NULL) + gen_and(b1, b0); + return b0; + case DLT_FDDI: + return gen_fhostop(ebroadcast, Q_DST); + case DLT_IEEE802: + return gen_thostop(ebroadcast, Q_DST); + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + return gen_wlanhostop(ebroadcast, Q_DST); + case DLT_IP_OVER_FC: + return gen_ipfchostop(ebroadcast, Q_DST); + default: + bpf_error("not a broadcast link"); + } + break; + + case Q_IP: + /* + * We treat a netmask of PCAP_NETMASK_UNKNOWN (0xffffffff) + * as an indication that we don't know the netmask, and fail + * in that case. + */ + if (netmask == PCAP_NETMASK_UNKNOWN) + bpf_error("netmask not known, so 'ip broadcast' not supported"); + b0 = gen_linktype(ETHERTYPE_IP); + hostmask = ~netmask; + b1 = gen_mcmp(OR_LINKPL, 16, BPF_W, (bpf_int32)0, hostmask); + b2 = gen_mcmp(OR_LINKPL, 16, BPF_W, + (bpf_int32)(~0 & hostmask), hostmask); + gen_or(b1, b2); + gen_and(b0, b2); + return b2; + } + bpf_error("only link-layer/IP broadcast filters supported"); + /* NOTREACHED */ + return NULL; +} + +/* + * Generate code to test the low-order bit of a MAC address (that's + * the bottom bit of the *first* byte). + */ +static struct block * +gen_mac_multicast(offset) + int offset; +{ + register struct block *b0; + register struct slist *s; + + /* link[offset] & 1 != 0 */ + s = gen_load_a(OR_LINKHDR, offset, BPF_B); + b0 = new_block(JMP(BPF_JSET)); + b0->s.k = 1; + b0->stmts = s; + return b0; +} + +struct block * +gen_multicast(proto) + int proto; +{ + register struct block *b0, *b1, *b2; + register struct slist *s; + + switch (proto) { + + case Q_DEFAULT: + case Q_LINK: + switch (linktype) { + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + /* all ARCnet multicasts use the same address */ + return gen_ahostop(abroadcast, Q_DST); + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + b1 = gen_prevlinkhdr_check(); + /* ether[0] & 1 != 0 */ + b0 = gen_mac_multicast(0); + if (b1 != NULL) + gen_and(b1, b0); + return b0; + case DLT_FDDI: + /* + * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX + * + * XXX - was that referring to bit-order issues? + */ + /* fddi[1] & 1 != 0 */ + return gen_mac_multicast(1); + case DLT_IEEE802: + /* tr[2] & 1 != 0 */ + return gen_mac_multicast(2); + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + /* + * Oh, yuk. + * + * For control frames, there is no DA. + * + * For management frames, DA is at an + * offset of 4 from the beginning of + * the packet. + * + * For data frames, DA is at an offset + * of 4 from the beginning of the packet + * if To DS is clear and at an offset of + * 16 from the beginning of the packet + * if To DS is set. + */ + + /* + * Generate the tests to be done for data frames. + * + * First, check for To DS set, i.e. "link[1] & 0x01". + */ + s = gen_load_a(OR_LINKHDR, 1, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x01; /* To DS */ + b1->stmts = s; + + /* + * If To DS is set, the DA is at 16. + */ + b0 = gen_mac_multicast(16); + gen_and(b1, b0); + + /* + * Now, check for To DS not set, i.e. check + * "!(link[1] & 0x01)". + */ + s = gen_load_a(OR_LINKHDR, 1, BPF_B); + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x01; /* To DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If To DS is not set, the DA is at 4. + */ + b1 = gen_mac_multicast(4); + gen_and(b2, b1); + + /* + * Now OR together the last two checks. That gives + * the complete set of checks for data frames. + */ + gen_or(b1, b0); + + /* + * Now check for a data frame. + * I.e, check "link[0] & 0x08". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the checks done for data frames. + */ + gen_and(b1, b0); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "!(link[0] & 0x08)". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x08; + b2->stmts = s; + gen_not(b2); + + /* + * For management frames, the DA is at 4. + */ + b1 = gen_mac_multicast(4); + gen_and(b2, b1); + + /* + * OR that with the checks done for data frames. + * That gives the checks done for management and + * data frames. + */ + gen_or(b1, b0); + + /* + * If the low-order bit of the type value is 1, + * this is either a control frame or a frame + * with a reserved type, and thus not a + * frame with an SA. + * + * I.e., check "!(link[0] & 0x04)". + */ + s = gen_load_a(OR_LINKHDR, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + /* + * AND that with the checks for data and management + * frames. + */ + gen_and(b1, b0); + return b0; + case DLT_IP_OVER_FC: + b0 = gen_mac_multicast(2); + return b0; + default: + break; + } + /* Link not known to support multicasts */ + break; + + case Q_IP: + b0 = gen_linktype(ETHERTYPE_IP); + b1 = gen_cmp_ge(OR_LINKPL, 16, BPF_B, (bpf_int32)224); + gen_and(b0, b1); + return b1; + + case Q_IPV6: + b0 = gen_linktype(ETHERTYPE_IPV6); + b1 = gen_cmp(OR_LINKPL, 24, BPF_B, (bpf_int32)255); + gen_and(b0, b1); + return b1; + } + bpf_error("link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel"); + /* NOTREACHED */ + return NULL; +} + +/* + * Filter on inbound (dir == 0) or outbound (dir == 1) traffic. + * Outbound traffic is sent by this machine, while inbound traffic is + * sent by a remote machine (and may include packets destined for a + * unicast or multicast link-layer address we are not subscribing to). + * These are the same definitions implemented by pcap_setdirection(). + * Capturing only unicast traffic destined for this host is probably + * better accomplished using a higher-layer filter. + */ +struct block * +gen_inbound(dir) + int dir; +{ + register struct block *b0; + + /* + * Only some data link types support inbound/outbound qualifiers. + */ + switch (linktype) { + case DLT_SLIP: + b0 = gen_relation(BPF_JEQ, + gen_load(Q_LINK, gen_loadi(0), 1), + gen_loadi(0), + dir); + break; + + case DLT_IPNET: + if (dir) { + /* match outgoing packets */ + b0 = gen_cmp(OR_LINKHDR, 2, BPF_H, IPNET_OUTBOUND); + } else { + /* match incoming packets */ + b0 = gen_cmp(OR_LINKHDR, 2, BPF_H, IPNET_INBOUND); + } + break; + + case DLT_LINUX_SLL: + /* match outgoing packets */ + b0 = gen_cmp(OR_LINKHDR, 0, BPF_H, LINUX_SLL_OUTGOING); + if (!dir) { + /* to filter on inbound traffic, invert the match */ + gen_not(b0); + } + break; + +#ifdef HAVE_NET_PFVAR_H + case DLT_PFLOG: + b0 = gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B, + (bpf_int32)((dir == 0) ? PF_IN : PF_OUT)); + break; +#endif + + case DLT_PPP_PPPD: + if (dir) { + /* match outgoing packets */ + b0 = gen_cmp(OR_LINKHDR, 0, BPF_B, PPP_PPPD_OUT); + } else { + /* match incoming packets */ + b0 = gen_cmp(OR_LINKHDR, 0, BPF_B, PPP_PPPD_IN); + } + break; + + case DLT_JUNIPER_MFR: + case DLT_JUNIPER_MLFR: + case DLT_JUNIPER_MLPPP: + case DLT_JUNIPER_ATM1: + case DLT_JUNIPER_ATM2: + case DLT_JUNIPER_PPPOE: + case DLT_JUNIPER_PPPOE_ATM: + case DLT_JUNIPER_GGSN: + case DLT_JUNIPER_ES: + case DLT_JUNIPER_MONITOR: + case DLT_JUNIPER_SERVICES: + case DLT_JUNIPER_ETHER: + case DLT_JUNIPER_PPP: + case DLT_JUNIPER_FRELAY: + case DLT_JUNIPER_CHDLC: + case DLT_JUNIPER_VP: + case DLT_JUNIPER_ST: + case DLT_JUNIPER_ISM: + case DLT_JUNIPER_VS: + case DLT_JUNIPER_SRX_E2E: + case DLT_JUNIPER_FIBRECHANNEL: + case DLT_JUNIPER_ATM_CEMIC: + + /* juniper flags (including direction) are stored + * the byte after the 3-byte magic number */ + if (dir) { + /* match outgoing packets */ + b0 = gen_mcmp(OR_LINKHDR, 3, BPF_B, 0, 0x01); + } else { + /* match incoming packets */ + b0 = gen_mcmp(OR_LINKHDR, 3, BPF_B, 1, 0x01); + } + break; + + default: + /* + * If we have packet meta-data indicating a direction, + * check it, otherwise give up as this link-layer type + * has nothing in the packet data. + */ +#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) + /* + * This is Linux with PF_PACKET support. + * If this is a *live* capture, we can look at + * special meta-data in the filter expression; + * if it's a savefile, we can't. + */ + if (bpf_pcap->rfile != NULL) { + /* We have a FILE *, so this is a savefile */ + bpf_error("inbound/outbound not supported on linktype %d when reading savefiles", + linktype); + b0 = NULL; + /* NOTREACHED */ + } + /* match outgoing packets */ + b0 = gen_cmp(OR_LINKHDR, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H, + PACKET_OUTGOING); + if (!dir) { + /* to filter on inbound traffic, invert the match */ + gen_not(b0); + } +#else /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ + bpf_error("inbound/outbound not supported on linktype %d", + linktype); + b0 = NULL; + /* NOTREACHED */ +#endif /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ + } + return (b0); +} + +#ifdef HAVE_NET_PFVAR_H +/* PF firewall log matched interface */ +struct block * +gen_pf_ifname(const char *ifname) +{ + struct block *b0; + u_int len, off; + + if (linktype != DLT_PFLOG) { + bpf_error("ifname supported only on PF linktype"); + /* NOTREACHED */ + } + len = sizeof(((struct pfloghdr *)0)->ifname); + off = offsetof(struct pfloghdr, ifname); + if (strlen(ifname) >= len) { + bpf_error("ifname interface names can only be %d characters", + len-1); + /* NOTREACHED */ + } + b0 = gen_bcmp(OR_LINKHDR, off, strlen(ifname), (const u_char *)ifname); + return (b0); +} + +/* PF firewall log ruleset name */ +struct block * +gen_pf_ruleset(char *ruleset) +{ + struct block *b0; + + if (linktype != DLT_PFLOG) { + bpf_error("ruleset supported only on PF linktype"); + /* NOTREACHED */ + } + + if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) { + bpf_error("ruleset names can only be %ld characters", + (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1)); + /* NOTREACHED */ + } + + b0 = gen_bcmp(OR_LINKHDR, offsetof(struct pfloghdr, ruleset), + strlen(ruleset), (const u_char *)ruleset); + return (b0); +} + +/* PF firewall log rule number */ +struct block * +gen_pf_rnr(int rnr) +{ + struct block *b0; + + if (linktype != DLT_PFLOG) { + bpf_error("rnr supported only on PF linktype"); + /* NOTREACHED */ + } + + b0 = gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W, + (bpf_int32)rnr); + return (b0); +} + +/* PF firewall log sub-rule number */ +struct block * +gen_pf_srnr(int srnr) +{ + struct block *b0; + + if (linktype != DLT_PFLOG) { + bpf_error("srnr supported only on PF linktype"); + /* NOTREACHED */ + } + + b0 = gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W, + (bpf_int32)srnr); + return (b0); +} + +/* PF firewall log reason code */ +struct block * +gen_pf_reason(int reason) +{ + struct block *b0; + + if (linktype != DLT_PFLOG) { + bpf_error("reason supported only on PF linktype"); + /* NOTREACHED */ + } + + b0 = gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B, + (bpf_int32)reason); + return (b0); +} + +/* PF firewall log action */ +struct block * +gen_pf_action(int action) +{ + struct block *b0; + + if (linktype != DLT_PFLOG) { + bpf_error("action supported only on PF linktype"); + /* NOTREACHED */ + } + + b0 = gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B, + (bpf_int32)action); + return (b0); +} +#else /* !HAVE_NET_PFVAR_H */ +struct block * +gen_pf_ifname(const char *ifname) +{ + bpf_error("libpcap was compiled without pf support"); + /* NOTREACHED */ + return (NULL); +} + +struct block * +gen_pf_ruleset(char *ruleset) +{ + bpf_error("libpcap was compiled on a machine without pf support"); + /* NOTREACHED */ + return (NULL); +} + +struct block * +gen_pf_rnr(int rnr) +{ + bpf_error("libpcap was compiled on a machine without pf support"); + /* NOTREACHED */ + return (NULL); +} + +struct block * +gen_pf_srnr(int srnr) +{ + bpf_error("libpcap was compiled on a machine without pf support"); + /* NOTREACHED */ + return (NULL); +} + +struct block * +gen_pf_reason(int reason) +{ + bpf_error("libpcap was compiled on a machine without pf support"); + /* NOTREACHED */ + return (NULL); +} + +struct block * +gen_pf_action(int action) +{ + bpf_error("libpcap was compiled on a machine without pf support"); + /* NOTREACHED */ + return (NULL); +} +#endif /* HAVE_NET_PFVAR_H */ + +/* IEEE 802.11 wireless header */ +struct block * +gen_p80211_type(int type, int mask) +{ + struct block *b0; + + switch (linktype) { + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + b0 = gen_mcmp(OR_LINKHDR, 0, BPF_B, (bpf_int32)type, + (bpf_int32)mask); + break; + + default: + bpf_error("802.11 link-layer types supported only on 802.11"); + /* NOTREACHED */ + } + + return (b0); +} + +struct block * +gen_p80211_fcdir(int fcdir) +{ + struct block *b0; + + switch (linktype) { + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + break; + + default: + bpf_error("frame direction supported only with 802.11 headers"); + /* NOTREACHED */ + } + + b0 = gen_mcmp(OR_LINKHDR, 1, BPF_B, (bpf_int32)fcdir, + (bpf_u_int32)IEEE80211_FC1_DIR_MASK); + + return (b0); +} + +struct block * +gen_acode(eaddr, q) + register const u_char *eaddr; + struct qual q; +{ + switch (linktype) { + + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && + q.proto == Q_LINK) + return (gen_ahostop(eaddr, (int)q.dir)); + else { + bpf_error("ARCnet address used in non-arc expression"); + /* NOTREACHED */ + } + break; + + default: + bpf_error("aid supported only on ARCnet"); + /* NOTREACHED */ + } + bpf_error("ARCnet address used in non-arc expression"); + /* NOTREACHED */ + return NULL; +} + +static struct block * +gen_ahostop(eaddr, dir) + register const u_char *eaddr; + register int dir; +{ + register struct block *b0, *b1; + + switch (dir) { + /* src comes first, different from Ethernet */ + case Q_SRC: + return gen_bcmp(OR_LINKHDR, 0, 1, eaddr); + + case Q_DST: + return gen_bcmp(OR_LINKHDR, 1, 1, eaddr); + + case Q_AND: + b0 = gen_ahostop(eaddr, Q_SRC); + b1 = gen_ahostop(eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_ahostop(eaddr, Q_SRC); + b1 = gen_ahostop(eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error("'addr1' is only supported on 802.11"); + break; + + case Q_ADDR2: + bpf_error("'addr2' is only supported on 802.11"); + break; + + case Q_ADDR3: + bpf_error("'addr3' is only supported on 802.11"); + break; + + case Q_ADDR4: + bpf_error("'addr4' is only supported on 802.11"); + break; + + case Q_RA: + bpf_error("'ra' is only supported on 802.11"); + break; + + case Q_TA: + bpf_error("'ta' is only supported on 802.11"); + break; + } + abort(); + /* NOTREACHED */ +} + +#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) +static struct block * +gen_vlan_bpf_extensions(int vlan_num) +{ + struct block *b0, *b1; + struct slist *s; + + /* generate new filter code based on extracting packet + * metadata */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT; + + b0 = new_block(JMP(BPF_JEQ)); + b0->stmts = s; + b0->s.k = 1; + + if (vlan_num >= 0) { + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG; + + b1 = new_block(JMP(BPF_JEQ)); + b1->stmts = s; + b1->s.k = (bpf_int32) vlan_num; + + gen_and(b0,b1); + b0 = b1; + } + + return b0; +} +#endif + +static struct block * +gen_vlan_no_bpf_extensions(int vlan_num) +{ + struct block *b0, *b1; + + /* check for VLAN, including QinQ */ + b0 = gen_linktype(ETHERTYPE_8021Q); + b1 = gen_linktype(ETHERTYPE_8021QINQ); + gen_or(b0,b1); + b0 = b1; + + /* If a specific VLAN is requested, check VLAN id */ + if (vlan_num >= 0) { + b1 = gen_mcmp(OR_LINKPL, 0, BPF_H, + (bpf_int32)vlan_num, 0x0fff); + gen_and(b0, b1); + b0 = b1; + } + + /* + * The payload follows the full header, including the + * VLAN tags, so skip past this VLAN tag. + */ + off_linkpl.constant_part += 4; + + /* + * The link-layer type information follows the VLAN tags, so + * skip past this VLAN tag. + */ + off_linktype.constant_part += 4; + + return b0; +} + +/* + * support IEEE 802.1Q VLAN trunk over ethernet + */ +struct block * +gen_vlan(vlan_num) + int vlan_num; +{ + struct block *b0; + + /* can't check for VLAN-encapsulated packets inside MPLS */ + if (label_stack_depth > 0) + bpf_error("no VLAN match after MPLS"); + + /* + * Check for a VLAN packet, and then change the offsets to point + * to the type and data fields within the VLAN packet. Just + * increment the offsets, so that we can support a hierarchy, e.g. + * "vlan 300 && vlan 200" to capture VLAN 200 encapsulated within + * VLAN 100. + * + * XXX - this is a bit of a kludge. If we were to split the + * compiler into a parser that parses an expression and + * generates an expression tree, and a code generator that + * takes an expression tree (which could come from our + * parser or from some other parser) and generates BPF code, + * we could perhaps make the offsets parameters of routines + * and, in the handler for an "AND" node, pass to subnodes + * other than the VLAN node the adjusted offsets. + * + * This would mean that "vlan" would, instead of changing the + * behavior of *all* tests after it, change only the behavior + * of tests ANDed with it. That would change the documented + * semantics of "vlan", which might break some expressions. + * However, it would mean that "(vlan and ip) or ip" would check + * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than + * checking only for VLAN-encapsulated IP, so that could still + * be considered worth doing; it wouldn't break expressions + * that are of the form "vlan and ..." or "vlan N and ...", + * which I suspect are the most common expressions involving + * "vlan". "vlan or ..." doesn't necessarily do what the user + * would really want, now, as all the "or ..." tests would + * be done assuming a VLAN, even though the "or" could be viewed + * as meaning "or, if this isn't a VLAN packet...". + */ + switch (linktype) { + + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: +#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) + /* Verify that this is the outer part of the packet and + * not encapsulated somehow. */ + if (vlan_stack_depth == 0 && !off_linkhdr.is_variable && + off_linkhdr.constant_part == + off_outermostlinkhdr.constant_part) { + /* + * Do we need special VLAN handling? + */ + if (bpf_pcap->bpf_codegen_flags & BPF_SPECIAL_VLAN_HANDLING) + b0 = gen_vlan_bpf_extensions(vlan_num); + else + b0 = gen_vlan_no_bpf_extensions(vlan_num); + } else +#endif + b0 = gen_vlan_no_bpf_extensions(vlan_num); + break; + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + b0 = gen_vlan_no_bpf_extensions(vlan_num); + break; + + default: + bpf_error("no VLAN support for data link type %d", + linktype); + /*NOTREACHED*/ + } + + vlan_stack_depth++; + + return (b0); +} + +/* + * support for MPLS + */ +struct block * +gen_mpls(label_num) + int label_num; +{ + struct block *b0, *b1; + + if (label_stack_depth > 0) { + /* just match the bottom-of-stack bit clear */ + b0 = gen_mcmp(OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01); + } else { + /* + * We're not in an MPLS stack yet, so check the link-layer + * type against MPLS. + */ + switch (linktype) { + + case DLT_C_HDLC: /* fall through */ + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + b0 = gen_linktype(ETHERTYPE_MPLS); + break; + + case DLT_PPP: + b0 = gen_linktype(PPP_MPLS_UCAST); + break; + + /* FIXME add other DLT_s ... + * for Frame-Relay/and ATM this may get messy due to SNAP headers + * leave it for now */ + + default: + bpf_error("no MPLS support for data link type %d", + linktype); + b0 = NULL; + /*NOTREACHED*/ + break; + } + } + + /* If a specific MPLS label is requested, check it */ + if (label_num >= 0) { + label_num = label_num << 12; /* label is shifted 12 bits on the wire */ + b1 = gen_mcmp(OR_LINKPL, 0, BPF_W, (bpf_int32)label_num, + 0xfffff000); /* only compare the first 20 bits */ + gen_and(b0, b1); + b0 = b1; + } + + /* + * Change the offsets to point to the type and data fields within + * the MPLS packet. Just increment the offsets, so that we + * can support a hierarchy, e.g. "mpls 100000 && mpls 1024" to + * capture packets with an outer label of 100000 and an inner + * label of 1024. + * + * Increment the MPLS stack depth as well; this indicates that + * we're checking MPLS-encapsulated headers, to make sure higher + * level code generators don't try to match against IP-related + * protocols such as Q_ARP, Q_RARP etc. + * + * XXX - this is a bit of a kludge. See comments in gen_vlan(). + */ + off_nl_nosnap += 4; + off_nl += 4; + label_stack_depth++; + return (b0); +} + +/* + * Support PPPOE discovery and session. + */ +struct block * +gen_pppoed() +{ + /* check for PPPoE discovery */ + return gen_linktype((bpf_int32)ETHERTYPE_PPPOED); +} + +struct block * +gen_pppoes(sess_num) + int sess_num; +{ + struct block *b0, *b1; + + /* + * Test against the PPPoE session link-layer type. + */ + b0 = gen_linktype((bpf_int32)ETHERTYPE_PPPOES); + + /* If a specific session is requested, check PPPoE session id */ + if (sess_num >= 0) { + b1 = gen_mcmp(OR_LINKPL, 0, BPF_W, + (bpf_int32)sess_num, 0x0000ffff); + gen_and(b0, b1); + b0 = b1; + } + + /* + * Change the offsets to point to the type and data fields within + * the PPP packet, and note that this is PPPoE rather than + * raw PPP. + * + * XXX - this is a bit of a kludge. If we were to split the + * compiler into a parser that parses an expression and + * generates an expression tree, and a code generator that + * takes an expression tree (which could come from our + * parser or from some other parser) and generates BPF code, + * we could perhaps make the offsets parameters of routines + * and, in the handler for an "AND" node, pass to subnodes + * other than the PPPoE node the adjusted offsets. + * + * This would mean that "pppoes" would, instead of changing the + * behavior of *all* tests after it, change only the behavior + * of tests ANDed with it. That would change the documented + * semantics of "pppoes", which might break some expressions. + * However, it would mean that "(pppoes and ip) or ip" would check + * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than + * checking only for VLAN-encapsulated IP, so that could still + * be considered worth doing; it wouldn't break expressions + * that are of the form "pppoes and ..." which I suspect are the + * most common expressions involving "pppoes". "pppoes or ..." + * doesn't necessarily do what the user would really want, now, + * as all the "or ..." tests would be done assuming PPPoE, even + * though the "or" could be viewed as meaning "or, if this isn't + * a PPPoE packet...". + * + * The "network-layer" protocol is PPPoE, which has a 6-byte + * PPPoE header, followed by a PPP packet. + * + * There is no HDLC encapsulation for the PPP packet (it's + * encapsulated in PPPoES instead), so the link-layer type + * starts at the first byte of the PPP packet. For PPPoE, + * that offset is relative to the beginning of the total + * link-layer payload, including any 802.2 LLC header, so + * it's 6 bytes past off_nl. + */ + PUSH_LINKHDR(DLT_PPP, off_linkpl.is_variable, + off_linkpl.constant_part + off_nl + 6, /* 6 bytes past the PPPoE header */ + off_linkpl.reg); + + off_linktype = off_linkhdr; + off_linkpl.constant_part = off_linkhdr.constant_part + 2; + + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + + return b0; +} + +/* Check that this is Geneve and the VNI is correct if + * specified. Parameterized to handle both IPv4 and IPv6. */ +static struct block * +gen_geneve_check(struct block *(*gen_portfn)(int, int, int), + enum e_offrel offrel, int vni) +{ + struct block *b0, *b1; + + b0 = gen_portfn(GENEVE_PORT, IPPROTO_UDP, Q_DST); + + /* Check that we are operating on version 0. Otherwise, we + * can't decode the rest of the fields. The version is 2 bits + * in the first byte of the Geneve header. */ + b1 = gen_mcmp(offrel, 8, BPF_B, (bpf_int32)0, 0xc0); + gen_and(b0, b1); + b0 = b1; + + if (vni >= 0) { + vni <<= 8; /* VNI is in the upper 3 bytes */ + b1 = gen_mcmp(offrel, 12, BPF_W, (bpf_int32)vni, + 0xffffff00); + gen_and(b0, b1); + b0 = b1; + } + + return b0; +} + +/* The IPv4 and IPv6 Geneve checks need to do two things: + * - Verify that this actually is Geneve with the right VNI. + * - Place the IP header length (plus variable link prefix if + * needed) into register A to be used later to compute + * the inner packet offsets. */ +static struct block * +gen_geneve4(int vni) +{ + struct block *b0, *b1; + struct slist *s, *s1; + + b0 = gen_geneve_check(gen_port, OR_TRAN_IPV4, vni); + + /* Load the IP header length into A. */ + s = gen_loadx_iphdrlen(); + + s1 = new_stmt(BPF_MISC|BPF_TXA); + sappend(s, s1); + + /* Forcibly append these statements to the true condition + * of the protocol check by creating a new block that is + * always true and ANDing them. */ + b1 = new_block(BPF_JMP|BPF_JEQ|BPF_X); + b1->stmts = s; + b1->s.k = 0; + + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_geneve6(int vni) +{ + struct block *b0, *b1; + struct slist *s, *s1; + + b0 = gen_geneve_check(gen_port6, OR_TRAN_IPV6, vni); + + /* Load the IP header length. We need to account for a + * variable length link prefix if there is one. */ + s = gen_abs_offset_varpart(&off_linkpl); + if (s) { + s1 = new_stmt(BPF_LD|BPF_IMM); + s1->s.k = 40; + sappend(s, s1); + + s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_X); + s1->s.k = 0; + sappend(s, s1); + } else { + s = new_stmt(BPF_LD|BPF_IMM); + s->s.k = 40;; + } + + /* Forcibly append these statements to the true condition + * of the protocol check by creating a new block that is + * always true and ANDing them. */ + s1 = new_stmt(BPF_MISC|BPF_TAX); + sappend(s, s1); + + b1 = new_block(BPF_JMP|BPF_JEQ|BPF_X); + b1->stmts = s; + b1->s.k = 0; + + gen_and(b0, b1); + + return b1; +} + +/* We need to store three values based on the Geneve header:: + * - The offset of the linktype. + * - The offset of the end of the Geneve header. + * - The offset of the end of the encapsulated MAC header. */ +static struct slist * +gen_geneve_offsets(void) +{ + struct slist *s, *s1, *s_proto; + + /* First we need to calculate the offset of the Geneve header + * itself. This is composed of the IP header previously calculated + * (include any variable link prefix) and stored in A plus the + * fixed sized headers (fixed link prefix, MAC length, and UDP + * header). */ + s = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s->s.k = off_linkpl.constant_part + off_nl + 8; + + /* Stash this in X since we'll need it later. */ + s1 = new_stmt(BPF_MISC|BPF_TAX); + sappend(s, s1); + + /* The EtherType in Geneve is 2 bytes in. Calculate this and + * store it. */ + s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s1->s.k = 2; + sappend(s, s1); + + off_linktype.reg = alloc_reg(); + off_linktype.is_variable = 1; + off_linktype.constant_part = 0; + + s1 = new_stmt(BPF_ST); + s1->s.k = off_linktype.reg; + sappend(s, s1); + + /* Load the Geneve option length and mask and shift to get the + * number of bytes. It is stored in the first byte of the Geneve + * header. */ + s1 = new_stmt(BPF_LD|BPF_IND|BPF_B); + s1->s.k = 0; + sappend(s, s1); + + s1 = new_stmt(BPF_ALU|BPF_AND|BPF_K); + s1->s.k = 0x3f; + sappend(s, s1); + + s1 = new_stmt(BPF_ALU|BPF_MUL|BPF_K); + s1->s.k = 4; + sappend(s, s1); + + /* Add in the rest of the Geneve base header. */ + s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s1->s.k = 8; + sappend(s, s1); + + /* Add the Geneve header length to its offset and store. */ + s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_X); + s1->s.k = 0; + sappend(s, s1); + + /* Set the encapsulated type as Ethernet. Even though we may + * not actually have Ethernet inside there are two reasons this + * is useful: + * - The linktype field is always in EtherType format regardless + * of whether it is in Geneve or an inner Ethernet frame. + * - The only link layer that we have specific support for is + * Ethernet. We will confirm that the packet actually is + * Ethernet at runtime before executing these checks. */ + PUSH_LINKHDR(DLT_EN10MB, 1, 0, alloc_reg()); + + s1 = new_stmt(BPF_ST); + s1->s.k = off_linkhdr.reg; + sappend(s, s1); + + /* Calculate whether we have an Ethernet header or just raw IP/ + * MPLS/etc. If we have Ethernet, advance the end of the MAC offset + * and linktype by 14 bytes so that the network header can be found + * seamlessly. Otherwise, keep what we've calculated already. */ + + /* We have a bare jmp so we can't use the optimizer. */ + no_optimize = 1; + + /* Load the EtherType in the Geneve header, 2 bytes in. */ + s1 = new_stmt(BPF_LD|BPF_IND|BPF_H); + s1->s.k = 2; + sappend(s, s1); + + /* Load X with the end of the Geneve header. */ + s1 = new_stmt(BPF_LDX|BPF_MEM); + s1->s.k = off_linkhdr.reg; + sappend(s, s1); + + /* Check if the EtherType is Transparent Ethernet Bridging. At the + * end of this check, we should have the total length in X. In + * the non-Ethernet case, it's already there. */ + s_proto = new_stmt(JMP(BPF_JEQ)); + s_proto->s.k = ETHERTYPE_TEB; + sappend(s, s_proto); + + s1 = new_stmt(BPF_MISC|BPF_TXA); + sappend(s, s1); + s_proto->s.jt = s1; + + /* Since this is Ethernet, use the EtherType of the payload + * directly as the linktype. Overwrite what we already have. */ + s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s1->s.k = 12; + sappend(s, s1); + + s1 = new_stmt(BPF_ST); + s1->s.k = off_linktype.reg; + sappend(s, s1); + + /* Advance two bytes further to get the end of the Ethernet + * header. */ + s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s1->s.k = 2; + sappend(s, s1); + + /* Move the result to X. */ + s1 = new_stmt(BPF_MISC|BPF_TAX); + sappend(s, s1); + + /* Store the final result of our linkpl calculation. */ + off_linkpl.reg = alloc_reg(); + off_linkpl.is_variable = 1; + off_linkpl.constant_part = 0; + + s1 = new_stmt(BPF_STX); + s1->s.k = off_linkpl.reg; + sappend(s, s1); + s_proto->s.jf = s1; + + off_nl = 0; + + return s; +} + +/* Check to see if this is a Geneve packet. */ +struct block * +gen_geneve(int vni) +{ + struct block *b0, *b1; + struct slist *s; + + b0 = gen_geneve4(vni); + b1 = gen_geneve6(vni); + + gen_or(b0, b1); + b0 = b1; + + /* Later filters should act on the payload of the Geneve frame, + * update all of the header pointers. Attach this code so that + * it gets executed in the event that the Geneve filter matches. */ + s = gen_geneve_offsets(); + + b1 = gen_true(); + sappend(s, b1->stmts); + b1->stmts = s; + + gen_and(b0, b1); + + is_geneve = 1; + + return b1; +} + +/* Check that the encapsulated frame has a link layer header + * for Ethernet filters. */ +static struct block * +gen_geneve_ll_check() +{ + struct block *b0; + struct slist *s, *s1; + + /* The easiest way to see if there is a link layer present + * is to check if the link layer header and payload are not + * the same. */ + + /* Geneve always generates pure variable offsets so we can + * compare only the registers. */ + s = new_stmt(BPF_LD|BPF_MEM); + s->s.k = off_linkhdr.reg; + + s1 = new_stmt(BPF_LDX|BPF_MEM); + s1->s.k = off_linkpl.reg; + sappend(s, s1); + + b0 = new_block(BPF_JMP|BPF_JEQ|BPF_X); + b0->stmts = s; + b0->s.k = 0; + gen_not(b0); + + return b0; +} + +struct block * +gen_atmfield_code(atmfield, jvalue, jtype, reverse) + int atmfield; + bpf_int32 jvalue; + bpf_u_int32 jtype; + int reverse; +{ + struct block *b0; + + switch (atmfield) { + + case A_VPI: + if (!is_atm) + bpf_error("'vpi' supported only on raw ATM"); + if (off_vpi == (u_int)-1) + abort(); + b0 = gen_ncmp(OR_LINKHDR, off_vpi, BPF_B, 0xffffffff, jtype, + reverse, jvalue); + break; + + case A_VCI: + if (!is_atm) + bpf_error("'vci' supported only on raw ATM"); + if (off_vci == (u_int)-1) + abort(); + b0 = gen_ncmp(OR_LINKHDR, off_vci, BPF_H, 0xffffffff, jtype, + reverse, jvalue); + break; + + case A_PROTOTYPE: + if (off_proto == (u_int)-1) + abort(); /* XXX - this isn't on FreeBSD */ + b0 = gen_ncmp(OR_LINKHDR, off_proto, BPF_B, 0x0f, jtype, + reverse, jvalue); + break; + + case A_MSGTYPE: + if (off_payload == (u_int)-1) + abort(); + b0 = gen_ncmp(OR_LINKHDR, off_payload + MSG_TYPE_POS, BPF_B, + 0xffffffff, jtype, reverse, jvalue); + break; + + case A_CALLREFTYPE: + if (!is_atm) + bpf_error("'callref' supported only on raw ATM"); + if (off_proto == (u_int)-1) + abort(); + b0 = gen_ncmp(OR_LINKHDR, off_proto, BPF_B, 0xffffffff, + jtype, reverse, jvalue); + break; + + default: + abort(); + } + return b0; +} + +struct block * +gen_atmtype_abbrev(type) + int type; +{ + struct block *b0, *b1; + + switch (type) { + + case A_METAC: + /* Get all packets in Meta signalling Circuit */ + if (!is_atm) + bpf_error("'metac' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 1, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_BCC: + /* Get all packets in Broadcast Circuit*/ + if (!is_atm) + bpf_error("'bcc' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 2, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_OAMF4SC: + /* Get all cells in Segment OAM F4 circuit*/ + if (!is_atm) + bpf_error("'oam4sc' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 3, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_OAMF4EC: + /* Get all cells in End-to-End OAM F4 Circuit*/ + if (!is_atm) + bpf_error("'oam4ec' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 4, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_SC: + /* Get all packets in connection Signalling Circuit */ + if (!is_atm) + bpf_error("'sc' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 5, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_ILMIC: + /* Get all packets in ILMI Circuit */ + if (!is_atm) + bpf_error("'ilmic' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 16, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_LANE: + /* Get all LANE packets */ + if (!is_atm) + bpf_error("'lane' supported only on raw ATM"); + b1 = gen_atmfield_code(A_PROTOTYPE, PT_LANE, BPF_JEQ, 0); + + /* + * Arrange that all subsequent tests assume LANE + * rather than LLC-encapsulated packets, and set + * the offsets appropriately for LANE-encapsulated + * Ethernet. + * + * We assume LANE means Ethernet, not Token Ring. + */ + PUSH_LINKHDR(DLT_EN10MB, 0, + off_payload + 2, /* Ethernet header */ + -1); + off_linktype.constant_part = off_linkhdr.constant_part + 12; + off_linkpl.constant_part = off_linkhdr.constant_part + 14; /* Ethernet */ + off_nl = 0; /* Ethernet II */ + off_nl_nosnap = 3; /* 802.3+802.2 */ + break; + + case A_LLC: + /* Get all LLC-encapsulated packets */ + if (!is_atm) + bpf_error("'llc' supported only on raw ATM"); + b1 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); + linktype = prevlinktype; + break; + + default: + abort(); + } + return b1; +} + +/* + * Filtering for MTP2 messages based on li value + * FISU, length is null + * LSSU, length is 1 or 2 + * MSU, length is 3 or more + * For MTP2_HSL, sequences are on 2 bytes, and length on 9 bits + */ +struct block * +gen_mtp2type_abbrev(type) + int type; +{ + struct block *b0, *b1; + + switch (type) { + + case M_FISU: + if ( (linktype != DLT_MTP2) && + (linktype != DLT_ERF) && + (linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error("'fisu' supported only on MTP2"); + /* gen_ncmp(offrel, offset, size, mask, jtype, reverse, value) */ + b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JEQ, 0, 0); + break; + + case M_LSSU: + if ( (linktype != DLT_MTP2) && + (linktype != DLT_ERF) && + (linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error("'lssu' supported only on MTP2"); + b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 1, 2); + b1 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 0, 0); + gen_and(b1, b0); + break; + + case M_MSU: + if ( (linktype != DLT_MTP2) && + (linktype != DLT_ERF) && + (linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error("'msu' supported only on MTP2"); + b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 0, 2); + break; + + case MH_FISU: + if ( (linktype != DLT_MTP2) && + (linktype != DLT_ERF) && + (linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error("'hfisu' supported only on MTP2_HSL"); + /* gen_ncmp(offrel, offset, size, mask, jtype, reverse, value) */ + b0 = gen_ncmp(OR_PACKET, off_li_hsl, BPF_H, 0xff80, BPF_JEQ, 0, 0); + break; + + case MH_LSSU: + if ( (linktype != DLT_MTP2) && + (linktype != DLT_ERF) && + (linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error("'hlssu' supported only on MTP2_HSL"); + b0 = gen_ncmp(OR_PACKET, off_li_hsl, BPF_H, 0xff80, BPF_JGT, 1, 0x0100); + b1 = gen_ncmp(OR_PACKET, off_li_hsl, BPF_H, 0xff80, BPF_JGT, 0, 0); + gen_and(b1, b0); + break; + + case MH_MSU: + if ( (linktype != DLT_MTP2) && + (linktype != DLT_ERF) && + (linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error("'hmsu' supported only on MTP2_HSL"); + b0 = gen_ncmp(OR_PACKET, off_li_hsl, BPF_H, 0xff80, BPF_JGT, 0, 0x0100); + break; + + default: + abort(); + } + return b0; +} + +struct block * +gen_mtp3field_code(mtp3field, jvalue, jtype, reverse) + int mtp3field; + bpf_u_int32 jvalue; + bpf_u_int32 jtype; + int reverse; +{ + struct block *b0; + bpf_u_int32 val1 , val2 , val3; + u_int newoff_sio=off_sio; + u_int newoff_opc=off_opc; + u_int newoff_dpc=off_dpc; + u_int newoff_sls=off_sls; + + switch (mtp3field) { + + case MH_SIO: + newoff_sio += 3; /* offset for MTP2_HSL */ + /* FALLTHROUGH */ + + case M_SIO: + if (off_sio == (u_int)-1) + bpf_error("'sio' supported only on SS7"); + /* sio coded on 1 byte so max value 255 */ + if(jvalue > 255) + bpf_error("sio value %u too big; max value = 255", + jvalue); + b0 = gen_ncmp(OR_PACKET, newoff_sio, BPF_B, 0xffffffff, + (u_int)jtype, reverse, (u_int)jvalue); + break; + + case MH_OPC: + newoff_opc+=3; + case M_OPC: + if (off_opc == (u_int)-1) + bpf_error("'opc' supported only on SS7"); + /* opc coded on 14 bits so max value 16383 */ + if (jvalue > 16383) + bpf_error("opc value %u too big; max value = 16383", + jvalue); + /* the following instructions are made to convert jvalue + * to the form used to write opc in an ss7 message*/ + val1 = jvalue & 0x00003c00; + val1 = val1 >>10; + val2 = jvalue & 0x000003fc; + val2 = val2 <<6; + val3 = jvalue & 0x00000003; + val3 = val3 <<22; + jvalue = val1 + val2 + val3; + b0 = gen_ncmp(OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0f, + (u_int)jtype, reverse, (u_int)jvalue); + break; + + case MH_DPC: + newoff_dpc += 3; + /* FALLTHROUGH */ + + case M_DPC: + if (off_dpc == (u_int)-1) + bpf_error("'dpc' supported only on SS7"); + /* dpc coded on 14 bits so max value 16383 */ + if (jvalue > 16383) + bpf_error("dpc value %u too big; max value = 16383", + jvalue); + /* the following instructions are made to convert jvalue + * to the forme used to write dpc in an ss7 message*/ + val1 = jvalue & 0x000000ff; + val1 = val1 << 24; + val2 = jvalue & 0x00003f00; + val2 = val2 << 8; + jvalue = val1 + val2; + b0 = gen_ncmp(OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000, + (u_int)jtype, reverse, (u_int)jvalue); + break; + + case MH_SLS: + newoff_sls+=3; + case M_SLS: + if (off_sls == (u_int)-1) + bpf_error("'sls' supported only on SS7"); + /* sls coded on 4 bits so max value 15 */ + if (jvalue > 15) + bpf_error("sls value %u too big; max value = 15", + jvalue); + /* the following instruction is made to convert jvalue + * to the forme used to write sls in an ss7 message*/ + jvalue = jvalue << 4; + b0 = gen_ncmp(OR_PACKET, newoff_sls, BPF_B, 0xf0, + (u_int)jtype,reverse, (u_int)jvalue); + break; + + default: + abort(); + } + return b0; +} + +static struct block * +gen_msg_abbrev(type) + int type; +{ + struct block *b1; + + /* + * Q.2931 signalling protocol messages for handling virtual circuits + * establishment and teardown + */ + switch (type) { + + case A_SETUP: + b1 = gen_atmfield_code(A_MSGTYPE, SETUP, BPF_JEQ, 0); + break; + + case A_CALLPROCEED: + b1 = gen_atmfield_code(A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0); + break; + + case A_CONNECT: + b1 = gen_atmfield_code(A_MSGTYPE, CONNECT, BPF_JEQ, 0); + break; + + case A_CONNECTACK: + b1 = gen_atmfield_code(A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0); + break; + + case A_RELEASE: + b1 = gen_atmfield_code(A_MSGTYPE, RELEASE, BPF_JEQ, 0); + break; + + case A_RELEASE_DONE: + b1 = gen_atmfield_code(A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0); + break; + + default: + abort(); + } + return b1; +} + +struct block * +gen_atmmulti_abbrev(type) + int type; +{ + struct block *b0, *b1; + + switch (type) { + + case A_OAM: + if (!is_atm) + bpf_error("'oam' supported only on raw ATM"); + b1 = gen_atmmulti_abbrev(A_OAMF4); + break; + + case A_OAMF4: + if (!is_atm) + bpf_error("'oamf4' supported only on raw ATM"); + /* OAM F4 type */ + b0 = gen_atmfield_code(A_VCI, 3, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 4, BPF_JEQ, 0); + gen_or(b0, b1); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_CONNECTMSG: + /* + * Get Q.2931 signalling messages for switched + * virtual connection + */ + if (!is_atm) + bpf_error("'connectmsg' supported only on raw ATM"); + b0 = gen_msg_abbrev(A_SETUP); + b1 = gen_msg_abbrev(A_CALLPROCEED); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_CONNECT); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_CONNECTACK); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_RELEASE); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_RELEASE_DONE); + gen_or(b0, b1); + b0 = gen_atmtype_abbrev(A_SC); + gen_and(b0, b1); + break; + + case A_METACONNECT: + if (!is_atm) + bpf_error("'metaconnect' supported only on raw ATM"); + b0 = gen_msg_abbrev(A_SETUP); + b1 = gen_msg_abbrev(A_CALLPROCEED); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_CONNECT); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_RELEASE); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_RELEASE_DONE); + gen_or(b0, b1); + b0 = gen_atmtype_abbrev(A_METAC); + gen_and(b0, b1); + break; + + default: + abort(); + } + return b1; +} diff --git a/tcpdump/jni/libpcap/gencode.h b/tcpdump/jni/libpcap/gencode.h new file mode 100644 index 0000000..67ed0dc --- /dev/null +++ b/tcpdump/jni/libpcap/gencode.h @@ -0,0 +1,365 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ATM support: + * + * Copyright (c) 1997 Yen Yen Lim and North Dakota State University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Yen Yen Lim and + * North Dakota State University + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAVE___ATTRIBUTE__ +#define __attribute__(x) +#endif /* HAVE___ATTRIBUTE__ */ + +/* Address qualifiers. */ + +#define Q_HOST 1 +#define Q_NET 2 +#define Q_PORT 3 +#define Q_GATEWAY 4 +#define Q_PROTO 5 +#define Q_PROTOCHAIN 6 +#define Q_PORTRANGE 7 + +/* Protocol qualifiers. */ + +#define Q_LINK 1 +#define Q_IP 2 +#define Q_ARP 3 +#define Q_RARP 4 +#define Q_SCTP 5 +#define Q_TCP 6 +#define Q_UDP 7 +#define Q_ICMP 8 +#define Q_IGMP 9 +#define Q_IGRP 10 + + +#define Q_ATALK 11 +#define Q_DECNET 12 +#define Q_LAT 13 +#define Q_SCA 14 +#define Q_MOPRC 15 +#define Q_MOPDL 16 + + +#define Q_IPV6 17 +#define Q_ICMPV6 18 +#define Q_AH 19 +#define Q_ESP 20 + +#define Q_PIM 21 +#define Q_VRRP 22 + +#define Q_AARP 23 + +#define Q_ISO 24 +#define Q_ESIS 25 +#define Q_ISIS 26 +#define Q_CLNP 27 + +#define Q_STP 28 + +#define Q_IPX 29 + +#define Q_NETBEUI 30 + +/* IS-IS Levels */ +#define Q_ISIS_L1 31 +#define Q_ISIS_L2 32 +/* PDU types */ +#define Q_ISIS_IIH 33 +#define Q_ISIS_LAN_IIH 34 +#define Q_ISIS_PTP_IIH 35 +#define Q_ISIS_SNP 36 +#define Q_ISIS_CSNP 37 +#define Q_ISIS_PSNP 38 +#define Q_ISIS_LSP 39 + +#define Q_RADIO 40 + +#define Q_CARP 41 + +/* Directional qualifiers. */ + +#define Q_SRC 1 +#define Q_DST 2 +#define Q_OR 3 +#define Q_AND 4 +#define Q_ADDR1 5 +#define Q_ADDR2 6 +#define Q_ADDR3 7 +#define Q_ADDR4 8 +#define Q_RA 9 +#define Q_TA 10 + +#define Q_DEFAULT 0 +#define Q_UNDEF 255 + +/* ATM types */ +#define A_METAC 22 /* Meta signalling Circuit */ +#define A_BCC 23 /* Broadcast Circuit */ +#define A_OAMF4SC 24 /* Segment OAM F4 Circuit */ +#define A_OAMF4EC 25 /* End-to-End OAM F4 Circuit */ +#define A_SC 26 /* Signalling Circuit*/ +#define A_ILMIC 27 /* ILMI Circuit */ +#define A_OAM 28 /* OAM cells : F4 only */ +#define A_OAMF4 29 /* OAM F4 cells: Segment + End-to-end */ +#define A_LANE 30 /* LANE traffic */ +#define A_LLC 31 /* LLC-encapsulated traffic */ + +/* Based on Q.2931 signalling protocol */ +#define A_SETUP 41 /* Setup message */ +#define A_CALLPROCEED 42 /* Call proceeding message */ +#define A_CONNECT 43 /* Connect message */ +#define A_CONNECTACK 44 /* Connect Ack message */ +#define A_RELEASE 45 /* Release message */ +#define A_RELEASE_DONE 46 /* Release message */ + +/* ATM field types */ +#define A_VPI 51 +#define A_VCI 52 +#define A_PROTOTYPE 53 +#define A_MSGTYPE 54 +#define A_CALLREFTYPE 55 + +#define A_CONNECTMSG 70 /* returns Q.2931 signalling messages for + establishing and destroying switched + virtual connection */ +#define A_METACONNECT 71 /* returns Q.2931 signalling messages for + establishing and destroying predefined + virtual circuits, such as broadcast + circuit, oamf4 segment circuit, oamf4 + end-to-end circuits, ILMI circuits or + connection signalling circuit. */ + +/* MTP2 types */ +#define M_FISU 22 /* FISU */ +#define M_LSSU 23 /* LSSU */ +#define M_MSU 24 /* MSU */ + +/* MTP2 HSL types */ +#define MH_FISU 25 /* FISU for HSL */ +#define MH_LSSU 26 /* LSSU */ +#define MH_MSU 27 /* MSU */ + +/* MTP3 field types */ +#define M_SIO 1 +#define M_OPC 2 +#define M_DPC 3 +#define M_SLS 4 + +/* MTP3 field types in case of MTP2 HSL */ +#define MH_SIO 5 +#define MH_OPC 6 +#define MH_DPC 7 +#define MH_SLS 8 + + +struct slist; + +struct stmt { + int code; + struct slist *jt; /*only for relative jump in block*/ + struct slist *jf; /*only for relative jump in block*/ + bpf_int32 k; +}; + +struct slist { + struct stmt s; + struct slist *next; +}; + +/* + * A bit vector to represent definition sets. We assume TOT_REGISTERS + * is smaller than 8*sizeof(atomset). + */ +typedef bpf_u_int32 atomset; +#define ATOMMASK(n) (1 << (n)) +#define ATOMELEM(d, n) (d & ATOMMASK(n)) + +/* + * An unbounded set. + */ +typedef bpf_u_int32 *uset; + +/* + * Total number of atomic entities, including accumulator (A) and index (X). + * We treat all these guys similarly during flow analysis. + */ +#define N_ATOMS (BPF_MEMWORDS+2) + +struct edge { + int id; + int code; + uset edom; + struct block *succ; + struct block *pred; + struct edge *next; /* link list of incoming edges for a node */ +}; + +struct block { + int id; + struct slist *stmts; /* side effect stmts */ + struct stmt s; /* branch stmt */ + int mark; + u_int longjt; /* jt branch requires long jump */ + u_int longjf; /* jf branch requires long jump */ + int level; + int offset; + int sense; + struct edge et; + struct edge ef; + struct block *head; + struct block *link; /* link field used by optimizer */ + uset dom; + uset closure; + struct edge *in_edges; + atomset def, kill; + atomset in_use; + atomset out_use; + int oval; + int val[N_ATOMS]; +}; + +struct arth { + struct block *b; /* protocol checks */ + struct slist *s; /* stmt list */ + int regno; /* virtual register number of result */ +}; + +struct qual { + unsigned char addr; + unsigned char proto; + unsigned char dir; + unsigned char pad; +}; + +struct arth *gen_loadi(int); +struct arth *gen_load(int, struct arth *, int); +struct arth *gen_loadlen(void); +struct arth *gen_neg(struct arth *); +struct arth *gen_arth(int, struct arth *, struct arth *); + +void gen_and(struct block *, struct block *); +void gen_or(struct block *, struct block *); +void gen_not(struct block *); + +struct block *gen_scode(const char *, struct qual); +struct block *gen_ecode(const u_char *, struct qual); +struct block *gen_acode(const u_char *, struct qual); +struct block *gen_mcode(const char *, const char *, unsigned int, struct qual); +#ifdef INET6 +struct block *gen_mcode6(const char *, const char *, unsigned int, struct qual); +#endif +struct block *gen_ncode(const char *, bpf_u_int32, struct qual); +struct block *gen_proto_abbrev(int); +struct block *gen_relation(int, struct arth *, struct arth *, int); +struct block *gen_less(int); +struct block *gen_greater(int); +struct block *gen_byteop(int, int, int); +struct block *gen_broadcast(int); +struct block *gen_multicast(int); +struct block *gen_inbound(int); + +struct block *gen_llc(void); +struct block *gen_llc_i(void); +struct block *gen_llc_s(void); +struct block *gen_llc_u(void); +struct block *gen_llc_s_subtype(bpf_u_int32); +struct block *gen_llc_u_subtype(bpf_u_int32); + +struct block *gen_vlan(int); +struct block *gen_mpls(int); + +struct block *gen_pppoed(void); +struct block *gen_pppoes(int); + +struct block *gen_geneve(int); + +struct block *gen_atmfield_code(int atmfield, bpf_int32 jvalue, bpf_u_int32 jtype, int reverse); +struct block *gen_atmtype_abbrev(int type); +struct block *gen_atmmulti_abbrev(int type); + +struct block *gen_mtp2type_abbrev(int type); +struct block *gen_mtp3field_code(int mtp3field, bpf_u_int32 jvalue, bpf_u_int32 jtype, int reverse); + +struct block *gen_pf_ifname(const char *); +struct block *gen_pf_rnr(int); +struct block *gen_pf_srnr(int); +struct block *gen_pf_ruleset(char *); +struct block *gen_pf_reason(int); +struct block *gen_pf_action(int); +struct block *gen_pf_dir(int); + +struct block *gen_p80211_type(int, int); +struct block *gen_p80211_fcdir(int); + +void bpf_optimize(struct block **); +void bpf_error(const char *, ...) + __attribute__((noreturn)) +#ifdef __ATTRIBUTE___FORMAT_OK + __attribute__((format (printf, 1, 2))) +#endif /* __ATTRIBUTE___FORMAT_OK */ + ; + +void finish_parse(struct block *); +char *sdup(const char *); + +struct bpf_insn *icode_to_fcode(struct block *, u_int *); +int pcap_parse(void); +void lex_init(const char *); +void lex_cleanup(void); +void sappend(struct slist *, struct slist *); + +/* XXX */ +#define JT(b) ((b)->et.succ) +#define JF(b) ((b)->ef.succ) + +extern int no_optimize; diff --git a/tcpdump/jni/libpcap/grammar.c b/tcpdump/jni/libpcap/grammar.c new file mode 100644 index 0000000..ea3169c --- /dev/null +++ b/tcpdump/jni/libpcap/grammar.c @@ -0,0 +1,3976 @@ +/* A Bison parser, made by GNU Bison 2.5. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.5" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse pcap_parse +#define yylex pcap_lex +#define yyerror pcap_error +#define yylval pcap_lval +#define yychar pcap_char +#define yydebug pcap_debug +#define yynerrs pcap_nerrs + + +/* Copy the first part of user declarations. */ + +/* Line 268 of yacc.c */ +#line 1 "grammar.y" + +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ +#ifndef lint +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/libpcap/grammar.y,v 1.101 2007-11-18 02:03:52 guy Exp $ (LBL)"; +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#include +#include +#endif /* WIN32 */ + +#include + +#ifndef WIN32 +#if __STDC__ +struct mbuf; +struct rtentry; +#endif + +#include +#include +#endif /* WIN32 */ + +#include + +#include "pcap-int.h" + +#include "gencode.h" +#ifdef HAVE_NET_PFVAR_H +#include +#include +#include +#endif +#include "ieee80211.h" +#include + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#define QSET(q, p, d, a) (q).proto = (p),\ + (q).dir = (d),\ + (q).addr = (a) + +struct tok { + int v; /* value */ + const char *s; /* string */ +}; + +static const struct tok ieee80211_types[] = { + { IEEE80211_FC0_TYPE_DATA, "data" }, + { IEEE80211_FC0_TYPE_MGT, "mgt" }, + { IEEE80211_FC0_TYPE_MGT, "management" }, + { IEEE80211_FC0_TYPE_CTL, "ctl" }, + { IEEE80211_FC0_TYPE_CTL, "control" }, + { 0, NULL } +}; +static const struct tok ieee80211_mgt_subtypes[] = { + { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assocreq" }, + { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assoc-req" }, + { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assocresp" }, + { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assoc-resp" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassocreq" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassoc-req" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassocresp" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassoc-resp" }, + { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probereq" }, + { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probe-req" }, + { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "proberesp" }, + { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "probe-resp" }, + { IEEE80211_FC0_SUBTYPE_BEACON, "beacon" }, + { IEEE80211_FC0_SUBTYPE_ATIM, "atim" }, + { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassoc" }, + { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassociation" }, + { IEEE80211_FC0_SUBTYPE_AUTH, "auth" }, + { IEEE80211_FC0_SUBTYPE_AUTH, "authentication" }, + { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauth" }, + { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauthentication" }, + { 0, NULL } +}; +static const struct tok ieee80211_ctl_subtypes[] = { + { IEEE80211_FC0_SUBTYPE_PS_POLL, "ps-poll" }, + { IEEE80211_FC0_SUBTYPE_RTS, "rts" }, + { IEEE80211_FC0_SUBTYPE_CTS, "cts" }, + { IEEE80211_FC0_SUBTYPE_ACK, "ack" }, + { IEEE80211_FC0_SUBTYPE_CF_END, "cf-end" }, + { IEEE80211_FC0_SUBTYPE_CF_END_ACK, "cf-end-ack" }, + { 0, NULL } +}; +static const struct tok ieee80211_data_subtypes[] = { + { IEEE80211_FC0_SUBTYPE_DATA, "data" }, + { IEEE80211_FC0_SUBTYPE_CF_ACK, "data-cf-ack" }, + { IEEE80211_FC0_SUBTYPE_CF_POLL, "data-cf-poll" }, + { IEEE80211_FC0_SUBTYPE_CF_ACPL, "data-cf-ack-poll" }, + { IEEE80211_FC0_SUBTYPE_NODATA, "null" }, + { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK, "cf-ack" }, + { IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "cf-poll" }, + { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "cf-ack-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_DATA, "qos-data" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACK, "qos-data-cf-ack" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_POLL, "qos-data-cf-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACPL, "qos-data-cf-ack-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA, "qos" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "qos-cf-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "qos-cf-ack-poll" }, + { 0, NULL } +}; +struct type2tok { + int type; + const struct tok *tok; +}; +static const struct type2tok ieee80211_type_subtypes[] = { + { IEEE80211_FC0_TYPE_MGT, ieee80211_mgt_subtypes }, + { IEEE80211_FC0_TYPE_CTL, ieee80211_ctl_subtypes }, + { IEEE80211_FC0_TYPE_DATA, ieee80211_data_subtypes }, + { 0, NULL } +}; + +static int +str2tok(const char *str, const struct tok *toks) +{ + int i; + + for (i = 0; toks[i].s != NULL; i++) { + if (pcap_strcasecmp(toks[i].s, str) == 0) + return (toks[i].v); + } + return (-1); +} + +int n_errors = 0; + +static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF }; + +static void +yyerror(const char *msg) +{ + ++n_errors; + bpf_error("%s", msg); + /* NOTREACHED */ +} + +#ifdef NEED_YYPARSE_WRAPPER +int yyparse(void); + +int +pcap_parse() +{ + return (yyparse()); +} +#endif + +#ifdef HAVE_NET_PFVAR_H +static int +pfreason_to_num(const char *reason) +{ + const char *reasons[] = PFRES_NAMES; + int i; + + for (i = 0; reasons[i]; i++) { + if (pcap_strcasecmp(reason, reasons[i]) == 0) + return (i); + } + bpf_error("unknown PF reason"); + /*NOTREACHED*/ +} + +static int +pfaction_to_num(const char *action) +{ + if (pcap_strcasecmp(action, "pass") == 0 || + pcap_strcasecmp(action, "accept") == 0) + return (PF_PASS); + else if (pcap_strcasecmp(action, "drop") == 0 || + pcap_strcasecmp(action, "block") == 0) + return (PF_DROP); +#if HAVE_PF_NAT_THROUGH_PF_NORDR + else if (pcap_strcasecmp(action, "rdr") == 0) + return (PF_RDR); + else if (pcap_strcasecmp(action, "nat") == 0) + return (PF_NAT); + else if (pcap_strcasecmp(action, "binat") == 0) + return (PF_BINAT); + else if (pcap_strcasecmp(action, "nordr") == 0) + return (PF_NORDR); +#endif + else { + bpf_error("unknown PF action"); + /*NOTREACHED*/ + } +} +#else /* !HAVE_NET_PFVAR_H */ +static int +pfreason_to_num(const char *reason) +{ + bpf_error("libpcap was compiled on a machine without pf support"); + /*NOTREACHED*/ + + /* this is to make the VC compiler happy */ + return -1; +} + +static int +pfaction_to_num(const char *action) +{ + bpf_error("libpcap was compiled on a machine without pf support"); + /*NOTREACHED*/ + + /* this is to make the VC compiler happy */ + return -1; +} +#endif /* HAVE_NET_PFVAR_H */ + + +/* Line 268 of yacc.c */ +#line 321 "y.tab.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + DST = 258, + SRC = 259, + HOST = 260, + GATEWAY = 261, + NET = 262, + NETMASK = 263, + PORT = 264, + PORTRANGE = 265, + LESS = 266, + GREATER = 267, + PROTO = 268, + PROTOCHAIN = 269, + CBYTE = 270, + ARP = 271, + RARP = 272, + IP = 273, + SCTP = 274, + TCP = 275, + UDP = 276, + ICMP = 277, + IGMP = 278, + IGRP = 279, + PIM = 280, + VRRP = 281, + CARP = 282, + ATALK = 283, + AARP = 284, + DECNET = 285, + LAT = 286, + SCA = 287, + MOPRC = 288, + MOPDL = 289, + TK_BROADCAST = 290, + TK_MULTICAST = 291, + NUM = 292, + INBOUND = 293, + OUTBOUND = 294, + PF_IFNAME = 295, + PF_RSET = 296, + PF_RNR = 297, + PF_SRNR = 298, + PF_REASON = 299, + PF_ACTION = 300, + TYPE = 301, + SUBTYPE = 302, + DIR = 303, + ADDR1 = 304, + ADDR2 = 305, + ADDR3 = 306, + ADDR4 = 307, + RA = 308, + TA = 309, + LINK = 310, + GEQ = 311, + LEQ = 312, + NEQ = 313, + ID = 314, + EID = 315, + HID = 316, + HID6 = 317, + AID = 318, + LSH = 319, + RSH = 320, + LEN = 321, + IPV6 = 322, + ICMPV6 = 323, + AH = 324, + ESP = 325, + VLAN = 326, + MPLS = 327, + PPPOED = 328, + PPPOES = 329, + ISO = 330, + ESIS = 331, + CLNP = 332, + ISIS = 333, + L1 = 334, + L2 = 335, + IIH = 336, + LSP = 337, + SNP = 338, + CSNP = 339, + PSNP = 340, + STP = 341, + IPX = 342, + NETBEUI = 343, + LANE = 344, + LLC = 345, + METAC = 346, + BCC = 347, + SC = 348, + ILMIC = 349, + OAMF4EC = 350, + OAMF4SC = 351, + OAM = 352, + OAMF4 = 353, + CONNECTMSG = 354, + METACONNECT = 355, + VPI = 356, + VCI = 357, + RADIO = 358, + FISU = 359, + LSSU = 360, + MSU = 361, + HFISU = 362, + HLSSU = 363, + HMSU = 364, + SIO = 365, + OPC = 366, + DPC = 367, + SLS = 368, + HSIO = 369, + HOPC = 370, + HDPC = 371, + HSLS = 372, + AND = 373, + OR = 374, + UMINUS = 375 + }; +#endif +/* Tokens. */ +#define DST 258 +#define SRC 259 +#define HOST 260 +#define GATEWAY 261 +#define NET 262 +#define NETMASK 263 +#define PORT 264 +#define PORTRANGE 265 +#define LESS 266 +#define GREATER 267 +#define PROTO 268 +#define PROTOCHAIN 269 +#define CBYTE 270 +#define ARP 271 +#define RARP 272 +#define IP 273 +#define SCTP 274 +#define TCP 275 +#define UDP 276 +#define ICMP 277 +#define IGMP 278 +#define IGRP 279 +#define PIM 280 +#define VRRP 281 +#define CARP 282 +#define ATALK 283 +#define AARP 284 +#define DECNET 285 +#define LAT 286 +#define SCA 287 +#define MOPRC 288 +#define MOPDL 289 +#define TK_BROADCAST 290 +#define TK_MULTICAST 291 +#define NUM 292 +#define INBOUND 293 +#define OUTBOUND 294 +#define PF_IFNAME 295 +#define PF_RSET 296 +#define PF_RNR 297 +#define PF_SRNR 298 +#define PF_REASON 299 +#define PF_ACTION 300 +#define TYPE 301 +#define SUBTYPE 302 +#define DIR 303 +#define ADDR1 304 +#define ADDR2 305 +#define ADDR3 306 +#define ADDR4 307 +#define RA 308 +#define TA 309 +#define LINK 310 +#define GEQ 311 +#define LEQ 312 +#define NEQ 313 +#define ID 314 +#define EID 315 +#define HID 316 +#define HID6 317 +#define AID 318 +#define LSH 319 +#define RSH 320 +#define LEN 321 +#define IPV6 322 +#define ICMPV6 323 +#define AH 324 +#define ESP 325 +#define VLAN 326 +#define MPLS 327 +#define PPPOED 328 +#define PPPOES 329 +#define ISO 330 +#define ESIS 331 +#define CLNP 332 +#define ISIS 333 +#define L1 334 +#define L2 335 +#define IIH 336 +#define LSP 337 +#define SNP 338 +#define CSNP 339 +#define PSNP 340 +#define STP 341 +#define IPX 342 +#define NETBEUI 343 +#define LANE 344 +#define LLC 345 +#define METAC 346 +#define BCC 347 +#define SC 348 +#define ILMIC 349 +#define OAMF4EC 350 +#define OAMF4SC 351 +#define OAM 352 +#define OAMF4 353 +#define CONNECTMSG 354 +#define METACONNECT 355 +#define VPI 356 +#define VCI 357 +#define RADIO 358 +#define FISU 359 +#define LSSU 360 +#define MSU 361 +#define HFISU 362 +#define HLSSU 363 +#define HMSU 364 +#define SIO 365 +#define OPC 366 +#define DPC 367 +#define SLS 368 +#define HSIO 369 +#define HOPC 370 +#define HDPC 371 +#define HSLS 372 +#define AND 373 +#define OR 374 +#define UMINUS 375 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 293 of yacc.c */ +#line 242 "grammar.y" + + int i; + bpf_u_int32 h; + u_char *e; + char *s; + struct stmt *stmt; + struct arth *a; + struct { + struct qual q; + int atmfieldtype; + int mtp3fieldtype; + struct block *b; + } blk; + struct block *rblk; + + + +/* Line 293 of yacc.c */ +#line 615 "y.tab.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 343 of yacc.c */ +#line 627 "y.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 3 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 710 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 136 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 46 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 213 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 285 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 375 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 120, 2, 2, 2, 2, 122, 2, + 129, 128, 125, 123, 2, 124, 2, 126, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 135, 2, + 132, 131, 130, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 133, 2, 134, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 121, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 127 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 6, 8, 9, 11, 15, 19, 23, + 27, 29, 31, 33, 35, 39, 41, 45, 49, 51, + 55, 57, 59, 61, 64, 66, 68, 70, 74, 78, + 80, 82, 84, 87, 91, 94, 97, 100, 103, 106, + 109, 113, 115, 119, 123, 125, 127, 129, 132, 134, + 137, 139, 140, 142, 144, 148, 152, 156, 160, 162, + 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, + 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, + 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, + 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, + 244, 246, 248, 250, 252, 254, 256, 258, 260, 263, + 266, 269, 272, 277, 279, 281, 284, 286, 289, 291, + 293, 296, 298, 300, 303, 306, 309, 312, 315, 318, + 321, 326, 329, 332, 335, 337, 339, 341, 343, 345, + 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, + 367, 369, 371, 376, 383, 387, 391, 395, 399, 403, + 407, 411, 415, 418, 422, 424, 426, 428, 430, 432, + 434, 436, 440, 442, 444, 446, 448, 450, 452, 454, + 456, 458, 460, 462, 464, 466, 468, 470, 473, 476, + 480, 482, 484, 488, 490, 492, 494, 496, 498, 500, + 502, 504, 506, 508, 510, 512, 514, 516, 518, 521, + 524, 528, 530, 532 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 137, 0, -1, 138, 139, -1, 138, -1, -1, 148, + -1, 139, 140, 148, -1, 139, 140, 142, -1, 139, + 141, 148, -1, 139, 141, 142, -1, 118, -1, 119, + -1, 143, -1, 170, -1, 145, 146, 128, -1, 59, + -1, 61, 126, 37, -1, 61, 8, 61, -1, 61, + -1, 62, 126, 37, -1, 62, -1, 60, -1, 63, + -1, 144, 142, -1, 120, -1, 129, -1, 143, -1, + 147, 140, 142, -1, 147, 141, 142, -1, 170, -1, + 146, -1, 150, -1, 144, 148, -1, 151, 152, 153, + -1, 151, 152, -1, 151, 153, -1, 151, 13, -1, + 151, 14, -1, 151, 154, -1, 149, 142, -1, 145, + 139, 128, -1, 155, -1, 167, 165, 167, -1, 167, + 166, 167, -1, 156, -1, 171, -1, 172, -1, 173, + 174, -1, 177, -1, 178, 179, -1, 155, -1, -1, + 4, -1, 3, -1, 4, 119, 3, -1, 3, 119, + 4, -1, 4, 118, 3, -1, 3, 118, 4, -1, + 49, -1, 50, -1, 51, -1, 52, -1, 53, -1, + 54, -1, 5, -1, 7, -1, 9, -1, 10, -1, + 6, -1, 55, -1, 18, -1, 16, -1, 17, -1, + 19, -1, 20, -1, 21, -1, 22, -1, 23, -1, + 24, -1, 25, -1, 26, -1, 27, -1, 28, -1, + 29, -1, 30, -1, 31, -1, 32, -1, 34, -1, + 33, -1, 67, -1, 68, -1, 69, -1, 70, -1, + 75, -1, 76, -1, 78, -1, 79, -1, 80, -1, + 81, -1, 82, -1, 83, -1, 85, -1, 84, -1, + 77, -1, 86, -1, 87, -1, 88, -1, 103, -1, + 151, 35, -1, 151, 36, -1, 11, 37, -1, 12, + 37, -1, 15, 37, 169, 37, -1, 38, -1, 39, + -1, 71, 170, -1, 71, -1, 72, 170, -1, 72, + -1, 73, -1, 74, 170, -1, 74, -1, 157, -1, + 151, 158, -1, 40, 59, -1, 41, 59, -1, 42, + 37, -1, 43, 37, -1, 44, 163, -1, 45, 164, + -1, 46, 159, 47, 160, -1, 46, 159, -1, 47, + 161, -1, 48, 162, -1, 37, -1, 59, -1, 37, + -1, 59, -1, 59, -1, 37, -1, 59, -1, 37, + -1, 59, -1, 59, -1, 130, -1, 56, -1, 131, + -1, 57, -1, 132, -1, 58, -1, 170, -1, 168, + -1, 155, 133, 167, 134, -1, 155, 133, 167, 135, + 37, 134, -1, 167, 123, 167, -1, 167, 124, 167, + -1, 167, 125, 167, -1, 167, 126, 167, -1, 167, + 122, 167, -1, 167, 121, 167, -1, 167, 64, 167, + -1, 167, 65, 167, -1, 124, 167, -1, 145, 168, + 128, -1, 66, -1, 122, -1, 121, -1, 132, -1, + 130, -1, 131, -1, 37, -1, 145, 170, 128, -1, + 89, -1, 90, -1, 91, -1, 92, -1, 95, -1, + 96, -1, 93, -1, 94, -1, 97, -1, 98, -1, + 99, -1, 100, -1, 101, -1, 102, -1, 175, -1, + 165, 37, -1, 166, 37, -1, 145, 176, 128, -1, + 37, -1, 175, -1, 176, 141, 175, -1, 104, -1, + 105, -1, 106, -1, 107, -1, 108, -1, 109, -1, + 110, -1, 111, -1, 112, -1, 113, -1, 114, -1, + 115, -1, 116, -1, 117, -1, 180, -1, 165, 37, + -1, 166, 37, -1, 145, 181, 128, -1, 37, -1, + 180, -1, 181, 141, 180, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 316, 316, 320, 322, 324, 325, 326, 327, 328, + 330, 332, 334, 335, 337, 339, 340, 342, 344, 357, + 366, 375, 384, 393, 395, 397, 399, 400, 401, 403, + 405, 407, 408, 410, 411, 412, 413, 414, 415, 417, + 418, 419, 420, 422, 424, 425, 426, 427, 428, 429, + 432, 433, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 450, 451, 452, 453, 456, 458, + 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, + 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, + 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 498, 499, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, + 510, 511, 512, 513, 516, 517, 518, 519, 520, 521, + 524, 529, 532, 536, 539, 540, 546, 547, 567, 583, + 584, 597, 598, 601, 604, 605, 606, 608, 609, 610, + 612, 613, 615, 616, 617, 618, 619, 620, 621, 622, + 623, 624, 625, 626, 627, 629, 630, 631, 632, 633, + 635, 636, 638, 639, 640, 641, 642, 643, 644, 645, + 647, 648, 649, 650, 653, 654, 656, 657, 658, 659, + 661, 668, 669, 672, 673, 674, 675, 676, 677, 680, + 681, 682, 683, 684, 685, 686, 687, 689, 690, 691, + 692, 694, 707, 708 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "DST", "SRC", "HOST", "GATEWAY", "NET", + "NETMASK", "PORT", "PORTRANGE", "LESS", "GREATER", "PROTO", "PROTOCHAIN", + "CBYTE", "ARP", "RARP", "IP", "SCTP", "TCP", "UDP", "ICMP", "IGMP", + "IGRP", "PIM", "VRRP", "CARP", "ATALK", "AARP", "DECNET", "LAT", "SCA", + "MOPRC", "MOPDL", "TK_BROADCAST", "TK_MULTICAST", "NUM", "INBOUND", + "OUTBOUND", "PF_IFNAME", "PF_RSET", "PF_RNR", "PF_SRNR", "PF_REASON", + "PF_ACTION", "TYPE", "SUBTYPE", "DIR", "ADDR1", "ADDR2", "ADDR3", + "ADDR4", "RA", "TA", "LINK", "GEQ", "LEQ", "NEQ", "ID", "EID", "HID", + "HID6", "AID", "LSH", "RSH", "LEN", "IPV6", "ICMPV6", "AH", "ESP", + "VLAN", "MPLS", "PPPOED", "PPPOES", "ISO", "ESIS", "CLNP", "ISIS", "L1", + "L2", "IIH", "LSP", "SNP", "CSNP", "PSNP", "STP", "IPX", "NETBEUI", + "LANE", "LLC", "METAC", "BCC", "SC", "ILMIC", "OAMF4EC", "OAMF4SC", + "OAM", "OAMF4", "CONNECTMSG", "METACONNECT", "VPI", "VCI", "RADIO", + "FISU", "LSSU", "MSU", "HFISU", "HLSSU", "HMSU", "SIO", "OPC", "DPC", + "SLS", "HSIO", "HOPC", "HDPC", "HSLS", "AND", "OR", "'!'", "'|'", "'&'", + "'+'", "'-'", "'*'", "'/'", "UMINUS", "')'", "'('", "'>'", "'='", "'<'", + "'['", "']'", "':'", "$accept", "prog", "null", "expr", "and", "or", + "id", "nid", "not", "paren", "pid", "qid", "term", "head", "rterm", + "pqual", "dqual", "aqual", "ndaqual", "pname", "other", "pfvar", + "p80211", "type", "subtype", "type_subtype", "dir", "reason", "action", + "relop", "irelop", "arth", "narth", "byteop", "pnum", "atmtype", + "atmmultitype", "atmfield", "atmvalue", "atmfieldvalue", "atmlistvalue", + "mtp2type", "mtp3field", "mtp3value", "mtp3fieldvalue", "mtp3listvalue", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 33, 124, 38, 43, 45, 42, 47, 375, 41, 40, + 62, 61, 60, 91, 93, 58 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 136, 137, 137, 138, 139, 139, 139, 139, 139, + 140, 141, 142, 142, 142, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 144, 145, 146, 146, 146, 147, + 147, 148, 148, 149, 149, 149, 149, 149, 149, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 151, 151, 152, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 152, 153, 153, 153, 153, 154, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 157, 157, 157, 157, 157, 157, + 158, 158, 158, 158, 159, 159, 160, 160, 161, 162, + 162, 163, 163, 164, 165, 165, 165, 166, 166, 166, + 167, 167, 168, 168, 168, 168, 168, 168, 168, 168, + 168, 168, 168, 168, 168, 169, 169, 169, 169, 169, + 170, 170, 171, 171, 171, 171, 171, 171, 171, 171, + 172, 172, 172, 172, 173, 173, 174, 174, 174, 174, + 175, 176, 176, 177, 177, 177, 177, 177, 177, 178, + 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, + 179, 180, 181, 181 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 1, 0, 1, 3, 3, 3, 3, + 1, 1, 1, 1, 3, 1, 3, 3, 1, 3, + 1, 1, 1, 2, 1, 1, 1, 3, 3, 1, + 1, 1, 2, 3, 2, 2, 2, 2, 2, 2, + 3, 1, 3, 3, 1, 1, 1, 2, 1, 2, + 1, 0, 1, 1, 3, 3, 3, 3, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 4, 1, 1, 2, 1, 2, 1, 1, + 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4, 6, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 3, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, + 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 3, 1, 1, 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 4, 0, 51, 1, 0, 0, 0, 71, 72, 70, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 88, 87, 170, 113, 114, 0, + 0, 0, 0, 0, 0, 69, 164, 89, 90, 91, + 92, 116, 118, 119, 121, 93, 94, 103, 95, 96, + 97, 98, 99, 100, 102, 101, 104, 105, 106, 172, + 173, 174, 175, 178, 179, 176, 177, 180, 181, 182, + 183, 184, 185, 107, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 24, 0, + 25, 2, 51, 51, 5, 0, 31, 0, 50, 44, + 122, 0, 151, 150, 45, 46, 0, 48, 0, 110, + 111, 0, 124, 125, 126, 127, 141, 142, 128, 143, + 129, 0, 115, 117, 120, 0, 0, 162, 10, 11, + 51, 51, 32, 0, 151, 150, 15, 21, 18, 20, + 22, 39, 12, 0, 0, 13, 53, 52, 64, 68, + 65, 66, 67, 36, 37, 108, 109, 0, 0, 0, + 58, 59, 60, 61, 62, 63, 34, 35, 38, 123, + 0, 145, 147, 149, 0, 0, 0, 0, 0, 0, + 0, 0, 144, 146, 148, 0, 0, 190, 0, 0, + 0, 47, 186, 211, 0, 0, 0, 49, 207, 166, + 165, 168, 169, 167, 0, 0, 0, 7, 51, 51, + 6, 150, 9, 8, 40, 163, 171, 0, 0, 0, + 23, 26, 30, 0, 29, 0, 0, 0, 0, 134, + 135, 131, 138, 132, 139, 140, 133, 33, 0, 160, + 161, 159, 158, 154, 155, 156, 157, 42, 43, 191, + 0, 187, 188, 212, 0, 208, 209, 112, 150, 17, + 16, 19, 14, 0, 0, 57, 55, 56, 54, 0, + 152, 0, 189, 0, 210, 0, 27, 28, 136, 137, + 130, 0, 192, 213, 153 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 2, 133, 130, 131, 220, 142, 143, 125, + 222, 223, 94, 95, 96, 97, 166, 167, 168, 126, + 99, 100, 169, 231, 280, 233, 236, 118, 120, 185, + 186, 101, 102, 204, 103, 104, 105, 106, 191, 192, + 250, 107, 108, 197, 198, 254 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -208 +static const yytype_int16 yypact[] = +{ + -208, 20, 226, -208, -10, -3, 1, -208, -208, -208, + -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, + -208, -208, -208, -208, -208, -208, -208, -208, -208, -28, + -15, 49, 68, -18, 62, -208, -208, -208, -208, -208, + -208, -26, -26, -208, -26, -208, -208, -208, -208, -208, + -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, + -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, + -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, + -208, -208, -208, -208, -208, -208, -208, -208, -208, 570, + -208, -42, 456, 456, -208, 19, -208, 656, 12, -208, + -208, 153, -208, -208, -208, -208, 55, -208, 59, -208, + -208, -69, -208, -208, -208, -208, -208, -208, -208, -208, + -208, -26, -208, -208, -208, 570, -19, -208, -208, -208, + 341, 341, -208, -93, -1, 21, -208, -208, -6, 34, + -208, -208, -208, 19, 19, -208, -9, 6, -208, -208, + -208, -208, -208, -208, -208, -208, -208, -14, 74, -13, + -208, -208, -208, -208, -208, -208, 23, -208, -208, -208, + 570, -208, -208, -208, 570, 570, 570, 570, 570, 570, + 570, 570, -208, -208, -208, 570, 570, -208, 81, 134, + 139, -208, -208, -208, 140, 141, 142, -208, -208, -208, + -208, -208, -208, -208, 143, 21, 79, -208, 341, 341, + -208, 4, -208, -208, -208, -208, -208, 86, 144, 145, + -208, -208, 64, -42, 21, 179, 189, 191, 192, -208, + -208, 149, -208, -208, -208, -208, -208, -208, -51, 42, + 42, 99, 110, 33, 33, -208, -208, 79, 79, -208, + -61, -208, -208, -208, -59, -208, -208, -208, -64, -208, + -208, -208, -208, 19, 19, -208, -208, -208, -208, -8, + -208, 160, -208, 81, -208, 140, -208, -208, -208, -208, + -208, 65, -208, -208, -208 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -208, -208, -208, 196, -11, -207, -94, -122, 5, -2, + -208, -208, -82, -208, -208, -208, -208, 53, -208, 7, + -208, -208, -208, -208, -208, -208, -208, -208, -208, -91, + -40, -24, -75, -208, -36, -208, -208, -208, -208, -185, + -208, -208, -208, -208, -173, -208 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -42 +static const yytype_int16 yytable[] = +{ + 93, 141, 217, 249, -13, 122, 123, 92, 124, 98, + 132, 26, -41, 174, 175, 189, 264, 195, 134, 116, + 3, 253, 221, 229, 234, 128, 129, 109, 148, 278, + 150, 112, 151, 152, 110, 214, 207, 212, 111, 121, + 121, 117, 121, 273, 113, 230, 235, 275, 210, 213, + 134, 279, 199, 200, -29, -29, 26, 135, 129, 145, + 129, 201, 202, 203, 216, 127, 190, 272, 196, 274, + 176, 177, 178, 179, 180, 181, 128, 129, 136, 137, + 138, 139, 140, 270, 271, 205, 114, 221, 282, 135, + 93, 93, 187, 144, 211, 211, 193, 92, 92, 98, + 98, 206, 283, 90, 188, 115, 194, 145, 224, 225, + 226, 171, 172, 173, 170, 171, 172, 173, 187, 121, + 218, 119, -13, -13, 227, 228, 132, 215, 209, 209, + -41, -41, -13, 232, 134, 208, 208, 98, 98, 88, + -41, 144, 121, 174, 175, 170, 238, 259, 90, 216, + 239, 240, 241, 242, 243, 244, 245, 246, 180, 181, + 219, 247, 248, 174, 175, 178, 179, 180, 181, 276, + 277, 251, 211, 258, 174, 175, 252, 193, 255, 256, + 257, 260, 261, 265, 90, 182, 183, 184, 90, 182, + 183, 184, 262, 266, 267, 268, 269, 281, 91, 284, + 176, 177, 178, 179, 180, 181, 209, 93, 0, 171, + 172, 173, 263, 208, 208, 98, 98, 174, 175, 237, + 0, 177, 178, 179, 180, 181, -3, 145, 145, 0, + 0, 0, 0, 178, 179, 180, 181, 4, 5, 0, + 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 144, 144, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 0, 0, 176, 177, 178, 179, 180, 181, + 0, 35, 0, 182, 183, 184, 0, 0, 0, 0, + 0, 0, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 0, 0, 88, 0, 0, 0, + 89, 0, 4, 5, 0, 90, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 0, 0, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, + 136, 137, 138, 139, 140, 0, 0, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 0, + 0, 88, 0, 0, 0, 89, 0, 4, 5, 0, + 90, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 0, 0, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 0, 0, 88, 0, 0, 0, + 89, 0, 0, 0, 0, 90, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 0, 0, 26, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 36, 37, 38, 39, + 40, 0, 0, 0, 0, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 146, + 147, 148, 149, 150, 0, 151, 152, 0, 0, 153, + 154, 0, 0, 73, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 155, 156, 0, 89, 0, 0, 0, 0, 90, + 0, 0, 157, 158, 159, 160, 161, 162, 163, 164, + 165 +}; + +#define yypact_value_is_default(yystate) \ + ((yystate) == (-208)) + +#define yytable_value_is_error(yytable_value) \ + YYID (0) + +static const yytype_int16 yycheck[] = +{ + 2, 95, 8, 188, 0, 41, 42, 2, 44, 2, + 92, 37, 0, 64, 65, 106, 223, 108, 93, 37, + 0, 194, 144, 37, 37, 118, 119, 37, 5, 37, + 7, 59, 9, 10, 37, 128, 130, 131, 37, 41, + 42, 59, 44, 250, 59, 59, 59, 254, 130, 131, + 125, 59, 121, 122, 118, 119, 37, 93, 119, 95, + 119, 130, 131, 132, 128, 89, 106, 128, 108, 128, + 121, 122, 123, 124, 125, 126, 118, 119, 59, 60, + 61, 62, 63, 134, 135, 121, 37, 209, 273, 125, + 92, 93, 37, 95, 130, 131, 37, 92, 93, 92, + 93, 125, 275, 129, 106, 37, 108, 143, 144, 118, + 119, 56, 57, 58, 133, 56, 57, 58, 37, 121, + 126, 59, 118, 119, 118, 119, 208, 128, 130, 131, + 118, 119, 128, 59, 209, 130, 131, 130, 131, 120, + 128, 143, 144, 64, 65, 133, 170, 61, 129, 128, + 174, 175, 176, 177, 178, 179, 180, 181, 125, 126, + 126, 185, 186, 64, 65, 123, 124, 125, 126, 263, + 264, 37, 208, 209, 64, 65, 37, 37, 37, 37, + 37, 37, 37, 4, 129, 130, 131, 132, 129, 130, + 131, 132, 128, 4, 3, 3, 47, 37, 2, 134, + 121, 122, 123, 124, 125, 126, 208, 209, -1, 56, + 57, 58, 223, 208, 209, 208, 209, 64, 65, 166, + -1, 122, 123, 124, 125, 126, 0, 263, 264, -1, + -1, -1, -1, 123, 124, 125, 126, 11, 12, -1, + -1, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 263, 264, 37, 38, 39, 40, 41, 42, 43, + 44, 45, -1, -1, 121, 122, 123, 124, 125, 126, + -1, 55, -1, 130, 131, 132, -1, -1, -1, -1, + -1, -1, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, -1, -1, 120, -1, -1, -1, + 124, -1, 11, 12, -1, 129, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, -1, -1, 37, 38, + 39, 40, 41, 42, 43, 44, 45, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, + 59, 60, 61, 62, 63, -1, -1, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, + -1, 120, -1, -1, -1, 124, -1, 11, 12, -1, + 129, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, -1, -1, 37, 38, 39, 40, 41, 42, 43, + 44, 45, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, -1, -1, 120, -1, -1, -1, + 124, -1, -1, -1, -1, 129, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, -1, -1, 37, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 66, 67, 68, 69, + 70, -1, -1, -1, -1, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 3, + 4, 5, 6, 7, -1, 9, 10, -1, -1, 13, + 14, -1, -1, 103, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 35, 36, -1, 124, -1, -1, -1, -1, 129, + -1, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 137, 138, 0, 11, 12, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 55, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 120, 124, + 129, 139, 144, 145, 148, 149, 150, 151, 155, 156, + 157, 167, 168, 170, 171, 172, 173, 177, 178, 37, + 37, 37, 59, 59, 37, 37, 37, 59, 163, 59, + 164, 145, 170, 170, 170, 145, 155, 167, 118, 119, + 140, 141, 148, 139, 168, 170, 59, 60, 61, 62, + 63, 142, 143, 144, 145, 170, 3, 4, 5, 6, + 7, 9, 10, 13, 14, 35, 36, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 152, 153, 154, 158, + 133, 56, 57, 58, 64, 65, 121, 122, 123, 124, + 125, 126, 130, 131, 132, 165, 166, 37, 145, 165, + 166, 174, 175, 37, 145, 165, 166, 179, 180, 121, + 122, 130, 131, 132, 169, 170, 167, 142, 144, 145, + 148, 170, 142, 148, 128, 128, 128, 8, 126, 126, + 142, 143, 146, 147, 170, 118, 119, 118, 119, 37, + 59, 159, 59, 161, 37, 59, 162, 153, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 175, + 176, 37, 37, 180, 181, 37, 37, 37, 170, 61, + 37, 37, 128, 140, 141, 4, 4, 3, 3, 47, + 134, 135, 128, 141, 128, 141, 142, 142, 37, 59, + 160, 37, 175, 180, 134 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* This macro is provided for backward compatibility. */ + +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = 0; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + +/* Line 1806 of yacc.c */ +#line 317 "grammar.y" + { + finish_parse((yyvsp[(2) - (2)].blk).b); +} + break; + + case 4: + +/* Line 1806 of yacc.c */ +#line 322 "grammar.y" + { (yyval.blk).q = qerr; } + break; + + case 6: + +/* Line 1806 of yacc.c */ +#line 325 "grammar.y" + { gen_and((yyvsp[(1) - (3)].blk).b, (yyvsp[(3) - (3)].blk).b); (yyval.blk) = (yyvsp[(3) - (3)].blk); } + break; + + case 7: + +/* Line 1806 of yacc.c */ +#line 326 "grammar.y" + { gen_and((yyvsp[(1) - (3)].blk).b, (yyvsp[(3) - (3)].blk).b); (yyval.blk) = (yyvsp[(3) - (3)].blk); } + break; + + case 8: + +/* Line 1806 of yacc.c */ +#line 327 "grammar.y" + { gen_or((yyvsp[(1) - (3)].blk).b, (yyvsp[(3) - (3)].blk).b); (yyval.blk) = (yyvsp[(3) - (3)].blk); } + break; + + case 9: + +/* Line 1806 of yacc.c */ +#line 328 "grammar.y" + { gen_or((yyvsp[(1) - (3)].blk).b, (yyvsp[(3) - (3)].blk).b); (yyval.blk) = (yyvsp[(3) - (3)].blk); } + break; + + case 10: + +/* Line 1806 of yacc.c */ +#line 330 "grammar.y" + { (yyval.blk) = (yyvsp[(0) - (1)].blk); } + break; + + case 11: + +/* Line 1806 of yacc.c */ +#line 332 "grammar.y" + { (yyval.blk) = (yyvsp[(0) - (1)].blk); } + break; + + case 13: + +/* Line 1806 of yacc.c */ +#line 335 "grammar.y" + { (yyval.blk).b = gen_ncode(NULL, (bpf_u_int32)(yyvsp[(1) - (1)].i), + (yyval.blk).q = (yyvsp[(0) - (1)].blk).q); } + break; + + case 14: + +/* Line 1806 of yacc.c */ +#line 337 "grammar.y" + { (yyval.blk) = (yyvsp[(2) - (3)].blk); } + break; + + case 15: + +/* Line 1806 of yacc.c */ +#line 339 "grammar.y" + { (yyval.blk).b = gen_scode((yyvsp[(1) - (1)].s), (yyval.blk).q = (yyvsp[(0) - (1)].blk).q); } + break; + + case 16: + +/* Line 1806 of yacc.c */ +#line 340 "grammar.y" + { (yyval.blk).b = gen_mcode((yyvsp[(1) - (3)].s), NULL, (yyvsp[(3) - (3)].i), + (yyval.blk).q = (yyvsp[(0) - (3)].blk).q); } + break; + + case 17: + +/* Line 1806 of yacc.c */ +#line 342 "grammar.y" + { (yyval.blk).b = gen_mcode((yyvsp[(1) - (3)].s), (yyvsp[(3) - (3)].s), 0, + (yyval.blk).q = (yyvsp[(0) - (3)].blk).q); } + break; + + case 18: + +/* Line 1806 of yacc.c */ +#line 344 "grammar.y" + { + /* Decide how to parse HID based on proto */ + (yyval.blk).q = (yyvsp[(0) - (1)].blk).q; + if ((yyval.blk).q.addr == Q_PORT) + bpf_error("'port' modifier applied to ip host"); + else if ((yyval.blk).q.addr == Q_PORTRANGE) + bpf_error("'portrange' modifier applied to ip host"); + else if ((yyval.blk).q.addr == Q_PROTO) + bpf_error("'proto' modifier applied to ip host"); + else if ((yyval.blk).q.addr == Q_PROTOCHAIN) + bpf_error("'protochain' modifier applied to ip host"); + (yyval.blk).b = gen_ncode((yyvsp[(1) - (1)].s), 0, (yyval.blk).q); + } + break; + + case 19: + +/* Line 1806 of yacc.c */ +#line 357 "grammar.y" + { +#ifdef INET6 + (yyval.blk).b = gen_mcode6((yyvsp[(1) - (3)].s), NULL, (yyvsp[(3) - (3)].i), + (yyval.blk).q = (yyvsp[(0) - (3)].blk).q); +#else + bpf_error("'ip6addr/prefixlen' not supported " + "in this configuration"); +#endif /*INET6*/ + } + break; + + case 20: + +/* Line 1806 of yacc.c */ +#line 366 "grammar.y" + { +#ifdef INET6 + (yyval.blk).b = gen_mcode6((yyvsp[(1) - (1)].s), 0, 128, + (yyval.blk).q = (yyvsp[(0) - (1)].blk).q); +#else + bpf_error("'ip6addr' not supported " + "in this configuration"); +#endif /*INET6*/ + } + break; + + case 21: + +/* Line 1806 of yacc.c */ +#line 375 "grammar.y" + { + (yyval.blk).b = gen_ecode((yyvsp[(1) - (1)].e), (yyval.blk).q = (yyvsp[(0) - (1)].blk).q); + /* + * $1 was allocated by "pcap_ether_aton()", + * so we must free it now that we're done + * with it. + */ + free((yyvsp[(1) - (1)].e)); + } + break; + + case 22: + +/* Line 1806 of yacc.c */ +#line 384 "grammar.y" + { + (yyval.blk).b = gen_acode((yyvsp[(1) - (1)].e), (yyval.blk).q = (yyvsp[(0) - (1)].blk).q); + /* + * $1 was allocated by "pcap_ether_aton()", + * so we must free it now that we're done + * with it. + */ + free((yyvsp[(1) - (1)].e)); + } + break; + + case 23: + +/* Line 1806 of yacc.c */ +#line 393 "grammar.y" + { gen_not((yyvsp[(2) - (2)].blk).b); (yyval.blk) = (yyvsp[(2) - (2)].blk); } + break; + + case 24: + +/* Line 1806 of yacc.c */ +#line 395 "grammar.y" + { (yyval.blk) = (yyvsp[(0) - (1)].blk); } + break; + + case 25: + +/* Line 1806 of yacc.c */ +#line 397 "grammar.y" + { (yyval.blk) = (yyvsp[(0) - (1)].blk); } + break; + + case 27: + +/* Line 1806 of yacc.c */ +#line 400 "grammar.y" + { gen_and((yyvsp[(1) - (3)].blk).b, (yyvsp[(3) - (3)].blk).b); (yyval.blk) = (yyvsp[(3) - (3)].blk); } + break; + + case 28: + +/* Line 1806 of yacc.c */ +#line 401 "grammar.y" + { gen_or((yyvsp[(1) - (3)].blk).b, (yyvsp[(3) - (3)].blk).b); (yyval.blk) = (yyvsp[(3) - (3)].blk); } + break; + + case 29: + +/* Line 1806 of yacc.c */ +#line 403 "grammar.y" + { (yyval.blk).b = gen_ncode(NULL, (bpf_u_int32)(yyvsp[(1) - (1)].i), + (yyval.blk).q = (yyvsp[(0) - (1)].blk).q); } + break; + + case 32: + +/* Line 1806 of yacc.c */ +#line 408 "grammar.y" + { gen_not((yyvsp[(2) - (2)].blk).b); (yyval.blk) = (yyvsp[(2) - (2)].blk); } + break; + + case 33: + +/* Line 1806 of yacc.c */ +#line 410 "grammar.y" + { QSET((yyval.blk).q, (yyvsp[(1) - (3)].i), (yyvsp[(2) - (3)].i), (yyvsp[(3) - (3)].i)); } + break; + + case 34: + +/* Line 1806 of yacc.c */ +#line 411 "grammar.y" + { QSET((yyval.blk).q, (yyvsp[(1) - (2)].i), (yyvsp[(2) - (2)].i), Q_DEFAULT); } + break; + + case 35: + +/* Line 1806 of yacc.c */ +#line 412 "grammar.y" + { QSET((yyval.blk).q, (yyvsp[(1) - (2)].i), Q_DEFAULT, (yyvsp[(2) - (2)].i)); } + break; + + case 36: + +/* Line 1806 of yacc.c */ +#line 413 "grammar.y" + { QSET((yyval.blk).q, (yyvsp[(1) - (2)].i), Q_DEFAULT, Q_PROTO); } + break; + + case 37: + +/* Line 1806 of yacc.c */ +#line 414 "grammar.y" + { QSET((yyval.blk).q, (yyvsp[(1) - (2)].i), Q_DEFAULT, Q_PROTOCHAIN); } + break; + + case 38: + +/* Line 1806 of yacc.c */ +#line 415 "grammar.y" + { QSET((yyval.blk).q, (yyvsp[(1) - (2)].i), Q_DEFAULT, (yyvsp[(2) - (2)].i)); } + break; + + case 39: + +/* Line 1806 of yacc.c */ +#line 417 "grammar.y" + { (yyval.blk) = (yyvsp[(2) - (2)].blk); } + break; + + case 40: + +/* Line 1806 of yacc.c */ +#line 418 "grammar.y" + { (yyval.blk).b = (yyvsp[(2) - (3)].blk).b; (yyval.blk).q = (yyvsp[(1) - (3)].blk).q; } + break; + + case 41: + +/* Line 1806 of yacc.c */ +#line 419 "grammar.y" + { (yyval.blk).b = gen_proto_abbrev((yyvsp[(1) - (1)].i)); (yyval.blk).q = qerr; } + break; + + case 42: + +/* Line 1806 of yacc.c */ +#line 420 "grammar.y" + { (yyval.blk).b = gen_relation((yyvsp[(2) - (3)].i), (yyvsp[(1) - (3)].a), (yyvsp[(3) - (3)].a), 0); + (yyval.blk).q = qerr; } + break; + + case 43: + +/* Line 1806 of yacc.c */ +#line 422 "grammar.y" + { (yyval.blk).b = gen_relation((yyvsp[(2) - (3)].i), (yyvsp[(1) - (3)].a), (yyvsp[(3) - (3)].a), 1); + (yyval.blk).q = qerr; } + break; + + case 44: + +/* Line 1806 of yacc.c */ +#line 424 "grammar.y" + { (yyval.blk).b = (yyvsp[(1) - (1)].rblk); (yyval.blk).q = qerr; } + break; + + case 45: + +/* Line 1806 of yacc.c */ +#line 425 "grammar.y" + { (yyval.blk).b = gen_atmtype_abbrev((yyvsp[(1) - (1)].i)); (yyval.blk).q = qerr; } + break; + + case 46: + +/* Line 1806 of yacc.c */ +#line 426 "grammar.y" + { (yyval.blk).b = gen_atmmulti_abbrev((yyvsp[(1) - (1)].i)); (yyval.blk).q = qerr; } + break; + + case 47: + +/* Line 1806 of yacc.c */ +#line 427 "grammar.y" + { (yyval.blk).b = (yyvsp[(2) - (2)].blk).b; (yyval.blk).q = qerr; } + break; + + case 48: + +/* Line 1806 of yacc.c */ +#line 428 "grammar.y" + { (yyval.blk).b = gen_mtp2type_abbrev((yyvsp[(1) - (1)].i)); (yyval.blk).q = qerr; } + break; + + case 49: + +/* Line 1806 of yacc.c */ +#line 429 "grammar.y" + { (yyval.blk).b = (yyvsp[(2) - (2)].blk).b; (yyval.blk).q = qerr; } + break; + + case 51: + +/* Line 1806 of yacc.c */ +#line 433 "grammar.y" + { (yyval.i) = Q_DEFAULT; } + break; + + case 52: + +/* Line 1806 of yacc.c */ +#line 436 "grammar.y" + { (yyval.i) = Q_SRC; } + break; + + case 53: + +/* Line 1806 of yacc.c */ +#line 437 "grammar.y" + { (yyval.i) = Q_DST; } + break; + + case 54: + +/* Line 1806 of yacc.c */ +#line 438 "grammar.y" + { (yyval.i) = Q_OR; } + break; + + case 55: + +/* Line 1806 of yacc.c */ +#line 439 "grammar.y" + { (yyval.i) = Q_OR; } + break; + + case 56: + +/* Line 1806 of yacc.c */ +#line 440 "grammar.y" + { (yyval.i) = Q_AND; } + break; + + case 57: + +/* Line 1806 of yacc.c */ +#line 441 "grammar.y" + { (yyval.i) = Q_AND; } + break; + + case 58: + +/* Line 1806 of yacc.c */ +#line 442 "grammar.y" + { (yyval.i) = Q_ADDR1; } + break; + + case 59: + +/* Line 1806 of yacc.c */ +#line 443 "grammar.y" + { (yyval.i) = Q_ADDR2; } + break; + + case 60: + +/* Line 1806 of yacc.c */ +#line 444 "grammar.y" + { (yyval.i) = Q_ADDR3; } + break; + + case 61: + +/* Line 1806 of yacc.c */ +#line 445 "grammar.y" + { (yyval.i) = Q_ADDR4; } + break; + + case 62: + +/* Line 1806 of yacc.c */ +#line 446 "grammar.y" + { (yyval.i) = Q_RA; } + break; + + case 63: + +/* Line 1806 of yacc.c */ +#line 447 "grammar.y" + { (yyval.i) = Q_TA; } + break; + + case 64: + +/* Line 1806 of yacc.c */ +#line 450 "grammar.y" + { (yyval.i) = Q_HOST; } + break; + + case 65: + +/* Line 1806 of yacc.c */ +#line 451 "grammar.y" + { (yyval.i) = Q_NET; } + break; + + case 66: + +/* Line 1806 of yacc.c */ +#line 452 "grammar.y" + { (yyval.i) = Q_PORT; } + break; + + case 67: + +/* Line 1806 of yacc.c */ +#line 453 "grammar.y" + { (yyval.i) = Q_PORTRANGE; } + break; + + case 68: + +/* Line 1806 of yacc.c */ +#line 456 "grammar.y" + { (yyval.i) = Q_GATEWAY; } + break; + + case 69: + +/* Line 1806 of yacc.c */ +#line 458 "grammar.y" + { (yyval.i) = Q_LINK; } + break; + + case 70: + +/* Line 1806 of yacc.c */ +#line 459 "grammar.y" + { (yyval.i) = Q_IP; } + break; + + case 71: + +/* Line 1806 of yacc.c */ +#line 460 "grammar.y" + { (yyval.i) = Q_ARP; } + break; + + case 72: + +/* Line 1806 of yacc.c */ +#line 461 "grammar.y" + { (yyval.i) = Q_RARP; } + break; + + case 73: + +/* Line 1806 of yacc.c */ +#line 462 "grammar.y" + { (yyval.i) = Q_SCTP; } + break; + + case 74: + +/* Line 1806 of yacc.c */ +#line 463 "grammar.y" + { (yyval.i) = Q_TCP; } + break; + + case 75: + +/* Line 1806 of yacc.c */ +#line 464 "grammar.y" + { (yyval.i) = Q_UDP; } + break; + + case 76: + +/* Line 1806 of yacc.c */ +#line 465 "grammar.y" + { (yyval.i) = Q_ICMP; } + break; + + case 77: + +/* Line 1806 of yacc.c */ +#line 466 "grammar.y" + { (yyval.i) = Q_IGMP; } + break; + + case 78: + +/* Line 1806 of yacc.c */ +#line 467 "grammar.y" + { (yyval.i) = Q_IGRP; } + break; + + case 79: + +/* Line 1806 of yacc.c */ +#line 468 "grammar.y" + { (yyval.i) = Q_PIM; } + break; + + case 80: + +/* Line 1806 of yacc.c */ +#line 469 "grammar.y" + { (yyval.i) = Q_VRRP; } + break; + + case 81: + +/* Line 1806 of yacc.c */ +#line 470 "grammar.y" + { (yyval.i) = Q_CARP; } + break; + + case 82: + +/* Line 1806 of yacc.c */ +#line 471 "grammar.y" + { (yyval.i) = Q_ATALK; } + break; + + case 83: + +/* Line 1806 of yacc.c */ +#line 472 "grammar.y" + { (yyval.i) = Q_AARP; } + break; + + case 84: + +/* Line 1806 of yacc.c */ +#line 473 "grammar.y" + { (yyval.i) = Q_DECNET; } + break; + + case 85: + +/* Line 1806 of yacc.c */ +#line 474 "grammar.y" + { (yyval.i) = Q_LAT; } + break; + + case 86: + +/* Line 1806 of yacc.c */ +#line 475 "grammar.y" + { (yyval.i) = Q_SCA; } + break; + + case 87: + +/* Line 1806 of yacc.c */ +#line 476 "grammar.y" + { (yyval.i) = Q_MOPDL; } + break; + + case 88: + +/* Line 1806 of yacc.c */ +#line 477 "grammar.y" + { (yyval.i) = Q_MOPRC; } + break; + + case 89: + +/* Line 1806 of yacc.c */ +#line 478 "grammar.y" + { (yyval.i) = Q_IPV6; } + break; + + case 90: + +/* Line 1806 of yacc.c */ +#line 479 "grammar.y" + { (yyval.i) = Q_ICMPV6; } + break; + + case 91: + +/* Line 1806 of yacc.c */ +#line 480 "grammar.y" + { (yyval.i) = Q_AH; } + break; + + case 92: + +/* Line 1806 of yacc.c */ +#line 481 "grammar.y" + { (yyval.i) = Q_ESP; } + break; + + case 93: + +/* Line 1806 of yacc.c */ +#line 482 "grammar.y" + { (yyval.i) = Q_ISO; } + break; + + case 94: + +/* Line 1806 of yacc.c */ +#line 483 "grammar.y" + { (yyval.i) = Q_ESIS; } + break; + + case 95: + +/* Line 1806 of yacc.c */ +#line 484 "grammar.y" + { (yyval.i) = Q_ISIS; } + break; + + case 96: + +/* Line 1806 of yacc.c */ +#line 485 "grammar.y" + { (yyval.i) = Q_ISIS_L1; } + break; + + case 97: + +/* Line 1806 of yacc.c */ +#line 486 "grammar.y" + { (yyval.i) = Q_ISIS_L2; } + break; + + case 98: + +/* Line 1806 of yacc.c */ +#line 487 "grammar.y" + { (yyval.i) = Q_ISIS_IIH; } + break; + + case 99: + +/* Line 1806 of yacc.c */ +#line 488 "grammar.y" + { (yyval.i) = Q_ISIS_LSP; } + break; + + case 100: + +/* Line 1806 of yacc.c */ +#line 489 "grammar.y" + { (yyval.i) = Q_ISIS_SNP; } + break; + + case 101: + +/* Line 1806 of yacc.c */ +#line 490 "grammar.y" + { (yyval.i) = Q_ISIS_PSNP; } + break; + + case 102: + +/* Line 1806 of yacc.c */ +#line 491 "grammar.y" + { (yyval.i) = Q_ISIS_CSNP; } + break; + + case 103: + +/* Line 1806 of yacc.c */ +#line 492 "grammar.y" + { (yyval.i) = Q_CLNP; } + break; + + case 104: + +/* Line 1806 of yacc.c */ +#line 493 "grammar.y" + { (yyval.i) = Q_STP; } + break; + + case 105: + +/* Line 1806 of yacc.c */ +#line 494 "grammar.y" + { (yyval.i) = Q_IPX; } + break; + + case 106: + +/* Line 1806 of yacc.c */ +#line 495 "grammar.y" + { (yyval.i) = Q_NETBEUI; } + break; + + case 107: + +/* Line 1806 of yacc.c */ +#line 496 "grammar.y" + { (yyval.i) = Q_RADIO; } + break; + + case 108: + +/* Line 1806 of yacc.c */ +#line 498 "grammar.y" + { (yyval.rblk) = gen_broadcast((yyvsp[(1) - (2)].i)); } + break; + + case 109: + +/* Line 1806 of yacc.c */ +#line 499 "grammar.y" + { (yyval.rblk) = gen_multicast((yyvsp[(1) - (2)].i)); } + break; + + case 110: + +/* Line 1806 of yacc.c */ +#line 500 "grammar.y" + { (yyval.rblk) = gen_less((yyvsp[(2) - (2)].i)); } + break; + + case 111: + +/* Line 1806 of yacc.c */ +#line 501 "grammar.y" + { (yyval.rblk) = gen_greater((yyvsp[(2) - (2)].i)); } + break; + + case 112: + +/* Line 1806 of yacc.c */ +#line 502 "grammar.y" + { (yyval.rblk) = gen_byteop((yyvsp[(3) - (4)].i), (yyvsp[(2) - (4)].i), (yyvsp[(4) - (4)].i)); } + break; + + case 113: + +/* Line 1806 of yacc.c */ +#line 503 "grammar.y" + { (yyval.rblk) = gen_inbound(0); } + break; + + case 114: + +/* Line 1806 of yacc.c */ +#line 504 "grammar.y" + { (yyval.rblk) = gen_inbound(1); } + break; + + case 115: + +/* Line 1806 of yacc.c */ +#line 505 "grammar.y" + { (yyval.rblk) = gen_vlan((yyvsp[(2) - (2)].i)); } + break; + + case 116: + +/* Line 1806 of yacc.c */ +#line 506 "grammar.y" + { (yyval.rblk) = gen_vlan(-1); } + break; + + case 117: + +/* Line 1806 of yacc.c */ +#line 507 "grammar.y" + { (yyval.rblk) = gen_mpls((yyvsp[(2) - (2)].i)); } + break; + + case 118: + +/* Line 1806 of yacc.c */ +#line 508 "grammar.y" + { (yyval.rblk) = gen_mpls(-1); } + break; + + case 119: + +/* Line 1806 of yacc.c */ +#line 509 "grammar.y" + { (yyval.rblk) = gen_pppoed(); } + break; + + case 120: + +/* Line 1806 of yacc.c */ +#line 510 "grammar.y" + { (yyval.rblk) = gen_pppoes((yyvsp[(2) - (2)].i)); } + break; + + case 121: + +/* Line 1806 of yacc.c */ +#line 511 "grammar.y" + { (yyval.rblk) = gen_pppoes(-1); } + break; + + case 122: + +/* Line 1806 of yacc.c */ +#line 512 "grammar.y" + { (yyval.rblk) = (yyvsp[(1) - (1)].rblk); } + break; + + case 123: + +/* Line 1806 of yacc.c */ +#line 513 "grammar.y" + { (yyval.rblk) = (yyvsp[(2) - (2)].rblk); } + break; + + case 124: + +/* Line 1806 of yacc.c */ +#line 516 "grammar.y" + { (yyval.rblk) = gen_pf_ifname((yyvsp[(2) - (2)].s)); } + break; + + case 125: + +/* Line 1806 of yacc.c */ +#line 517 "grammar.y" + { (yyval.rblk) = gen_pf_ruleset((yyvsp[(2) - (2)].s)); } + break; + + case 126: + +/* Line 1806 of yacc.c */ +#line 518 "grammar.y" + { (yyval.rblk) = gen_pf_rnr((yyvsp[(2) - (2)].i)); } + break; + + case 127: + +/* Line 1806 of yacc.c */ +#line 519 "grammar.y" + { (yyval.rblk) = gen_pf_srnr((yyvsp[(2) - (2)].i)); } + break; + + case 128: + +/* Line 1806 of yacc.c */ +#line 520 "grammar.y" + { (yyval.rblk) = gen_pf_reason((yyvsp[(2) - (2)].i)); } + break; + + case 129: + +/* Line 1806 of yacc.c */ +#line 521 "grammar.y" + { (yyval.rblk) = gen_pf_action((yyvsp[(2) - (2)].i)); } + break; + + case 130: + +/* Line 1806 of yacc.c */ +#line 525 "grammar.y" + { (yyval.rblk) = gen_p80211_type((yyvsp[(2) - (4)].i) | (yyvsp[(4) - (4)].i), + IEEE80211_FC0_TYPE_MASK | + IEEE80211_FC0_SUBTYPE_MASK); + } + break; + + case 131: + +/* Line 1806 of yacc.c */ +#line 529 "grammar.y" + { (yyval.rblk) = gen_p80211_type((yyvsp[(2) - (2)].i), + IEEE80211_FC0_TYPE_MASK); + } + break; + + case 132: + +/* Line 1806 of yacc.c */ +#line 532 "grammar.y" + { (yyval.rblk) = gen_p80211_type((yyvsp[(2) - (2)].i), + IEEE80211_FC0_TYPE_MASK | + IEEE80211_FC0_SUBTYPE_MASK); + } + break; + + case 133: + +/* Line 1806 of yacc.c */ +#line 536 "grammar.y" + { (yyval.rblk) = gen_p80211_fcdir((yyvsp[(2) - (2)].i)); } + break; + + case 135: + +/* Line 1806 of yacc.c */ +#line 540 "grammar.y" + { (yyval.i) = str2tok((yyvsp[(1) - (1)].s), ieee80211_types); + if ((yyval.i) == -1) + bpf_error("unknown 802.11 type name"); + } + break; + + case 137: + +/* Line 1806 of yacc.c */ +#line 547 "grammar.y" + { const struct tok *types = NULL; + int i; + for (i = 0;; i++) { + if (ieee80211_type_subtypes[i].tok == NULL) { + /* Ran out of types */ + bpf_error("unknown 802.11 type"); + break; + } + if ((yyvsp[(-1) - (1)].i) == ieee80211_type_subtypes[i].type) { + types = ieee80211_type_subtypes[i].tok; + break; + } + } + + (yyval.i) = str2tok((yyvsp[(1) - (1)].s), types); + if ((yyval.i) == -1) + bpf_error("unknown 802.11 subtype name"); + } + break; + + case 138: + +/* Line 1806 of yacc.c */ +#line 567 "grammar.y" + { int i; + for (i = 0;; i++) { + if (ieee80211_type_subtypes[i].tok == NULL) { + /* Ran out of types */ + bpf_error("unknown 802.11 type name"); + break; + } + (yyval.i) = str2tok((yyvsp[(1) - (1)].s), ieee80211_type_subtypes[i].tok); + if ((yyval.i) != -1) { + (yyval.i) |= ieee80211_type_subtypes[i].type; + break; + } + } + } + break; + + case 140: + +/* Line 1806 of yacc.c */ +#line 584 "grammar.y" + { if (pcap_strcasecmp((yyvsp[(1) - (1)].s), "nods") == 0) + (yyval.i) = IEEE80211_FC1_DIR_NODS; + else if (pcap_strcasecmp((yyvsp[(1) - (1)].s), "tods") == 0) + (yyval.i) = IEEE80211_FC1_DIR_TODS; + else if (pcap_strcasecmp((yyvsp[(1) - (1)].s), "fromds") == 0) + (yyval.i) = IEEE80211_FC1_DIR_FROMDS; + else if (pcap_strcasecmp((yyvsp[(1) - (1)].s), "dstods") == 0) + (yyval.i) = IEEE80211_FC1_DIR_DSTODS; + else + bpf_error("unknown 802.11 direction"); + } + break; + + case 141: + +/* Line 1806 of yacc.c */ +#line 597 "grammar.y" + { (yyval.i) = (yyvsp[(1) - (1)].i); } + break; + + case 142: + +/* Line 1806 of yacc.c */ +#line 598 "grammar.y" + { (yyval.i) = pfreason_to_num((yyvsp[(1) - (1)].s)); } + break; + + case 143: + +/* Line 1806 of yacc.c */ +#line 601 "grammar.y" + { (yyval.i) = pfaction_to_num((yyvsp[(1) - (1)].s)); } + break; + + case 144: + +/* Line 1806 of yacc.c */ +#line 604 "grammar.y" + { (yyval.i) = BPF_JGT; } + break; + + case 145: + +/* Line 1806 of yacc.c */ +#line 605 "grammar.y" + { (yyval.i) = BPF_JGE; } + break; + + case 146: + +/* Line 1806 of yacc.c */ +#line 606 "grammar.y" + { (yyval.i) = BPF_JEQ; } + break; + + case 147: + +/* Line 1806 of yacc.c */ +#line 608 "grammar.y" + { (yyval.i) = BPF_JGT; } + break; + + case 148: + +/* Line 1806 of yacc.c */ +#line 609 "grammar.y" + { (yyval.i) = BPF_JGE; } + break; + + case 149: + +/* Line 1806 of yacc.c */ +#line 610 "grammar.y" + { (yyval.i) = BPF_JEQ; } + break; + + case 150: + +/* Line 1806 of yacc.c */ +#line 612 "grammar.y" + { (yyval.a) = gen_loadi((yyvsp[(1) - (1)].i)); } + break; + + case 152: + +/* Line 1806 of yacc.c */ +#line 615 "grammar.y" + { (yyval.a) = gen_load((yyvsp[(1) - (4)].i), (yyvsp[(3) - (4)].a), 1); } + break; + + case 153: + +/* Line 1806 of yacc.c */ +#line 616 "grammar.y" + { (yyval.a) = gen_load((yyvsp[(1) - (6)].i), (yyvsp[(3) - (6)].a), (yyvsp[(5) - (6)].i)); } + break; + + case 154: + +/* Line 1806 of yacc.c */ +#line 617 "grammar.y" + { (yyval.a) = gen_arth(BPF_ADD, (yyvsp[(1) - (3)].a), (yyvsp[(3) - (3)].a)); } + break; + + case 155: + +/* Line 1806 of yacc.c */ +#line 618 "grammar.y" + { (yyval.a) = gen_arth(BPF_SUB, (yyvsp[(1) - (3)].a), (yyvsp[(3) - (3)].a)); } + break; + + case 156: + +/* Line 1806 of yacc.c */ +#line 619 "grammar.y" + { (yyval.a) = gen_arth(BPF_MUL, (yyvsp[(1) - (3)].a), (yyvsp[(3) - (3)].a)); } + break; + + case 157: + +/* Line 1806 of yacc.c */ +#line 620 "grammar.y" + { (yyval.a) = gen_arth(BPF_DIV, (yyvsp[(1) - (3)].a), (yyvsp[(3) - (3)].a)); } + break; + + case 158: + +/* Line 1806 of yacc.c */ +#line 621 "grammar.y" + { (yyval.a) = gen_arth(BPF_AND, (yyvsp[(1) - (3)].a), (yyvsp[(3) - (3)].a)); } + break; + + case 159: + +/* Line 1806 of yacc.c */ +#line 622 "grammar.y" + { (yyval.a) = gen_arth(BPF_OR, (yyvsp[(1) - (3)].a), (yyvsp[(3) - (3)].a)); } + break; + + case 160: + +/* Line 1806 of yacc.c */ +#line 623 "grammar.y" + { (yyval.a) = gen_arth(BPF_LSH, (yyvsp[(1) - (3)].a), (yyvsp[(3) - (3)].a)); } + break; + + case 161: + +/* Line 1806 of yacc.c */ +#line 624 "grammar.y" + { (yyval.a) = gen_arth(BPF_RSH, (yyvsp[(1) - (3)].a), (yyvsp[(3) - (3)].a)); } + break; + + case 162: + +/* Line 1806 of yacc.c */ +#line 625 "grammar.y" + { (yyval.a) = gen_neg((yyvsp[(2) - (2)].a)); } + break; + + case 163: + +/* Line 1806 of yacc.c */ +#line 626 "grammar.y" + { (yyval.a) = (yyvsp[(2) - (3)].a); } + break; + + case 164: + +/* Line 1806 of yacc.c */ +#line 627 "grammar.y" + { (yyval.a) = gen_loadlen(); } + break; + + case 165: + +/* Line 1806 of yacc.c */ +#line 629 "grammar.y" + { (yyval.i) = '&'; } + break; + + case 166: + +/* Line 1806 of yacc.c */ +#line 630 "grammar.y" + { (yyval.i) = '|'; } + break; + + case 167: + +/* Line 1806 of yacc.c */ +#line 631 "grammar.y" + { (yyval.i) = '<'; } + break; + + case 168: + +/* Line 1806 of yacc.c */ +#line 632 "grammar.y" + { (yyval.i) = '>'; } + break; + + case 169: + +/* Line 1806 of yacc.c */ +#line 633 "grammar.y" + { (yyval.i) = '='; } + break; + + case 171: + +/* Line 1806 of yacc.c */ +#line 636 "grammar.y" + { (yyval.i) = (yyvsp[(2) - (3)].i); } + break; + + case 172: + +/* Line 1806 of yacc.c */ +#line 638 "grammar.y" + { (yyval.i) = A_LANE; } + break; + + case 173: + +/* Line 1806 of yacc.c */ +#line 639 "grammar.y" + { (yyval.i) = A_LLC; } + break; + + case 174: + +/* Line 1806 of yacc.c */ +#line 640 "grammar.y" + { (yyval.i) = A_METAC; } + break; + + case 175: + +/* Line 1806 of yacc.c */ +#line 641 "grammar.y" + { (yyval.i) = A_BCC; } + break; + + case 176: + +/* Line 1806 of yacc.c */ +#line 642 "grammar.y" + { (yyval.i) = A_OAMF4EC; } + break; + + case 177: + +/* Line 1806 of yacc.c */ +#line 643 "grammar.y" + { (yyval.i) = A_OAMF4SC; } + break; + + case 178: + +/* Line 1806 of yacc.c */ +#line 644 "grammar.y" + { (yyval.i) = A_SC; } + break; + + case 179: + +/* Line 1806 of yacc.c */ +#line 645 "grammar.y" + { (yyval.i) = A_ILMIC; } + break; + + case 180: + +/* Line 1806 of yacc.c */ +#line 647 "grammar.y" + { (yyval.i) = A_OAM; } + break; + + case 181: + +/* Line 1806 of yacc.c */ +#line 648 "grammar.y" + { (yyval.i) = A_OAMF4; } + break; + + case 182: + +/* Line 1806 of yacc.c */ +#line 649 "grammar.y" + { (yyval.i) = A_CONNECTMSG; } + break; + + case 183: + +/* Line 1806 of yacc.c */ +#line 650 "grammar.y" + { (yyval.i) = A_METACONNECT; } + break; + + case 184: + +/* Line 1806 of yacc.c */ +#line 653 "grammar.y" + { (yyval.blk).atmfieldtype = A_VPI; } + break; + + case 185: + +/* Line 1806 of yacc.c */ +#line 654 "grammar.y" + { (yyval.blk).atmfieldtype = A_VCI; } + break; + + case 187: + +/* Line 1806 of yacc.c */ +#line 657 "grammar.y" + { (yyval.blk).b = gen_atmfield_code((yyvsp[(0) - (2)].blk).atmfieldtype, (bpf_int32)(yyvsp[(2) - (2)].i), (bpf_u_int32)(yyvsp[(1) - (2)].i), 0); } + break; + + case 188: + +/* Line 1806 of yacc.c */ +#line 658 "grammar.y" + { (yyval.blk).b = gen_atmfield_code((yyvsp[(0) - (2)].blk).atmfieldtype, (bpf_int32)(yyvsp[(2) - (2)].i), (bpf_u_int32)(yyvsp[(1) - (2)].i), 1); } + break; + + case 189: + +/* Line 1806 of yacc.c */ +#line 659 "grammar.y" + { (yyval.blk).b = (yyvsp[(2) - (3)].blk).b; (yyval.blk).q = qerr; } + break; + + case 190: + +/* Line 1806 of yacc.c */ +#line 661 "grammar.y" + { + (yyval.blk).atmfieldtype = (yyvsp[(0) - (1)].blk).atmfieldtype; + if ((yyval.blk).atmfieldtype == A_VPI || + (yyval.blk).atmfieldtype == A_VCI) + (yyval.blk).b = gen_atmfield_code((yyval.blk).atmfieldtype, (bpf_int32) (yyvsp[(1) - (1)].i), BPF_JEQ, 0); + } + break; + + case 192: + +/* Line 1806 of yacc.c */ +#line 669 "grammar.y" + { gen_or((yyvsp[(1) - (3)].blk).b, (yyvsp[(3) - (3)].blk).b); (yyval.blk) = (yyvsp[(3) - (3)].blk); } + break; + + case 193: + +/* Line 1806 of yacc.c */ +#line 672 "grammar.y" + { (yyval.i) = M_FISU; } + break; + + case 194: + +/* Line 1806 of yacc.c */ +#line 673 "grammar.y" + { (yyval.i) = M_LSSU; } + break; + + case 195: + +/* Line 1806 of yacc.c */ +#line 674 "grammar.y" + { (yyval.i) = M_MSU; } + break; + + case 196: + +/* Line 1806 of yacc.c */ +#line 675 "grammar.y" + { (yyval.i) = MH_FISU; } + break; + + case 197: + +/* Line 1806 of yacc.c */ +#line 676 "grammar.y" + { (yyval.i) = MH_LSSU; } + break; + + case 198: + +/* Line 1806 of yacc.c */ +#line 677 "grammar.y" + { (yyval.i) = MH_MSU; } + break; + + case 199: + +/* Line 1806 of yacc.c */ +#line 680 "grammar.y" + { (yyval.blk).mtp3fieldtype = M_SIO; } + break; + + case 200: + +/* Line 1806 of yacc.c */ +#line 681 "grammar.y" + { (yyval.blk).mtp3fieldtype = M_OPC; } + break; + + case 201: + +/* Line 1806 of yacc.c */ +#line 682 "grammar.y" + { (yyval.blk).mtp3fieldtype = M_DPC; } + break; + + case 202: + +/* Line 1806 of yacc.c */ +#line 683 "grammar.y" + { (yyval.blk).mtp3fieldtype = M_SLS; } + break; + + case 203: + +/* Line 1806 of yacc.c */ +#line 684 "grammar.y" + { (yyval.blk).mtp3fieldtype = MH_SIO; } + break; + + case 204: + +/* Line 1806 of yacc.c */ +#line 685 "grammar.y" + { (yyval.blk).mtp3fieldtype = MH_OPC; } + break; + + case 205: + +/* Line 1806 of yacc.c */ +#line 686 "grammar.y" + { (yyval.blk).mtp3fieldtype = MH_DPC; } + break; + + case 206: + +/* Line 1806 of yacc.c */ +#line 687 "grammar.y" + { (yyval.blk).mtp3fieldtype = MH_SLS; } + break; + + case 208: + +/* Line 1806 of yacc.c */ +#line 690 "grammar.y" + { (yyval.blk).b = gen_mtp3field_code((yyvsp[(0) - (2)].blk).mtp3fieldtype, (u_int)(yyvsp[(2) - (2)].i), (u_int)(yyvsp[(1) - (2)].i), 0); } + break; + + case 209: + +/* Line 1806 of yacc.c */ +#line 691 "grammar.y" + { (yyval.blk).b = gen_mtp3field_code((yyvsp[(0) - (2)].blk).mtp3fieldtype, (u_int)(yyvsp[(2) - (2)].i), (u_int)(yyvsp[(1) - (2)].i), 1); } + break; + + case 210: + +/* Line 1806 of yacc.c */ +#line 692 "grammar.y" + { (yyval.blk).b = (yyvsp[(2) - (3)].blk).b; (yyval.blk).q = qerr; } + break; + + case 211: + +/* Line 1806 of yacc.c */ +#line 694 "grammar.y" + { + (yyval.blk).mtp3fieldtype = (yyvsp[(0) - (1)].blk).mtp3fieldtype; + if ((yyval.blk).mtp3fieldtype == M_SIO || + (yyval.blk).mtp3fieldtype == M_OPC || + (yyval.blk).mtp3fieldtype == M_DPC || + (yyval.blk).mtp3fieldtype == M_SLS || + (yyval.blk).mtp3fieldtype == MH_SIO || + (yyval.blk).mtp3fieldtype == MH_OPC || + (yyval.blk).mtp3fieldtype == MH_DPC || + (yyval.blk).mtp3fieldtype == MH_SLS) + (yyval.blk).b = gen_mtp3field_code((yyval.blk).mtp3fieldtype, (u_int) (yyvsp[(1) - (1)].i), BPF_JEQ, 0); + } + break; + + case 213: + +/* Line 1806 of yacc.c */ +#line 708 "grammar.y" + { gen_or((yyvsp[(1) - (3)].blk).b, (yyvsp[(3) - (3)].blk).b); (yyval.blk) = (yyvsp[(3) - (3)].blk); } + break; + + + +/* Line 1806 of yacc.c */ +#line 3744 "y.tab.c" + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 2067 of yacc.c */ +#line 710 "grammar.y" + + diff --git a/tcpdump/jni/libpcap/grammar.y b/tcpdump/jni/libpcap/grammar.y new file mode 100644 index 0000000..995a514 --- /dev/null +++ b/tcpdump/jni/libpcap/grammar.y @@ -0,0 +1,753 @@ +%{ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#include +#include +#endif /* WIN32 */ + +#include + +#ifndef WIN32 +#if __STDC__ +struct mbuf; +struct rtentry; +#endif + +#include +#include +#endif /* WIN32 */ + +#include + +#include "pcap-int.h" + +#include "gencode.h" +#ifdef HAVE_NET_PFVAR_H +#include +#include +#include +#endif +#include "llc.h" +#include "ieee80211.h" +#include + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#define QSET(q, p, d, a) (q).proto = (p),\ + (q).dir = (d),\ + (q).addr = (a) + +struct tok { + int v; /* value */ + const char *s; /* string */ +}; + +static const struct tok ieee80211_types[] = { + { IEEE80211_FC0_TYPE_DATA, "data" }, + { IEEE80211_FC0_TYPE_MGT, "mgt" }, + { IEEE80211_FC0_TYPE_MGT, "management" }, + { IEEE80211_FC0_TYPE_CTL, "ctl" }, + { IEEE80211_FC0_TYPE_CTL, "control" }, + { 0, NULL } +}; +static const struct tok ieee80211_mgt_subtypes[] = { + { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assocreq" }, + { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assoc-req" }, + { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assocresp" }, + { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assoc-resp" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassocreq" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassoc-req" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassocresp" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassoc-resp" }, + { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probereq" }, + { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probe-req" }, + { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "proberesp" }, + { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "probe-resp" }, + { IEEE80211_FC0_SUBTYPE_BEACON, "beacon" }, + { IEEE80211_FC0_SUBTYPE_ATIM, "atim" }, + { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassoc" }, + { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassociation" }, + { IEEE80211_FC0_SUBTYPE_AUTH, "auth" }, + { IEEE80211_FC0_SUBTYPE_AUTH, "authentication" }, + { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauth" }, + { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauthentication" }, + { 0, NULL } +}; +static const struct tok ieee80211_ctl_subtypes[] = { + { IEEE80211_FC0_SUBTYPE_PS_POLL, "ps-poll" }, + { IEEE80211_FC0_SUBTYPE_RTS, "rts" }, + { IEEE80211_FC0_SUBTYPE_CTS, "cts" }, + { IEEE80211_FC0_SUBTYPE_ACK, "ack" }, + { IEEE80211_FC0_SUBTYPE_CF_END, "cf-end" }, + { IEEE80211_FC0_SUBTYPE_CF_END_ACK, "cf-end-ack" }, + { 0, NULL } +}; +static const struct tok ieee80211_data_subtypes[] = { + { IEEE80211_FC0_SUBTYPE_DATA, "data" }, + { IEEE80211_FC0_SUBTYPE_CF_ACK, "data-cf-ack" }, + { IEEE80211_FC0_SUBTYPE_CF_POLL, "data-cf-poll" }, + { IEEE80211_FC0_SUBTYPE_CF_ACPL, "data-cf-ack-poll" }, + { IEEE80211_FC0_SUBTYPE_NODATA, "null" }, + { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK, "cf-ack" }, + { IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "cf-poll" }, + { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "cf-ack-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_DATA, "qos-data" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACK, "qos-data-cf-ack" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_POLL, "qos-data-cf-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACPL, "qos-data-cf-ack-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA, "qos" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "qos-cf-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "qos-cf-ack-poll" }, + { 0, NULL } +}; +static const struct tok llc_s_subtypes[] = { + { LLC_RR, "rr" }, + { LLC_RNR, "rnr" }, + { LLC_REJ, "rej" }, + { 0, NULL } +}; +static const struct tok llc_u_subtypes[] = { + { LLC_UI, "ui" }, + { LLC_UA, "ua" }, + { LLC_DISC, "disc" }, + { LLC_DM, "dm" }, + { LLC_SABME, "sabme" }, + { LLC_TEST, "test" }, + { LLC_XID, "xid" }, + { LLC_FRMR, "frmr" }, + { 0, NULL } +}; +struct type2tok { + int type; + const struct tok *tok; +}; +static const struct type2tok ieee80211_type_subtypes[] = { + { IEEE80211_FC0_TYPE_MGT, ieee80211_mgt_subtypes }, + { IEEE80211_FC0_TYPE_CTL, ieee80211_ctl_subtypes }, + { IEEE80211_FC0_TYPE_DATA, ieee80211_data_subtypes }, + { 0, NULL } +}; + +static int +str2tok(const char *str, const struct tok *toks) +{ + int i; + + for (i = 0; toks[i].s != NULL; i++) { + if (pcap_strcasecmp(toks[i].s, str) == 0) + return (toks[i].v); + } + return (-1); +} + +int n_errors = 0; + +static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF }; + +static void +yyerror(const char *msg) +{ + ++n_errors; + bpf_error("%s", msg); + /* NOTREACHED */ +} + +#ifdef NEED_YYPARSE_WRAPPER +int yyparse(void); + +int +pcap_parse() +{ + return (yyparse()); +} +#endif + +#ifdef HAVE_NET_PFVAR_H +static int +pfreason_to_num(const char *reason) +{ + const char *reasons[] = PFRES_NAMES; + int i; + + for (i = 0; reasons[i]; i++) { + if (pcap_strcasecmp(reason, reasons[i]) == 0) + return (i); + } + bpf_error("unknown PF reason"); + /*NOTREACHED*/ +} + +static int +pfaction_to_num(const char *action) +{ + if (pcap_strcasecmp(action, "pass") == 0 || + pcap_strcasecmp(action, "accept") == 0) + return (PF_PASS); + else if (pcap_strcasecmp(action, "drop") == 0 || + pcap_strcasecmp(action, "block") == 0) + return (PF_DROP); +#if HAVE_PF_NAT_THROUGH_PF_NORDR + else if (pcap_strcasecmp(action, "rdr") == 0) + return (PF_RDR); + else if (pcap_strcasecmp(action, "nat") == 0) + return (PF_NAT); + else if (pcap_strcasecmp(action, "binat") == 0) + return (PF_BINAT); + else if (pcap_strcasecmp(action, "nordr") == 0) + return (PF_NORDR); +#endif + else { + bpf_error("unknown PF action"); + /*NOTREACHED*/ + } +} +#else /* !HAVE_NET_PFVAR_H */ +static int +pfreason_to_num(const char *reason) +{ + bpf_error("libpcap was compiled on a machine without pf support"); + /*NOTREACHED*/ + + /* this is to make the VC compiler happy */ + return -1; +} + +static int +pfaction_to_num(const char *action) +{ + bpf_error("libpcap was compiled on a machine without pf support"); + /*NOTREACHED*/ + + /* this is to make the VC compiler happy */ + return -1; +} +#endif /* HAVE_NET_PFVAR_H */ +%} + +%union { + int i; + bpf_u_int32 h; + u_char *e; + char *s; + struct stmt *stmt; + struct arth *a; + struct { + struct qual q; + int atmfieldtype; + int mtp3fieldtype; + struct block *b; + } blk; + struct block *rblk; +} + +%type expr id nid pid term rterm qid +%type head +%type pqual dqual aqual ndaqual +%type arth narth +%type byteop pname pnum relop irelop +%type and or paren not null prog +%type other pfvar p80211 pllc +%type atmtype atmmultitype +%type atmfield +%type atmfieldvalue atmvalue atmlistvalue +%type mtp2type +%type mtp3field +%type mtp3fieldvalue mtp3value mtp3listvalue + + +%token DST SRC HOST GATEWAY +%token NET NETMASK PORT PORTRANGE LESS GREATER PROTO PROTOCHAIN CBYTE +%token ARP RARP IP SCTP TCP UDP ICMP IGMP IGRP PIM VRRP CARP +%token ATALK AARP DECNET LAT SCA MOPRC MOPDL +%token TK_BROADCAST TK_MULTICAST +%token NUM INBOUND OUTBOUND +%token PF_IFNAME PF_RSET PF_RNR PF_SRNR PF_REASON PF_ACTION +%token TYPE SUBTYPE DIR ADDR1 ADDR2 ADDR3 ADDR4 RA TA +%token LINK +%token GEQ LEQ NEQ +%token ID EID HID HID6 AID +%token LSH RSH +%token LEN +%token IPV6 ICMPV6 AH ESP +%token VLAN MPLS +%token PPPOED PPPOES GENEVE +%token ISO ESIS CLNP ISIS L1 L2 IIH LSP SNP CSNP PSNP +%token STP +%token IPX +%token NETBEUI +%token LANE LLC METAC BCC SC ILMIC OAMF4EC OAMF4SC +%token OAM OAMF4 CONNECTMSG METACONNECT +%token VPI VCI +%token RADIO +%token FISU LSSU MSU HFISU HLSSU HMSU +%token SIO OPC DPC SLS HSIO HOPC HDPC HSLS + + +%type ID +%type EID +%type AID +%type HID HID6 +%type NUM action reason type subtype type_subtype dir + +%left OR AND +%nonassoc '!' +%left '|' +%left '&' +%left LSH RSH +%left '+' '-' +%left '*' '/' +%nonassoc UMINUS +%% +prog: null expr +{ + finish_parse($2.b); +} + | null + ; +null: /* null */ { $$.q = qerr; } + ; +expr: term + | expr and term { gen_and($1.b, $3.b); $$ = $3; } + | expr and id { gen_and($1.b, $3.b); $$ = $3; } + | expr or term { gen_or($1.b, $3.b); $$ = $3; } + | expr or id { gen_or($1.b, $3.b); $$ = $3; } + ; +and: AND { $$ = $0; } + ; +or: OR { $$ = $0; } + ; +id: nid + | pnum { $$.b = gen_ncode(NULL, (bpf_u_int32)$1, + $$.q = $0.q); } + | paren pid ')' { $$ = $2; } + ; +nid: ID { $$.b = gen_scode($1, $$.q = $0.q); } + | HID '/' NUM { $$.b = gen_mcode($1, NULL, $3, + $$.q = $0.q); } + | HID NETMASK HID { $$.b = gen_mcode($1, $3, 0, + $$.q = $0.q); } + | HID { + /* Decide how to parse HID based on proto */ + $$.q = $0.q; + if ($$.q.addr == Q_PORT) + bpf_error("'port' modifier applied to ip host"); + else if ($$.q.addr == Q_PORTRANGE) + bpf_error("'portrange' modifier applied to ip host"); + else if ($$.q.addr == Q_PROTO) + bpf_error("'proto' modifier applied to ip host"); + else if ($$.q.addr == Q_PROTOCHAIN) + bpf_error("'protochain' modifier applied to ip host"); + $$.b = gen_ncode($1, 0, $$.q); + } + | HID6 '/' NUM { +#ifdef INET6 + $$.b = gen_mcode6($1, NULL, $3, + $$.q = $0.q); +#else + bpf_error("'ip6addr/prefixlen' not supported " + "in this configuration"); +#endif /*INET6*/ + } + | HID6 { +#ifdef INET6 + $$.b = gen_mcode6($1, 0, 128, + $$.q = $0.q); +#else + bpf_error("'ip6addr' not supported " + "in this configuration"); +#endif /*INET6*/ + } + | EID { + $$.b = gen_ecode($1, $$.q = $0.q); + /* + * $1 was allocated by "pcap_ether_aton()", + * so we must free it now that we're done + * with it. + */ + free($1); + } + | AID { + $$.b = gen_acode($1, $$.q = $0.q); + /* + * $1 was allocated by "pcap_ether_aton()", + * so we must free it now that we're done + * with it. + */ + free($1); + } + | not id { gen_not($2.b); $$ = $2; } + ; +not: '!' { $$ = $0; } + ; +paren: '(' { $$ = $0; } + ; +pid: nid + | qid and id { gen_and($1.b, $3.b); $$ = $3; } + | qid or id { gen_or($1.b, $3.b); $$ = $3; } + ; +qid: pnum { $$.b = gen_ncode(NULL, (bpf_u_int32)$1, + $$.q = $0.q); } + | pid + ; +term: rterm + | not term { gen_not($2.b); $$ = $2; } + ; +head: pqual dqual aqual { QSET($$.q, $1, $2, $3); } + | pqual dqual { QSET($$.q, $1, $2, Q_DEFAULT); } + | pqual aqual { QSET($$.q, $1, Q_DEFAULT, $2); } + | pqual PROTO { QSET($$.q, $1, Q_DEFAULT, Q_PROTO); } + | pqual PROTOCHAIN { QSET($$.q, $1, Q_DEFAULT, Q_PROTOCHAIN); } + | pqual ndaqual { QSET($$.q, $1, Q_DEFAULT, $2); } + ; +rterm: head id { $$ = $2; } + | paren expr ')' { $$.b = $2.b; $$.q = $1.q; } + | pname { $$.b = gen_proto_abbrev($1); $$.q = qerr; } + | arth relop arth { $$.b = gen_relation($2, $1, $3, 0); + $$.q = qerr; } + | arth irelop arth { $$.b = gen_relation($2, $1, $3, 1); + $$.q = qerr; } + | other { $$.b = $1; $$.q = qerr; } + | atmtype { $$.b = gen_atmtype_abbrev($1); $$.q = qerr; } + | atmmultitype { $$.b = gen_atmmulti_abbrev($1); $$.q = qerr; } + | atmfield atmvalue { $$.b = $2.b; $$.q = qerr; } + | mtp2type { $$.b = gen_mtp2type_abbrev($1); $$.q = qerr; } + | mtp3field mtp3value { $$.b = $2.b; $$.q = qerr; } + ; +/* protocol level qualifiers */ +pqual: pname + | { $$ = Q_DEFAULT; } + ; +/* 'direction' qualifiers */ +dqual: SRC { $$ = Q_SRC; } + | DST { $$ = Q_DST; } + | SRC OR DST { $$ = Q_OR; } + | DST OR SRC { $$ = Q_OR; } + | SRC AND DST { $$ = Q_AND; } + | DST AND SRC { $$ = Q_AND; } + | ADDR1 { $$ = Q_ADDR1; } + | ADDR2 { $$ = Q_ADDR2; } + | ADDR3 { $$ = Q_ADDR3; } + | ADDR4 { $$ = Q_ADDR4; } + | RA { $$ = Q_RA; } + | TA { $$ = Q_TA; } + ; +/* address type qualifiers */ +aqual: HOST { $$ = Q_HOST; } + | NET { $$ = Q_NET; } + | PORT { $$ = Q_PORT; } + | PORTRANGE { $$ = Q_PORTRANGE; } + ; +/* non-directional address type qualifiers */ +ndaqual: GATEWAY { $$ = Q_GATEWAY; } + ; +pname: LINK { $$ = Q_LINK; } + | IP { $$ = Q_IP; } + | ARP { $$ = Q_ARP; } + | RARP { $$ = Q_RARP; } + | SCTP { $$ = Q_SCTP; } + | TCP { $$ = Q_TCP; } + | UDP { $$ = Q_UDP; } + | ICMP { $$ = Q_ICMP; } + | IGMP { $$ = Q_IGMP; } + | IGRP { $$ = Q_IGRP; } + | PIM { $$ = Q_PIM; } + | VRRP { $$ = Q_VRRP; } + | CARP { $$ = Q_CARP; } + | ATALK { $$ = Q_ATALK; } + | AARP { $$ = Q_AARP; } + | DECNET { $$ = Q_DECNET; } + | LAT { $$ = Q_LAT; } + | SCA { $$ = Q_SCA; } + | MOPDL { $$ = Q_MOPDL; } + | MOPRC { $$ = Q_MOPRC; } + | IPV6 { $$ = Q_IPV6; } + | ICMPV6 { $$ = Q_ICMPV6; } + | AH { $$ = Q_AH; } + | ESP { $$ = Q_ESP; } + | ISO { $$ = Q_ISO; } + | ESIS { $$ = Q_ESIS; } + | ISIS { $$ = Q_ISIS; } + | L1 { $$ = Q_ISIS_L1; } + | L2 { $$ = Q_ISIS_L2; } + | IIH { $$ = Q_ISIS_IIH; } + | LSP { $$ = Q_ISIS_LSP; } + | SNP { $$ = Q_ISIS_SNP; } + | PSNP { $$ = Q_ISIS_PSNP; } + | CSNP { $$ = Q_ISIS_CSNP; } + | CLNP { $$ = Q_CLNP; } + | STP { $$ = Q_STP; } + | IPX { $$ = Q_IPX; } + | NETBEUI { $$ = Q_NETBEUI; } + | RADIO { $$ = Q_RADIO; } + ; +other: pqual TK_BROADCAST { $$ = gen_broadcast($1); } + | pqual TK_MULTICAST { $$ = gen_multicast($1); } + | LESS NUM { $$ = gen_less($2); } + | GREATER NUM { $$ = gen_greater($2); } + | CBYTE NUM byteop NUM { $$ = gen_byteop($3, $2, $4); } + | INBOUND { $$ = gen_inbound(0); } + | OUTBOUND { $$ = gen_inbound(1); } + | VLAN pnum { $$ = gen_vlan($2); } + | VLAN { $$ = gen_vlan(-1); } + | MPLS pnum { $$ = gen_mpls($2); } + | MPLS { $$ = gen_mpls(-1); } + | PPPOED { $$ = gen_pppoed(); } + | PPPOES pnum { $$ = gen_pppoes($2); } + | PPPOES { $$ = gen_pppoes(-1); } + | GENEVE pnum { $$ = gen_geneve($2); } + | GENEVE { $$ = gen_geneve(-1); } + | pfvar { $$ = $1; } + | pqual p80211 { $$ = $2; } + | pllc { $$ = $1; } + ; + +pfvar: PF_IFNAME ID { $$ = gen_pf_ifname($2); } + | PF_RSET ID { $$ = gen_pf_ruleset($2); } + | PF_RNR NUM { $$ = gen_pf_rnr($2); } + | PF_SRNR NUM { $$ = gen_pf_srnr($2); } + | PF_REASON reason { $$ = gen_pf_reason($2); } + | PF_ACTION action { $$ = gen_pf_action($2); } + ; + +p80211: TYPE type SUBTYPE subtype + { $$ = gen_p80211_type($2 | $4, + IEEE80211_FC0_TYPE_MASK | + IEEE80211_FC0_SUBTYPE_MASK); + } + | TYPE type { $$ = gen_p80211_type($2, + IEEE80211_FC0_TYPE_MASK); + } + | SUBTYPE type_subtype { $$ = gen_p80211_type($2, + IEEE80211_FC0_TYPE_MASK | + IEEE80211_FC0_SUBTYPE_MASK); + } + | DIR dir { $$ = gen_p80211_fcdir($2); } + ; + +type: NUM + | ID { $$ = str2tok($1, ieee80211_types); + if ($$ == -1) + bpf_error("unknown 802.11 type name"); + } + ; + +subtype: NUM + | ID { const struct tok *types = NULL; + int i; + for (i = 0;; i++) { + if (ieee80211_type_subtypes[i].tok == NULL) { + /* Ran out of types */ + bpf_error("unknown 802.11 type"); + break; + } + if ($-1 == ieee80211_type_subtypes[i].type) { + types = ieee80211_type_subtypes[i].tok; + break; + } + } + + $$ = str2tok($1, types); + if ($$ == -1) + bpf_error("unknown 802.11 subtype name"); + } + ; + +type_subtype: ID { int i; + for (i = 0;; i++) { + if (ieee80211_type_subtypes[i].tok == NULL) { + /* Ran out of types */ + bpf_error("unknown 802.11 type name"); + break; + } + $$ = str2tok($1, ieee80211_type_subtypes[i].tok); + if ($$ != -1) { + $$ |= ieee80211_type_subtypes[i].type; + break; + } + } + } + ; + +pllc: LLC { $$ = gen_llc(); } + | LLC ID { if (pcap_strcasecmp($2, "i") == 0) + $$ = gen_llc_i(); + else if (pcap_strcasecmp($2, "s") == 0) + $$ = gen_llc_s(); + else if (pcap_strcasecmp($2, "u") == 0) + $$ = gen_llc_u(); + else { + u_int subtype; + + subtype = str2tok($2, llc_s_subtypes); + if (subtype != -1) + $$ = gen_llc_s_subtype(subtype); + else { + subtype = str2tok($2, llc_u_subtypes); + if (subtype == -1) + bpf_error("unknown LLC type name \"%s\"", $2); + $$ = gen_llc_u_subtype(subtype); + } + } + } + /* sigh, "rnr" is already a keyword for PF */ + | LLC PF_RNR { $$ = gen_llc_s_subtype(LLC_RNR); } + ; + +dir: NUM + | ID { if (pcap_strcasecmp($1, "nods") == 0) + $$ = IEEE80211_FC1_DIR_NODS; + else if (pcap_strcasecmp($1, "tods") == 0) + $$ = IEEE80211_FC1_DIR_TODS; + else if (pcap_strcasecmp($1, "fromds") == 0) + $$ = IEEE80211_FC1_DIR_FROMDS; + else if (pcap_strcasecmp($1, "dstods") == 0) + $$ = IEEE80211_FC1_DIR_DSTODS; + else + bpf_error("unknown 802.11 direction"); + } + ; + +reason: NUM { $$ = $1; } + | ID { $$ = pfreason_to_num($1); } + ; + +action: ID { $$ = pfaction_to_num($1); } + ; + +relop: '>' { $$ = BPF_JGT; } + | GEQ { $$ = BPF_JGE; } + | '=' { $$ = BPF_JEQ; } + ; +irelop: LEQ { $$ = BPF_JGT; } + | '<' { $$ = BPF_JGE; } + | NEQ { $$ = BPF_JEQ; } + ; +arth: pnum { $$ = gen_loadi($1); } + | narth + ; +narth: pname '[' arth ']' { $$ = gen_load($1, $3, 1); } + | pname '[' arth ':' NUM ']' { $$ = gen_load($1, $3, $5); } + | arth '+' arth { $$ = gen_arth(BPF_ADD, $1, $3); } + | arth '-' arth { $$ = gen_arth(BPF_SUB, $1, $3); } + | arth '*' arth { $$ = gen_arth(BPF_MUL, $1, $3); } + | arth '/' arth { $$ = gen_arth(BPF_DIV, $1, $3); } + | arth '%' arth { $$ = gen_arth(BPF_MOD, $1, $3); } + | arth '&' arth { $$ = gen_arth(BPF_AND, $1, $3); } + | arth '|' arth { $$ = gen_arth(BPF_OR, $1, $3); } + | arth '^' arth { $$ = gen_arth(BPF_XOR, $1, $3); } + | arth LSH arth { $$ = gen_arth(BPF_LSH, $1, $3); } + | arth RSH arth { $$ = gen_arth(BPF_RSH, $1, $3); } + | '-' arth %prec UMINUS { $$ = gen_neg($2); } + | paren narth ')' { $$ = $2; } + | LEN { $$ = gen_loadlen(); } + ; +byteop: '&' { $$ = '&'; } + | '|' { $$ = '|'; } + | '<' { $$ = '<'; } + | '>' { $$ = '>'; } + | '=' { $$ = '='; } + ; +pnum: NUM + | paren pnum ')' { $$ = $2; } + ; +atmtype: LANE { $$ = A_LANE; } + | METAC { $$ = A_METAC; } + | BCC { $$ = A_BCC; } + | OAMF4EC { $$ = A_OAMF4EC; } + | OAMF4SC { $$ = A_OAMF4SC; } + | SC { $$ = A_SC; } + | ILMIC { $$ = A_ILMIC; } + ; +atmmultitype: OAM { $$ = A_OAM; } + | OAMF4 { $$ = A_OAMF4; } + | CONNECTMSG { $$ = A_CONNECTMSG; } + | METACONNECT { $$ = A_METACONNECT; } + ; + /* ATM field types quantifier */ +atmfield: VPI { $$.atmfieldtype = A_VPI; } + | VCI { $$.atmfieldtype = A_VCI; } + ; +atmvalue: atmfieldvalue + | relop NUM { $$.b = gen_atmfield_code($0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 0); } + | irelop NUM { $$.b = gen_atmfield_code($0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 1); } + | paren atmlistvalue ')' { $$.b = $2.b; $$.q = qerr; } + ; +atmfieldvalue: NUM { + $$.atmfieldtype = $0.atmfieldtype; + if ($$.atmfieldtype == A_VPI || + $$.atmfieldtype == A_VCI) + $$.b = gen_atmfield_code($$.atmfieldtype, (bpf_int32) $1, BPF_JEQ, 0); + } + ; +atmlistvalue: atmfieldvalue + | atmlistvalue or atmfieldvalue { gen_or($1.b, $3.b); $$ = $3; } + ; + /* MTP2 types quantifier */ +mtp2type: FISU { $$ = M_FISU; } + | LSSU { $$ = M_LSSU; } + | MSU { $$ = M_MSU; } + | HFISU { $$ = MH_FISU; } + | HLSSU { $$ = MH_LSSU; } + | HMSU { $$ = MH_MSU; } + ; + /* MTP3 field types quantifier */ +mtp3field: SIO { $$.mtp3fieldtype = M_SIO; } + | OPC { $$.mtp3fieldtype = M_OPC; } + | DPC { $$.mtp3fieldtype = M_DPC; } + | SLS { $$.mtp3fieldtype = M_SLS; } + | HSIO { $$.mtp3fieldtype = MH_SIO; } + | HOPC { $$.mtp3fieldtype = MH_OPC; } + | HDPC { $$.mtp3fieldtype = MH_DPC; } + | HSLS { $$.mtp3fieldtype = MH_SLS; } + ; +mtp3value: mtp3fieldvalue + | relop NUM { $$.b = gen_mtp3field_code($0.mtp3fieldtype, (u_int)$2, (u_int)$1, 0); } + | irelop NUM { $$.b = gen_mtp3field_code($0.mtp3fieldtype, (u_int)$2, (u_int)$1, 1); } + | paren mtp3listvalue ')' { $$.b = $2.b; $$.q = qerr; } + ; +mtp3fieldvalue: NUM { + $$.mtp3fieldtype = $0.mtp3fieldtype; + if ($$.mtp3fieldtype == M_SIO || + $$.mtp3fieldtype == M_OPC || + $$.mtp3fieldtype == M_DPC || + $$.mtp3fieldtype == M_SLS || + $$.mtp3fieldtype == MH_SIO || + $$.mtp3fieldtype == MH_OPC || + $$.mtp3fieldtype == MH_DPC || + $$.mtp3fieldtype == MH_SLS) + $$.b = gen_mtp3field_code($$.mtp3fieldtype, (u_int) $1, BPF_JEQ, 0); + } + ; +mtp3listvalue: mtp3fieldvalue + | mtp3listvalue or mtp3fieldvalue { gen_or($1.b, $3.b); $$ = $3; } + ; +%% diff --git a/tcpdump/jni/libpcap/ieee80211.h b/tcpdump/jni/libpcap/ieee80211.h new file mode 100644 index 0000000..473803d --- /dev/null +++ b/tcpdump/jni/libpcap/ieee80211.h @@ -0,0 +1,146 @@ +/*- + * Copyright (c) 2001 Atsushi Onoe + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/net80211/ieee80211.h,v 1.10 2005/07/22 16:55:27 sam Exp $ + */ +#ifndef _NET80211_IEEE80211_H_ +#define _NET80211_IEEE80211_H_ + +/* + * 802.11 protocol definitions. + */ + +#define IEEE80211_FC0_VERSION_MASK 0x03 +#define IEEE80211_FC0_VERSION_SHIFT 0 +#define IEEE80211_FC0_VERSION_0 0x00 +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_SHIFT 2 +#define IEEE80211_FC0_TYPE_MGT 0x00 +#define IEEE80211_FC0_TYPE_CTL 0x04 +#define IEEE80211_FC0_TYPE_DATA 0x08 + +#define IEEE80211_FC0_SUBTYPE_MASK 0xf0 +#define IEEE80211_FC0_SUBTYPE_SHIFT 4 +/* for TYPE_MGT */ +#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 +#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 +#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 +#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 +#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 +#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 +#define IEEE80211_FC0_SUBTYPE_BEACON 0x80 +#define IEEE80211_FC0_SUBTYPE_ATIM 0x90 +#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 +#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 +#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 +/* for TYPE_CTL */ +#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0 +#define IEEE80211_FC0_SUBTYPE_RTS 0xb0 +#define IEEE80211_FC0_SUBTYPE_CTS 0xc0 +#define IEEE80211_FC0_SUBTYPE_ACK 0xd0 +#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0 +#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0 +/* for TYPE_DATA (bit combination) */ +#define IEEE80211_FC0_SUBTYPE_DATA 0x00 +#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10 +#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20 +#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30 +#define IEEE80211_FC0_SUBTYPE_NODATA 0x40 +#define IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK 0x50 +#define IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL 0x60 +#define IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL 0x70 +#define IEEE80211_FC0_SUBTYPE_QOS 0x80 +#define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0 + +#define IEEE80211_FC1_DIR_MASK 0x03 +#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ +#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ +#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ +#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ + +#define IEEE80211_FC1_MORE_FRAG 0x04 +#define IEEE80211_FC1_RETRY 0x08 +#define IEEE80211_FC1_PWR_MGT 0x10 +#define IEEE80211_FC1_MORE_DATA 0x20 +#define IEEE80211_FC1_WEP 0x40 +#define IEEE80211_FC1_ORDER 0x80 + +#define IEEE80211_SEQ_FRAG_MASK 0x000f +#define IEEE80211_SEQ_FRAG_SHIFT 0 +#define IEEE80211_SEQ_SEQ_MASK 0xfff0 +#define IEEE80211_SEQ_SEQ_SHIFT 4 + +#define IEEE80211_NWID_LEN 32 + +#define IEEE80211_QOS_TXOP 0x00ff +/* bit 8 is reserved */ +#define IEEE80211_QOS_ACKPOLICY 0x60 +#define IEEE80211_QOS_ACKPOLICY_S 5 +#define IEEE80211_QOS_ESOP 0x10 +#define IEEE80211_QOS_ESOP_S 4 +#define IEEE80211_QOS_TID 0x0f + +#define IEEE80211_MGT_SUBTYPE_NAMES { \ + "assoc-req", "assoc-resp", \ + "reassoc-req", "reassoc-resp", \ + "probe-req", "probe-resp", \ + "reserved#6", "reserved#7", \ + "beacon", "atim", \ + "disassoc", "auth", \ + "deauth", "reserved#13", \ + "reserved#14", "reserved#15" \ +} + +#define IEEE80211_CTL_SUBTYPE_NAMES { \ + "reserved#0", "reserved#1", \ + "reserved#2", "reserved#3", \ + "reserved#3", "reserved#5", \ + "reserved#6", "reserved#7", \ + "reserved#8", "reserved#9", \ + "ps-poll", "rts", \ + "cts", "ack", \ + "cf-end", "cf-end-ack" \ +} + +#define IEEE80211_DATA_SUBTYPE_NAMES { \ + "data", "data-cf-ack", \ + "data-cf-poll", "data-cf-ack-poll", \ + "null", "cf-ack", \ + "cf-poll", "cf-ack-poll", \ + "qos-data", "qos-data-cf-ack", \ + "qos-data-cf-poll", "qos-data-cf-ack-poll", \ + "qos", "reserved#13", \ + "qos-cf-poll", "qos-cf-ack-poll" \ +} + +#define IEEE80211_TYPE_NAMES { "mgt", "ctl", "data", "reserved#4" } + +#endif /* _NET80211_IEEE80211_H_ */ diff --git a/tcpdump/jni/libpcap/inet.c b/tcpdump/jni/libpcap/inet.c new file mode 100644 index 0000000..e7d2104 --- /dev/null +++ b/tcpdump/jni/libpcap/inet.c @@ -0,0 +1,1101 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ + +#include +#ifndef MSDOS +#include +#endif +#include +#include +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif + +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ +#include +#include +#endif /* WIN32 */ + +#include +#include +#include +#include +#include +#include +#if !defined(WIN32) && !defined(__BORLANDC__) +#include +#endif /* !WIN32 && !__BORLANDC__ */ +#ifdef HAVE_LIMITS_H +#include +#else +#define INT_MAX 2147483647 +#endif + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* Not all systems have IFF_LOOPBACK */ +#ifdef IFF_LOOPBACK +#define ISLOOPBACK(name, flags) ((flags) & IFF_LOOPBACK) +#else +#define ISLOOPBACK(name, flags) ((name)[0] == 'l' && (name)[1] == 'o' && \ + (isdigit((unsigned char)((name)[2])) || (name)[2] == '\0')) +#endif + +#ifdef IFF_UP +#define ISUP(flags) ((flags) & IFF_UP) +#else +#define ISUP(flags) 0 +#endif + +#ifdef IFF_RUNNING +#define ISRUNNING(flags) ((flags) & IFF_RUNNING) +#else +#define ISRUNNING(flags) 0 +#endif + +struct sockaddr * +dup_sockaddr(struct sockaddr *sa, size_t sa_length) +{ + struct sockaddr *newsa; + + if ((newsa = malloc(sa_length)) == NULL) + return (NULL); + return (memcpy(newsa, sa, sa_length)); +} + +/* + * Construct a "figure of merit" for an interface, for use when sorting + * the list of interfaces, in which interfaces that are up are superior + * to interfaces that aren't up, interfaces that are up and running are + * superior to interfaces that are up but not running, and non-loopback + * interfaces that are up and running are superior to loopback interfaces, + * and interfaces with the same flags have a figure of merit that's higher + * the lower the instance number. + * + * The goal is to try to put the interfaces most likely to be useful for + * capture at the beginning of the list. + * + * The figure of merit, which is lower the "better" the interface is, + * has the uppermost bit set if the interface isn't running, the bit + * below that set if the interface isn't up, the bit below that set + * if the interface is a loopback interface, and the interface index + * in the 29 bits below that. (Yes, we assume u_int is 32 bits.) + */ +static u_int +get_figure_of_merit(pcap_if_t *dev) +{ + const char *cp; + u_int n; + + if (strcmp(dev->name, "any") == 0) { + /* + * Give the "any" device an artificially high instance + * number, so it shows up after all other non-loopback + * interfaces. + */ + n = 0x1FFFFFFF; /* 29 all-1 bits */ + } else { + /* + * A number at the end of the device name string is + * assumed to be a unit number. + */ + cp = dev->name + strlen(dev->name) - 1; + while (cp-1 >= dev->name && *(cp-1) >= '0' && *(cp-1) <= '9') + cp--; + if (*cp >= '0' && *cp <= '9') + n = atoi(cp); + else + n = 0; + } + if (!(dev->flags & PCAP_IF_RUNNING)) + n |= 0x80000000; + if (!(dev->flags & PCAP_IF_UP)) + n |= 0x40000000; + if (dev->flags & PCAP_IF_LOOPBACK) + n |= 0x20000000; + return (n); +} + +/* + * Look for a given device in the specified list of devices. + * + * If we find it, return 0 and set *curdev_ret to point to it. + * + * If we don't find it, check whether we can open it: + * + * If that fails with PCAP_ERROR_NO_SUCH_DEVICE or + * PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for + * it, as that probably means it exists but doesn't support + * packet capture. + * + * Otherwise, attempt to add an entry for it, with the specified + * ifnet flags and description, and, if that succeeds, return 0 + * and set *curdev_ret to point to the new entry, otherwise + * return PCAP_ERROR and set errbuf to an error message. + */ +int +add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, + u_int flags, const char *description, char *errbuf) +{ + pcap_t *p; + pcap_if_t *curdev, *prevdev, *nextdev; + u_int this_figure_of_merit, nextdev_figure_of_merit; + char open_errbuf[PCAP_ERRBUF_SIZE]; + int ret; + + /* + * Is there already an entry in the list for this interface? + */ + for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) { + if (strcmp(name, curdev->name) == 0) + break; /* yes, we found it */ + } + + if (curdev == NULL) { + /* + * No, we didn't find it. + * + * Can we open this interface for live capture? + * + * We do this check so that interfaces that are + * supplied by the interface enumeration mechanism + * we're using but that don't support packet capture + * aren't included in the list. Loopback interfaces + * on Solaris are an example of this; we don't just + * omit loopback interfaces on all platforms because + * you *can* capture on loopback interfaces on some + * OSes. + * + * On OS X, we don't do this check if the device + * name begins with "wlt"; at least some versions + * of OS X offer monitor mode capturing by having + * a separate "monitor mode" device for each wireless + * adapter, rather than by implementing the ioctls + * that {Free,Net,Open,DragonFly}BSD provide. + * Opening that device puts the adapter into monitor + * mode, which, at least for some adapters, causes + * them to deassociate from the network with which + * they're associated. + * + * Instead, we try to open the corresponding "en" + * device (so that we don't end up with, for users + * without sufficient privilege to open capture + * devices, a list of adapters that only includes + * the wlt devices). + */ +#ifdef __APPLE__ + if (strncmp(name, "wlt", 3) == 0) { + char *en_name; + size_t en_name_len; + + /* + * Try to allocate a buffer for the "en" + * device's name. + */ + en_name_len = strlen(name) - 1; + en_name = malloc(en_name_len + 1); + if (en_name == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + strcpy(en_name, "en"); + strcat(en_name, name + 3); + p = pcap_create(en_name, open_errbuf); + free(en_name); + } else +#endif /* __APPLE */ + p = pcap_create(name, open_errbuf); + if (p == NULL) { + /* + * The attempt to create the pcap_t failed; + * that's probably an indication that we're + * out of memory. + * + * Don't bother including this interface, + * but don't treat it as an error. + */ + *curdev_ret = NULL; + return (0); + } + /* Small snaplen, so we don't try to allocate much memory. */ + pcap_set_snaplen(p, 68); + ret = pcap_activate(p); + pcap_close(p); + switch (ret) { + + case PCAP_ERROR_NO_SUCH_DEVICE: + case PCAP_ERROR_IFACE_NOT_UP: + /* + * We expect these two errors - they're the + * reason we try to open the device. + * + * PCAP_ERROR_NO_SUCH_DEVICE typically means + * "there's no such device *known to the + * OS's capture mechanism*", so, even though + * it might be a valid network interface, you + * can't capture on it (e.g., the loopback + * device in Solaris up to Solaris 10, or + * the vmnet devices in OS X with VMware + * Fusion). We don't include those devices + * in our list of devices, as there's no + * point in doing so - they're not available + * for capture. + * + * PCAP_ERROR_IFACE_NOT_UP means that the + * OS's capture mechanism doesn't work on + * interfaces not marked as up; some capture + * mechanisms *do* support that, so we no + * longer reject those interfaces out of hand, + * but we *do* want to reject them if they + * can't be opened for capture. + */ + *curdev_ret = NULL; + return (0); + } + + /* + * Yes, we can open it, or we can't, for some other + * reason. + * + * If we can open it, we want to offer it for + * capture, as you can capture on it. If we can't, + * we want to offer it for capture, so that, if + * the user tries to capture on it, they'll get + * an error and they'll know why they can't + * capture on it (e.g., insufficient permissions) + * or they'll report it as a problem (and then + * have the error message to provide as information). + * + * Allocate a new entry. + */ + curdev = malloc(sizeof(pcap_if_t)); + if (curdev == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + + /* + * Fill in the entry. + */ + curdev->next = NULL; + curdev->name = strdup(name); + if (curdev->name == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + free(curdev); + return (-1); + } + if (description != NULL) { + /* + * We have a description for this interface. + */ + curdev->description = strdup(description); + if (curdev->description == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + free(curdev->name); + free(curdev); + return (-1); + } + } else { + /* + * We don't. + */ + curdev->description = NULL; + } + curdev->addresses = NULL; /* list starts out as empty */ + curdev->flags = 0; + if (ISLOOPBACK(name, flags)) + curdev->flags |= PCAP_IF_LOOPBACK; + if (ISUP(flags)) + curdev->flags |= PCAP_IF_UP; + if (ISRUNNING(flags)) + curdev->flags |= PCAP_IF_RUNNING; + + /* + * Add it to the list, in the appropriate location. + * First, get the "figure of merit" for this + * interface. + */ + this_figure_of_merit = get_figure_of_merit(curdev); + + /* + * Now look for the last interface with an figure of merit + * less than or equal to the new interface's figure of + * merit. + * + * We start with "prevdev" being NULL, meaning we're before + * the first element in the list. + */ + prevdev = NULL; + for (;;) { + /* + * Get the interface after this one. + */ + if (prevdev == NULL) { + /* + * The next element is the first element. + */ + nextdev = *alldevs; + } else + nextdev = prevdev->next; + + /* + * Are we at the end of the list? + */ + if (nextdev == NULL) { + /* + * Yes - we have to put the new entry + * after "prevdev". + */ + break; + } + + /* + * Is the new interface's figure of merit less + * than the next interface's figure of merit, + * meaning that the new interface is better + * than the next interface? + */ + nextdev_figure_of_merit = get_figure_of_merit(nextdev); + if (this_figure_of_merit < nextdev_figure_of_merit) { + /* + * Yes - we should put the new entry + * before "nextdev", i.e. after "prevdev". + */ + break; + } + + prevdev = nextdev; + } + + /* + * Insert before "nextdev". + */ + curdev->next = nextdev; + + /* + * Insert after "prevdev" - unless "prevdev" is null, + * in which case this is the first interface. + */ + if (prevdev == NULL) { + /* + * This is the first interface. Pass back a + * pointer to it, and put "curdev" before + * "nextdev". + */ + *alldevs = curdev; + } else + prevdev->next = curdev; + } + + *curdev_ret = curdev; + return (0); +} + +/* + * Try to get a description for a given device. + * Returns a mallocated description if it could and NULL if it couldn't. + * + * XXX - on FreeBSDs that support it, should it get the sysctl named + * "dev.{adapter family name}.{adapter unit}.%desc" to get a description + * of the adapter? Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800" + * with my Cisco 350 card, so the name isn't entirely descriptive. The + * "dev.an.0.%pnpinfo" has a better description, although one might argue + * that the problem is really a driver bug - if it can find out that it's + * a Cisco 340 or 350, rather than an old Aironet card, it should use + * that in the description. + * + * Do NetBSD, DragonflyBSD, or OpenBSD support this as well? FreeBSD + * and OpenBSD let you get a description, but it's not generated by the OS, + * it's set with another ioctl that ifconfig supports; we use that to get + * a description in FreeBSD and OpenBSD, but if there is no such + * description available, it still might be nice to get some description + * string based on the device type or something such as that. + * + * In OS X, the System Configuration framework can apparently return + * names in 10.4 and later. + * + * It also appears that freedesktop.org's HAL offers an "info.product" + * string, but the HAL specification says it "should not be used in any + * UI" and "subsystem/capability specific properties" should be used + * instead and, in any case, I think HAL is being deprecated in + * favor of other stuff such as DeviceKit. DeviceKit doesn't appear + * to have any obvious product information for devices, but maybe + * I haven't looked hard enough. + * + * Using the System Configuration framework, or HAL, or DeviceKit, or + * whatever, would require that libpcap applications be linked with + * the frameworks/libraries in question. That shouldn't be a problem + * for programs linking with the shared version of libpcap (unless + * you're running on AIX - which I think is the only UN*X that doesn't + * support linking a shared library with other libraries on which it + * depends, and having an executable linked only with the first shared + * library automatically pick up the other libraries when started - + * and using HAL or whatever). Programs linked with the static + * version of libpcap would have to use pcap-config with the --static + * flag in order to get the right linker flags in order to pick up + * the additional libraries/frameworks; those programs need that anyway + * for libpcap 1.1 and beyond on Linux, as, by default, it requires + * -lnl. + * + * Do any other UN*Xes, or desktop environments support getting a + * description? + */ +static char * +get_if_description(const char *name) +{ +#ifdef SIOCGIFDESCR + char *description = NULL; + int s; + struct ifreq ifrdesc; +#ifndef IFDESCRSIZE + size_t descrlen = 64; +#else + size_t descrlen = IFDESCRSIZE; +#endif /* IFDESCRSIZE */ + + /* + * Get the description for the interface. + */ + memset(&ifrdesc, 0, sizeof ifrdesc); + strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name); + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s >= 0) { +#ifdef __FreeBSD__ + /* + * On FreeBSD, if the buffer isn't big enough for the + * description, the ioctl succeeds, but the description + * isn't copied, ifr_buffer.length is set to the description + * length, and ifr_buffer.buffer is set to NULL. + */ + for (;;) { + free(description); + if ((description = malloc(descrlen)) != NULL) { + ifrdesc.ifr_buffer.buffer = description; + ifrdesc.ifr_buffer.length = descrlen; + if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) { + if (ifrdesc.ifr_buffer.buffer == + description) + break; + else + descrlen = ifrdesc.ifr_buffer.length; + } else { + /* + * Failed to get interface description. + */ + free(description); + description = NULL; + break; + } + } else + break; + } +#else /* __FreeBSD__ */ + /* + * The only other OS that currently supports + * SIOCGIFDESCR is OpenBSD, and it has no way + * to get the description length - it's clamped + * to a maximum of IFDESCRSIZE. + */ + if ((description = malloc(descrlen)) != NULL) { + ifrdesc.ifr_data = (caddr_t)description; + if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) { + /* + * Failed to get interface description. + */ + free(description); + description = NULL; + } + } +#endif /* __FreeBSD__ */ + close(s); + if (description != NULL && strlen(description) == 0) { + free(description); + description = NULL; + } + } + + return (description); +#else /* SIOCGIFDESCR */ + return (NULL); +#endif /* SIOCGIFDESCR */ +} + +/* + * Try to get a description for a given device, and then look for that + * device in the specified list of devices. + * + * If we find it, then, if the specified address isn't null, add it to + * the list of addresses for the device and return 0. + * + * If we don't find it, check whether we can open it: + * + * If that fails with PCAP_ERROR_NO_SUCH_DEVICE or + * PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for + * it, as that probably means it exists but doesn't support + * packet capture. + * + * Otherwise, attempt to add an entry for it, with the specified + * ifnet flags and description, and, if that succeeds, add the + * specified address to its list of addresses if that address is + * non-null, set *curdev_ret to point to the new entry, and + * return 0, otherwise return PCAP_ERROR and set errbuf to an + * error message. + * + * (We can get called with a null address because we might get a list + * of interface name/address combinations from the underlying OS, with + * the address being absent in some cases, rather than a list of + * interfaces with each interface having a list of addresses, so this + * call may be the only call made to add to the list, and we want to + * add interfaces even if they have no addresses.) + */ +int +add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, + struct sockaddr *addr, size_t addr_size, + struct sockaddr *netmask, size_t netmask_size, + struct sockaddr *broadaddr, size_t broadaddr_size, + struct sockaddr *dstaddr, size_t dstaddr_size, + char *errbuf) +{ + char *description; + pcap_if_t *curdev; + + description = get_if_description(name); + if (add_or_find_if(&curdev, alldevs, name, flags, description, + errbuf) == -1) { + free(description); + /* + * Error - give up. + */ + return (-1); + } + free(description); + if (curdev == NULL) { + /* + * Device wasn't added because it can't be opened. + * Not a fatal error. + */ + return (0); + } + + if (addr == NULL) { + /* + * There's no address to add; this entry just meant + * "here's a new interface". + */ + return (0); + } + + /* + * "curdev" is an entry for this interface, and we have an + * address for it; add an entry for that address to the + * interface's list of addresses. + * + * Allocate the new entry and fill it in. + */ + return (add_addr_to_dev(curdev, addr, addr_size, netmask, + netmask_size, broadaddr, broadaddr_size, dstaddr, + dstaddr_size, errbuf)); +} + +/* + * Add an entry to the list of addresses for an interface. + * "curdev" is the entry for that interface. + * If this is the first IP address added to the interface, move it + * in the list as appropriate. + */ +int +add_addr_to_dev(pcap_if_t *curdev, + struct sockaddr *addr, size_t addr_size, + struct sockaddr *netmask, size_t netmask_size, + struct sockaddr *broadaddr, size_t broadaddr_size, + struct sockaddr *dstaddr, size_t dstaddr_size, + char *errbuf) +{ + pcap_addr_t *curaddr, *prevaddr, *nextaddr; + + curaddr = malloc(sizeof(pcap_addr_t)); + if (curaddr == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + + curaddr->next = NULL; + if (addr != NULL) { + curaddr->addr = dup_sockaddr(addr, addr_size); + if (curaddr->addr == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + free(curaddr); + return (-1); + } + } else + curaddr->addr = NULL; + + if (netmask != NULL) { + curaddr->netmask = dup_sockaddr(netmask, netmask_size); + if (curaddr->netmask == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + if (curaddr->addr != NULL) + free(curaddr->addr); + free(curaddr); + return (-1); + } + } else + curaddr->netmask = NULL; + + if (broadaddr != NULL) { + curaddr->broadaddr = dup_sockaddr(broadaddr, broadaddr_size); + if (curaddr->broadaddr == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + if (curaddr->netmask != NULL) + free(curaddr->netmask); + if (curaddr->addr != NULL) + free(curaddr->addr); + free(curaddr); + return (-1); + } + } else + curaddr->broadaddr = NULL; + + if (dstaddr != NULL) { + curaddr->dstaddr = dup_sockaddr(dstaddr, dstaddr_size); + if (curaddr->dstaddr == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + if (curaddr->broadaddr != NULL) + free(curaddr->broadaddr); + if (curaddr->netmask != NULL) + free(curaddr->netmask); + if (curaddr->addr != NULL) + free(curaddr->addr); + free(curaddr); + return (-1); + } + } else + curaddr->dstaddr = NULL; + + /* + * Find the end of the list of addresses. + */ + for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) { + nextaddr = prevaddr->next; + if (nextaddr == NULL) { + /* + * This is the end of the list. + */ + break; + } + } + + if (prevaddr == NULL) { + /* + * The list was empty; this is the first member. + */ + curdev->addresses = curaddr; + } else { + /* + * "prevaddr" is the last member of the list; append + * this member to it. + */ + prevaddr->next = curaddr; + } + + return (0); +} + +/* + * Look for a given device in the specified list of devices. + * + * If we find it, return 0. + * + * If we don't find it, check whether we can open it: + * + * If that fails with PCAP_ERROR_NO_SUCH_DEVICE or + * PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for + * it, as that probably means it exists but doesn't support + * packet capture. + * + * Otherwise, attempt to add an entry for it, with the specified + * ifnet flags and description, and, if that succeeds, return 0 + * and set *curdev_ret to point to the new entry, otherwise + * return PCAP_ERROR and set errbuf to an error message. + */ +int +pcap_add_if(pcap_if_t **devlist, const char *name, u_int flags, + const char *description, char *errbuf) +{ + pcap_if_t *curdev; + + return (add_or_find_if(&curdev, devlist, name, flags, description, + errbuf)); +} + + +/* + * Free a list of interfaces. + */ +void +pcap_freealldevs(pcap_if_t *alldevs) +{ + pcap_if_t *curdev, *nextdev; + pcap_addr_t *curaddr, *nextaddr; + + for (curdev = alldevs; curdev != NULL; curdev = nextdev) { + nextdev = curdev->next; + + /* + * Free all addresses. + */ + for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) { + nextaddr = curaddr->next; + if (curaddr->addr) + free(curaddr->addr); + if (curaddr->netmask) + free(curaddr->netmask); + if (curaddr->broadaddr) + free(curaddr->broadaddr); + if (curaddr->dstaddr) + free(curaddr->dstaddr); + free(curaddr); + } + + /* + * Free the name string. + */ + free(curdev->name); + + /* + * Free the description string, if any. + */ + if (curdev->description != NULL) + free(curdev->description); + + /* + * Free the interface. + */ + free(curdev); + } +} + +#if !defined(WIN32) && !defined(MSDOS) + +/* + * Return the name of a network interface attached to the system, or NULL + * if none can be found. The interface must be configured up; the + * lowest unit number is preferred; loopback is ignored. + */ +char * +pcap_lookupdev(errbuf) + register char *errbuf; +{ + pcap_if_t *alldevs; +/* for old BSD systems, including bsdi3 */ +#ifndef IF_NAMESIZE +#define IF_NAMESIZE IFNAMSIZ +#endif + static char device[IF_NAMESIZE + 1]; + char *ret; + + if (pcap_findalldevs(&alldevs, errbuf) == -1) + return (NULL); + + if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) { + /* + * There are no devices on the list, or the first device + * on the list is a loopback device, which means there + * are no non-loopback devices on the list. This means + * we can't return any device. + * + * XXX - why not return a loopback device? If we can't + * capture on it, it won't be on the list, and if it's + * on the list, there aren't any non-loopback devices, + * so why not just supply it as the default device? + */ + (void)strlcpy(errbuf, "no suitable device found", + PCAP_ERRBUF_SIZE); + ret = NULL; + } else { + /* + * Return the name of the first device on the list. + */ + (void)strlcpy(device, alldevs->name, sizeof(device)); + ret = device; + } + + pcap_freealldevs(alldevs); + return (ret); +} + +int +pcap_lookupnet(device, netp, maskp, errbuf) + register const char *device; + register bpf_u_int32 *netp, *maskp; + register char *errbuf; +{ + register int fd; + register struct sockaddr_in *sin4; + struct ifreq ifr; + + /* + * The pseudo-device "any" listens on all interfaces and therefore + * has the network address and -mask "0.0.0.0" therefore catching + * all traffic. Using NULL for the interface is the same as "any". + */ + if (!device || strcmp(device, "any") == 0 +#ifdef HAVE_DAG_API + || strstr(device, "dag") != NULL +#endif +#ifdef HAVE_SEPTEL_API + || strstr(device, "septel") != NULL +#endif +#ifdef PCAP_SUPPORT_BT + || strstr(device, "bluetooth") != NULL +#endif +#ifdef PCAP_SUPPORT_USB + || strstr(device, "usbmon") != NULL +#endif +#ifdef HAVE_SNF_API + || strstr(device, "snf") != NULL +#endif + ) { + *netp = *maskp = 0; + return 0; + } + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", + pcap_strerror(errno)); + return (-1); + } + memset(&ifr, 0, sizeof(ifr)); +#ifdef linux + /* XXX Work around Linux kernel bug */ + ifr.ifr_addr.sa_family = AF_INET; +#endif + (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { + if (errno == EADDRNOTAVAIL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "%s: no IPv4 address assigned", device); + } else { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFADDR: %s: %s", + device, pcap_strerror(errno)); + } + (void)close(fd); + return (-1); + } + sin4 = (struct sockaddr_in *)&ifr.ifr_addr; + *netp = sin4->sin_addr.s_addr; + memset(&ifr, 0, sizeof(ifr)); +#ifdef linux + /* XXX Work around Linux kernel bug */ + ifr.ifr_addr.sa_family = AF_INET; +#endif + (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno)); + (void)close(fd); + return (-1); + } + (void)close(fd); + *maskp = sin4->sin_addr.s_addr; + if (*maskp == 0) { + if (IN_CLASSA(*netp)) + *maskp = IN_CLASSA_NET; + else if (IN_CLASSB(*netp)) + *maskp = IN_CLASSB_NET; + else if (IN_CLASSC(*netp)) + *maskp = IN_CLASSC_NET; + else { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "inet class for 0x%x unknown", *netp); + return (-1); + } + } + *netp &= *maskp; + return (0); +} + +#elif defined(WIN32) + +/* + * Return the name of a network interface attached to the system, or NULL + * if none can be found. The interface must be configured up; the + * lowest unit number is preferred; loopback is ignored. + */ +char * +pcap_lookupdev(errbuf) + register char *errbuf; +{ + DWORD dwVersion; + DWORD dwWindowsMajorVersion; + dwVersion = GetVersion(); /* get the OS version */ + dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); + + if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) { + /* + * Windows 95, 98, ME. + */ + ULONG NameLength = 8192; + static char AdaptersName[8192]; + + if (PacketGetAdapterNames(AdaptersName,&NameLength) ) + return (AdaptersName); + else + return NULL; + } else { + /* + * Windows NT (NT 4.0, W2K, WXP). Convert the names to UNICODE for backward compatibility + */ + ULONG NameLength = 8192; + static WCHAR AdaptersName[8192]; + char *tAstr; + WCHAR *tUstr; + WCHAR *TAdaptersName = (WCHAR*)malloc(8192 * sizeof(WCHAR)); + int NAdapts = 0; + + if(TAdaptersName == NULL) + { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure"); + return NULL; + } + + if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) ) + { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "PacketGetAdapterNames: %s", + pcap_win32strerror()); + free(TAdaptersName); + return NULL; + } + + + tAstr = (char*)TAdaptersName; + tUstr = (WCHAR*)AdaptersName; + + /* + * Convert and copy the device names + */ + while(sscanf(tAstr, "%S", tUstr) > 0) + { + tAstr += strlen(tAstr) + 1; + tUstr += wcslen(tUstr) + 1; + NAdapts ++; + } + + tAstr++; + *tUstr = 0; + tUstr++; + + /* + * Copy the descriptions + */ + while(NAdapts--) + { + char* tmp = (char*)tUstr; + strcpy(tmp, tAstr); + tmp += strlen(tAstr) + 1; + tUstr = (WCHAR*)tmp; + tAstr += strlen(tAstr) + 1; + } + + free(TAdaptersName); + return (char *)(AdaptersName); + } +} + + +int +pcap_lookupnet(device, netp, maskp, errbuf) + register const char *device; + register bpf_u_int32 *netp, *maskp; + register char *errbuf; +{ + /* + * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo() + * in order to skip non IPv4 (i.e. IPv6 addresses) + */ + npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; + LONG if_addr_size = 1; + struct sockaddr_in *t_addr; + unsigned int i; + + if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) { + *netp = *maskp = 0; + return (0); + } + + for(i=0; isin_addr.S_un.S_addr; + t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask); + *maskp = t_addr->sin_addr.S_un.S_addr; + + *netp &= *maskp; + return (0); + } + + } + + *netp = *maskp = 0; + return (0); +} + +#endif /* !WIN32 && !MSDOS */ diff --git a/tcpdump/jni/libpcap/install-sh b/tcpdump/jni/libpcap/install-sh new file mode 100755 index 0000000..b44de09 --- /dev/null +++ b/tcpdump/jni/libpcap/install-sh @@ -0,0 +1,250 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/tcpdump/jni/libpcap/lbl/os-aix4.h b/tcpdump/jni/libpcap/lbl/os-aix4.h new file mode 100644 index 0000000..5cf4586 --- /dev/null +++ b/tcpdump/jni/libpcap/lbl/os-aix4.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in AIX 4.x */ +int ffs(int i); diff --git a/tcpdump/jni/libpcap/lbl/os-hpux11.h b/tcpdump/jni/libpcap/lbl/os-hpux11.h new file mode 100644 index 0000000..42c6b60 --- /dev/null +++ b/tcpdump/jni/libpcap/lbl/os-hpux11.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in HP-UX 11.x */ +int ffs(int i); diff --git a/tcpdump/jni/libpcap/lbl/os-osf4.h b/tcpdump/jni/libpcap/lbl/os-osf4.h new file mode 100644 index 0000000..f461eea --- /dev/null +++ b/tcpdump/jni/libpcap/lbl/os-osf4.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in Digital UNIX 4.x */ +int snprintf(char *, size_t, const char *, ...); +int vsnprintf(char *, size_t, const char *, va_list); +int pfopen(char *, int); + diff --git a/tcpdump/jni/libpcap/lbl/os-osf5.h b/tcpdump/jni/libpcap/lbl/os-osf5.h new file mode 100644 index 0000000..52ab175 --- /dev/null +++ b/tcpdump/jni/libpcap/lbl/os-osf5.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Prototypes missing in Tru64 UNIX 5.x + * XXX - "snprintf()" and "vsnprintf()" aren't missing, but you have to + * #define the right value to get them defined by . + */ +int snprintf(char *, size_t, const char *, ...); +int vsnprintf(char *, size_t, const char *, va_list); +int pfopen(char *, int); + diff --git a/tcpdump/jni/libpcap/lbl/os-solaris2.h b/tcpdump/jni/libpcap/lbl/os-solaris2.h new file mode 100644 index 0000000..22948b4 --- /dev/null +++ b/tcpdump/jni/libpcap/lbl/os-solaris2.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in SunOS 5 */ +char *strerror(int); +int snprintf(char *, size_t, const char *, ...); diff --git a/tcpdump/jni/libpcap/lbl/os-sunos4.h b/tcpdump/jni/libpcap/lbl/os-sunos4.h new file mode 100644 index 0000000..b735857 --- /dev/null +++ b/tcpdump/jni/libpcap/lbl/os-sunos4.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 1989, 1990, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in SunOS 4 */ +#ifdef FILE +int _filbuf(FILE *); +int _flsbuf(u_char, FILE *); +int fclose(FILE *); +int fflush(FILE *); +int fgetc(FILE *); +int fprintf(FILE *, const char *, ...); +int fputc(int, FILE *); +int fputs(const char *, FILE *); +u_int fread(void *, u_int, u_int, FILE *); +int fseek(FILE *, long, int); +u_int fwrite(const void *, u_int, u_int, FILE *); +int pclose(FILE *); +void rewind(FILE *); +void setbuf(FILE *, char *); +int setlinebuf(FILE *); +int ungetc(int, FILE *); +int vfprintf(FILE *, const char *, ...); +int vprintf(const char *, ...); +#endif + +#if __GNUC__ <= 1 +int read(int, char *, u_int); +int write(int, char *, u_int); +#endif + +long a64l(const char *); +#ifdef __STDC__ +struct sockaddr; +#endif +int accept(int, struct sockaddr *, int *); +int bind(int, struct sockaddr *, int); +int bcmp(const void *, const void *, u_int); +void bcopy(const void *, void *, u_int); +void bzero(void *, int); +int chroot(const char *); +int close(int); +void closelog(void); +int connect(int, struct sockaddr *, int); +char *crypt(const char *, const char *); +int daemon(int, int); +int fchmod(int, int); +int fchown(int, int, int); +void endgrent(void); +void endpwent(void); +void endservent(void); +#ifdef __STDC__ +struct ether_addr; +#endif +struct ether_addr *ether_aton(const char *); +int flock(int, int); +#ifdef __STDC__ +struct stat; +#endif +int fstat(int, struct stat *); +#ifdef __STDC__ +struct statfs; +#endif +int fstatfs(int, struct statfs *); +int fsync(int); +#ifdef __STDC__ +struct timeb; +#endif +int ftime(struct timeb *); +int ftruncate(int, off_t); +int getdtablesize(void); +long gethostid(void); +int gethostname(char *, int); +int getopt(int, char * const *, const char *); +int getpagesize(void); +char *getpass(char *); +int getpeername(int, struct sockaddr *, int *); +int getpriority(int, int); +#ifdef __STDC__ +struct rlimit; +#endif +int getrlimit(int, struct rlimit *); +int getsockname(int, struct sockaddr *, int *); +int getsockopt(int, int, int, char *, int *); +#ifdef __STDC__ +struct timeval; +struct timezone; +#endif +int gettimeofday(struct timeval *, struct timezone *); +char *getusershell(void); +char *getwd(char *); +int initgroups(const char *, int); +int ioctl(int, int, caddr_t); +int iruserok(u_long, int, char *, char *); +int isatty(int); +int killpg(int, int); +int listen(int, int); +#ifdef __STDC__ +struct utmp; +#endif +void login(struct utmp *); +int logout(const char *); +off_t lseek(int, off_t, int); +int lstat(const char *, struct stat *); +int mkstemp(char *); +char *mktemp(char *); +int munmap(caddr_t, int); +void openlog(const char *, int, int); +void perror(const char *); +int printf(const char *, ...); +int puts(const char *); +long random(void); +int readlink(const char *, char *, int); +#ifdef __STDC__ +struct iovec; +#endif +int readv(int, struct iovec *, int); +int recv(int, char *, u_int, int); +int recvfrom(int, char *, u_int, int, struct sockaddr *, int *); +int rename(const char *, const char *); +int rcmd(char **, u_short, char *, char *, char *, int *); +int rresvport(int *); +int send(int, char *, u_int, int); +int sendto(int, char *, u_int, int, struct sockaddr *, int); +int setenv(const char *, const char *, int); +int seteuid(int); +int setpriority(int, int, int); +int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +int setpgrp(int, int); +void setpwent(void); +int setrlimit(int, struct rlimit *); +void setservent(int); +int setsockopt(int, int, int, char *, int); +int shutdown(int, int); +int sigblock(int); +void (*signal (int, void (*) (int))) (int); +int sigpause(int); +int sigsetmask(int); +#ifdef __STDC__ +struct sigvec; +#endif +int sigvec(int, struct sigvec *, struct sigvec*); +int snprintf(char *, size_t, const char *, ...); +int socket(int, int, int); +int socketpair(int, int, int, int *); +int symlink(const char *, const char *); +void srandom(int); +int sscanf(char *, const char *, ...); +int stat(const char *, struct stat *); +int statfs(char *, struct statfs *); +char *strerror(int); +int strcasecmp(const char *, const char *); +#ifdef __STDC__ +struct tm; +#endif +int strftime(char *, int, char *, struct tm *); +int strncasecmp(const char *, const char *, int); +long strtol(const char *, char **, int); +void sync(void); +void syslog(int, const char *, ...); +int system(const char *); +long tell(int); +time_t time(time_t *); +char *timezone(int, int); +int tolower(int); +int toupper(int); +int truncate(char *, off_t); +void unsetenv(const char *); +int vfork(void); +int vsprintf(char *, const char *, ...); +int writev(int, struct iovec *, int); +#ifdef __STDC__ +struct rusage; +#endif +int utimes(const char *, struct timeval *); +#if __GNUC__ <= 1 +int wait(int *); +pid_t wait3(int *, int, struct rusage *); +#endif + +/* Ugly signal hacking */ +#ifdef SIG_ERR +#undef SIG_ERR +#define SIG_ERR (void (*)(int))-1 +#undef SIG_DFL +#define SIG_DFL (void (*)(int))0 +#undef SIG_IGN +#define SIG_IGN (void (*)(int))1 + +#ifdef KERNEL +#undef SIG_CATCH +#define SIG_CATCH (void (*)(int))2 +#endif +#undef SIG_HOLD +#define SIG_HOLD (void (*)(int))3 +#endif diff --git a/tcpdump/jni/libpcap/lbl/os-ultrix4.h b/tcpdump/jni/libpcap/lbl/os-ultrix4.h new file mode 100644 index 0000000..fa1f770 --- /dev/null +++ b/tcpdump/jni/libpcap/lbl/os-ultrix4.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in Ultrix 4 */ +int bcmp(const char *, const char *, u_int); +void bcopy(const void *, void *, u_int); +void bzero(void *, u_int); +void endservent(void); +int getopt(int, char * const *, const char *); +#ifdef __STDC__ +struct timeval; +struct timezone; +#endif +int gettimeofday(struct timeval *, struct timezone *); +int ioctl(int, int, caddr_t); +int pfopen(char *, int); +int setlinebuf(FILE *); +int socket(int, int, int); +int strcasecmp(const char *, const char *); diff --git a/tcpdump/jni/libpcap/llc.h b/tcpdump/jni/libpcap/llc.h new file mode 100644 index 0000000..b0cf881 --- /dev/null +++ b/tcpdump/jni/libpcap/llc.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1993, 1994, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Definitions for information in the LLC header. + */ + +#define LLC_U_FMT 3 +#define LLC_GSAP 1 +#define LLC_IG 1 /* Individual / Group */ +#define LLC_S_FMT 1 + +#define LLC_U_POLL 0x10 +#define LLC_IS_POLL 0x0100 +#define LLC_XID_FI 0x81 + +#define LLC_U_CMD_MASK 0xef +#define LLC_UI 0x03 +#define LLC_UA 0x63 +#define LLC_DISC 0x43 +#define LLC_DM 0x0f +#define LLC_SABME 0x6f +#define LLC_TEST 0xe3 +#define LLC_XID 0xaf +#define LLC_FRMR 0x87 + +#define LLC_S_CMD_MASK 0x0f +#define LLC_RR 0x0001 +#define LLC_RNR 0x0005 +#define LLC_REJ 0x0009 + +#define LLC_IS_NR(is) (((is) >> 9) & 0x7f) +#define LLC_I_NS(is) (((is) >> 1) & 0x7f) + +/* + * 802.2 LLC SAP values. + */ + +#ifndef LLCSAP_NULL +#define LLCSAP_NULL 0x00 +#endif +#ifndef LLCSAP_GLOBAL +#define LLCSAP_GLOBAL 0xff +#endif +#ifndef LLCSAP_8021B_I +#define LLCSAP_8021B_I 0x02 +#endif +#ifndef LLCSAP_8021B_G +#define LLCSAP_8021B_G 0x03 +#endif +#ifndef LLCSAP_IP +#define LLCSAP_IP 0x06 +#endif +#ifndef LLCSAP_PROWAYNM +#define LLCSAP_PROWAYNM 0x0e +#endif +#ifndef LLCSAP_8021D +#define LLCSAP_8021D 0x42 +#endif +#ifndef LLCSAP_RS511 +#define LLCSAP_RS511 0x4e +#endif +#ifndef LLCSAP_ISO8208 +#define LLCSAP_ISO8208 0x7e +#endif +#ifndef LLCSAP_PROWAY +#define LLCSAP_PROWAY 0x8e +#endif +#ifndef LLCSAP_SNAP +#define LLCSAP_SNAP 0xaa +#endif +#ifndef LLCSAP_IPX +#define LLCSAP_IPX 0xe0 +#endif +#ifndef LLCSAP_NETBEUI +#define LLCSAP_NETBEUI 0xf0 +#endif +#ifndef LLCSAP_ISONS +#define LLCSAP_ISONS 0xfe +#endif diff --git a/tcpdump/jni/libpcap/missing/snprintf.c b/tcpdump/jni/libpcap/missing/snprintf.c new file mode 100644 index 0000000..9b63f8b --- /dev/null +++ b/tcpdump/jni/libpcap/missing/snprintf.c @@ -0,0 +1,625 @@ +/* + * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +enum format_flags { + minus_flag = 1, + plus_flag = 2, + space_flag = 4, + alternate_flag = 8, + zero_flag = 16 +}; + +/* + * Common state + */ + +struct state { + unsigned char *str; + unsigned char *s; + unsigned char *theend; + size_t sz; + size_t max_sz; + int (*append_char)(struct state *, unsigned char); + int (*reserve)(struct state *, size_t); + /* XXX - methods */ +}; + +#ifndef HAVE_VSNPRINTF +static int +sn_reserve (struct state *state, size_t n) +{ + return state->s + n > state->theend; +} + +static int +sn_append_char (struct state *state, unsigned char c) +{ + if (sn_reserve (state, 1)) { + return 1; + } else { + *state->s++ = c; + return 0; + } +} +#endif + +#if 0 +static int +as_reserve (struct state *state, size_t n) +{ + if (state->s + n > state->theend) { + int off = state->s - state->str; + unsigned char *tmp; + + if (state->max_sz && state->sz >= state->max_sz) + return 1; + + state->sz = max(state->sz * 2, state->sz + n); + if (state->max_sz) + state->sz = min(state->sz, state->max_sz); + tmp = realloc (state->str, state->sz); + if (tmp == NULL) + return 1; + state->str = tmp; + state->s = state->str + off; + state->theend = state->str + state->sz - 1; + } + return 0; +} + +static int +as_append_char (struct state *state, unsigned char c) +{ + if(as_reserve (state, 1)) + return 1; + else { + *state->s++ = c; + return 0; + } +} +#endif + +static int +append_number(struct state *state, + unsigned long num, unsigned base, char *rep, + int width, int prec, int flags, int minusp) +{ + int len = 0; + int i; + + /* given precision, ignore zero flag */ + if(prec != -1) + flags &= ~zero_flag; + else + prec = 1; + /* zero value with zero precision -> "" */ + if(prec == 0 && num == 0) + return 0; + do{ + if((*state->append_char)(state, rep[num % base])) + return 1; + len++; + num /= base; + }while(num); + prec -= len; + /* pad with prec zeros */ + while(prec-- > 0){ + if((*state->append_char)(state, '0')) + return 1; + len++; + } + /* add length of alternate prefix (added later) to len */ + if(flags & alternate_flag && (base == 16 || base == 8)) + len += base / 8; + /* pad with zeros */ + if(flags & zero_flag){ + width -= len; + if(minusp || (flags & space_flag) || (flags & plus_flag)) + width--; + while(width-- > 0){ + if((*state->append_char)(state, '0')) + return 1; + len++; + } + } + /* add alternate prefix */ + if(flags & alternate_flag && (base == 16 || base == 8)){ + if(base == 16) + if((*state->append_char)(state, rep[10] + 23)) /* XXX */ + return 1; + if((*state->append_char)(state, '0')) + return 1; + } + /* add sign */ + if(minusp){ + if((*state->append_char)(state, '-')) + return 1; + len++; + } else if(flags & plus_flag) { + if((*state->append_char)(state, '+')) + return 1; + len++; + } else if(flags & space_flag) { + if((*state->append_char)(state, ' ')) + return 1; + len++; + } + if(flags & minus_flag) + /* swap before padding with spaces */ + for(i = 0; i < len / 2; i++){ + char c = state->s[-i-1]; + state->s[-i-1] = state->s[-len+i]; + state->s[-len+i] = c; + } + width -= len; + while(width-- > 0){ + if((*state->append_char)(state, ' ')) + return 1; + len++; + } + if(!(flags & minus_flag)) + /* swap after padding with spaces */ + for(i = 0; i < len / 2; i++){ + char c = state->s[-i-1]; + state->s[-i-1] = state->s[-len+i]; + state->s[-len+i] = c; + } + + return 0; +} + +static int +append_string (struct state *state, + unsigned char *arg, + int width, + int prec, + int flags) +{ + if(prec != -1) + width -= prec; + else + width -= strlen((char *)arg); + if(!(flags & minus_flag)) + while(width-- > 0) + if((*state->append_char) (state, ' ')) + return 1; + if (prec != -1) { + while (*arg && prec--) + if ((*state->append_char) (state, *arg++)) + return 1; + } else { + while (*arg) + if ((*state->append_char) (state, *arg++)) + return 1; + } + if(flags & minus_flag) + while(width-- > 0) + if((*state->append_char) (state, ' ')) + return 1; + return 0; +} + +static int +append_char(struct state *state, + unsigned char arg, + int width, + int flags) +{ + while(!(flags & minus_flag) && --width > 0) + if((*state->append_char) (state, ' ')) + return 1; + + if((*state->append_char) (state, arg)) + return 1; + while((flags & minus_flag) && --width > 0) + if((*state->append_char) (state, ' ')) + return 1; + + return 0; +} + +/* + * This can't be made into a function... + */ + +#define PARSE_INT_FORMAT(res, arg, unsig) \ +if (long_flag) \ + res = (unsig long)va_arg(arg, unsig long); \ +else if (short_flag) \ + res = (unsig short)va_arg(arg, unsig int); \ +else \ + res = (unsig int)va_arg(arg, unsig int) + +/* + * zyxprintf - return 0 or -1 + */ + +static int +xyzprintf (struct state *state, const char *char_format, va_list ap) +{ + const unsigned char *format = (const unsigned char *)char_format; + unsigned char c; + + while((c = *format++)) { + if (c == '%') { + int flags = 0; + int width = 0; + int prec = -1; + int long_flag = 0; + int short_flag = 0; + + /* flags */ + while((c = *format++)){ + if(c == '-') + flags |= minus_flag; + else if(c == '+') + flags |= plus_flag; + else if(c == ' ') + flags |= space_flag; + else if(c == '#') + flags |= alternate_flag; + else if(c == '0') + flags |= zero_flag; + else + break; + } + + if((flags & space_flag) && (flags & plus_flag)) + flags ^= space_flag; + + if((flags & minus_flag) && (flags & zero_flag)) + flags ^= zero_flag; + + /* width */ + if (isdigit(c)) + do { + width = width * 10 + c - '0'; + c = *format++; + } while(isdigit(c)); + else if(c == '*') { + width = va_arg(ap, int); + c = *format++; + } + + /* precision */ + if (c == '.') { + prec = 0; + c = *format++; + if (isdigit(c)) + do { + prec = prec * 10 + c - '0'; + c = *format++; + } while(isdigit(c)); + else if (c == '*') { + prec = va_arg(ap, int); + c = *format++; + } + } + + /* size */ + + if (c == 'h') { + short_flag = 1; + c = *format++; + } else if (c == 'l') { + long_flag = 1; + c = *format++; + } + + switch (c) { + case 'c' : + if(append_char(state, va_arg(ap, int), width, flags)) + return -1; + break; + case 's' : + if (append_string(state, + va_arg(ap, unsigned char*), + width, + prec, + flags)) + return -1; + break; + case 'd' : + case 'i' : { + long arg; + unsigned long num; + int minusp = 0; + + PARSE_INT_FORMAT(arg, ap, signed); + + if (arg < 0) { + minusp = 1; + num = -arg; + } else + num = arg; + + if (append_number (state, num, 10, "0123456789", + width, prec, flags, minusp)) + return -1; + break; + } + case 'u' : { + unsigned long arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + if (append_number (state, arg, 10, "0123456789", + width, prec, flags, 0)) + return -1; + break; + } + case 'o' : { + unsigned long arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + if (append_number (state, arg, 010, "01234567", + width, prec, flags, 0)) + return -1; + break; + } + case 'x' : { + unsigned long arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + if (append_number (state, arg, 0x10, "0123456789abcdef", + width, prec, flags, 0)) + return -1; + break; + } + case 'X' :{ + unsigned long arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + if (append_number (state, arg, 0x10, "0123456789ABCDEF", + width, prec, flags, 0)) + return -1; + break; + } + case 'p' : { + unsigned long arg = (unsigned long)va_arg(ap, void*); + + if (append_number (state, arg, 0x10, "0123456789ABCDEF", + width, prec, flags, 0)) + return -1; + break; + } + case 'n' : { + int *arg = va_arg(ap, int*); + *arg = state->s - state->str; + break; + } + case '\0' : + --format; + /* FALLTHROUGH */ + case '%' : + if ((*state->append_char)(state, c)) + return -1; + break; + default : + if ( (*state->append_char)(state, '%') + || (*state->append_char)(state, c)) + return -1; + break; + } + } else + if ((*state->append_char) (state, c)) + return -1; + } + return 0; +} + +#ifndef HAVE_SNPRINTF +int +snprintf (char *str, size_t sz, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + ret = vsnprintf (str, sz, format, args); + +#ifdef PARANOIA + { + int ret2; + char *tmp; + + tmp = malloc (sz); + if (tmp == NULL) + abort (); + + ret2 = vsprintf (tmp, format, args); + if (ret != ret2 || strcmp(str, tmp)) + abort (); + free (tmp); + } +#endif + + va_end(args); + return ret; +} +#endif + +#if 0 +#ifndef HAVE_ASPRINTF +int +asprintf (char **ret, const char *format, ...) +{ + va_list args; + int val; + + va_start(args, format); + val = vasprintf (ret, format, args); + +#ifdef PARANOIA + { + int ret2; + char *tmp; + tmp = malloc (val + 1); + if (tmp == NULL) + abort (); + + ret2 = vsprintf (tmp, format, args); + if (val != ret2 || strcmp(*ret, tmp)) + abort (); + free (tmp); + } +#endif + + va_end(args); + return val; +} +#endif + +#ifndef HAVE_ASNPRINTF +int +asnprintf (char **ret, size_t max_sz, const char *format, ...) +{ + va_list args; + int val; + + va_start(args, format); + val = vasnprintf (ret, max_sz, format, args); + +#ifdef PARANOIA + { + int ret2; + char *tmp; + tmp = malloc (val + 1); + if (tmp == NULL) + abort (); + + ret2 = vsprintf (tmp, format, args); + if (val != ret2 || strcmp(*ret, tmp)) + abort (); + free (tmp); + } +#endif + + va_end(args); + return val; +} +#endif + +#ifndef HAVE_VASPRINTF +int +vasprintf (char **ret, const char *format, va_list args) +{ + return vasnprintf (ret, 0, format, args); +} +#endif + + +#ifndef HAVE_VASNPRINTF +int +vasnprintf (char **ret, size_t max_sz, const char *format, va_list args) +{ + int st; + size_t len; + struct state state; + + state.max_sz = max_sz; + state.sz = 1; + state.str = malloc(state.sz); + if (state.str == NULL) { + *ret = NULL; + return -1; + } + state.s = state.str; + state.theend = state.s + state.sz - 1; + state.append_char = as_append_char; + state.reserve = as_reserve; + + st = xyzprintf (&state, format, args); + if (st) { + free (state.str); + *ret = NULL; + return -1; + } else { + char *tmp; + + *state.s = '\0'; + len = state.s - state.str; + tmp = realloc (state.str, len+1); + if (tmp == NULL) { + free (state.str); + *ret = NULL; + return -1; + } + *ret = tmp; + return len; + } +} +#endif +#endif + +#ifndef HAVE_VSNPRINTF +int +vsnprintf (char *str, size_t sz, const char *format, va_list args) +{ + struct state state; + int ret; + unsigned char *ustr = (unsigned char *)str; + + state.max_sz = 0; + state.sz = sz; + state.str = ustr; + state.s = ustr; + state.theend = ustr + sz - 1; + state.append_char = sn_append_char; + state.reserve = sn_reserve; + + ret = xyzprintf (&state, format, args); + *state.s = '\0'; + if (ret) + return sz; + else + return state.s - state.str; +} +#endif + diff --git a/tcpdump/jni/libpcap/mkdep b/tcpdump/jni/libpcap/mkdep new file mode 100755 index 0000000..1486b18 --- /dev/null +++ b/tcpdump/jni/libpcap/mkdep @@ -0,0 +1,112 @@ +#!/bin/sh - +# +# Copyright (c) 1994, 1996 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that this notice is preserved and that due credit is given +# to the University of California at Berkeley. The name of the University +# may not be used to endorse or promote products derived from this +# software without specific prior written permission. This software +# is provided ``as is'' without express or implied warranty. +# +# @(#)mkdep.sh 5.11 (Berkeley) 5/5/88 +# + +MAKE=Makefile # default makefile name is "Makefile" +CC=cc # default C compiler is "cc" +DEPENDENCY_CFLAG=-M # default dependency-generation flag is -M + +while : + do case "$1" in + # -c allows you to specify the C compiler + -c) + CC=$2 + shift; shift ;; + + # -f allows you to select a makefile name + -f) + MAKE=$2 + shift; shift ;; + + # -m allows you to specify the dependency-generation flag + -m) + DEPENDENCY_CFLAG=$2 + shift; shift ;; + + # the -p flag produces "program: program.c" style dependencies + # so .o's don't get produced + -p) + SED='s;\.o;;' + shift ;; + *) + break ;; + esac +done + +if [ $# = 0 ] ; then + echo 'usage: mkdep [-p] [-c cc] [-f makefile] [-m dependency-cflag] [flags] file ...' + exit 1 +fi + +if [ ! -w $MAKE ]; then + echo "mkdep: no writeable file \"$MAKE\"" + exit 1 +fi + +TMP=/tmp/mkdep$$ + +trap 'rm -f $TMP ; exit 1' 1 2 3 13 15 + +cp $MAKE ${MAKE}.bak + +sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP + +cat << _EOF_ >> $TMP +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +_EOF_ + +# If your compiler doesn't have -M, add it. If you can't, the next two +# lines will try and replace the "cc -M". The real problem is that this +# hack can't deal with anything that requires a search path, and doesn't +# even try for anything using bracket (<>) syntax. +# +# egrep '^#include[ ]*".*"' /dev/null $* | +# sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' | + +# XXX this doesn't work with things like "-DDECLWAITSTATUS=union\ wait" +$CC $DEPENDENCY_CFLAG $* | +sed " + s; \./; ;g + $SED" | +awk '{ + if ($1 != prev) { + if (rec != "") + print rec; + rec = $0; + prev = $1; + } + else { + if (length(rec $2) > 78) { + print rec; + rec = $0; + } + else + rec = rec " " $2 + } +} +END { + print rec +}' >> $TMP + +cat << _EOF_ >> $TMP + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY +_EOF_ + +# copy to preserve permissions +cp $TMP $MAKE +rm -f ${MAKE}.bak $TMP +exit 0 diff --git a/tcpdump/jni/libpcap/msdos/bin2c.c b/tcpdump/jni/libpcap/msdos/bin2c.c new file mode 100644 index 0000000..d82056e --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/bin2c.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +static void Abort (char *fmt,...) +{ + va_list args; + va_start (args, fmt); + vfprintf (stderr, fmt, args); + va_end (args); + exit (1); +} + +int main (int argc, char **argv) +{ + FILE *inFile; + FILE *outFile = stdout; + time_t now = time (NULL); + int ch, i; + + if (argc != 2) + Abort ("Usage: %s bin-file [> result]", argv[0]); + + if ((inFile = fopen(argv[1],"rb")) == NULL) + Abort ("Cannot open %s\n", argv[1]); + + fprintf (outFile, + "/* data statements for file %s at %.24s */\n" + "/* Generated by BIN2C, G.Vanem 1995 */\n", + argv[1], ctime(&now)); + + i = 0; + while ((ch = fgetc(inFile)) != EOF) + { + if (i++ % 12 == 0) + fputs ("\n ", outFile); + fprintf (outFile, "0x%02X,", ch); + } + fputc ('\n', outFile); + fclose (inFile); + return (0); +} diff --git a/tcpdump/jni/libpcap/msdos/common.dj b/tcpdump/jni/libpcap/msdos/common.dj new file mode 100644 index 0000000..ec0ce02 --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/common.dj @@ -0,0 +1,79 @@ +# +# Common defines for libpcap and 16/32-bit network drivers (djgpp) +# + +.SUFFIXES: .exe .wlm .dxe .l .y +.PHONY: check_gcclib + +default: check_gcclib all + +GCCLIB = /djgpp/lib/gcc-lib/djgpp/3.31 +MAKEFILE = Makefile.dj + +# +# DLX 2.91+ lib. Change path to suite. +# Not used anymore. Uses DXE3 now. +# +# DLX_LIB = $(DJDIR)/contrib/dlx.291/libdlx.a +# DLX_LINK = $(DJDIR)/bin/dlxgen.exe + +WATT32_ROOT = $(subst \,/,$(WATT_ROOT)) + + +ifeq ($(wildcard $(GCCLIB)/libgcc.a),) +check_gcclib: + @echo libgcc.a not found. Set \"$(GCCLIB)\" to \"/djgpp/lib/gcc-lib/djgpp/3.X\" +endif + + +# +# Include 32-bit driver support +# +USE_32BIT_DRIVERS = 0 + +# +# Use loadable driver modules instead of statically linking +# all drivers. +# +USE_32BIT_MODULES = 0 + +# +# Put interrupt sensitive code/data in locked sections +# Do `make clean' in all affected directories after changing this. +# +USE_SECTION_LOCKING = 0 + +# +# Set to 1 to use exception handler lib (only for me) +# +USE_EXCEPT = 0 + +CC = gcc.exe +LD = ld.exe +ASM = nasm.exe -fbin -dDEBUG +YACC = bison.exe +LEX = flex.exe + +CFLAGS = -g -gcoff -O2 -Wall -I. -I$(WATT32_ROOT)/inc + +ifeq ($(USE_EXCEPT),1) + CFLAGS += -DUSE_EXCEPT + EXC_LIB = d:/prog/mw/except/lib/libexc.a +endif + +ifeq ($(USE_SECTION_LOCKING),1) + CFLAGS += -DUSE_SECTION_LOCKING +endif + +ifeq ($(USE_32BIT_DRIVERS),1) + CFLAGS += -DUSE_32BIT_DRIVERS +endif + +%.o: %.c + $(CC) -c $(CFLAGS) $< + @echo + +%.o: %.s + $(CC) -c $(CFLAGS) -x assembler-with-cpp -o $@ $< + @echo + diff --git a/tcpdump/jni/libpcap/msdos/makefile b/tcpdump/jni/libpcap/msdos/makefile new file mode 100644 index 0000000..cdb4e7c --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/makefile @@ -0,0 +1,184 @@ +# +# Makefile for dos-libpcap. NB. This makefile requires a Borland +# compatible make tool. +# +# Targets: +# Borland C 4.0+ (DOS large model) +# Metaware HighC 3.3+ (PharLap 386|DosX) +# + +.AUTODEPEND +.SWAP + +!if "$(WATT_ROOT)" == "" +!error Environment variable "WATT_ROOT" not set. +!endif + +WATT_INC = $(WATT_ROOT)\inc + +DEFS = -DMSDOS -DDEBUG -DNDIS_DEBUG -D_U_= -Dinline= \ + -DHAVE_STRERROR -DHAVE_LIMITS_H + +ASM = tasm.exe -t -l -mx -m2 -DDEBUG + +SOURCE = grammar.c scanner.c bpf_filt.c bpf_imag.c bpf_dump.c \ + etherent.c gencode.c nametoad.c pcap-dos.c optimize.c \ + savefile.c pcap.c inet.c msdos\ndis2.c msdos\pktdrvr.c \ + missing\snprintf.c + +BORLAND_OBJ = $(SOURCE:.c=.obj) msdos\pkt_rx0.obj msdos\ndis_0.obj + +HIGHC_OBJ = $(SOURCE:.c=.o32) msdos\pkt_rx0.o32 + +all: + @echo Usage: make pcap_bc.lib or pcap_hc.lib + + +pcap_bc.lib: bcc.arg $(BORLAND_OBJ) pcap_bc + + +pcap_hc.lib: hc386.arg $(HIGHC_OBJ) + 386lib $< @&&| + -nowarn -nobackup -twocase -replace $(HIGHC_OBJ) +| + +pcap_bc: $(BORLAND_OBJ) + @tlib pcap_bc.lib /C @&&| + -+$(**:.obj=-+) +| + +.c.obj: + bcc.exe @bcc.arg -o$*.obj $*.c + +.c.o32: + hc386.exe @hc386.arg -o $*.o32 $*.c + +.asm.obj: + $(ASM) $*.asm, $*.obj + +.asm.o32: + $(ASM) -DDOSX=1 $*.asm, $*.o32 + +scanner.c: scanner.l + flex -Ppcap_ -7 -oscanner.c scanner.l + +grammar.c tokdefs.h: grammar.y + bison --name-prefix=pcap_ --yacc --defines grammar.y + - @del grammar.c + - @del tokdefs.h + ren y_tab.c grammar.c + ren y_tab.h tokdefs.h + +bcc.arg: msdos\Makefile + @copy &&| + $(DEFS) -ml -c -v -3 -O2 -po -RT- -w- + -I$(WATT_INC) -I. -I.\msdos\pm_drvr -H=$(TEMP)\bcc.sym +| $< + +hc386.arg: msdos\Makefile + @copy &&| + # -DUSE_32BIT_DRIVERS + $(DEFS) -DDOSX=1 -w3 -c -g -O5 + -I$(WATT_INC) -I. -I.\msdos\pm_drvr + -Hsuffix=.o32 + -Hnocopyr + -Hpragma=Offwarn(491,553,572) + -Hon=Recognize_library # make memcpy/strlen etc. inline + -Hoff=Behaved # turn off some optimiser warnings +| $< + +clean: + @del *.obj + @del *.o32 + @del *.lst + @del *.map + @del bcc.arg + @del hc386.arg + @del grammar.c + @del tokdefs.h + @del scanner.c + @echo Cleaned + +# +# dependencies +# +pkt_rx0.obj: msdos\pkt_rx0.asm + +bpf_filt.obj: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h + +bpf_imag.obj: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h + +bpf_dump.obj: bpf_dump.c pcap.h pcap-bpf.h + +etherent.obj: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h + +optimize.obj: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h + +savefile.obj: savefile.c pcap-int.h pcap.h pcap-bpf.h + +pcap.obj: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h + +inet.obj: inet.c pcap-int.h pcap.h pcap-bpf.h + +grammar.obj: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pf.h pcap-namedb.h + +scanner.obj: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h tokdefs.h + +gencode.obj: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h ppp.h sll.h \ + arcnet.h pf.h pcap-namedb.h + +nametoad.obj: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h ethertype.h + +pcap-dos.obj: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h \ + msdos\pktdrvr.h + +pktdrvr.obj: msdos\pktdrvr.c gnuc.h pcap-dos.h pcap-int.h \ + pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc + +ndis2.obj: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + msdos\ndis2.h + +pkt_rx0.o32: msdos\pkt_rx0.asm + +bpf_filt.o32: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h + +bpf_imag.o32: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h + +bpf_dump.o32: bpf_dump.c pcap.h pcap-bpf.h + +etherent.o32: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h + +optimize.o32: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h + +savefile.o32: savefile.c pcap-int.h pcap.h pcap-bpf.h + +pcap.o32: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h + +inet.o32: inet.c pcap-int.h pcap.h pcap-bpf.h + +grammar.o32: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pf.h pcap-namedb.h + +scanner.o32: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h tokdefs.h + +gencode.o32: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h ppp.h sll.h \ + arcnet.h pf.h pcap-namedb.h + +nametoad.o32: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h ethertype.h + +pcap-dos.o32: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h \ + msdos\pktdrvr.h + +pktdrvr.o32: msdos\pktdrvr.c gnuc.h pcap-dos.h pcap-int.h \ + pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc + +ndis2.o32: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + msdos\ndis2.h + diff --git a/tcpdump/jni/libpcap/msdos/makefile.dj b/tcpdump/jni/libpcap/msdos/makefile.dj new file mode 100644 index 0000000..ae20ada --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/makefile.dj @@ -0,0 +1,151 @@ +# +# GNU Makefile for DOS-libpcap. djgpp version. +# +# Use this makefile from the libpcap root directory. +# E.g. like this: +# +# c:\net\pcap> make -f msdos/makefile.dj +# + +VPATH = missing msdos + +PREREQUISITES = scanner.c grammar.c tokdefs.h version.h msdos/pkt_stub.inc + +include msdos/common.dj + +DRIVER_DIR = ./msdos/pm_drvr + +CFLAGS += -DDEBUG -DNDIS_DEBUG -DHAVE_LIMITS_H -DHAVE_STRERROR \ + -D_U_='__attribute__((unused))' -DHAVE_VERSION_H + +# CFLAGS += -Dyylval=pcap_lval -DBDEBUG -DNDEBUG + +SOURCES = grammar.c scanner.c bpf_filt.c bpf_imag.c bpf_dump.c \ + etherent.c gencode.c nametoad.c pcap-dos.c optimize.c \ + savefile.c pcap.c inet.c msdos\pktdrvr.c msdos/ndis2.c \ + missing/snprintf.c + +OBJECTS = $(notdir $(SOURCES:.c=.o)) +TEMPBIN = tmp.bin + +ifeq ($(USE_32BIT_DRIVERS),1) + PM_OBJECTS = $(addprefix $(DRIVER_DIR)/, \ + printk.o pci.o pci-scan.o bios32.o dma.o irq.o intwrap.o \ + lock.o kmalloc.o quirks.o timer.o net_init.o) + # + # Static link of drivers + # + ifeq ($(USE_32BIT_MODULES),0) + PM_OBJECTS += $(addprefix $(DRIVER_DIR)/, \ + accton.o 8390.o 3c503.o 3c509.o 3c59x.o 3c515.o \ + 3c575_cb.o 3c90x.o ne.o wd.o cs89x0.o rtl8139.o) + endif +endif + +all: libpcap.a + +ifeq ($(USE_32BIT_DRIVERS),1) +$(PM_OBJECTS): + $(MAKE) -f Makefile.dj -C $(DRIVER_DIR) $(notdir $@) +endif + +libpcap.a: version.h $(OBJECTS) $(PM_OBJECTS) + rm -f $@ + ar rs $@ $^ + +msdos/pkt_stub.inc: msdos/bin2c.exe msdos/pkt_rx1.S + $(ASM) -o $(TEMPBIN) -lmsdos/pkt_rx1.lst msdos/pkt_rx1.S + ./msdos/bin2c $(TEMPBIN) > $@ + rm -f $(TEMPBIN) + +grammar.c tokdefs.h: grammar.y + rm -f grammar.c tokdefs.h + $(YACC) --name-prefix=pcap_ --yacc --defines grammar.y + mv -f y_tab.c grammar.c + mv -f y_tab.h tokdefs.h + +version.h: ./VERSION + @echo '/* Generated from VERSION. Do not edit */' > $@ + sed -e 's/.*/static char pcap_version_string[] = "libpcap (&)";/' ./VERSION >> $@ + +scanner.c: scanner.l + $(LEX) -Ppcap_ -7 -t $^ > $@ + @echo + +msdos/bin2c.exe: msdos/bin2c.c + $(CC) $*.c -o $*.exe + +clean: + $(MAKE) -f Makefile.dj -C $(DRIVER_DIR) clean + $(MAKE) -f Makefile.dj -C libcpcap clean + rm -f $(OBJECTS) msdos/pkt_rx1.lst Makefile.bak $(PREREQUISITES) + +vclean: clean + rm -f libpcap.a msdos/bin2c.exe + +# +# Generated dependencies; Due to some hacks in gcc 2.95 and djgpp 2.03 +# we must prevent "$(DJDIR)/bin/../include/sys/version.h" from beeing +# included in dependency output (or else this makefile cannot be used on +# another machine). We therefore use a special 'specs' file during +# pre-processing. +# +MM_SPECS = specs.tmp +MAKEFILE = msdos/Makefile.dj + +depend: $(PREREQUISITES) + @echo Generating dependencies.. + @cp $(MAKEFILE) Makefile.bak + @echo "*cpp: %(cpp_cpu) %{posix:-D_POSIX_SOURCE} -remap" > $(MM_SPECS) + sed -e "/^# DO NOT DELETE THIS LINE/,$$d" < Makefile.bak > $(MAKEFILE) + echo "# DO NOT DELETE THIS LINE" >> $(MAKEFILE) + $(CC) -MM -specs=$(MM_SPECS) $(CFLAGS) $(SOURCES) >> $(MAKEFILE) + rm -f $(MM_SPECS) + +# +# Manually generated dependencies +# +msdos/pktdrvr.c: msdos/pkt_stub.inc +scanner.c: scanner.l +grammar.c tokdefs.h: grammar.y +grammar.h: grammar.y +scanner.l: pcap-int.h pcap-namedb.h gencode.h grammar.h gnuc.h +grammar.y: pcap-int.h gencode.h pcap-namedb.h gnuc.h + +# +# Automatically generated dependencies +# +# DO NOT DELETE THIS LINE +grammar.o: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h pf.h \ + pcap-namedb.h +scanner.o: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h pcap-namedb.h \ + tokdefs.h +bpf_filt.o: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h +bpf_imag.o: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h +bpf_dump.o: bpf_dump.c pcap.h pcap-bpf.h +etherent.o: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h +gencode.o: gencode.c pcap-dos.h msdos/pm_drvr/lock.h pcap-int.h pcap.h \ + pcap-bpf.h ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h \ + ppp.h sll.h arcnet.h pf.h pcap-namedb.h +nametoad.o: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h ethertype.h +pcap-dos.o: pcap-dos.c msdos/pm_drvr/pmdrvr.h msdos/pm_drvr/iface.h \ + msdos/pm_drvr/lock.h msdos/pm_drvr/ioport.h pcap-dos.h pcap-int.h \ + pcap.h pcap-bpf.h msdos/pm_drvr/kmalloc.h msdos/pm_drvr/bitops.h \ + msdos/pm_drvr/timer.h msdos/pm_drvr/dma.h msdos/pm_drvr/irq.h \ + msdos/pm_drvr/printk.h msdos/pm_drvr/pci.h msdos/pm_drvr/bios32.h \ + msdos/pm_drvr/module.h msdos/pm_drvr/3c501.h msdos/pm_drvr/3c503.h \ + msdos/pm_drvr/3c509.h msdos/pm_drvr/3c59x.h msdos/pm_drvr/3c515.h \ + msdos/pm_drvr/3c90x.h msdos/pm_drvr/3c575_cb.h msdos/pm_drvr/ne.h \ + msdos/pm_drvr/wd.h msdos/pm_drvr/accton.h msdos/pm_drvr/cs89x0.h \ + msdos/pm_drvr/rtl8139.h msdos/pm_drvr/ne2k-pci.h msdos/pktdrvr.h +optimize.o: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h +savefile.o: savefile.c pcap-int.h pcap.h pcap-bpf.h +pcap.o: pcap.c pcap-dos.h msdos/pm_drvr/lock.h pcap-int.h pcap.h \ + pcap-bpf.h +inet.o: inet.c pcap-int.h pcap.h pcap-bpf.h +pktdrvr.o: msdos/pktdrvr.c gnuc.h pcap-dos.h msdos/pm_drvr/lock.h \ + pcap-int.h pcap.h pcap-bpf.h msdos/pktdrvr.h msdos/pkt_stub.inc +ndis2.o: msdos/ndis2.c pcap-dos.h msdos/pm_drvr/lock.h pcap-int.h pcap.h \ + pcap-bpf.h msdos/ndis2.h +snprintf.o: missing/snprintf.c pcap-int.h pcap.h pcap-bpf.h diff --git a/tcpdump/jni/libpcap/msdos/makefile.wc b/tcpdump/jni/libpcap/msdos/makefile.wc new file mode 100644 index 0000000..e0d5672 --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/makefile.wc @@ -0,0 +1,131 @@ +# +# Watcom Makefile for dos-libpcap. +# +# Specify MODEL = `3r' or `3s' +# Specify TARGET = `pharlap' or `dos4g' +# +# Use this makefile from the libpcap root directory. +# E.g. like this: +# +# c:\net\pcap> wmake -f msdos\makefile.wc +# + +MODEL = 3s +TARGET = dos4g + +OBJDIR = msdos\$(TARGET).w$(MODEL) +LIB = $(OBJDIR)\pcap.lib + +.EXTENSIONS: .l .y + +DEFS = -dDEBUG -dNDIS_DEBUG -d_U_= -dHAVE_LIMITS_H -dHAVE_STRERROR & + -dHAVE_SNPRINTF -dHAVE_VSNPRINTF + +CC = wcc386.exe +ASM = wasm.exe -$(MODEL) $(DEFS) -dDOSX -dDOS4GW -zq -bt=dos -fr=nul -d3 -s + +OBJS = $(OBJDIR)\grammar.obj $(OBJDIR)\scanner.obj $(OBJDIR)\pcap.obj & + $(OBJDIR)\bpf_filt.obj $(OBJDIR)\bpf_imag.obj $(OBJDIR)\bpf_dump.obj & + $(OBJDIR)\etherent.obj $(OBJDIR)\gencode.obj $(OBJDIR)\nametoad.obj & + $(OBJDIR)\pcap-dos.obj $(OBJDIR)\pktdrvr.obj $(OBJDIR)\optimize.obj & + $(OBJDIR)\savefile.obj $(OBJDIR)\inet.obj $(OBJDIR)\ndis2.obj + +CFLAGS = $(DEFS) $(YYDEFS) -I. -I$(%watt_root)\inc -I.\msdos\pm_drvr & + -$(MODEL) -mf -zff -zgf -zq -bt=dos -fr=nul -w6 -fpi & + -oilrtf -zm + +TEMPBIN = tmp.bin + +all: $(OBJDIR) $(OBJDIR)\pcap.lib + +$(OBJDIR): + - mkdir $(OBJDIR) + +$(OBJDIR)\pcap.lib: $(OBJS) wlib.arg + wlib -q -b -c $(OBJDIR)\pcap.lib @wlib.arg + +wlib.arg: msdos\makefile.wc + %create $^@ + for %f in ($(OBJS)) do %append $^@ +- %f + +$(OBJDIR)\pktdrvr.obj: msdos\pkt_stub.inc msdos\pktdrvr.c gnuc.h & + pcap-dos.h pcap-int.h pcap.h msdos\pktdrvr.h + *$(CC) $(CFLAGS) msdos\pktdrvr.c -fo=$@ + +$(OBJDIR)\ndis2.obj: msdos\ndis2.c + *$(CC) $(CFLAGS) msdos\ndis2.c -fo=$@ + +.ERASE +.c{$(OBJDIR)}.obj: + *$(CC) $(CFLAGS) $[@ -fo=$@ + +grammar.c tokdefs.h: grammar.y + bison --name-prefix=pcap_ --yacc --defines $[@ + - @del grammar.c + - @del tokdefs.h + ren y_tab.c grammar.c + ren y_tab.h tokdefs.h + +scanner.c: scanner.l + flex -Ppcap_ -7 -o$@ $[@ + +msdos\pkt_stub.inc: bin2c.exe msdos\pkt_rx1.S + nasm -fbin -dDEBUG -o $(TEMPBIN) -lmsdos\pkt_rx1.lst msdos\pkt_rx1.S + bin2c.exe $(TEMPBIN) > $@ + @del $(TEMPBIN) + +bin2c.exe: msdos\bin2c.c + wcl $[@ + +clean realclean vclean: .SYMBOLIC + for %f in (dos4g.w3r dos4g.w3s pharlap.w3r pharlap.w3s) do & + @del %f\*.obj + @del grammar.c + @del tokdefs.h + @del scanner.c + @del bin2c.exe + @del bin2c.obj + @del msdos\pkt_stub.inc + @echo Cleaned + +# +# dependencies +# +$(OBJDIR)\bpf_filt.obj: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h + +$(OBJDIR)\bpf_imag.obj: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\bpf_dump.obj: bpf_dump.c pcap.h pcap-bpf.h + +$(OBJDIR)\etherent.obj: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-nam.h + +$(OBJDIR)\optimize.obj: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h + +$(OBJDIR)\savefile.obj: savefile.c pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\pcap.obj: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\inet.obj: inet.c pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\grammar.obj: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h & + pf.h pcap-nam.h + +$(OBJDIR)\scanner.obj: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h & + pcap-nam.h tokdefs.h + +$(OBJDIR)\gencode.obj: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h & + ethertyp.h nlpid.h llc.h gencode.h atmuni31.h sunatmpo.h ppp.h sll.h & + arcnet.h pf.h pcap-nam.h + +$(OBJDIR)\nametoad.obj: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h & + pcap-nam.h ethertyp.h + +$(OBJDIR)\pcap-dos.obj: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h & + msdos\pktdrvr.h + +$(OBJDIR)\pktdrvr.obj: msdos\pktdrvr.c gnuc.h pcap-dos.h pcap-int.h & + pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc + +$(OBJDIR)\ndis2.obj: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h & + msdos\ndis2.h + diff --git a/tcpdump/jni/libpcap/msdos/ndis2.c b/tcpdump/jni/libpcap/msdos/ndis2.c new file mode 100644 index 0000000..0a5ea2a --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/ndis2.c @@ -0,0 +1,860 @@ +/* + * Copyright (c) 1993,1994 + * Texas A&M University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Texas A&M University + * and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Developers: + * David K. Hess, Douglas Lee Schales, David R. Safford + * + * Heavily modified for Metaware HighC + GNU C 2.8+ + * Gisle Vanem 1998 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-dos.h" +#include "pcap-int.h" +#include "msdos/ndis2.h" + +#if defined(USE_NDIS2) + +/* + * Packet buffer handling + */ +extern int FreePktBuf (PktBuf *buf); +extern int EnquePktBuf (PktBuf *buf); +extern PktBuf* AllocPktBuf (void); + +/* + * Various defines + */ +#define MAX_NUM_DEBUG_STRINGS 90 +#define DEBUG_STRING_LENGTH 80 +#define STACK_POOL_SIZE 6 +#define STACK_SIZE 256 + +#define MEDIA_FDDI 1 +#define MEDIA_ETHERNET 2 +#define MEDIA_TOKEN 3 + +static int startDebug = 0; +static int stopDebug = 0; + +static DWORD droppedPackets = 0L; +static WORD frameSize = 0; +static WORD headerSize = 0; +static int mediaType = 0; +static char *lastErr = NULL; + +static BYTE debugStrings [MAX_NUM_DEBUG_STRINGS][DEBUG_STRING_LENGTH]; +static BYTE *freeStacks [STACK_POOL_SIZE]; +static int freeStackPtr = STACK_POOL_SIZE - 1; + +static ProtMan protManEntry = NULL; +static WORD protManDS = 0; +static volatile int xmitPending; + +static struct _PktBuf *txBufPending; +static struct _CardHandle *handle; +static struct _CommonChars common; +static struct _ProtocolChars protChars; +static struct _ProtDispatch lowerTable; + +static struct _FailingModules failingModules; +static struct _BindingsList bindings; + +static struct { + WORD err_num; + char *err_text; + } ndis_errlist[] = { + + { ERR_SUCCESS, + "The function completed successfully.\n" }, + + { ERR_WAIT_FOR_RELEASE, + "The ReceiveChain completed successfully but the protocol has\n" + "retained control of the buffer.\n" }, + + { ERR_REQUEST_QUEUED, + "The current request has been queued.\n" }, + + { ERR_FRAME_NOT_RECOGNIZED, + "Frame not recognized.\n" }, + + { ERR_FRAME_REJECTED, + "Frame was discarded.\n" }, + + { ERR_FORWARD_FRAME, + "Protocol wishes to forward frame to another protocol.\n" }, + + { ERR_OUT_OF_RESOURCE, + "Out of resource.\n" }, + + { ERR_INVALID_PARAMETER, + "Invalid parameter.\n" }, + + { ERR_INVALID_FUNCTION, + "Invalid function.\n" }, + + { ERR_NOT_SUPPORTED, + "Not supported.\n" }, + + { ERR_HARDWARE_ERROR, + "Hardware error.\n" }, + + { ERR_TRANSMIT_ERROR, + "The packet was not transmitted due to an error.\n" }, + + { ERR_NO_SUCH_DESTINATION, + "Token ring packet was not recognized when transmitted.\n" }, + + { ERR_BUFFER_TOO_SMALL, + "Provided buffer was too small.\n" }, + + { ERR_ALREADY_STARTED, + "Network drivers already started.\n" }, + + { ERR_INCOMPLETE_BINDING, + "Protocol driver could not complete its bindings.\n" }, + + { ERR_DRIVER_NOT_INITIALIZED, + "MAC did not initialize properly.\n" }, + + { ERR_HARDWARE_NOT_FOUND, + "Hardware not found.\n" }, + + { ERR_HARDWARE_FAILURE, + "Hardware failure.\n" }, + + { ERR_CONFIGURATION_FAILURE, + "Configuration failure.\n" }, + + { ERR_INTERRUPT_CONFLICT, + "Interrupt conflict.\n" }, + + { ERR_INCOMPATIBLE_MAC, + "The MAC is not compatible with the protocol.\n" }, + + { ERR_INITIALIZATION_FAILED, + "Initialization failed.\n" }, + + { ERR_NO_BINDING, + "Binding did not occur.\n" }, + + { ERR_NETWORK_MAY_NOT_BE_CONNECTED, + "The network may not be connected to the adapter.\n" }, + + { ERR_INCOMPATIBLE_OS_VERSION, + "The version of the operating system is incompatible with the protocol.\n" }, + + { ERR_ALREADY_REGISTERED, + "The protocol is already registered.\n" }, + + { ERR_PATH_NOT_FOUND, + "PROTMAN.EXE could not be found.\n" }, + + { ERR_INSUFFICIENT_MEMORY, + "Insufficient memory.\n" }, + + { ERR_INFO_NOT_FOUND, + "Protocol Mananger info structure is lost or corrupted.\n" }, + + { ERR_GENERAL_FAILURE, + "General failure.\n" } +}; + +/* + * Some handy macros + */ +#define PERROR(str) printf("%s (%d): %s\n", __FILE__,__LINE__,str) +#define DEBUG_RING() (debugStrings[stopDebug+1 == MAX_NUM_DEBUG_STRINGS ? \ + stopDebug = 0 : ++stopDebug]) + +/* + * needs rewrite for DOSX + */ +#define MAC_DISPATCH(hnd) ((struct _MacUpperDispatch*)(hnd)->common->upperDispatchTable) +#define MAC_STATUS(hnd) ((struct _MacStatusTable*) (hnd)->common->serviceStatus) +#define MAC_CHAR(hnd) ((struct _MacChars*) (hnd)->common->serviceChars) + +#ifdef NDIS_DEBUG + #define DEBUG0(str) printf (str) + #define DEBUG1(fmt,a) printf (fmt,a) + #define DEBUG2(fmt,a,b) printf (fmt,a,b) + #define TRACE0(str) sprintf (DEBUG_RING(),str) + #define TRACE1(fmt,a) sprintf (DEBUG_RING(),fmt,a) +#else + #define DEBUG0(str) ((void)0) + #define DEBUG1(fmt,a) ((void)0) + #define DEBUG2(fmt,a,b) ((void)0) + #define TRACE0(str) ((void)0) + #define TRACE1(fmt,a) ((void)0) +#endif + +/* + * This routine is called from both threads + */ +void NdisFreeStack (BYTE *aStack) +{ + GUARD(); + + if (freeStackPtr == STACK_POOL_SIZE - 1) + PERROR ("tried to free too many stacks"); + + freeStacks[++freeStackPtr] = aStack; + + if (freeStackPtr == 0) + TRACE0 ("freeStackPtr went positive\n"); + + UNGUARD(); +} + +/* + * This routine is called from callbacks to allocate local data + */ +BYTE *NdisAllocStack (void) +{ + BYTE *stack; + + GUARD(); + + if (freeStackPtr < 0) + { + /* Ran out of stack buffers. Return NULL which will start + * dropping packets + */ + TRACE0 ("freeStackPtr went negative\n"); + stack = 0; + } + else + stack = freeStacks[freeStackPtr--]; + + UNGUARD(); + return (stack); +} + +CALLBACK (NdisSystemRequest (DWORD param1, DWORD param2, WORD param3, + WORD opcode, WORD targetDS)) +{ + static int bindEntry = 0; + struct _CommonChars *macCommon; + volatile WORD result; + + switch (opcode) + { + case REQ_INITIATE_BIND: + macCommon = (struct _CommonChars*) param2; + if (macCommon == NULL) + { + printf ("There is an NDIS misconfiguration.\n"); + result = ERR_GENERAL_FAILURE; + break; + } + DEBUG2 ("module name %s\n" + "module type %s\n", + macCommon->moduleName, + ((MacChars*) macCommon->serviceChars)->macName); + + /* Binding to the MAC */ + result = macCommon->systemRequest ((DWORD)&common, (DWORD)&macCommon, + 0, REQ_BIND, + macCommon->moduleDS); + + if (!strcmp(bindings.moduleName[bindEntry], handle->moduleName)) + handle->common = macCommon; + else PERROR ("unknown module"); + ++bindEntry; + break; + + case REQ_INITIATE_UNBIND: + macCommon = (struct _CommonChars*) param2; + result = macCommon->systemRequest ((DWORD)&common, 0, + 0, REQ_UNBIND, + macCommon->moduleDS); + break; + + default: + result = ERR_GENERAL_FAILURE; + break; + } + ARGSUSED (param1); + ARGSUSED (param3); + ARGSUSED (targetDS); + return (result); +} + +CALLBACK (NdisRequestConfirm (WORD protId, WORD macId, WORD reqHandle, + WORD status, WORD request, WORD protDS)) +{ + ARGSUSED (protId); ARGSUSED (macId); + ARGSUSED (reqHandle); ARGSUSED (status); + ARGSUSED (request); ARGSUSED (protDS); + return (ERR_SUCCESS); +} + +CALLBACK (NdisTransmitConfirm (WORD protId, WORD macId, WORD reqHandle, + WORD status, WORD protDS)) +{ + xmitPending--; + FreePktBuf (txBufPending); /* Add passed ECB back to the free list */ + + ARGSUSED (reqHandle); + ARGSUSED (status); + ARGSUSED (protDS); + return (ERR_SUCCESS); +} + + +/* + * The primary function for receiving packets + */ +CALLBACK (NdisReceiveLookahead (WORD macId, WORD frameSize, + WORD bytesAvail, BYTE *buffer, + BYTE *indicate, WORD protDS)) +{ + int result; + PktBuf *pktBuf; + WORD bytesCopied; + struct _TDBufDescr tDBufDescr; + +#if 0 + TRACE1 ("lookahead length = %d, ", bytesAvail); + TRACE1 ("ecb = %08lX, ", *ecb); + TRACE1 ("count = %08lX\n", count); + TRACE1 ("offset = %08lX, ", offset); + TRACE1 ("timesAllowed = %d, ", timesAllowed); + TRACE1 ("packet size = %d\n", look->dataLookAheadLen); +#endif + + /* Allocate a buffer for the packet + */ + if ((pktBuf = AllocPktBuf()) == NULL) + { + droppedPackets++; + return (ERR_FRAME_REJECTED); + } + + /* + * Now kludge things. Note we will have to undo this later. This will + * make the packet contiguous after the MLID has done the requested copy. + */ + + tDBufDescr.tDDataCount = 1; + tDBufDescr.tDBufDescrRec[0].tDPtrType = NDIS_PTR_PHYSICAL; + tDBufDescr.tDBufDescrRec[0].tDDataPtr = pktBuf->buffer; + tDBufDescr.tDBufDescrRec[0].tDDataLen = pktBuf->length; + tDBufDescr.tDBufDescrRec[0].dummy = 0; + + result = MAC_DISPATCH(handle)->transferData (&bytesCopied, 0, &tDBufDescr, + handle->common->moduleDS); + pktBuf->packetLength = bytesCopied; + + if (result == ERR_SUCCESS) + EnquePktBuf(pktBuf); + else FreePktBuf (pktBuf); + + ARGSUSED (frameSize); + ARGSUSED (bytesAvail); + ARGSUSED (indicate); + ARGSUSED (protDS); + + return (ERR_SUCCESS); +} + +CALLBACK (NdisIndicationComplete (WORD macId, WORD protDS)) +{ + ARGSUSED (macId); + ARGSUSED (protDS); + + /* We don't give a hoot about these. Just return + */ + return (ERR_SUCCESS); +} + +/* + * This is the OTHER way we may receive packets + */ +CALLBACK (NdisReceiveChain (WORD macId, WORD frameSize, WORD reqHandle, + struct _RxBufDescr *rxBufDescr, + BYTE *indicate, WORD protDS)) +{ + struct _PktBuf *pktBuf; + int i; + + /* + * For now we copy the entire packet over to a PktBuf structure. This may be + * a performance hit but this routine probably isn't called very much, and + * it is a lot of work to do it otherwise. Also if it is a filter protocol + * packet we could end up sucking up MAC buffes. + */ + + if ((pktBuf = AllocPktBuf()) == NULL) + { + droppedPackets++; + return (ERR_FRAME_REJECTED); + } + pktBuf->packetLength = 0; + + /* Copy the packet to the buffer + */ + for (i = 0; i < rxBufDescr->rxDataCount; ++i) + { + struct _RxBufDescrRec *rxDescr = &rxBufDescr->rxBufDescrRec[i]; + + memcpy (pktBuf->buffer + pktBuf->packetLength, + rxDescr->rxDataPtr, rxDescr->rxDataLen); + pktBuf->packetLength += rxDescr->rxDataLen; + } + + EnquePktBuf (pktBuf); + + ARGSUSED (frameSize); + ARGSUSED (reqHandle); + ARGSUSED (indicate); + ARGSUSED (protDS); + + /* This frees up the buffer for the MAC to use + */ + return (ERR_SUCCESS); +} + +CALLBACK (NdisStatusProc (WORD macId, WORD param1, BYTE *indicate, + WORD opcode, WORD protDS)) +{ + switch (opcode) + { + case STATUS_RING_STATUS: + break; + case STATUS_ADAPTER_CHECK: + break; + case STATUS_START_RESET: + break; + case STATUS_INTERRUPT: + break; + case STATUS_END_RESET: + break; + default: + break; + } + ARGSUSED (macId); + ARGSUSED (param1); + ARGSUSED (indicate); + ARGSUSED (opcode); + ARGSUSED (protDS); + + /* We don't need to do anything about this stuff yet + */ + return (ERR_SUCCESS); +} + +/* + * Tell the NDIS driver to start the delivery of the packet + */ +int NdisSendPacket (struct _PktBuf *pktBuf, int macId) +{ + struct _TxBufDescr txBufDescr; + int result; + + xmitPending++; + txBufPending = pktBuf; /* we only have 1 pending Tx at a time */ + + txBufDescr.txImmedLen = 0; + txBufDescr.txImmedPtr = NULL; + txBufDescr.txDataCount = 1; + txBufDescr.txBufDescrRec[0].txPtrType = NDIS_PTR_PHYSICAL; + txBufDescr.txBufDescrRec[0].dummy = 0; + txBufDescr.txBufDescrRec[0].txDataLen = pktBuf->packetLength; + txBufDescr.txBufDescrRec[0].txDataPtr = pktBuf->buffer; + + result = MAC_DISPATCH(handle)->transmitChain (common.moduleId, + pktBuf->handle, + &txBufDescr, + handle->common->moduleDS); + switch (result) + { + case ERR_OUT_OF_RESOURCE: + /* Note that this should not happen but if it does there is not + * much we can do about it + */ + printf ("ERROR: transmit queue overflowed\n"); + return (0); + + case ERR_SUCCESS: + /* Everything was hunky dory and synchronous. Free up the + * packet buffer + */ + xmitPending--; + FreePktBuf (pktBuf); + return (1); + + case ERR_REQUEST_QUEUED: + /* Everything was hunky dory and asynchronous. Do nothing + */ + return (1); + + default: + printf ("Tx fail, code = %04X\n", result); + return (0); + } +} + + + +static int ndis_nerr = sizeof(ndis_errlist) / sizeof(ndis_errlist[0]); + +static char *Ndis_strerror (WORD errorCode) +{ + static char buf[30]; + int i; + + for (i = 0; i < ndis_nerr; i++) + if (errorCode == ndis_errlist[i].err_num) + return (ndis_errlist[i].err_text); + + sprintf (buf,"unknown error %d",errorCode); + return (buf); +} + + +char *NdisLastError (void) +{ + char *errStr = lastErr; + lastErr = NULL; + return (errStr); +} + +int NdisOpen (void) +{ + struct _ReqBlock reqBlock; + int result; + int ndisFd = open (NDIS_PATH, O_RDONLY); + + if (ndisFd < 0) + { + printf ("Could not open NDIS Protocol Manager device.\n"); + return (0); + } + + memset (&reqBlock, 0, sizeof(ReqBlock)); + + reqBlock.opcode = PM_GET_PROTOCOL_MANAGER_LINKAGE; + + result = NdisGetLinkage (ndisFd, (char*)&reqBlock, sizeof(ReqBlock)); + if (result != 0) + { + printf ("Could not get Protocol Manager linkage.\n"); + close (ndisFd); + return (0); + } + + close (ndisFd); + protManEntry = (ProtMan) reqBlock.pointer1; + protManDS = reqBlock.word1; + + DEBUG2 ("Entry Point = %04X:%04X\n", FP_SEG(protManEntry),FP_OFF(protManEntry)); + DEBUG1 ("ProtMan DS = %04X\n", protManDS); + return (1); +} + + +int NdisRegisterAndBind (int promis) +{ + struct _ReqBlock reqBlock; + WORD result; + + memset (&common,0,sizeof(common)); + + common.tableSize = sizeof (common); + + common.majorNdisVersion = 2; + common.minorNdisVersion = 0; + common.majorModuleVersion = 2; + common.minorModuleVersion = 0; + + /* Indicates binding from below and dynamically loaded + */ + common.moduleFlags = 0x00000006L; + + strcpy (common.moduleName, "PCAP"); + + common.protocolLevelUpper = 0xFF; + common.protocolLevelLower = 1; + common.interfaceLower = 1; +#ifdef __DJGPP__ + common.moduleDS = _dos_ds; /* the callback data segment */ +#else + common.moduleDS = _DS; +#endif + + common.systemRequest = (SystemRequest) systemRequestGlue; + common.serviceChars = (BYTE*) &protChars; + common.serviceStatus = NULL; + common.upperDispatchTable = NULL; + common.lowerDispatchTable = (BYTE*) &lowerTable; + + protChars.length = sizeof (protChars); + protChars.name[0] = 0; + protChars.type = 0; + + lowerTable.backPointer = &common; + lowerTable.requestConfirm = requestConfirmGlue; + lowerTable.transmitConfirm = transmitConfirmGlue; + lowerTable.receiveLookahead = receiveLookaheadGlue; + lowerTable.indicationComplete = indicationCompleteGlue; + lowerTable.receiveChain = receiveChainGlue; + lowerTable.status = statusGlue; + lowerTable.flags = 3; + if (promis) + lowerTable.flags |= 4; /* promiscous mode (receive everything) */ + + bindings.numBindings = 1; + strcpy (bindings.moduleName[0], handle->moduleName); + + /* Register ourselves with NDIS + */ + reqBlock.opcode = PM_REGISTER_MODULE; + reqBlock.pointer1 = (BYTE FAR*) &common; + reqBlock.pointer2 = (BYTE FAR*) &bindings; + + result = (*protManEntry) (&reqBlock, protManDS); + if (result) + { + printf ("Protman registering failed: %s\n", Ndis_strerror(result)); + return (0); + } + + /* Start the binding process + */ + reqBlock.opcode = PM_BIND_AND_START; + reqBlock.pointer1 = (BYTE FAR*) &failingModules; + + result = (*protManEntry) (&reqBlock, protManDS); + if (result) + { + printf ("Start binding failed: %s\n", Ndis_strerror(result)); + return (0); + } + return (1); +} + +static int CheckMacFeatures (CardHandle *card) +{ + DWORD serviceFlags; + BYTE _far *mediaString; + BYTE _far *mac_addr; + + DEBUG2 ("checking card features\n" + "common table address = %08lX, macId = %d\n", + card->common, card->common->moduleId); + + serviceFlags = MAC_CHAR (handle)->serviceFlags; + + if ((serviceFlags & SF_PROMISCUOUS) == 0) + { + printf ("The MAC %s does not support promiscuous mode.\n", + card->moduleName); + return (0); + } + + mediaString = MAC_CHAR (handle)->macName; + + DEBUG1 ("media type = %s\n",mediaString); + + /* Get the media type. And set the header size + */ + if (!strncmp(mediaString,"802.3",5) || + !strncmp(mediaString,"DIX",3) || + !strncmp(mediaString,"DIX+802.3",9)) + headerSize = sizeof (EthernetIIHeader); + + else if (!strncmp(mediaString,"FDDI",4)) + headerSize = sizeof (FddiHeader) + + sizeof (Ieee802Dot2SnapHeader); + else + { + printf ("Unsupported MAC type: `%s'\n", mediaString); + return (0); + } + + frameSize = MAC_CHAR (handle)->maxFrameSize; + mac_addr = MAC_CHAR (handle)->currentAddress; + + printf ("Hardware address: %02X:%02X:%02X:%02X:%02X:%02X\n", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + return (1); +} + +static int NdisStartMac (CardHandle *card) +{ + WORD result; + + /* Set the lookahead length + */ + result = MAC_DISPATCH(handle)->request (common.moduleId, 0, + headerSize, 0, + REQ_SET_LOOKAHEAD, + card->common->moduleDS); + + /* We assume that if we got INVALID PARAMETER then either this + * is not supported or will work anyway. NE2000 does this. + */ + if (result != ERR_SUCCESS && result != ERR_INVALID_PARAMETER) + { + DEBUG1 ("Set lookahead failed: %s\n", Ndis_strerror(result)); + return (0); + } + + /* Set the packet filter. Note that for some medias and drivers we + * must specify all three flags or the card(s) will not operate correctly. + */ + result = MAC_DISPATCH(handle)->request (common.moduleId, 0, + /* all packets */ FILTER_PROMISCUOUS | + /* packets to us */ FILTER_DIRECTED | + /* broadcasts */ FILTER_BROADCAST, + 0, REQ_SET_PACKET_FILTER, + card->common->moduleDS); + if (result != ERR_SUCCESS) + { + DEBUG1 ("Set packet filter failed: %s\n", Ndis_strerror(result)); + return (0); + } + + /* If OPEN/CLOSE supported then open the adapter + */ + if (MAC_CHAR(handle)->serviceFlags & SF_OPEN_CLOSE) + { + result = MAC_DISPATCH(handle)->request (common.moduleId, 0, 0, NULL, + REQ_OPEN_ADAPTER, + card->common->moduleDS); + if (result != ERR_SUCCESS) + { + DEBUG1 ("Opening the MAC failed: %s\n", Ndis_strerror(result)); + return (0); + } + } + return (1); +} + +void NdisShutdown (void) +{ + struct _ReqBlock reqBlock; + int result, i; + + if (!handle) + return; + + /* If the adapters support open and are open then close them + */ + if ((MAC_CHAR(handle)->serviceFlags & SF_OPEN_CLOSE) && + (MAC_STATUS(handle)->macStatus & MAC_OPEN)) + { + result = MAC_DISPATCH(handle)->request (common.moduleId, 0, 0, 0, + REQ_CLOSE_ADAPTER, + handle->common->moduleDS); + if (result != ERR_SUCCESS) + { + printf ("Closing the MAC failed: %s\n", Ndis_strerror(result)); + return; + } + } + + /* Tell the Protocol Manager to unbind and stop + */ + reqBlock.opcode = PM_UNBIND_AND_STOP; + reqBlock.pointer1 = (BYTE FAR*) &failingModules; + reqBlock.pointer2 = NULL; + + result = (*protManEntry) (&reqBlock, protManDS); + if (result) + printf ("Unbind failed: %s\n", Ndis_strerror(result)); + + for (i = 0; i < STACK_POOL_SIZE; ++i) + free (freeStacks[i] - STACK_SIZE); + + handle = NULL; +} + +int NdisInit (int promis) +{ + int i, result; + + /* Allocate the real mode stacks used for NDIS callbacks + */ + for (i = 0; i < STACK_POOL_SIZE; ++i) + { + freeStacks[i] = malloc (STACK_SIZE); + if (!freeStacks[i]) + return (0); + freeStacks[i] += STACK_SIZE; + } + + if (!NdisOpen()) + return (0); + + if (!NdisRegisterAndBind(promis)) + return (0); + + DEBUG1 ("My module id: %d\n", common.moduleId); + DEBUG1 ("Handle id; %d\n", handle->common->moduleId); + DEBUG1 ("MAC card: %-16s - ", handle->moduleName); + + atexit (NdisShutdown); + + if (!CheckMacFeatures(&handle)) + return (0); + + switch (mediaType) + { + case MEDIA_FDDI: + DEBUG0 ("Media type: FDDI"); + break; + case MEDIA_ETHERNET: + DEBUG0 ("Media type: ETHERNET"); + break; + default: + DEBUG0 ("Unsupported media.\n"); + return (0); + } + + DEBUG1 (" - Frame size: %d\n", frameSize); + + if (!NdisStartMac(&handle)) + return (0); + return (1); +} +#endif /* USE_NDIS2 */ + diff --git a/tcpdump/jni/libpcap/msdos/ndis2.h b/tcpdump/jni/libpcap/msdos/ndis2.h new file mode 100644 index 0000000..dc72f4c --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/ndis2.h @@ -0,0 +1,559 @@ +/* + * Copyright (c) 1993,1994 + * Texas A&M University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Texas A&M University + * and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Developers: + * David K. Hess, Douglas Lee Schales, David R. Safford + * + * Heavily modified for Metaware HighC + GNU C 2.8+ + * Gisle Vanem 1998 + */ + +#ifndef __PCAP_NDIS_H +#define __PCAP_NDIS_H + +#if defined (__HIGHC__) + #define pascal _CC(_CALLEE_POPS_STACK & ~_REVERSE_PARMS) /* calling convention */ + #define CALLBACK(foo) pascal WORD foo + #define PAS_PTR(x,arg) typedef FAR WORD pascal (*x) arg + #define GUARD() _inline (0x9C,0xFA) /* pushfd, cli */ + #define UNGUARD() _inline (0x9D) /* popfd */ + #define FAR _far + +#elif defined(__GNUC__) + #define CALLBACK(foo) WORD foo __attribute__((stdcall)) + #define PAS_PTR(x,arg) typedef WORD (*x) arg __attribute__((stdcall)) + #define GUARD() __asm__ __volatile__ ("pushfd; cli") + #define UNGUARD() __asm__ __volatile__ ("popfd") + #define FAR + +#elif defined (__TURBOC__) + #define CALLBACK(foo) WORD pascal foo + #define PAS_PTR(x,arg) typedef WORD pascal (_far *x) arg + #define GUARD() _asm { pushf; cli } + #define UNGUARD() _asm { popf } + #define FAR _far + +#elif defined (__WATCOMC__) + #define CALLBACK(foo) WORD pascal foo + #define PAS_PTR(x,arg) typedef WORD pascal (_far *x) arg + #define GUARD() _disable() + #define UNGUARD() _enable() + #define FAR _far + +#else + #error Unsupported compiler +#endif + + +/* + * Forwards + */ +struct _ReqBlock; +struct _TxBufDescr; +struct _TDBufDescr; + +/* + * Protocol Manager API + */ +PAS_PTR (ProtMan, (struct _ReqBlock FAR*, WORD)); + +/* + * System request + */ +PAS_PTR (SystemRequest, (DWORD, DWORD, WORD, WORD, WORD)); + +/* + * MAC API + */ +PAS_PTR (TransmitChain, (WORD, WORD, struct _TxBufDescr FAR*, WORD)); +PAS_PTR (TransferData, (WORD*,WORD, struct _TDBufDescr FAR*, WORD)); +PAS_PTR (Request, (WORD, WORD, WORD, DWORD, WORD, WORD)); +PAS_PTR (ReceiveRelease,(WORD, WORD)); +PAS_PTR (IndicationOn, (WORD)); +PAS_PTR (IndicationOff, (WORD)); + + +typedef enum { + HARDWARE_NOT_INSTALLED = 0, + HARDWARE_FAILED_DIAG = 1, + HARDWARE_FAILED_CONFIG = 2, + HARDWARE_HARD_FAULT = 3, + HARDWARE_SOFT_FAULT = 4, + HARDWARE_OK = 7, + HARDWARE_MASK = 0x0007, + MAC_BOUND = 0x0008, + MAC_OPEN = 0x0010, + DIAG_IN_PROGRESS = 0x0020 + } NdisMacStatus; + +typedef enum { + STATUS_RING_STATUS = 1, + STATUS_ADAPTER_CHECK = 2, + STATUS_START_RESET = 3, + STATUS_INTERRUPT = 4, + STATUS_END_RESET = 5 + } NdisStatus; + +typedef enum { + FILTER_DIRECTED = 1, + FILTER_BROADCAST = 2, + FILTER_PROMISCUOUS = 4, + FILTER_SOURCE_ROUTE = 8 + } NdisPacketFilter; + +typedef enum { + REQ_INITIATE_DIAGNOSTICS = 1, + REQ_READ_ERROR_LOG = 2, + REQ_SET_STATION_ADDRESS = 3, + REQ_OPEN_ADAPTER = 4, + REQ_CLOSE_ADAPTER = 5, + REQ_RESET_MAC = 6, + REQ_SET_PACKET_FILTER = 7, + REQ_ADD_MULTICAST_ADDRESS = 8, + REQ_DELETE_MULTICAST_ADDRESS = 9, + REQ_UPDATE_STATISTICS = 10, + REQ_CLEAR_STATISTICS = 11, + REQ_INTERRUPT_REQUEST = 12, + REQ_SET_FUNCTIONAL_ADDRESS = 13, + REQ_SET_LOOKAHEAD = 14 + } NdisGeneralRequest; + +typedef enum { + SF_BROADCAST = 0x00000001L, + SF_MULTICAST = 0x00000002L, + SF_FUNCTIONAL = 0x00000004L, + SF_PROMISCUOUS = 0x00000008L, + SF_SOFT_ADDRESS = 0x00000010L, + SF_STATS_CURRENT = 0x00000020L, + SF_INITIATE_DIAGS = 0x00000040L, + SF_LOOPBACK = 0x00000080L, + SF_RECEIVE_CHAIN = 0x00000100L, + SF_SOURCE_ROUTING = 0x00000200L, + SF_RESET_MAC = 0x00000400L, + SF_OPEN_CLOSE = 0x00000800L, + SF_INTERRUPT_REQUEST = 0x00001000L, + SF_SOURCE_ROUTING_BRIDGE = 0x00002000L, + SF_VIRTUAL_ADDRESSES = 0x00004000L + } NdisMacServiceFlags; + +typedef enum { + REQ_INITIATE_BIND = 1, + REQ_BIND = 2, + REQ_INITIATE_PREBIND = 3, + REQ_INITIATE_UNBIND = 4, + REQ_UNBIND = 5 + } NdisSysRequest; + +typedef enum { + PM_GET_PROTOCOL_MANAGER_INFO = 1, + PM_REGISTER_MODULE = 2, + PM_BIND_AND_START = 3, + PM_GET_PROTOCOL_MANAGER_LINKAGE = 4, + PM_GET_PROTOCOL_INI_PATH = 5, + PM_REGISTER_PROTOCOL_MANAGER_INFO = 6, + PM_INIT_AND_REGISTER = 7, + PM_UNBIND_AND_STOP = 8, + PM_BIND_STATUS = 9, + PM_REGISTER_STATUS = 10 + } NdisProtManager; + + +typedef enum { + ERR_SUCCESS = 0x00, + ERR_WAIT_FOR_RELEASE = 0x01, + ERR_REQUEST_QUEUED = 0x02, + ERR_FRAME_NOT_RECOGNIZED = 0x03, + ERR_FRAME_REJECTED = 0x04, + ERR_FORWARD_FRAME = 0x05, + ERR_OUT_OF_RESOURCE = 0x06, + ERR_INVALID_PARAMETER = 0x07, + ERR_INVALID_FUNCTION = 0x08, + ERR_NOT_SUPPORTED = 0x09, + ERR_HARDWARE_ERROR = 0x0A, + ERR_TRANSMIT_ERROR = 0x0B, + ERR_NO_SUCH_DESTINATION = 0x0C, + ERR_BUFFER_TOO_SMALL = 0x0D, + ERR_ALREADY_STARTED = 0x20, + ERR_INCOMPLETE_BINDING = 0x21, + ERR_DRIVER_NOT_INITIALIZED = 0x22, + ERR_HARDWARE_NOT_FOUND = 0x23, + ERR_HARDWARE_FAILURE = 0x24, + ERR_CONFIGURATION_FAILURE = 0x25, + ERR_INTERRUPT_CONFLICT = 0x26, + ERR_INCOMPATIBLE_MAC = 0x27, + ERR_INITIALIZATION_FAILED = 0x28, + ERR_NO_BINDING = 0x29, + ERR_NETWORK_MAY_NOT_BE_CONNECTED = 0x2A, + ERR_INCOMPATIBLE_OS_VERSION = 0x2B, + ERR_ALREADY_REGISTERED = 0x2C, + ERR_PATH_NOT_FOUND = 0x2D, + ERR_INSUFFICIENT_MEMORY = 0x2E, + ERR_INFO_NOT_FOUND = 0x2F, + ERR_GENERAL_FAILURE = 0xFF + } NdisError; + +#define NDIS_PARAM_INTEGER 0 +#define NDIS_PARAM_STRING 1 + +#define NDIS_TX_BUF_LENGTH 8 +#define NDIS_TD_BUF_LENGTH 1 +#define NDIS_RX_BUF_LENGTH 8 + +#define NDIS_PTR_PHYSICAL 0 +#define NDIS_PTR_VIRTUAL 2 + +#define NDIS_PATH "PROTMAN$" + + +typedef struct _CommonChars { + WORD tableSize; + BYTE majorNdisVersion; /* 2 - Latest version */ + BYTE minorNdisVersion; /* 0 */ + WORD reserved1; + BYTE majorModuleVersion; + BYTE minorModuleVersion; + DWORD moduleFlags; + /* 0 - Binding at upper boundary supported + * 1 - Binding at lower boundary supported + * 2 - Dynamically bound. + * 3-31 - Reserved, must be zero. + */ + BYTE moduleName[16]; + BYTE protocolLevelUpper; + /* 1 - MAC + * 2 - Data Link + * 3 - Network + * 4 - Transport + * 5 - Session + * -1 - Not specified + */ + BYTE interfaceUpper; + BYTE protocolLevelLower; + /* 0 - Physical + * 1 - MAC + * 2 - Data Link + * 3 - Network + * 4 - Transport + * 5 - Session + * -1 - Not specified + */ + BYTE interfaceLower; + WORD moduleId; + WORD moduleDS; + SystemRequest systemRequest; + BYTE *serviceChars; + BYTE *serviceStatus; + BYTE *upperDispatchTable; + BYTE *lowerDispatchTable; + BYTE *reserved2; /* Must be NULL */ + BYTE *reserved3; /* Must be NULL */ + } CommonChars; + + +typedef struct _MulticastList { + WORD maxMulticastAddresses; + WORD numberMulticastAddresses; + BYTE multicastAddress[16][16]; + } MulticastList; + + +typedef struct _MacChars { + WORD tableSize; + BYTE macName[16]; + WORD addressLength; + BYTE permanentAddress[16]; + BYTE currentAddress[16]; + DWORD currentFunctionalAddress; + MulticastList *multicastList; + DWORD linkSpeed; + DWORD serviceFlags; + WORD maxFrameSize; + DWORD txBufferSize; + WORD txBufferAllocSize; + DWORD rxBufferSize; + WORD rxBufferAllocSize; + BYTE ieeeVendor[3]; + BYTE vendorAdapter; + BYTE *vendorAdapterDescription; + WORD interruptLevel; + WORD txQueueDepth; + WORD maxDataBlocks; + } MacChars; + + +typedef struct _ProtocolChars { + WORD length; + BYTE name[16]; + WORD type; + } ProtocolChars; + + +typedef struct _MacUpperDispatch { + CommonChars *backPointer; + Request request; + TransmitChain transmitChain; + TransferData transferData; + ReceiveRelease receiveRelease; + IndicationOn indicationOn; + IndicationOff indicationOff; + } MacUpperDispatch; + + +typedef struct _MacStatusTable { + WORD tableSize; + DWORD lastDiag; + DWORD macStatus; + WORD packetFilter; + BYTE *mediaSpecificStats; + DWORD lastClear; + DWORD totalFramesRx; + DWORD totalFramesCrc; + DWORD totalBytesRx; + DWORD totalDiscardBufSpaceRx; + DWORD totalMulticastRx; + DWORD totalBroadcastRx; + DWORD obsolete1[5]; + DWORD totalDiscardHwErrorRx; + DWORD totalFramesTx; + DWORD totalBytesTx; + DWORD totalMulticastTx; + DWORD totalBroadcastTx; + DWORD obsolete2[2]; + DWORD totalDiscardTimeoutTx; + DWORD totalDiscardHwErrorTx; + } MacStatusTable; + + +typedef struct _ProtDispatch { + CommonChars *backPointer; + DWORD flags; + /* 0 - handles non-LLC frames + * 1 - handles specific-LSAP LLC frames + * 2 - handles specific-LSAP LLC frames + * 3-31 - reserved must be 0 + */ + void (*requestConfirm) (void); + void (*transmitConfirm) (void); + void (*receiveLookahead) (void); + void (*indicationComplete) (void); + void (*receiveChain) (void); + void (*status) (void); + } ProtDispatch; + + +typedef struct _ReqBlock { + WORD opcode; + WORD status; + BYTE FAR *pointer1; + BYTE FAR *pointer2; + WORD word1; + } ReqBlock; + + +typedef struct _TxBufDescrRec { + BYTE txPtrType; + BYTE dummy; + WORD txDataLen; + BYTE *txDataPtr; + } TxBufDescrRec; + + +typedef struct _TxBufDescr { + WORD txImmedLen; + BYTE *txImmedPtr; + WORD txDataCount; + TxBufDescrRec txBufDescrRec[NDIS_TX_BUF_LENGTH]; + } TxBufDescr; + + +typedef struct _TDBufDescrRec { + BYTE tDPtrType; + BYTE dummy; + WORD tDDataLen; + BYTE *tDDataPtr; + } TDBufDescrRec; + + +typedef struct _TDBufDescr { + WORD tDDataCount; + TDBufDescrRec tDBufDescrRec[NDIS_TD_BUF_LENGTH]; + } TDBufDescr; + + +typedef struct _RxBufDescrRec { + WORD rxDataLen; + BYTE *rxDataPtr; + } RxBufDescrRec; + + +typedef struct _RxBufDescr { + WORD rxDataCount; + RxBufDescrRec rxBufDescrRec[NDIS_RX_BUF_LENGTH]; + } RxBufDescr; + + +typedef struct _PktBuf { + struct _PktBuf *nextLink; + struct _PktBuf *prevLink; + int handle; + int length; + int packetLength; + DWORD sequence; + BYTE *buffer; + } PktBuf; + + +typedef struct _CardHandle { + BYTE moduleName[16]; + CommonChars *common; + } CardHandle; + + +typedef struct _BindingsList { + WORD numBindings; + BYTE moduleName[2][16]; + } BindingsList; + + +typedef struct _FailingModules { + BYTE upperModuleName[16]; + BYTE lowerModuleName[16]; + } FailingModules; + + +typedef union _HardwareAddress { + BYTE bytes[6]; + WORD words[3]; + struct { + BYTE bytes[6]; + } addr; + } HardwareAddress; + + +typedef struct _FddiHeader { + BYTE frameControl; + HardwareAddress etherDestHost; + HardwareAddress etherSrcHost; + } FddiHeader; + + +typedef struct _EthernetIIHeader { + HardwareAddress etherDestHost; + HardwareAddress etherSrcHost; + WORD etherType; + } EthernetIIHeader; + + +typedef struct _Ieee802Dot5Header { + HardwareAddress etherDestHost; + HardwareAddress etherSrcHost; + BYTE routeInfo[30]; + } Ieee802Dot5Header; + + +typedef struct _Ieee802Dot2SnapHeader { + BYTE dsap; /* 0xAA */ + BYTE ssap; /* 0xAA */ + BYTE control; /* 3 */ + BYTE protocolId[5]; + } Ieee802Dot2SnapHeader; + + +/* + * Prototypes + */ +extern char *NdisLastError (void); +extern int NdisOpen (void); +extern int NdisInit (int promis); +extern int NdisRegisterAndBind (int promis); +extern void NdisShutdown (void); +extern void NdisCheckMacFeatures (struct _CardHandle *card); +extern int NdisSendPacket (struct _PktBuf *pktBuf, int macId); + +/* + * Assembly "glue" functions + */ +extern int systemRequestGlue(); +extern int requestConfirmGlue(); +extern int transmitConfirmGlue(); +extern int receiveLookaheadGlue(); +extern int indicationCompleteGlue(); +extern int receiveChainGlue(); +extern int statusGlue(); + +/* + * IOCTL function + */ +#ifdef __SMALL__ +extern int _far NdisGetLinkage (int handle, char *data, int size); +#else +extern int NdisGetLinkage (int handle, char *data, int size); +#endif + +/* + * NDIS callback handlers + */ +CALLBACK (NdisSystemRequest (DWORD,DWORD, WORD, WORD, WORD)); +CALLBACK (NdisRequestConfirm ( WORD, WORD, WORD, WORD, WORD,WORD)); +CALLBACK (NdisTransmitConfirm ( WORD, WORD, WORD, WORD, WORD)); +CALLBACK (NdisReceiveLookahead ( WORD, WORD, WORD, BYTE*, BYTE*, WORD)); +CALLBACK (NdisReceiveChain ( WORD, WORD, WORD, struct _RxBufDescr*, BYTE*, WORD)); +CALLBACK (NdisStatusProc ( WORD, WORD, BYTE*, WORD,WORD)); +CALLBACK (NdisIndicationComplete( WORD, WORD)); + +BYTE *NdisAllocStack (void); +void NdisFreeStack (BYTE*); + +#ifdef __HIGHC__ + #define RENAME_ASM_SYM(x) pragma Alias(x,"@" #x "") /* prepend `@' */ + #define RENAME_C_SYM(x) pragma Alias(x,"_" #x "") /* prepend `_' */ + + RENAME_ASM_SYM (systemRequestGlue); + RENAME_ASM_SYM (requestConfirmGlue); + RENAME_ASM_SYM (transmitConfirmGlue); + RENAME_ASM_SYM (receiveLookaheadGlue); + RENAME_ASM_SYM (indicationCompleteGlue); + RENAME_ASM_SYM (receiveChainGlue); + RENAME_ASM_SYM (statusGlue); + RENAME_ASM_SYM (NdisGetLinkage); + RENAME_C_SYM (NdisSystemRequest); + RENAME_C_SYM (NdisRequestConfirm); + RENAME_C_SYM (NdisTransmitConfirm); + RENAME_C_SYM (NdisReceiveLookahead); + RENAME_C_SYM (NdisIndicationComplete); + RENAME_C_SYM (NdisReceiveChain); + RENAME_C_SYM (NdisStatusProc); + RENAME_C_SYM (NdisAllocStack); + RENAME_C_SYM (NdisFreeStack); +#endif + +#endif diff --git a/tcpdump/jni/libpcap/msdos/ndis_0.asm b/tcpdump/jni/libpcap/msdos/ndis_0.asm new file mode 100644 index 0000000..2990985 --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/ndis_0.asm @@ -0,0 +1,188 @@ +PAGE 60,132 +NAME NDIS_0 + +ifdef DOSX + .386 + _TEXT SEGMENT PUBLIC DWORD USE16 'CODE' + _TEXT ENDS + _DATA SEGMENT PUBLIC DWORD USE16 'CODE' + _DATA ENDS + _TEXT32 SEGMENT PUBLIC BYTE USE32 'CODE' + _TEXT32 ENDS + CB_DSEG EQU ; DOSX is tiny-model + D_SEG EQU <_TEXT SEGMENT> + D_END EQU <_TEXT ENDS> + ASSUME CS:_TEXT,DS:_TEXT + + PUSHREGS equ + POPREGS equ + + PUBPROC macro name + align 4 + public @&name + @&name label near + endm +else + .286 + _TEXT SEGMENT PUBLIC DWORD 'CODE' + _TEXT ENDS + _DATA SEGMENT PUBLIC DWORD 'DATA' + _DATA ENDS + CB_DSEG EQU ; 16bit is small/large model + D_SEG EQU <_DATA SEGMENT> + D_END EQU <_DATA ENDS> + ASSUME CS:_TEXT,DS:_DATA + + PUSHREGS equ + POPREGS equ + + PUBPROC macro name + public _&name + _&name label far + endm +endif + +;------------------------------------------- + +D_SEG + +D_END + + +_TEXT SEGMENT + +EXTRN _NdisSystemRequest : near +EXTRN _NdisRequestConfirm : near +EXTRN _NdisTransmitConfirm : near +EXTRN _NdisReceiveLookahead : near +EXTRN _NdisIndicationComplete : near +EXTRN _NdisReceiveChain : near +EXTRN _NdisStatusProc : near +EXTRN _NdisAllocStack : near +EXTRN _NdisFreeStack : near + +; +; *ALL* interrupt threads come through this macro. +; +CALLBACK macro callbackProc, argsSize + + pushf + PUSHREGS ;; Save the registers + + push es + push ds + mov ax,CB_DSEG ;; Load DS + mov ds,ax + call _NdisAllocStack ;; Get and install a stack. + + mov bx,ss ;; Save off the old stack in other regs + mov cx,sp + mov ss,dx ;; Install the new one + mov sp,ax + push bx ;; Save the old one on to the new stack + push cx + sub sp,&argsSize ;; Allocate space for arguments on the stack + + mov ax,ss ;; Set up the destination for the move + mov es,ax + mov di,sp + mov ds,bx ;; Set up the source for the move. + mov si,cx + add si,4+6+32 + + mov cx,&argsSize ;; Move the arguments to the stack. + shr cx,1 + cld + rep movsw + + mov ax,CB_DSEG ;; Set my data segment again. + mov ds,ax + + call &callbackProc ;; Call the real callback. + pop di ;; Pop off the old stack + pop si + mov bx,ss ;; Save off the current allocated stack. + mov cx,sp + mov ss,si ;; Restore the old stack + mov sp,di + push ax ;; Save the return code + push bx ;; Free the stack. Push the pointer to it + push cx + call _NdisFreeStack + add sp,4 + pop ax ;; Get the return code back + add di,32 ;; Get a pointer to ax on the stack + mov word ptr ss:[di],ax + pop ds + pop es + + POPREGS + popf +endm + +; +; Define all of the callbacks for the NDIS procs. +; + +PUBPROC systemRequestGlue +CALLBACK _NdisSystemRequest,14 +RETF + +PUBPROC requestConfirmGlue +CALLBACK _NdisRequestConfirm,12 +RETF + +PUBPROC transmitConfirmGlue +CALLBACK _NdisTransmitConfirm,10 +RETF + +PUBPROC receiveLookaheadGlue +CALLBACK _NdisReceiveLookahead,16 +RETF + +PUBPROC indicationCompleteGlue +CALLBACK _NdisIndicationComplete,4 +RETF + +PUBPROC receiveChainGlue +CALLBACK _NdisReceiveChain,16 +RETF + +PUBPROC statusGlue +CALLBACK _NdisStatusProc,12 +RETF + +; +; int FAR NdisGetLinkage (int handle, char *data, int size); +; + +ifdef DOSX + PUBPROC NdisGetLinkage + push ebx + mov ebx, [esp+8] ; device handle + mov eax, 4402h ; IOCTRL read function + mov edx, [esp+12] ; DS:EDX -> result data + mov ecx, [esp+16] ; ECX = length + int 21h + pop ebx + jc @fail + xor eax, eax + @fail: ret + +else + PUBPROC NdisGetLinkage + enter 0, 0 + mov bx, [bp+6] + mov ax, 4402h + mov dx, [bp+8] + mov cx, [bp+12] + int 21h + jc @fail + xor ax, ax + @fail: leave + retf +endif + +ENDS + +END diff --git a/tcpdump/jni/libpcap/msdos/pkt_rx0.asm b/tcpdump/jni/libpcap/msdos/pkt_rx0.asm new file mode 100644 index 0000000..94f3d09 --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/pkt_rx0.asm @@ -0,0 +1,197 @@ +PAGE 60,132 +NAME PKT_RX + +ifdef ??version ; using TASM + masm + jumps +endif + +PUBLIC _pktDrop, _pktRxBuf, _pktTxBuf, _pktTemp +PUBLIC _rxOutOfs, _rxInOfs, _PktReceiver, _pktRxEnd + +; +; these sizes MUST be equal to the sizes in PKTDRVR.H +; + +RX_BUF_SIZE = 1500 ; max message size on Ethernet +TX_BUF_SIZE = 1500 + +ifdef DOSX + .386 + NUM_RX_BUF = 32 ; # of RX element buffers + _TEXT SEGMENT PUBLIC DWORD USE16 'CODE' + _TEXT ENDS + _DATA SEGMENT PUBLIC DWORD USE16 'CODE' + _DATA ENDS + D_SEG EQU <_TEXT SEGMENT> + D_END EQU <_TEXT ENDS> + ASSUME CS:_TEXT,DS:_TEXT +else + .286 + NUM_RX_BUF = 10 + _TEXT SEGMENT PUBLIC DWORD 'CODE' + _TEXT ENDS + _DATA SEGMENT PUBLIC DWORD 'DATA' + _DATA ENDS + D_SEG EQU <_DATA SEGMENT> + D_END EQU <_DATA ENDS> + ASSUME CS:_TEXT,DS:_DATA +endif + +;------------------------------------------- + +D_SEG + +RX_ELEMENT STRUC + firstCount dw 0 ; # of bytes on 1st call + secondCount dw 0 ; # of bytes on 2nd call + handle dw 0 ; handle for upcall + destinAdr db 6 dup (0) ; packet destination address + sourceAdr db 6 dup (0) ; packet source address + protocol dw 0 ; packet protocol number + rxBuffer db RX_BUF_SIZE dup (0) ; RX buffer +ENDS + align 4 +_rxOutOfs dw offset _pktRxBuf ; ring buffer offsets +_rxInOfs dw offset _pktRxBuf ; into _pktRxBuf +_pktDrop dw 0,0 ; packet drop counter +_pktTemp db 20 dup (0) ; temp work area +_pktTxBuf db (TX_BUF_SIZE+14) dup (0) ; TX buffer +_pktRxBuf RX_ELEMENT NUM_RX_BUF dup (<>) ; RX structures + LAST_OFS = offset $ + + screenSeg dw 0B800h + newInOffset dw 0 + + fanChars db '-\|/' + fanIndex dw 0 + +D_END + +_TEXT SEGMENT + + +SHOW_RX MACRO + push es + push bx + mov bx, screenSeg + mov es, bx ;; r-mode segment of colour screen + mov di, 158 ;; upper right corner - 1 + mov bx, fanIndex + mov al, fanChars[bx] ;; get write char + mov ah, 15 ;; and white colour + stosw ;; write to screen at ES:EDI + inc fanIndex ;; update next index + and fanIndex, 3 + pop bx + pop es +ENDM + +;------------------------------------------------------------------------ +; +; This macro return ES:DI to tail of Rx queue + +ENQUEUE MACRO + LOCAL @noWrap + mov ax, _rxInOfs ;; DI = current in-offset + add ax, SIZE RX_ELEMENT ;; point to next _pktRxBuf buffer + cmp ax, LAST_OFS ;; pointing past last ? + jb @noWrap ;; no - jump + lea ax, _pktRxBuf ;; yes, point to 1st buffer + align 4 +@noWrap: cmp ax, _rxOutOfs ;; in-ofs = out-ofs ? + je @dump ;; yes, queue is full + mov di, _rxInOfs ;; ES:DI -> buffer at queue input + mov newInOffset, ax ;; remember new input offset + + ;; NOTE. rxInOfs is updated after the packet has been copied + ;; to ES:DI (= DS:SI on 2nd call) by the packet driver + +ENDM + +;------------------------------------------------------------------------ +; +; This routine gets called by the packet driver twice: +; 1st time (AX=0) it requests an address where to put the packet +; +; 2nd time (AX=1) the packet has been copied to this location (DS:SI) +; BX has client handle (stored in RX_ELEMENT.handle). +; CX has # of bytes in packet on both call. They should be equal. +; +; A test for equality is done by putting CX in _pktRxBuf [n].firstCount +; and _pktRxBuf[n].secondCount, and CL on first call in +; _pktRxBuf[n].rxBuffer[CX]. These values are checked in "PktReceive" +; (PKTDRVR.C) +; +;--------------------------------------------------------------------- + +_PktReceiver: + pushf + cli ; no distraction wanted ! + push ds + push bx +ifdef DOSX + mov bx, cs +else + mov bx, SEG _DATA +endif + mov ds, bx + mov es, bx ; ES = DS = CS or seg _DATA + pop bx ; restore handle + + cmp ax, 0 ; first call? (AX=0) + jne @post ; AX=1: second call, do post process + +ifdef DEBUG + SHOW_RX ; show that a packet is received +endif + cmp cx, RX_BUF_SIZE+14 ; size OK ? + ja @skip ; no, packet to large for us + + ENQUEUE ; ES:DI -> _pktRxBuf[n] + + mov [di].firstCount, cx ; remember the first count. + mov [di].handle, bx ; remember the handle. + add di, 6 ; ES:DI -> _pktRxBuf[n].destinAdr + pop ds + popf + retf ; far return to driver with ES:DI + + align 4 +@dump: inc _pktDrop[0] ; discard the packet on 1st call + adc _pktDrop[2], 0 ; increment packets lost + +@skip: xor di, di ; return ES:DI = NIL pointer + xor ax, ax + mov es, ax + pop ds + popf + retf + + align 4 +@post: or si, si ; DS:SI->_pktRxBuf[n][n].destinAdr + jz @discard ; make sure we don't use NULL-pointer + + sub si, 6 ; DS:SI -> _pktRxBuf[n].destinAdr + ; + ; push si + ; push [si].firstCount + ; call bpf_filter_match ; run the filter here some day? + ; add sp, 4 + ; cmp ax, 0 + ; je @discard + + mov [si].secondCount, cx + mov ax, newInOffset + mov _rxInOfs, ax ; update _pktRxBuf input offset + + align 4 +@discard:pop ds + popf + retf + +_pktRxEnd db 0 ; marker for end of r-mode code/data + +_TEXT ENDS + +END diff --git a/tcpdump/jni/libpcap/msdos/pkt_rx1.s b/tcpdump/jni/libpcap/msdos/pkt_rx1.s new file mode 100644 index 0000000..b294a36 --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/pkt_rx1.s @@ -0,0 +1,155 @@ +; +; This file requires NASM 0.97+ to assemble +; +; Currently used only for djgpp + DOS4GW targets +; +; these sizes MUST be equal to the sizes in PKTDRVR.H +; +%define ETH_MTU 1500 ; max data size on Ethernet +%define ETH_MIN 60 ; min/max total frame size +%define ETH_MAX (ETH_MTU+2*6+2) +%define NUM_RX_BUF 32 ; # of RX element buffers +%define RX_SIZE (ETH_MAX+6) ; sizeof(RX_ELEMENT) = 1514+6 +%idefine offset + +struc RX_ELEMENT + .firstCount resw 1 ; # of bytes on 1st call + .secondCount resw 1 ; # of bytes on 2nd call + .handle resw 1 ; handle for upcall + ; .timeStamp resw 4 ; 64-bit RDTSC value + .destinAdr resb 6 ; packet destination address + .sourceAdr resb 6 ; packet source address + .protocol resw 1 ; packet protocol number + .rxBuffer resb ETH_MTU ; RX buffer +endstruc + +;------------------------------------------- + +[org 0] ; assemble to .bin file + +_rxOutOfs dw offset _pktRxBuf ; ring buffer offsets +_rxInOfs dw offset _pktRxBuf ; into _pktRxBuf +_pktDrop dw 0,0 ; packet drop counter +_pktTemp resb 20 ; temp work area +_pktTxBuf resb (ETH_MAX) ; TX buffer +_pktRxBuf resb (RX_SIZE*NUM_RX_BUF) ; RX structures + LAST_OFS equ $ + +screenSeg dw 0B800h +newInOffset dw 0 + +fanChars db '-\|/' +fanIndex dw 0 + +%macro SHOW_RX 0 + push es + push bx + mov bx, [screenSeg] + mov es, bx ;; r-mode segment of colour screen + mov di, 158 ;; upper right corner - 1 + mov bx, [fanIndex] + mov al, [fanChars+bx] ;; get write char + mov ah, 15 ;; and white colour + cld ;; Needed? + stosw ;; write to screen at ES:EDI + inc word [fanIndex] ;; update next index + and word [fanIndex], 3 + pop bx + pop es +%endmacro + +;PutTimeStamp +; rdtsc +; mov [si].timeStamp, eax +; mov [si+4].timeStamp, edx +; ret + + +;------------------------------------------------------------------------ +; +; This routine gets called by the packet driver twice: +; 1st time (AX=0) it requests an address where to put the packet +; +; 2nd time (AX=1) the packet has been copied to this location (DS:SI) +; BX has client handle (stored in RX_ELEMENT.handle). +; CX has # of bytes in packet on both call. They should be equal. +; A test for equality is done by putting CX in _pktRxBuf [n].firstCount +; and _pktRxBuf[n].secondCount, and CL on first call in +; _pktRxBuf[n].rxBuffer[CX]. These values are checked in "PktReceive" +; (PKTDRVR.C) +; +;--------------------------------------------------------------------- + +_PktReceiver: + pushf + cli ; no distraction wanted ! + push ds + push bx + mov bx, cs + mov ds, bx + mov es, bx ; ES = DS = CS or seg _DATA + pop bx ; restore handle + + cmp ax, 0 ; first call? (AX=0) + jne @post ; AX=1: second call, do post process + +%ifdef DEBUG + SHOW_RX ; show that a packet is received +%endif + + cmp cx, ETH_MAX ; size OK ? + ja @skip ; no, too big + + mov ax, [_rxInOfs] + add ax, RX_SIZE + cmp ax, LAST_OFS + jb @noWrap + mov ax, offset _pktRxBuf +@noWrap: + cmp ax, [_rxOutOfs] + je @dump + mov di, [_rxInOfs] ; ES:DI -> _pktRxBuf[n] + mov [newInOffset], ax + + mov [di], cx ; remember firstCount. + mov [di+4], bx ; remember handle. + add di, 6 ; ES:DI -> _pktRxBuf[n].destinAdr + pop ds + popf + retf ; far return to driver with ES:DI + +@dump: add word [_pktDrop+0], 1 ; discard the packet on 1st call + adc word [_pktDrop+2], 0 ; increment packets lost + +@skip: xor di, di ; return ES:DI = NIL pointer + xor ax, ax + mov es, ax + pop ds + popf + retf + +@post: or si, si ; DS:SI->_pktRxBuf[n][n].destinAdr + jz @discard ; make sure we don't use NULL-pointer + + ; + ; push si + ; call bpf_filter_match ; run the filter here some day + ; pop si + ; cmp ax, 0 + ; je @discard + + mov [si-6+2], cx ; store _pktRxBuf[n].secondCount + mov ax, [newInOffset] + mov [_rxInOfs], ax ; update _pktRxBuf input offset + + ; call PutTimeStamp + +@discard: + pop ds + popf + retf + +_pktRxEnd db 0 ; marker for end of r-mode code/data + +END + diff --git a/tcpdump/jni/libpcap/msdos/pktdrvr.c b/tcpdump/jni/libpcap/msdos/pktdrvr.c new file mode 100644 index 0000000..cd22ee6 --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/pktdrvr.c @@ -0,0 +1,1436 @@ +/* + * File.........: pktdrvr.c + * + * Responsible..: Gisle Vanem, giva@bgnett.no + * + * Created......: 26.Sept 1995 + * + * Description..: Packet-driver interface for 16/32-bit C : + * Borland C/C++ 3.0+ small/large model + * Watcom C/C++ 11+, DOS4GW flat model + * Metaware HighC 3.1+ and PharLap 386|DosX + * GNU C/C++ 2.7+ and djgpp 2.x extender + * + * References...: PC/TCP Packet driver Specification. rev 1.09 + * FTP Software Inc. + * + */ + +#include +#include +#include +#include + +#include "pcap-dos.h" +#include "pcap-int.h" +#include "msdos/pktdrvr.h" + +#if (DOSX) +#define NUM_RX_BUF 32 /* # of buffers in Rx FIFO queue */ +#else +#define NUM_RX_BUF 10 +#endif + +#define DIM(x) (sizeof((x)) / sizeof(x[0])) +#define PUTS(s) do { \ + if (!pktInfo.quiet) \ + pktInfo.error ? \ + printf ("%s: %s\n", s, pktInfo.error) : \ + printf ("%s\n", pktInfo.error = s); \ + } while (0) + +#if defined(__HIGHC__) + extern UINT _mwenv; + +#elif defined(__DJGPP__) + #include + #include + #include + #include + #include + +#elif defined(__WATCOMC__) + #include + #include + extern char _Extender; + +#else + extern void far PktReceiver (void); +#endif + + +#if (DOSX & (DJGPP|DOS4GW)) + #include + + struct DPMI_regs { + DWORD r_di; + DWORD r_si; + DWORD r_bp; + DWORD reserved; + DWORD r_bx; + DWORD r_dx; + DWORD r_cx; + DWORD r_ax; + WORD r_flags; + WORD r_es, r_ds, r_fs, r_gs; + WORD r_ip, r_cs, r_sp, r_ss; + }; + + /* Data located in a real-mode segment. This becomes far at runtime + */ + typedef struct { /* must match data/code in pkt_rx1.s */ + WORD _rxOutOfs; + WORD _rxInOfs; + DWORD _pktDrop; + BYTE _pktTemp [20]; + TX_ELEMENT _pktTxBuf[1]; + RX_ELEMENT _pktRxBuf[NUM_RX_BUF]; + WORD _dummy[2]; /* screenSeg,newInOffset */ + BYTE _fanChars[4]; + WORD _fanIndex; + BYTE _PktReceiver[15]; /* starts on a paragraph (16byte) */ + } PktRealStub; + #include + + static BYTE real_stub_array [] = { + #include "pkt_stub.inc" /* generated opcode array */ + }; + + #define rxOutOfs offsetof (PktRealStub,_rxOutOfs) + #define rxInOfs offsetof (PktRealStub,_rxInOfs) + #define PktReceiver offsetof (PktRealStub,_PktReceiver [para_skip]) + #define pktDrop offsetof (PktRealStub,_pktDrop) + #define pktTemp offsetof (PktRealStub,_pktTemp) + #define pktTxBuf offsetof (PktRealStub,_pktTxBuf) + #define FIRST_RX_BUF offsetof (PktRealStub,_pktRxBuf [0]) + #define LAST_RX_BUF offsetof (PktRealStub,_pktRxBuf [NUM_RX_BUF-1]) + +#else + extern WORD rxOutOfs; /* offsets into pktRxBuf FIFO queue */ + extern WORD rxInOfs; + extern DWORD pktDrop; /* # packets dropped in PktReceiver() */ + extern BYTE pktRxEnd; /* marks the end of r-mode code/data */ + + extern RX_ELEMENT pktRxBuf [NUM_RX_BUF]; /* PktDrvr Rx buffers */ + extern TX_ELEMENT pktTxBuf; /* PktDrvr Tx buffer */ + extern char pktTemp[20]; /* PktDrvr temp area */ + + #define FIRST_RX_BUF (WORD) &pktRxBuf [0] + #define LAST_RX_BUF (WORD) &pktRxBuf [NUM_RX_BUF-1] +#endif + + +#ifdef __BORLANDC__ /* Use Borland's inline functions */ + #define memcpy __memcpy__ + #define memcmp __memcmp__ + #define memset __memset__ +#endif + + +#if (DOSX & PHARLAP) + extern void PktReceiver (void); /* in pkt_rx0.asm */ + static int RealCopy (ULONG, ULONG, REALPTR*, FARPTR*, USHORT*); + + #undef FP_SEG + #undef FP_OFF + #define FP_OFF(x) ((WORD)(x)) + #define FP_SEG(x) ((WORD)(realBase >> 16)) + #define DOS_ADDR(s,o) (((DWORD)(s) << 16) + (WORD)(o)) + #define r_ax eax + #define r_bx ebx + #define r_dx edx + #define r_cx ecx + #define r_si esi + #define r_di edi + #define r_ds ds + #define r_es es + LOCAL FARPTR protBase; + LOCAL REALPTR realBase; + LOCAL WORD realSeg; /* DOS para-address of allocated area */ + LOCAL SWI_REGS reg; + + static WORD _far *rxOutOfsFp, *rxInOfsFp; + +#elif (DOSX & DJGPP) + static _go32_dpmi_seginfo rm_mem; + static __dpmi_regs reg; + static DWORD realBase; + static int para_skip = 0; + + #define DOS_ADDR(s,o) (((WORD)(s) << 4) + (o)) + #define r_ax x.ax + #define r_bx x.bx + #define r_dx x.dx + #define r_cx x.cx + #define r_si x.si + #define r_di x.di + #define r_ds x.ds + #define r_es x.es + +#elif (DOSX & DOS4GW) + LOCAL struct DPMI_regs reg; + LOCAL WORD rm_base_seg, rm_base_sel; + LOCAL DWORD realBase; + LOCAL int para_skip = 0; + + LOCAL DWORD dpmi_get_real_vector (int intr); + LOCAL WORD dpmi_real_malloc (int size, WORD *selector); + LOCAL void dpmi_real_free (WORD selector); + #define DOS_ADDR(s,o) (((DWORD)(s) << 4) + (WORD)(o)) + +#else /* real-mode Borland etc. */ + static struct { + WORD r_ax, r_bx, r_cx, r_dx, r_bp; + WORD r_si, r_di, r_ds, r_es, r_flags; + } reg; +#endif + +#ifdef __HIGHC__ + #pragma Alias (pktDrop, "_pktDrop") + #pragma Alias (pktRxBuf, "_pktRxBuf") + #pragma Alias (pktTxBuf, "_pktTxBuf") + #pragma Alias (pktTemp, "_pktTemp") + #pragma Alias (rxOutOfs, "_rxOutOfs") + #pragma Alias (rxInOfs, "_rxInOfs") + #pragma Alias (pktRxEnd, "_pktRxEnd") + #pragma Alias (PktReceiver,"_PktReceiver") +#endif + + +PUBLIC PKT_STAT pktStat; /* statistics for packets */ +PUBLIC PKT_INFO pktInfo; /* packet-driver information */ + +PUBLIC PKT_RX_MODE receiveMode = PDRX_DIRECT; +PUBLIC ETHER myAddress = { 0, 0, 0, 0, 0, 0 }; +PUBLIC ETHER ethBroadcast = { 255,255,255,255,255,255 }; + +LOCAL struct { /* internal statistics */ + DWORD tooSmall; /* size < ETH_MIN */ + DWORD tooLarge; /* size > ETH_MAX */ + DWORD badSync; /* count_1 != count_2 */ + DWORD wrongHandle; /* upcall to wrong handle */ + } intStat; + +/***************************************************************************/ + +PUBLIC const char *PktGetErrorStr (int errNum) +{ + static const char *errStr[] = { + "", + "Invalid handle number", + "No interfaces of specified class found", + "No interfaces of specified type found", + "No interfaces of specified number found", + "Bad packet type specified", + "Interface does not support multicast", + "Packet driver cannot terminate", + "Invalid receiver mode specified", + "Insufficient memory space", + "Type previously accessed, and not released", + "Command out of range, or not implemented", + "Cannot send packet (usually hardware error)", + "Cannot change hardware address ( > 1 handle open)", + "Hardware address has bad length or format", + "Cannot reset interface (more than 1 handle open)", + "Bad Check-sum", + "Bad size", + "Bad sync" , + "Source hit" + }; + + if (errNum < 0 || errNum >= DIM(errStr)) + return ("Unknown driver error."); + return (errStr [errNum]); +} + +/**************************************************************************/ + +PUBLIC const char *PktGetClassName (WORD class) +{ + switch (class) + { + case PD_ETHER: + return ("DIX-Ether"); + case PD_PRONET10: + return ("ProNET-10"); + case PD_IEEE8025: + return ("IEEE 802.5"); + case PD_OMNINET: + return ("OmniNet"); + case PD_APPLETALK: + return ("AppleTalk"); + case PD_SLIP: + return ("SLIP"); + case PD_STARTLAN: + return ("StartLAN"); + case PD_ARCNET: + return ("ArcNet"); + case PD_AX25: + return ("AX.25"); + case PD_KISS: + return ("KISS"); + case PD_IEEE8023_2: + return ("IEEE 802.3 w/802.2 hdr"); + case PD_FDDI8022: + return ("FDDI w/802.2 hdr"); + case PD_X25: + return ("X.25"); + case PD_LANstar: + return ("LANstar"); + case PD_PPP: + return ("PPP"); + default: + return ("unknown"); + } +} + +/**************************************************************************/ + +PUBLIC char const *PktRXmodeStr (PKT_RX_MODE mode) +{ + static const char *modeStr [] = { + "Receiver turned off", + "Receive only directly addressed packets", + "Receive direct & broadcast packets", + "Receive direct,broadcast and limited multicast packets", + "Receive direct,broadcast and all multicast packets", + "Receive all packets (promiscuouos mode)" + }; + + if (mode > DIM(modeStr)) + return ("??"); + return (modeStr [mode-1]); +} + +/**************************************************************************/ + +LOCAL __inline BOOL PktInterrupt (void) +{ + BOOL okay; + +#if (DOSX & PHARLAP) + _dx_real_int ((UINT)pktInfo.intr, ®); + okay = ((reg.flags & 1) == 0); /* OK if carry clear */ + +#elif (DOSX & DJGPP) + __dpmi_int ((int)pktInfo.intr, ®); + okay = ((reg.x.flags & 1) == 0); + +#elif (DOSX & DOS4GW) + union REGS r; + struct SREGS s; + + memset (&r, 0, sizeof(r)); + segread (&s); + r.w.ax = 0x300; + r.x.ebx = pktInfo.intr; + r.w.cx = 0; + s.es = FP_SEG (®); + r.x.edi = FP_OFF (®); + reg.r_flags = 0; + reg.r_ss = reg.r_sp = 0; /* DPMI host provides stack */ + + int386x (0x31, &r, &r, &s); + okay = (!r.w.cflag); + +#else + reg.r_flags = 0; + intr (pktInfo.intr, (struct REGPACK*)®); + okay = ((reg.r_flags & 1) == 0); +#endif + + if (okay) + pktInfo.error = NULL; + else pktInfo.error = PktGetErrorStr (reg.r_dx >> 8); + return (okay); +} + +/**************************************************************************/ + +/* + * Search for packet driver at interrupt 60h through 80h. If ASCIIZ + * string "PKT DRVR" found at offset 3 in the interrupt handler, return + * interrupt number, else return zero in pktInfo.intr + */ +PUBLIC BOOL PktSearchDriver (void) +{ + BYTE intr = 0x20; + BOOL found = FALSE; + + while (!found && intr < 0xFF) + { + static char str[12]; /* 3 + strlen("PKT DRVR") */ + static char pktStr[9] = "PKT DRVR"; /* ASCIIZ string at ofs 3 */ + DWORD rp; /* in interrupt routine */ + +#if (DOSX & PHARLAP) + _dx_rmiv_get (intr, &rp); + ReadRealMem (&str, (REALPTR)rp, sizeof(str)); + +#elif (DOSX & DJGPP) + __dpmi_raddr realAdr; + __dpmi_get_real_mode_interrupt_vector (intr, &realAdr); + rp = (realAdr.segment << 4) + realAdr.offset16; + dosmemget (rp, sizeof(str), &str); + +#elif (DOSX & DOS4GW) + rp = dpmi_get_real_vector (intr); + memcpy (&str, (void*)rp, sizeof(str)); + +#else + _fmemcpy (&str, getvect(intr), sizeof(str)); +#endif + + found = memcmp (&str[3],&pktStr,sizeof(pktStr)) == 0; + intr++; + } + pktInfo.intr = (found ? intr-1 : 0); + return (found); +} + + +/**************************************************************************/ + +static BOOL PktSetAccess (void) +{ + reg.r_ax = 0x0200 + pktInfo.class; + reg.r_bx = 0xFFFF; + reg.r_dx = 0; + reg.r_cx = 0; + +#if (DOSX & PHARLAP) + reg.ds = 0; + reg.esi = 0; + reg.es = RP_SEG (realBase); + reg.edi = (WORD) &PktReceiver; + +#elif (DOSX & DJGPP) + reg.x.ds = 0; + reg.x.si = 0; + reg.x.es = rm_mem.rm_segment; + reg.x.di = PktReceiver; + +#elif (DOSX & DOS4GW) + reg.r_ds = 0; + reg.r_si = 0; + reg.r_es = rm_base_seg; + reg.r_di = PktReceiver; + +#else + reg.r_ds = 0; + reg.r_si = 0; + reg.r_es = FP_SEG (&PktReceiver); + reg.r_di = FP_OFF (&PktReceiver); +#endif + + if (!PktInterrupt()) + return (FALSE); + + pktInfo.handle = reg.r_ax; + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktReleaseHandle (WORD handle) +{ + reg.r_ax = 0x0300; + reg.r_bx = handle; + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktTransmit (const void *eth, int len) +{ + if (len > ETH_MTU) + return (FALSE); + + reg.r_ax = 0x0400; /* Function 4, send pkt */ + reg.r_cx = len; /* total size of frame */ + +#if (DOSX & DJGPP) + dosmemput (eth, len, realBase+pktTxBuf); + reg.x.ds = rm_mem.rm_segment; /* DOS data segment and */ + reg.x.si = pktTxBuf; /* DOS offset to buffer */ + +#elif (DOSX & DOS4GW) + memcpy ((void*)(realBase+pktTxBuf), eth, len); + reg.r_ds = rm_base_seg; + reg.r_si = pktTxBuf; + +#elif (DOSX & PHARLAP) + memcpy (&pktTxBuf, eth, len); + reg.r_ds = FP_SEG (&pktTxBuf); + reg.r_si = FP_OFF (&pktTxBuf); + +#else + reg.r_ds = FP_SEG (eth); + reg.r_si = FP_OFF (eth); +#endif + + return PktInterrupt(); +} + +/**************************************************************************/ + +#if (DOSX & (DJGPP|DOS4GW)) +LOCAL __inline BOOL CheckElement (RX_ELEMENT *rx) +#else +LOCAL __inline BOOL CheckElement (RX_ELEMENT _far *rx) +#endif +{ + WORD count_1, count_2; + + /* + * We got an upcall to the same RMCB with wrong handle. + * This can happen if we failed to release handle at program exit + */ + if (rx->handle != pktInfo.handle) + { + pktInfo.error = "Wrong handle"; + intStat.wrongHandle++; + PktReleaseHandle (rx->handle); + return (FALSE); + } + count_1 = rx->firstCount; + count_2 = rx->secondCount; + + if (count_1 != count_2) + { + pktInfo.error = "Bad sync"; + intStat.badSync++; + return (FALSE); + } + if (count_1 > ETH_MAX) + { + pktInfo.error = "Large esize"; + intStat.tooLarge++; + return (FALSE); + } +#if 0 + if (count_1 < ETH_MIN) + { + pktInfo.error = "Small esize"; + intStat.tooSmall++; + return (FALSE); + } +#endif + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktTerminHandle (WORD handle) +{ + reg.r_ax = 0x0500; + reg.r_bx = handle; + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktResetInterface (WORD handle) +{ + reg.r_ax = 0x0700; + reg.r_bx = handle; + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktSetReceiverMode (PKT_RX_MODE mode) +{ + if (pktInfo.class == PD_SLIP || pktInfo.class == PD_PPP) + return (TRUE); + + reg.r_ax = 0x1400; + reg.r_bx = pktInfo.handle; + reg.r_cx = (WORD)mode; + + if (!PktInterrupt()) + return (FALSE); + + receiveMode = mode; + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetReceiverMode (PKT_RX_MODE *mode) +{ + reg.r_ax = 0x1500; + reg.r_bx = pktInfo.handle; + + if (!PktInterrupt()) + return (FALSE); + + *mode = reg.r_ax; + return (TRUE); +} + +/**************************************************************************/ + +static PKT_STAT initialStat; /* statistics at startup */ +static BOOL resetStat = FALSE; /* statistics reset ? */ + +PUBLIC BOOL PktGetStatistics (WORD handle) +{ + reg.r_ax = 0x1800; + reg.r_bx = handle; + + if (!PktInterrupt()) + return (FALSE); + +#if (DOSX & PHARLAP) + ReadRealMem (&pktStat, DOS_ADDR(reg.ds,reg.esi), sizeof(pktStat)); + +#elif (DOSX & DJGPP) + dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktStat), &pktStat); + +#elif (DOSX & DOS4GW) + memcpy (&pktStat, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktStat)); + +#else + _fmemcpy (&pktStat, MK_FP(reg.r_ds,reg.r_si), sizeof(pktStat)); +#endif + + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktSessStatistics (WORD handle) +{ + if (!PktGetStatistics(pktInfo.handle)) + return (FALSE); + + if (resetStat) + { + pktStat.inPackets -= initialStat.inPackets; + pktStat.outPackets -= initialStat.outPackets; + pktStat.inBytes -= initialStat.inBytes; + pktStat.outBytes -= initialStat.outBytes; + pktStat.inErrors -= initialStat.inErrors; + pktStat.outErrors -= initialStat.outErrors; + pktStat.outErrors -= initialStat.outErrors; + pktStat.lost -= initialStat.lost; + } + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktResetStatistics (WORD handle) +{ + if (!PktGetStatistics(pktInfo.handle)) + return (FALSE); + + memcpy (&initialStat, &pktStat, sizeof(initialStat)); + resetStat = TRUE; + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetAddress (ETHER *addr) +{ + reg.r_ax = 0x0600; + reg.r_bx = pktInfo.handle; + reg.r_cx = sizeof (*addr); + +#if (DOSX & DJGPP) + reg.x.es = rm_mem.rm_segment; + reg.x.di = pktTemp; +#elif (DOSX & DOS4GW) + reg.r_es = rm_base_seg; + reg.r_di = pktTemp; +#else + reg.r_es = FP_SEG (&pktTemp); + reg.r_di = FP_OFF (&pktTemp); /* ES:DI = address for result */ +#endif + + if (!PktInterrupt()) + return (FALSE); + +#if (DOSX & PHARLAP) + ReadRealMem (addr, realBase + (WORD)&pktTemp, sizeof(*addr)); + +#elif (DOSX & DJGPP) + dosmemget (realBase+pktTemp, sizeof(*addr), addr); + +#elif (DOSX & DOS4GW) + memcpy (addr, (void*)(realBase+pktTemp), sizeof(*addr)); + +#else + memcpy ((void*)addr, &pktTemp, sizeof(*addr)); +#endif + + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktSetAddress (const ETHER *addr) +{ + /* copy addr to real-mode scrath area */ + +#if (DOSX & PHARLAP) + WriteRealMem (realBase + (WORD)&pktTemp, (void*)addr, sizeof(*addr)); + +#elif (DOSX & DJGPP) + dosmemput (addr, sizeof(*addr), realBase+pktTemp); + +#elif (DOSX & DOS4GW) + memcpy ((void*)(realBase+pktTemp), addr, sizeof(*addr)); + +#else + memcpy (&pktTemp, (void*)addr, sizeof(*addr)); +#endif + + reg.r_ax = 0x1900; + reg.r_cx = sizeof (*addr); /* address length */ + +#if (DOSX & DJGPP) + reg.x.es = rm_mem.rm_segment; /* DOS offset to param */ + reg.x.di = pktTemp; /* DOS segment to param */ +#elif (DOSX & DOS4GW) + reg.r_es = rm_base_seg; + reg.r_di = pktTemp; +#else + reg.r_es = FP_SEG (&pktTemp); + reg.r_di = FP_OFF (&pktTemp); +#endif + + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetDriverInfo (void) +{ + pktInfo.majVer = 0; + pktInfo.minVer = 0; + memset (&pktInfo.name, 0, sizeof(pktInfo.name)); + reg.r_ax = 0x01FF; + reg.r_bx = 0; + + if (!PktInterrupt()) + return (FALSE); + + pktInfo.number = reg.r_cx & 0xFF; + pktInfo.class = reg.r_cx >> 8; +#if 0 + pktInfo.minVer = reg.r_bx % 10; + pktInfo.majVer = reg.r_bx / 10; +#else + pktInfo.majVer = reg.r_bx; // !! +#endif + pktInfo.funcs = reg.r_ax & 0xFF; + pktInfo.type = reg.r_dx & 0xFF; + +#if (DOSX & PHARLAP) + ReadRealMem (&pktInfo.name, DOS_ADDR(reg.ds,reg.esi), sizeof(pktInfo.name)); + +#elif (DOSX & DJGPP) + dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktInfo.name), &pktInfo.name); + +#elif (DOSX & DOS4GW) + memcpy (&pktInfo.name, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktInfo.name)); + +#else + _fmemcpy (&pktInfo.name, MK_FP(reg.r_ds,reg.r_si), sizeof(pktInfo.name)); +#endif + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetDriverParam (void) +{ + reg.r_ax = 0x0A00; + + if (!PktInterrupt()) + return (FALSE); + +#if (DOSX & PHARLAP) + ReadRealMem (&pktInfo.majVer, DOS_ADDR(reg.es,reg.edi), PKT_PARAM_SIZE); + +#elif (DOSX & DJGPP) + dosmemget (DOS_ADDR(reg.x.es,reg.x.di), PKT_PARAM_SIZE, &pktInfo.majVer); + +#elif (DOSX & DOS4GW) + memcpy (&pktInfo.majVer, (void*)DOS_ADDR(reg.r_es,reg.r_di), PKT_PARAM_SIZE); + +#else + _fmemcpy (&pktInfo.majVer, MK_FP(reg.r_es,reg.r_di), PKT_PARAM_SIZE); +#endif + return (TRUE); +} + +/**************************************************************************/ + +#if (DOSX & PHARLAP) + PUBLIC int PktReceive (BYTE *buf, int max) + { + WORD inOfs = *rxInOfsFp; + WORD outOfs = *rxOutOfsFp; + + if (outOfs != inOfs) + { + RX_ELEMENT _far *head = (RX_ELEMENT _far*)(protBase+outOfs); + int size, len = max; + + if (CheckElement(head)) + { + size = min (head->firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + _fmemcpy (buf, &head->destin, len); + } + else + size = -1; + + outOfs += sizeof (RX_ELEMENT); + if (outOfs > LAST_RX_BUF) + outOfs = FIRST_RX_BUF; + *rxOutOfsFp = outOfs; + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + *rxOutOfsFp = busy ? (*rxInOfsFp + sizeof(RX_ELEMENT)) : *rxInOfsFp; + if (*rxOutOfsFp > LAST_RX_BUF) + *rxOutOfsFp = FIRST_RX_BUF; + *(DWORD _far*)(protBase + (WORD)&pktDrop) = 0; + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs = *rxInOfsFp; + WORD outOfs = *rxOutOfsFp; + + if (inOfs >= outOfs) + return (inOfs - outOfs) / sizeof(RX_ELEMENT); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return (*(DWORD _far*)(protBase + (WORD)&pktDrop)); + } + +#elif (DOSX & DJGPP) + PUBLIC int PktReceive (BYTE *buf, int max) + { + WORD ofs = _farpeekw (_dos_ds, realBase+rxOutOfs); + + if (ofs != _farpeekw (_dos_ds, realBase+rxInOfs)) + { + RX_ELEMENT head; + int size, len = max; + + head.firstCount = _farpeekw (_dos_ds, realBase+ofs); + head.secondCount = _farpeekw (_dos_ds, realBase+ofs+2); + head.handle = _farpeekw (_dos_ds, realBase+ofs+4); + + if (CheckElement(&head)) + { + size = min (head.firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + dosmemget (realBase+ofs+6, len, buf); + } + else + size = -1; + + ofs += sizeof (RX_ELEMENT); + if (ofs > LAST_RX_BUF) + _farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); + else _farpokew (_dos_ds, realBase+rxOutOfs, ofs); + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + WORD ofs; + + disable(); + ofs = _farpeekw (_dos_ds, realBase+rxInOfs); + if (busy) + ofs += sizeof (RX_ELEMENT); + + if (ofs > LAST_RX_BUF) + _farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); + else _farpokew (_dos_ds, realBase+rxOutOfs, ofs); + _farpokel (_dos_ds, realBase+pktDrop, 0UL); + enable(); + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs, outOfs; + + disable(); + inOfs = _farpeekw (_dos_ds, realBase+rxInOfs); + outOfs = _farpeekw (_dos_ds, realBase+rxOutOfs); + enable(); + if (inOfs >= outOfs) + return (inOfs - outOfs) / sizeof(RX_ELEMENT); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return _farpeekl (_dos_ds, realBase+pktDrop); + } + +#elif (DOSX & DOS4GW) + PUBLIC int PktReceive (BYTE *buf, int max) + { + WORD ofs = *(WORD*) (realBase+rxOutOfs); + + if (ofs != *(WORD*) (realBase+rxInOfs)) + { + RX_ELEMENT head; + int size, len = max; + + head.firstCount = *(WORD*) (realBase+ofs); + head.secondCount = *(WORD*) (realBase+ofs+2); + head.handle = *(WORD*) (realBase+ofs+4); + + if (CheckElement(&head)) + { + size = min (head.firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + memcpy (buf, (const void*)(realBase+ofs+6), len); + } + else + size = -1; + + ofs += sizeof (RX_ELEMENT); + if (ofs > LAST_RX_BUF) + *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; + else *(WORD*) (realBase+rxOutOfs) = ofs; + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + WORD ofs; + + _disable(); + ofs = *(WORD*) (realBase+rxInOfs); + if (busy) + ofs += sizeof (RX_ELEMENT); + + if (ofs > LAST_RX_BUF) + *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; + else *(WORD*) (realBase+rxOutOfs) = ofs; + *(DWORD*) (realBase+pktDrop) = 0UL; + _enable(); + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs, outOfs; + + _disable(); + inOfs = *(WORD*) (realBase+rxInOfs); + outOfs = *(WORD*) (realBase+rxOutOfs); + _enable(); + if (inOfs >= outOfs) + return (inOfs - outOfs) / sizeof(RX_ELEMENT); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return *(DWORD*) (realBase+pktDrop); + } + +#else /* real-mode small/large model */ + + PUBLIC int PktReceive (BYTE *buf, int max) + { + if (rxOutOfs != rxInOfs) + { + RX_ELEMENT far *head = (RX_ELEMENT far*) MK_FP (_DS,rxOutOfs); + int size, len = max; + + if (CheckElement(head)) + { + size = min (head->firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + _fmemcpy (buf, &head->destin, len); + } + else + size = -1; + + rxOutOfs += sizeof (RX_ELEMENT); + if (rxOutOfs > LAST_RX_BUF) + rxOutOfs = FIRST_RX_BUF; + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + rxOutOfs = busy ? (rxInOfs + sizeof(RX_ELEMENT)) : rxInOfs; + if (rxOutOfs > LAST_RX_BUF) + rxOutOfs = FIRST_RX_BUF; + pktDrop = 0L; + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs = rxInOfs; + WORD outOfs = rxOutOfs; + + if (inOfs >= outOfs) + return ((inOfs - outOfs) / sizeof(RX_ELEMENT)); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return (pktDrop); + } +#endif + +/**************************************************************************/ + +LOCAL __inline void PktFreeMem (void) +{ +#if (DOSX & PHARLAP) + if (realSeg) + { + _dx_real_free (realSeg); + realSeg = 0; + } +#elif (DOSX & DJGPP) + if (rm_mem.rm_segment) + { + unsigned ofs; /* clear the DOS-mem to prevent further upcalls */ + + for (ofs = 0; ofs < 16 * rm_mem.size / 4; ofs += 4) + _farpokel (_dos_ds, realBase + ofs, 0); + _go32_dpmi_free_dos_memory (&rm_mem); + rm_mem.rm_segment = 0; + } +#elif (DOSX & DOS4GW) + if (rm_base_sel) + { + dpmi_real_free (rm_base_sel); + rm_base_sel = 0; + } +#endif +} + +/**************************************************************************/ + +PUBLIC BOOL PktExitDriver (void) +{ + if (pktInfo.handle) + { + if (!PktSetReceiverMode(PDRX_BROADCAST)) + PUTS ("Error restoring receiver mode."); + + if (!PktReleaseHandle(pktInfo.handle)) + PUTS ("Error releasing PKT-DRVR handle."); + + PktFreeMem(); + pktInfo.handle = 0; + } + + if (pcap_pkt_debug >= 1) + printf ("Internal stats: too-small %lu, too-large %lu, bad-sync %lu, " + "wrong-handle %lu\n", + intStat.tooSmall, intStat.tooLarge, + intStat.badSync, intStat.wrongHandle); + return (TRUE); +} + +#if (DOSX & (DJGPP|DOS4GW)) +static void dump_pkt_stub (void) +{ + int i; + + fprintf (stderr, "PktReceiver %lu, pkt_stub[PktReceiver] =\n", + PktReceiver); + for (i = 0; i < 15; i++) + fprintf (stderr, "%02X, ", real_stub_array[i+PktReceiver]); + fputs ("\n", stderr); +} +#endif + +/* + * Front end initialization routine + */ +PUBLIC BOOL PktInitDriver (PKT_RX_MODE mode) +{ + PKT_RX_MODE rxMode; + BOOL writeInfo = (pcap_pkt_debug >= 3); + + pktInfo.quiet = (pcap_pkt_debug < 3); + +#if (DOSX & PHARLAP) && defined(__HIGHC__) + if (_mwenv != 2) + { + fprintf (stderr, "Only Pharlap DOS extender supported.\n"); + return (FALSE); + } +#endif + +#if (DOSX & PHARLAP) && defined(__WATCOMC__) + if (_Extender != 1) + { + fprintf (stderr, "Only DOS4GW style extenders supported.\n"); + return (FALSE); + } +#endif + + if (!PktSearchDriver()) + { + PUTS ("Packet driver not found."); + PktFreeMem(); + return (FALSE); + } + + if (!PktGetDriverInfo()) + { + PUTS ("Error getting pkt-drvr information."); + PktFreeMem(); + return (FALSE); + } + +#if (DOSX & PHARLAP) + if (RealCopy((ULONG)&rxOutOfs, (ULONG)&pktRxEnd, + &realBase, &protBase, (USHORT*)&realSeg)) + { + rxOutOfsFp = (WORD _far *) (protBase + (WORD) &rxOutOfs); + rxInOfsFp = (WORD _far *) (protBase + (WORD) &rxInOfs); + *rxOutOfsFp = FIRST_RX_BUF; + *rxInOfsFp = FIRST_RX_BUF; + } + else + { + PUTS ("Cannot allocate real-mode stub."); + return (FALSE); + } + +#elif (DOSX & (DJGPP|DOS4GW)) + if (sizeof(real_stub_array) > 0xFFFF) + { + fprintf (stderr, "`real_stub_array[]' too big.\n"); + return (FALSE); + } +#if (DOSX & DJGPP) + rm_mem.size = (sizeof(real_stub_array) + 15) / 16; + + if (_go32_dpmi_allocate_dos_memory(&rm_mem) || rm_mem.rm_offset != 0) + { + PUTS ("real-mode init failed."); + return (FALSE); + } + realBase = (rm_mem.rm_segment << 4); + dosmemput (&real_stub_array, sizeof(real_stub_array), realBase); + _farpokel (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); + _farpokel (_dos_ds, realBase+rxInOfs, FIRST_RX_BUF); + +#elif (DOSX & DOS4GW) + rm_base_seg = dpmi_real_malloc (sizeof(real_stub_array), &rm_base_sel); + if (!rm_base_seg) + { + PUTS ("real-mode init failed."); + return (FALSE); + } + realBase = (rm_base_seg << 4); + memcpy ((void*)realBase, &real_stub_array, sizeof(real_stub_array)); + *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; + *(WORD*) (realBase+rxInOfs) = FIRST_RX_BUF; + +#endif + { + int pushf = PktReceiver; + + while (real_stub_array[pushf++] != 0x9C && /* pushf */ + real_stub_array[pushf] != 0xFA) /* cli */ + { + if (++para_skip > 16) + { + fprintf (stderr, "Something wrong with `pkt_stub.inc'.\n"); + para_skip = 0; + dump_pkt_stub(); + return (FALSE); + } + } + if (*(WORD*)(real_stub_array + offsetof(PktRealStub,_dummy)) != 0xB800) + { + fprintf (stderr, "`real_stub_array[]' is misaligned.\n"); + return (FALSE); + } + } + + if (pcap_pkt_debug > 2) + dump_pkt_stub(); + +#else + rxOutOfs = FIRST_RX_BUF; + rxInOfs = FIRST_RX_BUF; +#endif + + if (!PktSetAccess()) + { + PUTS ("Error setting pkt-drvr access."); + PktFreeMem(); + return (FALSE); + } + + if (!PktGetAddress(&myAddress)) + { + PUTS ("Error fetching adapter address."); + PktFreeMem(); + return (FALSE); + } + + if (!PktSetReceiverMode(mode)) + { + PUTS ("Error setting receiver mode."); + PktFreeMem(); + return (FALSE); + } + + if (!PktGetReceiverMode(&rxMode)) + { + PUTS ("Error getting receiver mode."); + PktFreeMem(); + return (FALSE); + } + + if (writeInfo) + printf ("Pkt-driver information:\n" + " Version : %d.%d\n" + " Name : %.15s\n" + " Class : %u (%s)\n" + " Type : %u\n" + " Number : %u\n" + " Funcs : %u\n" + " Intr : %Xh\n" + " Handle : %u\n" + " Extended : %s\n" + " Hi-perf : %s\n" + " RX mode : %s\n" + " Eth-addr : %02X:%02X:%02X:%02X:%02X:%02X\n", + + pktInfo.majVer, pktInfo.minVer, pktInfo.name, + pktInfo.class, PktGetClassName(pktInfo.class), + pktInfo.type, pktInfo.number, + pktInfo.funcs, pktInfo.intr, pktInfo.handle, + pktInfo.funcs == 2 || pktInfo.funcs == 6 ? "Yes" : "No", + pktInfo.funcs == 5 || pktInfo.funcs == 6 ? "Yes" : "No", + PktRXmodeStr(rxMode), + myAddress[0], myAddress[1], myAddress[2], + myAddress[3], myAddress[4], myAddress[5]); + +#if defined(DEBUG) && (DOSX & PHARLAP) + if (writeInfo) + { + DWORD rAdr = realBase + (WORD)&PktReceiver; + unsigned sel, ofs; + + printf ("\nReceiver at %04X:%04X\n", RP_SEG(rAdr), RP_OFF(rAdr)); + printf ("Realbase = %04X:%04X\n", RP_SEG(realBase),RP_OFF(realBase)); + + sel = _FP_SEG (protBase); + ofs = _FP_OFF (protBase); + printf ("Protbase = %04X:%08X\n", sel,ofs); + printf ("RealSeg = %04X\n", realSeg); + + sel = _FP_SEG (rxOutOfsFp); + ofs = _FP_OFF (rxOutOfsFp); + printf ("rxOutOfsFp = %04X:%08X\n", sel,ofs); + + sel = _FP_SEG (rxInOfsFp); + ofs = _FP_OFF (rxInOfsFp); + printf ("rxInOfsFp = %04X:%08X\n", sel,ofs); + + printf ("Ready: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n", + *rxOutOfsFp, *rxInOfsFp); + + PktQueueBusy (TRUE); + printf ("Busy: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n", + *rxOutOfsFp, *rxInOfsFp); + } +#endif + + memset (&pktStat, 0, sizeof(pktStat)); /* clear statistics */ + PktQueueBusy (TRUE); + return (TRUE); +} + + +/* + * DPMI functions only for Watcom + DOS4GW extenders + */ +#if (DOSX & DOS4GW) +LOCAL DWORD dpmi_get_real_vector (int intr) +{ + union REGS r; + + r.x.eax = 0x200; + r.x.ebx = (DWORD) intr; + int386 (0x31, &r, &r); + return ((r.w.cx << 4) + r.w.dx); +} + +LOCAL WORD dpmi_real_malloc (int size, WORD *selector) +{ + union REGS r; + + r.x.eax = 0x0100; /* DPMI allocate DOS memory */ + r.x.ebx = (size + 15) / 16; /* Number of paragraphs requested */ + int386 (0x31, &r, &r); + if (r.w.cflag & 1) + return (0); + + *selector = r.w.dx; + return (r.w.ax); /* Return segment address */ +} + +LOCAL void dpmi_real_free (WORD selector) +{ + union REGS r; + + r.x.eax = 0x101; /* DPMI free DOS memory */ + r.x.ebx = selector; /* Selector to free */ + int386 (0x31, &r, &r); +} +#endif + + +#if defined(DOSX) && (DOSX & PHARLAP) +/* + * Description: + * This routine allocates conventional memory for the specified block + * of code (which must be within the first 64K of the protected mode + * program segment) and copies the code to it. + * + * The caller should free up the conventional memory block when it + * is done with the conventional memory. + * + * NOTE THIS ROUTINE REQUIRES 386|DOS-EXTENDER 3.0 OR LATER. + * + * Calling arguments: + * start_offs start of real mode code in program segment + * end_offs 1 byte past end of real mode code in program segment + * real_basep returned; real mode ptr to use as a base for the + * real mode code (eg, to get the real mode FAR + * addr of a function foo(), take + * real_basep + (ULONG) foo). + * This pointer is constructed such that + * offsets within the real mode segment are + * the same as the link-time offsets in the + * protected mode program segment + * prot_basep returned; prot mode ptr to use as a base for getting + * to the conventional memory, also constructed + * so that adding the prot mode offset of a + * function or variable to the base gets you a + * ptr to the function or variable in the + * conventional memory block. + * rmem_adrp returned; real mode para addr of allocated + * conventional memory block, to be used to free + * up the conventional memory when done. DO NOT + * USE THIS TO CONSTRUCT A REAL MODE PTR, USE + * REAL_BASEP INSTEAD SO THAT OFFSETS WORK OUT + * CORRECTLY. + * + * Returned values: + * 0 if error + * 1 if success + */ +int RealCopy (ULONG start_offs, + ULONG end_offs, + REALPTR *real_basep, + FARPTR *prot_basep, + USHORT *rmem_adrp) +{ + ULONG rm_base; /* base real mode para addr for accessing */ + /* allocated conventional memory */ + UCHAR *source; /* source pointer for copy */ + FARPTR destin; /* destination pointer for copy */ + ULONG len; /* number of bytes to copy */ + ULONG temp; + USHORT stemp; + + /* First check for valid inputs + */ + if (start_offs >= end_offs || end_offs > 0x10000) + return (FALSE); + + /* Round start_offs down to a paragraph (16-byte) boundary so we can set up + * the real mode pointer easily. Round up end_offs to make sure we allocate + * enough paragraphs + */ + start_offs &= ~15; + end_offs = (15 + (end_offs << 4)) >> 4; + + /* Allocate the conventional memory for our real mode code. Remember to + * round byte count UP to 16-byte paragraph size. We alloc it + * above the DOS data buffer so both the DOS data buffer and the appl + * conventional mem block can still be resized. + * + * First just try to alloc it; if we can't get it, shrink the appl mem + * block down to the minimum, try to alloc the memory again, then grow the + * appl mem block back to the maximum. (Don't try to shrink the DOS data + * buffer to free conventional memory; it wouldn't be good for this routine + * to have the possible side effect of making file I/O run slower.) + */ + len = ((end_offs - start_offs) + 15) >> 4; + if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE) + { + if (_dx_cmem_usage(0, 0, &temp, &temp) != _DOSE_NONE) + return (FALSE); + + if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE) + *rmem_adrp = 0; + + if (_dx_cmem_usage(0, 1, &temp, &temp) != _DOSE_NONE) + { + if (*rmem_adrp != 0) + _dx_real_free (*rmem_adrp); + return (FALSE); + } + + if (*rmem_adrp == 0) + return (FALSE); + } + + /* Construct real mode & protected mode pointers to access the allocated + * memory. Note we know start_offs is aligned on a paragraph (16-byte) + * boundary, because we rounded it down. + * + * We make the offsets come out rights by backing off the real mode selector + * by start_offs. + */ + rm_base = ((ULONG) *rmem_adrp) - (start_offs >> 4); + RP_SET (*real_basep, 0, rm_base); + FP_SET (*prot_basep, rm_base << 4, SS_DOSMEM); + + /* Copy the real mode code/data to the allocated memory + */ + source = (UCHAR *) start_offs; + destin = *prot_basep; + FP_SET (destin, FP_OFF(*prot_basep) + start_offs, FP_SEL(*prot_basep)); + len = end_offs - start_offs; + WriteFarMem (destin, source, len); + + return (TRUE); +} +#endif /* DOSX && (DOSX & PHARLAP) */ diff --git a/tcpdump/jni/libpcap/msdos/pktdrvr.h b/tcpdump/jni/libpcap/msdos/pktdrvr.h new file mode 100644 index 0000000..08898ae --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/pktdrvr.h @@ -0,0 +1,153 @@ +#ifndef __PKTDRVR_H +#define __PKTDRVR_H + +#define PUBLIC +#define LOCAL static + +#define RX_BUF_SIZE ETH_MTU /* buffer size variables. NB !! */ +#define TX_BUF_SIZE ETH_MTU /* must be same as in pkt_rx*.* */ + +#ifdef __HIGHC__ +#pragma Off(Align_members) +#else +#pragma pack(1) +#endif + +typedef enum { /* Packet-driver classes */ + PD_ETHER = 1, + PD_PRONET10 = 2, + PD_IEEE8025 = 3, + PD_OMNINET = 4, + PD_APPLETALK = 5, + PD_SLIP = 6, + PD_STARTLAN = 7, + PD_ARCNET = 8, + PD_AX25 = 9, + PD_KISS = 10, + PD_IEEE8023_2 = 11, + PD_FDDI8022 = 12, + PD_X25 = 13, + PD_LANstar = 14, + PD_PPP = 18 + } PKT_CLASS; + +typedef enum { /* Packet-driver receive modes */ + PDRX_OFF = 1, /* turn off receiver */ + PDRX_DIRECT, /* receive only to this interface */ + PDRX_BROADCAST, /* DIRECT + broadcast packets */ + PDRX_MULTICAST1, /* BROADCAST + limited multicast */ + PDRX_MULTICAST2, /* BROADCAST + all multicast */ + PDRX_ALL_PACKETS, /* receive all packets on network */ + } PKT_RX_MODE; + +typedef struct { + char type[8]; + char len; + } PKT_FRAME; + + +typedef struct { + BYTE class; /* = 1 for DEC/Interl/Xerox Ethernet */ + BYTE number; /* = 0 for single LAN adapter */ + WORD type; /* = 13 for 3C523 */ + BYTE funcs; /* Basic/Extended/HiPerf functions */ + WORD intr; /* user interrupt vector number */ + WORD handle; /* Handle associated with session */ + BYTE name [15]; /* Name of adapter interface,ie.3C523*/ + BOOL quiet; /* (don't) print errors to stdout */ + const char *error; /* address of error string */ + BYTE majVer; /* Major driver implementation ver. */ + BYTE minVer; /* Minor driver implementation ver. */ + BYTE dummyLen; /* length of following data */ + WORD MAClength; /* HiPerformance data, N/A */ + WORD MTU; /* HiPerformance data, N/A */ + WORD multicast; /* HiPerformance data, N/A */ + WORD rcvrBuffers; /* valid for */ + WORD UMTbufs; /* High Performance drivers only */ + WORD postEOIintr; /* Usage ?? */ + } PKT_INFO; + +#define PKT_PARAM_SIZE 14 /* members majVer - postEOIintr */ + + +typedef struct { + DWORD inPackets; /* # of packets received */ + DWORD outPackets; /* # of packets transmitted */ + DWORD inBytes; /* # of bytes received */ + DWORD outBytes; /* # of bytes transmitted */ + DWORD inErrors; /* # of reception errors */ + DWORD outErrors; /* # of transmission errors */ + DWORD lost; /* # of packets lost (RX) */ + } PKT_STAT; + + +typedef struct { + ETHER destin; + ETHER source; + WORD proto; + BYTE data [TX_BUF_SIZE]; + } TX_ELEMENT; + +typedef struct { + WORD firstCount; /* # of bytes on 1st */ + WORD secondCount; /* and 2nd upcall */ + WORD handle; /* instance that upcalled */ + ETHER destin; /* E-net destination address */ + ETHER source; /* E-net source address */ + WORD proto; /* protocol number */ + BYTE data [RX_BUF_SIZE]; + } RX_ELEMENT; + + +#ifdef __HIGHC__ +#pragma pop(Align_members) +#else +#pragma pack() +#endif + + +/* + * Prototypes for publics + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern PKT_STAT pktStat; /* statistics for packets */ +extern PKT_INFO pktInfo; /* packet-driver information */ + +extern PKT_RX_MODE receiveMode; +extern ETHER myAddress, ethBroadcast; + +extern BOOL PktInitDriver (PKT_RX_MODE mode); +extern BOOL PktExitDriver (void); + +extern const char *PktGetErrorStr (int errNum); +extern const char *PktGetClassName (WORD class); +extern const char *PktRXmodeStr (PKT_RX_MODE mode); +extern BOOL PktSearchDriver (void); +extern int PktReceive (BYTE *buf, int max); +extern BOOL PktTransmit (const void *eth, int len); +extern DWORD PktRxDropped (void); +extern BOOL PktReleaseHandle (WORD handle); +extern BOOL PktTerminHandle (WORD handle); +extern BOOL PktResetInterface (WORD handle); +extern BOOL PktSetReceiverMode(PKT_RX_MODE mode); +extern BOOL PktGetReceiverMode(PKT_RX_MODE *mode); +extern BOOL PktGetStatistics (WORD handle); +extern BOOL PktSessStatistics (WORD handle); +extern BOOL PktResetStatistics(WORD handle); +extern BOOL PktGetAddress (ETHER *addr); +extern BOOL PktSetAddress (const ETHER *addr); +extern BOOL PktGetDriverInfo (void); +extern BOOL PktGetDriverParam (void); +extern void PktQueueBusy (BOOL busy); +extern WORD PktBuffersUsed (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __PKTDRVR_H */ + diff --git a/tcpdump/jni/libpcap/msdos/readme.dos b/tcpdump/jni/libpcap/msdos/readme.dos new file mode 100644 index 0000000..353d0cc --- /dev/null +++ b/tcpdump/jni/libpcap/msdos/readme.dos @@ -0,0 +1,160 @@ +libpcap for DOS +--------------- + +This file contains some notes on building and using libpcap for MS-DOS. +Look in `README' and `pcap.man' for usage and details. These targets are +supported: + + - Borland C 4.0+ small or large model. + - Metaware HighC 3.1+ with PharLap DOS-extender + - GNU C 2.7+ with djgpp 2.01+ DOS extender + - Watcom C 11.x with DOS4GW extender + +Note: the files in the libpcap.zip contains short trucated filenames. + So for djgpp to work with these, disable the use of long file names by + setting "LFN=n" in the environment. + +Files specific to DOS are pcap-dos.[ch] and the assembly and C files in +the MSDOS sub-directory. Remember to built lipcap libraries from the top +install directory. And not from the MSDOS sub-directory. + +Note for djgpp users: + If you got the libpcap from the official site www.tcpdump, then that + distribution does NOT contain any sources for building 32-bit drivers. + Instead get the full version at + http://www.bgnett.no/~giva/pcap/libpcap.zip + + and set "USE_32BIT_DRIVERS = 1" in msdos\common.dj. + + + +Requirements +------------ + +DOS-libpcap currently only works reliably with a real-mode Ethernet packet- +driver. This driver must be installed prior to using any program (e.g. +tcpdump) compiled with libpcap. Work is underway to implement protected- +mode drivers for 32-bit targets (djgpp only). The 3Com 3c509 driver is +working almost perfectly. Due to lack of LAN-cards, I've not had the +opportunity to test other drivers. These 32-bit drivers are modified +Linux drivers. + + +Required packages +----------------- + +The following packages and tools must be present for all targets. + +1. Watt-32 tcp/ip library. This library is *not* used to send or + receive network data. It's mostly used to access the 'hosts' + file and other features. Get 'watt32s*.zip' at: + + http://www.bgnett.no/~giva/ + +2. Exception handler and disassember library (libexc.a) is needed if + "USE_EXCEPT = 1" in common.dj. Available at: + + http://www.bgnett.no/~giva/misc/exc_dx07.zip + +3. Flex & Bison is used to generate parser for the filter handler + pcap_compile: + + ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/flx254b.zip + ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsn128b.zip + +4. NASM assembler v 0.98 or later is required when building djgpp and + Watcom targets: + + ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2tk/nasm098p.zip + +5. sed (Stream Editor) is required for doing `make depend'. + It's available at + ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/sed*.zip + + A touch tool to update the time-stamp of a file. E.g. + ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/grep*.zip + +6. For djgpp rm.exe and cp.exe are required. These should already be + part of your djgpp installation. Also required (experimental at the + time) for djgpp is DLX 2.91 or later. This tool is for the generation + of dynamically loadable modules. + + +Compiling libpcap +----------------- + +Follow these steps in building libpcap: + +1. Make sure you've installed Watt-32 properly (see it's `INSTALL' file). + During that installation a environment variable `WATT_ROOT' is set. + This variable is used for building libpcap also (`WATT_INC' is + deducted from `WATT_ROOT'). djgpp users should also define environment + variables `C_INCLUDE_PATH' and `LIBRARY_PATH' to point to the include + directory and library directory respectively. E.g. put this in your + AUTOEXEC.BAT: + set C_INCLUDE_PATH=c:/net/watt/inc + set LIBRARY_PATH=c:/net/watt/lib + +2. Revise the msdos/common.dj file for your djgpp/gcc installation; + - change the value of `GCCLIB' to match location of libgcc.a. + - set `USE_32BIT_DRIVERS = 1' to build 32-bit driver objects. + + +3. Build pcap by using appropriate makefile. For djgpp, use: + `make -f msdos/makefile.dj' (i.e. GNU `make') + + For a Watcom target say: + `wmake -f msdos\makefile.wc' + + For a Borland target say: + `maker -f msdos\Makefile pcap_bc.lib' (Borland's `maker.exe') + + And for a HighC/Pharlap target say: + `maker -f msdos\Makefile pcap_hc.lib' (Borland's `maker.exe') + + You might like to change some `CFLAGS' -- only `DEBUG' define currently + have any effect. It shows a rotating "fan" in upper right corner of + screen. Remove `DEBUG' if you don't like it. You could add + `-fomit-frame-pointer' to `CFLAGS' to speed up the generated code. + But note, this makes debugging and crash-traceback difficult. Only + add it if you're fully confident your application is 100% stable. + + Note: Code in `USE_NDIS2' does not work at the moment. + +4. The resulting libraries are put in current directory. There's no + test-program for `libpcap'. Linking the library with `tcpdump' is + the ultimate test anyway. + + + +Extensions to libpcap +--------------------- + +I've included some extra functions to DOS-libpcap: + + `pcap_config_hook (const char *name, const char *value)' + + Allows an application to set values of internal libpcap variables. + `name' is typically a left-side keyword with an associated `value' + that is called from application's configure process (see tcpdump's + config.c file). libpcap keeps a set of tables that are searched for + a name/value match. Currently only used to set debug-levels and + parameters for the 32-bit network drivers. + + `pcap_set_wait (pcap_t *, void (*)(void), int)' : + + Only effective when reading offline traffic from dump-files. + Function `pcap_offline_read()' will wait (and optionally yield) + before printing next packet. This will simulate the pace the packets + where actually recorded. + + + +Happy sniffing ! + + +Gisle Vanem + + +October 1999, 2004 + diff --git a/tcpdump/jni/libpcap/nametoaddr.c b/tcpdump/jni/libpcap/nametoaddr.c new file mode 100644 index 0000000..e6483a3 --- /dev/null +++ b/tcpdump/jni/libpcap/nametoaddr.c @@ -0,0 +1,509 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Name to id translation routines used by the scanner. + * These functions are not time critical. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef DECNETLIB +#include +#include +#endif + +#ifdef WIN32 +#include + +#else /* WIN32 */ + +#include +#include /* concession to AIX */ +#include +#include + +#include +#endif /* WIN32 */ + +#ifndef WIN32 +#ifdef HAVE_ETHER_HOSTTON +/* + * XXX - do we need any of this if doesn't declare + * ether_hostton()? + */ +#ifdef HAVE_NETINET_IF_ETHER_H +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ +#include /* for "struct ifnet" in "struct arpcom" on Solaris */ +#include +#endif /* HAVE_NETINET_IF_ETHER_H */ +#ifdef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON +#include +#endif /* NETINET_ETHER_H_DECLARES_ETHER_HOSTTON */ +#endif /* HAVE_ETHER_HOSTTON */ +#include +#include +#endif /* WIN32 */ + +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#include "gencode.h" +#include + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#ifndef NTOHL +#define NTOHL(x) (x) = ntohl(x) +#define NTOHS(x) (x) = ntohs(x) +#endif + +static inline int xdtoi(int); + +/* + * Convert host name to internet address. + * Return 0 upon failure. + */ +bpf_u_int32 ** +pcap_nametoaddr(const char *name) +{ +#ifndef h_addr + static bpf_u_int32 *hlist[2]; +#endif + bpf_u_int32 **p; + struct hostent *hp; + + if ((hp = gethostbyname(name)) != NULL) { +#ifndef h_addr + hlist[0] = (bpf_u_int32 *)hp->h_addr; + NTOHL(hp->h_addr); + return hlist; +#else + for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p) + NTOHL(**p); + return (bpf_u_int32 **)hp->h_addr_list; +#endif + } + else + return 0; +} + +#ifdef INET6 +struct addrinfo * +pcap_nametoaddrinfo(const char *name) +{ + struct addrinfo hints, *res; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; /*not really*/ + hints.ai_protocol = IPPROTO_TCP; /*not really*/ + error = getaddrinfo(name, NULL, &hints, &res); + if (error) + return NULL; + else + return res; +} +#endif /*INET6*/ + +/* + * Convert net name to internet address. + * Return 0 upon failure. + */ +bpf_u_int32 +pcap_nametonetaddr(const char *name) +{ +#ifndef WIN32 + struct netent *np; + + if ((np = getnetbyname(name)) != NULL) + return np->n_net; + else + return 0; +#else + /* + * There's no "getnetbyname()" on Windows. + */ + return 0; +#endif +} + +/* + * Convert a port name to its port and protocol numbers. + * We assume only TCP or UDP. + * Return 0 upon failure. + */ +int +pcap_nametoport(const char *name, int *port, int *proto) +{ + struct servent *sp; + int tcp_port = -1; + int udp_port = -1; + + /* + * We need to check /etc/services for ambiguous entries. + * If we find the ambiguous entry, and it has the + * same port number, change the proto to PROTO_UNDEF + * so both TCP and UDP will be checked. + */ + sp = getservbyname(name, "tcp"); + if (sp != NULL) tcp_port = ntohs(sp->s_port); + sp = getservbyname(name, "udp"); + if (sp != NULL) udp_port = ntohs(sp->s_port); + if (tcp_port >= 0) { + *port = tcp_port; + *proto = IPPROTO_TCP; + if (udp_port >= 0) { + if (udp_port == tcp_port) + *proto = PROTO_UNDEF; +#ifdef notdef + else + /* Can't handle ambiguous names that refer + to different port numbers. */ + warning("ambiguous port %s in /etc/services", + name); +#endif + } + return 1; + } + if (udp_port >= 0) { + *port = udp_port; + *proto = IPPROTO_UDP; + return 1; + } +#if defined(ultrix) || defined(__osf__) + /* Special hack in case NFS isn't in /etc/services */ + if (strcmp(name, "nfs") == 0) { + *port = 2049; + *proto = PROTO_UNDEF; + return 1; + } +#endif + return 0; +} + +/* + * Convert a string in the form PPP-PPP, where correspond to ports, to + * a starting and ending port in a port range. + * Return 0 on failure. + */ +int +pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto) +{ + u_int p1, p2; + char *off, *cpy; + int save_proto; + + if (sscanf(name, "%d-%d", &p1, &p2) != 2) { + if ((cpy = strdup(name)) == NULL) + return 0; + + if ((off = strchr(cpy, '-')) == NULL) { + free(cpy); + return 0; + } + + *off = '\0'; + + if (pcap_nametoport(cpy, port1, proto) == 0) { + free(cpy); + return 0; + } + save_proto = *proto; + + if (pcap_nametoport(off + 1, port2, proto) == 0) { + free(cpy); + return 0; + } + free(cpy); + + if (*proto != save_proto) + *proto = PROTO_UNDEF; + } else { + *port1 = p1; + *port2 = p2; + *proto = PROTO_UNDEF; + } + + return 1; +} + +int +pcap_nametoproto(const char *str) +{ + struct protoent *p; + + p = getprotobyname(str); + if (p != 0) + return p->p_proto; + else + return PROTO_UNDEF; +} + +#include "ethertype.h" + +struct eproto { + const char *s; + u_short p; +}; + +/* Static data base of ether protocol types. */ +struct eproto eproto_db[] = { + { "pup", ETHERTYPE_PUP }, + { "xns", ETHERTYPE_NS }, + { "ip", ETHERTYPE_IP }, +#ifdef INET6 + { "ip6", ETHERTYPE_IPV6 }, +#endif + { "arp", ETHERTYPE_ARP }, + { "rarp", ETHERTYPE_REVARP }, + { "sprite", ETHERTYPE_SPRITE }, + { "mopdl", ETHERTYPE_MOPDL }, + { "moprc", ETHERTYPE_MOPRC }, + { "decnet", ETHERTYPE_DN }, + { "lat", ETHERTYPE_LAT }, + { "sca", ETHERTYPE_SCA }, + { "lanbridge", ETHERTYPE_LANBRIDGE }, + { "vexp", ETHERTYPE_VEXP }, + { "vprod", ETHERTYPE_VPROD }, + { "atalk", ETHERTYPE_ATALK }, + { "atalkarp", ETHERTYPE_AARP }, + { "loopback", ETHERTYPE_LOOPBACK }, + { "decdts", ETHERTYPE_DECDTS }, + { "decdns", ETHERTYPE_DECDNS }, + { (char *)0, 0 } +}; + +int +pcap_nametoeproto(const char *s) +{ + struct eproto *p = eproto_db; + + while (p->s != 0) { + if (strcmp(p->s, s) == 0) + return p->p; + p += 1; + } + return PROTO_UNDEF; +} + +#include "llc.h" + +/* Static data base of LLC values. */ +static struct eproto llc_db[] = { + { "iso", LLCSAP_ISONS }, + { "stp", LLCSAP_8021D }, + { "ipx", LLCSAP_IPX }, + { "netbeui", LLCSAP_NETBEUI }, + { (char *)0, 0 } +}; + +int +pcap_nametollc(const char *s) +{ + struct eproto *p = llc_db; + + while (p->s != 0) { + if (strcmp(p->s, s) == 0) + return p->p; + p += 1; + } + return PROTO_UNDEF; +} + +/* Hex digit to integer. */ +static inline int +xdtoi(c) + register int c; +{ + if (isdigit(c)) + return c - '0'; + else if (islower(c)) + return c - 'a' + 10; + else + return c - 'A' + 10; +} + +int +__pcap_atoin(const char *s, bpf_u_int32 *addr) +{ + u_int n; + int len; + + *addr = 0; + len = 0; + while (1) { + n = 0; + while (*s && *s != '.') + n = n * 10 + *s++ - '0'; + *addr <<= 8; + *addr |= n & 0xff; + len += 8; + if (*s == '\0') + return len; + ++s; + } + /* NOTREACHED */ +} + +int +__pcap_atodn(const char *s, bpf_u_int32 *addr) +{ +#define AREASHIFT 10 +#define AREAMASK 0176000 +#define NODEMASK 01777 + + u_int node, area; + + if (sscanf(s, "%d.%d", &area, &node) != 2) + bpf_error("malformed decnet address '%s'", s); + + *addr = (area << AREASHIFT) & AREAMASK; + *addr |= (node & NODEMASK); + + return(32); +} + +/* + * Convert 's', which can have the one of the forms: + * + * "xx:xx:xx:xx:xx:xx" + * "xx.xx.xx.xx.xx.xx" + * "xx-xx-xx-xx-xx-xx" + * "xxxx.xxxx.xxxx" + * "xxxxxxxxxxxx" + * + * (or various mixes of ':', '.', and '-') into a new + * ethernet address. Assumes 's' is well formed. + */ +u_char * +pcap_ether_aton(const char *s) +{ + register u_char *ep, *e; + register u_int d; + + e = ep = (u_char *)malloc(6); + if (e == NULL) + return (NULL); + + while (*s) { + if (*s == ':' || *s == '.' || *s == '-') + s += 1; + d = xdtoi(*s++); + if (isxdigit((unsigned char)*s)) { + d <<= 4; + d |= xdtoi(*s++); + } + *ep++ = d; + } + + return (e); +} + +#ifndef HAVE_ETHER_HOSTTON +/* Roll our own */ +u_char * +pcap_ether_hostton(const char *name) +{ + register struct pcap_etherent *ep; + register u_char *ap; + static FILE *fp = NULL; + static int init = 0; + + if (!init) { + fp = fopen(PCAP_ETHERS_FILE, "r"); + ++init; + if (fp == NULL) + return (NULL); + } else if (fp == NULL) + return (NULL); + else + rewind(fp); + + while ((ep = pcap_next_etherent(fp)) != NULL) { + if (strcmp(ep->name, name) == 0) { + ap = (u_char *)malloc(6); + if (ap != NULL) { + memcpy(ap, ep->addr, 6); + return (ap); + } + break; + } + } + return (NULL); +} +#else + +#if !defined(HAVE_DECL_ETHER_HOSTTON) || !HAVE_DECL_ETHER_HOSTTON +#ifndef HAVE_STRUCT_ETHER_ADDR +struct ether_addr { + unsigned char ether_addr_octet[6]; +}; +#endif +extern int ether_hostton(const char *, struct ether_addr *); +#endif + +/* Use the os supplied routines */ +u_char * +pcap_ether_hostton(const char *name) +{ + register u_char *ap; + u_char a[6]; + + ap = NULL; + if (ether_hostton(name, (struct ether_addr *)a) == 0) { + ap = (u_char *)malloc(6); + if (ap != NULL) + memcpy((char *)ap, (char *)a, 6); + } + return (ap); +} +#endif + +u_short +__pcap_nametodnaddr(const char *name) +{ +#ifdef DECNETLIB + struct nodeent *getnodebyname(); + struct nodeent *nep; + unsigned short res; + + nep = getnodebyname(name); + if (nep == ((struct nodeent *)0)) + bpf_error("unknown decnet host name '%s'\n", name); + + memcpy((char *)&res, (char *)nep->n_addr, sizeof(unsigned short)); + return(res); +#else + bpf_error("decnet name support not included, '%s' cannot be translated\n", + name); + return(0); +#endif +} diff --git a/tcpdump/jni/libpcap/nlpid.h b/tcpdump/jni/libpcap/nlpid.h new file mode 100644 index 0000000..9dfa752 --- /dev/null +++ b/tcpdump/jni/libpcap/nlpid.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1996 + * Juniper Networks, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution. The name of Juniper Networks may not + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Types missing from some systems */ + +/* + * Network layer prototocol identifiers + */ +#ifndef ISO8473_CLNP +#define ISO8473_CLNP 0x81 +#endif +#ifndef ISO9542_ESIS +#define ISO9542_ESIS 0x82 +#endif +#ifndef ISO9542X25_ESIS +#define ISO9542X25_ESIS 0x8a +#endif +#ifndef ISO10589_ISIS +#define ISO10589_ISIS 0x83 +#endif +/* + * this does not really belong in the nlpid.h file + * however we need it for generating nice + * IS-IS related BPF filters + */ +#define ISIS_L1_LAN_IIH 15 +#define ISIS_L2_LAN_IIH 16 +#define ISIS_PTP_IIH 17 +#define ISIS_L1_LSP 18 +#define ISIS_L2_LSP 20 +#define ISIS_L1_CSNP 24 +#define ISIS_L2_CSNP 25 +#define ISIS_L1_PSNP 26 +#define ISIS_L2_PSNP 27 + +#ifndef ISO8878A_CONS +#define ISO8878A_CONS 0x84 +#endif +#ifndef ISO10747_IDRP +#define ISO10747_IDRP 0x85 +#endif diff --git a/tcpdump/jni/libpcap/optimize.c b/tcpdump/jni/libpcap/optimize.c new file mode 100644 index 0000000..ada2019 --- /dev/null +++ b/tcpdump/jni/libpcap/optimize.c @@ -0,0 +1,2355 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Optimization module for tcpdump intermediate representation. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#endif /* WIN32 */ + +#include +#include +#include +#include + +#include + +#include "pcap-int.h" + +#include "gencode.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#ifdef BDEBUG +extern int dflag; +#endif + +#if defined(MSDOS) && !defined(__DJGPP__) +extern int _w32_ffs (int mask); +#define ffs _w32_ffs +#endif + +#if defined(WIN32) && defined (_MSC_VER) +int ffs(int mask); +#endif + +/* + * Represents a deleted instruction. + */ +#define NOP -1 + +/* + * Register numbers for use-def values. + * 0 through BPF_MEMWORDS-1 represent the corresponding scratch memory + * location. A_ATOM is the accumulator and X_ATOM is the index + * register. + */ +#define A_ATOM BPF_MEMWORDS +#define X_ATOM (BPF_MEMWORDS+1) + +/* + * This define is used to represent *both* the accumulator and + * x register in use-def computations. + * Currently, the use-def code assumes only one definition per instruction. + */ +#define AX_ATOM N_ATOMS + +/* + * A flag to indicate that further optimization is needed. + * Iterative passes are continued until a given pass yields no + * branch movement. + */ +static int done; + +/* + * A block is marked if only if its mark equals the current mark. + * Rather than traverse the code array, marking each item, 'cur_mark' is + * incremented. This automatically makes each element unmarked. + */ +static int cur_mark; +#define isMarked(p) ((p)->mark == cur_mark) +#define unMarkAll() cur_mark += 1 +#define Mark(p) ((p)->mark = cur_mark) + +static void opt_init(struct block *); +static void opt_cleanup(void); + +static void intern_blocks(struct block *); + +static void find_inedges(struct block *); +#ifdef BDEBUG +static void opt_dump(struct block *); +#endif + +static int n_blocks; +struct block **blocks; +static int n_edges; +struct edge **edges; + +/* + * A bit vector set representation of the dominators. + * We round up the set size to the next power of two. + */ +static int nodewords; +static int edgewords; +struct block **levels; +bpf_u_int32 *space; +#define BITS_PER_WORD (8*sizeof(bpf_u_int32)) +/* + * True if a is in uset {p} + */ +#define SET_MEMBER(p, a) \ +((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD))) + +/* + * Add 'a' to uset p. + */ +#define SET_INSERT(p, a) \ +(p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD)) + +/* + * Delete 'a' from uset p. + */ +#define SET_DELETE(p, a) \ +(p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD)) + +/* + * a := a intersect b + */ +#define SET_INTERSECT(a, b, n)\ +{\ + register bpf_u_int32 *_x = a, *_y = b;\ + register int _n = n;\ + while (--_n >= 0) *_x++ &= *_y++;\ +} + +/* + * a := a - b + */ +#define SET_SUBTRACT(a, b, n)\ +{\ + register bpf_u_int32 *_x = a, *_y = b;\ + register int _n = n;\ + while (--_n >= 0) *_x++ &=~ *_y++;\ +} + +/* + * a := a union b + */ +#define SET_UNION(a, b, n)\ +{\ + register bpf_u_int32 *_x = a, *_y = b;\ + register int _n = n;\ + while (--_n >= 0) *_x++ |= *_y++;\ +} + +static uset all_dom_sets; +static uset all_closure_sets; +static uset all_edge_sets; + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +static void +find_levels_r(struct block *b) +{ + int level; + + if (isMarked(b)) + return; + + Mark(b); + b->link = 0; + + if (JT(b)) { + find_levels_r(JT(b)); + find_levels_r(JF(b)); + level = MAX(JT(b)->level, JF(b)->level) + 1; + } else + level = 0; + b->level = level; + b->link = levels[level]; + levels[level] = b; +} + +/* + * Level graph. The levels go from 0 at the leaves to + * N_LEVELS at the root. The levels[] array points to the + * first node of the level list, whose elements are linked + * with the 'link' field of the struct block. + */ +static void +find_levels(struct block *root) +{ + memset((char *)levels, 0, n_blocks * sizeof(*levels)); + unMarkAll(); + find_levels_r(root); +} + +/* + * Find dominator relationships. + * Assumes graph has been leveled. + */ +static void +find_dom(struct block *root) +{ + int i; + struct block *b; + bpf_u_int32 *x; + + /* + * Initialize sets to contain all nodes. + */ + x = all_dom_sets; + i = n_blocks * nodewords; + while (--i >= 0) + *x++ = ~0; + /* Root starts off empty. */ + for (i = nodewords; --i >= 0;) + root->dom[i] = 0; + + /* root->level is the highest level no found. */ + for (i = root->level; i >= 0; --i) { + for (b = levels[i]; b; b = b->link) { + SET_INSERT(b->dom, b->id); + if (JT(b) == 0) + continue; + SET_INTERSECT(JT(b)->dom, b->dom, nodewords); + SET_INTERSECT(JF(b)->dom, b->dom, nodewords); + } + } +} + +static void +propedom(struct edge *ep) +{ + SET_INSERT(ep->edom, ep->id); + if (ep->succ) { + SET_INTERSECT(ep->succ->et.edom, ep->edom, edgewords); + SET_INTERSECT(ep->succ->ef.edom, ep->edom, edgewords); + } +} + +/* + * Compute edge dominators. + * Assumes graph has been leveled and predecessors established. + */ +static void +find_edom(struct block *root) +{ + int i; + uset x; + struct block *b; + + x = all_edge_sets; + for (i = n_edges * edgewords; --i >= 0; ) + x[i] = ~0; + + /* root->level is the highest level no found. */ + memset(root->et.edom, 0, edgewords * sizeof(*(uset)0)); + memset(root->ef.edom, 0, edgewords * sizeof(*(uset)0)); + for (i = root->level; i >= 0; --i) { + for (b = levels[i]; b != 0; b = b->link) { + propedom(&b->et); + propedom(&b->ef); + } + } +} + +/* + * Find the backwards transitive closure of the flow graph. These sets + * are backwards in the sense that we find the set of nodes that reach + * a given node, not the set of nodes that can be reached by a node. + * + * Assumes graph has been leveled. + */ +static void +find_closure(struct block *root) +{ + int i; + struct block *b; + + /* + * Initialize sets to contain no nodes. + */ + memset((char *)all_closure_sets, 0, + n_blocks * nodewords * sizeof(*all_closure_sets)); + + /* root->level is the highest level no found. */ + for (i = root->level; i >= 0; --i) { + for (b = levels[i]; b; b = b->link) { + SET_INSERT(b->closure, b->id); + if (JT(b) == 0) + continue; + SET_UNION(JT(b)->closure, b->closure, nodewords); + SET_UNION(JF(b)->closure, b->closure, nodewords); + } + } +} + +/* + * Return the register number that is used by s. If A and X are both + * used, return AX_ATOM. If no register is used, return -1. + * + * The implementation should probably change to an array access. + */ +static int +atomuse(struct stmt *s) +{ + register int c = s->code; + + if (c == NOP) + return -1; + + switch (BPF_CLASS(c)) { + + case BPF_RET: + return (BPF_RVAL(c) == BPF_A) ? A_ATOM : + (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1; + + case BPF_LD: + case BPF_LDX: + return (BPF_MODE(c) == BPF_IND) ? X_ATOM : + (BPF_MODE(c) == BPF_MEM) ? s->k : -1; + + case BPF_ST: + return A_ATOM; + + case BPF_STX: + return X_ATOM; + + case BPF_JMP: + case BPF_ALU: + if (BPF_SRC(c) == BPF_X) + return AX_ATOM; + return A_ATOM; + + case BPF_MISC: + return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM; + } + abort(); + /* NOTREACHED */ +} + +/* + * Return the register number that is defined by 's'. We assume that + * a single stmt cannot define more than one register. If no register + * is defined, return -1. + * + * The implementation should probably change to an array access. + */ +static int +atomdef(struct stmt *s) +{ + if (s->code == NOP) + return -1; + + switch (BPF_CLASS(s->code)) { + + case BPF_LD: + case BPF_ALU: + return A_ATOM; + + case BPF_LDX: + return X_ATOM; + + case BPF_ST: + case BPF_STX: + return s->k; + + case BPF_MISC: + return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM; + } + return -1; +} + +/* + * Compute the sets of registers used, defined, and killed by 'b'. + * + * "Used" means that a statement in 'b' uses the register before any + * statement in 'b' defines it, i.e. it uses the value left in + * that register by a predecessor block of this block. + * "Defined" means that a statement in 'b' defines it. + * "Killed" means that a statement in 'b' defines it before any + * statement in 'b' uses it, i.e. it kills the value left in that + * register by a predecessor block of this block. + */ +static void +compute_local_ud(struct block *b) +{ + struct slist *s; + atomset def = 0, use = 0, kill = 0; + int atom; + + for (s = b->stmts; s; s = s->next) { + if (s->s.code == NOP) + continue; + atom = atomuse(&s->s); + if (atom >= 0) { + if (atom == AX_ATOM) { + if (!ATOMELEM(def, X_ATOM)) + use |= ATOMMASK(X_ATOM); + if (!ATOMELEM(def, A_ATOM)) + use |= ATOMMASK(A_ATOM); + } + else if (atom < N_ATOMS) { + if (!ATOMELEM(def, atom)) + use |= ATOMMASK(atom); + } + else + abort(); + } + atom = atomdef(&s->s); + if (atom >= 0) { + if (!ATOMELEM(use, atom)) + kill |= ATOMMASK(atom); + def |= ATOMMASK(atom); + } + } + if (BPF_CLASS(b->s.code) == BPF_JMP) { + /* + * XXX - what about RET? + */ + atom = atomuse(&b->s); + if (atom >= 0) { + if (atom == AX_ATOM) { + if (!ATOMELEM(def, X_ATOM)) + use |= ATOMMASK(X_ATOM); + if (!ATOMELEM(def, A_ATOM)) + use |= ATOMMASK(A_ATOM); + } + else if (atom < N_ATOMS) { + if (!ATOMELEM(def, atom)) + use |= ATOMMASK(atom); + } + else + abort(); + } + } + + b->def = def; + b->kill = kill; + b->in_use = use; +} + +/* + * Assume graph is already leveled. + */ +static void +find_ud(struct block *root) +{ + int i, maxlevel; + struct block *p; + + /* + * root->level is the highest level no found; + * count down from there. + */ + maxlevel = root->level; + for (i = maxlevel; i >= 0; --i) + for (p = levels[i]; p; p = p->link) { + compute_local_ud(p); + p->out_use = 0; + } + + for (i = 1; i <= maxlevel; ++i) { + for (p = levels[i]; p; p = p->link) { + p->out_use |= JT(p)->in_use | JF(p)->in_use; + p->in_use |= p->out_use &~ p->kill; + } + } +} + +/* + * These data structures are used in a Cocke and Shwarz style + * value numbering scheme. Since the flowgraph is acyclic, + * exit values can be propagated from a node's predecessors + * provided it is uniquely defined. + */ +struct valnode { + int code; + int v0, v1; + int val; + struct valnode *next; +}; + +#define MODULUS 213 +static struct valnode *hashtbl[MODULUS]; +static int curval; +static int maxval; + +/* Integer constants mapped with the load immediate opcode. */ +#define K(i) F(BPF_LD|BPF_IMM|BPF_W, i, 0L) + +struct vmapinfo { + int is_const; + bpf_int32 const_val; +}; + +struct vmapinfo *vmap; +struct valnode *vnode_base; +struct valnode *next_vnode; + +static void +init_val(void) +{ + curval = 0; + next_vnode = vnode_base; + memset((char *)vmap, 0, maxval * sizeof(*vmap)); + memset((char *)hashtbl, 0, sizeof hashtbl); +} + +/* Because we really don't have an IR, this stuff is a little messy. */ +static int +F(int code, int v0, int v1) +{ + u_int hash; + int val; + struct valnode *p; + + hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8); + hash %= MODULUS; + + for (p = hashtbl[hash]; p; p = p->next) + if (p->code == code && p->v0 == v0 && p->v1 == v1) + return p->val; + + val = ++curval; + if (BPF_MODE(code) == BPF_IMM && + (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) { + vmap[val].const_val = v0; + vmap[val].is_const = 1; + } + p = next_vnode++; + p->val = val; + p->code = code; + p->v0 = v0; + p->v1 = v1; + p->next = hashtbl[hash]; + hashtbl[hash] = p; + + return val; +} + +static inline void +vstore(struct stmt *s, int *valp, int newval, int alter) +{ + if (alter && *valp == newval) + s->code = NOP; + else + *valp = newval; +} + +/* + * Do constant-folding on binary operators. + * (Unary operators are handled elsewhere.) + */ +static void +fold_op(struct stmt *s, int v0, int v1) +{ + bpf_u_int32 a, b; + + a = vmap[v0].const_val; + b = vmap[v1].const_val; + + switch (BPF_OP(s->code)) { + case BPF_ADD: + a += b; + break; + + case BPF_SUB: + a -= b; + break; + + case BPF_MUL: + a *= b; + break; + + case BPF_DIV: + if (b == 0) + bpf_error("division by zero"); + a /= b; + break; + + case BPF_MOD: + if (b == 0) + bpf_error("modulus by zero"); + a %= b; + break; + + case BPF_AND: + a &= b; + break; + + case BPF_OR: + a |= b; + break; + + case BPF_XOR: + a ^= b; + break; + + case BPF_LSH: + a <<= b; + break; + + case BPF_RSH: + a >>= b; + break; + + default: + abort(); + } + s->k = a; + s->code = BPF_LD|BPF_IMM; + done = 0; +} + +static inline struct slist * +this_op(struct slist *s) +{ + while (s != 0 && s->s.code == NOP) + s = s->next; + return s; +} + +static void +opt_not(struct block *b) +{ + struct block *tmp = JT(b); + + JT(b) = JF(b); + JF(b) = tmp; +} + +static void +opt_peep(struct block *b) +{ + struct slist *s; + struct slist *next, *last; + int val; + + s = b->stmts; + if (s == 0) + return; + + last = s; + for (/*empty*/; /*empty*/; s = next) { + /* + * Skip over nops. + */ + s = this_op(s); + if (s == 0) + break; /* nothing left in the block */ + + /* + * Find the next real instruction after that one + * (skipping nops). + */ + next = this_op(s->next); + if (next == 0) + break; /* no next instruction */ + last = next; + + /* + * st M[k] --> st M[k] + * ldx M[k] tax + */ + if (s->s.code == BPF_ST && + next->s.code == (BPF_LDX|BPF_MEM) && + s->s.k == next->s.k) { + done = 0; + next->s.code = BPF_MISC|BPF_TAX; + } + /* + * ld #k --> ldx #k + * tax txa + */ + if (s->s.code == (BPF_LD|BPF_IMM) && + next->s.code == (BPF_MISC|BPF_TAX)) { + s->s.code = BPF_LDX|BPF_IMM; + next->s.code = BPF_MISC|BPF_TXA; + done = 0; + } + /* + * This is an ugly special case, but it happens + * when you say tcp[k] or udp[k] where k is a constant. + */ + if (s->s.code == (BPF_LD|BPF_IMM)) { + struct slist *add, *tax, *ild; + + /* + * Check that X isn't used on exit from this + * block (which the optimizer might cause). + * We know the code generator won't generate + * any local dependencies. + */ + if (ATOMELEM(b->out_use, X_ATOM)) + continue; + + /* + * Check that the instruction following the ldi + * is an addx, or it's an ldxms with an addx + * following it (with 0 or more nops between the + * ldxms and addx). + */ + if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B)) + add = next; + else + add = this_op(next->next); + if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X)) + continue; + + /* + * Check that a tax follows that (with 0 or more + * nops between them). + */ + tax = this_op(add->next); + if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX)) + continue; + + /* + * Check that an ild follows that (with 0 or more + * nops between them). + */ + ild = this_op(tax->next); + if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD || + BPF_MODE(ild->s.code) != BPF_IND) + continue; + /* + * We want to turn this sequence: + * + * (004) ldi #0x2 {s} + * (005) ldxms [14] {next} -- optional + * (006) addx {add} + * (007) tax {tax} + * (008) ild [x+0] {ild} + * + * into this sequence: + * + * (004) nop + * (005) ldxms [14] + * (006) nop + * (007) nop + * (008) ild [x+2] + * + * XXX We need to check that X is not + * subsequently used, because we want to change + * what'll be in it after this sequence. + * + * We know we can eliminate the accumulator + * modifications earlier in the sequence since + * it is defined by the last stmt of this sequence + * (i.e., the last statement of the sequence loads + * a value into the accumulator, so we can eliminate + * earlier operations on the accumulator). + */ + ild->s.k += s->s.k; + s->s.code = NOP; + add->s.code = NOP; + tax->s.code = NOP; + done = 0; + } + } + /* + * If the comparison at the end of a block is an equality + * comparison against a constant, and nobody uses the value + * we leave in the A register at the end of a block, and + * the operation preceding the comparison is an arithmetic + * operation, we can sometime optimize it away. + */ + if (b->s.code == (BPF_JMP|BPF_JEQ|BPF_K) && + !ATOMELEM(b->out_use, A_ATOM)) { + /* + * We can optimize away certain subtractions of the + * X register. + */ + if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X)) { + val = b->val[X_ATOM]; + if (vmap[val].is_const) { + /* + * If we have a subtract to do a comparison, + * and the X register is a known constant, + * we can merge this value into the + * comparison: + * + * sub x -> nop + * jeq #y jeq #(x+y) + */ + b->s.k += vmap[val].const_val; + last->s.code = NOP; + done = 0; + } else if (b->s.k == 0) { + /* + * If the X register isn't a constant, + * and the comparison in the test is + * against 0, we can compare with the + * X register, instead: + * + * sub x -> nop + * jeq #0 jeq x + */ + last->s.code = NOP; + b->s.code = BPF_JMP|BPF_JEQ|BPF_X; + done = 0; + } + } + /* + * Likewise, a constant subtract can be simplified: + * + * sub #x -> nop + * jeq #y -> jeq #(x+y) + */ + else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K)) { + last->s.code = NOP; + b->s.k += last->s.k; + done = 0; + } + /* + * And, similarly, a constant AND can be simplified + * if we're testing against 0, i.e.: + * + * and #k nop + * jeq #0 -> jset #k + */ + else if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) && + b->s.k == 0) { + b->s.k = last->s.k; + b->s.code = BPF_JMP|BPF_K|BPF_JSET; + last->s.code = NOP; + done = 0; + opt_not(b); + } + } + /* + * jset #0 -> never + * jset #ffffffff -> always + */ + if (b->s.code == (BPF_JMP|BPF_K|BPF_JSET)) { + if (b->s.k == 0) + JT(b) = JF(b); + if (b->s.k == 0xffffffff) + JF(b) = JT(b); + } + /* + * If we're comparing against the index register, and the index + * register is a known constant, we can just compare against that + * constant. + */ + val = b->val[X_ATOM]; + if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) { + bpf_int32 v = vmap[val].const_val; + b->s.code &= ~BPF_X; + b->s.k = v; + } + /* + * If the accumulator is a known constant, we can compute the + * comparison result. + */ + val = b->val[A_ATOM]; + if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) { + bpf_int32 v = vmap[val].const_val; + switch (BPF_OP(b->s.code)) { + + case BPF_JEQ: + v = v == b->s.k; + break; + + case BPF_JGT: + v = (unsigned)v > b->s.k; + break; + + case BPF_JGE: + v = (unsigned)v >= b->s.k; + break; + + case BPF_JSET: + v &= b->s.k; + break; + + default: + abort(); + } + if (JF(b) != JT(b)) + done = 0; + if (v) + JF(b) = JT(b); + else + JT(b) = JF(b); + } +} + +/* + * Compute the symbolic value of expression of 's', and update + * anything it defines in the value table 'val'. If 'alter' is true, + * do various optimizations. This code would be cleaner if symbolic + * evaluation and code transformations weren't folded together. + */ +static void +opt_stmt(struct stmt *s, int val[], int alter) +{ + int op; + int v; + + switch (s->code) { + + case BPF_LD|BPF_ABS|BPF_W: + case BPF_LD|BPF_ABS|BPF_H: + case BPF_LD|BPF_ABS|BPF_B: + v = F(s->code, s->k, 0L); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LD|BPF_IND|BPF_W: + case BPF_LD|BPF_IND|BPF_H: + case BPF_LD|BPF_IND|BPF_B: + v = val[X_ATOM]; + if (alter && vmap[v].is_const) { + s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code); + s->k += vmap[v].const_val; + v = F(s->code, s->k, 0L); + done = 0; + } + else + v = F(s->code, s->k, v); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LD|BPF_LEN: + v = F(s->code, 0L, 0L); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LD|BPF_IMM: + v = K(s->k); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LDX|BPF_IMM: + v = K(s->k); + vstore(s, &val[X_ATOM], v, alter); + break; + + case BPF_LDX|BPF_MSH|BPF_B: + v = F(s->code, s->k, 0L); + vstore(s, &val[X_ATOM], v, alter); + break; + + case BPF_ALU|BPF_NEG: + if (alter && vmap[val[A_ATOM]].is_const) { + s->code = BPF_LD|BPF_IMM; + s->k = -vmap[val[A_ATOM]].const_val; + val[A_ATOM] = K(s->k); + } + else + val[A_ATOM] = F(s->code, val[A_ATOM], 0L); + break; + + case BPF_ALU|BPF_ADD|BPF_K: + case BPF_ALU|BPF_SUB|BPF_K: + case BPF_ALU|BPF_MUL|BPF_K: + case BPF_ALU|BPF_DIV|BPF_K: + case BPF_ALU|BPF_MOD|BPF_K: + case BPF_ALU|BPF_AND|BPF_K: + case BPF_ALU|BPF_OR|BPF_K: + case BPF_ALU|BPF_XOR|BPF_K: + case BPF_ALU|BPF_LSH|BPF_K: + case BPF_ALU|BPF_RSH|BPF_K: + op = BPF_OP(s->code); + if (alter) { + if (s->k == 0) { + /* don't optimize away "sub #0" + * as it may be needed later to + * fixup the generated math code */ + if (op == BPF_ADD || + op == BPF_LSH || op == BPF_RSH || + op == BPF_OR || op == BPF_XOR) { + s->code = NOP; + break; + } + if (op == BPF_MUL || op == BPF_AND) { + s->code = BPF_LD|BPF_IMM; + val[A_ATOM] = K(s->k); + break; + } + } + if (vmap[val[A_ATOM]].is_const) { + fold_op(s, val[A_ATOM], K(s->k)); + val[A_ATOM] = K(s->k); + break; + } + } + val[A_ATOM] = F(s->code, val[A_ATOM], K(s->k)); + break; + + case BPF_ALU|BPF_ADD|BPF_X: + case BPF_ALU|BPF_SUB|BPF_X: + case BPF_ALU|BPF_MUL|BPF_X: + case BPF_ALU|BPF_DIV|BPF_X: + case BPF_ALU|BPF_MOD|BPF_X: + case BPF_ALU|BPF_AND|BPF_X: + case BPF_ALU|BPF_OR|BPF_X: + case BPF_ALU|BPF_XOR|BPF_X: + case BPF_ALU|BPF_LSH|BPF_X: + case BPF_ALU|BPF_RSH|BPF_X: + op = BPF_OP(s->code); + if (alter && vmap[val[X_ATOM]].is_const) { + if (vmap[val[A_ATOM]].is_const) { + fold_op(s, val[A_ATOM], val[X_ATOM]); + val[A_ATOM] = K(s->k); + } + else { + s->code = BPF_ALU|BPF_K|op; + s->k = vmap[val[X_ATOM]].const_val; + done = 0; + val[A_ATOM] = + F(s->code, val[A_ATOM], K(s->k)); + } + break; + } + /* + * Check if we're doing something to an accumulator + * that is 0, and simplify. This may not seem like + * much of a simplification but it could open up further + * optimizations. + * XXX We could also check for mul by 1, etc. + */ + if (alter && vmap[val[A_ATOM]].is_const + && vmap[val[A_ATOM]].const_val == 0) { + if (op == BPF_ADD || op == BPF_OR || op == BPF_XOR) { + s->code = BPF_MISC|BPF_TXA; + vstore(s, &val[A_ATOM], val[X_ATOM], alter); + break; + } + else if (op == BPF_MUL || op == BPF_DIV || op == BPF_MOD || + op == BPF_AND || op == BPF_LSH || op == BPF_RSH) { + s->code = BPF_LD|BPF_IMM; + s->k = 0; + vstore(s, &val[A_ATOM], K(s->k), alter); + break; + } + else if (op == BPF_NEG) { + s->code = NOP; + break; + } + } + val[A_ATOM] = F(s->code, val[A_ATOM], val[X_ATOM]); + break; + + case BPF_MISC|BPF_TXA: + vstore(s, &val[A_ATOM], val[X_ATOM], alter); + break; + + case BPF_LD|BPF_MEM: + v = val[s->k]; + if (alter && vmap[v].is_const) { + s->code = BPF_LD|BPF_IMM; + s->k = vmap[v].const_val; + done = 0; + } + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_MISC|BPF_TAX: + vstore(s, &val[X_ATOM], val[A_ATOM], alter); + break; + + case BPF_LDX|BPF_MEM: + v = val[s->k]; + if (alter && vmap[v].is_const) { + s->code = BPF_LDX|BPF_IMM; + s->k = vmap[v].const_val; + done = 0; + } + vstore(s, &val[X_ATOM], v, alter); + break; + + case BPF_ST: + vstore(s, &val[s->k], val[A_ATOM], alter); + break; + + case BPF_STX: + vstore(s, &val[s->k], val[X_ATOM], alter); + break; + } +} + +static void +deadstmt(register struct stmt *s, register struct stmt *last[]) +{ + register int atom; + + atom = atomuse(s); + if (atom >= 0) { + if (atom == AX_ATOM) { + last[X_ATOM] = 0; + last[A_ATOM] = 0; + } + else + last[atom] = 0; + } + atom = atomdef(s); + if (atom >= 0) { + if (last[atom]) { + done = 0; + last[atom]->code = NOP; + } + last[atom] = s; + } +} + +static void +opt_deadstores(register struct block *b) +{ + register struct slist *s; + register int atom; + struct stmt *last[N_ATOMS]; + + memset((char *)last, 0, sizeof last); + + for (s = b->stmts; s != 0; s = s->next) + deadstmt(&s->s, last); + deadstmt(&b->s, last); + + for (atom = 0; atom < N_ATOMS; ++atom) + if (last[atom] && !ATOMELEM(b->out_use, atom)) { + last[atom]->code = NOP; + done = 0; + } +} + +static void +opt_blk(struct block *b, int do_stmts) +{ + struct slist *s; + struct edge *p; + int i; + bpf_int32 aval, xval; + +#if 0 + for (s = b->stmts; s && s->next; s = s->next) + if (BPF_CLASS(s->s.code) == BPF_JMP) { + do_stmts = 0; + break; + } +#endif + + /* + * Initialize the atom values. + */ + p = b->in_edges; + if (p == 0) { + /* + * We have no predecessors, so everything is undefined + * upon entry to this block. + */ + memset((char *)b->val, 0, sizeof(b->val)); + } else { + /* + * Inherit values from our predecessors. + * + * First, get the values from the predecessor along the + * first edge leading to this node. + */ + memcpy((char *)b->val, (char *)p->pred->val, sizeof(b->val)); + /* + * Now look at all the other nodes leading to this node. + * If, for the predecessor along that edge, a register + * has a different value from the one we have (i.e., + * control paths are merging, and the merging paths + * assign different values to that register), give the + * register the undefined value of 0. + */ + while ((p = p->next) != NULL) { + for (i = 0; i < N_ATOMS; ++i) + if (b->val[i] != p->pred->val[i]) + b->val[i] = 0; + } + } + aval = b->val[A_ATOM]; + xval = b->val[X_ATOM]; + for (s = b->stmts; s; s = s->next) + opt_stmt(&s->s, b->val, do_stmts); + + /* + * This is a special case: if we don't use anything from this + * block, and we load the accumulator or index register with a + * value that is already there, or if this block is a return, + * eliminate all the statements. + * + * XXX - what if it does a store? + * + * XXX - why does it matter whether we use anything from this + * block? If the accumulator or index register doesn't change + * its value, isn't that OK even if we use that value? + * + * XXX - if we load the accumulator with a different value, + * and the block ends with a conditional branch, we obviously + * can't eliminate it, as the branch depends on that value. + * For the index register, the conditional branch only depends + * on the index register value if the test is against the index + * register value rather than a constant; if nothing uses the + * value we put into the index register, and we're not testing + * against the index register's value, and there aren't any + * other problems that would keep us from eliminating this + * block, can we eliminate it? + */ + if (do_stmts && + ((b->out_use == 0 && aval != 0 && b->val[A_ATOM] == aval && + xval != 0 && b->val[X_ATOM] == xval) || + BPF_CLASS(b->s.code) == BPF_RET)) { + if (b->stmts != 0) { + b->stmts = 0; + done = 0; + } + } else { + opt_peep(b); + opt_deadstores(b); + } + /* + * Set up values for branch optimizer. + */ + if (BPF_SRC(b->s.code) == BPF_K) + b->oval = K(b->s.k); + else + b->oval = b->val[X_ATOM]; + b->et.code = b->s.code; + b->ef.code = -b->s.code; +} + +/* + * Return true if any register that is used on exit from 'succ', has + * an exit value that is different from the corresponding exit value + * from 'b'. + */ +static int +use_conflict(struct block *b, struct block *succ) +{ + int atom; + atomset use = succ->out_use; + + if (use == 0) + return 0; + + for (atom = 0; atom < N_ATOMS; ++atom) + if (ATOMELEM(use, atom)) + if (b->val[atom] != succ->val[atom]) + return 1; + return 0; +} + +static struct block * +fold_edge(struct block *child, struct edge *ep) +{ + int sense; + int aval0, aval1, oval0, oval1; + int code = ep->code; + + if (code < 0) { + code = -code; + sense = 0; + } else + sense = 1; + + if (child->s.code != code) + return 0; + + aval0 = child->val[A_ATOM]; + oval0 = child->oval; + aval1 = ep->pred->val[A_ATOM]; + oval1 = ep->pred->oval; + + if (aval0 != aval1) + return 0; + + if (oval0 == oval1) + /* + * The operands of the branch instructions are + * identical, so the result is true if a true + * branch was taken to get here, otherwise false. + */ + return sense ? JT(child) : JF(child); + + if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K)) + /* + * At this point, we only know the comparison if we + * came down the true branch, and it was an equality + * comparison with a constant. + * + * I.e., if we came down the true branch, and the branch + * was an equality comparison with a constant, we know the + * accumulator contains that constant. If we came down + * the false branch, or the comparison wasn't with a + * constant, we don't know what was in the accumulator. + * + * We rely on the fact that distinct constants have distinct + * value numbers. + */ + return JF(child); + + return 0; +} + +static void +opt_j(struct edge *ep) +{ + register int i, k; + register struct block *target; + + if (JT(ep->succ) == 0) + return; + + if (JT(ep->succ) == JF(ep->succ)) { + /* + * Common branch targets can be eliminated, provided + * there is no data dependency. + */ + if (!use_conflict(ep->pred, ep->succ->et.succ)) { + done = 0; + ep->succ = JT(ep->succ); + } + } + /* + * For each edge dominator that matches the successor of this + * edge, promote the edge successor to the its grandchild. + * + * XXX We violate the set abstraction here in favor a reasonably + * efficient loop. + */ + top: + for (i = 0; i < edgewords; ++i) { + register bpf_u_int32 x = ep->edom[i]; + + while (x != 0) { + k = ffs(x) - 1; + x &=~ (1 << k); + k += i * BITS_PER_WORD; + + target = fold_edge(ep->succ, edges[k]); + /* + * Check that there is no data dependency between + * nodes that will be violated if we move the edge. + */ + if (target != 0 && !use_conflict(ep->pred, target)) { + done = 0; + ep->succ = target; + if (JT(target) != 0) + /* + * Start over unless we hit a leaf. + */ + goto top; + return; + } + } + } +} + + +static void +or_pullup(struct block *b) +{ + int val, at_top; + struct block *pull; + struct block **diffp, **samep; + struct edge *ep; + + ep = b->in_edges; + if (ep == 0) + return; + + /* + * Make sure each predecessor loads the same value. + * XXX why? + */ + val = ep->pred->val[A_ATOM]; + for (ep = ep->next; ep != 0; ep = ep->next) + if (val != ep->pred->val[A_ATOM]) + return; + + if (JT(b->in_edges->pred) == b) + diffp = &JT(b->in_edges->pred); + else + diffp = &JF(b->in_edges->pred); + + at_top = 1; + while (1) { + if (*diffp == 0) + return; + + if (JT(*diffp) != JT(b)) + return; + + if (!SET_MEMBER((*diffp)->dom, b->id)) + return; + + if ((*diffp)->val[A_ATOM] != val) + break; + + diffp = &JF(*diffp); + at_top = 0; + } + samep = &JF(*diffp); + while (1) { + if (*samep == 0) + return; + + if (JT(*samep) != JT(b)) + return; + + if (!SET_MEMBER((*samep)->dom, b->id)) + return; + + if ((*samep)->val[A_ATOM] == val) + break; + + /* XXX Need to check that there are no data dependencies + between dp0 and dp1. Currently, the code generator + will not produce such dependencies. */ + samep = &JF(*samep); + } +#ifdef notdef + /* XXX This doesn't cover everything. */ + for (i = 0; i < N_ATOMS; ++i) + if ((*samep)->val[i] != pred->val[i]) + return; +#endif + /* Pull up the node. */ + pull = *samep; + *samep = JF(pull); + JF(pull) = *diffp; + + /* + * At the top of the chain, each predecessor needs to point at the + * pulled up node. Inside the chain, there is only one predecessor + * to worry about. + */ + if (at_top) { + for (ep = b->in_edges; ep != 0; ep = ep->next) { + if (JT(ep->pred) == b) + JT(ep->pred) = pull; + else + JF(ep->pred) = pull; + } + } + else + *diffp = pull; + + done = 0; +} + +static void +and_pullup(struct block *b) +{ + int val, at_top; + struct block *pull; + struct block **diffp, **samep; + struct edge *ep; + + ep = b->in_edges; + if (ep == 0) + return; + + /* + * Make sure each predecessor loads the same value. + */ + val = ep->pred->val[A_ATOM]; + for (ep = ep->next; ep != 0; ep = ep->next) + if (val != ep->pred->val[A_ATOM]) + return; + + if (JT(b->in_edges->pred) == b) + diffp = &JT(b->in_edges->pred); + else + diffp = &JF(b->in_edges->pred); + + at_top = 1; + while (1) { + if (*diffp == 0) + return; + + if (JF(*diffp) != JF(b)) + return; + + if (!SET_MEMBER((*diffp)->dom, b->id)) + return; + + if ((*diffp)->val[A_ATOM] != val) + break; + + diffp = &JT(*diffp); + at_top = 0; + } + samep = &JT(*diffp); + while (1) { + if (*samep == 0) + return; + + if (JF(*samep) != JF(b)) + return; + + if (!SET_MEMBER((*samep)->dom, b->id)) + return; + + if ((*samep)->val[A_ATOM] == val) + break; + + /* XXX Need to check that there are no data dependencies + between diffp and samep. Currently, the code generator + will not produce such dependencies. */ + samep = &JT(*samep); + } +#ifdef notdef + /* XXX This doesn't cover everything. */ + for (i = 0; i < N_ATOMS; ++i) + if ((*samep)->val[i] != pred->val[i]) + return; +#endif + /* Pull up the node. */ + pull = *samep; + *samep = JT(pull); + JT(pull) = *diffp; + + /* + * At the top of the chain, each predecessor needs to point at the + * pulled up node. Inside the chain, there is only one predecessor + * to worry about. + */ + if (at_top) { + for (ep = b->in_edges; ep != 0; ep = ep->next) { + if (JT(ep->pred) == b) + JT(ep->pred) = pull; + else + JF(ep->pred) = pull; + } + } + else + *diffp = pull; + + done = 0; +} + +static void +opt_blks(struct block *root, int do_stmts) +{ + int i, maxlevel; + struct block *p; + + init_val(); + maxlevel = root->level; + + find_inedges(root); + for (i = maxlevel; i >= 0; --i) + for (p = levels[i]; p; p = p->link) + opt_blk(p, do_stmts); + + if (do_stmts) + /* + * No point trying to move branches; it can't possibly + * make a difference at this point. + */ + return; + + for (i = 1; i <= maxlevel; ++i) { + for (p = levels[i]; p; p = p->link) { + opt_j(&p->et); + opt_j(&p->ef); + } + } + + find_inedges(root); + for (i = 1; i <= maxlevel; ++i) { + for (p = levels[i]; p; p = p->link) { + or_pullup(p); + and_pullup(p); + } + } +} + +static inline void +link_inedge(struct edge *parent, struct block *child) +{ + parent->next = child->in_edges; + child->in_edges = parent; +} + +static void +find_inedges(struct block *root) +{ + int i; + struct block *b; + + for (i = 0; i < n_blocks; ++i) + blocks[i]->in_edges = 0; + + /* + * Traverse the graph, adding each edge to the predecessor + * list of its successors. Skip the leaves (i.e. level 0). + */ + for (i = root->level; i > 0; --i) { + for (b = levels[i]; b != 0; b = b->link) { + link_inedge(&b->et, JT(b)); + link_inedge(&b->ef, JF(b)); + } + } +} + +static void +opt_root(struct block **b) +{ + struct slist *tmp, *s; + + s = (*b)->stmts; + (*b)->stmts = 0; + while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b)) + *b = JT(*b); + + tmp = (*b)->stmts; + if (tmp != 0) + sappend(s, tmp); + (*b)->stmts = s; + + /* + * If the root node is a return, then there is no + * point executing any statements (since the bpf machine + * has no side effects). + */ + if (BPF_CLASS((*b)->s.code) == BPF_RET) + (*b)->stmts = 0; +} + +static void +opt_loop(struct block *root, int do_stmts) +{ + +#ifdef BDEBUG + if (dflag > 1) { + printf("opt_loop(root, %d) begin\n", do_stmts); + opt_dump(root); + } +#endif + do { + done = 1; + find_levels(root); + find_dom(root); + find_closure(root); + find_ud(root); + find_edom(root); + opt_blks(root, do_stmts); +#ifdef BDEBUG + if (dflag > 1) { + printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, done); + opt_dump(root); + } +#endif + } while (!done); +} + +/* + * Optimize the filter code in its dag representation. + */ +void +bpf_optimize(struct block **rootp) +{ + struct block *root; + + root = *rootp; + + opt_init(root); + opt_loop(root, 0); + opt_loop(root, 1); + intern_blocks(root); +#ifdef BDEBUG + if (dflag > 1) { + printf("after intern_blocks()\n"); + opt_dump(root); + } +#endif + opt_root(rootp); +#ifdef BDEBUG + if (dflag > 1) { + printf("after opt_root()\n"); + opt_dump(root); + } +#endif + opt_cleanup(); +} + +static void +make_marks(struct block *p) +{ + if (!isMarked(p)) { + Mark(p); + if (BPF_CLASS(p->s.code) != BPF_RET) { + make_marks(JT(p)); + make_marks(JF(p)); + } + } +} + +/* + * Mark code array such that isMarked(i) is true + * only for nodes that are alive. + */ +static void +mark_code(struct block *p) +{ + cur_mark += 1; + make_marks(p); +} + +/* + * True iff the two stmt lists load the same value from the packet into + * the accumulator. + */ +static int +eq_slist(struct slist *x, struct slist *y) +{ + while (1) { + while (x && x->s.code == NOP) + x = x->next; + while (y && y->s.code == NOP) + y = y->next; + if (x == 0) + return y == 0; + if (y == 0) + return x == 0; + if (x->s.code != y->s.code || x->s.k != y->s.k) + return 0; + x = x->next; + y = y->next; + } +} + +static inline int +eq_blk(struct block *b0, struct block *b1) +{ + if (b0->s.code == b1->s.code && + b0->s.k == b1->s.k && + b0->et.succ == b1->et.succ && + b0->ef.succ == b1->ef.succ) + return eq_slist(b0->stmts, b1->stmts); + return 0; +} + +static void +intern_blocks(struct block *root) +{ + struct block *p; + int i, j; + int done1; /* don't shadow global */ + top: + done1 = 1; + for (i = 0; i < n_blocks; ++i) + blocks[i]->link = 0; + + mark_code(root); + + for (i = n_blocks - 1; --i >= 0; ) { + if (!isMarked(blocks[i])) + continue; + for (j = i + 1; j < n_blocks; ++j) { + if (!isMarked(blocks[j])) + continue; + if (eq_blk(blocks[i], blocks[j])) { + blocks[i]->link = blocks[j]->link ? + blocks[j]->link : blocks[j]; + break; + } + } + } + for (i = 0; i < n_blocks; ++i) { + p = blocks[i]; + if (JT(p) == 0) + continue; + if (JT(p)->link) { + done1 = 0; + JT(p) = JT(p)->link; + } + if (JF(p)->link) { + done1 = 0; + JF(p) = JF(p)->link; + } + } + if (!done1) + goto top; +} + +static void +opt_cleanup(void) +{ + free((void *)vnode_base); + free((void *)vmap); + free((void *)edges); + free((void *)space); + free((void *)levels); + free((void *)blocks); +} + +/* + * Return the number of stmts in 's'. + */ +static u_int +slength(struct slist *s) +{ + u_int n = 0; + + for (; s; s = s->next) + if (s->s.code != NOP) + ++n; + return n; +} + +/* + * Return the number of nodes reachable by 'p'. + * All nodes should be initially unmarked. + */ +static int +count_blocks(struct block *p) +{ + if (p == 0 || isMarked(p)) + return 0; + Mark(p); + return count_blocks(JT(p)) + count_blocks(JF(p)) + 1; +} + +/* + * Do a depth first search on the flow graph, numbering the + * the basic blocks, and entering them into the 'blocks' array.` + */ +static void +number_blks_r(struct block *p) +{ + int n; + + if (p == 0 || isMarked(p)) + return; + + Mark(p); + n = n_blocks++; + p->id = n; + blocks[n] = p; + + number_blks_r(JT(p)); + number_blks_r(JF(p)); +} + +/* + * Return the number of stmts in the flowgraph reachable by 'p'. + * The nodes should be unmarked before calling. + * + * Note that "stmts" means "instructions", and that this includes + * + * side-effect statements in 'p' (slength(p->stmts)); + * + * statements in the true branch from 'p' (count_stmts(JT(p))); + * + * statements in the false branch from 'p' (count_stmts(JF(p))); + * + * the conditional jump itself (1); + * + * an extra long jump if the true branch requires it (p->longjt); + * + * an extra long jump if the false branch requires it (p->longjf). + */ +static u_int +count_stmts(struct block *p) +{ + u_int n; + + if (p == 0 || isMarked(p)) + return 0; + Mark(p); + n = count_stmts(JT(p)) + count_stmts(JF(p)); + return slength(p->stmts) + n + 1 + p->longjt + p->longjf; +} + +/* + * Allocate memory. All allocation is done before optimization + * is begun. A linear bound on the size of all data structures is computed + * from the total number of blocks and/or statements. + */ +static void +opt_init(struct block *root) +{ + bpf_u_int32 *p; + int i, n, max_stmts; + + /* + * First, count the blocks, so we can malloc an array to map + * block number to block. Then, put the blocks into the array. + */ + unMarkAll(); + n = count_blocks(root); + blocks = (struct block **)calloc(n, sizeof(*blocks)); + if (blocks == NULL) + bpf_error("malloc"); + unMarkAll(); + n_blocks = 0; + number_blks_r(root); + + n_edges = 2 * n_blocks; + edges = (struct edge **)calloc(n_edges, sizeof(*edges)); + if (edges == NULL) + bpf_error("malloc"); + + /* + * The number of levels is bounded by the number of nodes. + */ + levels = (struct block **)calloc(n_blocks, sizeof(*levels)); + if (levels == NULL) + bpf_error("malloc"); + + edgewords = n_edges / (8 * sizeof(bpf_u_int32)) + 1; + nodewords = n_blocks / (8 * sizeof(bpf_u_int32)) + 1; + + /* XXX */ + space = (bpf_u_int32 *)malloc(2 * n_blocks * nodewords * sizeof(*space) + + n_edges * edgewords * sizeof(*space)); + if (space == NULL) + bpf_error("malloc"); + p = space; + all_dom_sets = p; + for (i = 0; i < n; ++i) { + blocks[i]->dom = p; + p += nodewords; + } + all_closure_sets = p; + for (i = 0; i < n; ++i) { + blocks[i]->closure = p; + p += nodewords; + } + all_edge_sets = p; + for (i = 0; i < n; ++i) { + register struct block *b = blocks[i]; + + b->et.edom = p; + p += edgewords; + b->ef.edom = p; + p += edgewords; + b->et.id = i; + edges[i] = &b->et; + b->ef.id = n_blocks + i; + edges[n_blocks + i] = &b->ef; + b->et.pred = b; + b->ef.pred = b; + } + max_stmts = 0; + for (i = 0; i < n; ++i) + max_stmts += slength(blocks[i]->stmts) + 1; + /* + * We allocate at most 3 value numbers per statement, + * so this is an upper bound on the number of valnodes + * we'll need. + */ + maxval = 3 * max_stmts; + vmap = (struct vmapinfo *)calloc(maxval, sizeof(*vmap)); + vnode_base = (struct valnode *)calloc(maxval, sizeof(*vnode_base)); + if (vmap == NULL || vnode_base == NULL) + bpf_error("malloc"); +} + +/* + * Some pointers used to convert the basic block form of the code, + * into the array form that BPF requires. 'fstart' will point to + * the malloc'd array while 'ftail' is used during the recursive traversal. + */ +static struct bpf_insn *fstart; +static struct bpf_insn *ftail; + +#ifdef BDEBUG +int bids[1000]; +#endif + +/* + * Returns true if successful. Returns false if a branch has + * an offset that is too large. If so, we have marked that + * branch so that on a subsequent iteration, it will be treated + * properly. + */ +static int +convert_code_r(struct block *p) +{ + struct bpf_insn *dst; + struct slist *src; + int slen; + u_int off; + int extrajmps; /* number of extra jumps inserted */ + struct slist **offset = NULL; + + if (p == 0 || isMarked(p)) + return (1); + Mark(p); + + if (convert_code_r(JF(p)) == 0) + return (0); + if (convert_code_r(JT(p)) == 0) + return (0); + + slen = slength(p->stmts); + dst = ftail -= (slen + 1 + p->longjt + p->longjf); + /* inflate length by any extra jumps */ + + p->offset = dst - fstart; + + /* generate offset[] for convenience */ + if (slen) { + offset = (struct slist **)calloc(slen, sizeof(struct slist *)); + if (!offset) { + bpf_error("not enough core"); + /*NOTREACHED*/ + } + } + src = p->stmts; + for (off = 0; off < slen && src; off++) { +#if 0 + printf("off=%d src=%x\n", off, src); +#endif + offset[off] = src; + src = src->next; + } + + off = 0; + for (src = p->stmts; src; src = src->next) { + if (src->s.code == NOP) + continue; + dst->code = (u_short)src->s.code; + dst->k = src->s.k; + + /* fill block-local relative jump */ + if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP|BPF_JA)) { +#if 0 + if (src->s.jt || src->s.jf) { + bpf_error("illegal jmp destination"); + /*NOTREACHED*/ + } +#endif + goto filled; + } + if (off == slen - 2) /*???*/ + goto filled; + + { + int i; + int jt, jf; + const char *ljerr = "%s for block-local relative jump: off=%d"; + +#if 0 + printf("code=%x off=%d %x %x\n", src->s.code, + off, src->s.jt, src->s.jf); +#endif + + if (!src->s.jt || !src->s.jf) { + bpf_error(ljerr, "no jmp destination", off); + /*NOTREACHED*/ + } + + jt = jf = 0; + for (i = 0; i < slen; i++) { + if (offset[i] == src->s.jt) { + if (jt) { + bpf_error(ljerr, "multiple matches", off); + /*NOTREACHED*/ + } + + dst->jt = i - off - 1; + jt++; + } + if (offset[i] == src->s.jf) { + if (jf) { + bpf_error(ljerr, "multiple matches", off); + /*NOTREACHED*/ + } + dst->jf = i - off - 1; + jf++; + } + } + if (!jt || !jf) { + bpf_error(ljerr, "no destination found", off); + /*NOTREACHED*/ + } + } +filled: + ++dst; + ++off; + } + if (offset) + free(offset); + +#ifdef BDEBUG + bids[dst - fstart] = p->id + 1; +#endif + dst->code = (u_short)p->s.code; + dst->k = p->s.k; + if (JT(p)) { + extrajmps = 0; + off = JT(p)->offset - (p->offset + slen) - 1; + if (off >= 256) { + /* offset too large for branch, must add a jump */ + if (p->longjt == 0) { + /* mark this instruction and retry */ + p->longjt++; + return(0); + } + /* branch if T to following jump */ + dst->jt = extrajmps; + extrajmps++; + dst[extrajmps].code = BPF_JMP|BPF_JA; + dst[extrajmps].k = off - extrajmps; + } + else + dst->jt = off; + off = JF(p)->offset - (p->offset + slen) - 1; + if (off >= 256) { + /* offset too large for branch, must add a jump */ + if (p->longjf == 0) { + /* mark this instruction and retry */ + p->longjf++; + return(0); + } + /* branch if F to following jump */ + /* if two jumps are inserted, F goes to second one */ + dst->jf = extrajmps; + extrajmps++; + dst[extrajmps].code = BPF_JMP|BPF_JA; + dst[extrajmps].k = off - extrajmps; + } + else + dst->jf = off; + } + return (1); +} + + +/* + * Convert flowgraph intermediate representation to the + * BPF array representation. Set *lenp to the number of instructions. + * + * This routine does *NOT* leak the memory pointed to by fp. It *must + * not* do free(fp) before returning fp; doing so would make no sense, + * as the BPF array pointed to by the return value of icode_to_fcode() + * must be valid - it's being returned for use in a bpf_program structure. + * + * If it appears that icode_to_fcode() is leaking, the problem is that + * the program using pcap_compile() is failing to free the memory in + * the BPF program when it's done - the leak is in the program, not in + * the routine that happens to be allocating the memory. (By analogy, if + * a program calls fopen() without ever calling fclose() on the FILE *, + * it will leak the FILE structure; the leak is not in fopen(), it's in + * the program.) Change the program to use pcap_freecode() when it's + * done with the filter program. See the pcap man page. + */ +struct bpf_insn * +icode_to_fcode(struct block *root, u_int *lenp) +{ + u_int n; + struct bpf_insn *fp; + + /* + * Loop doing convert_code_r() until no branches remain + * with too-large offsets. + */ + while (1) { + unMarkAll(); + n = *lenp = count_stmts(root); + + fp = (struct bpf_insn *)malloc(sizeof(*fp) * n); + if (fp == NULL) + bpf_error("malloc"); + memset((char *)fp, 0, sizeof(*fp) * n); + fstart = fp; + ftail = fp + n; + + unMarkAll(); + if (convert_code_r(root)) + break; + free(fp); + } + + return fp; +} + +/* + * Make a copy of a BPF program and put it in the "fcode" member of + * a "pcap_t". + * + * If we fail to allocate memory for the copy, fill in the "errbuf" + * member of the "pcap_t" with an error message, and return -1; + * otherwise, return 0. + */ +int +install_bpf_program(pcap_t *p, struct bpf_program *fp) +{ + size_t prog_size; + + /* + * Validate the program. + */ + if (!bpf_validate(fp->bf_insns, fp->bf_len)) { + snprintf(p->errbuf, sizeof(p->errbuf), + "BPF program is not valid"); + return (-1); + } + + /* + * Free up any already installed program. + */ + pcap_freecode(&p->fcode); + + prog_size = sizeof(*fp->bf_insns) * fp->bf_len; + p->fcode.bf_len = fp->bf_len; + p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size); + if (p->fcode.bf_insns == NULL) { + snprintf(p->errbuf, sizeof(p->errbuf), + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size); + return (0); +} + +#ifdef BDEBUG +static void +dot_dump_node(struct block *block, struct bpf_program *prog, FILE *out) +{ + int icount, noffset; + int i; + + if (block == NULL || isMarked(block)) + return; + Mark(block); + + icount = slength(block->stmts) + 1 + block->longjt + block->longjf; + noffset = min(block->offset + icount, (int)prog->bf_len); + + fprintf(out, "\tblock%d [shape=ellipse, id=\"block-%d\" label=\"BLOCK%d\\n", block->id, block->id, block->id); + for (i = block->offset; i < noffset; i++) { + fprintf(out, "\\n%s", bpf_image(prog->bf_insns + i, i)); + } + fprintf(out, "\" tooltip=\""); + for (i = 0; i < BPF_MEMWORDS; i++) + if (block->val[i] != 0) + fprintf(out, "val[%d]=%d ", i, block->val[i]); + fprintf(out, "val[A]=%d ", block->val[A_ATOM]); + fprintf(out, "val[X]=%d", block->val[X_ATOM]); + fprintf(out, "\""); + if (JT(block) == NULL) + fprintf(out, ", peripheries=2"); + fprintf(out, "];\n"); + + dot_dump_node(JT(block), prog, out); + dot_dump_node(JF(block), prog, out); +} +static void +dot_dump_edge(struct block *block, FILE *out) +{ + if (block == NULL || isMarked(block)) + return; + Mark(block); + + if (JT(block)) { + fprintf(out, "\t\"block%d\":se -> \"block%d\":n [label=\"T\"]; \n", + block->id, JT(block)->id); + fprintf(out, "\t\"block%d\":sw -> \"block%d\":n [label=\"F\"]; \n", + block->id, JF(block)->id); + } + dot_dump_edge(JT(block), out); + dot_dump_edge(JF(block), out); +} +/* Output the block CFG using graphviz/DOT language + * In the CFG, block's code, value index for each registers at EXIT, + * and the jump relationship is show. + * + * example DOT for BPF `ip src host 1.1.1.1' is: + digraph BPF { + block0 [shape=ellipse, id="block-0" label="BLOCK0\n\n(000) ldh [12]\n(001) jeq #0x800 jt 2 jf 5" tooltip="val[A]=0 val[X]=0"]; + block1 [shape=ellipse, id="block-1" label="BLOCK1\n\n(002) ld [26]\n(003) jeq #0x1010101 jt 4 jf 5" tooltip="val[A]=0 val[X]=0"]; + block2 [shape=ellipse, id="block-2" label="BLOCK2\n\n(004) ret #68" tooltip="val[A]=0 val[X]=0", peripheries=2]; + block3 [shape=ellipse, id="block-3" label="BLOCK3\n\n(005) ret #0" tooltip="val[A]=0 val[X]=0", peripheries=2]; + "block0":se -> "block1":n [label="T"]; + "block0":sw -> "block3":n [label="F"]; + "block1":se -> "block2":n [label="T"]; + "block1":sw -> "block3":n [label="F"]; + } + * + * After install graphviz on http://www.graphviz.org/, save it as bpf.dot + * and run `dot -Tpng -O bpf.dot' to draw the graph. + */ +static void +dot_dump(struct block *root) +{ + struct bpf_program f; + FILE *out = stdout; + + memset(bids, 0, sizeof bids); + f.bf_insns = icode_to_fcode(root, &f.bf_len); + + fprintf(out, "digraph BPF {\n"); + unMarkAll(); + dot_dump_node(root, &f, out); + unMarkAll(); + dot_dump_edge(root, out); + fprintf(out, "}\n"); + + free((char *)f.bf_insns); +} + +static void +plain_dump(struct block *root) +{ + struct bpf_program f; + + memset(bids, 0, sizeof bids); + f.bf_insns = icode_to_fcode(root, &f.bf_len); + bpf_dump(&f, 1); + putchar('\n'); + free((char *)f.bf_insns); +} +static void +opt_dump(struct block *root) +{ + /* if optimizer debugging is enabled, output DOT graph + * `dflag=4' is equivalent to -dddd to follow -d/-dd/-ddd + * convention in tcpdump command line + */ + if (dflag > 3) + dot_dump(root); + else + plain_dump(root); +} + +#endif diff --git a/tcpdump/jni/libpcap/org.tcpdump.chmod_bpf.plist b/tcpdump/jni/libpcap/org.tcpdump.chmod_bpf.plist new file mode 100644 index 0000000..8ad6852 --- /dev/null +++ b/tcpdump/jni/libpcap/org.tcpdump.chmod_bpf.plist @@ -0,0 +1,16 @@ + + + + + Label + org.tcpdump.chmod_bpf + RunAtLoad + + Program + /usr/local/bin/chmod_bpf + ProgramArguments + + /usr/local/bin/chmod_bpf + + + diff --git a/tcpdump/jni/libpcap/packaging/pcap.spec.in b/tcpdump/jni/libpcap/packaging/pcap.spec.in new file mode 100644 index 0000000..ff7b996 --- /dev/null +++ b/tcpdump/jni/libpcap/packaging/pcap.spec.in @@ -0,0 +1,77 @@ +%define prefix /usr +%define version @VERSION@ + +Summary: A system-independent interface for user-level packet capture +Name: libpcap +Version: %version +Release: 1 +Group: Development/Libraries +License: BSD with advertising +Source: @NAME@.tar.gz +BuildRoot: /tmp/%{name}-buildroot +URL: http://www.tcpdump.org + +Source: http://www.tcpdump.org/release/%{name}-%{version}.tar.gz + +%description +Libpcap provides a portable framework for low-level network +monitoring. Libpcap can provide network statistics collection, +security monitoring and network debugging. Since almost every system +vendor provides a different interface for packet capture, the libpcap +authors created this system-independent API to ease in porting and to +alleviate the need for several system-dependent packet capture modules +in each application. + +Install libpcap if you need to do low-level network traffic monitoring +on your network. + +%package devel +Summary: Libraries and header files for the libpcap library +Group: Development/Libraries + +%description devel +Libpcap provides a portable framework for low-level network +monitoring. Libpcap can provide network statistics collection, +security monitoring and network debugging. Since almost every system +vendor provides a different interface for packet capture, the libpcap +authors created this system-independent API to ease in porting and to +alleviate the need for several system-dependent packet capture modules +in each application. + +This package provides the libraries, include files, and other +resources needed for developing libpcap applications. + +%prep +%setup -q + +%build +export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" +%configure +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT + +make DESTDIR=$RPM_BUILD_ROOT install + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc LICENSE README CHANGES INSTALL.txt README.linux TODO VERSION CREDITS packaging/pcap.spec +%{_libdir}/libpcap.so.* +%{_mandir}/man7/pcap*.7* + +%files devel +%defattr(-,root,root) +%{_bindir}/pcap-config +%{_includedir}/pcap/*.h +%{_includedir}/pcap.h +%{_includedir}/pcap-bpf.h +%{_includedir}/pcap-namedb.h +%{_libdir}/libpcap.so +%{_libdir}/libpcap.a +%{_mandir}/man1/pcap-config.1* +%{_mandir}/man3/pcap*.3* +%{_mandir}/man5/pcap*.5* diff --git a/tcpdump/jni/libpcap/pcap-bpf.c b/tcpdump/jni/libpcap/pcap-bpf.c new file mode 100644 index 0000000..b1da1a0 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-bpf.c @@ -0,0 +1,2752 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* optionally get BSD define */ +#ifdef HAVE_ZEROCOPY_BPF +#include +#endif +#include +#include +/* + * defines ioctls, but doesn't include . + * + * We include as it might be necessary to declare ioctl(); + * at least on *BSD and Mac OS X, it also defines various SIOC ioctls - + * we could include , but if we're already including + * , which includes on those platforms, + * there's not much point in doing so. + * + * If we have , we include it as well, to handle systems + * such as Solaris which don't arrange to include if you + * include + */ +#include +#ifdef HAVE_SYS_IOCCOM_H +#include +#endif +#include + +#ifdef HAVE_ZEROCOPY_BPF +#include +#endif + +#include + +#ifdef _AIX + +/* + * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the + * native OS version, as we need "struct bpf_config" from it. + */ +#define PCAP_DONT_INCLUDE_PCAP_BPF_H + +#include + +/* + * Prevent bpf.h from redefining the DLT_ values to their + * IFT_ values, as we're going to return the standard libpcap + * values, not IBM's non-standard IFT_ values. + */ +#undef _AIX +#include +#define _AIX + +#include /* for IFT_ values */ +#include +#include +#include +#include + +#ifdef __64BIT__ +#define domakedev makedev64 +#define getmajor major64 +#define bpf_hdr bpf_hdr32 +#else /* __64BIT__ */ +#define domakedev makedev +#define getmajor major +#endif /* __64BIT__ */ + +#define BPF_NAME "bpf" +#define BPF_MINORS 4 +#define DRIVER_PATH "/usr/lib/drivers" +#define BPF_NODE "/dev/bpf" +static int bpfloadedflag = 0; +static int odmlockid = 0; + +static int bpf_load(char *errbuf); + +#else /* _AIX */ + +#include + +#endif /* _AIX */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NET_IF_MEDIA_H +# include +#endif + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * Later versions of NetBSD stick padding in front of FDDI frames + * to align the IP header on a 4-byte boundary. + */ +#if defined(__NetBSD__) && __NetBSD_Version__ > 106000000 +#define PCAP_FDDIPAD 3 +#endif + +/* + * Private data for capturing on BPF devices. + */ +struct pcap_bpf { +#ifdef PCAP_FDDIPAD + int fddipad; +#endif + +#ifdef HAVE_ZEROCOPY_BPF + /* + * Zero-copy read buffer -- for zero-copy BPF. 'buffer' above will + * alternative between these two actual mmap'd buffers as required. + * As there is a header on the front size of the mmap'd buffer, only + * some of the buffer is exposed to libpcap as a whole via bufsize; + * zbufsize is the true size. zbuffer tracks the current zbuf + * assocated with buffer so that it can be used to decide which the + * next buffer to read will be. + */ + u_char *zbuf1, *zbuf2, *zbuffer; + u_int zbufsize; + u_int zerocopy; + u_int interrupted; + struct timespec firstsel; + /* + * If there's currently a buffer being actively processed, then it is + * referenced here; 'buffer' is also pointed at it, but offset by the + * size of the header. + */ + struct bpf_zbuf_header *bzh; + int nonblock; /* true if in nonblocking mode */ +#endif /* HAVE_ZEROCOPY_BPF */ + + char *device; /* device name */ + int filtering_in_kernel; /* using kernel filter */ + int must_do_on_close; /* stuff we must do when we close */ +}; + +/* + * Stuff to do when we close. + */ +#define MUST_CLEAR_RFMON 0x00000001 /* clear rfmon (monitor) mode */ + +#ifdef BIOCGDLTLIST +# if (defined(HAVE_NET_IF_MEDIA_H) && defined(IFM_IEEE80211)) && !defined(__APPLE__) +#define HAVE_BSD_IEEE80211 +# endif + +# if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) +static int find_802_11(struct bpf_dltlist *); + +# ifdef HAVE_BSD_IEEE80211 +static int monitor_mode(pcap_t *, int); +# endif + +# if defined(__APPLE__) +static void remove_en(pcap_t *); +static void remove_802_11(pcap_t *); +# endif + +# endif /* defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) */ + +#endif /* BIOCGDLTLIST */ + +#if defined(sun) && defined(LIFNAMSIZ) && defined(lifr_zoneid) +#include +#endif + +/* + * We include the OS's , not our "pcap/bpf.h", so we probably + * don't get DLT_DOCSIS defined. + */ +#ifndef DLT_DOCSIS +#define DLT_DOCSIS 143 +#endif + +/* + * On OS X, we don't even get any of the 802.11-plus-radio-header DLT_'s + * defined, even though some of them are used by various Airport drivers. + */ +#ifndef DLT_PRISM_HEADER +#define DLT_PRISM_HEADER 119 +#endif +#ifndef DLT_AIRONET_HEADER +#define DLT_AIRONET_HEADER 120 +#endif +#ifndef DLT_IEEE802_11_RADIO +#define DLT_IEEE802_11_RADIO 127 +#endif +#ifndef DLT_IEEE802_11_RADIO_AVS +#define DLT_IEEE802_11_RADIO_AVS 163 +#endif + +static int pcap_can_set_rfmon_bpf(pcap_t *p); +static int pcap_activate_bpf(pcap_t *p); +static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp); +static int pcap_setdirection_bpf(pcap_t *, pcap_direction_t); +static int pcap_set_datalink_bpf(pcap_t *p, int dlt); + +/* + * For zerocopy bpf, the setnonblock/getnonblock routines need to modify + * pb->nonblock so we don't call select(2) if the pcap handle is in non- + * blocking mode. + */ +static int +pcap_getnonblock_bpf(pcap_t *p, char *errbuf) +{ +#ifdef HAVE_ZEROCOPY_BPF + struct pcap_bpf *pb = p->priv; + + if (pb->zerocopy) + return (pb->nonblock); +#endif + return (pcap_getnonblock_fd(p, errbuf)); +} + +static int +pcap_setnonblock_bpf(pcap_t *p, int nonblock, char *errbuf) +{ +#ifdef HAVE_ZEROCOPY_BPF + struct pcap_bpf *pb = p->priv; + + if (pb->zerocopy) { + pb->nonblock = nonblock; + return (0); + } +#endif + return (pcap_setnonblock_fd(p, nonblock, errbuf)); +} + +#ifdef HAVE_ZEROCOPY_BPF +/* + * Zero-copy BPF buffer routines to check for and acknowledge BPF data in + * shared memory buffers. + * + * pcap_next_zbuf_shm(): Check for a newly available shared memory buffer, + * and set up p->buffer and cc to reflect one if available. Notice that if + * there was no prior buffer, we select zbuf1 as this will be the first + * buffer filled for a fresh BPF session. + */ +static int +pcap_next_zbuf_shm(pcap_t *p, int *cc) +{ + struct pcap_bpf *pb = p->priv; + struct bpf_zbuf_header *bzh; + + if (pb->zbuffer == pb->zbuf2 || pb->zbuffer == NULL) { + bzh = (struct bpf_zbuf_header *)pb->zbuf1; + if (bzh->bzh_user_gen != + atomic_load_acq_int(&bzh->bzh_kernel_gen)) { + pb->bzh = bzh; + pb->zbuffer = (u_char *)pb->zbuf1; + p->buffer = pb->zbuffer + sizeof(*bzh); + *cc = bzh->bzh_kernel_len; + return (1); + } + } else if (pb->zbuffer == pb->zbuf1) { + bzh = (struct bpf_zbuf_header *)pb->zbuf2; + if (bzh->bzh_user_gen != + atomic_load_acq_int(&bzh->bzh_kernel_gen)) { + pb->bzh = bzh; + pb->zbuffer = (u_char *)pb->zbuf2; + p->buffer = pb->zbuffer + sizeof(*bzh); + *cc = bzh->bzh_kernel_len; + return (1); + } + } + *cc = 0; + return (0); +} + +/* + * pcap_next_zbuf() -- Similar to pcap_next_zbuf_shm(), except wait using + * select() for data or a timeout, and possibly force rotation of the buffer + * in the event we time out or are in immediate mode. Invoke the shared + * memory check before doing system calls in order to avoid doing avoidable + * work. + */ +static int +pcap_next_zbuf(pcap_t *p, int *cc) +{ + struct pcap_bpf *pb = p->priv; + struct bpf_zbuf bz; + struct timeval tv; + struct timespec cur; + fd_set r_set; + int data, r; + int expire, tmout; + +#define TSTOMILLI(ts) (((ts)->tv_sec * 1000) + ((ts)->tv_nsec / 1000000)) + /* + * Start out by seeing whether anything is waiting by checking the + * next shared memory buffer for data. + */ + data = pcap_next_zbuf_shm(p, cc); + if (data) + return (data); + /* + * If a previous sleep was interrupted due to signal delivery, make + * sure that the timeout gets adjusted accordingly. This requires + * that we analyze when the timeout should be been expired, and + * subtract the current time from that. If after this operation, + * our timeout is less then or equal to zero, handle it like a + * regular timeout. + */ + tmout = p->opt.timeout; + if (tmout) + (void) clock_gettime(CLOCK_MONOTONIC, &cur); + if (pb->interrupted && p->opt.timeout) { + expire = TSTOMILLI(&pb->firstsel) + p->opt.timeout; + tmout = expire - TSTOMILLI(&cur); +#undef TSTOMILLI + if (tmout <= 0) { + pb->interrupted = 0; + data = pcap_next_zbuf_shm(p, cc); + if (data) + return (data); + if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { + (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCROTZBUF: %s", strerror(errno)); + return (PCAP_ERROR); + } + return (pcap_next_zbuf_shm(p, cc)); + } + } + /* + * No data in the buffer, so must use select() to wait for data or + * the next timeout. Note that we only call select if the handle + * is in blocking mode. + */ + if (!pb->nonblock) { + FD_ZERO(&r_set); + FD_SET(p->fd, &r_set); + if (tmout != 0) { + tv.tv_sec = tmout / 1000; + tv.tv_usec = (tmout * 1000) % 1000000; + } + r = select(p->fd + 1, &r_set, NULL, NULL, + p->opt.timeout != 0 ? &tv : NULL); + if (r < 0 && errno == EINTR) { + if (!pb->interrupted && p->opt.timeout) { + pb->interrupted = 1; + pb->firstsel = cur; + } + return (0); + } else if (r < 0) { + (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "select: %s", strerror(errno)); + return (PCAP_ERROR); + } + } + pb->interrupted = 0; + /* + * Check again for data, which may exist now that we've either been + * woken up as a result of data or timed out. Try the "there's data" + * case first since it doesn't require a system call. + */ + data = pcap_next_zbuf_shm(p, cc); + if (data) + return (data); + /* + * Try forcing a buffer rotation to dislodge timed out or immediate + * data. + */ + if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { + (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCROTZBUF: %s", strerror(errno)); + return (PCAP_ERROR); + } + return (pcap_next_zbuf_shm(p, cc)); +} + +/* + * Notify kernel that we are done with the buffer. We don't reset zbuffer so + * that we know which buffer to use next time around. + */ +static int +pcap_ack_zbuf(pcap_t *p) +{ + struct pcap_bpf *pb = p->priv; + + atomic_store_rel_int(&pb->bzh->bzh_user_gen, + pb->bzh->bzh_kernel_gen); + pb->bzh = NULL; + p->buffer = NULL; + return (0); +} +#endif /* HAVE_ZEROCOPY_BPF */ + +pcap_t * +pcap_create_interface(const char *device, char *ebuf) +{ + pcap_t *p; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_bpf)); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_bpf; + p->can_set_rfmon_op = pcap_can_set_rfmon_bpf; + return (p); +} + +/* + * On success, returns a file descriptor for a BPF device. + * On failure, returns a PCAP_ERROR_ value, and sets p->errbuf. + */ +static int +bpf_open(pcap_t *p) +{ + int fd; +#ifdef HAVE_CLONING_BPF + static const char device[] = "/dev/bpf"; +#else + int n = 0; + char device[sizeof "/dev/bpf0000000000"]; +#endif + +#ifdef _AIX + /* + * Load the bpf driver, if it isn't already loaded, + * and create the BPF device entries, if they don't + * already exist. + */ + if (bpf_load(p->errbuf) == PCAP_ERROR) + return (PCAP_ERROR); +#endif + +#ifdef HAVE_CLONING_BPF + if ((fd = open(device, O_RDWR)) == -1 && + (errno != EACCES || (fd = open(device, O_RDONLY)) == -1)) { + if (errno == EACCES) + fd = PCAP_ERROR_PERM_DENIED; + else + fd = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "(cannot open device) %s: %s", device, pcap_strerror(errno)); + } +#else + /* + * Go through all the minors and find one that isn't in use. + */ + do { + (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++); + /* + * Initially try a read/write open (to allow the inject + * method to work). If that fails due to permission + * issues, fall back to read-only. This allows a + * non-root user to be granted specific access to pcap + * capabilities via file permissions. + * + * XXX - we should have an API that has a flag that + * controls whether to open read-only or read-write, + * so that denial of permission to send (or inability + * to send, if sending packets isn't supported on + * the device in question) can be indicated at open + * time. + */ + fd = open(device, O_RDWR); + if (fd == -1 && errno == EACCES) + fd = open(device, O_RDONLY); + } while (fd < 0 && errno == EBUSY); + + /* + * XXX better message for all minors used + */ + if (fd < 0) { + switch (errno) { + + case ENOENT: + fd = PCAP_ERROR; + if (n == 1) { + /* + * /dev/bpf0 doesn't exist, which + * means we probably have no BPF + * devices. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "(there are no BPF devices)"); + } else { + /* + * We got EBUSY on at least one + * BPF device, so we have BPF + * devices, but all the ones + * that exist are busy. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "(all BPF devices are busy)"); + } + break; + + case EACCES: + /* + * Got EACCES on the last device we tried, + * and EBUSY on all devices before that, + * if any. + */ + fd = PCAP_ERROR_PERM_DENIED; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "(cannot open BPF device) %s: %s", device, + pcap_strerror(errno)); + break; + + default: + /* + * Some other problem. + */ + fd = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "(cannot open BPF device) %s: %s", device, + pcap_strerror(errno)); + break; + } + } +#endif + + return (fd); +} + +#ifdef BIOCGDLTLIST +static int +get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf) +{ + memset(bdlp, 0, sizeof(*bdlp)); + if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) == 0) { + u_int i; + int is_ethernet; + + bdlp->bfl_list = (u_int *) malloc(sizeof(u_int) * (bdlp->bfl_len + 1)); + if (bdlp->bfl_list == NULL) { + (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + return (PCAP_ERROR); + } + + if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) < 0) { + (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, + "BIOCGDLTLIST: %s", pcap_strerror(errno)); + free(bdlp->bfl_list); + return (PCAP_ERROR); + } + + /* + * OK, for real Ethernet devices, add DLT_DOCSIS to the + * list, so that an application can let you choose it, + * in case you're capturing DOCSIS traffic that a Cisco + * Cable Modem Termination System is putting out onto + * an Ethernet (it doesn't put an Ethernet header onto + * the wire, it puts raw DOCSIS frames out on the wire + * inside the low-level Ethernet framing). + * + * A "real Ethernet device" is defined here as a device + * that has a link-layer type of DLT_EN10MB and that has + * no alternate link-layer types; that's done to exclude + * 802.11 interfaces (which might or might not be the + * right thing to do, but I suspect it is - Ethernet <-> + * 802.11 bridges would probably badly mishandle frames + * that don't have Ethernet headers). + * + * On Solaris with BPF, Ethernet devices also offer + * DLT_IPNET, so we, if DLT_IPNET is defined, we don't + * treat it as an indication that the device isn't an + * Ethernet. + */ + if (v == DLT_EN10MB) { + is_ethernet = 1; + for (i = 0; i < bdlp->bfl_len; i++) { + if (bdlp->bfl_list[i] != DLT_EN10MB +#ifdef DLT_IPNET + && bdlp->bfl_list[i] != DLT_IPNET +#endif + ) { + is_ethernet = 0; + break; + } + } + if (is_ethernet) { + /* + * We reserved one more slot at the end of + * the list. + */ + bdlp->bfl_list[bdlp->bfl_len] = DLT_DOCSIS; + bdlp->bfl_len++; + } + } + } else { + /* + * EINVAL just means "we don't support this ioctl on + * this device"; don't treat it as an error. + */ + if (errno != EINVAL) { + (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, + "BIOCGDLTLIST: %s", pcap_strerror(errno)); + return (PCAP_ERROR); + } + } + return (0); +} +#endif + +static int +pcap_can_set_rfmon_bpf(pcap_t *p) +{ +#if defined(__APPLE__) + struct utsname osinfo; + struct ifreq ifr; + int fd; +#ifdef BIOCGDLTLIST + struct bpf_dltlist bdl; +#endif + + /* + * The joys of monitor mode on OS X. + * + * Prior to 10.4, it's not supported at all. + * + * In 10.4, if adapter enN supports monitor mode, there's a + * wltN adapter corresponding to it; you open it, instead of + * enN, to get monitor mode. You get whatever link-layer + * headers it supplies. + * + * In 10.5, and, we assume, later releases, if adapter enN + * supports monitor mode, it offers, among its selectable + * DLT_ values, values that let you get the 802.11 header; + * selecting one of those values puts the adapter into monitor + * mode (i.e., you can't get 802.11 headers except in monitor + * mode, and you can't get Ethernet headers in monitor mode). + */ + if (uname(&osinfo) == -1) { + /* + * Can't get the OS version; just say "no". + */ + return (0); + } + /* + * We assume osinfo.sysname is "Darwin", because + * __APPLE__ is defined. We just check the version. + */ + if (osinfo.release[0] < '8' && osinfo.release[1] == '.') { + /* + * 10.3 (Darwin 7.x) or earlier. + * Monitor mode not supported. + */ + return (0); + } + if (osinfo.release[0] == '8' && osinfo.release[1] == '.') { + /* + * 10.4 (Darwin 8.x). s/en/wlt/, and check + * whether the device exists. + */ + if (strncmp(p->opt.source, "en", 2) != 0) { + /* + * Not an enN device; no monitor mode. + */ + return (0); + } + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + return (PCAP_ERROR); + } + strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name)); + strlcat(ifr.ifr_name, p->opt.source + 2, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { + /* + * No such device? + */ + close(fd); + return (0); + } + close(fd); + return (1); + } + +#ifdef BIOCGDLTLIST + /* + * Everything else is 10.5 or later; for those, + * we just open the enN device, and check whether + * we have any 802.11 devices. + * + * First, open a BPF device. + */ + fd = bpf_open(p); + if (fd < 0) + return (fd); /* fd is the appropriate error code */ + + /* + * Now bind to the device. + */ + (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name)); + if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { + switch (errno) { + + case ENXIO: + /* + * There's no such device. + */ + close(fd); + return (PCAP_ERROR_NO_SUCH_DEVICE); + + case ENETDOWN: + /* + * Return a "network down" indication, so that + * the application can report that rather than + * saying we had a mysterious failure and + * suggest that they report a problem to the + * libpcap developers. + */ + close(fd); + return (PCAP_ERROR_IFACE_NOT_UP); + + default: + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCSETIF: %s: %s", + p->opt.source, pcap_strerror(errno)); + close(fd); + return (PCAP_ERROR); + } + } + + /* + * We know the default link type -- now determine all the DLTs + * this interface supports. If this fails with EINVAL, it's + * not fatal; we just don't get to use the feature later. + * (We don't care about DLT_DOCSIS, so we pass DLT_NULL + * as the default DLT for this adapter.) + */ + if (get_dlt_list(fd, DLT_NULL, &bdl, p->errbuf) == PCAP_ERROR) { + close(fd); + return (PCAP_ERROR); + } + if (find_802_11(&bdl) != -1) { + /* + * We have an 802.11 DLT, so we can set monitor mode. + */ + free(bdl.bfl_list); + close(fd); + return (1); + } + free(bdl.bfl_list); +#endif /* BIOCGDLTLIST */ + return (0); +#elif defined(HAVE_BSD_IEEE80211) + int ret; + + ret = monitor_mode(p, 0); + if (ret == PCAP_ERROR_RFMON_NOTSUP) + return (0); /* not an error, just a "can't do" */ + if (ret == 0) + return (1); /* success */ + return (ret); +#else + return (0); +#endif +} + +static int +pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps) +{ + struct bpf_stat s; + + /* + * "ps_recv" counts packets handed to the filter, not packets + * that passed the filter. This includes packets later dropped + * because we ran out of buffer space. + * + * "ps_drop" counts packets dropped inside the BPF device + * because we ran out of buffer space. It doesn't count + * packets dropped by the interface driver. It counts + * only packets that passed the filter. + * + * Both statistics include packets not yet read from the kernel + * by libpcap, and thus not yet seen by the application. + */ + if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s", + pcap_strerror(errno)); + return (PCAP_ERROR); + } + + ps->ps_recv = s.bs_recv; + ps->ps_drop = s.bs_drop; + ps->ps_ifdrop = 0; + return (0); +} + +static int +pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_bpf *pb = p->priv; + int cc; + int n = 0; + register u_char *bp, *ep; + u_char *datap; +#ifdef PCAP_FDDIPAD + register int pad; +#endif +#ifdef HAVE_ZEROCOPY_BPF + int i; +#endif + + again: + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return PCAP_ERROR_BREAK to indicate + * that we were told to break out of the loop. + */ + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } + cc = p->cc; + if (p->cc == 0) { + /* + * When reading without zero-copy from a file descriptor, we + * use a single buffer and return a length of data in the + * buffer. With zero-copy, we update the p->buffer pointer + * to point at whatever underlying buffer contains the next + * data and update cc to reflect the data found in the + * buffer. + */ +#ifdef HAVE_ZEROCOPY_BPF + if (pb->zerocopy) { + if (p->buffer != NULL) + pcap_ack_zbuf(p); + i = pcap_next_zbuf(p, &cc); + if (i == 0) + goto again; + if (i < 0) + return (PCAP_ERROR); + } else +#endif + { + cc = read(p->fd, (char *)p->buffer, p->bufsize); + } + if (cc < 0) { + /* Don't choke when we get ptraced */ + switch (errno) { + + case EINTR: + goto again; + +#ifdef _AIX + case EFAULT: + /* + * Sigh. More AIX wonderfulness. + * + * For some unknown reason the uiomove() + * operation in the bpf kernel extension + * used to copy the buffer into user + * space sometimes returns EFAULT. I have + * no idea why this is the case given that + * a kernel debugger shows the user buffer + * is correct. This problem appears to + * be mostly mitigated by the memset of + * the buffer before it is first used. + * Very strange.... Shaun Clowes + * + * In any case this means that we shouldn't + * treat EFAULT as a fatal error; as we + * don't have an API for returning + * a "some packets were dropped since + * the last packet you saw" indication, + * we just ignore EFAULT and keep reading. + */ + goto again; +#endif + + case EWOULDBLOCK: + return (0); + + case ENXIO: + /* + * The device on which we're capturing + * went away. + * + * XXX - we should really return + * PCAP_ERROR_IFACE_NOT_UP, but + * pcap_dispatch() etc. aren't + * defined to retur that. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The interface went down"); + return (PCAP_ERROR); + +#if defined(sun) && !defined(BSD) && !defined(__svr4__) && !defined(__SVR4) + /* + * Due to a SunOS bug, after 2^31 bytes, the kernel + * file offset overflows and read fails with EINVAL. + * The lseek() to 0 will fix things. + */ + case EINVAL: + if (lseek(p->fd, 0L, SEEK_CUR) + + p->bufsize < 0) { + (void)lseek(p->fd, 0L, SEEK_SET); + goto again; + } + /* fall through */ +#endif + } + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s", + pcap_strerror(errno)); + return (PCAP_ERROR); + } + bp = p->buffer; + } else + bp = p->bp; + + /* + * Loop through each packet. + */ +#define bhp ((struct bpf_hdr *)bp) + ep = bp + cc; +#ifdef PCAP_FDDIPAD + pad = p->fddipad; +#endif + while (bp < ep) { + register int caplen, hdrlen; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return PCAP_ERROR_BREAK + * to indicate that we were told to break out of the loop, + * otherwise leave the flag set, so that the *next* call + * will break out of the loop without having read any + * packets, and return the number of packets we've + * processed so far. + */ + if (p->break_loop) { + p->bp = bp; + p->cc = ep - bp; + /* + * ep is set based on the return value of read(), + * but read() from a BPF device doesn't necessarily + * return a value that's a multiple of the alignment + * value for BPF_WORDALIGN(). However, whenever we + * increment bp, we round up the increment value by + * a value rounded up by BPF_WORDALIGN(), so we + * could increment bp past ep after processing the + * last packet in the buffer. + * + * We treat ep < bp as an indication that this + * happened, and just set p->cc to 0. + */ + if (p->cc < 0) + p->cc = 0; + if (n == 0) { + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } else + return (n); + } + + caplen = bhp->bh_caplen; + hdrlen = bhp->bh_hdrlen; + datap = bp + hdrlen; + /* + * Short-circuit evaluation: if using BPF filter + * in kernel, no need to do it now - we already know + * the packet passed the filter. + * +#ifdef PCAP_FDDIPAD + * Note: the filter code was generated assuming + * that p->fddipad was the amount of padding + * before the header, as that's what's required + * in the kernel, so we run the filter before + * skipping that padding. +#endif + */ + if (pb->filtering_in_kernel || + bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { + struct pcap_pkthdr pkthdr; + + pkthdr.ts.tv_sec = bhp->bh_tstamp.tv_sec; +#ifdef _AIX + /* + * AIX's BPF returns seconds/nanoseconds time + * stamps, not seconds/microseconds time stamps. + */ + pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec/1000; +#else + pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec; +#endif +#ifdef PCAP_FDDIPAD + if (caplen > pad) + pkthdr.caplen = caplen - pad; + else + pkthdr.caplen = 0; + if (bhp->bh_datalen > pad) + pkthdr.len = bhp->bh_datalen - pad; + else + pkthdr.len = 0; + datap += pad; +#else + pkthdr.caplen = caplen; + pkthdr.len = bhp->bh_datalen; +#endif + (*callback)(user, &pkthdr, datap); + bp += BPF_WORDALIGN(caplen + hdrlen); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + p->bp = bp; + p->cc = ep - bp; + /* + * See comment above about p->cc < 0. + */ + if (p->cc < 0) + p->cc = 0; + return (n); + } + } else { + /* + * Skip this packet. + */ + bp += BPF_WORDALIGN(caplen + hdrlen); + } + } +#undef bhp + p->cc = 0; + return (n); +} + +static int +pcap_inject_bpf(pcap_t *p, const void *buf, size_t size) +{ + int ret; + + ret = write(p->fd, buf, size); +#ifdef __APPLE__ + if (ret == -1 && errno == EAFNOSUPPORT) { + /* + * In Mac OS X, there's a bug wherein setting the + * BIOCSHDRCMPLT flag causes writes to fail; see, + * for example: + * + * http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/BIOCSHDRCMPLT-10.3.3.patch + * + * So, if, on OS X, we get EAFNOSUPPORT from the write, we + * assume it's due to that bug, and turn off that flag + * and try again. If we succeed, it either means that + * somebody applied the fix from that URL, or other patches + * for that bug from + * + * http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/ + * + * and are running a Darwin kernel with those fixes, or + * that Apple fixed the problem in some OS X release. + */ + u_int spoof_eth_src = 0; + + if (ioctl(p->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { + (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "send: can't turn off BIOCSHDRCMPLT: %s", + pcap_strerror(errno)); + return (PCAP_ERROR); + } + + /* + * Now try the write again. + */ + ret = write(p->fd, buf, size); + } +#endif /* __APPLE__ */ + if (ret == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", + pcap_strerror(errno)); + return (PCAP_ERROR); + } + return (ret); +} + +#ifdef _AIX +static int +bpf_odminit(char *errbuf) +{ + char *errstr; + + if (odm_initialize() == -1) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_initialize failed: %s", + errstr); + return (PCAP_ERROR); + } + + if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s", + errstr); + (void)odm_terminate(); + return (PCAP_ERROR); + } + + return (0); +} + +static int +bpf_odmcleanup(char *errbuf) +{ + char *errstr; + + if (odm_unlock(odmlockid) == -1) { + if (errbuf != NULL) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_unlock failed: %s", + errstr); + } + return (PCAP_ERROR); + } + + if (odm_terminate() == -1) { + if (errbuf != NULL) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_terminate failed: %s", + errstr); + } + return (PCAP_ERROR); + } + + return (0); +} + +static int +bpf_load(char *errbuf) +{ + long major; + int *minors; + int numminors, i, rc; + char buf[1024]; + struct stat sbuf; + struct bpf_config cfg_bpf; + struct cfg_load cfg_ld; + struct cfg_kmod cfg_km; + + /* + * This is very very close to what happens in the real implementation + * but I've fixed some (unlikely) bug situations. + */ + if (bpfloadedflag) + return (0); + + if (bpf_odminit(errbuf) == PCAP_ERROR) + return (PCAP_ERROR); + + major = genmajor(BPF_NAME); + if (major == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: genmajor failed: %s", pcap_strerror(errno)); + (void)bpf_odmcleanup(NULL); + return (PCAP_ERROR); + } + + minors = getminor(major, &numminors, BPF_NAME); + if (!minors) { + minors = genminor("bpf", major, 0, BPF_MINORS, 1, 1); + if (!minors) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: genminor failed: %s", + pcap_strerror(errno)); + (void)bpf_odmcleanup(NULL); + return (PCAP_ERROR); + } + } + + if (bpf_odmcleanup(errbuf) == PCAP_ERROR) + return (PCAP_ERROR); + + rc = stat(BPF_NODE "0", &sbuf); + if (rc == -1 && errno != ENOENT) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: can't stat %s: %s", + BPF_NODE "0", pcap_strerror(errno)); + return (PCAP_ERROR); + } + + if (rc == -1 || getmajor(sbuf.st_rdev) != major) { + for (i = 0; i < BPF_MINORS; i++) { + sprintf(buf, "%s%d", BPF_NODE, i); + unlink(buf); + if (mknod(buf, S_IRUSR | S_IFCHR, domakedev(major, i)) == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: can't mknod %s: %s", + buf, pcap_strerror(errno)); + return (PCAP_ERROR); + } + } + } + + /* Check if the driver is loaded */ + memset(&cfg_ld, 0x0, sizeof(cfg_ld)); + cfg_ld.path = buf; + sprintf(cfg_ld.path, "%s/%s", DRIVER_PATH, BPF_NAME); + if ((sysconfig(SYS_QUERYLOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) || + (cfg_ld.kmid == 0)) { + /* Driver isn't loaded, load it now */ + if (sysconfig(SYS_SINGLELOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: could not load driver: %s", + strerror(errno)); + return (PCAP_ERROR); + } + } + + /* Configure the driver */ + cfg_km.cmd = CFG_INIT; + cfg_km.kmid = cfg_ld.kmid; + cfg_km.mdilen = sizeof(cfg_bpf); + cfg_km.mdiptr = (void *)&cfg_bpf; + for (i = 0; i < BPF_MINORS; i++) { + cfg_bpf.devno = domakedev(major, i); + if (sysconfig(SYS_CFGKMOD, (void *)&cfg_km, sizeof(cfg_km)) == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: could not configure driver: %s", + strerror(errno)); + return (PCAP_ERROR); + } + } + + bpfloadedflag = 1; + + return (0); +} +#endif + +/* + * Turn off rfmon mode if necessary. + */ +static void +pcap_cleanup_bpf(pcap_t *p) +{ + struct pcap_bpf *pb = p->priv; +#ifdef HAVE_BSD_IEEE80211 + int sock; + struct ifmediareq req; + struct ifreq ifr; +#endif + + if (pb->must_do_on_close != 0) { + /* + * There's something we have to do when closing this + * pcap_t. + */ +#ifdef HAVE_BSD_IEEE80211 + if (pb->must_do_on_close & MUST_CLEAR_RFMON) { + /* + * We put the interface into rfmon mode; + * take it out of rfmon mode. + * + * XXX - if somebody else wants it in rfmon + * mode, this code cannot know that, so it'll take + * it out of rfmon mode. + */ + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + fprintf(stderr, + "Can't restore interface flags (socket() failed: %s).\n" + "Please adjust manually.\n", + strerror(errno)); + } else { + memset(&req, 0, sizeof(req)); + strncpy(req.ifm_name, pb->device, + sizeof(req.ifm_name)); + if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { + fprintf(stderr, + "Can't restore interface flags (SIOCGIFMEDIA failed: %s).\n" + "Please adjust manually.\n", + strerror(errno)); + } else { + if (req.ifm_current & IFM_IEEE80211_MONITOR) { + /* + * Rfmon mode is currently on; + * turn it off. + */ + memset(&ifr, 0, sizeof(ifr)); + (void)strncpy(ifr.ifr_name, + pb->device, + sizeof(ifr.ifr_name)); + ifr.ifr_media = + req.ifm_current & ~IFM_IEEE80211_MONITOR; + if (ioctl(sock, SIOCSIFMEDIA, + &ifr) == -1) { + fprintf(stderr, + "Can't restore interface flags (SIOCSIFMEDIA failed: %s).\n" + "Please adjust manually.\n", + strerror(errno)); + } + } + } + close(sock); + } + } +#endif /* HAVE_BSD_IEEE80211 */ + + /* + * Take this pcap out of the list of pcaps for which we + * have to take the interface out of some mode. + */ + pcap_remove_from_pcaps_to_close(p); + pb->must_do_on_close = 0; + } + +#ifdef HAVE_ZEROCOPY_BPF + if (pb->zerocopy) { + /* + * Delete the mappings. Note that p->buffer gets + * initialized to one of the mmapped regions in + * this case, so do not try and free it directly; + * null it out so that pcap_cleanup_live_common() + * doesn't try to free it. + */ + if (pb->zbuf1 != MAP_FAILED && pb->zbuf1 != NULL) + (void) munmap(pb->zbuf1, pb->zbufsize); + if (pb->zbuf2 != MAP_FAILED && pb->zbuf2 != NULL) + (void) munmap(pb->zbuf2, pb->zbufsize); + p->buffer = NULL; + } +#endif + if (pb->device != NULL) { + free(pb->device); + pb->device = NULL; + } + pcap_cleanup_live_common(p); +} + +static int +check_setif_failure(pcap_t *p, int error) +{ +#ifdef __APPLE__ + int fd; + struct ifreq ifr; + int err; +#endif + + if (error == ENXIO) { + /* + * No such device exists. + */ +#ifdef __APPLE__ + if (p->opt.rfmon && strncmp(p->opt.source, "wlt", 3) == 0) { + /* + * Monitor mode was requested, and we're trying + * to open a "wltN" device. Assume that this + * is 10.4 and that we were asked to open an + * "enN" device; if that device exists, return + * "monitor mode not supported on the device". + */ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd != -1) { + strlcpy(ifr.ifr_name, "en", + sizeof(ifr.ifr_name)); + strlcat(ifr.ifr_name, p->opt.source + 3, + sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { + /* + * We assume this failed because + * the underlying device doesn't + * exist. + */ + err = PCAP_ERROR_NO_SUCH_DEVICE; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFFLAGS on %s failed: %s", + ifr.ifr_name, pcap_strerror(errno)); + } else { + /* + * The underlying "enN" device + * exists, but there's no + * corresponding "wltN" device; + * that means that the "enN" + * device doesn't support + * monitor mode, probably because + * it's an Ethernet device rather + * than a wireless device. + */ + err = PCAP_ERROR_RFMON_NOTSUP; + } + close(fd); + } else { + /* + * We can't find out whether there's + * an underlying "enN" device, so + * just report "no such device". + */ + err = PCAP_ERROR_NO_SUCH_DEVICE; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "socket() failed: %s", + pcap_strerror(errno)); + } + return (err); + } +#endif + /* + * No such device. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF failed: %s", + pcap_strerror(errno)); + return (PCAP_ERROR_NO_SUCH_DEVICE); + } else if (errno == ENETDOWN) { + /* + * Return a "network down" indication, so that + * the application can report that rather than + * saying we had a mysterious failure and + * suggest that they report a problem to the + * libpcap developers. + */ + return (PCAP_ERROR_IFACE_NOT_UP); + } else { + /* + * Some other error; fill in the error string, and + * return PCAP_ERROR. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", + p->opt.source, pcap_strerror(errno)); + return (PCAP_ERROR); + } +} + +/* + * Default capture buffer size. + * 32K isn't very much for modern machines with fast networks; we + * pick .5M, as that's the maximum on at least some systems with BPF. + * + * However, on AIX 3.5, the larger buffer sized caused unrecoverable + * read failures under stress, so we leave it as 32K; yet another + * place where AIX's BPF is broken. + */ +#ifdef _AIX +#define DEFAULT_BUFSIZE 32768 +#else +#define DEFAULT_BUFSIZE 524288 +#endif + +static int +pcap_activate_bpf(pcap_t *p) +{ + struct pcap_bpf *pb = p->priv; + int status = 0; +#ifdef HAVE_BSD_IEEE80211 + int retv; +#endif + int fd; +#ifdef LIFNAMSIZ + char *zonesep; + struct lifreq ifr; + char *ifrname = ifr.lifr_name; + const size_t ifnamsiz = sizeof(ifr.lifr_name); +#else + struct ifreq ifr; + char *ifrname = ifr.ifr_name; + const size_t ifnamsiz = sizeof(ifr.ifr_name); +#endif + struct bpf_version bv; +#ifdef __APPLE__ + int sockfd; + char *wltdev = NULL; +#endif +#ifdef BIOCGDLTLIST + struct bpf_dltlist bdl; +#if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) + int new_dlt; +#endif +#endif /* BIOCGDLTLIST */ +#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) + u_int spoof_eth_src = 1; +#endif + u_int v; + struct bpf_insn total_insn; + struct bpf_program total_prog; + struct utsname osinfo; + int have_osinfo = 0; +#ifdef HAVE_ZEROCOPY_BPF + struct bpf_zbuf bz; + u_int bufmode, zbufmax; +#endif + + fd = bpf_open(p); + if (fd < 0) { + status = fd; + goto bad; + } + + p->fd = fd; + + if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + if (bv.bv_major != BPF_MAJOR_VERSION || + bv.bv_minor < BPF_MINOR_VERSION) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "kernel bpf filter out of date"); + status = PCAP_ERROR; + goto bad; + } + +#if defined(LIFNAMSIZ) && defined(ZONENAME_MAX) && defined(lifr_zoneid) + /* + * Retrieve the zoneid of the zone we are currently executing in. + */ + if ((ifr.lifr_zoneid = getzoneid()) == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "getzoneid(): %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + /* + * Check if the given source datalink name has a '/' separated + * zonename prefix string. The zonename prefixed source datalink can + * be used by pcap consumers in the Solaris global zone to capture + * traffic on datalinks in non-global zones. Non-global zones + * do not have access to datalinks outside of their own namespace. + */ + if ((zonesep = strchr(p->opt.source, '/')) != NULL) { + char path_zname[ZONENAME_MAX]; + int znamelen; + char *lnamep; + + if (ifr.lifr_zoneid != GLOBAL_ZONEID) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "zonename/linkname only valid in global zone."); + status = PCAP_ERROR; + goto bad; + } + znamelen = zonesep - p->opt.source; + (void) strlcpy(path_zname, p->opt.source, znamelen + 1); + ifr.lifr_zoneid = getzoneidbyname(path_zname); + if (ifr.lifr_zoneid == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "getzoneidbyname(%s): %s", path_zname, + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + lnamep = strdup(zonesep + 1); + free(p->opt.source); + p->opt.source = lnamep; + } +#endif + + pb->device = strdup(p->opt.source); + if (pb->device == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + + /* + * Attempt to find out the version of the OS on which we're running. + */ + if (uname(&osinfo) == 0) + have_osinfo = 1; + +#ifdef __APPLE__ + /* + * See comment in pcap_can_set_rfmon_bpf() for an explanation + * of why we check the version number. + */ + if (p->opt.rfmon) { + if (have_osinfo) { + /* + * We assume osinfo.sysname is "Darwin", because + * __APPLE__ is defined. We just check the version. + */ + if (osinfo.release[0] < '8' && + osinfo.release[1] == '.') { + /* + * 10.3 (Darwin 7.x) or earlier. + */ + status = PCAP_ERROR_RFMON_NOTSUP; + goto bad; + } + if (osinfo.release[0] == '8' && + osinfo.release[1] == '.') { + /* + * 10.4 (Darwin 8.x). s/en/wlt/ + */ + if (strncmp(p->opt.source, "en", 2) != 0) { + /* + * Not an enN device; check + * whether the device even exists. + */ + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd != -1) { + strlcpy(ifrname, + p->opt.source, ifnamsiz); + if (ioctl(sockfd, SIOCGIFFLAGS, + (char *)&ifr) < 0) { + /* + * We assume this + * failed because + * the underlying + * device doesn't + * exist. + */ + status = PCAP_ERROR_NO_SUCH_DEVICE; + snprintf(p->errbuf, + PCAP_ERRBUF_SIZE, + "SIOCGIFFLAGS failed: %s", + pcap_strerror(errno)); + } else + status = PCAP_ERROR_RFMON_NOTSUP; + close(sockfd); + } else { + /* + * We can't find out whether + * the device exists, so just + * report "no such device". + */ + status = PCAP_ERROR_NO_SUCH_DEVICE; + snprintf(p->errbuf, + PCAP_ERRBUF_SIZE, + "socket() failed: %s", + pcap_strerror(errno)); + } + goto bad; + } + wltdev = malloc(strlen(p->opt.source) + 2); + if (wltdev == NULL) { + (void)snprintf(p->errbuf, + PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + strcpy(wltdev, "wlt"); + strcat(wltdev, p->opt.source + 2); + free(p->opt.source); + p->opt.source = wltdev; + } + /* + * Everything else is 10.5 or later; for those, + * we just open the enN device, and set the DLT. + */ + } + } +#endif /* __APPLE__ */ +#ifdef HAVE_ZEROCOPY_BPF + /* + * If the BPF extension to set buffer mode is present, try setting + * the mode to zero-copy. If that fails, use regular buffering. If + * it succeeds but other setup fails, return an error to the user. + */ + bufmode = BPF_BUFMODE_ZBUF; + if (ioctl(fd, BIOCSETBUFMODE, (caddr_t)&bufmode) == 0) { + /* + * We have zerocopy BPF; use it. + */ + pb->zerocopy = 1; + + /* + * How to pick a buffer size: first, query the maximum buffer + * size supported by zero-copy. This also lets us quickly + * determine whether the kernel generally supports zero-copy. + * Then, if a buffer size was specified, use that, otherwise + * query the default buffer size, which reflects kernel + * policy for a desired default. Round to the nearest page + * size. + */ + if (ioctl(fd, BIOCGETZMAX, (caddr_t)&zbufmax) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGETZMAX: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + + if (p->opt.buffer_size != 0) { + /* + * A buffer size was explicitly specified; use it. + */ + v = p->opt.buffer_size; + } else { + if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || + v < DEFAULT_BUFSIZE) + v = DEFAULT_BUFSIZE; + } +#ifndef roundup +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ +#endif + pb->zbufsize = roundup(v, getpagesize()); + if (pb->zbufsize > zbufmax) + pb->zbufsize = zbufmax; + pb->zbuf1 = mmap(NULL, pb->zbufsize, PROT_READ | PROT_WRITE, + MAP_ANON, -1, 0); + pb->zbuf2 = mmap(NULL, pb->zbufsize, PROT_READ | PROT_WRITE, + MAP_ANON, -1, 0); + if (pb->zbuf1 == MAP_FAILED || pb->zbuf2 == MAP_FAILED) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "mmap: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + memset(&bz, 0, sizeof(bz)); /* bzero() deprecated, replaced with memset() */ + bz.bz_bufa = pb->zbuf1; + bz.bz_bufb = pb->zbuf2; + bz.bz_buflen = pb->zbufsize; + if (ioctl(fd, BIOCSETZBUF, (caddr_t)&bz) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETZBUF: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + (void)strncpy(ifrname, p->opt.source, ifnamsiz); + if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", + p->opt.source, pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + v = pb->zbufsize - sizeof(struct bpf_zbuf_header); + } else +#endif + { + /* + * We don't have zerocopy BPF. + * Set the buffer size. + */ + if (p->opt.buffer_size != 0) { + /* + * A buffer size was explicitly specified; use it. + */ + if (ioctl(fd, BIOCSBLEN, + (caddr_t)&p->opt.buffer_size) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCSBLEN: %s: %s", p->opt.source, + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + + /* + * Now bind to the device. + */ + (void)strncpy(ifrname, p->opt.source, ifnamsiz); +#ifdef BIOCSETLIF + if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) < 0) +#else + if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) +#endif + { + status = check_setif_failure(p, errno); + goto bad; + } + } else { + /* + * No buffer size was explicitly specified. + * + * Try finding a good size for the buffer; + * DEFAULT_BUFSIZE may be too big, so keep + * cutting it in half until we find a size + * that works, or run out of sizes to try. + * If the default is larger, don't make it smaller. + */ + if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || + v < DEFAULT_BUFSIZE) + v = DEFAULT_BUFSIZE; + for ( ; v != 0; v >>= 1) { + /* + * Ignore the return value - this is because the + * call fails on BPF systems that don't have + * kernel malloc. And if the call fails, it's + * no big deal, we just continue to use the + * standard buffer size. + */ + (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v); + + (void)strncpy(ifrname, p->opt.source, ifnamsiz); +#ifdef BIOCSETLIF + if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) >= 0) +#else + if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0) +#endif + break; /* that size worked; we're done */ + + if (errno != ENOBUFS) { + status = check_setif_failure(p, errno); + goto bad; + } + } + + if (v == 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCSBLEN: %s: No buffer size worked", + p->opt.source); + status = PCAP_ERROR; + goto bad; + } + } + } + + /* Get the data link layer type. */ + if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + +#ifdef _AIX + /* + * AIX's BPF returns IFF_ types, not DLT_ types, in BIOCGDLT. + */ + switch (v) { + + case IFT_ETHER: + case IFT_ISO88023: + v = DLT_EN10MB; + break; + + case IFT_FDDI: + v = DLT_FDDI; + break; + + case IFT_ISO88025: + v = DLT_IEEE802; + break; + + case IFT_LOOP: + v = DLT_NULL; + break; + + default: + /* + * We don't know what to map this to yet. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u", + v); + status = PCAP_ERROR; + goto bad; + } +#endif +#if _BSDI_VERSION - 0 >= 199510 + /* The SLIP and PPP link layer header changed in BSD/OS 2.1 */ + switch (v) { + + case DLT_SLIP: + v = DLT_SLIP_BSDOS; + break; + + case DLT_PPP: + v = DLT_PPP_BSDOS; + break; + + case 11: /*DLT_FR*/ + v = DLT_FRELAY; + break; + + case 12: /*DLT_C_HDLC*/ + v = DLT_CHDLC; + break; + } +#endif + +#ifdef BIOCGDLTLIST + /* + * We know the default link type -- now determine all the DLTs + * this interface supports. If this fails with EINVAL, it's + * not fatal; we just don't get to use the feature later. + */ + if (get_dlt_list(fd, v, &bdl, p->errbuf) == -1) { + status = PCAP_ERROR; + goto bad; + } + p->dlt_count = bdl.bfl_len; + p->dlt_list = bdl.bfl_list; + +#ifdef __APPLE__ + /* + * Monitor mode fun, continued. + * + * For 10.5 and, we're assuming, later releases, as noted above, + * 802.1 adapters that support monitor mode offer both DLT_EN10MB, + * DLT_IEEE802_11, and possibly some 802.11-plus-radio-information + * DLT_ value. Choosing one of the 802.11 DLT_ values will turn + * monitor mode on. + * + * Therefore, if the user asked for monitor mode, we filter out + * the DLT_EN10MB value, as you can't get that in monitor mode, + * and, if the user didn't ask for monitor mode, we filter out + * the 802.11 DLT_ values, because selecting those will turn + * monitor mode on. Then, for monitor mode, if an 802.11-plus- + * radio DLT_ value is offered, we try to select that, otherwise + * we try to select DLT_IEEE802_11. + */ + if (have_osinfo) { + if (isdigit((unsigned)osinfo.release[0]) && + (osinfo.release[0] == '9' || + isdigit((unsigned)osinfo.release[1]))) { + /* + * 10.5 (Darwin 9.x), or later. + */ + new_dlt = find_802_11(&bdl); + if (new_dlt != -1) { + /* + * We have at least one 802.11 DLT_ value, + * so this is an 802.11 interface. + * new_dlt is the best of the 802.11 + * DLT_ values in the list. + */ + if (p->opt.rfmon) { + /* + * Our caller wants monitor mode. + * Purge DLT_EN10MB from the list + * of link-layer types, as selecting + * it will keep monitor mode off. + */ + remove_en(p); + + /* + * If the new mode we want isn't + * the default mode, attempt to + * select the new mode. + */ + if (new_dlt != v) { + if (ioctl(p->fd, BIOCSDLT, + &new_dlt) != -1) { + /* + * We succeeded; + * make this the + * new DLT_ value. + */ + v = new_dlt; + } + } + } else { + /* + * Our caller doesn't want + * monitor mode. Unless this + * is being done by pcap_open_live(), + * purge the 802.11 link-layer types + * from the list, as selecting + * one of them will turn monitor + * mode on. + */ + if (!p->oldstyle) + remove_802_11(p); + } + } else { + if (p->opt.rfmon) { + /* + * The caller requested monitor + * mode, but we have no 802.11 + * link-layer types, so they + * can't have it. + */ + status = PCAP_ERROR_RFMON_NOTSUP; + goto bad; + } + } + } + } +#elif defined(HAVE_BSD_IEEE80211) + /* + * *BSD with the new 802.11 ioctls. + * Do we want monitor mode? + */ + if (p->opt.rfmon) { + /* + * Try to put the interface into monitor mode. + */ + retv = monitor_mode(p, 1); + if (retv != 0) { + /* + * We failed. + */ + status = retv; + goto bad; + } + + /* + * We're in monitor mode. + * Try to find the best 802.11 DLT_ value and, if we + * succeed, try to switch to that mode if we're not + * already in that mode. + */ + new_dlt = find_802_11(&bdl); + if (new_dlt != -1) { + /* + * We have at least one 802.11 DLT_ value. + * new_dlt is the best of the 802.11 + * DLT_ values in the list. + * + * If the new mode we want isn't the default mode, + * attempt to select the new mode. + */ + if (new_dlt != v) { + if (ioctl(p->fd, BIOCSDLT, &new_dlt) != -1) { + /* + * We succeeded; make this the + * new DLT_ value. + */ + v = new_dlt; + } + } + } + } +#endif /* various platforms */ +#endif /* BIOCGDLTLIST */ + + /* + * If this is an Ethernet device, and we don't have a DLT_ list, + * give it a list with DLT_EN10MB and DLT_DOCSIS. (That'd give + * 802.11 interfaces DLT_DOCSIS, which isn't the right thing to + * do, but there's not much we can do about that without finding + * some other way of determining whether it's an Ethernet or 802.11 + * device.) + */ + if (v == DLT_EN10MB && p->dlt_count == 0) { + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (p->dlt_list != NULL) { + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + } + } +#ifdef PCAP_FDDIPAD + if (v == DLT_FDDI) + p->fddipad = PCAP_FDDIPAD; + else +#endif + p->fddipad = 0; + p->linktype = v; + +#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) + /* + * Do a BIOCSHDRCMPLT, if defined, to turn that flag on, so + * the link-layer source address isn't forcibly overwritten. + * (Should we ignore errors? Should we do this only if + * we're open for writing?) + * + * XXX - I seem to remember some packet-sending bug in some + * BSDs - check CVS log for "bpf.c"? + */ + if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { + (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCSHDRCMPLT: %s", pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } +#endif + /* set timeout */ +#ifdef HAVE_ZEROCOPY_BPF + /* + * In zero-copy mode, we just use the timeout in select(). + * XXX - what if we're in non-blocking mode and the *application* + * is using select() or poll() or kqueues or....? + */ + if (p->opt.timeout && !pb->zerocopy) { +#else + if (p->opt.timeout) { +#endif + /* + * XXX - is this seconds/nanoseconds in AIX? + * (Treating it as such doesn't fix the timeout + * problem described below.) + * + * XXX - Mac OS X 10.6 mishandles BIOCSRTIMEOUT in + * 64-bit userland - it takes, as an argument, a + * "struct BPF_TIMEVAL", which has 32-bit tv_sec + * and tv_usec, rather than a "struct timeval". + * + * If this platform defines "struct BPF_TIMEVAL", + * we check whether the structure size in BIOCSRTIMEOUT + * is that of a "struct timeval" and, if not, we use + * a "struct BPF_TIMEVAL" rather than a "struct timeval". + * (That way, if the bug is fixed in a future release, + * we will still do the right thing.) + */ + struct timeval to; +#ifdef HAVE_STRUCT_BPF_TIMEVAL + struct BPF_TIMEVAL bpf_to; + + if (IOCPARM_LEN(BIOCSRTIMEOUT) != sizeof(struct timeval)) { + bpf_to.tv_sec = p->opt.timeout / 1000; + bpf_to.tv_usec = (p->opt.timeout * 1000) % 1000000; + if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&bpf_to) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + } else { +#endif + to.tv_sec = p->opt.timeout / 1000; + to.tv_usec = (p->opt.timeout * 1000) % 1000000; + if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } +#ifdef HAVE_STRUCT_BPF_TIMEVAL + } +#endif + } + +#ifdef BIOCIMMEDIATE + /* + * Darren Reed notes that + * + * On AIX (4.2 at least), if BIOCIMMEDIATE is not set, the + * timeout appears to be ignored and it waits until the buffer + * is filled before returning. The result of not having it + * set is almost worse than useless if your BPF filter + * is reducing things to only a few packets (i.e. one every + * second or so). + * + * so we always turn BIOCIMMEDIATE mode on if this is AIX. + * + * For other platforms, we don't turn immediate mode on by default, + * as that would mean we get woken up for every packet, which + * probably isn't what you want for a packet sniffer. + * + * We set immediate mode if the caller requested it by calling + * pcap_set_immediate() before calling pcap_activate(). + */ +#ifndef _AIX + if (p->opt.immediate) { +#endif /* _AIX */ + v = 1; + if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCIMMEDIATE: %s", pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } +#ifndef _AIX + } +#endif /* _AIX */ +#else /* BIOCIMMEDIATE */ + if (p->opt.immediate) { + /* + * We don't support immediate mode. Fail. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Immediate mode not supported"); + status = PCAP_ERROR; + goto bad; + } +#endif /* BIOCIMMEDIATE */ + + if (p->opt.promisc) { + /* set promiscuous mode, just warn if it fails */ + if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s", + pcap_strerror(errno)); + status = PCAP_WARNING_PROMISC_NOTSUP; + } + } + + if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + p->bufsize = v; +#ifdef HAVE_ZEROCOPY_BPF + if (!pb->zerocopy) { +#endif + p->buffer = (u_char *)malloc(p->bufsize); + if (p->buffer == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } +#ifdef _AIX + /* For some strange reason this seems to prevent the EFAULT + * problems we have experienced from AIX BPF. */ + memset(p->buffer, 0x0, p->bufsize); +#endif +#ifdef HAVE_ZEROCOPY_BPF + } +#endif + + /* + * If there's no filter program installed, there's + * no indication to the kernel of what the snapshot + * length should be, so no snapshotting is done. + * + * Therefore, when we open the device, we install + * an "accept everything" filter with the specified + * snapshot length. + */ + total_insn.code = (u_short)(BPF_RET | BPF_K); + total_insn.jt = 0; + total_insn.jf = 0; + total_insn.k = p->snapshot; + + total_prog.bf_len = 1; + total_prog.bf_insns = &total_insn; + if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + + /* + * On most BPF platforms, either you can do a "select()" or + * "poll()" on a BPF file descriptor and it works correctly, + * or you can do it and it will return "readable" if the + * hold buffer is full but not if the timeout expires *and* + * a non-blocking read will, if the hold buffer is empty + * but the store buffer isn't empty, rotate the buffers + * and return what packets are available. + * + * In the latter case, the fact that a non-blocking read + * will give you the available packets means you can work + * around the failure of "select()" and "poll()" to wake up + * and return "readable" when the timeout expires by using + * the timeout as the "select()" or "poll()" timeout, putting + * the BPF descriptor into non-blocking mode, and read from + * it regardless of whether "select()" reports it as readable + * or not. + * + * However, in FreeBSD 4.3 and 4.4, "select()" and "poll()" + * won't wake up and return "readable" if the timer expires + * and non-blocking reads return EWOULDBLOCK if the hold + * buffer is empty, even if the store buffer is non-empty. + * + * This means the workaround in question won't work. + * + * Therefore, on FreeBSD 4.3 and 4.4, we set "p->selectable_fd" + * to -1, which means "sorry, you can't use 'select()' or 'poll()' + * here". On all other BPF platforms, we set it to the FD for + * the BPF device; in NetBSD, OpenBSD, and Darwin, a non-blocking + * read will, if the hold buffer is empty and the store buffer + * isn't empty, rotate the buffers and return what packets are + * there (and in sufficiently recent versions of OpenBSD + * "select()" and "poll()" should work correctly). + * + * XXX - what about AIX? + */ + p->selectable_fd = p->fd; /* assume select() works until we know otherwise */ + if (have_osinfo) { + /* + * We can check what OS this is. + */ + if (strcmp(osinfo.sysname, "FreeBSD") == 0) { + if (strncmp(osinfo.release, "4.3-", 4) == 0 || + strncmp(osinfo.release, "4.4-", 4) == 0) + p->selectable_fd = -1; + } + } + + p->read_op = pcap_read_bpf; + p->inject_op = pcap_inject_bpf; + p->setfilter_op = pcap_setfilter_bpf; + p->setdirection_op = pcap_setdirection_bpf; + p->set_datalink_op = pcap_set_datalink_bpf; + p->getnonblock_op = pcap_getnonblock_bpf; + p->setnonblock_op = pcap_setnonblock_bpf; + p->stats_op = pcap_stats_bpf; + p->cleanup_op = pcap_cleanup_bpf; + + return (status); + bad: + pcap_cleanup_bpf(p); + return (status); +} + +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + return (0); +} + +#ifdef HAVE_BSD_IEEE80211 +static int +monitor_mode(pcap_t *p, int set) +{ + struct pcap_bpf *pb = p->priv; + int sock; + struct ifmediareq req; + int *media_list; + int i; + int can_do; + struct ifreq ifr; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't open socket: %s", + pcap_strerror(errno)); + return (PCAP_ERROR); + } + + memset(&req, 0, sizeof req); + strncpy(req.ifm_name, p->opt.source, sizeof req.ifm_name); + + /* + * Find out how many media types we have. + */ + if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { + /* + * Can't get the media types. + */ + switch (errno) { + + case ENXIO: + /* + * There's no such device. + */ + close(sock); + return (PCAP_ERROR_NO_SUCH_DEVICE); + + case EINVAL: + /* + * Interface doesn't support SIOC{G,S}IFMEDIA. + */ + close(sock); + return (PCAP_ERROR_RFMON_NOTSUP); + + default: + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFMEDIA 1: %s", pcap_strerror(errno)); + close(sock); + return (PCAP_ERROR); + } + } + if (req.ifm_count == 0) { + /* + * No media types. + */ + close(sock); + return (PCAP_ERROR_RFMON_NOTSUP); + } + + /* + * Allocate a buffer to hold all the media types, and + * get the media types. + */ + media_list = malloc(req.ifm_count * sizeof(int)); + if (media_list == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + close(sock); + return (PCAP_ERROR); + } + req.ifm_ulist = media_list; + if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA: %s", + pcap_strerror(errno)); + free(media_list); + close(sock); + return (PCAP_ERROR); + } + + /* + * Look for an 802.11 "automatic" media type. + * We assume that all 802.11 adapters have that media type, + * and that it will carry the monitor mode supported flag. + */ + can_do = 0; + for (i = 0; i < req.ifm_count; i++) { + if (IFM_TYPE(media_list[i]) == IFM_IEEE80211 + && IFM_SUBTYPE(media_list[i]) == IFM_AUTO) { + /* OK, does it do monitor mode? */ + if (media_list[i] & IFM_IEEE80211_MONITOR) { + can_do = 1; + break; + } + } + } + free(media_list); + if (!can_do) { + /* + * This adapter doesn't support monitor mode. + */ + close(sock); + return (PCAP_ERROR_RFMON_NOTSUP); + } + + if (set) { + /* + * Don't just check whether we can enable monitor mode, + * do so, if it's not already enabled. + */ + if ((req.ifm_current & IFM_IEEE80211_MONITOR) == 0) { + /* + * Monitor mode isn't currently on, so turn it on, + * and remember that we should turn it off when the + * pcap_t is closed. + */ + + /* + * If we haven't already done so, arrange to have + * "pcap_close_all()" called when we exit. + */ + if (!pcap_do_addexit(p)) { + /* + * "atexit()" failed; don't put the interface + * in monitor mode, just give up. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "atexit failed"); + close(sock); + return (PCAP_ERROR); + } + memset(&ifr, 0, sizeof(ifr)); + (void)strncpy(ifr.ifr_name, p->opt.source, + sizeof(ifr.ifr_name)); + ifr.ifr_media = req.ifm_current | IFM_IEEE80211_MONITOR; + if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "SIOCSIFMEDIA: %s", pcap_strerror(errno)); + close(sock); + return (PCAP_ERROR); + } + + pb->must_do_on_close |= MUST_CLEAR_RFMON; + + /* + * Add this to the list of pcaps to close when we exit. + */ + pcap_add_to_pcaps_to_close(p); + } + } + return (0); +} +#endif /* HAVE_BSD_IEEE80211 */ + +#if defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)) +/* + * Check whether we have any 802.11 link-layer types; return the best + * of the 802.11 link-layer types if we find one, and return -1 + * otherwise. + * + * DLT_IEEE802_11_RADIO, with the radiotap header, is considered the + * best 802.11 link-layer type; any of the other 802.11-plus-radio + * headers are second-best; 802.11 with no radio information is + * the least good. + */ +static int +find_802_11(struct bpf_dltlist *bdlp) +{ + int new_dlt; + int i; + + /* + * Scan the list of DLT_ values, looking for 802.11 values, + * and, if we find any, choose the best of them. + */ + new_dlt = -1; + for (i = 0; i < bdlp->bfl_len; i++) { + switch (bdlp->bfl_list[i]) { + + case DLT_IEEE802_11: + /* + * 802.11, but no radio. + * + * Offer this, and select it as the new mode + * unless we've already found an 802.11 + * header with radio information. + */ + if (new_dlt == -1) + new_dlt = bdlp->bfl_list[i]; + break; + + case DLT_PRISM_HEADER: + case DLT_AIRONET_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + /* + * 802.11 with radio, but not radiotap. + * + * Offer this, and select it as the new mode + * unless we've already found the radiotap DLT_. + */ + if (new_dlt != DLT_IEEE802_11_RADIO) + new_dlt = bdlp->bfl_list[i]; + break; + + case DLT_IEEE802_11_RADIO: + /* + * 802.11 with radiotap. + * + * Offer this, and select it as the new mode. + */ + new_dlt = bdlp->bfl_list[i]; + break; + + default: + /* + * Not 802.11. + */ + break; + } + } + + return (new_dlt); +} +#endif /* defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)) */ + +#if defined(__APPLE__) && defined(BIOCGDLTLIST) +/* + * Remove DLT_EN10MB from the list of DLT_ values, as we're in monitor mode, + * and DLT_EN10MB isn't supported in monitor mode. + */ +static void +remove_en(pcap_t *p) +{ + int i, j; + + /* + * Scan the list of DLT_ values and discard DLT_EN10MB. + */ + j = 0; + for (i = 0; i < p->dlt_count; i++) { + switch (p->dlt_list[i]) { + + case DLT_EN10MB: + /* + * Don't offer this one. + */ + continue; + + default: + /* + * Just copy this mode over. + */ + break; + } + + /* + * Copy this DLT_ value to its new position. + */ + p->dlt_list[j] = p->dlt_list[i]; + j++; + } + + /* + * Set the DLT_ count to the number of entries we copied. + */ + p->dlt_count = j; +} + +/* + * Remove 802.11 link-layer types from the list of DLT_ values, as + * we're not in monitor mode, and those DLT_ values will switch us + * to monitor mode. + */ +static void +remove_802_11(pcap_t *p) +{ + int i, j; + + /* + * Scan the list of DLT_ values and discard 802.11 values. + */ + j = 0; + for (i = 0; i < p->dlt_count; i++) { + switch (p->dlt_list[i]) { + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_AIRONET_HEADER: + case DLT_IEEE802_11_RADIO: + case DLT_IEEE802_11_RADIO_AVS: + /* + * 802.11. Don't offer this one. + */ + continue; + + default: + /* + * Just copy this mode over. + */ + break; + } + + /* + * Copy this DLT_ value to its new position. + */ + p->dlt_list[j] = p->dlt_list[i]; + j++; + } + + /* + * Set the DLT_ count to the number of entries we copied. + */ + p->dlt_count = j; +} +#endif /* defined(__APPLE__) && defined(BIOCGDLTLIST) */ + +static int +pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) +{ + struct pcap_bpf *pb = p->priv; + + /* + * Free any user-mode filter we might happen to have installed. + */ + pcap_freecode(&p->fcode); + + /* + * Try to install the kernel filter. + */ + if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) == 0) { + /* + * It worked. + */ + pb->filtering_in_kernel = 1; /* filtering in the kernel */ + + /* + * Discard any previously-received packets, as they might + * have passed whatever filter was formerly in effect, but + * might not pass this filter (BIOCSETF discards packets + * buffered in the kernel, so you can lose packets in any + * case). + */ + p->cc = 0; + return (0); + } + + /* + * We failed. + * + * If it failed with EINVAL, that's probably because the program + * is invalid or too big. Validate it ourselves; if we like it + * (we currently allow backward branches, to support protochain), + * run it in userland. (There's no notion of "too big" for + * userland.) + * + * Otherwise, just give up. + * XXX - if the copy of the program into the kernel failed, + * we will get EINVAL rather than, say, EFAULT on at least + * some kernels. + */ + if (errno != EINVAL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", + pcap_strerror(errno)); + return (-1); + } + + /* + * install_bpf_program() validates the program. + * + * XXX - what if we already have a filter in the kernel? + */ + if (install_bpf_program(p, fp) < 0) + return (-1); + pb->filtering_in_kernel = 0; /* filtering in userland */ + return (0); +} + +/* + * Set direction flag: Which packets do we accept on a forwarding + * single device? IN, OUT or both? + */ +static int +pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) +{ +#if defined(BIOCSDIRECTION) + u_int direction; + + direction = (d == PCAP_D_IN) ? BPF_D_IN : + ((d == PCAP_D_OUT) ? BPF_D_OUT : BPF_D_INOUT); + if (ioctl(p->fd, BIOCSDIRECTION, &direction) == -1) { + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "Cannot set direction to %s: %s", + (d == PCAP_D_IN) ? "PCAP_D_IN" : + ((d == PCAP_D_OUT) ? "PCAP_D_OUT" : "PCAP_D_INOUT"), + strerror(errno)); + return (-1); + } + return (0); +#elif defined(BIOCSSEESENT) + u_int seesent; + + /* + * We don't support PCAP_D_OUT. + */ + if (d == PCAP_D_OUT) { + snprintf(p->errbuf, sizeof(p->errbuf), + "Setting direction to PCAP_D_OUT is not supported on BPF"); + return -1; + } + + seesent = (d == PCAP_D_INOUT); + if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) { + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "Cannot set direction to %s: %s", + (d == PCAP_D_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_IN", + strerror(errno)); + return (-1); + } + return (0); +#else + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "This system doesn't support BIOCSSEESENT, so the direction can't be set"); + return (-1); +#endif +} + +static int +pcap_set_datalink_bpf(pcap_t *p, int dlt) +{ +#ifdef BIOCSDLT + if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) { + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "Cannot set DLT %d: %s", dlt, strerror(errno)); + return (-1); + } +#endif + return (0); +} diff --git a/tcpdump/jni/libpcap/pcap-bpf.h b/tcpdump/jni/libpcap/pcap-bpf.h new file mode 100644 index 0000000..ebb64c3 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-bpf.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/tcpdump/jni/libpcap/pcap-bt-linux.c b/tcpdump/jni/libpcap/pcap-bt-linux.c new file mode 100644 index 0000000..56df687 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-bt-linux.c @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Bluetooth sniffing API implementation for Linux platform + * By Paolo Abeni + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pcap-int.h" +#include "pcap-bt-linux.h" +#include "pcap/bluetooth.h" + +#ifdef NEED_STRERROR_H +#include "strerror.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define BT_IFACE "bluetooth" +#define BT_CTRL_SIZE 128 + +/* forward declaration */ +static int bt_activate(pcap_t *); +static int bt_read_linux(pcap_t *, int , pcap_handler , u_char *); +static int bt_inject_linux(pcap_t *, const void *, size_t); +static int bt_setdirection_linux(pcap_t *, pcap_direction_t); +static int bt_stats_linux(pcap_t *, struct pcap_stat *); + +/* + * Private data for capturing on Linux Bluetooth devices. + */ +struct pcap_bt { + int dev_id; /* device ID of device we're bound to */ +}; + +int +bt_findalldevs(pcap_if_t **alldevsp, char *err_str) +{ + struct hci_dev_list_req *dev_list; + struct hci_dev_req *dev_req; + int i, sock; + int ret = 0; + + sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (sock < 0) + { + /* if bluetooth is not supported this this is not fatal*/ + if (errno == EAFNOSUPPORT) + return 0; + snprintf(err_str, PCAP_ERRBUF_SIZE, + "Can't open raw Bluetooth socket: %s", strerror(errno)); + return -1; + } + + dev_list = malloc(HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); + if (!dev_list) + { + snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't allocate %zu bytes for Bluetooth device list", + HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); + ret = -1; + goto done; + } + + dev_list->dev_num = HCI_MAX_DEV; + + if (ioctl(sock, HCIGETDEVLIST, (void *) dev_list) < 0) + { + snprintf(err_str, PCAP_ERRBUF_SIZE, + "Can't get Bluetooth device list via ioctl: %s", + strerror(errno)); + ret = -1; + goto free; + } + + dev_req = dev_list->dev_req; + for (i = 0; i < dev_list->dev_num; i++, dev_req++) { + char dev_name[20], dev_descr[30]; + + snprintf(dev_name, 20, BT_IFACE"%d", dev_req->dev_id); + snprintf(dev_descr, 30, "Bluetooth adapter number %d", i); + + if (pcap_add_if(alldevsp, dev_name, 0, + dev_descr, err_str) < 0) + { + ret = -1; + break; + } + + } + +free: + free(dev_list); + +done: + close(sock); + return ret; +} + +pcap_t * +bt_create(const char *device, char *ebuf, int *is_ours) +{ + const char *cp; + char *cpend; + long devnum; + pcap_t *p; + + /* Does this look like a Bluetooth device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + /* Does it begin with BT_IFACE? */ + if (strncmp(cp, BT_IFACE, sizeof BT_IFACE - 1) != 0) { + /* Nope, doesn't begin with BT_IFACE */ + *is_ours = 0; + return NULL; + } + /* Yes - is BT_IFACE followed by a number? */ + cp += sizeof BT_IFACE - 1; + devnum = strtol(cp, &cpend, 10); + if (cpend == cp || *cpend != '\0') { + /* Not followed by a number. */ + *is_ours = 0; + return NULL; + } + if (devnum < 0) { + /* Followed by a non-valid number. */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_bt)); + if (p == NULL) + return (NULL); + + p->activate_op = bt_activate; + return (p); +} + +static int +bt_activate(pcap_t* handle) +{ + struct pcap_bt *handlep = handle->priv; + struct sockaddr_hci addr; + int opt; + int dev_id; + struct hci_filter flt; + int err = PCAP_ERROR; + + /* get bt interface id */ + if (sscanf(handle->opt.source, BT_IFACE"%d", &dev_id) != 1) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't get Bluetooth device index from %s", + handle->opt.source); + return PCAP_ERROR; + } + + /* Initialize some components of the pcap structure. */ + handle->bufsize = handle->snapshot+BT_CTRL_SIZE+sizeof(pcap_bluetooth_h4_header); + handle->offset = BT_CTRL_SIZE; + handle->linktype = DLT_BLUETOOTH_HCI_H4_WITH_PHDR; + + handle->read_op = bt_read_linux; + handle->inject_op = bt_inject_linux; + handle->setfilter_op = install_bpf_program; /* no kernel filtering */ + handle->setdirection_op = bt_setdirection_linux; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->stats_op = bt_stats_linux; + handlep->dev_id = dev_id; + + /* Create HCI socket */ + handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (handle->fd < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't create raw socket: %s", strerror(errno)); + return PCAP_ERROR; + } + + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", + pcap_strerror(errno)); + goto close_fail; + } + + opt = 1; + if (setsockopt(handle->fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't enable data direction info: %s", strerror(errno)); + goto close_fail; + } + + opt = 1; + if (setsockopt(handle->fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't enable time stamp: %s", strerror(errno)); + goto close_fail; + } + + /* Setup filter, do not call hci function to avoid dependence on + * external libs */ + memset(&flt, 0, sizeof(flt)); + memset((void *) &flt.type_mask, 0xff, sizeof(flt.type_mask)); + memset((void *) &flt.event_mask, 0xff, sizeof(flt.event_mask)); + if (setsockopt(handle->fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't set filter: %s", strerror(errno)); + goto close_fail; + } + + + /* Bind socket to the HCI device */ + addr.hci_family = AF_BLUETOOTH; + addr.hci_dev = handlep->dev_id; +#ifdef SOCKADDR_HCI_HAS_HCI_CHANNEL + addr.hci_channel = HCI_CHANNEL_RAW; +#endif + if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't attach to device %d: %s", handlep->dev_id, + strerror(errno)); + goto close_fail; + } + + if (handle->opt.rfmon) { + /* + * Monitor mode doesn't apply to Bluetooth devices. + */ + err = PCAP_ERROR_RFMON_NOTSUP; + goto close_fail; + } + + if (handle->opt.buffer_size != 0) { + /* + * Set the socket buffer size to the specified value. + */ + if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, + &handle->opt.buffer_size, + sizeof(handle->opt.buffer_size)) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "SO_RCVBUF: %s", pcap_strerror(errno)); + goto close_fail; + } + } + + handle->selectable_fd = handle->fd; + return 0; + +close_fail: + pcap_cleanup_live_common(handle); + return err; +} + +static int +bt_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + struct cmsghdr *cmsg; + struct msghdr msg; + struct iovec iv; + ssize_t ret; + struct pcap_pkthdr pkth; + pcap_bluetooth_h4_header* bthdr; + + bthdr = (pcap_bluetooth_h4_header*) &handle->buffer[handle->offset]; + iv.iov_base = &handle->buffer[handle->offset+sizeof(pcap_bluetooth_h4_header)]; + iv.iov_len = handle->snapshot; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iv; + msg.msg_iovlen = 1; + msg.msg_control = handle->buffer; + msg.msg_controllen = handle->offset; + + /* ignore interrupt system call error */ + do { + ret = recvmsg(handle->fd, &msg, 0); + if (handle->break_loop) + { + handle->break_loop = 0; + return -2; + } + } while ((ret == -1) && (errno == EINTR)); + + if (ret < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't receive packet: %s", strerror(errno)); + return -1; + } + + pkth.caplen = ret; + + /* get direction and timestamp*/ + cmsg = CMSG_FIRSTHDR(&msg); + int in=0; + while (cmsg) { + switch (cmsg->cmsg_type) { + case HCI_CMSG_DIR: + memcpy(&in, CMSG_DATA(cmsg), sizeof in); + break; + case HCI_CMSG_TSTAMP: + memcpy(&pkth.ts, CMSG_DATA(cmsg), + sizeof pkth.ts); + break; + } + cmsg = CMSG_NXTHDR(&msg, cmsg); + } + if ((in && (handle->direction == PCAP_D_OUT)) || + ((!in) && (handle->direction == PCAP_D_IN))) + return 0; + + bthdr->direction = htonl(in != 0); + pkth.caplen+=sizeof(pcap_bluetooth_h4_header); + pkth.len = pkth.caplen; + if (handle->fcode.bf_insns == NULL || + bpf_filter(handle->fcode.bf_insns, &handle->buffer[handle->offset], + pkth.len, pkth.caplen)) { + callback(user, &pkth, &handle->buffer[handle->offset]); + return 1; + } + return 0; /* didn't pass filter */ +} + +static int +bt_inject_linux(pcap_t *handle, const void *buf, size_t size) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " + "bluetooth devices"); + return (-1); +} + + +static int +bt_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_bt *handlep = handle->priv; + int ret; + struct hci_dev_info dev_info; + struct hci_dev_stats * s = &dev_info.stat; + dev_info.dev_id = handlep->dev_id; + + /* ignore eintr */ + do { + ret = ioctl(handle->fd, HCIGETDEVINFO, (void *)&dev_info); + } while ((ret == -1) && (errno == EINTR)); + + if (ret < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't get stats via ioctl: %s", strerror(errno)); + return (-1); + + } + + /* we receive both rx and tx frames, so comulate all stats */ + stats->ps_recv = s->evt_rx + s->acl_rx + s->sco_rx + s->cmd_tx + + s->acl_tx +s->sco_tx; + stats->ps_drop = s->err_rx + s->err_tx; + stats->ps_ifdrop = 0; + return 0; +} + +static int +bt_setdirection_linux(pcap_t *p, pcap_direction_t d) +{ + p->direction = d; + return 0; +} diff --git a/tcpdump/jni/libpcap/pcap-bt-linux.h b/tcpdump/jni/libpcap/pcap-bt-linux.h new file mode 100644 index 0000000..e098654 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-bt-linux.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Bluetooth sniffing API implementation for Linux platform + * By Paolo Abeni + */ + +/* + * Prototypes for Bluetooth-related functions + */ +int bt_findalldevs(pcap_if_t **alldevsp, char *err_str); +pcap_t *bt_create(const char *device, char *ebuf, int *is_ours); diff --git a/tcpdump/jni/libpcap/pcap-bt-monitor-linux.c b/tcpdump/jni/libpcap/pcap-bt-monitor-linux.c new file mode 100644 index 0000000..f193e26 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-bt-monitor-linux.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2014 Michal Labedzki for Tieto Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include + +#include "pcap/bluetooth.h" +#include "pcap-int.h" + +#include "pcap-bt-monitor-linux.h" + +#define BT_CONTROL_SIZE 32 +#define INTERFACE_NAME "bluetooth-monitor" + +int +bt_monitor_findalldevs(pcap_if_t **alldevsp, char *err_str) +{ + int ret = 0; + + if (pcap_add_if(alldevsp, INTERFACE_NAME, 0, + "Bluetooth Linux Monitor", err_str) < 0) + { + ret = -1; + } + + return ret; +} + +static int +bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) +{ + struct cmsghdr *cmsg; + struct msghdr msg; + struct iovec iv[2]; + ssize_t ret; + struct pcap_pkthdr pkth; + pcap_bluetooth_linux_monitor_header *bthdr; + struct mgmt_hdr hdr; + + bthdr = (pcap_bluetooth_linux_monitor_header*) &handle->buffer[handle->offset]; + + iv[0].iov_base = &hdr; + iv[0].iov_len = MGMT_HDR_SIZE; + iv[1].iov_base = &handle->buffer[handle->offset + sizeof(pcap_bluetooth_linux_monitor_header)]; + iv[1].iov_len = handle->snapshot; + + memset(&pkth.ts, 0, sizeof(pkth.ts)); + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iv; + msg.msg_iovlen = 2; + msg.msg_control = handle->buffer; + msg.msg_controllen = handle->offset; + + do { + ret = recvmsg(handle->fd, &msg, 0); + if (handle->break_loop) + { + handle->break_loop = 0; + return -2; + } + } while ((ret == -1) && (errno == EINTR)); + + if (ret < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't receive packet: %s", strerror(errno)); + return -1; + } + + pkth.caplen = ret - MGMT_HDR_SIZE + sizeof(pcap_bluetooth_linux_monitor_header); + pkth.len = pkth.caplen; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET) continue; + + if (cmsg->cmsg_type == SCM_TIMESTAMP) { + memcpy(&pkth.ts, CMSG_DATA(cmsg), sizeof(pkth.ts)); + } + } + + bthdr->adapter_id = htons(hdr.index); + bthdr->opcode = htons(hdr.opcode); + + if (handle->fcode.bf_insns == NULL || + bpf_filter(handle->fcode.bf_insns, &handle->buffer[handle->offset], + pkth.len, pkth.caplen)) { + callback(user, &pkth, &handle->buffer[handle->offset]); + return 1; + } + return 0; /* didn't pass filter */ +} + +static int +bt_monitor_inject(pcap_t *handle, const void *buf _U_, size_t size _U_) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported yet"); + return -1; +} + +static int +bt_monitor_setdirection(pcap_t *p, pcap_direction_t d) +{ + p->direction = d; + return 0; +} + +static int +bt_monitor_stats(pcap_t *handle _U_, struct pcap_stat *stats) +{ + stats->ps_recv = 0; + stats->ps_drop = 0; + stats->ps_ifdrop = 0; + + return 0; +} + +static int +bt_monitor_activate(pcap_t* handle) +{ + struct sockaddr_hci addr; + int err = PCAP_ERROR; + int opt; + + if (handle->opt.rfmon) { + /* monitor mode doesn't apply here */ + return PCAP_ERROR_RFMON_NOTSUP; + } + + handle->bufsize = handle->snapshot + BT_CONTROL_SIZE + sizeof(pcap_bluetooth_linux_monitor_header); + handle->offset = BT_CONTROL_SIZE; + handle->linktype = DLT_BLUETOOTH_LINUX_MONITOR; + + handle->read_op = bt_monitor_read; + handle->inject_op = bt_monitor_inject; + handle->setfilter_op = install_bpf_program; /* no kernel filtering */ + handle->setdirection_op = bt_monitor_setdirection; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->stats_op = bt_monitor_stats; + + handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (handle->fd < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't create raw socket: %s", strerror(errno)); + return PCAP_ERROR; + } + + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", + pcap_strerror(errno)); + goto close_fail; + } + + /* Bind socket to the HCI device */ + addr.hci_family = AF_BLUETOOTH; + addr.hci_dev = HCI_DEV_NONE; + addr.hci_channel = HCI_CHANNEL_MONITOR; + + if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't attach to interface: %s", strerror(errno)); + goto close_fail; + } + + opt = 1; + if (setsockopt(handle->fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't enable time stamp: %s", strerror(errno)); + goto close_fail; + } + + handle->selectable_fd = handle->fd; + + return 0; + +close_fail: + pcap_cleanup_live_common(handle); + return err; +} + +pcap_t * +bt_monitor_create(const char *device, char *ebuf, int *is_ours) +{ + pcap_t *p; + const char *cp; + + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + + if (strcmp(cp, INTERFACE_NAME) != 0) { + *is_ours = 0; + return NULL; + } + + *is_ours = 1; + p = pcap_create_common(device, ebuf, 0); + if (p == NULL) + return NULL; + + p->activate_op = bt_monitor_activate; + + return p; +} diff --git a/tcpdump/jni/libpcap/pcap-bt-monitor-linux.h b/tcpdump/jni/libpcap/pcap-bt-monitor-linux.h new file mode 100644 index 0000000..aada2bc --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-bt-monitor-linux.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Michal Labedzki for Tieto Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +int bt_monitor_findalldevs(pcap_if_t **alldevsp, char *err_str); +pcap_t *bt_monitor_create(const char *device, char *ebuf, int *is_ours); diff --git a/tcpdump/jni/libpcap/pcap-can-linux.c b/tcpdump/jni/libpcap/pcap-can-linux.c new file mode 100644 index 0000000..a8e1e35 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-can-linux.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2009 Felix Obenhuber + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SocketCan sniffing API implementation for Linux platform + * By Felix Obenhuber + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pcap-int.h" +#include "pcap-can-linux.h" + +#ifdef NEED_STRERROR_H +#include "strerror.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* not yet defined anywhere */ +#ifndef PF_CAN +#define PF_CAN 29 +#endif +#ifndef AF_CAN +#define AF_CAN PF_CAN +#endif + +/* forward declaration */ +static int can_activate(pcap_t *); +static int can_read_linux(pcap_t *, int , pcap_handler , u_char *); +static int can_inject_linux(pcap_t *, const void *, size_t); +static int can_setfilter_linux(pcap_t *, struct bpf_program *); +static int can_setdirection_linux(pcap_t *, pcap_direction_t); +static int can_stats_linux(pcap_t *, struct pcap_stat *); + +/* + * Private data for capturing on Linux CANbus devices. + */ +struct pcap_can { + int ifindex; /* interface index of device we're bound to */ +}; + +int +can_findalldevs(pcap_if_t **devlistp, char *errbuf) +{ + /* + * There are no platform-specific devices since each device + * exists as a regular network interface. + * + * XXX - true? + */ + return 0; +} + +pcap_t * +can_create(const char *device, char *ebuf, int *is_ours) +{ + const char *cp; + char *cpend; + long devnum; + pcap_t* p; + + /* Does this look like a CANbus device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + /* Does it begin with "can" or "vcan"? */ + if (strncmp(cp, "can", 3) == 0) { + /* Begins with "can" */ + cp += 3; /* skip past "can" */ + } else if (strncmp(cp, "vcan", 4) == 0) { + /* Begins with "vcan" */ + cp += 4; + } else { + /* Nope, doesn't begin with "can" or "vcan" */ + *is_ours = 0; + return NULL; + } + /* Yes - is "can" or "vcan" followed by a number from 0? */ + devnum = strtol(cp, &cpend, 10); + if (cpend == cp || *cpend != '\0') { + /* Not followed by a number. */ + *is_ours = 0; + return NULL; + } + if (devnum < 0) { + /* Followed by a non-valid number. */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_can)); + if (p == NULL) + return (NULL); + + p->activate_op = can_activate; + return (p); +} + + +static int +can_activate(pcap_t* handle) +{ + struct pcap_can *handlep = handle->priv; + struct sockaddr_can addr; + struct ifreq ifr; + + /* Initialize some components of the pcap structure. */ + handle->bufsize = 24; + handle->offset = 8; + handle->linktype = DLT_CAN_SOCKETCAN; + handle->read_op = can_read_linux; + handle->inject_op = can_inject_linux; + handle->setfilter_op = can_setfilter_linux; + handle->setdirection_op = can_setdirection_linux; + handle->set_datalink_op = NULL; + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->stats_op = can_stats_linux; + + /* Create socket */ + handle->fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); + if (handle->fd < 0) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s", + errno, strerror(errno)); + return PCAP_ERROR; + } + + /* get interface index */ + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name)); + if (ioctl(handle->fd, SIOCGIFINDEX, &ifr) < 0) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Unable to get interface index: %s", + pcap_strerror(errno)); + pcap_cleanup_live_common(handle); + return PCAP_ERROR; + } + handlep->ifindex = ifr.ifr_ifindex; + + /* allocate butter */ + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", + pcap_strerror(errno)); + pcap_cleanup_live_common(handle); + return PCAP_ERROR; + } + + /* Bind to the socket */ + addr.can_family = AF_CAN; + addr.can_ifindex = handlep->ifindex; + if( bind( handle->fd, (struct sockaddr*)&addr, sizeof(addr) ) < 0 ) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't attach to device %d %d:%s", + handlep->ifindex, errno, strerror(errno)); + pcap_cleanup_live_common(handle); + return PCAP_ERROR; + } + + if (handle->opt.rfmon) + { + /* Monitor mode doesn't apply to CAN devices. */ + pcap_cleanup_live_common(handle); + return PCAP_ERROR_RFMON_NOTSUP; + } + + handle->selectable_fd = handle->fd; + return 0; + +} + + +static int +can_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + struct msghdr msg; + struct pcap_pkthdr pkth; + struct iovec iv; + struct can_frame* cf; + + iv.iov_base = &handle->buffer[handle->offset]; + iv.iov_len = handle->snapshot; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iv; + msg.msg_iovlen = 1; + msg.msg_control = handle->buffer; + msg.msg_controllen = handle->offset; + + do + { + pkth.caplen = recvmsg(handle->fd, &msg, 0); + if (handle->break_loop) + { + handle->break_loop = 0; + return -2; + } + } while ((pkth.caplen == -1) && (errno == EINTR)); + + if (pkth.caplen == -1) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", + errno, strerror(errno)); + return -1; + } + + /* adjust capture len according to frame len */ + cf = (struct can_frame*)&handle->buffer[8]; + pkth.caplen -= 8 - cf->can_dlc; + pkth.len = pkth.caplen; + + cf->can_id = htonl( cf->can_id ); + + if( -1 == gettimeofday(&pkth.ts, NULL) ) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get time of day %d:%s", + errno, strerror(errno)); + return -1; + } + + callback(user, &pkth, &handle->buffer[8]); + + return 1; +} + + +static int +can_inject_linux(pcap_t *handle, const void *buf, size_t size) +{ + /* not yet implemented */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " + "can devices"); + return (-1); +} + + +static int +can_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + /* not yet implemented */ + stats->ps_recv = 0; /* number of packets received */ + stats->ps_drop = 0; /* number of packets dropped */ + stats->ps_ifdrop = 0; /* drops by interface -- only supported on some platforms */ + return 0; +} + + +static int +can_setfilter_linux(pcap_t *p, struct bpf_program *fp) +{ + /* not yet implemented */ + return 0; +} + + +static int +can_setdirection_linux(pcap_t *p, pcap_direction_t d) +{ + /* no support for PCAP_D_OUT */ + if (d == PCAP_D_OUT) + { + snprintf(p->errbuf, sizeof(p->errbuf), + "Setting direction to PCAP_D_OUT is not supported on can"); + return -1; + } + + p->direction = d; + + return 0; +} + + +/* eof */ diff --git a/tcpdump/jni/libpcap/pcap-can-linux.h b/tcpdump/jni/libpcap/pcap-can-linux.h new file mode 100644 index 0000000..fe806ff --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-can-linux.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2009 Felix Obenhuber + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * Prototypes for SocketCAN related functions + */ +pcap_t* can_create(const char *device, char *ebuf, int *is_ours); +int can_findalldevs(pcap_if_t **devlistp, char *errbuf); diff --git a/tcpdump/jni/libpcap/pcap-canusb-linux.c b/tcpdump/jni/libpcap/pcap-canusb-linux.c new file mode 100644 index 0000000..f44c45e --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-canusb-linux.c @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2009 Felix Obenhuber + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Sockettrace sniffing API implementation for Linux platform + * By Felix Obenhuber + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" +#include "pcap-canusb-linux.h" + +#define CANUSB_IFACE "canusb" + +#define CANUSB_VID 0x0403 +#define CANUSB_PID 0x8990 + +#define USE_THREAD 1 + +#if USE_THREAD == 0 +#include +#endif + + +/* forward declaration */ +static int canusb_activate(pcap_t *); +static int canusb_read_linux(pcap_t *, int , pcap_handler , u_char *); +static int canusb_inject_linux(pcap_t *, const void *, size_t); +static int canusb_setfilter_linux(pcap_t *, struct bpf_program *); +static int canusb_setdirection_linux(pcap_t *, pcap_direction_t); +static int canusb_stats_linux(pcap_t *, struct pcap_stat *); + +struct CAN_Msg +{ + uint32_t timestamp; + uint32_t id; + uint32_t length; + uint8_t data[8]; +}; + +/* + * Private data for capturing on Linux CANbus USB devices. + */ +struct pcap_canusb { + libusb_context *ctx; + libusb_device_handle *dev; + pthread_t worker; + int rdpipe, wrpipe; + volatile int loop; +}; + +int canusb_findalldevs(pcap_if_t **alldevsp, char *err_str) +{ + libusb_context *fdctx; + libusb_device** devs; + unsigned char sernum[65]; + int cnt, i; + + if (libusb_init(&fdctx) != 0) { + /* + * XXX - if this doesn't just mean "no USB file system mounted", + * perhaps we should report a real error rather than just + * saying "no CANUSB devices". + */ + return 0; + } + + cnt = libusb_get_device_list(fdctx,&devs); + + for(i=0;ipriv; + canusb->ctx = NULL; + canusb->dev = NULL; + canusb->rdpipe = -1; + canusb->wrpipe = -1; + + p->activate_op = canusb_activate; + + return (p); +} + + +static void* canusb_capture_thread(void *arg) +{ + struct pcap_canusb *canusb = arg; + int i; + struct + { + uint8_t rxsz, txsz; + } status; + + fcntl(canusb->wrpipe, F_SETFL, O_NONBLOCK); + + while(canusb->loop) + { + int sz; + struct CAN_Msg msg; + + libusb_interrupt_transfer(canusb->dev, 0x81, (unsigned char*)&status, sizeof(status), &sz, 100); + //HACK!!!!! -> drop buffered data, read new one by reading twice. + libusb_interrupt_transfer(canusb->dev, 0x81, (unsigned char*)&status, sizeof(status), &sz, 100); + + for(i = 0; idev, 0x85, (unsigned char*)&msg, sizeof(msg), &sz, 100); + if(write(canusb->wrpipe, &msg, sizeof(msg)) < 0) + fprintf(stderr,"write() error: %s\n", strerror(errno)); + } + + } + + return NULL; +} + +static int canusb_startcapture(struct pcap_canusb* this) +{ + int pipefd[2]; + + if (pipe(pipefd) == -1) + return -1; + + this->rdpipe = pipefd[0]; + this->wrpipe = pipefd[1]; + + this->loop = 1; + pthread_create(&this->worker, NULL, canusb_capture_thread, this); + + return this->rdpipe; +} + +static void canusb_clearbufs(struct pcap_canusb* this) +{ + unsigned char cmd[16]; + int al; + + cmd[0] = 1; //Empty incoming buffer + cmd[1] = 1; //Empty outgoing buffer + cmd[3] = 0; //Not a write to serial number + memset(&cmd[4],0,16-4); + + libusb_interrupt_transfer(this->dev, 0x1,cmd,16,&al,100); +} + + +static void canusb_close(pcap_t* handle) +{ + struct pcap_canusb *canusb = handle->priv; + + canusb->loop = 0; + pthread_join(canusb->worker, NULL); + + if (canusb->dev) + { + libusb_close(canusb->dev); + canusb->dev = NULL; + } + if (canusb->ctx) + { + libusb_exit(canusb->ctx); + canusb->ctx = NULL; + } +} + + + +static int canusb_activate(pcap_t* handle) +{ + struct pcap_canusb *canusb = handle->priv; + char *serial; + + if (libusb_init(&canusb->ctx) != 0) { + /* + * XXX - what causes this to fail? + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "libusb_init() failed"); + return PCAP_ERROR; + } + + handle->read_op = canusb_read_linux; + + handle->inject_op = canusb_inject_linux; + handle->setfilter_op = canusb_setfilter_linux; + handle->setdirection_op = canusb_setdirection_linux; + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->stats_op = canusb_stats_linux; + handle->cleanup_op = canusb_close; + + /* Initialize some components of the pcap structure. */ + handle->bufsize = 32; + handle->offset = 8; + handle->linktype = DLT_CAN_SOCKETCAN; + handle->set_datalink_op = NULL; + + serial = handle->opt.source + strlen(CANUSB_IFACE); + + canusb->dev = canusb_opendevice(canusb->ctx, serial); + if (!canusb->dev) + { + libusb_exit(canusb->ctx); + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't open USB Device"); + return PCAP_ERROR; + } + + canusb_clearbufs(canusb); + + handle->fd = canusb_startcapture(canusb); + handle->selectable_fd = handle->fd; + + return 0; +} + + + + +static int +canusb_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + static struct timeval firstpacket = { -1, -1}; + int i = 0; + struct CAN_Msg msg; + struct pcap_pkthdr pkth; + + while(i < max_packets) + { + int n; + usleep(10 * 1000); + n = read(handle->fd, &msg, sizeof(msg)); + if (n <= 0) + break; + pkth.caplen = pkth.len = n; + pkth.caplen -= 4; + pkth.caplen -= 8 - msg.length; + + if ((firstpacket.tv_sec == -1) && (firstpacket.tv_usec == -1)) + gettimeofday(&firstpacket, NULL); + + pkth.ts.tv_usec = firstpacket.tv_usec + (msg.timestamp % 100) * 10000; + pkth.ts.tv_sec = firstpacket.tv_usec + (msg.timestamp / 100); + if (pkth.ts.tv_usec > 1000000) + { + pkth.ts.tv_usec -= 1000000; + pkth.ts.tv_sec++; + } + + callback(user, &pkth, (void*)&msg.id); + i++; + } + + return i; +} + + +static int +canusb_inject_linux(pcap_t *handle, const void *buf, size_t size) +{ + /* not yet implemented */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on canusb devices"); + return (-1); +} + + +static int +canusb_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + /* not yet implemented */ + stats->ps_recv = 0; /* number of packets received */ + stats->ps_drop = 0; /* number of packets dropped */ + stats->ps_ifdrop = 0; /* drops by interface -- only supported on some platforms */ + return 0; +} + + +static int +canusb_setfilter_linux(pcap_t *p, struct bpf_program *fp) +{ + /* not yet implemented */ + return 0; +} + + +static int +canusb_setdirection_linux(pcap_t *p, pcap_direction_t d) +{ + /* no support for PCAP_D_OUT */ + if (d == PCAP_D_OUT) + { + snprintf(p->errbuf, sizeof(p->errbuf), + "Setting direction to PCAP_D_OUT is not supported on this interface"); + return -1; + } + + p->direction = d; + + return 0; +} + + +/* eof */ diff --git a/tcpdump/jni/libpcap/pcap-canusb-linux.h b/tcpdump/jni/libpcap/pcap-canusb-linux.h new file mode 100644 index 0000000..c8f3be1 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-canusb-linux.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009 Felix Obenhuber + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * Prototypes for SocketCAN related functions + */ +pcap_t* canusb_create(const char *device, char *ebuf, int *is_ours); +int canusb_findalldevs(pcap_if_t **pdevlist, char* errbuf); + diff --git a/tcpdump/jni/libpcap/pcap-common.c b/tcpdump/jni/libpcap/pcap-common.c new file mode 100644 index 0000000..4db4968 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-common.c @@ -0,0 +1,1386 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * pcap-common.c - common code for pcap and pcap-ng files + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#endif /* WIN32 */ + +#include "pcap-int.h" +#include "pcap/usb.h" +#include "pcap/nflog.h" + +#include "pcap-common.h" + +/* + * We don't write DLT_* values to capture files, because they're not the + * same on all platforms. + * + * Unfortunately, the various flavors of BSD have not always used the same + * numerical values for the same data types, and various patches to + * libpcap for non-BSD OSes have added their own DLT_* codes for link + * layer encapsulation types seen on those OSes, and those codes have had, + * in some cases, values that were also used, on other platforms, for other + * link layer encapsulation types. + * + * This means that capture files of a type whose numerical DLT_* code + * means different things on different BSDs, or with different versions + * of libpcap, can't always be read on systems other than those like + * the one running on the machine on which the capture was made. + * + * Instead, we define here a set of LINKTYPE_* codes, and map DLT_* codes + * to LINKTYPE_* codes when writing a savefile header, and map LINKTYPE_* + * codes to DLT_* codes when reading a savefile header. + * + * For those DLT_* codes that have, as far as we know, the same values on + * all platforms (DLT_NULL through DLT_FDDI), we define LINKTYPE_xxx as + * DLT_xxx; that way, captures of those types can still be read by + * versions of libpcap that map LINKTYPE_* values to DLT_* values, and + * captures of those types written by versions of libpcap that map DLT_ + * values to LINKTYPE_ values can still be read by older versions + * of libpcap. + * + * The other LINKTYPE_* codes are given values starting at 100, in the + * hopes that no DLT_* code will be given one of those values. + * + * In order to ensure that a given LINKTYPE_* code's value will refer to + * the same encapsulation type on all platforms, you should not allocate + * a new LINKTYPE_* value without consulting + * "tcpdump-workers@lists.tcpdump.org". The tcpdump developers will + * allocate a value for you, and will not subsequently allocate it to + * anybody else; that value will be added to the "pcap.h" in the + * tcpdump.org Git repository, so that a future libpcap release will + * include it. + * + * You should, if possible, also contribute patches to libpcap and tcpdump + * to handle the new encapsulation type, so that they can also be checked + * into the tcpdump.org Git repository and so that they will appear in + * future libpcap and tcpdump releases. + * + * Do *NOT* assume that any values after the largest value in this file + * are available; you might not have the most up-to-date version of this + * file, and new values after that one might have been assigned. Also, + * do *NOT* use any values below 100 - those might already have been + * taken by one (or more!) organizations. + * + * Any platform that defines additional DLT_* codes should: + * + * request a LINKTYPE_* code and value from tcpdump.org, + * as per the above; + * + * add, in their version of libpcap, an entry to map + * those DLT_* codes to the corresponding LINKTYPE_* + * code; + * + * redefine, in their "net/bpf.h", any DLT_* values + * that collide with the values used by their additional + * DLT_* codes, to remove those collisions (but without + * making them collide with any of the LINKTYPE_* + * values equal to 50 or above; they should also avoid + * defining DLT_* values that collide with those + * LINKTYPE_* values, either). + */ +#define LINKTYPE_NULL DLT_NULL +#define LINKTYPE_ETHERNET DLT_EN10MB /* also for 100Mb and up */ +#define LINKTYPE_EXP_ETHERNET DLT_EN3MB /* 3Mb experimental Ethernet */ +#define LINKTYPE_AX25 DLT_AX25 +#define LINKTYPE_PRONET DLT_PRONET +#define LINKTYPE_CHAOS DLT_CHAOS +#define LINKTYPE_IEEE802_5 DLT_IEEE802 /* DLT_IEEE802 is used for 802.5 Token Ring */ +#define LINKTYPE_ARCNET_BSD DLT_ARCNET /* BSD-style headers */ +#define LINKTYPE_SLIP DLT_SLIP +#define LINKTYPE_PPP DLT_PPP +#define LINKTYPE_FDDI DLT_FDDI + +/* + * LINKTYPE_PPP is for use when there might, or might not, be an RFC 1662 + * PPP in HDLC-like framing header (with 0xff 0x03 before the PPP protocol + * field) at the beginning of the packet. + * + * This is for use when there is always such a header; the address field + * might be 0xff, for regular PPP, or it might be an address field for Cisco + * point-to-point with HDLC framing as per section 4.3.1 of RFC 1547 ("Cisco + * HDLC"). This is, for example, what you get with NetBSD's DLT_PPP_SERIAL. + * + * We give it the same value as NetBSD's DLT_PPP_SERIAL, in the hopes that + * nobody else will choose a DLT_ value of 50, and so that DLT_PPP_SERIAL + * captures will be written out with a link type that NetBSD's tcpdump + * can read. + */ +#define LINKTYPE_PPP_HDLC 50 /* PPP in HDLC-like framing */ + +#define LINKTYPE_PPP_ETHER 51 /* NetBSD PPP-over-Ethernet */ + +#define LINKTYPE_SYMANTEC_FIREWALL 99 /* Symantec Enterprise Firewall */ + +/* + * These correspond to DLT_s that have different values on different + * platforms; we map between these values in capture files and + * the DLT_ values as returned by pcap_datalink() and passed to + * pcap_open_dead(). + */ +#define LINKTYPE_ATM_RFC1483 100 /* LLC/SNAP-encapsulated ATM */ +#define LINKTYPE_RAW 101 /* raw IP */ +#define LINKTYPE_SLIP_BSDOS 102 /* BSD/OS SLIP BPF header */ +#define LINKTYPE_PPP_BSDOS 103 /* BSD/OS PPP BPF header */ + +/* + * Values starting with 104 are used for newly-assigned link-layer + * header type values; for those link-layer header types, the DLT_ + * value returned by pcap_datalink() and passed to pcap_open_dead(), + * and the LINKTYPE_ value that appears in capture files, are the + * same. + * + * LINKTYPE_MATCHING_MIN is the lowest such value; LINKTYPE_MATCHING_MAX + * is the highest such value. + */ +#define LINKTYPE_MATCHING_MIN 104 /* lowest value in the "matching" range */ + +#define LINKTYPE_C_HDLC 104 /* Cisco HDLC */ +#define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 (wireless) */ +#define LINKTYPE_ATM_CLIP 106 /* Linux Classical IP over ATM */ +#define LINKTYPE_FRELAY 107 /* Frame Relay */ +#define LINKTYPE_LOOP 108 /* OpenBSD loopback */ +#define LINKTYPE_ENC 109 /* OpenBSD IPSEC enc */ + +/* + * These three types are reserved for future use. + */ +#define LINKTYPE_LANE8023 110 /* ATM LANE + 802.3 */ +#define LINKTYPE_HIPPI 111 /* NetBSD HIPPI */ +#define LINKTYPE_HDLC 112 /* NetBSD HDLC framing */ + +#define LINKTYPE_LINUX_SLL 113 /* Linux cooked socket capture */ +#define LINKTYPE_LTALK 114 /* Apple LocalTalk hardware */ +#define LINKTYPE_ECONET 115 /* Acorn Econet */ + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define LINKTYPE_IPFILTER 116 + +#define LINKTYPE_PFLOG 117 /* OpenBSD DLT_PFLOG */ +#define LINKTYPE_CISCO_IOS 118 /* For Cisco-internal use */ +#define LINKTYPE_IEEE802_11_PRISM 119 /* 802.11 plus Prism II monitor mode radio metadata header */ +#define LINKTYPE_IEEE802_11_AIRONET 120 /* 802.11 plus FreeBSD Aironet driver radio metadata header */ + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define LINKTYPE_HHDLC 121 + +#define LINKTYPE_IP_OVER_FC 122 /* RFC 2625 IP-over-Fibre Channel */ +#define LINKTYPE_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define LINKTYPE_RIO 124 /* RapidIO */ +#define LINKTYPE_PCI_EXP 125 /* PCI Express */ +#define LINKTYPE_AURORA 126 /* Xilinx Aurora link layer */ + +#define LINKTYPE_IEEE802_11_RADIOTAP 127 /* 802.11 plus radiotap radio metadata header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define LINKTYPE_TZSP 128 /* Tazmen Sniffer Protocol */ + +#define LINKTYPE_ARCNET_LINUX 129 /* Linux-style headers */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The corresponding + * DLT_s are used for passing on chassis-internal + * metainformation such as QOS profiles, etc.. + */ +#define LINKTYPE_JUNIPER_MLPPP 130 +#define LINKTYPE_JUNIPER_MLFR 131 +#define LINKTYPE_JUNIPER_ES 132 +#define LINKTYPE_JUNIPER_GGSN 133 +#define LINKTYPE_JUNIPER_MFR 134 +#define LINKTYPE_JUNIPER_ATM2 135 +#define LINKTYPE_JUNIPER_SERVICES 136 +#define LINKTYPE_JUNIPER_ATM1 137 + +#define LINKTYPE_APPLE_IP_OVER_IEEE1394 138 /* Apple IP-over-IEEE 1394 cooked header */ + +#define LINKTYPE_MTP2_WITH_PHDR 139 +#define LINKTYPE_MTP2 140 +#define LINKTYPE_MTP3 141 +#define LINKTYPE_SCCP 142 + +#define LINKTYPE_DOCSIS 143 /* DOCSIS MAC frames */ + +#define LINKTYPE_LINUX_IRDA 144 /* Linux-IrDA */ + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define LINKTYPE_IBM_SP 145 +#define LINKTYPE_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that LINKTYPE_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, in those cases, ask "tcpdump-workers@lists.tcpdump.org" for a + * new DLT_ and LINKTYPE_ value, as per the comment in pcap/bpf.h, and use + * the type you're given. + */ +#define LINKTYPE_USER0 147 +#define LINKTYPE_USER1 148 +#define LINKTYPE_USER2 149 +#define LINKTYPE_USER3 150 +#define LINKTYPE_USER4 151 +#define LINKTYPE_USER5 152 +#define LINKTYPE_USER6 153 +#define LINKTYPE_USER7 154 +#define LINKTYPE_USER8 155 +#define LINKTYPE_USER9 156 +#define LINKTYPE_USER10 157 +#define LINKTYPE_USER11 158 +#define LINKTYPE_USER12 159 +#define LINKTYPE_USER13 160 +#define LINKTYPE_USER14 161 +#define LINKTYPE_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + */ +#define LINKTYPE_IEEE802_11_AVS 163 /* 802.11 plus AVS radio metadata header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The corresponding + * DLT_s are used for passing on chassis-internal + * metainformation such as QOS profiles, etc.. + */ +#define LINKTYPE_JUNIPER_MONITOR 164 + +/* + * BACnet MS/TP frames. + */ +#define LINKTYPE_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accomodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define LINKTYPE_PPP_PPPD 166 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define LINKTYPE_JUNIPER_PPPOE 167 +#define LINKTYPE_JUNIPER_PPPOE_ATM 168 + +#define LINKTYPE_GPRS_LLC 169 /* GPRS LLC */ +#define LINKTYPE_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define LINKTYPE_GPF_F 171 /* GPF-T (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define LINKTYPE_GCOM_T1E1 172 +#define LINKTYPE_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define LINKTYPE_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define LINKTYPE_ERF_ETH 175 /* Ethernet */ +#define LINKTYPE_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define LINKTYPE_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The Link Types are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define LINKTYPE_JUNIPER_ETHER 178 +#define LINKTYPE_JUNIPER_PPP 179 +#define LINKTYPE_JUNIPER_FRELAY 180 +#define LINKTYPE_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define LINKTYPE_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define LINKTYPE_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define LINKTYPE_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define LINKTYPE_A653_ICM 185 + +/* + * USB packets, beginning with a USB setup header; requested by + * Paolo Abeni . + */ +#define LINKTYPE_USB 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define LINKTYPE_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define LINKTYPE_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define LINKTYPE_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define LINKTYPE_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define LINKTYPE_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * LINKTYPE_ requested by Gianluca Varenni . + */ +#define LINKTYPE_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define LINKTYPE_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define LINKTYPE_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing); requested by Mikko Saarnivala . + */ +#define LINKTYPE_IEEE802_15_4 195 + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define LINKTYPE_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define LINKTYPE_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define LINKTYPE_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with the I2C slave address, followed + * by the netFn and LUN, etc.. Requested by Chanthy Toeung + * . + */ +#define LINKTYPE_IPMB 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define LINKTYPE_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define LINKTYPE_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define LINKTYPE_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define LINKTYPE_LAPD 203 + +/* + * Variants of various link-layer headers, with a one-byte direction + * pseudo-header prepended - zero means "received by this host", + * non-zero (any non-zero value) means "sent by this host" - as per + * Will Barker . + */ +#define LINKTYPE_PPP_WITH_DIR 204 /* PPP */ +#define LINKTYPE_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ +#define LINKTYPE_FRELAY_WITH_DIR 206 /* Frame Relay */ +#define LINKTYPE_LAPB_WITH_DIR 207 /* LAPB */ + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define LINKTYPE_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define LINKTYPE_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - http://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define LINKTYPE_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define LINKTYPE_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define LINKTYPE_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define LINKTYPE_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define LINKTYPE_IEEE802_15_4_NONASK_PHY 215 + +/* + * David Gibson requested this for + * captures from the Linux kernel /dev/input/eventN devices. This + * is used to communicate keystrokes and mouse movements from the + * Linux kernel to display systems, such as Xorg. + */ +#define LINKTYPE_LINUX_EVDEV 216 + +/* + * GSM Um and Abis interfaces, preceded by a "gsmtap" header. + * + * Requested by Harald Welte . + */ +#define LINKTYPE_GSMTAP_UM 217 +#define LINKTYPE_GSMTAP_ABIS 218 + +/* + * MPLS, with an MPLS label as the link-layer header. + * Requested by Michele Marchetto on behalf + * of OpenBSD. + */ +#define LINKTYPE_MPLS 219 + +/* + * USB packets, beginning with a Linux USB header, with the USB header + * padded to 64 bytes; required for memory-mapped access. + */ +#define LINKTYPE_USB_LINUX_MMAPPED 220 + +/* + * DECT packets, with a pseudo-header; requested by + * Matthias Wenzel . + */ +#define LINKTYPE_DECT 221 + +/* + * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" + * Date: Mon, 11 May 2009 11:18:30 -0500 + * + * DLT_AOS. We need it for AOS Space Data Link Protocol. + * I have already written dissectors for but need an OK from + * legal before I can submit a patch. + * + */ +#define LINKTYPE_AOS 222 + +/* + * Wireless HART (Highway Addressable Remote Transducer) + * From the HART Communication Foundation + * IES/PAS 62591 + * + * Requested by Sam Roberts . + */ +#define LINKTYPE_WIHART 223 + +/* + * Fibre Channel FC-2 frames, beginning with a Frame_Header. + * Requested by Kahou Lei . + */ +#define LINKTYPE_FC_2 224 + +/* + * Fibre Channel FC-2 frames, beginning with an encoding of the + * SOF, and ending with an encoding of the EOF. + * + * The encodings represent the frame delimiters as 4-byte sequences + * representing the corresponding ordered sets, with K28.5 + * represented as 0xBC, and the D symbols as the corresponding + * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2, + * is represented as 0xBC 0xB5 0x55 0x55. + * + * Requested by Kahou Lei . + */ +#define LINKTYPE_FC_2_WITH_FRAME_DELIMS 225 + +/* + * Solaris ipnet pseudo-header; requested by Darren Reed . + * + * The pseudo-header starts with a one-byte version number; for version 2, + * the pseudo-header is: + * + * struct dl_ipnetinfo { + * u_int8_t dli_version; + * u_int8_t dli_family; + * u_int16_t dli_htype; + * u_int32_t dli_pktlen; + * u_int32_t dli_ifindex; + * u_int32_t dli_grifindex; + * u_int32_t dli_zsrc; + * u_int32_t dli_zdst; + * }; + * + * dli_version is 2 for the current version of the pseudo-header. + * + * dli_family is a Solaris address family value, so it's 2 for IPv4 + * and 26 for IPv6. + * + * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing + * packets, and 2 for packets arriving from another zone on the same + * machine. + * + * dli_pktlen is the length of the packet data following the pseudo-header + * (so the captured length minus dli_pktlen is the length of the + * pseudo-header, assuming the entire pseudo-header was captured). + * + * dli_ifindex is the interface index of the interface on which the + * packet arrived. + * + * dli_grifindex is the group interface index number (for IPMP interfaces). + * + * dli_zsrc is the zone identifier for the source of the packet. + * + * dli_zdst is the zone identifier for the destination of the packet. + * + * A zone number of 0 is the global zone; a zone number of 0xffffffff + * means that the packet arrived from another host on the network, not + * from another zone on the same machine. + * + * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates + * which of those it is. + */ +#define LINKTYPE_IPNET 226 + +/* + * CAN (Controller Area Network) frames, with a pseudo-header as supplied + * by Linux SocketCAN. See Documentation/networking/can.txt in the Linux + * source. + * + * Requested by Felix Obenhuber . + */ +#define LINKTYPE_CAN_SOCKETCAN 227 + +/* + * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies + * whether it's v4 or v6. Requested by Darren Reed . + */ +#define LINKTYPE_IPV4 228 +#define LINKTYPE_IPV6 229 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), and with no FCS at the end of the frame; requested by + * Jon Smirl . + */ +#define LINKTYPE_IEEE802_15_4_NOFCS 230 + +/* + * Raw D-Bus: + * + * http://www.freedesktop.org/wiki/Software/dbus + * + * messages: + * + * http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages + * + * starting with the endianness flag, followed by the message type, etc., + * but without the authentication handshake before the message sequence: + * + * http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol + * + * Requested by Martin Vidner . + */ +#define LINKTYPE_DBUS 231 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + */ +#define LINKTYPE_JUNIPER_VS 232 +#define LINKTYPE_JUNIPER_SRX_E2E 233 +#define LINKTYPE_JUNIPER_FIBRECHANNEL 234 + +/* + * DVB-CI (DVB Common Interface for communication between a PC Card + * module and a DVB receiver). See + * + * http://www.kaiser.cx/pcap-dvbci.html + * + * for the specification. + * + * Requested by Martin Kaiser . + */ +#define LINKTYPE_DVB_CI 235 + +/* + * Variant of 3GPP TS 27.010 multiplexing protocol. Requested + * by Hans-Christoph Schemmel . + */ +#define LINKTYPE_MUX27010 236 + +/* + * STANAG 5066 D_PDUs. Requested by M. Baris Demiray + * . + */ +#define LINKTYPE_STANAG_5066_D_PDU 237 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + */ +#define LINKTYPE_JUNIPER_ATM_CEMIC 238 + +/* + * NetFilter LOG messages + * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets) + * + * Requested by Jakub Zawadzki + */ +#define LINKTYPE_NFLOG 239 + +/* + * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type + * for Ethernet packets with a 4-byte pseudo-header and always + * with the payload including the FCS, as supplied by their + * netANALYZER hardware and software. + * + * Requested by Holger P. Frommer + */ +#define LINKTYPE_NETANALYZER 240 + +/* + * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type + * for Ethernet packets with a 4-byte pseudo-header and FCS and + * 1 byte of SFD, as supplied by their netANALYZER hardware and + * software. + * + * Requested by Holger P. Frommer + */ +#define LINKTYPE_NETANALYZER_TRANSPARENT 241 + +/* + * IP-over-InfiniBand, as specified by RFC 4391. + * + * Requested by Petr Sumbera . + */ +#define LINKTYPE_IPOIB 242 + +/* + * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0). + * + * Requested by Guy Martin . + */ +#define LINKTYPE_MPEG_2_TS 243 + +/* + * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as + * used by their ng40 protocol tester. + * + * Requested by Jens Grimmer . + */ +#define LINKTYPE_NG40 244 + +/* + * Pseudo-header giving adapter number and flags, followed by an NFC + * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU, + * as specified by NFC Forum Logical Link Control Protocol Technical + * Specification LLCP 1.1. + * + * Requested by Mike Wakerly . + */ +#define LINKTYPE_NFC_LLCP 245 + +/* + * pfsync output; DLT_PFSYNC is 18, which collides with DLT_CIP in + * SuSE 6.3, on OpenBSD, NetBSD, DragonFly BSD, and Mac OS X, and + * is 121, which collides with DLT_HHDLC, in FreeBSD. We pick a + * shiny new link-layer header type value that doesn't collide with + * anything, in the hopes that future pfsync savefiles, if any, + * won't require special hacks to distinguish from other savefiles. + * + */ +#define LINKTYPE_PFSYNC 246 + +/* + * Raw InfiniBand packets, starting with the Local Routing Header. + * + * Requested by Oren Kladnitsky . + */ +#define LINKTYPE_INFINIBAND 247 + +/* + * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6). + * + * Requested by Michael Tuexen . + */ +#define LINKTYPE_SCTP 248 + +/* + * USB packets, beginning with a USBPcap header. + * + * Requested by Tomasz Mon + */ +#define LINKTYPE_USBPCAP 249 + +/* + * Schweitzer Engineering Laboratories "RTAC" product serial-line + * packets. + * + * Requested by Chris Bontje . + */ +#define DLT_RTAC_SERIAL 250 + +/* + * Bluetooth Low Energy air interface link-layer packets. + * + * Requested by Mike Kershaw . + */ +#define LINKTYPE_BLUETOOTH_LE_LL 251 + +/* + * Link-layer header type for upper-protocol layer PDU saves from wireshark. + * + * the actual contents are determined by two TAGs stored with each + * packet: + * EXP_PDU_TAG_LINKTYPE the link type (LINKTYPE_ value) of the + * original packet. + * + * EXP_PDU_TAG_PROTO_NAME the name of the wireshark dissector + * that can make sense of the data stored. + */ +#define LINKTYPE_WIRESHARK_UPPER_PDU 252 + +/* + * Link-layer header type for the netlink protocol (nlmon devices). + */ +#define LINKTYPE_NETLINK 253 + +/* + * Bluetooth Linux Monitor headers for the BlueZ stack. + */ +#define LINKTYPE_BLUETOOTH_LINUX_MONITOR 254 + +/* + * Bluetooth Basic Rate/Enhanced Data Rate baseband packets, as + * captured by Ubertooth. + */ +#define LINKTYPE_BLUETOOTH_BREDR_BB 255 + +/* + * Bluetooth Low Energy link layer packets, as captured by Ubertooth. + */ +#define LINKTYPE_BLUETOOTH_LE_LL_WITH_PHDR 256 + +/* + * PROFIBUS data link layer. + */ +#define LINKTYPE_PROFIBUS_DL 257 + + +/* + * Apple's DLT_PKTAP headers. + * + * Sadly, the folks at Apple either had no clue that the DLT_USERn values + * are for internal use within an organization and partners only, and + * didn't know that the right way to get a link-layer header type is to + * ask tcpdump.org for one, or knew and didn't care, so they just + * used DLT_USER2, which causes problems for everything except for + * their version of tcpdump. + * + * So I'll just give them one; hopefully this will show up in a + * libpcap release in time for them to get this into 10.10 Big Sur + * or whatever Mavericks' successor is called. LINKTYPE_PKTAP + * will be 258 *even on OS X*; that is *intentional*, so that + * PKTAP files look the same on *all* OSes (different OSes can have + * different numerical values for a given DLT_, but *MUST NOT* have + * different values for what goes in a file, as files can be moved + * between OSes!). + */ +#define LINKTYPE_PKTAP 258 + +/* + * Ethernet packets preceded by a header giving the last 6 octets + * of the preamble specified by 802.3-2012 Clause 65, section + * 65.1.3.2 "Transmit". + */ +#define LINKTYPE_EPON 259 + +/* + * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format" + * in the PICMG HPM.2 specification. + */ +#define LINKTYPE_IPMI_HPM_2 260 + +/* + * per Joshua Wright , formats for Zwave captures. + */ +#define LINKTYPE_ZWAVE_R1_R2 261 +#define LINKTYPE_ZWAVE_R3 262 + +#define LINKTYPE_MATCHING_MAX 262 /* highest value in the "matching" range */ + +static struct linktype_map { + int dlt; + int linktype; +} map[] = { + /* + * These DLT_* codes have LINKTYPE_* codes with values identical + * to the values of the corresponding DLT_* code. + */ + { DLT_NULL, LINKTYPE_NULL }, + { DLT_EN10MB, LINKTYPE_ETHERNET }, + { DLT_EN3MB, LINKTYPE_EXP_ETHERNET }, + { DLT_AX25, LINKTYPE_AX25 }, + { DLT_PRONET, LINKTYPE_PRONET }, + { DLT_CHAOS, LINKTYPE_CHAOS }, + { DLT_IEEE802, LINKTYPE_IEEE802_5 }, + { DLT_ARCNET, LINKTYPE_ARCNET_BSD }, + { DLT_SLIP, LINKTYPE_SLIP }, + { DLT_PPP, LINKTYPE_PPP }, + { DLT_FDDI, LINKTYPE_FDDI }, + { DLT_SYMANTEC_FIREWALL, LINKTYPE_SYMANTEC_FIREWALL }, + + /* + * These DLT_* codes have different values on different + * platforms; we map them to LINKTYPE_* codes that + * have values that should never be equal to any DLT_* + * code. + */ +#ifdef DLT_FR + /* BSD/OS Frame Relay */ + { DLT_FR, LINKTYPE_FRELAY }, +#endif + + { DLT_ATM_RFC1483, LINKTYPE_ATM_RFC1483 }, + { DLT_RAW, LINKTYPE_RAW }, + { DLT_SLIP_BSDOS, LINKTYPE_SLIP_BSDOS }, + { DLT_PPP_BSDOS, LINKTYPE_PPP_BSDOS }, + + /* BSD/OS Cisco HDLC */ + { DLT_C_HDLC, LINKTYPE_C_HDLC }, + + /* + * These DLT_* codes are not on all platforms, but, so far, + * there don't appear to be any platforms that define + * other codes with those values; we map them to + * different LINKTYPE_* values anyway, just in case. + */ + + /* Linux ATM Classical IP */ + { DLT_ATM_CLIP, LINKTYPE_ATM_CLIP }, + + /* NetBSD sync/async serial PPP (or Cisco HDLC) */ + { DLT_PPP_SERIAL, LINKTYPE_PPP_HDLC }, + + /* NetBSD PPP over Ethernet */ + { DLT_PPP_ETHER, LINKTYPE_PPP_ETHER }, + + /* + * All LINKTYPE_ values between LINKTYPE_MATCHING_MIN + * and LINKTYPE_MATCHING_MAX are mapped to identical + * DLT_ values. + */ + + { -1, -1 } +}; + +int +dlt_to_linktype(int dlt) +{ + int i; + + /* + * DLTs that, on some platforms, have values in the matching range + * but that *don't* have the same value as the corresponding + * LINKTYPE because, for some reason, not all OSes have the + * same value for that DLT (note that the DLT's value might be + * outside the matching range on some of those OSes). + */ + if (dlt == DLT_PFSYNC) + return (LINKTYPE_PFSYNC); + if (dlt == DLT_PKTAP) + return (LINKTYPE_PKTAP); + + /* + * For all other values in the matching range, the DLT + * value is the same as the LINKTYPE value. + */ + if (dlt >= DLT_MATCHING_MIN && dlt <= DLT_MATCHING_MAX) + return (dlt); + + /* + * Map the values outside that range. + */ + for (i = 0; map[i].dlt != -1; i++) { + if (map[i].dlt == dlt) + return (map[i].linktype); + } + + /* + * If we don't have a mapping for this DLT, return an + * error; that means that this is a value with no corresponding + * LINKTYPE, and we need to assign one. + */ + return (-1); +} + +int +linktype_to_dlt(int linktype) +{ + int i; + + /* + * LINKTYPEs in the matching range that *don't* + * have the same value as the corresponding DLTs + * because, for some reason, not all OSes have the + * same value for that DLT. + */ + if (linktype == LINKTYPE_PFSYNC) + return (DLT_PFSYNC); + if (linktype == LINKTYPE_PKTAP) + return (DLT_PKTAP); + + /* + * For all other values in the matching range, the LINKTYPE + * value is the same as the DLT value. + */ + if (linktype >= LINKTYPE_MATCHING_MIN && + linktype <= LINKTYPE_MATCHING_MAX) + return (linktype); + + /* + * Map the values outside that range. + */ + for (i = 0; map[i].linktype != -1; i++) { + if (map[i].linktype == linktype) + return (map[i].dlt); + } + + /* + * If we don't have an entry for this LINKTYPE, return + * the link type value; it may be a DLT from an older + * version of libpcap. + */ + return linktype; +} + +/* + * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host + * byte order when capturing (it's supplied directly from a + * memory-mapped buffer shared by the kernel). + * + * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED capture file, + * we need to convert it from the byte order of the host that wrote + * the file to this host's byte order. + */ +static void +swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, + int header_len_64_bytes) +{ + pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf; + bpf_u_int32 offset = 0; + + /* + * "offset" is the offset *past* the field we're swapping; + * we skip the field *before* checking to make sure + * the captured data length includes the entire field. + */ + + /* + * The URB id is a totally opaque value; do we really need to + * convert it to the reading host's byte order??? + */ + offset += 8; /* skip past id */ + if (hdr->caplen < offset) + return; + uhdr->id = SWAPLL(uhdr->id); + + offset += 4; /* skip past various 1-byte fields */ + + offset += 2; /* skip past bus_id */ + if (hdr->caplen < offset) + return; + uhdr->bus_id = SWAPSHORT(uhdr->bus_id); + + offset += 2; /* skip past various 1-byte fields */ + + offset += 8; /* skip past ts_sec */ + if (hdr->caplen < offset) + return; + uhdr->ts_sec = SWAPLL(uhdr->ts_sec); + + offset += 4; /* skip past ts_usec */ + if (hdr->caplen < offset) + return; + uhdr->ts_usec = SWAPLONG(uhdr->ts_usec); + + offset += 4; /* skip past status */ + if (hdr->caplen < offset) + return; + uhdr->status = SWAPLONG(uhdr->status); + + offset += 4; /* skip past urb_len */ + if (hdr->caplen < offset) + return; + uhdr->urb_len = SWAPLONG(uhdr->urb_len); + + offset += 4; /* skip past data_len */ + if (hdr->caplen < offset) + return; + uhdr->data_len = SWAPLONG(uhdr->data_len); + + if (uhdr->transfer_type == URB_ISOCHRONOUS) { + offset += 4; /* skip past s.iso.error_count */ + if (hdr->caplen < offset) + return; + uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count); + + offset += 4; /* skip past s.iso.numdesc */ + if (hdr->caplen < offset) + return; + uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc); + } else + offset += 8; /* skip USB setup header */ + + /* + * With the old header, there are no isochronous descriptors + * after the header. + * + * With the new header, the actual number of descriptors in + * the header is not s.iso.numdesc, it's ndesc - only the + * first N descriptors, for some value of N, are put into + * the header, and ndesc is set to the actual number copied. + * In addition, if s.iso.numdesc is negative, no descriptors + * are captured, and ndesc is set to 0. + */ + if (header_len_64_bytes) { + /* + * This is either the "version 1" header, with + * 16 bytes of additional fields at the end, or + * a "version 0" header from a memory-mapped + * capture, with 16 bytes of zeroed-out padding + * at the end. Byte swap them as if this were + * a "version 1" header. + */ + offset += 4; /* skip past interval */ + if (hdr->caplen < offset) + return; + uhdr->interval = SWAPLONG(uhdr->interval); + + offset += 4; /* skip past start_frame */ + if (hdr->caplen < offset) + return; + uhdr->start_frame = SWAPLONG(uhdr->start_frame); + + offset += 4; /* skip past xfer_flags */ + if (hdr->caplen < offset) + return; + uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags); + + offset += 4; /* skip past ndesc */ + if (hdr->caplen < offset) + return; + uhdr->ndesc = SWAPLONG(uhdr->ndesc); + + if (uhdr->transfer_type == URB_ISOCHRONOUS) { + /* swap the values in struct linux_usb_isodesc */ + usb_isodesc *pisodesc; + u_int32_t i; + + pisodesc = (usb_isodesc *)(void *)(buf+offset); + for (i = 0; i < uhdr->ndesc; i++) { + offset += 4; /* skip past status */ + if (hdr->caplen < offset) + return; + pisodesc->status = SWAPLONG(pisodesc->status); + + offset += 4; /* skip past offset */ + if (hdr->caplen < offset) + return; + pisodesc->offset = SWAPLONG(pisodesc->offset); + + offset += 4; /* skip past len */ + if (hdr->caplen < offset) + return; + pisodesc->len = SWAPLONG(pisodesc->len); + + offset += 4; /* skip past padding */ + + pisodesc++; + } + } + } +} + +/* + * The DLT_NFLOG "packets" have a mixture of big-endian and host-byte-order + * data. They begin with a fixed-length header with big-endian fields, + * followed by a set of TLVs, where the type and length are in host + * byte order but the values are either big-endian or are a raw byte + * sequence that's the same regardless of the host's byte order. + * + * When reading a DLT_NFLOG capture file, we need to convert the type + * and length values from the byte order of the host that wrote the + * file to the byte order of this host. + */ +static void +swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_char *p = buf; + nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf; + nflog_tlv_t *tlv; + u_int caplen = hdr->caplen; + u_int length = hdr->len; + u_int16_t size; + + if (caplen < (int) sizeof(nflog_hdr_t) || length < (int) sizeof(nflog_hdr_t)) { + /* Not enough data to have any TLVs. */ + return; + } + + if (!(nfhdr->nflog_version) == 0) { + /* Unknown NFLOG version */ + return; + } + + length -= sizeof(nflog_hdr_t); + caplen -= sizeof(nflog_hdr_t); + p += sizeof(nflog_hdr_t); + + while (caplen >= sizeof(nflog_tlv_t)) { + tlv = (nflog_tlv_t *) p; + + /* Swap the type and length. */ + tlv->tlv_type = SWAPSHORT(tlv->tlv_type); + tlv->tlv_length = SWAPSHORT(tlv->tlv_length); + + /* Get the length of the TLV. */ + size = tlv->tlv_length; + if (size % 4 != 0) + size += 4 - size % 4; + + /* Is the TLV's length less than the minimum? */ + if (size < sizeof(nflog_tlv_t)) { + /* Yes. Give up now. */ + return; + } + + /* Do we have enough data for the full TLV? */ + if (caplen < size || length < size) { + /* No. */ + return; + } + + /* Skip over the TLV. */ + length -= size; + caplen -= size; + p += size; + } +} + +void +swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data) +{ + /* + * Convert pseudo-headers from the byte order of + * the host on which the file was saved to our + * byte order, as necessary. + */ + switch (linktype) { + + case DLT_USB_LINUX: + swap_linux_usb_header(hdr, data, 0); + break; + + case DLT_USB_LINUX_MMAPPED: + swap_linux_usb_header(hdr, data, 1); + break; + + case DLT_NFLOG: + swap_nflog_header(hdr, data); + break; + } +} diff --git a/tcpdump/jni/libpcap/pcap-common.h b/tcpdump/jni/libpcap/pcap-common.h new file mode 100644 index 0000000..6ac5bcd --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-common.h @@ -0,0 +1,25 @@ + +/* + * We use the "receiver-makes-right" approach to byte order, + * because time is at a premium when we are writing the file. + * In other words, the pcap_file_header and pcap_pkthdr, + * records are written in host byte order. + * Note that the bytes of packet data are written out in the order in + * which they were received, so multi-byte fields in packets are not + * written in host byte order, they're written in whatever order the + * sending machine put them in. + * + * ntoh[ls] aren't sufficient because we might need to swap on a big-endian + * machine (if the file was written in little-end order). + */ +#define SWAPLONG(y) \ +((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) +#define SWAPSHORT(y) \ + ( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) ) + +extern int dlt_to_linktype(int dlt); + +extern int linktype_to_dlt(int linktype); + +extern void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, + u_char *data); diff --git a/tcpdump/jni/libpcap/pcap-config.1 b/tcpdump/jni/libpcap/pcap-config.1 new file mode 100644 index 0000000..2a2272b --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-config.1 @@ -0,0 +1,72 @@ +.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP-CONFIG 1 "22 May 2009" +.SH NAME +pcap-config \- write libpcap compiler and linker flags to standard output +.SH SYNOPSIS +.na +.B pcap-config +[ +.B \-\-static +] +[ +.B \-\-cflags | \-\-libs | \-\-additional-libs +] +.ad +.SH DESCRIPTION +.LP +When run with the +.B \-\-cflags +option, +.I pcap-config +writes to the standard output the +.B \-I +compiler flags required to include libpcap's header files. +When run with the +.B \-\-libs +option, +.I pcap-config +writes to the standard output the +.B \-L +and +.B \-l +linker flags required to link with libpcap, including +.B \-l +flags for libraries required by libpcap. +When run with the +.B \-\-additional-libs +option, +.I pcap-config +writes to the standard output the +.B \-L +and +.B \-l +flags for libraries required by libpcap, but not the +.B \-lpcap +flag to link with libpcap itself. +.LP +By default, it writes flags appropriate for compiling with a +dynamically-linked version of libpcap; the +.B \-\-static +flag causes it to write flags appropriate for compiling with a +statically-linked version of libpcap. +.SH "SEE ALSO" +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap-config.in b/tcpdump/jni/libpcap/pcap-config.in new file mode 100644 index 0000000..206be3b --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-config.in @@ -0,0 +1,89 @@ +#! /bin/sh + +# +# Script to give the appropriate compiler flags and linker flags +# to use when building code that uses libpcap. +# +prefix="@prefix@" +exec_prefix="@exec_prefix@" +includedir="@includedir@" +libdir="@libdir@" +V_RPATH_OPT="@V_RPATH_OPT@" +LIBS="@LIBS@" + +static=0 +show_cflags=0 +show_libs=0 +while [ "$#" != 0 ] +do + case "$1" in + + --static) + static=1 + ;; + + --cflags) + show_cflags=1 + ;; + + --libs) + show_libs=1 + ;; + + --additional-libs) + show_additional_libs=1 + ;; + esac + shift +done +if [ "$V_RPATH_OPT" != "" ] +then + # + # If libdir isn't /usr/lib, add it to the run-time linker path. + # + if [ "$libdir" != "/usr/lib" ] + then + RPATH=$V_RPATH_OPT$libdir + fi +fi +if [ "$static" = 1 ] +then + # + # Include LIBS so that the flags include libraries containing + # routines that libpcap uses. + # + if [ "$show_cflags" = 1 -a "$show_libs" = 1 ] + then + echo "-I$includedir -L$libdir -lpcap $LIBS" + elif [ "$show_cflags" = 1 -a "$show_additional_libs" = 1 ] + then + echo "-I$includedir -L$libdir $LIBS" + elif [ "$show_cflags" = 1 ] + then + echo "-I$includedir" + elif [ "$show_libs" = 1 ] + then + echo "-L$libdir -lpcap $LIBS" + elif [ "$show_additional_libs" = 1 ] + then + echo "$LIBS" + fi +else + # + # Omit LIBS - libpcap is assumed to be linked with those + # libraries, so there's no need to do so explicitly. + # + if [ "$show_cflags" = 1 -a "$show_libs" = 1 ] + then + echo "-I$includedir -L$libdir $RPATH -lpcap" + elif [ "$show_cflags" = 1 -a "$show_additional_libs" = 1 ] + then + echo "-I$includedir" + elif [ "$show_cflags" = 1 ] + then + echo "-I$includedir" + elif [ "$show_libs" = 1 ] + then + echo "-L$libdir $RPATH -lpcap" + fi +fi diff --git a/tcpdump/jni/libpcap/pcap-dag.c b/tcpdump/jni/libpcap/pcap-dag.c new file mode 100644 index 0000000..4915248 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-dag.c @@ -0,0 +1,1262 @@ +/* + * pcap-dag.c: Packet capture interface for Emulex EndaceDAG cards. + * + * The functionality of this code attempts to mimic that of pcap-linux as much + * as possible. This code is compiled in several different ways depending on + * whether DAG_ONLY and HAVE_DAG_API are defined. If HAVE_DAG_API is not + * defined it should not get compiled in, otherwise if DAG_ONLY is defined then + * the 'dag_' function calls are renamed to 'pcap_' equivalents. If DAG_ONLY + * is not defined then nothing is altered - the dag_ functions will be + * called as required from their pcap-linux/bpf equivalents. + * + * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) + * Modifications: Jesper Peterson + * Koryn Grant + * Stephen Donnelly + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* optionally get BSD define */ + +#include +#include +#include + +#include "pcap-int.h" + +#include +#include +#include +#include +#include +#include + +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ +#include + +#include "dagnew.h" +#include "dagapi.h" +#include "dagpci.h" + +#include "pcap-dag.h" + +/* + * DAG devices have names beginning with "dag", followed by a number + * from 0 to DAG_MAX_BOARDS, then optionally a colon and a stream number + * from 0 to DAG_STREAM_MAX. + */ +#ifndef DAG_MAX_BOARDS +#define DAG_MAX_BOARDS 32 +#endif + +#define ATM_CELL_SIZE 52 +#define ATM_HDR_SIZE 4 + +/* + * A header containing additional MTP information. + */ +#define MTP2_SENT_OFFSET 0 /* 1 byte */ +#define MTP2_ANNEX_A_USED_OFFSET 1 /* 1 byte */ +#define MTP2_LINK_NUMBER_OFFSET 2 /* 2 bytes */ +#define MTP2_HDR_LEN 4 /* length of the header */ + +#define MTP2_ANNEX_A_NOT_USED 0 +#define MTP2_ANNEX_A_USED 1 +#define MTP2_ANNEX_A_USED_UNKNOWN 2 + +/* SunATM pseudo header */ +struct sunatm_hdr { + unsigned char flags; /* destination and traffic type */ + unsigned char vpi; /* VPI */ + unsigned short vci; /* VCI */ +}; + +/* + * Private data for capturing on DAG devices. + */ +struct pcap_dag { + struct pcap_stat stat; +#ifdef HAVE_DAG_STREAMS_API + u_char *dag_mem_bottom; /* DAG card current memory bottom pointer */ + u_char *dag_mem_top; /* DAG card current memory top pointer */ +#else /* HAVE_DAG_STREAMS_API */ + void *dag_mem_base; /* DAG card memory base address */ + u_int dag_mem_bottom; /* DAG card current memory bottom offset */ + u_int dag_mem_top; /* DAG card current memory top offset */ +#endif /* HAVE_DAG_STREAMS_API */ + int dag_fcs_bits; /* Number of checksum bits from link layer */ + int dag_offset_flags; /* Flags to pass to dag_offset(). */ + int dag_stream; /* DAG stream number */ + int dag_timeout; /* timeout specified to pcap_open_live. + * Same as in linux above, introduce + * generally? */ +}; + +typedef struct pcap_dag_node { + struct pcap_dag_node *next; + pcap_t *p; + pid_t pid; +} pcap_dag_node_t; + +static pcap_dag_node_t *pcap_dags = NULL; +static int atexit_handler_installed = 0; +static const unsigned short endian_test_word = 0x0100; + +#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) + +#define MAX_DAG_PACKET 65536 + +static unsigned char TempPkt[MAX_DAG_PACKET]; + +static int dag_setfilter(pcap_t *p, struct bpf_program *fp); +static int dag_stats(pcap_t *p, struct pcap_stat *ps); +static int dag_set_datalink(pcap_t *p, int dlt); +static int dag_get_datalink(pcap_t *p); +static int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf); + +static void +delete_pcap_dag(pcap_t *p) +{ + pcap_dag_node_t *curr = NULL, *prev = NULL; + + for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) { + /* empty */ + } + + if (curr != NULL && curr->p == p) { + if (prev != NULL) { + prev->next = curr->next; + } else { + pcap_dags = curr->next; + } + } +} + +/* + * Performs a graceful shutdown of the DAG card, frees dynamic memory held + * in the pcap_t structure, and closes the file descriptor for the DAG card. + */ + +static void +dag_platform_cleanup(pcap_t *p) +{ + struct pcap_dag *pd; + + if (p != NULL) { + pd = p->priv; +#ifdef HAVE_DAG_STREAMS_API + if(dag_stop_stream(p->fd, pd->dag_stream) < 0) + fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); + + if(dag_detach_stream(p->fd, pd->dag_stream) < 0) + fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); +#else + if(dag_stop(p->fd) < 0) + fprintf(stderr,"dag_stop: %s\n", strerror(errno)); +#endif /* HAVE_DAG_STREAMS_API */ + if(p->fd != -1) { + if(dag_close(p->fd) < 0) + fprintf(stderr,"dag_close: %s\n", strerror(errno)); + p->fd = -1; + } + delete_pcap_dag(p); + pcap_cleanup_live_common(p); + } + /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */ +} + +static void +atexit_handler(void) +{ + while (pcap_dags != NULL) { + if (pcap_dags->pid == getpid()) { + dag_platform_cleanup(pcap_dags->p); + } else { + delete_pcap_dag(pcap_dags->p); + } + } +} + +static int +new_pcap_dag(pcap_t *p) +{ + pcap_dag_node_t *node = NULL; + + if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) { + return -1; + } + + if (!atexit_handler_installed) { + atexit(atexit_handler); + atexit_handler_installed = 1; + } + + node->next = pcap_dags; + node->p = p; + node->pid = getpid(); + + pcap_dags = node; + + return 0; +} + +static unsigned int +dag_erf_ext_header_count(uint8_t * erf, size_t len) +{ + uint32_t hdr_num = 0; + uint8_t hdr_type; + + /* basic sanity checks */ + if ( erf == NULL ) + return 0; + if ( len < 16 ) + return 0; + + /* check if we have any extension headers */ + if ( (erf[8] & 0x80) == 0x00 ) + return 0; + + /* loop over the extension headers */ + do { + + /* sanity check we have enough bytes */ + if ( len < (24 + (hdr_num * 8)) ) + return hdr_num; + + /* get the header type */ + hdr_type = erf[(16 + (hdr_num * 8))]; + hdr_num++; + + } while ( hdr_type & 0x80 ); + + return hdr_num; +} + +/* + * Read at most max_packets from the capture stream and call the callback + * for each of them. Returns the number of packets handled, -1 if an + * error occured, or -2 if we were told to break out of the loop. + */ +static int +dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_dag *pd = p->priv; + unsigned int processed = 0; + int flags = pd->dag_offset_flags; + unsigned int nonblocking = flags & DAGF_NONBLOCK; + unsigned int num_ext_hdr = 0; + unsigned int ticks_per_second; + + /* Get the next bufferful of packets (if necessary). */ + while (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size) { + + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that + * it has, and return -2 to indicate that + * we were told to break out of the loop. + */ + p->break_loop = 0; + return -2; + } + +#ifdef HAVE_DAG_STREAMS_API + /* dag_advance_stream() will block (unless nonblock is called) + * until 64kB of data has accumulated. + * If to_ms is set, it will timeout before 64kB has accumulated. + * We wait for 64kB because processing a few packets at a time + * can cause problems at high packet rates (>200kpps) due + * to inefficiencies. + * This does mean if to_ms is not specified the capture may 'hang' + * for long periods if the data rate is extremely slow (<64kB/sec) + * If non-block is specified it will return immediately. The user + * is then responsible for efficiency. + */ + if ( NULL == (pd->dag_mem_top = dag_advance_stream(p->fd, pd->dag_stream, &(pd->dag_mem_bottom))) ) { + return -1; + } +#else + /* dag_offset does not support timeouts */ + pd->dag_mem_top = dag_offset(p->fd, &(pd->dag_mem_bottom), flags); +#endif /* HAVE_DAG_STREAMS_API */ + + if (nonblocking && (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) + { + /* Pcap is configured to process only available packets, and there aren't any, return immediately. */ + return 0; + } + + if(!nonblocking && + pd->dag_timeout && + (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) + { + /* Blocking mode, but timeout set and no data has arrived, return anyway.*/ + return 0; + } + + } + + /* Process the packets. */ + while (pd->dag_mem_top - pd->dag_mem_bottom >= dag_record_size) { + + unsigned short packet_len = 0; + int caplen = 0; + struct pcap_pkthdr pcap_header; + +#ifdef HAVE_DAG_STREAMS_API + dag_record_t *header = (dag_record_t *)(pd->dag_mem_bottom); +#else + dag_record_t *header = (dag_record_t *)(pd->dag_mem_base + pd->dag_mem_bottom); +#endif /* HAVE_DAG_STREAMS_API */ + + u_char *dp = ((u_char *)header); /* + dag_record_size; */ + unsigned short rlen; + + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that + * it has, and return -2 to indicate that + * we were told to break out of the loop. + */ + p->break_loop = 0; + return -2; + } + + rlen = ntohs(header->rlen); + if (rlen < dag_record_size) + { + strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); + return -1; + } + pd->dag_mem_bottom += rlen; + + /* Count lost packets. */ + switch((header->type & 0x7f)) { + /* in these types the color value overwrites the lctr */ + case TYPE_COLOR_HDLC_POS: + case TYPE_COLOR_ETH: + case TYPE_DSM_COLOR_HDLC_POS: + case TYPE_DSM_COLOR_ETH: + case TYPE_COLOR_MC_HDLC_POS: + case TYPE_COLOR_HASH_ETH: + case TYPE_COLOR_HASH_POS: + break; + + default: + if (header->lctr) { + if (pd->stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { + pd->stat.ps_drop = UINT_MAX; + } else { + pd->stat.ps_drop += ntohs(header->lctr); + } + } + } + + if ((header->type & 0x7f) == TYPE_PAD) { + continue; + } + + num_ext_hdr = dag_erf_ext_header_count(dp, rlen); + + /* ERF encapsulation */ + /* The Extensible Record Format is not dropped for this kind of encapsulation, + * and will be handled as a pseudo header by the decoding application. + * The information carried in the ERF header and in the optional subheader (if present) + * could be merged with the libpcap information, to offer a better decoding. + * The packet length is + * o the length of the packet on the link (header->wlen), + * o plus the length of the ERF header (dag_record_size), as the length of the + * pseudo header will be adjusted during the decoding, + * o plus the length of the optional subheader (if present). + * + * The capture length is header.rlen and the byte stuffing for alignment will be dropped + * if the capture length is greater than the packet length. + */ + if (p->linktype == DLT_ERF) { + packet_len = ntohs(header->wlen) + dag_record_size; + caplen = rlen; + switch ((header->type & 0x7f)) { + case TYPE_MC_AAL5: + case TYPE_MC_ATM: + case TYPE_MC_HDLC: + case TYPE_MC_RAW_CHANNEL: + case TYPE_MC_RAW: + case TYPE_MC_AAL2: + case TYPE_COLOR_MC_HDLC_POS: + packet_len += 4; /* MC header */ + break; + + case TYPE_COLOR_HASH_ETH: + case TYPE_DSM_COLOR_ETH: + case TYPE_COLOR_ETH: + case TYPE_ETH: + packet_len += 2; /* ETH header */ + break; + } /* switch type */ + + /* Include ERF extension headers */ + packet_len += (8 * num_ext_hdr); + + if (caplen > packet_len) { + caplen = packet_len; + } + } else { + /* Other kind of encapsulation according to the header Type */ + + /* Skip over generic ERF header */ + dp += dag_record_size; + /* Skip over extension headers */ + dp += 8 * num_ext_hdr; + + switch((header->type & 0x7f)) { + case TYPE_ATM: + case TYPE_AAL5: + if (header->type == TYPE_AAL5) { + packet_len = ntohs(header->wlen); + caplen = rlen - dag_record_size; + } + case TYPE_MC_ATM: + if (header->type == TYPE_MC_ATM) { + caplen = packet_len = ATM_CELL_SIZE; + dp+=4; + } + case TYPE_MC_AAL5: + if (header->type == TYPE_MC_AAL5) { + packet_len = ntohs(header->wlen); + caplen = rlen - dag_record_size - 4; + dp+=4; + } + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + + if (header->type == TYPE_ATM) { + caplen = packet_len = ATM_CELL_SIZE; + } + if (p->linktype == DLT_SUNATM) { + struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; + unsigned long rawatm; + + rawatm = ntohl(*((unsigned long *)dp)); + sunatm->vci = htons((rawatm >> 4) & 0xffff); + sunatm->vpi = (rawatm >> 20) & 0x00ff; + sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | + ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : + ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : + ((dp[ATM_HDR_SIZE] == 0xaa && + dp[ATM_HDR_SIZE+1] == 0xaa && + dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); + + } else { + packet_len -= ATM_HDR_SIZE; + caplen -= ATM_HDR_SIZE; + dp += ATM_HDR_SIZE; + } + break; + + case TYPE_COLOR_HASH_ETH: + case TYPE_DSM_COLOR_ETH: + case TYPE_COLOR_ETH: + case TYPE_ETH: + packet_len = ntohs(header->wlen); + packet_len -= (pd->dag_fcs_bits >> 3); + caplen = rlen - dag_record_size - 2; + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + if (caplen > packet_len) { + caplen = packet_len; + } + dp += 2; + break; + + case TYPE_COLOR_HASH_POS: + case TYPE_DSM_COLOR_HDLC_POS: + case TYPE_COLOR_HDLC_POS: + case TYPE_HDLC_POS: + packet_len = ntohs(header->wlen); + packet_len -= (pd->dag_fcs_bits >> 3); + caplen = rlen - dag_record_size; + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + if (caplen > packet_len) { + caplen = packet_len; + } + break; + + case TYPE_COLOR_MC_HDLC_POS: + case TYPE_MC_HDLC: + packet_len = ntohs(header->wlen); + packet_len -= (pd->dag_fcs_bits >> 3); + caplen = rlen - dag_record_size - 4; + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + if (caplen > packet_len) { + caplen = packet_len; + } + /* jump the MC_HDLC_HEADER */ + dp += 4; +#ifdef DLT_MTP2_WITH_PHDR + if (p->linktype == DLT_MTP2_WITH_PHDR) { + /* Add the MTP2 Pseudo Header */ + caplen += MTP2_HDR_LEN; + packet_len += MTP2_HDR_LEN; + + TempPkt[MTP2_SENT_OFFSET] = 0; + TempPkt[MTP2_ANNEX_A_USED_OFFSET] = MTP2_ANNEX_A_USED_UNKNOWN; + *(TempPkt+MTP2_LINK_NUMBER_OFFSET) = ((header->rec.mc_hdlc.mc_header>>16)&0x01); + *(TempPkt+MTP2_LINK_NUMBER_OFFSET+1) = ((header->rec.mc_hdlc.mc_header>>24)&0xff); + memcpy(TempPkt+MTP2_HDR_LEN, dp, caplen); + dp = TempPkt; + } +#endif + break; + + case TYPE_IPV4: + case TYPE_IPV6: + packet_len = ntohs(header->wlen); + caplen = rlen - dag_record_size; + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + if (caplen > packet_len) { + caplen = packet_len; + } + break; + + /* These types have no matching 'native' DLT, but can be used with DLT_ERF above */ + case TYPE_MC_RAW: + case TYPE_MC_RAW_CHANNEL: + case TYPE_IP_COUNTER: + case TYPE_TCP_FLOW_COUNTER: + case TYPE_INFINIBAND: + case TYPE_RAW_LINK: + case TYPE_INFINIBAND_LINK: + default: + /* Unhandled ERF type. + * Ignore rather than generating error + */ + continue; + } /* switch type */ + + } /* ERF encapsulation */ + + if (caplen > p->snapshot) + caplen = p->snapshot; + + /* Run the packet filter if there is one. */ + if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { + + /* convert between timestamp formats */ + register unsigned long long ts; + + if (IS_BIGENDIAN()) { + ts = SWAPLL(header->ts); + } else { + ts = header->ts; + } + + switch (p->opt.tstamp_precision) { + case PCAP_TSTAMP_PRECISION_NANO: + ticks_per_second = 1000000000; + break; + case PCAP_TSTAMP_PRECISION_MICRO: + default: + ticks_per_second = 1000000; + break; + + } + pcap_header.ts.tv_sec = ts >> 32; + ts = (ts & 0xffffffffULL) * ticks_per_second; + ts += 0x80000000; /* rounding */ + pcap_header.ts.tv_usec = ts >> 32; + if (pcap_header.ts.tv_usec >= ticks_per_second) { + pcap_header.ts.tv_usec -= ticks_per_second; + pcap_header.ts.tv_sec++; + } + + /* Fill in our own header data */ + pcap_header.caplen = caplen; + pcap_header.len = packet_len; + + /* Count the packet. */ + pd->stat.ps_recv++; + + /* Call the user supplied callback function */ + callback(user, &pcap_header, dp); + + /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ + processed++; + if (processed == cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) + { + /* Reached the user-specified limit. */ + return cnt; + } + } + } + + return processed; +} + +static int +dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) +{ + strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", + PCAP_ERRBUF_SIZE); + return (-1); +} + +/* + * Get a handle for a live capture from the given DAG device. Passing a NULL + * device will result in a failure. The promisc flag is ignored because DAG + * cards are always promiscuous. The to_ms parameter is used in setting the + * API polling parameters. + * + * snaplen is now also ignored, until we get per-stream slen support. Set + * slen with approprite DAG tool BEFORE pcap_activate(). + * + * See also pcap(3). + */ +static int dag_activate(pcap_t* handle) +{ + struct pcap_dag *handlep = handle->priv; +#if 0 + char conf[30]; /* dag configure string */ +#endif + char *s; + int n; + daginf_t* daginf; + char * newDev = NULL; + char * device = handle->opt.source; +#ifdef HAVE_DAG_STREAMS_API + uint32_t mindata; + struct timeval maxwait; + struct timeval poll; +#endif + + if (device == NULL) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno)); + return -1; + } + + /* Initialize some components of the pcap structure. */ + +#ifdef HAVE_DAG_STREAMS_API + newDev = (char *)malloc(strlen(device) + 16); + if (newDev == NULL) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno)); + goto fail; + } + + /* Parse input name to get dag device and stream number if provided */ + if (dag_parse_name(device, newDev, strlen(device) + 16, &handlep->dag_stream) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: %s\n", pcap_strerror(errno)); + goto fail; + } + device = newDev; + + if (handlep->dag_stream%2) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture\n"); + goto fail; + } +#else + if (strncmp(device, "/dev/", 5) != 0) { + newDev = (char *)malloc(strlen(device) + 5); + if (newDev == NULL) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno)); + goto fail; + } + strcpy(newDev, "/dev/"); + strcat(newDev, device); + device = newDev; + } +#endif /* HAVE_DAG_STREAMS_API */ + + /* setup device parameters */ + if((handle->fd = dag_open((char *)device)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno)); + goto fail; + } + +#ifdef HAVE_DAG_STREAMS_API + /* Open requested stream. Can fail if already locked or on error */ + if (dag_attach_stream(handle->fd, handlep->dag_stream, 0, 0) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_attach_stream: %s\n", pcap_strerror(errno)); + goto failclose; + } + + /* Set up default poll parameters for stream + * Can be overridden by pcap_set_nonblock() + */ + if (dag_get_stream_poll(handle->fd, handlep->dag_stream, + &mindata, &maxwait, &poll) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno)); + goto faildetach; + } + + if (handle->opt.immediate) { + /* Call callback immediately. + * XXX - is this the right way to handle this? + */ + mindata = 0; + } else { + /* Amount of data to collect in Bytes before calling callbacks. + * Important for efficiency, but can introduce latency + * at low packet rates if to_ms not set! + */ + mindata = 65536; + } + + /* Obey opt.timeout (was to_ms) if supplied. This is a good idea! + * Recommend 10-100ms. Calls will time out even if no data arrived. + */ + maxwait.tv_sec = handle->opt.timeout/1000; + maxwait.tv_usec = (handle->opt.timeout%1000) * 1000; + + if (dag_set_stream_poll(handle->fd, handlep->dag_stream, + mindata, &maxwait, &poll) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno)); + goto faildetach; + } + +#else + if((handlep->dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno)); + goto failclose; + } + +#endif /* HAVE_DAG_STREAMS_API */ + + /* XXX Not calling dag_configure() to set slen; this is unsafe in + * multi-stream environments as the gpp config is global. + * Once the firmware provides 'per-stream slen' this can be supported + * again via the Config API without side-effects */ +#if 0 + /* set the card snap length to the specified snaplen parameter */ + /* This is a really bad idea, as different cards have different + * valid slen ranges. Should fix in Config API. */ + if (handle->snapshot == 0 || handle->snapshot > MAX_DAG_SNAPLEN) { + handle->snapshot = MAX_DAG_SNAPLEN; + } else if (snaplen < MIN_DAG_SNAPLEN) { + handle->snapshot = MIN_DAG_SNAPLEN; + } + /* snap len has to be a multiple of 4 */ + snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3); + + if(dag_configure(handle->fd, conf) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno)); + goto faildetach; + } +#endif + +#ifdef HAVE_DAG_STREAMS_API + if(dag_start_stream(handle->fd, handlep->dag_stream) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start_stream %s: %s\n", device, pcap_strerror(errno)); + goto faildetach; + } +#else + if(dag_start(handle->fd) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno)); + goto failclose; + } +#endif /* HAVE_DAG_STREAMS_API */ + + /* + * Important! You have to ensure bottom is properly + * initialized to zero on startup, it won't give you + * a compiler warning if you make this mistake! + */ + handlep->dag_mem_bottom = 0; + handlep->dag_mem_top = 0; + + /* + * Find out how many FCS bits we should strip. + * First, query the card to see if it strips the FCS. + */ + daginf = dag_info(handle->fd); + if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code)) { + /* DAG 4.2S and 4.23S already strip the FCS. Stripping the final word again truncates the packet. */ + handlep->dag_fcs_bits = 0; + + /* Note that no FCS will be supplied. */ + handle->linktype_ext = LT_FCS_DATALINK_EXT(0); + } else { + /* + * Start out assuming it's 32 bits. + */ + handlep->dag_fcs_bits = 32; + + /* Allow an environment variable to override. */ + if ((s = getenv("ERF_FCS_BITS")) != NULL) { + if ((n = atoi(s)) == 0 || n == 16 || n == 32) { + handlep->dag_fcs_bits = n; + } else { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n); + goto failstop; + } + } + + /* + * Did the user request that they not be stripped? + */ + if ((s = getenv("ERF_DONT_STRIP_FCS")) != NULL) { + /* Yes. Note the number of bytes that will be + supplied. */ + handle->linktype_ext = LT_FCS_DATALINK_EXT(handlep->dag_fcs_bits/16); + + /* And don't strip them. */ + handlep->dag_fcs_bits = 0; + } + } + + handlep->dag_timeout = handle->opt.timeout; + + handle->linktype = -1; + if (dag_get_datalink(handle) < 0) + goto failstop; + + handle->bufsize = 0; + + if (new_pcap_dag(handle) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno)); + goto failstop; + } + + /* + * "select()" and "poll()" don't work on DAG device descriptors. + */ + handle->selectable_fd = -1; + + if (newDev != NULL) { + free((char *)newDev); + } + + handle->read_op = dag_read; + handle->inject_op = dag_inject; + handle->setfilter_op = dag_setfilter; + handle->setdirection_op = NULL; /* Not implemented.*/ + handle->set_datalink_op = dag_set_datalink; + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = dag_setnonblock; + handle->stats_op = dag_stats; + handle->cleanup_op = dag_platform_cleanup; + handlep->stat.ps_drop = 0; + handlep->stat.ps_recv = 0; + handlep->stat.ps_ifdrop = 0; + return 0; + +#ifdef HAVE_DAG_STREAMS_API +failstop: + if (dag_stop_stream(handle->fd, handlep->dag_stream) < 0) { + fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); + } + +faildetach: + if (dag_detach_stream(handle->fd, handlep->dag_stream) < 0) + fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); +#else +failstop: + if (dag_stop(handle->fd) < 0) + fprintf(stderr,"dag_stop: %s\n", strerror(errno)); +#endif /* HAVE_DAG_STREAMS_API */ + +failclose: + if (dag_close(handle->fd) < 0) + fprintf(stderr,"dag_close: %s\n", strerror(errno)); + delete_pcap_dag(handle); + +fail: + pcap_cleanup_live_common(handle); + if (newDev != NULL) { + free((char *)newDev); + } + + return PCAP_ERROR; +} + +pcap_t *dag_create(const char *device, char *ebuf, int *is_ours) +{ + const char *cp; + char *cpend; + long devnum; + pcap_t *p; +#ifdef HAVE_DAG_STREAMS_API + long stream = 0; +#endif + + /* Does this look like a DAG device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + /* Does it begin with "dag"? */ + if (strncmp(cp, "dag", 3) != 0) { + /* Nope, doesn't begin with "dag" */ + *is_ours = 0; + return NULL; + } + /* Yes - is "dag" followed by a number from 0 to DAG_MAX_BOARDS-1 */ + cp += 3; + devnum = strtol(cp, &cpend, 10); +#ifdef HAVE_DAG_STREAMS_API + if (*cpend == ':') { + /* Followed by a stream number. */ + stream = strtol(++cpend, &cpend, 10); + } +#endif + if (cpend == cp || *cpend != '\0') { + /* Not followed by a number. */ + *is_ours = 0; + return NULL; + } + if (devnum < 0 || devnum >= DAG_MAX_BOARDS) { + /* Followed by a non-valid number. */ + *is_ours = 0; + return NULL; + } +#ifdef HAVE_DAG_STREAMS_API + if (stream <0 || stream >= DAG_STREAM_MAX) { + /* Followed by a non-valid stream number. */ + *is_ours = 0; + return NULL; + } +#endif + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_dag)); + if (p == NULL) + return NULL; + + p->activate_op = dag_activate; + + /* + * We claim that we support microsecond and nanosecond time + * stamps. + * + * XXX Our native precision is 2^-32s, but libpcap doesn't support + * power of two precisions yet. We can convert to either MICRO or NANO. + */ + p->tstamp_precision_count = 2; + p->tstamp_precision_list = malloc(2 * sizeof(u_int)); + if (p->tstamp_precision_list == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + if (p->tstamp_type_list != NULL) + free(p->tstamp_type_list); + free(p); + return NULL; + } + p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; + p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; + return p; +} + +static int +dag_stats(pcap_t *p, struct pcap_stat *ps) { + struct pcap_dag *pd = p->priv; + + /* This needs to be filled out correctly. Hopefully a dagapi call will + provide all necessary information. + */ + /*pd->stat.ps_recv = 0;*/ + /*pd->stat.ps_drop = 0;*/ + + *ps = pd->stat; + + return 0; +} + +/* + * Previously we just generated a list of all possible names and let + * pcap_add_if() attempt to open each one, but with streams this adds up + * to 81 possibilities which is inefficient. + * + * Since we know more about the devices we can prune the tree here. + * pcap_add_if() will still retest each device but the total number of + * open attempts will still be much less than the naive approach. + */ +int +dag_findalldevs(pcap_if_t **devlistp, char *errbuf) +{ + char name[12]; /* XXX - pick a size */ + int ret = 0; + int c; + char dagname[DAGNAME_BUFSIZE]; + int dagstream; + int dagfd; + dag_card_inf_t *inf; + char *description; + + /* Try all the DAGs 0-DAG_MAX_BOARDS */ + for (c = 0; c < DAG_MAX_BOARDS; c++) { + snprintf(name, 12, "dag%d", c); + if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream)) + { + return -1; + } + description = NULL; + if ( (dagfd = dag_open(dagname)) >= 0 ) { + if ((inf = dag_pciinfo(dagfd))) + description = dag_device_name(inf->device_code, 1); + if (pcap_add_if(devlistp, name, 0, description, errbuf) == -1) { + /* + * Failure. + */ + ret = -1; + } +#ifdef HAVE_DAG_STREAMS_API + { + int stream, rxstreams; + rxstreams = dag_rx_get_stream_count(dagfd); + for(stream=0;streamerrbuf, "setfilter: No filter specified", + sizeof(p->errbuf)); + return -1; + } + + /* Make our private copy of the filter */ + + if (install_bpf_program(p, fp) < 0) + return -1; + + return (0); +} + +static int +dag_set_datalink(pcap_t *p, int dlt) +{ + p->linktype = dlt; + + return (0); +} + +static int +dag_setnonblock(pcap_t *p, int nonblock, char *errbuf) +{ + struct pcap_dag *pd = p->priv; + + /* + * Set non-blocking mode on the FD. + * XXX - is that necessary? If not, don't bother calling it, + * and have a "dag_getnonblock()" function that looks at + * "pd->dag_offset_flags". + */ + if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0) + return (-1); +#ifdef HAVE_DAG_STREAMS_API + { + uint32_t mindata; + struct timeval maxwait; + struct timeval poll; + + if (dag_get_stream_poll(p->fd, pd->dag_stream, + &mindata, &maxwait, &poll) < 0) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno)); + return -1; + } + + /* Amount of data to collect in Bytes before calling callbacks. + * Important for efficiency, but can introduce latency + * at low packet rates if to_ms not set! + */ + if(nonblock) + mindata = 0; + else + mindata = 65536; + + if (dag_set_stream_poll(p->fd, pd->dag_stream, + mindata, &maxwait, &poll) < 0) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno)); + return -1; + } + } +#endif /* HAVE_DAG_STREAMS_API */ + if (nonblock) { + pd->dag_offset_flags |= DAGF_NONBLOCK; + } else { + pd->dag_offset_flags &= ~DAGF_NONBLOCK; + } + return (0); +} + +static int +dag_get_datalink(pcap_t *p) +{ + struct pcap_dag *pd = p->priv; + int index=0, dlt_index=0; + uint8_t types[255]; + + memset(types, 0, 255); + + if (p->dlt_list == NULL && (p->dlt_list = malloc(255*sizeof(*(p->dlt_list)))) == NULL) { + (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); + return (-1); + } + + p->linktype = 0; + +#ifdef HAVE_DAG_GET_STREAM_ERF_TYPES + /* Get list of possible ERF types for this card */ + if (dag_get_stream_erf_types(p->fd, pd->dag_stream, types, 255) < 0) { + snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_stream_erf_types: %s", pcap_strerror(errno)); + return (-1); + } + + while (types[index]) { + +#elif defined HAVE_DAG_GET_ERF_TYPES + /* Get list of possible ERF types for this card */ + if (dag_get_erf_types(p->fd, types, 255) < 0) { + snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_erf_types: %s", pcap_strerror(errno)); + return (-1); + } + + while (types[index]) { +#else + /* Check the type through a dagapi call. */ + types[index] = dag_linktype(p->fd); + + { +#endif + switch((types[index] & 0x7f)) { + + case TYPE_HDLC_POS: + case TYPE_COLOR_HDLC_POS: + case TYPE_DSM_COLOR_HDLC_POS: + case TYPE_COLOR_HASH_POS: + + if (p->dlt_list != NULL) { + p->dlt_list[dlt_index++] = DLT_CHDLC; + p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; + p->dlt_list[dlt_index++] = DLT_FRELAY; + } + if(!p->linktype) + p->linktype = DLT_CHDLC; + break; + + case TYPE_ETH: + case TYPE_COLOR_ETH: + case TYPE_DSM_COLOR_ETH: + case TYPE_COLOR_HASH_ETH: + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + if (p->dlt_list != NULL) { + p->dlt_list[dlt_index++] = DLT_EN10MB; + p->dlt_list[dlt_index++] = DLT_DOCSIS; + } + if(!p->linktype) + p->linktype = DLT_EN10MB; + break; + + case TYPE_ATM: + case TYPE_AAL5: + case TYPE_MC_ATM: + case TYPE_MC_AAL5: + if (p->dlt_list != NULL) { + p->dlt_list[dlt_index++] = DLT_ATM_RFC1483; + p->dlt_list[dlt_index++] = DLT_SUNATM; + } + if(!p->linktype) + p->linktype = DLT_ATM_RFC1483; + break; + + case TYPE_COLOR_MC_HDLC_POS: + case TYPE_MC_HDLC: + if (p->dlt_list != NULL) { + p->dlt_list[dlt_index++] = DLT_CHDLC; + p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; + p->dlt_list[dlt_index++] = DLT_FRELAY; + p->dlt_list[dlt_index++] = DLT_MTP2; + p->dlt_list[dlt_index++] = DLT_MTP2_WITH_PHDR; + p->dlt_list[dlt_index++] = DLT_LAPD; + } + if(!p->linktype) + p->linktype = DLT_CHDLC; + break; + + case TYPE_IPV4: + case TYPE_IPV6: + if(!p->linktype) + p->linktype = DLT_RAW; + break; + + case TYPE_LEGACY: + case TYPE_MC_RAW: + case TYPE_MC_RAW_CHANNEL: + case TYPE_IP_COUNTER: + case TYPE_TCP_FLOW_COUNTER: + case TYPE_INFINIBAND: + case TYPE_RAW_LINK: + case TYPE_INFINIBAND_LINK: + default: + /* Libpcap cannot deal with these types yet */ + /* Add no 'native' DLTs, but still covered by DLT_ERF */ + break; + + } /* switch */ + index++; + } + + p->dlt_list[dlt_index++] = DLT_ERF; + + p->dlt_count = dlt_index; + + if(!p->linktype) + p->linktype = DLT_ERF; + + return p->linktype; +} diff --git a/tcpdump/jni/libpcap/pcap-dag.h b/tcpdump/jni/libpcap/pcap-dag.h new file mode 100644 index 0000000..68520dc --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-dag.h @@ -0,0 +1,106 @@ +/* + * pcap-dag.c: Packet capture interface for Endace DAG card. + * + * The functionality of this code attempts to mimic that of pcap-linux as much + * as possible. This code is only needed when compiling in the DAG card code + * at the same time as another type of device. + * + * Author: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) + */ + +pcap_t *dag_create(const char *, char *, int *); +int dag_findalldevs(pcap_if_t **devlistp, char *errbuf); + +#ifndef TYPE_AAL5 +#define TYPE_AAL5 4 +#endif + +#ifndef TYPE_MC_HDLC +#define TYPE_MC_HDLC 5 +#endif + +#ifndef TYPE_MC_RAW +#define TYPE_MC_RAW 6 +#endif + +#ifndef TYPE_MC_ATM +#define TYPE_MC_ATM 7 +#endif + +#ifndef TYPE_MC_RAW_CHANNEL +#define TYPE_MC_RAW_CHANNEL 8 +#endif + +#ifndef TYPE_MC_AAL5 +#define TYPE_MC_AAL5 9 +#endif + +#ifndef TYPE_COLOR_HDLC_POS +#define TYPE_COLOR_HDLC_POS 10 +#endif + +#ifndef TYPE_COLOR_ETH +#define TYPE_COLOR_ETH 11 +#endif + +#ifndef TYPE_MC_AAL2 +#define TYPE_MC_AAL2 12 +#endif + +#ifndef TYPE_IP_COUNTER +#define TYPE_IP_COUNTER 13 +#endif + +#ifndef TYPE_TCP_FLOW_COUNTER +#define TYPE_TCP_FLOW_COUNTER 14 +#endif + +#ifndef TYPE_DSM_COLOR_HDLC_POS +#define TYPE_DSM_COLOR_HDLC_POS 15 +#endif + +#ifndef TYPE_DSM_COLOR_ETH +#define TYPE_DSM_COLOR_ETH 16 +#endif + +#ifndef TYPE_COLOR_MC_HDLC_POS +#define TYPE_COLOR_MC_HDLC_POS 17 +#endif + +#ifndef TYPE_AAL2 +#define TYPE_AAL2 18 +#endif + +#ifndef TYPE_COLOR_HASH_POS +#define TYPE_COLOR_HASH_POS 19 +#endif + +#ifndef TYPE_COLOR_HASH_ETH +#define TYPE_COLOR_HASH_ETH 20 +#endif + +#ifndef TYPE_INFINIBAND +#define TYPE_INFINIBAND 21 +#endif + +#ifndef TYPE_IPV4 +#define TYPE_IPV4 22 +#endif + +#ifndef TYPE_IPV6 +#define TYPE_IPV6 23 +#endif + +#ifndef TYPE_RAW_LINK +#define TYPE_RAW_LINK 24 +#endif + +#ifndef TYPE_INFINIBAND_LINK +#define TYPE_INFINIBAND_LINK 25 +#endif + + + +#ifndef TYPE_PAD +#define TYPE_PAD 48 +#endif diff --git a/tcpdump/jni/libpcap/pcap-dbus.c b/tcpdump/jni/libpcap/pcap-dbus.c new file mode 100644 index 0000000..ab3f125 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-dbus.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2012 Jakub Zawadzki + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include + +#include + +#include "pcap-int.h" +#include "pcap-dbus.h" + +/* + * Private data for capturing on D-Bus. + */ +struct pcap_dbus { + DBusConnection *conn; + u_int packets_read; /* count of packets read */ +}; + +static int +dbus_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + struct pcap_dbus *handlep = handle->priv; + + struct pcap_pkthdr pkth; + DBusMessage *message; + + char *raw_msg; + int raw_msg_len; + + int count = 0; + + message = dbus_connection_pop_message(handlep->conn); + + while (!message) { + // XXX handle->opt.timeout = timeout_ms; + if (!dbus_connection_read_write(handlep->conn, 100)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed"); + return -1; + } + + if (handle->break_loop) { + handle->break_loop = 0; + return -2; + } + + message = dbus_connection_pop_message(handlep->conn); + } + + if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected"); + return -1; + } + + if (dbus_message_marshal(message, &raw_msg, &raw_msg_len)) { + pkth.caplen = pkth.len = raw_msg_len; + /* pkth.caplen = min (payload_len, handle->snapshot); */ + + gettimeofday(&pkth.ts, NULL); + if (handle->fcode.bf_insns == NULL || + bpf_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) { + handlep->packets_read++; + callback(user, &pkth, (u_char *)raw_msg); + count++; + } + + dbus_free(raw_msg); + } + return count; +} + +static int +dbus_write(pcap_t *handle, const void *buf, size_t size) +{ + /* XXX, not tested */ + struct pcap_dbus *handlep = handle->priv; + + DBusError error = DBUS_ERROR_INIT; + DBusMessage *msg; + + if (!(msg = dbus_message_demarshal(buf, size, &error))) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message); + dbus_error_free(&error); + return -1; + } + + dbus_connection_send(handlep->conn, msg, NULL); + dbus_connection_flush(handlep->conn); + + dbus_message_unref(msg); + return 0; +} + +static int +dbus_stats(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_dbus *handlep = handle->priv; + + stats->ps_recv = handlep->packets_read; + stats->ps_drop = 0; + stats->ps_ifdrop = 0; + return 0; +} + +static void +dbus_cleanup(pcap_t *handle) +{ + struct pcap_dbus *handlep = handle->priv; + + dbus_connection_unref(handlep->conn); + + pcap_cleanup_live_common(handle); +} + +static int +dbus_activate(pcap_t *handle) +{ +#define EAVESDROPPING_RULE "eavesdrop=true," + + static const char *rules[] = { + EAVESDROPPING_RULE "type='signal'", + EAVESDROPPING_RULE "type='method_call'", + EAVESDROPPING_RULE "type='method_return'", + EAVESDROPPING_RULE "type='error'", + }; + + #define N_RULES sizeof(rules)/sizeof(rules[0]) + + struct pcap_dbus *handlep = handle->priv; + const char *dev = handle->opt.source; + + DBusError error = DBUS_ERROR_INIT; + int i; + + if (strcmp(dev, "dbus-system") == 0) { + if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message); + dbus_error_free(&error); + return PCAP_ERROR; + } + + } else if (strcmp(dev, "dbus-session") == 0) { + if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SESSION, &error))) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message); + dbus_error_free(&error); + return PCAP_ERROR; + } + + } else if (strncmp(dev, "dbus://", 7) == 0) { + const char *addr = dev + 7; + + if (!(handlep->conn = dbus_connection_open(addr, &error))) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message); + dbus_error_free(&error); + return PCAP_ERROR; + } + + if (!dbus_bus_register(handlep->conn, &error)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message); + dbus_error_free(&error); + return PCAP_ERROR; + } + + } else { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.source); + return PCAP_ERROR; + } + + /* Initialize some components of the pcap structure. */ + handle->bufsize = 0; + handle->offset = 0; + handle->linktype = DLT_DBUS; + handle->read_op = dbus_read; + handle->inject_op = dbus_write; + handle->setfilter_op = install_bpf_program; /* XXX, later add support for dbus_bus_add_match() */ + handle->setdirection_op = NULL; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->stats_op = dbus_stats; + + handle->selectable_fd = handle->fd = -1; + + if (handle->opt.rfmon) { + /* + * Monitor mode doesn't apply to dbus connections. + */ + dbus_cleanup(handle); + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* dbus_connection_set_max_message_size(handlep->conn, handle->snapshot); */ + if (handle->opt.buffer_size != 0) + dbus_connection_set_max_received_size(handlep->conn, handle->opt.buffer_size); + + for (i = 0; i < N_RULES; i++) { + dbus_bus_add_match(handlep->conn, rules[i], &error); + if (dbus_error_is_set(&error)) { + dbus_error_free(&error); + + /* try without eavesdrop */ + dbus_bus_add_match(handlep->conn, rules[i] + strlen(EAVESDROPPING_RULE), &error); + if (dbus_error_is_set(&error)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message); + dbus_error_free(&error); + dbus_cleanup(handle); + return PCAP_ERROR; + } + } + } + + return 0; +} + +pcap_t * +dbus_create(const char *device, char *ebuf, int *is_ours) +{ + pcap_t *p; + + if (strcmp(device, "dbus-system") && + strcmp(device, "dbus-session") && + strncmp(device, "dbus://", 7)) + { + *is_ours = 0; + return NULL; + } + + *is_ours = 1; + p = pcap_create_common(device, ebuf, sizeof (struct pcap_dbus)); + if (p == NULL) + return (NULL); + + p->activate_op = dbus_activate; + return (p); +} + +int +dbus_findalldevs(pcap_if_t **alldevsp, char *err_str) +{ + if (pcap_add_if(alldevsp, "dbus-system", 0, "D-Bus system bus", err_str) < 0) + return -1; + if (pcap_add_if(alldevsp, "dbus-session", 0, "D-Bus session bus", err_str) < 0) + return -1; + return 0; +} + diff --git a/tcpdump/jni/libpcap/pcap-dbus.h b/tcpdump/jni/libpcap/pcap-dbus.h new file mode 100644 index 0000000..67493cc --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-dbus.h @@ -0,0 +1,2 @@ +pcap_t *dbus_create(const char *, char *, int *); +int dbus_findalldevs(pcap_if_t **devlistp, char *errbuf); diff --git a/tcpdump/jni/libpcap/pcap-dlpi.c b/tcpdump/jni/libpcap/pcap-dlpi.c new file mode 100644 index 0000000..c007135 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-dlpi.c @@ -0,0 +1,1763 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), + * University College London, and subsequently modified by + * Guy Harris (guy@alum.mit.edu), Mark Pizzolato + * , + * Mark C. Brown (mbrown@hp.com), and Sagun Shakya . + */ + +/* + * Packet capture routine for DLPI under SunOS 5, HP-UX 9/10/11, and AIX. + * + * Notes: + * + * - The DLIOCRAW ioctl() is specific to SunOS. + * + * - There is a bug in bufmod(7) such that setting the snapshot + * length results in data being left of the front of the packet. + * + * - It might be desirable to use pfmod(7) to filter packets in the + * kernel when possible. + * + * - An older version of the HP-UX DLPI Programmer's Guide, which + * I think was advertised as the 10.20 version, used to be available + * at + * + * http://docs.hp.com/hpux/onlinedocs/B2355-90093/B2355-90093.html + * + * but is no longer available; it can still be found at + * + * http://h21007.www2.hp.com/dspp/files/unprotected/Drivers/Docs/Refs/B2355-90093.pdf + * + * in PDF form. + * + * - The HP-UX 10.x, 11.0, and 11i v1.6 version of the HP-UX DLPI + * Programmer's Guide, which I think was once advertised as the + * 11.00 version is available at + * + * http://docs.hp.com/en/B2355-90139/index.html + * + * - The HP-UX 11i v2 version of the HP-UX DLPI Programmer's Guide + * is available at + * + * http://docs.hp.com/en/B2355-90871/index.html + * + * - All of the HP documents describe raw-mode services, which are + * what we use if DL_HP_RAWDLS is defined. XXX - we use __hpux + * in some places to test for HP-UX, but use DL_HP_RAWDLS in + * other places; do we support any versions of HP-UX without + * DL_HP_RAWDLS? + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#ifdef HAVE_SYS_BUFMOD_H +#include +#endif +#include +#ifdef HAVE_SYS_DLPI_EXT_H +#include +#endif +#ifdef HAVE_HPUX9 +#include +#endif +#ifdef DL_HP_PPA_REQ +#include +#endif +#include +#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) +#include +#endif + +#ifdef HAVE_HPUX9 +#include +#endif + +#include +#ifdef HAVE_HPUX9 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIMITS_H +#include +#else +#define INT_MAX 2147483647 +#endif + +#include "pcap-int.h" +#include "dlpisubs.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#ifndef PCAP_DEV_PREFIX +#ifdef _AIX +#define PCAP_DEV_PREFIX "/dev/dlpi" +#else +#define PCAP_DEV_PREFIX "/dev" +#endif +#endif + +#define MAXDLBUF 8192 + +/* Forwards */ +static char *split_dname(char *, int *, char *); +static int dl_doattach(int, int, char *); +#ifdef DL_HP_RAWDLS +static int dl_dohpuxbind(int, char *); +#endif +static int dlpromiscon(pcap_t *, bpf_u_int32); +static int dlbindreq(int, bpf_u_int32, char *); +static int dlbindack(int, char *, char *, int *); +static int dlokack(int, const char *, char *, char *); +static int dlinforeq(int, char *); +static int dlinfoack(int, char *, char *); + +#ifdef HAVE_DLPI_PASSIVE +static void dlpassive(int, char *); +#endif + +#ifdef DL_HP_RAWDLS +static int dlrawdatareq(int, const u_char *, int); +#endif +static int recv_ack(int, int, const char *, char *, char *, int *); +static char *dlstrerror(bpf_u_int32); +static char *dlprim(bpf_u_int32); +#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) +static char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *); +#endif +static int send_request(int, char *, int, char *, char *); +#ifdef HAVE_HPUX9 +static int dlpi_kread(int, off_t, void *, u_int, char *); +#endif +#ifdef HAVE_DEV_DLPI +static int get_dlpi_ppa(int, const char *, int, char *); +#endif + +/* XXX Needed by HP-UX (at least) */ +static bpf_u_int32 ctlbuf[MAXDLBUF]; +static struct strbuf ctl = { + MAXDLBUF, + 0, + (char *)ctlbuf +}; + +/* + * Cast a buffer to "union DL_primitives" without provoking warnings + * from the compiler. + */ +#define MAKE_DL_PRIMITIVES(ptr) ((union DL_primitives *)(void *)(ptr)) + +static int +pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + int cc; + u_char *bp; + int flags; + struct strbuf data; + + flags = 0; + cc = p->cc; + if (cc == 0) { + data.buf = (char *)p->buffer + p->offset; + data.maxlen = p->bufsize; + data.len = 0; + do { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates + * that it has, and return -2 to + * indicate that we were told to + * break out of the loop. + */ + p->break_loop = 0; + return (-2); + } + /* + * XXX - check for the DLPI primitive, which + * would be DL_HP_RAWDATA_IND on HP-UX + * if we're in raw mode? + */ + if (getmsg(p->fd, &ctl, &data, &flags) < 0) { + /* Don't choke when we get ptraced */ + switch (errno) { + + case EINTR: + cc = 0; + continue; + + case EAGAIN: + return (0); + } + strlcpy(p->errbuf, pcap_strerror(errno), + sizeof(p->errbuf)); + return (-1); + } + cc = data.len; + } while (cc == 0); + bp = p->buffer + p->offset; + } else + bp = p->bp; + + return (pcap_process_pkts(p, callback, user, cnt, bp, cc)); +} + +static int +pcap_inject_dlpi(pcap_t *p, const void *buf, size_t size) +{ +#ifdef DL_HP_RAWDLS + struct pcap_dlpi *pd = p->priv; +#endif + int ret; + +#if defined(DLIOCRAW) + ret = write(p->fd, buf, size); + if (ret == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", + pcap_strerror(errno)); + return (-1); + } +#elif defined(DL_HP_RAWDLS) + if (pd->send_fd < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "send: Output FD couldn't be opened"); + return (-1); + } + ret = dlrawdatareq(pd->send_fd, buf, size); + if (ret == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", + pcap_strerror(errno)); + return (-1); + } + /* + * putmsg() returns either 0 or -1; it doesn't indicate how + * many bytes were written (presumably they were all written + * or none of them were written). OpenBSD's pcap_inject() + * returns the number of bytes written, so, for API compatibility, + * we return the number of bytes we were told to write. + */ + ret = size; +#else /* no raw mode */ + /* + * XXX - this is a pain, because you might have to extract + * the address from the packet and use it in a DL_UNITDATA_REQ + * request. That would be dependent on the link-layer type. + * + * I also don't know what SAP you'd have to bind the descriptor + * to, or whether you'd need separate "receive" and "send" FDs, + * nor do I know whether you'd need different bindings for + * D/I/X Ethernet and 802.3, or for {FDDI,Token Ring} plus + * 802.2 and {FDDI,Token Ring} plus 802.2 plus SNAP. + * + * So, for now, we just return a "you can't send" indication, + * and leave it up to somebody with a DLPI-based system lacking + * both DLIOCRAW and DL_HP_RAWDLS to supply code to implement + * packet transmission on that system. If they do, they should + * send it to us - but should not send us code that assumes + * Ethernet; if the code doesn't work on non-Ethernet interfaces, + * it should check "p->linktype" and reject the send request if + * it's anything other than DLT_EN10MB. + */ + strlcpy(p->errbuf, "send: Not supported on this version of this OS", + PCAP_ERRBUF_SIZE); + ret = -1; +#endif /* raw mode */ + return (ret); +} + +#ifndef DL_IPATM +#define DL_IPATM 0x12 /* ATM Classical IP interface */ +#endif + +#ifdef HAVE_SOLARIS +/* + * For SunATM. + */ +#ifndef A_GET_UNITS +#define A_GET_UNITS (('A'<<8)|118) +#endif /* A_GET_UNITS */ +#ifndef A_PROMISCON_REQ +#define A_PROMISCON_REQ (('A'<<8)|121) +#endif /* A_PROMISCON_REQ */ +#endif /* HAVE_SOLARIS */ + +static void +pcap_cleanup_dlpi(pcap_t *p) +{ +#ifdef DL_HP_RAWDLS + struct pcap_dlpi *pd = p->priv; + + if (pd->send_fd >= 0) { + close(pd->send_fd); + pd->send_fd = -1; + } +#endif + pcap_cleanup_live_common(p); +} + +static int +pcap_activate_dlpi(pcap_t *p) +{ +#ifdef DL_HP_RAWDLS + struct pcap_dlpi *pd = p->priv; +#endif + int status = 0; + int retv; + register char *cp; + int ppa; +#ifdef HAVE_SOLARIS + int isatm = 0; +#endif + register dl_info_ack_t *infop; +#ifdef HAVE_SYS_BUFMOD_H + bpf_u_int32 ss; +#ifdef HAVE_SOLARIS + register char *release; + bpf_u_int32 osmajor, osminor, osmicro; +#endif +#endif + bpf_u_int32 buf[MAXDLBUF]; + char dname[100]; +#ifndef HAVE_DEV_DLPI + char dname2[100]; +#endif + +#ifdef HAVE_DEV_DLPI + /* + ** Remove any "/dev/" on the front of the device. + */ + cp = strrchr(p->opt.source, '/'); + if (cp == NULL) + strlcpy(dname, p->opt.source, sizeof(dname)); + else + strlcpy(dname, cp + 1, sizeof(dname)); + + /* + * Split the device name into a device type name and a unit number; + * chop off the unit number, so "dname" is just a device type name. + */ + cp = split_dname(dname, &ppa, p->errbuf); + if (cp == NULL) { + status = PCAP_ERROR_NO_SUCH_DEVICE; + goto bad; + } + *cp = '\0'; + + /* + * Use "/dev/dlpi" as the device. + * + * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that + * the "dl_mjr_num" field is for the "major number of interface + * driver"; that's the major of "/dev/dlpi" on the system on + * which I tried this, but there may be DLPI devices that + * use a different driver, in which case we may need to + * search "/dev" for the appropriate device with that major + * device number, rather than hardwiring "/dev/dlpi". + */ + cp = "/dev/dlpi"; + if ((p->fd = open(cp, O_RDWR)) < 0) { + if (errno == EPERM || errno == EACCES) + status = PCAP_ERROR_PERM_DENIED; + else + status = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: %s", cp, pcap_strerror(errno)); + goto bad; + } + +#ifdef DL_HP_RAWDLS + /* + * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and + * receiving packets on the same descriptor - you need separate + * descriptors for sending and receiving, bound to different SAPs. + * + * If the open fails, we just leave -1 in "pd->send_fd" and reject + * attempts to send packets, just as if, in pcap-bpf.c, we fail + * to open the BPF device for reading and writing, we just try + * to open it for reading only and, if that succeeds, just let + * the send attempts fail. + */ + pd->send_fd = open(cp, O_RDWR); +#endif + + /* + * Get a table of all PPAs for that device, and search that + * table for the specified device type name and unit number. + */ + ppa = get_dlpi_ppa(p->fd, dname, ppa, p->errbuf); + if (ppa < 0) { + status = ppa; + goto bad; + } +#else + /* + * If the device name begins with "/", assume it begins with + * the pathname of the directory containing the device to open; + * otherwise, concatenate the device directory name and the + * device name. + */ + if (*p->opt.source == '/') + strlcpy(dname, p->opt.source, sizeof(dname)); + else + snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX, + p->opt.source); + + /* + * Get the unit number, and a pointer to the end of the device + * type name. + */ + cp = split_dname(dname, &ppa, p->errbuf); + if (cp == NULL) { + status = PCAP_ERROR_NO_SUCH_DEVICE; + goto bad; + } + + /* + * Make a copy of the device pathname, and then remove the unit + * number from the device pathname. + */ + strlcpy(dname2, dname, sizeof(dname)); + *cp = '\0'; + + /* Try device without unit number */ + if ((p->fd = open(dname, O_RDWR)) < 0) { + if (errno != ENOENT) { + if (errno == EPERM || errno == EACCES) + status = PCAP_ERROR_PERM_DENIED; + else + status = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dname, + pcap_strerror(errno)); + goto bad; + } + + /* Try again with unit number */ + if ((p->fd = open(dname2, O_RDWR)) < 0) { + if (errno == ENOENT) { + status = PCAP_ERROR_NO_SUCH_DEVICE; + + /* + * We provide an error message even + * for this error, for diagnostic + * purposes (so that, for example, + * the app can show the message if the + * user requests it). + * + * In it, we just report "No DLPI device + * found" with the device name, so people + * don't get confused and think, for example, + * that if they can't capture on "lo0" + * on Solaris the fix is to change libpcap + * (or the application that uses it) to + * look for something other than "/dev/lo0", + * as the fix is to look for an operating + * system other than Solaris - you just + * *can't* capture on a loopback interface + * on Solaris, the lack of a DLPI device + * for the loopback interface is just a + * symptom of that inability. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: No DLPI device found", p->opt.source); + } else { + if (errno == EPERM || errno == EACCES) + status = PCAP_ERROR_PERM_DENIED; + else + status = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + dname2, pcap_strerror(errno)); + } + goto bad; + } + /* XXX Assume unit zero */ + ppa = 0; + } +#endif + + /* + ** Attach if "style 2" provider + */ + if (dlinforeq(p->fd, p->errbuf) < 0 || + dlinfoack(p->fd, (char *)buf, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + infop = &(MAKE_DL_PRIMITIVES(buf))->info_ack; +#ifdef HAVE_SOLARIS + if (infop->dl_mac_type == DL_IPATM) + isatm = 1; +#endif + if (infop->dl_provider_style == DL_STYLE2) { + retv = dl_doattach(p->fd, ppa, p->errbuf); + if (retv < 0) { + status = retv; + goto bad; + } +#ifdef DL_HP_RAWDLS + if (pd->send_fd >= 0) { + retv = dl_doattach(pd->send_fd, ppa, p->errbuf); + if (retv < 0) { + status = retv; + goto bad; + } + } +#endif + } + + if (p->opt.rfmon) { + /* + * This device exists, but we don't support monitor mode + * any platforms that support DLPI. + */ + status = PCAP_ERROR_RFMON_NOTSUP; + goto bad; + } + +#ifdef HAVE_DLPI_PASSIVE + /* + * Enable Passive mode to be able to capture on aggregated link. + * Not supported in all Solaris versions. + */ + dlpassive(p->fd, p->errbuf); +#endif + /* + ** Bind (defer if using HP-UX 9 or HP-UX 10.20 or later, totally + ** skip if using SINIX) + */ +#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20_OR_LATER) && !defined(sinix) +#ifdef _AIX + /* + ** AIX. + ** According to IBM's AIX Support Line, the dl_sap value + ** should not be less than 0x600 (1536) for standard Ethernet. + ** However, we seem to get DL_BADADDR - "DLSAP addr in improper + ** format or invalid" - errors if we use 1537 on the "tr0" + ** device, which, given that its name starts with "tr" and that + ** it's IBM, probably means a Token Ring device. (Perhaps we + ** need to use 1537 on "/dev/dlpi/en" because that device is for + ** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and + ** it rejects invalid Ethernet types.) + ** + ** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea + ** says that works on Token Ring (he says that 0 does *not* + ** work; perhaps that's considered an invalid LLC SAP value - I + ** assume the SAP value in a DLPI bind is an LLC SAP for network + ** types that use 802.2 LLC). + */ + if ((dlbindreq(p->fd, 1537, p->errbuf) < 0 && + dlbindreq(p->fd, 2, p->errbuf) < 0) || + dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0) { + status = PCAP_ERROR; + goto bad; + } +#elif defined(DL_HP_RAWDLS) + /* + ** HP-UX 10.0x and 10.1x. + */ + if (dl_dohpuxbind(p->fd, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + if (pd->send_fd >= 0) { + /* + ** XXX - if this fails, just close send_fd and + ** set it to -1, so that you can't send but can + ** still receive? + */ + if (dl_dohpuxbind(pd->send_fd, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + } +#else /* neither AIX nor HP-UX */ + /* + ** Not Sinix, and neither AIX nor HP-UX - Solaris, and any other + ** OS using DLPI. + **/ + if (dlbindreq(p->fd, 0, p->errbuf) < 0 || + dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0) { + status = PCAP_ERROR; + goto bad; + } +#endif /* AIX vs. HP-UX vs. other */ +#endif /* !HP-UX 9 and !HP-UX 10.20 or later and !SINIX */ + +#ifdef HAVE_SOLARIS + if (isatm) { + /* + ** Have to turn on some special ATM promiscuous mode + ** for SunATM. + ** Do *NOT* turn regular promiscuous mode on; it doesn't + ** help, and may break things. + */ + if (strioctl(p->fd, A_PROMISCON_REQ, 0, NULL) < 0) { + status = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A_PROMISCON_REQ: %s", pcap_strerror(errno)); + goto bad; + } + } else +#endif + if (p->opt.promisc) { + /* + ** Enable promiscuous (not necessary on send FD) + */ + retv = dlpromiscon(p, DL_PROMISC_PHYS); + if (retv < 0) { + if (retv == PCAP_ERROR_PERM_DENIED) + status = PCAP_ERROR_PROMISC_PERM_DENIED; + else + status = retv; + goto bad; + } + + /* + ** Try to enable multicast (you would have thought + ** promiscuous would be sufficient). (Skip if using + ** HP-UX or SINIX) (Not necessary on send FD) + */ +#if !defined(__hpux) && !defined(sinix) + retv = dlpromiscon(p, DL_PROMISC_MULTI); + if (retv < 0) + status = PCAP_WARNING; +#endif + } + /* + ** Try to enable SAP promiscuity (when not in promiscuous mode + ** when using HP-UX, when not doing SunATM on Solaris, and never + ** under SINIX) (Not necessary on send FD) + */ +#ifndef sinix +#if defined(__hpux) + /* HP-UX - only do this when not in promiscuous mode */ + if (!p->opt.promisc) { +#elif defined(HAVE_SOLARIS) + /* Solaris - don't do this on SunATM devices */ + if (!isatm) { +#else + /* Everything else (except for SINIX) - always do this */ + { +#endif + retv = dlpromiscon(p, DL_PROMISC_SAP); + if (retv < 0) { + if (p->opt.promisc) { + /* + * Not fatal, since the DL_PROMISC_PHYS mode + * worked. + * + * Report it as a warning, however. + */ + status = PCAP_WARNING; + } else { + /* + * Fatal. + */ + status = retv; + goto bad; + } + } + } +#endif /* sinix */ + + /* + ** HP-UX 9, and HP-UX 10.20 or later, must bind after setting + ** promiscuous options. + */ +#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20_OR_LATER) + if (dl_dohpuxbind(p->fd, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + /* + ** We don't set promiscuous mode on the send FD, but we'll defer + ** binding it anyway, just to keep the HP-UX 9/10.20 or later + ** code together. + */ + if (pd->send_fd >= 0) { + /* + ** XXX - if this fails, just close send_fd and + ** set it to -1, so that you can't send but can + ** still receive? + */ + if (dl_dohpuxbind(pd->send_fd, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + } +#endif + + /* + ** Determine link type + ** XXX - get SAP length and address length as well, for use + ** when sending packets. + */ + if (dlinforeq(p->fd, p->errbuf) < 0 || + dlinfoack(p->fd, (char *)buf, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + + infop = &(MAKE_DL_PRIMITIVES(buf))->info_ack; + if (pcap_process_mactype(p, infop->dl_mac_type) != 0) { + status = PCAP_ERROR; + goto bad; + } + +#ifdef DLIOCRAW + /* + ** This is a non standard SunOS hack to get the full raw link-layer + ** header. + */ + if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { + status = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s", + pcap_strerror(errno)); + goto bad; + } +#endif + +#ifdef HAVE_SYS_BUFMOD_H + ss = p->snapshot; + + /* + ** There is a bug in bufmod(7). When dealing with messages of + ** less than snaplen size it strips data from the beginning not + ** the end. + ** + ** This bug is fixed in 5.3.2. Also, there is a patch available. + ** Ask for bugid 1149065. + */ +#ifdef HAVE_SOLARIS + release = get_release(&osmajor, &osminor, &osmicro); + if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && + getenv("BUFMOD_FIXED") == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.", + release); + ss = 0; + status = PCAP_WARNING; + } +#endif + + /* Push and configure bufmod. */ + if (pcap_conf_bufmod(p, ss) != 0) { + status = PCAP_ERROR; + goto bad; + } +#endif + + /* + ** As the last operation flush the read side. + */ + if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { + status = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", + pcap_strerror(errno)); + goto bad; + } + + /* Allocate data buffer. */ + if (pcap_alloc_databuf(p) != 0) { + status = PCAP_ERROR; + goto bad; + } + + /* + * Success. + * + * "p->fd" is an FD for a STREAMS device, so "select()" and + * "poll()" should work on it. + */ + p->selectable_fd = p->fd; + + p->read_op = pcap_read_dlpi; + p->inject_op = pcap_inject_dlpi; + p->setfilter_op = install_bpf_program; /* no kernel filtering */ + p->setdirection_op = NULL; /* Not implemented.*/ + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcap_getnonblock_fd; + p->setnonblock_op = pcap_setnonblock_fd; + p->stats_op = pcap_stats_dlpi; + p->cleanup_op = pcap_cleanup_dlpi; + + return (status); +bad: + pcap_cleanup_dlpi(p); + return (status); +} + +/* + * Split a device name into a device type name and a unit number; + * return the a pointer to the beginning of the unit number, which + * is the end of the device type name, and set "*unitp" to the unit + * number. + * + * Returns NULL on error, and fills "ebuf" with an error message. + */ +static char * +split_dname(char *device, int *unitp, char *ebuf) +{ + char *cp; + char *eos; + long unit; + + /* + * Look for a number at the end of the device name string. + */ + cp = device + strlen(device) - 1; + if (*cp < '0' || *cp > '9') { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number", + device); + return (NULL); + } + + /* Digits at end of string are unit number */ + while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9') + cp--; + + errno = 0; + unit = strtol(cp, &eos, 10); + if (*eos != '\0') { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device); + return (NULL); + } + if (errno == ERANGE || unit > INT_MAX) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large", + device); + return (NULL); + } + if (unit < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative", + device); + return (NULL); + } + *unitp = (int)unit; + return (cp); +} + +static int +dl_doattach(int fd, int ppa, char *ebuf) +{ + dl_attach_req_t req; + bpf_u_int32 buf[MAXDLBUF]; + int err; + + req.dl_primitive = DL_ATTACH_REQ; + req.dl_ppa = ppa; + if (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf) < 0) + return (PCAP_ERROR); + + err = dlokack(fd, "attach", (char *)buf, ebuf); + if (err < 0) + return (err); + return (0); +} + +#ifdef DL_HP_RAWDLS +static int +dl_dohpuxbind(int fd, char *ebuf) +{ + int hpsap; + int uerror; + bpf_u_int32 buf[MAXDLBUF]; + + /* + * XXX - we start at 22 because we used to use only 22, but + * that was just because that was the value used in some + * sample code from HP. With what value *should* we start? + * Does it matter, given that we're enabling SAP promiscuity + * on the input FD? + */ + hpsap = 22; + for (;;) { + if (dlbindreq(fd, hpsap, ebuf) < 0) + return (-1); + if (dlbindack(fd, (char *)buf, ebuf, &uerror) >= 0) + break; + /* + * For any error other than a UNIX EBUSY, give up. + */ + if (uerror != EBUSY) { + /* + * dlbindack() has already filled in ebuf for + * this error. + */ + return (-1); + } + + /* + * For EBUSY, try the next SAP value; that means that + * somebody else is using that SAP. Clear ebuf so + * that application doesn't report the "Device busy" + * error as a warning. + */ + *ebuf = '\0'; + hpsap++; + if (hpsap > 100) { + strlcpy(ebuf, + "All SAPs from 22 through 100 are in use", + PCAP_ERRBUF_SIZE); + return (-1); + } + } + return (0); +} +#endif + +#define STRINGIFY(n) #n + +static int +dlpromiscon(pcap_t *p, bpf_u_int32 level) +{ + dl_promiscon_req_t req; + bpf_u_int32 buf[MAXDLBUF]; + int err; + + req.dl_primitive = DL_PROMISCON_REQ; + req.dl_level = level; + if (send_request(p->fd, (char *)&req, sizeof(req), "promiscon", + p->errbuf) < 0) + return (PCAP_ERROR); + err = dlokack(p->fd, "promiscon" STRINGIFY(level), (char *)buf, + p->errbuf); + if (err < 0) + return (err); + return (0); +} + +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ +#ifdef HAVE_SOLARIS + int fd; + union { + u_int nunits; + char pad[516]; /* XXX - must be at least 513; is 516 + in "atmgetunits" */ + } buf; + char baname[2+1+1]; + u_int i; + + /* + * We may have to do special magic to get ATM devices. + */ + if ((fd = open("/dev/ba", O_RDWR)) < 0) { + /* + * We couldn't open the "ba" device. + * For now, just give up; perhaps we should + * return an error if the problem is neither + * a "that device doesn't exist" error (ENOENT, + * ENXIO, etc.) or a "you're not allowed to do + * that" error (EPERM, EACCES). + */ + return (0); + } + + if (strioctl(fd, A_GET_UNITS, sizeof(buf), (char *)&buf) < 0) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "A_GET_UNITS: %s", + pcap_strerror(errno)); + return (-1); + } + for (i = 0; i < buf.nunits; i++) { + snprintf(baname, sizeof baname, "ba%u", i); + if (pcap_add_if(alldevsp, baname, 0, NULL, errbuf) < 0) + return (-1); + } +#endif + + return (0); +} + +static int +send_request(int fd, char *ptr, int len, char *what, char *ebuf) +{ + struct strbuf ctl; + int flags; + + ctl.maxlen = 0; + ctl.len = len; + ctl.buf = ptr; + + flags = 0; + if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "send_request: putmsg \"%s\": %s", + what, pcap_strerror(errno)); + return (-1); + } + return (0); +} + +static int +recv_ack(int fd, int size, const char *what, char *bufp, char *ebuf, int *uerror) +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + /* + * Clear out "*uerror", so it's only set for DL_ERROR_ACK/DL_SYSERR, + * making that the only place where EBUSY is treated specially. + */ + if (uerror != NULL) + *uerror = 0; + + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + flags = 0; + if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s", + what, pcap_strerror(errno)); + return (PCAP_ERROR); + } + + dlp = MAKE_DL_PRIMITIVES(ctl.buf); + switch (dlp->dl_primitive) { + + case DL_INFO_ACK: + case DL_BIND_ACK: + case DL_OK_ACK: +#ifdef DL_HP_PPA_ACK + case DL_HP_PPA_ACK: +#endif + /* These are OK */ + break; + + case DL_ERROR_ACK: + switch (dlp->error_ack.dl_errno) { + + case DL_SYSERR: + if (uerror != NULL) + *uerror = dlp->error_ack.dl_unix_errno; + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "recv_ack: %s: UNIX error - %s", + what, pcap_strerror(dlp->error_ack.dl_unix_errno)); + if (dlp->error_ack.dl_unix_errno == EPERM || + dlp->error_ack.dl_unix_errno == EACCES) + return (PCAP_ERROR_PERM_DENIED); + break; + + default: + snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s", + what, dlstrerror(dlp->error_ack.dl_errno)); + if (dlp->error_ack.dl_errno == DL_BADPPA) + return (PCAP_ERROR_NO_SUCH_DEVICE); + else if (dlp->error_ack.dl_errno == DL_ACCESS) + return (PCAP_ERROR_PERM_DENIED); + break; + } + return (PCAP_ERROR); + + default: + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "recv_ack: %s: Unexpected primitive ack %s", + what, dlprim(dlp->dl_primitive)); + return (PCAP_ERROR); + } + + if (ctl.len < size) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "recv_ack: %s: Ack too small (%d < %d)", + what, ctl.len, size); + return (PCAP_ERROR); + } + return (ctl.len); +} + +static char * +dlstrerror(bpf_u_int32 dl_errno) +{ + static char errstring[6+2+8+1]; + + switch (dl_errno) { + + case DL_ACCESS: + return ("Improper permissions for request"); + + case DL_BADADDR: + return ("DLSAP addr in improper format or invalid"); + + case DL_BADCORR: + return ("Seq number not from outstand DL_CONN_IND"); + + case DL_BADDATA: + return ("User data exceeded provider limit"); + + case DL_BADPPA: +#ifdef HAVE_DEV_DLPI + /* + * With a single "/dev/dlpi" device used for all + * DLPI providers, PPAs have nothing to do with + * unit numbers. + */ + return ("Specified PPA was invalid"); +#else + /* + * We have separate devices for separate devices; + * the PPA is just the unit number. + */ + return ("Specified PPA (device unit) was invalid"); +#endif + + case DL_BADPRIM: + return ("Primitive received not known by provider"); + + case DL_BADQOSPARAM: + return ("QOS parameters contained invalid values"); + + case DL_BADQOSTYPE: + return ("QOS structure type is unknown/unsupported"); + + case DL_BADSAP: + return ("Bad LSAP selector"); + + case DL_BADTOKEN: + return ("Token used not an active stream"); + + case DL_BOUND: + return ("Attempted second bind with dl_max_conind"); + + case DL_INITFAILED: + return ("Physical link initialization failed"); + + case DL_NOADDR: + return ("Provider couldn't allocate alternate address"); + + case DL_NOTINIT: + return ("Physical link not initialized"); + + case DL_OUTSTATE: + return ("Primitive issued in improper state"); + + case DL_SYSERR: + return ("UNIX system error occurred"); + + case DL_UNSUPPORTED: + return ("Requested service not supplied by provider"); + + case DL_UNDELIVERABLE: + return ("Previous data unit could not be delivered"); + + case DL_NOTSUPPORTED: + return ("Primitive is known but not supported"); + + case DL_TOOMANY: + return ("Limit exceeded"); + + case DL_NOTENAB: + return ("Promiscuous mode not enabled"); + + case DL_BUSY: + return ("Other streams for PPA in post-attached"); + + case DL_NOAUTO: + return ("Automatic handling XID&TEST not supported"); + + case DL_NOXIDAUTO: + return ("Automatic handling of XID not supported"); + + case DL_NOTESTAUTO: + return ("Automatic handling of TEST not supported"); + + case DL_XIDAUTO: + return ("Automatic handling of XID response"); + + case DL_TESTAUTO: + return ("Automatic handling of TEST response"); + + case DL_PENDING: + return ("Pending outstanding connect indications"); + + default: + sprintf(errstring, "Error %02x", dl_errno); + return (errstring); + } +} + +static char * +dlprim(bpf_u_int32 prim) +{ + static char primbuf[80]; + + switch (prim) { + + case DL_INFO_REQ: + return ("DL_INFO_REQ"); + + case DL_INFO_ACK: + return ("DL_INFO_ACK"); + + case DL_ATTACH_REQ: + return ("DL_ATTACH_REQ"); + + case DL_DETACH_REQ: + return ("DL_DETACH_REQ"); + + case DL_BIND_REQ: + return ("DL_BIND_REQ"); + + case DL_BIND_ACK: + return ("DL_BIND_ACK"); + + case DL_UNBIND_REQ: + return ("DL_UNBIND_REQ"); + + case DL_OK_ACK: + return ("DL_OK_ACK"); + + case DL_ERROR_ACK: + return ("DL_ERROR_ACK"); + + case DL_SUBS_BIND_REQ: + return ("DL_SUBS_BIND_REQ"); + + case DL_SUBS_BIND_ACK: + return ("DL_SUBS_BIND_ACK"); + + case DL_UNITDATA_REQ: + return ("DL_UNITDATA_REQ"); + + case DL_UNITDATA_IND: + return ("DL_UNITDATA_IND"); + + case DL_UDERROR_IND: + return ("DL_UDERROR_IND"); + + case DL_UDQOS_REQ: + return ("DL_UDQOS_REQ"); + + case DL_CONNECT_REQ: + return ("DL_CONNECT_REQ"); + + case DL_CONNECT_IND: + return ("DL_CONNECT_IND"); + + case DL_CONNECT_RES: + return ("DL_CONNECT_RES"); + + case DL_CONNECT_CON: + return ("DL_CONNECT_CON"); + + case DL_TOKEN_REQ: + return ("DL_TOKEN_REQ"); + + case DL_TOKEN_ACK: + return ("DL_TOKEN_ACK"); + + case DL_DISCONNECT_REQ: + return ("DL_DISCONNECT_REQ"); + + case DL_DISCONNECT_IND: + return ("DL_DISCONNECT_IND"); + + case DL_RESET_REQ: + return ("DL_RESET_REQ"); + + case DL_RESET_IND: + return ("DL_RESET_IND"); + + case DL_RESET_RES: + return ("DL_RESET_RES"); + + case DL_RESET_CON: + return ("DL_RESET_CON"); + + default: + (void) sprintf(primbuf, "unknown primitive 0x%x", prim); + return (primbuf); + } +} + +static int +dlbindreq(int fd, bpf_u_int32 sap, char *ebuf) +{ + + dl_bind_req_t req; + + memset((char *)&req, 0, sizeof(req)); + req.dl_primitive = DL_BIND_REQ; + /* XXX - what if neither of these are defined? */ +#if defined(DL_HP_RAWDLS) + req.dl_max_conind = 1; /* XXX magic number */ + req.dl_service_mode = DL_HP_RAWDLS; +#elif defined(DL_CLDLS) + req.dl_service_mode = DL_CLDLS; +#endif + req.dl_sap = sap; + + return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf)); +} + +static int +dlbindack(int fd, char *bufp, char *ebuf, int *uerror) +{ + + return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf, uerror)); +} + +static int +dlokack(int fd, const char *what, char *bufp, char *ebuf) +{ + + return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf, NULL)); +} + + +static int +dlinforeq(int fd, char *ebuf) +{ + dl_info_req_t req; + + req.dl_primitive = DL_INFO_REQ; + + return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf)); +} + +static int +dlinfoack(int fd, char *bufp, char *ebuf) +{ + + return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf, NULL)); +} + +#ifdef HAVE_DLPI_PASSIVE +/* + * Enable DLPI passive mode. We do not care if this request fails, as this + * indicates the underlying DLPI device does not support link aggregation. + */ +static void +dlpassive(int fd, char *ebuf) +{ + dl_passive_req_t req; + bpf_u_int32 buf[MAXDLBUF]; + + req.dl_primitive = DL_PASSIVE_REQ; + + if (send_request(fd, (char *)&req, sizeof(req), "dlpassive", ebuf) == 0) + (void) dlokack(fd, "dlpassive", (char *)buf, ebuf); +} +#endif + +#ifdef DL_HP_RAWDLS +/* + * There's an ack *if* there's an error. + */ +static int +dlrawdatareq(int fd, const u_char *datap, int datalen) +{ + struct strbuf ctl, data; + long buf[MAXDLBUF]; /* XXX - char? */ + union DL_primitives *dlp; + int dlen; + + dlp = MAKE_DL_PRIMITIVES(buf); + + dlp->dl_primitive = DL_HP_RAWDATA_REQ; + dlen = DL_HP_RAWDATA_REQ_SIZE; + + /* + * HP's documentation doesn't appear to show us supplying any + * address pointed to by the control part of the message. + * I think that's what raw mode means - you just send the raw + * packet, you don't specify where to send it to, as that's + * implied by the destination address. + */ + ctl.maxlen = 0; + ctl.len = dlen; + ctl.buf = (void *)buf; + + data.maxlen = 0; + data.len = datalen; + data.buf = (void *)datap; + + return (putmsg(fd, &ctl, &data, 0)); +} +#endif /* DL_HP_RAWDLS */ + +#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) +static char * +get_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp) +{ + char *cp; + static char buf[32]; + + *majorp = 0; + *minorp = 0; + *microp = 0; + if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0) + return ("?"); + cp = buf; + if (!isdigit((unsigned char)*cp)) + return (buf); + *majorp = strtol(cp, &cp, 10); + if (*cp++ != '.') + return (buf); + *minorp = strtol(cp, &cp, 10); + if (*cp++ != '.') + return (buf); + *microp = strtol(cp, &cp, 10); + return (buf); +} +#endif + +#ifdef DL_HP_PPA_REQ +/* + * Under HP-UX 10 and HP-UX 11, we can ask for the ppa + */ + + +/* + * Determine ppa number that specifies ifname. + * + * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member, + * the code that's used here is the old code for HP-UX 10.x. + * + * However, HP-UX 10.20, at least, appears to have such a member + * in its "dl_hp_ppa_info_t" structure, so the new code is used. + * The new code didn't work on an old 10.20 system on which Rick + * Jones of HP tried it, but with later patches installed, it + * worked - it appears that the older system had those members but + * didn't put anything in them, so, if the search by name fails, we + * do the old search. + * + * Rick suggests that making sure your system is "up on the latest + * lancommon/DLPI/driver patches" is probably a good idea; it'd fix + * that problem, as well as allowing libpcap to see packets sent + * from the system on which the libpcap application is being run. + * (On 10.20, in addition to getting the latest patches, you need + * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB; + * a posting to "comp.sys.hp.hpux" at + * + * http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266 + * + * says that, to see the machine's outgoing traffic, you'd need to + * apply the right patches to your system, and also set that variable + * with: + +echo 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem + + * which could be put in, for example, "/sbin/init.d/lan". + * + * Setting the variable is not necessary on HP-UX 11.x. + */ +static int +get_dlpi_ppa(register int fd, register const char *device, register int unit, + register char *ebuf) +{ + register dl_hp_ppa_ack_t *ap; + register dl_hp_ppa_info_t *ipstart, *ip; + register int i; + char dname[100]; + register u_long majdev; + struct stat statbuf; + dl_hp_ppa_req_t req; + char buf[MAXDLBUF]; + char *ppa_data_buf; + dl_hp_ppa_ack_t *dlp; + struct strbuf ctl; + int flags; + int ppa; + + memset((char *)&req, 0, sizeof(req)); + req.dl_primitive = DL_HP_PPA_REQ; + + memset((char *)buf, 0, sizeof(buf)); + if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0) + return (PCAP_ERROR); + + ctl.maxlen = DL_HP_PPA_ACK_SIZE; + ctl.len = 0; + ctl.buf = (char *)buf; + + flags = 0; + /* + * DLPI may return a big chunk of data for a DL_HP_PPA_REQ. The normal + * recv_ack will fail because it set the maxlen to MAXDLBUF (8192) + * which is NOT big enough for a DL_HP_PPA_REQ. + * + * This causes libpcap applications to fail on a system with HP-APA + * installed. + * + * To figure out how big the returned data is, we first call getmsg + * to get the small head and peek at the head to get the actual data + * length, and then issue another getmsg to get the actual PPA data. + */ + /* get the head first */ + if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno)); + return (PCAP_ERROR); + } + + dlp = (dl_hp_ppa_ack_t *)ctl.buf; + if (dlp->dl_primitive != DL_HP_PPA_ACK) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa unexpected primitive ack 0x%x", + (bpf_u_int32)dlp->dl_primitive); + return (PCAP_ERROR); + } + + if (ctl.len < DL_HP_PPA_ACK_SIZE) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa ack too small (%d < %lu)", + ctl.len, (unsigned long)DL_HP_PPA_ACK_SIZE); + return (PCAP_ERROR); + } + + /* allocate buffer */ + if ((ppa_data_buf = (char *)malloc(dlp->dl_length)) == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa malloc: %s", pcap_strerror(errno)); + return (PCAP_ERROR); + } + ctl.maxlen = dlp->dl_length; + ctl.len = 0; + ctl.buf = (char *)ppa_data_buf; + /* get the data */ + if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno)); + free(ppa_data_buf); + return (PCAP_ERROR); + } + if (ctl.len < dlp->dl_length) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa ack too small (%d < %lu)", + ctl.len, (unsigned long)dlp->dl_length); + free(ppa_data_buf); + return (PCAP_ERROR); + } + + ap = (dl_hp_ppa_ack_t *)buf; + ipstart = (dl_hp_ppa_info_t *)ppa_data_buf; + ip = ipstart; + +#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 + /* + * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1" + * member that should, in theory, contain the part of the + * name for the device that comes before the unit number, + * and should also have a "dl_module_id_2" member that may + * contain an alternate name (e.g., I think Ethernet devices + * have both "lan", for "lanN", and "snap", for "snapN", with + * the former being for Ethernet packets and the latter being + * for 802.3/802.2 packets). + * + * Search for the device that has the specified name and + * instance number. + */ + for (i = 0; i < ap->dl_count; i++) { + if ((strcmp((const char *)ip->dl_module_id_1, device) == 0 || + strcmp((const char *)ip->dl_module_id_2, device) == 0) && + ip->dl_instance_num == unit) + break; + + ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); + } +#else + /* + * We don't have that member, so the search is impossible; make it + * look as if the search failed. + */ + i = ap->dl_count; +#endif + + if (i == ap->dl_count) { + /* + * Well, we didn't, or can't, find the device by name. + * + * HP-UX 10.20, whilst it has "dl_module_id_1" and + * "dl_module_id_2" fields in the "dl_hp_ppa_info_t", + * doesn't seem to fill them in unless the system is + * at a reasonably up-to-date patch level. + * + * Older HP-UX 10.x systems might not have those fields + * at all. + * + * Therefore, we'll search for the entry with the major + * device number of a device with the name "/dev/", + * if such a device exists, as the old code did. + */ + snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit); + if (stat(dname, &statbuf) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s", + dname, pcap_strerror(errno)); + return (PCAP_ERROR); + } + majdev = major(statbuf.st_rdev); + + ip = ipstart; + + for (i = 0; i < ap->dl_count; i++) { + if (ip->dl_mjr_num == majdev && + ip->dl_instance_num == unit) + break; + + ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); + } + } + if (i == ap->dl_count) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "can't find /dev/dlpi PPA for %s%d", device, unit); + return (PCAP_ERROR_NO_SUCH_DEVICE); + } + if (ip->dl_hdw_state == HDW_DEAD) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "%s%d: hardware state: DOWN\n", device, unit); + free(ppa_data_buf); + return (PCAP_ERROR); + } + ppa = ip->dl_ppa; + free(ppa_data_buf); + return (ppa); +} +#endif + +#ifdef HAVE_HPUX9 +/* + * Under HP-UX 9, there is no good way to determine the ppa. + * So punt and read it from /dev/kmem. + */ +static struct nlist nl[] = { +#define NL_IFNET 0 + { "ifnet" }, + { "" } +}; + +static char path_vmunix[] = "/hp-ux"; + +/* Determine ppa number that specifies ifname */ +static int +get_dlpi_ppa(register int fd, register const char *ifname, register int unit, + register char *ebuf) +{ + register const char *cp; + register int kd; + void *addr; + struct ifnet ifnet; + char if_name[sizeof(ifnet.if_name) + 1]; + + cp = strrchr(ifname, '/'); + if (cp != NULL) + ifname = cp + 1; + if (nlist(path_vmunix, &nl) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed", + path_vmunix); + return (-1); + } + if (nl[NL_IFNET].n_value == 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "could't find %s kernel symbol", + nl[NL_IFNET].n_name); + return (-1); + } + kd = open("/dev/kmem", O_RDONLY); + if (kd < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s", + pcap_strerror(errno)); + return (-1); + } + if (dlpi_kread(kd, nl[NL_IFNET].n_value, + &addr, sizeof(addr), ebuf) < 0) { + close(kd); + return (-1); + } + for (; addr != NULL; addr = ifnet.if_next) { + if (dlpi_kread(kd, (off_t)addr, + &ifnet, sizeof(ifnet), ebuf) < 0 || + dlpi_kread(kd, (off_t)ifnet.if_name, + if_name, sizeof(ifnet.if_name), ebuf) < 0) { + (void)close(kd); + return (-1); + } + if_name[sizeof(ifnet.if_name)] = '\0'; + if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit) + return (ifnet.if_index); + } + + snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname); + return (-1); +} + +static int +dlpi_kread(register int fd, register off_t addr, + register void *buf, register u_int len, register char *ebuf) +{ + register int cc; + + if (lseek(fd, addr, SEEK_SET) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s", + pcap_strerror(errno)); + return (-1); + } + cc = read(fd, buf, len); + if (cc < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s", + pcap_strerror(errno)); + return (-1); + } else if (cc != len) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc, + len); + return (-1); + } + return (cc); +} +#endif + +pcap_t * +pcap_create_interface(const char *device, char *ebuf) +{ + pcap_t *p; +#ifdef DL_HP_RAWDLS + struct pcap_dlpi *pd; +#endif + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_dlpi)); + if (p == NULL) + return (NULL); + +#ifdef DL_HP_RAWDLS + pd = p->priv; + pd->send_fd = -1; /* it hasn't been opened yet */ +#endif + + p->activate_op = pcap_activate_dlpi; + return (p); +} diff --git a/tcpdump/jni/libpcap/pcap-dos.c b/tcpdump/jni/libpcap/pcap-dos.c new file mode 100644 index 0000000..8632cee --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-dos.c @@ -0,0 +1,1496 @@ +/* + * This file is part of DOS-libpcap + * Ported to DOS/DOSX by G. Vanem + * + * pcap-dos.c: Interface to PKTDRVR, NDIS2 and 32-bit pmode + * network drivers. + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(USE_32BIT_DRIVERS) + #include "msdos/pm_drvr/pmdrvr.h" + #include "msdos/pm_drvr/pci.h" + #include "msdos/pm_drvr/bios32.h" + #include "msdos/pm_drvr/module.h" + #include "msdos/pm_drvr/3c501.h" + #include "msdos/pm_drvr/3c503.h" + #include "msdos/pm_drvr/3c509.h" + #include "msdos/pm_drvr/3c59x.h" + #include "msdos/pm_drvr/3c515.h" + #include "msdos/pm_drvr/3c90x.h" + #include "msdos/pm_drvr/3c575_cb.h" + #include "msdos/pm_drvr/ne.h" + #include "msdos/pm_drvr/wd.h" + #include "msdos/pm_drvr/accton.h" + #include "msdos/pm_drvr/cs89x0.h" + #include "msdos/pm_drvr/rtl8139.h" + #include "msdos/pm_drvr/ne2k-pci.h" +#endif + +#include "pcap.h" +#include "pcap-dos.h" +#include "pcap-int.h" +#include "msdos/pktdrvr.h" + +#ifdef USE_NDIS2 +#include "msdos/ndis2.h" +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(USE_32BIT_DRIVERS) + #define FLUSHK() do { _printk_safe = 1; _printk_flush(); } while (0) + #define NDIS_NEXT_DEV &rtl8139_dev + + static char *rx_pool = NULL; + static void init_32bit (void); + + static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool); + static int pktq_check (struct rx_ringbuf *q); + static int pktq_inc_out (struct rx_ringbuf *q); + static int pktq_in_index (struct rx_ringbuf *q) LOCKED_FUNC; + static void pktq_clear (struct rx_ringbuf *q) LOCKED_FUNC; + + static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q) LOCKED_FUNC; + static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q); + +#else + #define FLUSHK() ((void)0) + #define NDIS_NEXT_DEV NULL +#endif + +/* + * Internal variables/functions in Watt-32 + */ +extern WORD _pktdevclass; +extern BOOL _eth_is_init; +extern int _w32_dynamic_host; +extern int _watt_do_exit; +extern int _watt_is_init; +extern int _w32__bootp_on, _w32__dhcp_on, _w32__rarp_on, _w32__do_mask_req; +extern void (*_w32_usr_post_init) (void); +extern void (*_w32_print_hook)(); + +extern void dbug_write (const char *); /* Watt-32 lib, pcdbug.c */ +extern int pkt_get_mtu (void); + +static int ref_count = 0; + +static u_long mac_count = 0; +static u_long filter_count = 0; + +static volatile BOOL exc_occured = 0; + +static struct device *handle_to_device [20]; + +static int pcap_activate_dos (pcap_t *p); +static int pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, + u_char *data); +static void pcap_cleanup_dos (pcap_t *p); +static int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps); +static int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len); +static int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp); + +static int ndis_probe (struct device *dev); +static int pkt_probe (struct device *dev); + +static void close_driver (void); +static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf); +static int first_init (const char *name, char *ebuf, int promisc); + +static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap, + const u_char *buf); + +/* + * These are the device we always support + */ +static struct device ndis_dev = { + "ndis", + "NDIS2 LanManager", + 0, + 0,0,0,0,0,0, + NDIS_NEXT_DEV, /* NULL or a 32-bit device */ + ndis_probe + }; + +static struct device pkt_dev = { + "pkt", + "Packet-Driver", + 0, + 0,0,0,0,0,0, + &ndis_dev, + pkt_probe + }; + +static struct device *get_device (int fd) +{ + if (fd <= 0 || fd >= sizeof(handle_to_device)/sizeof(handle_to_device[0])) + return (NULL); + return handle_to_device [fd-1]; +} + +/* + * Private data for capturing on MS-DOS. + */ +struct pcap_dos { + void (*wait_proc)(void); /* call proc while waiting */ + struct pcap_stat stat; +}; + +pcap_t *pcap_create_interface (const char *device, char *ebuf) +{ + pcap_t *p; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_dos)); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_dos; + return (p); +} + +/* + * Open MAC-driver with name 'device_name' for live capture of + * network packets. + */ +static int pcap_activate_dos (pcap_t *pcap) +{ + struct pcap_dos *pcapd = pcap->priv; + + if (pcap->opt.rfmon) { + /* + * No monitor mode on DOS. + */ + return (PCAP_ERROR_RFMON_NOTSUP); + } + + if (pcap->snapshot < ETH_MIN+8) + pcap->snapshot = ETH_MIN+8; + + if (pcap->snapshot > ETH_MAX) /* silently accept and truncate large MTUs */ + pcap->snapshot = ETH_MAX; + + pcap->linktype = DLT_EN10MB; /* !! */ + pcap->cleanup_op = pcap_cleanup_dos; + pcap->read_op = pcap_read_dos; + pcap->stats_op = pcap_stats_dos; + pcap->inject_op = pcap_sendpacket_dos; + pcap->setfilter_op = pcap_setfilter_dos; + pcap->setdirection_op = NULL; /* Not implemented.*/ + pcap->fd = ++ref_count; + + if (pcap->fd == 1) /* first time we're called */ + { + if (!init_watt32(pcap, pcap->opt.source, pcap->errbuf) || + !first_init(pcap->opt.source, pcap->errbuf, pcap->opt.promisc)) + { + return (PCAP_ERROR); + } + atexit (close_driver); + } + else if (stricmp(active_dev->name,pcap->opt.source)) + { + snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE, + "Cannot use different devices simultaneously " + "(`%s' vs. `%s')", active_dev->name, pcap->opt.source); + return (PCAP_ERROR); + } + handle_to_device [pcap->fd-1] = active_dev; + return (0); +} + +/* + * Poll the receiver queue and call the pcap callback-handler + * with the packet. + */ +static int +pcap_read_one (pcap_t *p, pcap_handler callback, u_char *data) +{ + struct pcap_dos *pd = p->priv; + struct pcap_pkthdr pcap; + struct timeval now, expiry = { 0,0 }; + BYTE *rx_buf; + int rx_len = 0; + + if (p->opt.timeout > 0) + { + gettimeofday2 (&now, NULL); + expiry.tv_usec = now.tv_usec + 1000UL * p->opt.timeout; + expiry.tv_sec = now.tv_sec; + while (expiry.tv_usec >= 1000000L) + { + expiry.tv_usec -= 1000000L; + expiry.tv_sec++; + } + } + + while (!exc_occured) + { + volatile struct device *dev; /* might be reset by sig_handler */ + + dev = get_device (p->fd); + if (!dev) + break; + + PCAP_ASSERT (dev->copy_rx_buf || dev->peek_rx_buf); + FLUSHK(); + + /* If driver has a zero-copy receive facility, peek at the queue, + * filter it, do the callback and release the buffer. + */ + if (dev->peek_rx_buf) + { + PCAP_ASSERT (dev->release_rx_buf); + rx_len = (*dev->peek_rx_buf) (&rx_buf); + } + else + { + BYTE buf [ETH_MAX+100]; /* add some margin */ + rx_len = (*dev->copy_rx_buf) (buf, p->snapshot); + rx_buf = buf; + } + + if (rx_len > 0) /* got a packet */ + { + mac_count++; + + FLUSHK(); + + pcap.caplen = min (rx_len, p->snapshot); + pcap.len = rx_len; + + if (callback && + (!p->fcode.bf_insns || bpf_filter(p->fcode.bf_insns, rx_buf, pcap.len, pcap.caplen))) + { + filter_count++; + + /* Fix-me!! Should be time of arrival. Not time of + * capture. + */ + gettimeofday2 (&pcap.ts, NULL); + (*callback) (data, &pcap, rx_buf); + } + + if (dev->release_rx_buf) + (*dev->release_rx_buf) (rx_buf); + + if (pcap_pkt_debug > 0) + { + if (callback == watt32_recv_hook) + dbug_write ("pcap_recv_hook\n"); + else dbug_write ("pcap_read_op\n"); + } + FLUSHK(); + return (1); + } + + /* If not to wait for a packet or pcap_cleanup_dos() called from + * e.g. SIGINT handler, exit loop now. + */ + if (p->opt.timeout <= 0 || (volatile int)p->fd <= 0) + break; + + gettimeofday2 (&now, NULL); + + if (timercmp(&now, &expiry, >)) + break; + +#ifndef DJGPP + kbhit(); /* a real CPU hog */ +#endif + + if (p->wait_proc) + (*p->wait_proc)(); /* call yield func */ + } + + if (rx_len < 0) /* receive error */ + { + pd->stat.ps_drop++; +#ifdef USE_32BIT_DRIVERS + if (pcap_pkt_debug > 1) + printk ("pkt-err %s\n", pktInfo.error); +#endif + return (-1); + } + return (0); +} + +static int +pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, u_char *data) +{ + struct pcap_dos *pd = p->priv; + int rc, num = 0; + + while (num <= cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) + { + if (p->fd <= 0) + return (-1); + rc = pcap_read_one (p, callback, data); + if (rc > 0) + num++; + if (rc < 0) + break; + _w32_os_yield(); /* allow SIGINT generation, yield to Win95/NT */ + } + return (num); +} + +/* + * Return network statistics + */ +static int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps) +{ + struct net_device_stats *stats; + struct pcap_dos *pd; + struct device *dev = p ? get_device(p->fd) : NULL; + + if (!dev) + { + strcpy (p->errbuf, "illegal pcap handle"); + return (-1); + } + + if (!dev->get_stats || (stats = (*dev->get_stats)(dev)) == NULL) + { + strcpy (p->errbuf, "device statistics not available"); + return (-1); + } + + FLUSHK(); + + pd = p->priv; + pd->stat.ps_recv = stats->rx_packets; + pd->stat.ps_drop += stats->rx_missed_errors; + pd->stat.ps_ifdrop = stats->rx_dropped + /* queue full */ + stats->rx_errors; /* HW errors */ + if (ps) + *ps = pd->stat; + + return (0); +} + +/* + * Return detailed network/device statistics. + * May be called after 'dev->close' is called. + */ +int pcap_stats_ex (pcap_t *p, struct pcap_stat_ex *se) +{ + struct device *dev = p ? get_device (p->fd) : NULL; + + if (!dev || !dev->get_stats) + { + strlcpy (p->errbuf, "detailed device statistics not available", + PCAP_ERRBUF_SIZE); + return (-1); + } + + if (!strnicmp(dev->name,"pkt",3)) + { + strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics", + PCAP_ERRBUF_SIZE); + return (-1); + } + memcpy (se, (*dev->get_stats)(dev), sizeof(*se)); + return (0); +} + +/* + * Simply store the filter-code for the pcap_read_dos() callback + * Some day the filter-code could be handed down to the active + * device (pkt_rx1.s or 32-bit device interrupt handler). + */ +static int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp) +{ + if (!p) + return (-1); + p->fcode = *fp; + return (0); +} + +/* + * Return # of packets received in pcap_read_dos() + */ +u_long pcap_mac_packets (void) +{ + return (mac_count); +} + +/* + * Return # of packets passed through filter in pcap_read_dos() + */ +u_long pcap_filter_packets (void) +{ + return (filter_count); +} + +/* + * Close pcap device. Not called for offline captures. + */ +static void pcap_cleanup_dos (pcap_t *p) +{ + struct pcap_dos *pd; + + if (p && !exc_occured) + { + pd = p->priv; + if (pcap_stats(p,NULL) < 0) + pd->stat.ps_drop = 0; + if (!get_device(p->fd)) + return; + + handle_to_device [p->fd-1] = NULL; + p->fd = 0; + if (ref_count > 0) + ref_count--; + if (ref_count > 0) + return; + } + close_driver(); +} + +/* + * Return the name of the 1st network interface, + * or NULL if none can be found. + */ +char *pcap_lookupdev (char *ebuf) +{ + struct device *dev; + +#ifdef USE_32BIT_DRIVERS + init_32bit(); +#endif + + for (dev = (struct device*)dev_base; dev; dev = dev->next) + { + PCAP_ASSERT (dev->probe); + + if ((*dev->probe)(dev)) + { + FLUSHK(); + probed_dev = (struct device*) dev; /* remember last probed device */ + return (char*) dev->name; + } + } + + if (ebuf) + strcpy (ebuf, "No driver found"); + return (NULL); +} + +/* + * Gets localnet & netmask from Watt-32. + */ +int pcap_lookupnet (const char *device, bpf_u_int32 *localnet, + bpf_u_int32 *netmask, char *errbuf) +{ + if (!_watt_is_init) + { + strcpy (errbuf, "pcap_open_offline() or pcap_activate() must be " + "called first"); + return (-1); + } + + *netmask = _w32_sin_mask; + *localnet = my_ip_addr & *netmask; + if (*localnet == 0) + { + if (IN_CLASSA(*netmask)) + *localnet = IN_CLASSA_NET; + else if (IN_CLASSB(*netmask)) + *localnet = IN_CLASSB_NET; + else if (IN_CLASSC(*netmask)) + *localnet = IN_CLASSC_NET; + else + { + sprintf (errbuf, "inet class for 0x%lx unknown", *netmask); + return (-1); + } + } + ARGSUSED (device); + return (0); +} + +/* + * Get a list of all interfaces that are present and that we probe okay. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * were up and could be opened. + */ +int pcap_findalldevs (pcap_if_t **alldevsp, char *errbuf) +{ + struct device *dev; + struct sockaddr_ll sa_ll_1, sa_ll_2; + struct sockaddr *addr, *netmask, *broadaddr, *dstaddr; + pcap_if_t *devlist = NULL; + int ret = 0; + size_t addr_size = sizeof(struct sockaddr_ll); + + for (dev = (struct device*)dev_base; dev; dev = dev->next) + { + PCAP_ASSERT (dev->probe); + + if (!(*dev->probe)(dev)) + continue; + + PCAP_ASSERT (dev->close); /* set by probe routine */ + FLUSHK(); + (*dev->close) (dev); + + memset (&sa_ll_1, 0, sizeof(sa_ll_1)); + memset (&sa_ll_2, 0, sizeof(sa_ll_2)); + sa_ll_1.sll_family = AF_PACKET; + sa_ll_2.sll_family = AF_PACKET; + + addr = (struct sockaddr*) &sa_ll_1; + netmask = (struct sockaddr*) &sa_ll_1; + dstaddr = (struct sockaddr*) &sa_ll_1; + broadaddr = (struct sockaddr*) &sa_ll_2; + memset (&sa_ll_2.sll_addr, 0xFF, sizeof(sa_ll_2.sll_addr)); + + if (pcap_add_if(&devlist, dev->name, dev->flags, + dev->long_name, errbuf) < 0) + { + ret = -1; + break; + } + if (add_addr_to_iflist(&devlist,dev->name, dev->flags, addr, addr_size, + netmask, addr_size, broadaddr, addr_size, + dstaddr, addr_size, errbuf) < 0) + { + ret = -1; + break; + } + } + + if (devlist && ret < 0) + { + pcap_freealldevs (devlist); + devlist = NULL; + } + else + if (!devlist) + strcpy (errbuf, "No drivers found"); + + *alldevsp = devlist; + return (ret); +} + +/* + * pcap_assert() is mainly used for debugging + */ +void pcap_assert (const char *what, const char *file, unsigned line) +{ + FLUSHK(); + fprintf (stderr, "%s (%u): Assertion \"%s\" failed\n", + file, line, what); + close_driver(); + _exit (-1); +} + +/* + * For pcap_offline_read(): wait and yield between printing packets + * to simulate the pace packets where actually recorded. + */ +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait) +{ + struct pcap_dos *pd; + if (p) + { + pd = p->priv; + pd->wait_proc = yield; + p->opt.timeout = wait; + } +} + +/* + * Initialise a named network device. + */ +static struct device * +open_driver (const char *dev_name, char *ebuf, int promisc) +{ + struct device *dev; + + for (dev = (struct device*)dev_base; dev; dev = dev->next) + { + PCAP_ASSERT (dev->name); + + if (strcmp (dev_name,dev->name)) + continue; + + if (!probed_dev) /* user didn't call pcap_lookupdev() first */ + { + PCAP_ASSERT (dev->probe); + + if (!(*dev->probe)(dev)) /* call the xx_probe() function */ + { + sprintf (ebuf, "failed to detect device `%s'", dev_name); + return (NULL); + } + probed_dev = dev; /* device is probed okay and may be used */ + } + else if (dev != probed_dev) + { + goto not_probed; + } + + FLUSHK(); + + /* Select what traffic to receive + */ + if (promisc) + dev->flags |= (IFF_ALLMULTI | IFF_PROMISC); + else dev->flags &= ~(IFF_ALLMULTI | IFF_PROMISC); + + PCAP_ASSERT (dev->open); + + if (!(*dev->open)(dev)) + { + sprintf (ebuf, "failed to activate device `%s'", dev_name); + if (pktInfo.error && !strncmp(dev->name,"pkt",3)) + { + strcat (ebuf, ": "); + strcat (ebuf, pktInfo.error); + } + return (NULL); + } + + /* Some devices need this to operate in promiscous mode + */ + if (promisc && dev->set_multicast_list) + (*dev->set_multicast_list) (dev); + + active_dev = dev; /* remember our active device */ + break; + } + + /* 'dev_name' not matched in 'dev_base' list. + */ + if (!dev) + { + sprintf (ebuf, "device `%s' not supported", dev_name); + return (NULL); + } + +not_probed: + if (!probed_dev) + { + sprintf (ebuf, "device `%s' not probed", dev_name); + return (NULL); + } + return (dev); +} + +/* + * Deinitialise MAC driver. + * Set receive mode back to default mode. + */ +static void close_driver (void) +{ + /* !!todo: loop over all 'handle_to_device[]' ? */ + struct device *dev = active_dev; + + if (dev && dev->close) + { + (*dev->close) (dev); + FLUSHK(); + } + + active_dev = NULL; + +#ifdef USE_32BIT_DRIVERS + if (rx_pool) + { + k_free (rx_pool); + rx_pool = NULL; + } + if (dev) + pcibios_exit(); +#endif +} + + +#ifdef __DJGPP__ +static void setup_signals (void (*handler)(int)) +{ + signal (SIGSEGV,handler); + signal (SIGILL, handler); + signal (SIGFPE, handler); +} + +static void exc_handler (int sig) +{ +#ifdef USE_32BIT_DRIVERS + if (active_dev->irq > 0) /* excludes IRQ 0 */ + { + disable_irq (active_dev->irq); + irq_eoi_cmd (active_dev->irq); + _printk_safe = 1; + } +#endif + + switch (sig) + { + case SIGSEGV: + fputs ("Catching SIGSEGV.\n", stderr); + break; + case SIGILL: + fputs ("Catching SIGILL.\n", stderr); + break; + case SIGFPE: + _fpreset(); + fputs ("Catching SIGFPE.\n", stderr); + break; + default: + fprintf (stderr, "Catching signal %d.\n", sig); + } + exc_occured = 1; + pcap_cleanup_dos (NULL); +} +#endif /* __DJGPP__ */ + + +/* + * Open the pcap device for the first client calling pcap_activate() + */ +static int first_init (const char *name, char *ebuf, int promisc) +{ + struct device *dev; + +#ifdef USE_32BIT_DRIVERS + rx_pool = k_calloc (RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE); + if (!rx_pool) + { + strcpy (ebuf, "Not enough memory (Rx pool)"); + return (0); + } +#endif + +#ifdef __DJGPP__ + setup_signals (exc_handler); +#endif + +#ifdef USE_32BIT_DRIVERS + init_32bit(); +#endif + + dev = open_driver (name, ebuf, promisc); + if (!dev) + { +#ifdef USE_32BIT_DRIVERS + k_free (rx_pool); + rx_pool = NULL; +#endif + +#ifdef __DJGPP__ + setup_signals (SIG_DFL); +#endif + return (0); + } + +#ifdef USE_32BIT_DRIVERS + /* + * If driver is NOT a 16-bit "pkt/ndis" driver (having a 'copy_rx_buf' + * set in it's probe handler), initialise near-memory ring-buffer for + * the 32-bit device. + */ + if (dev->copy_rx_buf == NULL) + { + dev->get_rx_buf = get_rxbuf; + dev->peek_rx_buf = peek_rxbuf; + dev->release_rx_buf = release_rxbuf; + pktq_init (&dev->queue, RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE, rx_pool); + } +#endif + return (1); +} + +#ifdef USE_32BIT_DRIVERS +static void init_32bit (void) +{ + static int init_pci = 0; + + if (!_printk_file) + _printk_init (64*1024, NULL); /* calls atexit(printk_exit) */ + + if (!init_pci) + (void)pci_init(); /* init BIOS32+PCI interface */ + init_pci = 1; +} +#endif + + +/* + * Hook functions for using Watt-32 together with pcap + */ +static char rxbuf [ETH_MAX+100]; /* rx-buffer with some margin */ +static WORD etype; +static pcap_t pcap_save; + +static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap, + const u_char *buf) +{ + /* Fix me: assumes Ethernet II only */ + struct ether_header *ep = (struct ether_header*) buf; + + memcpy (rxbuf, buf, pcap->caplen); + etype = ep->ether_type; + ARGSUSED (dummy); +} + +#if (WATTCP_VER >= 0x0224) +/* + * This function is used by Watt-32 to poll for a packet. + * i.e. it's set to bypass _eth_arrived() + */ +static void *pcap_recv_hook (WORD *type) +{ + int len = pcap_read_dos (&pcap_save, 1, watt32_recv_hook, NULL); + + if (len < 0) + return (NULL); + + *type = etype; + return (void*) &rxbuf; +} + +/* + * This function is called by Watt-32 (via _eth_xmit_hook). + * If dbug_init() was called, we should trace packets sent. + */ +static int pcap_xmit_hook (const void *buf, unsigned len) +{ + int rc = 0; + + if (pcap_pkt_debug > 0) + dbug_write ("pcap_xmit_hook: "); + + if (active_dev && active_dev->xmit) + if ((*active_dev->xmit) (active_dev, buf, len) > 0) + rc = len; + + if (pcap_pkt_debug > 0) + dbug_write (rc ? "ok\n" : "fail\n"); + return (rc); +} +#endif + +static int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len) +{ + struct device *dev = p ? get_device(p->fd) : NULL; + + if (!dev || !dev->xmit) + return (-1); + return (*dev->xmit) (dev, buf, len); +} + +/* + * This function is called by Watt-32 in tcp_post_init(). + * We should prevent Watt-32 from using BOOTP/DHCP/RARP etc. + */ +static void (*prev_post_hook) (void); + +static void pcap_init_hook (void) +{ + _w32__bootp_on = _w32__dhcp_on = _w32__rarp_on = 0; + _w32__do_mask_req = 0; + _w32_dynamic_host = 0; + if (prev_post_hook) + (*prev_post_hook)(); +} + +/* + * Supress PRINT message from Watt-32's sock_init() + */ +static void null_print (void) {} + +/* + * To use features of Watt-32 (netdb functions and socket etc.) + * we must call sock_init(). But we set various hooks to prevent + * using normal PKTDRVR functions in pcpkt.c. This should hopefully + * make Watt-32 and pcap co-operate. + */ +static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf) +{ + char *env; + int rc, MTU, has_ip_addr; + int using_pktdrv = 1; + + /* If user called sock_init() first, we need to reinit in + * order to open debug/trace-file properly + */ + if (_watt_is_init) + sock_exit(); + + env = getenv ("PCAP_DEBUG"); + if (env && atoi(env) > 0 && + pcap_pkt_debug < 0) /* if not already set */ + { + dbug_init(); + pcap_pkt_debug = atoi (env); + } + + _watt_do_exit = 0; /* prevent sock_init() calling exit() */ + prev_post_hook = _w32_usr_post_init; + _w32_usr_post_init = pcap_init_hook; + _w32_print_hook = null_print; + + if (dev_name && strncmp(dev_name,"pkt",3)) + using_pktdrv = FALSE; + + rc = sock_init(); + has_ip_addr = (rc != 8); /* IP-address assignment failed */ + + /* if pcap is using a 32-bit driver w/o a pktdrvr loaded, we + * just pretend Watt-32 is initialised okay. + * + * !! fix-me: The Watt-32 config isn't done if no pktdrvr + * was found. In that case my_ip_addr + sin_mask + * have default values. Should be taken from another + * ini-file/environment in any case (ref. tcpdump.ini) + */ + _watt_is_init = 1; + + if (!using_pktdrv || !has_ip_addr) /* for now .... */ + { + static const char myip[] = "192.168.0.1"; + static const char mask[] = "255.255.255.0"; + + printf ("Just guessing, using IP %s and netmask %s\n", myip, mask); + my_ip_addr = aton (myip); + _w32_sin_mask = aton (mask); + } + else if (rc && using_pktdrv) + { + sprintf (err_buf, "sock_init() failed, code %d", rc); + return (0); + } + + /* Set recv-hook for peeking in _eth_arrived(). + */ +#if (WATTCP_VER >= 0x0224) + _eth_recv_hook = pcap_recv_hook; + _eth_xmit_hook = pcap_xmit_hook; +#endif + + /* Free the pkt-drvr handle allocated in pkt_init(). + * The above hooks should thus use the handle reopened in open_driver() + */ + if (using_pktdrv) + { + _eth_release(); +/* _eth_is_init = 1; */ /* hack to get Rx/Tx-hooks in Watt-32 working */ + } + + memcpy (&pcap_save, pcap, sizeof(pcap_save)); + MTU = pkt_get_mtu(); + pcap_save.fcode.bf_insns = NULL; + pcap_save.linktype = _eth_get_hwtype (NULL, NULL); + pcap_save.snapshot = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */ + +#if 1 + /* prevent use of resolve() and resolve_ip() + */ + last_nameserver = 0; +#endif + return (1); +} + +int EISA_bus = 0; /* Where is natural place for this? */ + +/* + * Application config hooks to set various driver parameters. + */ + +static const struct config_table debug_tab[] = { + { "PKT.DEBUG", ARG_ATOI, &pcap_pkt_debug }, + { "PKT.VECTOR", ARG_ATOX_W, NULL }, + { "NDIS.DEBUG", ARG_ATOI, NULL }, +#ifdef USE_32BIT_DRIVERS + { "3C503.DEBUG", ARG_ATOI, &ei_debug }, + { "3C503.IO_BASE", ARG_ATOX_W, &el2_dev.base_addr }, + { "3C503.MEMORY", ARG_ATOX_W, &el2_dev.mem_start }, + { "3C503.IRQ", ARG_ATOI, &el2_dev.irq }, + { "3C505.DEBUG", ARG_ATOI, NULL }, + { "3C505.BASE", ARG_ATOX_W, NULL }, + { "3C507.DEBUG", ARG_ATOI, NULL }, + { "3C509.DEBUG", ARG_ATOI, &el3_debug }, + { "3C509.ILOOP", ARG_ATOI, &el3_max_loop }, + { "3C529.DEBUG", ARG_ATOI, NULL }, + { "3C575.DEBUG", ARG_ATOI, &debug_3c575 }, + { "3C59X.DEBUG", ARG_ATOI, &vortex_debug }, + { "3C59X.IFACE0", ARG_ATOI, &vortex_options[0] }, + { "3C59X.IFACE1", ARG_ATOI, &vortex_options[1] }, + { "3C59X.IFACE2", ARG_ATOI, &vortex_options[2] }, + { "3C59X.IFACE3", ARG_ATOI, &vortex_options[3] }, + { "3C90X.DEBUG", ARG_ATOX_W, &tc90xbc_debug }, + { "ACCT.DEBUG", ARG_ATOI, ðpk_debug }, + { "CS89.DEBUG", ARG_ATOI, &cs89_debug }, + { "RTL8139.DEBUG", ARG_ATOI, &rtl8139_debug }, + /* { "RTL8139.FDUPLEX", ARG_ATOI, &rtl8139_options }, */ + { "SMC.DEBUG", ARG_ATOI, &ei_debug }, + /* { "E100.DEBUG", ARG_ATOI, &e100_debug }, */ + { "PCI.DEBUG", ARG_ATOI, &pci_debug }, + { "BIOS32.DEBUG", ARG_ATOI, &bios32_debug }, + { "IRQ.DEBUG", ARG_ATOI, &irq_debug }, + { "TIMER.IRQ", ARG_ATOI, &timer_irq }, +#endif + { NULL } + }; + +/* + * pcap_config_hook() is an extension to application's config + * handling. Uses Watt-32's config-table function. + */ +int pcap_config_hook (const char *name, const char *value) +{ + return parse_config_table (debug_tab, NULL, name, value); +} + +/* + * Linked list of supported devices + */ +struct device *active_dev = NULL; /* the device we have opened */ +struct device *probed_dev = NULL; /* the device we have probed */ +const struct device *dev_base = &pkt_dev; /* list of network devices */ + +/* + * PKTDRVR device functions + */ +int pcap_pkt_debug = -1; + +static void pkt_close (struct device *dev) +{ + BOOL okay = PktExitDriver(); + + if (pcap_pkt_debug > 1) + fprintf (stderr, "pkt_close(): %d\n", okay); + + if (dev->priv) + free (dev->priv); + dev->priv = NULL; +} + +static int pkt_open (struct device *dev) +{ + PKT_RX_MODE mode; + + if (dev->flags & IFF_PROMISC) + mode = PDRX_ALL_PACKETS; + else mode = PDRX_BROADCAST; + + if (!PktInitDriver(mode)) + return (0); + + PktResetStatistics (pktInfo.handle); + PktQueueBusy (FALSE); + return (1); +} + +static int pkt_xmit (struct device *dev, const void *buf, int len) +{ + struct net_device_stats *stats = (struct net_device_stats*) dev->priv; + + if (pcap_pkt_debug > 0) + dbug_write ("pcap_xmit\n"); + + if (!PktTransmit(buf,len)) + { + stats->tx_errors++; + return (0); + } + return (len); +} + +static void *pkt_stats (struct device *dev) +{ + struct net_device_stats *stats = (struct net_device_stats*) dev->priv; + + if (!stats || !PktSessStatistics(pktInfo.handle)) + return (NULL); + + stats->rx_packets = pktStat.inPackets; + stats->rx_errors = pktStat.lost; + stats->rx_missed_errors = PktRxDropped(); + return (stats); +} + +static int pkt_probe (struct device *dev) +{ + if (!PktSearchDriver()) + return (0); + + dev->open = pkt_open; + dev->xmit = pkt_xmit; + dev->close = pkt_close; + dev->get_stats = pkt_stats; + dev->copy_rx_buf = PktReceive; /* farmem peek and copy routine */ + dev->get_rx_buf = NULL; + dev->peek_rx_buf = NULL; + dev->release_rx_buf = NULL; + dev->priv = calloc (sizeof(struct net_device_stats), 1); + if (!dev->priv) + return (0); + return (1); +} + +/* + * NDIS device functions + */ +static void ndis_close (struct device *dev) +{ +#ifdef USE_NDIS2 + NdisShutdown(); +#endif + ARGSUSED (dev); +} + +static int ndis_open (struct device *dev) +{ + int promis = (dev->flags & IFF_PROMISC); + +#ifdef USE_NDIS2 + if (!NdisInit(promis)) + return (0); + return (1); +#else + ARGSUSED (promis); + return (0); +#endif +} + +static void *ndis_stats (struct device *dev) +{ + static struct net_device_stats stats; + + /* to-do */ + ARGSUSED (dev); + return (&stats); +} + +static int ndis_probe (struct device *dev) +{ +#ifdef USE_NDIS2 + if (!NdisOpen()) + return (0); +#endif + + dev->open = ndis_open; + dev->xmit = NULL; + dev->close = ndis_close; + dev->get_stats = ndis_stats; + dev->copy_rx_buf = NULL; /* to-do */ + dev->get_rx_buf = NULL; /* upcall is from rmode driver */ + dev->peek_rx_buf = NULL; + dev->release_rx_buf = NULL; + return (0); +} + +/* + * Search & probe for supported 32-bit (pmode) pcap devices + */ +#if defined(USE_32BIT_DRIVERS) + +struct device el2_dev LOCKED_VAR = { + "3c503", + "EtherLink II", + 0, + 0,0,0,0,0,0, + NULL, + el2_probe + }; + +struct device el3_dev LOCKED_VAR = { + "3c509", + "EtherLink III", + 0, + 0,0,0,0,0,0, + &el2_dev, + el3_probe + }; + +struct device tc515_dev LOCKED_VAR = { + "3c515", + "EtherLink PCI", + 0, + 0,0,0,0,0,0, + &el3_dev, + tc515_probe + }; + +struct device tc59_dev LOCKED_VAR = { + "3c59x", + "EtherLink PCI", + 0, + 0,0,0,0,0,0, + &tc515_dev, + tc59x_probe + }; + +struct device tc90xbc_dev LOCKED_VAR = { + "3c90x", + "EtherLink 90X", + 0, + 0,0,0,0,0,0, + &tc59_dev, + tc90xbc_probe + }; + +struct device wd_dev LOCKED_VAR = { + "wd", + "Westen Digital", + 0, + 0,0,0,0,0,0, + &tc90xbc_dev, + wd_probe + }; + +struct device ne_dev LOCKED_VAR = { + "ne", + "NEx000", + 0, + 0,0,0,0,0,0, + &wd_dev, + ne_probe + }; + +struct device acct_dev LOCKED_VAR = { + "acct", + "Accton EtherPocket", + 0, + 0,0,0,0,0,0, + &ne_dev, + ethpk_probe + }; + +struct device cs89_dev LOCKED_VAR = { + "cs89", + "Crystal Semiconductor", + 0, + 0,0,0,0,0,0, + &acct_dev, + cs89x0_probe + }; + +struct device rtl8139_dev LOCKED_VAR = { + "rtl8139", + "RealTek PCI", + 0, + 0,0,0,0,0,0, + &cs89_dev, + rtl8139_probe /* dev->probe routine */ + }; + +/* + * Dequeue routine is called by polling. + * NOTE: the queue-element is not copied, only a pointer is + * returned at '*buf' + */ +int peek_rxbuf (BYTE **buf) +{ + struct rx_elem *tail, *head; + + PCAP_ASSERT (pktq_check (&active_dev->queue)); + + DISABLE(); + tail = pktq_out_elem (&active_dev->queue); + head = pktq_in_elem (&active_dev->queue); + ENABLE(); + + if (head != tail) + { + PCAP_ASSERT (tail->size < active_dev->queue.elem_size-4-2); + + *buf = &tail->data[0]; + return (tail->size); + } + *buf = NULL; + return (0); +} + +/* + * Release buffer we peeked at above. + */ +int release_rxbuf (BYTE *buf) +{ +#ifndef NDEBUG + struct rx_elem *tail = pktq_out_elem (&active_dev->queue); + + PCAP_ASSERT (&tail->data[0] == buf); +#else + ARGSUSED (buf); +#endif + pktq_inc_out (&active_dev->queue); + return (1); +} + +/* + * get_rxbuf() routine (in locked code) is called from IRQ handler + * to request a buffer. Interrupts are disabled and we have a 32kB stack. + */ +BYTE *get_rxbuf (int len) +{ + int idx; + + if (len < ETH_MIN || len > ETH_MAX) + return (NULL); + + idx = pktq_in_index (&active_dev->queue); + +#ifdef DEBUG + { + static int fan_idx LOCKED_VAR = 0; + writew ("-\\|/"[fan_idx++] | (15 << 8), /* white on black colour */ + 0xB8000 + 2*79); /* upper-right corner, 80-col colour screen */ + fan_idx &= 3; + } +/* writew (idx + '0' + 0x0F00, 0xB8000 + 2*78); */ +#endif + + if (idx != active_dev->queue.out_index) + { + struct rx_elem *head = pktq_in_elem (&active_dev->queue); + + head->size = len; + active_dev->queue.in_index = idx; + return (&head->data[0]); + } + + /* !!to-do: drop 25% of the oldest element + */ + pktq_clear (&active_dev->queue); + return (NULL); +} + +/* + * Simple ring-buffer queue handler for reception of packets + * from network driver. + */ +#define PKTQ_MARKER 0xDEADBEEF + +static int pktq_check (struct rx_ringbuf *q) +{ +#ifndef NDEBUG + int i; + char *buf; +#endif + + if (!q || !q->num_elem || !q->buf_start) + return (0); + +#ifndef NDEBUG + buf = q->buf_start; + + for (i = 0; i < q->num_elem; i++) + { + buf += q->elem_size; + if (*(DWORD*)(buf - sizeof(DWORD)) != PKTQ_MARKER) + return (0); + } +#endif + return (1); +} + +static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool) +{ + int i; + + q->elem_size = size; + q->num_elem = num; + q->buf_start = pool; + q->in_index = 0; + q->out_index = 0; + + PCAP_ASSERT (size >= sizeof(struct rx_elem) + sizeof(DWORD)); + PCAP_ASSERT (num); + PCAP_ASSERT (pool); + + for (i = 0; i < num; i++) + { +#if 0 + struct rx_elem *elem = (struct rx_elem*) pool; + + /* assert dword aligned elements + */ + PCAP_ASSERT (((unsigned)(&elem->data[0]) & 3) == 0); +#endif + pool += size; + *(DWORD*) (pool - sizeof(DWORD)) = PKTQ_MARKER; + } + return (1); +} + +/* + * Increment the queue 'out_index' (tail). + * Check for wraps. + */ +static int pktq_inc_out (struct rx_ringbuf *q) +{ + q->out_index++; + if (q->out_index >= q->num_elem) + q->out_index = 0; + return (q->out_index); +} + +/* + * Return the queue's next 'in_index' (head). + * Check for wraps. + */ +static int pktq_in_index (struct rx_ringbuf *q) +{ + volatile int index = q->in_index + 1; + + if (index >= q->num_elem) + index = 0; + return (index); +} + +/* + * Return the queue's head-buffer. + */ +static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q) +{ + return (struct rx_elem*) (q->buf_start + (q->elem_size * q->in_index)); +} + +/* + * Return the queue's tail-buffer. + */ +static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q) +{ + return (struct rx_elem*) (q->buf_start + (q->elem_size * q->out_index)); +} + +/* + * Clear the queue ring-buffer by setting head=tail. + */ +static void pktq_clear (struct rx_ringbuf *q) +{ + q->in_index = q->out_index; +} + +/* + * Symbols that must be linkable for "gcc -O0" + */ +#undef __IOPORT_H +#undef __DMA_H + +#define extern +#define __inline__ + +#include "msdos/pm_drvr/ioport.h" +#include "msdos/pm_drvr/dma.h" + +#endif /* USE_32BIT_DRIVERS */ + diff --git a/tcpdump/jni/libpcap/pcap-dos.h b/tcpdump/jni/libpcap/pcap-dos.h new file mode 100644 index 0000000..bf47fb5 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-dos.h @@ -0,0 +1,225 @@ +/* + * Internal details for libpcap on DOS. + * 32-bit targets: djgpp, Pharlap or DOS4GW. + */ + +#ifndef __PCAP_DOS_H +#define __PCAP_DOS_H + +#ifdef __DJGPP__ +#include /* simple non-conio kbhit */ +#else +#include +#endif + +typedef int BOOL; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef BYTE ETHER[6]; + +#define ETH_ALEN sizeof(ETHER) /* Ether address length */ +#define ETH_HLEN (2*ETH_ALEN+2) /* Ether header length */ +#define ETH_MTU 1500 +#define ETH_MIN 60 +#define ETH_MAX (ETH_MTU+ETH_HLEN) + +#ifndef TRUE + #define TRUE 1 + #define FALSE 0 +#endif + +#define PHARLAP 1 +#define DJGPP 2 +#define DOS4GW 4 + +#ifdef __DJGPP__ + #undef DOSX + #define DOSX DJGPP +#endif + +#ifdef __WATCOMC__ + #undef DOSX + #define DOSX DOS4GW +#endif + +#ifdef __HIGHC__ + #include + #undef DOSX + #define DOSX PHARLAP + #define inline +#else + typedef unsigned int UINT; +#endif + + +#if defined(__GNUC__) || defined(__HIGHC__) + typedef unsigned long long uint64; + typedef unsigned long long QWORD; +#endif + +#if defined(__WATCOMC__) + typedef unsigned __int64 uint64; + typedef unsigned __int64 QWORD; +#endif + +#define ARGSUSED(x) (void) x + +#if defined (__SMALL__) || defined(__LARGE__) + #define DOSX 0 + +#elif !defined(DOSX) + #error DOSX not defined; 1 = PharLap, 2 = djgpp, 4 = DOS4GW +#endif + +#ifdef __HIGHC__ +#define min(a,b) _min(a,b) +#define max(a,b) _max(a,b) +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) ((a) < (b) ? (b) : (a)) +#endif + +#if !defined(_U_) && defined(__GNUC__) +#define _U_ __attribute__((unused)) +#endif + +#ifndef _U_ +#define _U_ +#endif + +#if defined(USE_32BIT_DRIVERS) + #include "msdos/pm_drvr/lock.h" + + #ifndef RECEIVE_QUEUE_SIZE + #define RECEIVE_QUEUE_SIZE 60 + #endif + + #ifndef RECEIVE_BUF_SIZE + #define RECEIVE_BUF_SIZE (ETH_MAX+20) + #endif + + extern struct device el2_dev LOCKED_VAR; /* 3Com EtherLink II */ + extern struct device el3_dev LOCKED_VAR; /* EtherLink III */ + extern struct device tc59_dev LOCKED_VAR; /* 3Com Vortex Card (?) */ + extern struct device tc515_dev LOCKED_VAR; + extern struct device tc90x_dev LOCKED_VAR; + extern struct device tc90bcx_dev LOCKED_VAR; + extern struct device wd_dev LOCKED_VAR; + extern struct device ne_dev LOCKED_VAR; + extern struct device acct_dev LOCKED_VAR; + extern struct device cs89_dev LOCKED_VAR; + extern struct device rtl8139_dev LOCKED_VAR; + + struct rx_ringbuf { + volatile int in_index; /* queue index head */ + int out_index; /* queue index tail */ + int elem_size; /* size of each element */ + int num_elem; /* number of elements */ + char *buf_start; /* start of buffer pool */ + }; + + struct rx_elem { + DWORD size; /* size copied to this element */ + BYTE data[ETH_MAX+10]; /* add some margin. data[0] should be */ + }; /* dword aligned */ + + extern BYTE *get_rxbuf (int len) LOCKED_FUNC; + extern int peek_rxbuf (BYTE **buf); + extern int release_rxbuf (BYTE *buf); + +#else + #define LOCKED_VAR + #define LOCKED_FUNC + + struct device { + const char *name; + const char *long_name; + DWORD base_addr; /* device I/O address */ + int irq; /* device IRQ number */ + int dma; /* DMA channel */ + DWORD mem_start; /* shared mem start */ + DWORD mem_end; /* shared mem end */ + DWORD rmem_start; /* shmem "recv" start */ + DWORD rmem_end; /* shared "recv" end */ + + struct device *next; /* next device in list */ + + /* interface service routines */ + int (*probe)(struct device *dev); + int (*open) (struct device *dev); + void (*close)(struct device *dev); + int (*xmit) (struct device *dev, const void *buf, int len); + void *(*get_stats)(struct device *dev); + void (*set_multicast_list)(struct device *dev); + + /* driver-to-pcap receive buffer routines */ + int (*copy_rx_buf) (BYTE *buf, int max); /* rx-copy (pktdrvr only) */ + BYTE *(*get_rx_buf) (int len); /* rx-buf fetch/enqueue */ + int (*peek_rx_buf) (BYTE **buf); /* rx-non-copy at queue */ + int (*release_rx_buf) (BYTE *buf); /* release after peek */ + + WORD flags; /* Low-level status flags. */ + void *priv; /* private data */ + }; + + /* + * Network device statistics + */ + typedef struct net_device_stats { + DWORD rx_packets; /* total packets received */ + DWORD tx_packets; /* total packets transmitted */ + DWORD rx_bytes; /* total bytes received */ + DWORD tx_bytes; /* total bytes transmitted */ + DWORD rx_errors; /* bad packets received */ + DWORD tx_errors; /* packet transmit problems */ + DWORD rx_dropped; /* no space in Rx buffers */ + DWORD tx_dropped; /* no space available for Tx */ + DWORD multicast; /* multicast packets received */ + + /* detailed rx_errors: */ + DWORD rx_length_errors; + DWORD rx_over_errors; /* recv'r overrun error */ + DWORD rx_osize_errors; /* recv'r over-size error */ + DWORD rx_crc_errors; /* recv'd pkt with crc error */ + DWORD rx_frame_errors; /* recv'd frame alignment error */ + DWORD rx_fifo_errors; /* recv'r fifo overrun */ + DWORD rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + DWORD tx_aborted_errors; + DWORD tx_carrier_errors; + DWORD tx_fifo_errors; + DWORD tx_heartbeat_errors; + DWORD tx_window_errors; + DWORD tx_collisions; + DWORD tx_jabbers; + } NET_STATS; +#endif + +extern struct device *active_dev LOCKED_VAR; +extern const struct device *dev_base LOCKED_VAR; +extern struct device *probed_dev; + +extern int pcap_pkt_debug; + +extern void _w32_os_yield (void); /* Watt-32's misc.c */ + +#ifdef NDEBUG + #define PCAP_ASSERT(x) ((void)0) + +#else + void pcap_assert (const char *what, const char *file, unsigned line); + + #define PCAP_ASSERT(x) do { \ + if (!(x)) \ + pcap_assert (#x, __FILE__, __LINE__); \ + } while (0) +#endif + +#endif /* __PCAP_DOS_H */ diff --git a/tcpdump/jni/libpcap/pcap-enet.c b/tcpdump/jni/libpcap/pcap-enet.c new file mode 100644 index 0000000..777d3e3 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-enet.c @@ -0,0 +1,231 @@ +/* + * Stanford Enetfilter subroutines for tcpdump + * + * Based on the MERIT NNstat etherifrt.c and the Ultrix pcap-pf.c + * subroutines. + * + * Rayan Zachariassen, CA*Net + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include "interface.h" + +struct packet_header { +#ifdef IBMRTPC + struct LengthWords length; + struct tap_header tap; +#endif /* IBMRTPC */ + u_char packet[8] +}; + +extern int errno; + +#define BUFSPACE (4*1024) + +/* Forwards */ +static void efReadError(int, char *); + +void +readloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit) +{ +#ifdef IBMRTPC + register struct packet_header *ph; + register u_char *bp; + register int inc; +#else /* !IBMRTPC */ + static struct timeval tv = { 0 }; +#endif /* IBMRTPC */ + register int cc, caplen; + register struct bpf_insn *fcode = fp->bf_insns; + union { + struct packet_header hdr; + u_char p[BUFSPACE]; + u_short s; + } buf; + + while (1) { + if ((cc = read(if_fd, (char *)buf.p, sizeof(buf))) < 0) + efReadError(if_fd, "reader"); + +#ifdef IBMRTPC + /* + * Loop through each packet. + */ + bp = buf.p; + while (cc > 0) { + ph = (struct packet_header *)bp; + caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap +.th_wirelen ; + if (bpf_filter(fcode, (char *)ph->packet, + ph->tap.th_wirelen, caplen)) { + if (cnt >= 0 && --cnt < 0) + goto out; + (*printit)((char *)ph->packet, + (struct timeval *)ph->tap.th_timestamp, + ph->tap.th_wirelen, caplen); + } + inc = ph->length.PacketOffset; + cc -= inc; + bp += inc; + } +#else /* !IBMRTPC */ + caplen = cc > snaplen ? snaplen : cc ; + if (bpf_filter(fcode, buf.hdr.packet, cc, caplen)) { + if (cnt >= 0 && --cnt < 0) + goto out; + (*printit)(buf.hdr.packet, &tv, cc, caplen); + } +#endif /* IBMRTPC */ + } + out: + wrapup(if_fd); +} + +/* Call ONLY if read() has returned an error on packet filter */ +static void +efReadError(int fid, char *msg) +{ + if (errno == EINVAL) { /* read MAXINT bytes already! */ + if (lseek(fid, 0, 0) < 0) { + perror("tcpdump: efReadError/lseek"); + exit(-1); + } + else + return; + } + else { + (void) fprintf(stderr, "tcpdump: "); + perror(msg); + exit(-1); + } +} + +void +wrapup(int fd) +{ +#ifdef IBMRTPC + struct enstats es; + + if (ioctl(fd, EIOSTATS, &es) == -1) { + perror("tcpdump: enet ioctl EIOSTATS error"); + exit(-1); + } + + fprintf(stderr, "%d packets queued", es.enStat_Rcnt); + if (es.enStat_Rdrops > 0) + fprintf(stderr, ", %d dropped", es.enStat_Rdrops); + if (es.enStat_Reads > 0) + fprintf(stderr, ", %d tcpdump %s", es.enStat_Reads, + es.enStat_Reads > 1 ? "reads" : "read"); + if (es.enStat_MaxRead > 1) + fprintf(stderr, ", %d packets in largest read", + es.enStat_MaxRead); + putc('\n', stderr); +#endif /* IBMRTPC */ + close(fd); +} + +int +initdevice(char *device, int pflag, int *linktype) +{ + struct eniocb ctl; + struct enfilter filter; + u_int maxwaiting; + int if_fd; + +#ifdef IBMRTPC + GETENETDEVICE(0, O_RDONLY, &if_fd); +#else /* !IBMRTPC */ + if_fd = open("/dev/enet", O_RDONLY, 0); +#endif /* IBMRTPC */ + + if (if_fd == -1) { + perror("tcpdump: enet open error"); + error( +"your system may not be properly configured; see \"man enet(4)\""); + exit(-1); + } + + /* Get operating parameters. */ + + if (ioctl(if_fd, EIOCGETP, (char *)&ctl) == -1) { + perror("tcpdump: enet ioctl EIOCGETP error"); + exit(-1); + } + + /* Set operating parameters. */ + +#ifdef IBMRTPC + ctl.en_rtout = 1 * ctl.en_hz; + ctl.en_tr_etherhead = 1; + ctl.en_tap_network = 1; + ctl.en_multi_packet = 1; + ctl.en_maxlen = BUFSPACE; +#else /* !IBMRTPC */ + ctl.en_rtout = 64; /* randomly picked value for HZ */ +#endif /* IBMRTPC */ + if (ioctl(if_fd, EIOCSETP, &ctl) == -1) { + perror("tcpdump: enet ioctl EIOCSETP error"); + exit(-1); + } + + /* Flush the receive queue, since we've changed + the operating parameters and we otherwise might + receive data without headers. */ + + if (ioctl(if_fd, EIOCFLUSH) == -1) { + perror("tcpdump: enet ioctl EIOCFLUSH error"); + exit(-1); + } + + /* Set the receive queue depth to its maximum. */ + + maxwaiting = ctl.en_maxwaiting; + if (ioctl(if_fd, EIOCSETW, &maxwaiting) == -1) { + perror("tcpdump: enet ioctl EIOCSETW error"); + exit(-1); + } + +#ifdef IBMRTPC + /* Clear statistics. */ + + if (ioctl(if_fd, EIOCLRSTAT, 0) == -1) { + perror("tcpdump: enet ioctl EIOCLRSTAT error"); + exit(-1); + } +#endif /* IBMRTPC */ + + /* Set the filter (accept all packets). */ + + filter.enf_Priority = 3; + filter.enf_FilterLen = 0; + if (ioctl(if_fd, EIOCSETF, &filter) == -1) { + perror("tcpdump: enet ioctl EIOCSETF error"); + exit(-1); + } + /* + * "enetfilter" supports only ethernets. + */ + *linktype = DLT_EN10MB; + + return(if_fd); +} diff --git a/tcpdump/jni/libpcap/pcap-filter.manmisc.in b/tcpdump/jni/libpcap/pcap-filter.manmisc.in new file mode 100644 index 0000000..d740194 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-filter.manmisc.in @@ -0,0 +1,1033 @@ +.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP-FILTER @MAN_MISC_INFO@ "17 May 2013" +.SH NAME +pcap-filter \- packet filter syntax +.br +.ad +.SH DESCRIPTION +.LP +.B pcap_compile() +is used to compile a string into a filter program. +The resulting filter program can then be applied to +some stream of packets to determine which packets will be supplied to +.BR pcap_loop() , +.BR pcap_dispatch() , +.BR pcap_next() , +or +.BR pcap_next_ex() . +.LP +The \fIfilter expression\fP consists of one or more +.IR primitives . +Primitives usually consist of an +.I id +(name or number) preceded by one or more qualifiers. +There are three +different kinds of qualifier: +.IP \fItype\fP +.I type +qualifiers say what kind of thing the id name or number refers to. +Possible types are +.BR host , +.B net , +.B port +and +.BR portrange . +E.g., `host foo', `net 128.3', `port 20', `portrange 6000-6008'. +If there is no type +qualifier, +.B host +is assumed. +.IP \fIdir\fP +.I dir +qualifiers specify a particular transfer direction to and/or from +.IR id . +Possible directions are +.BR src , +.BR dst , +.BR "src or dst" , +.BR "src and dst" , +.BR ra , +.BR ta , +.BR addr1 , +.BR addr2 , +.BR addr3 , +and +.BR addr4 . +E.g., `src foo', `dst net 128.3', `src or dst port ftp-data'. +If +there is no dir qualifier, +.B "src or dst" +is assumed. +The +.BR ra , +.BR ta , +.BR addr1 , +.BR addr2 , +.BR addr3 , +and +.B addr4 +qualifiers are only valid for IEEE 802.11 Wireless LAN link layers. +For some link layers, such as SLIP and the ``cooked'' Linux capture mode +used for the ``any'' device and for some other device types, the +.B inbound +and +.B outbound +qualifiers can be used to specify a desired direction. +.IP \fIproto\fP +.I proto +qualifiers restrict the match to a particular protocol. +Possible +protos are: +.BR ether , +.BR fddi , +.BR tr , +.BR wlan , +.BR ip , +.BR ip6 , +.BR arp , +.BR rarp , +.BR decnet , +.B tcp +and +.BR udp . +E.g., `ether src foo', `arp net 128.3', `tcp port 21', `udp portrange +7000-7009', `wlan addr2 0:2:3:4:5:6'. +If there is +no proto qualifier, all protocols consistent with the type are +assumed. +E.g., `src foo' means `(ip or arp or rarp) src foo' +(except the latter is not legal syntax), `net bar' means `(ip or +arp or rarp) net bar' and `port 53' means `(tcp or udp) port 53'. +.LP +[`fddi' is actually an alias for `ether'; the parser treats them +identically as meaning ``the data link level used on the specified +network interface.'' FDDI headers contain Ethernet-like source +and destination addresses, and often contain Ethernet-like packet +types, so you can filter on these FDDI fields just as with the +analogous Ethernet fields. +FDDI headers also contain other fields, +but you cannot name them explicitly in a filter expression. +.LP +Similarly, `tr' and `wlan' are aliases for `ether'; the previous +paragraph's statements about FDDI headers also apply to Token Ring +and 802.11 wireless LAN headers. For 802.11 headers, the destination +address is the DA field and the source address is the SA field; the +BSSID, RA, and TA fields aren't tested.] +.LP +In addition to the above, there are some special `primitive' keywords +that don't follow the pattern: +.BR gateway , +.BR broadcast , +.BR less , +.B greater +and arithmetic expressions. +All of these are described below. +.LP +More complex filter expressions are built up by using the words +.BR and , +.B or +and +.B not +to combine primitives. +E.g., `host foo and not port ftp and not port ftp-data'. +To save typing, identical qualifier lists can be omitted. +E.g., +`tcp dst port ftp or ftp-data or domain' is exactly the same as +`tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain'. +.LP +Allowable primitives are: +.IP "\fBdst host \fIhost\fR" +True if the IPv4/v6 destination field of the packet is \fIhost\fP, +which may be either an address or a name. +.IP "\fBsrc host \fIhost\fR" +True if the IPv4/v6 source field of the packet is \fIhost\fP. +.IP "\fBhost \fIhost\fP" +True if either the IPv4/v6 source or destination of the packet is \fIhost\fP. +.IP +Any of the above host expressions can be prepended with the keywords, +\fBip\fP, \fBarp\fP, \fBrarp\fP, or \fBip6\fP as in: +.in +.5i +.nf +\fBip host \fIhost\fR +.fi +.in -.5i +which is equivalent to: +.in +.5i +.nf +\fBether proto \fI\\ip\fB and host \fIhost\fR +.fi +.in -.5i +If \fIhost\fR is a name with multiple IP addresses, each address will +be checked for a match. +.IP "\fBether dst \fIehost\fP" +True if the Ethernet destination address is \fIehost\fP. +\fIEhost\fP +may be either a name from /etc/ethers or a number (see +.IR ethers (3N) +for numeric format). +.IP "\fBether src \fIehost\fP" +True if the Ethernet source address is \fIehost\fP. +.IP "\fBether host \fIehost\fP" +True if either the Ethernet source or destination address is \fIehost\fP. +.IP "\fBgateway\fP \fIhost\fP" +True if the packet used \fIhost\fP as a gateway. +I.e., the Ethernet +source or destination address was \fIhost\fP but neither the IP source +nor the IP destination was \fIhost\fP. +\fIHost\fP must be a name and +must be found both by the machine's host-name-to-IP-address resolution +mechanisms (host name file, DNS, NIS, etc.) and by the machine's +host-name-to-Ethernet-address resolution mechanism (/etc/ethers, etc.). +(An equivalent expression is +.in +.5i +.nf +\fBether host \fIehost \fBand not host \fIhost\fR +.fi +.in -.5i +which can be used with either names or numbers for \fIhost / ehost\fP.) +This syntax does not work in IPv6-enabled configuration at this moment. +.IP "\fBdst net \fInet\fR" +True if the IPv4/v6 destination address of the packet has a network +number of \fInet\fP. +\fINet\fP may be either a name from the networks database +(/etc/networks, etc.) or a network number. +An IPv4 network number can be written as a dotted quad (e.g., 192.168.1.0), +dotted triple (e.g., 192.168.1), dotted pair (e.g, 172.16), or single +number (e.g., 10); the netmask is 255.255.255.255 for a dotted quad +(which means that it's really a host match), 255.255.255.0 for a dotted +triple, 255.255.0.0 for a dotted pair, or 255.0.0.0 for a single number. +An IPv6 network number must be written out fully; the netmask is +ff:ff:ff:ff:ff:ff:ff:ff, so IPv6 "network" matches are really always +host matches, and a network match requires a netmask length. +.IP "\fBsrc net \fInet\fR" +True if the IPv4/v6 source address of the packet has a network +number of \fInet\fP. +.IP "\fBnet \fInet\fR" +True if either the IPv4/v6 source or destination address of the packet has a network +number of \fInet\fP. +.IP "\fBnet \fInet\fR \fBmask \fInetmask\fR" +True if the IPv4 address matches \fInet\fR with the specific \fInetmask\fR. +May be qualified with \fBsrc\fR or \fBdst\fR. +Note that this syntax is not valid for IPv6 \fInet\fR. +.IP "\fBnet \fInet\fR/\fIlen\fR" +True if the IPv4/v6 address matches \fInet\fR with a netmask \fIlen\fR +bits wide. +May be qualified with \fBsrc\fR or \fBdst\fR. +.IP "\fBdst port \fIport\fR" +True if the packet is ip/tcp, ip/udp, ip6/tcp or ip6/udp and has a +destination port value of \fIport\fP. +The \fIport\fP can be a number or a name used in /etc/services (see +.IR tcp (4P) +and +.IR udp (4P)). +If a name is used, both the port +number and protocol are checked. +If a number or ambiguous name is used, +only the port number is checked (e.g., \fBdst port 513\fR will print both +tcp/login traffic and udp/who traffic, and \fBport domain\fR will print +both tcp/domain and udp/domain traffic). +.IP "\fBsrc port \fIport\fR" +True if the packet has a source port value of \fIport\fP. +.IP "\fBport \fIport\fR" +True if either the source or destination port of the packet is \fIport\fP. +.IP "\fBdst portrange \fIport1\fB-\fIport2\fR" +True if the packet is ip/tcp, ip/udp, ip6/tcp or ip6/udp and has a +destination port value between \fIport1\fP and \fIport2\fP. +.I port1 +and +.I port2 +are interpreted in the same fashion as the +.I port +parameter for +.BR port . +.IP "\fBsrc portrange \fIport1\fB-\fIport2\fR" +True if the packet has a source port value between \fIport1\fP and +\fIport2\fP. +.IP "\fBportrange \fIport1\fB-\fIport2\fR" +True if either the source or destination port of the packet is between +\fIport1\fP and \fIport2\fP. +.IP +Any of the above port or port range expressions can be prepended with +the keywords, \fBtcp\fP or \fBudp\fP, as in: +.in +.5i +.nf +\fBtcp src port \fIport\fR +.fi +.in -.5i +which matches only tcp packets whose source port is \fIport\fP. +.IP "\fBless \fIlength\fR" +True if the packet has a length less than or equal to \fIlength\fP. +This is equivalent to: +.in +.5i +.nf +\fBlen <= \fIlength\fP. +.fi +.in -.5i +.IP "\fBgreater \fIlength\fR" +True if the packet has a length greater than or equal to \fIlength\fP. +This is equivalent to: +.in +.5i +.nf +\fBlen >= \fIlength\fP. +.fi +.in -.5i +.IP "\fBip proto \fIprotocol\fR" +True if the packet is an IPv4 packet (see +.IR ip (4P)) +of protocol type \fIprotocol\fP. +\fIProtocol\fP can be a number or one of the names +\fBicmp\fP, \fBicmp6\fP, \fBigmp\fP, \fBigrp\fP, \fBpim\fP, \fBah\fP, +\fBesp\fP, \fBvrrp\fP, \fBudp\fP, or \fBtcp\fP. +Note that the identifiers \fBtcp\fP, \fBudp\fP, and \fBicmp\fP are also +keywords and must be escaped via backslash (\\), which is \\\\ in the C-shell. +Note that this primitive does not chase the protocol header chain. +.IP "\fBip6 proto \fIprotocol\fR" +True if the packet is an IPv6 packet of protocol type \fIprotocol\fP. +Note that this primitive does not chase the protocol header chain. +.IP "\fBproto \fIprotocol\fR" +True if the packet is an IPv4 or IPv6 packet of protocol type +\fIprotocol\fP. Note that this primitive does not chase the protocol +header chain. +.IP "\fBtcp\fR, \fBudp\fR, \fBicmp\fR" +Abbreviations for: +.in +.5i +.nf +\fBproto \fIp\fR\fB +.fi +.in -.5i +where \fIp\fR is one of the above protocols. +.IP "\fBip6 protochain \fIprotocol\fR" +True if the packet is IPv6 packet, +and contains protocol header with type \fIprotocol\fR +in its protocol header chain. +For example, +.in +.5i +.nf +\fBip6 protochain 6\fR +.fi +.in -.5i +matches any IPv6 packet with TCP protocol header in the protocol header chain. +The packet may contain, for example, +authentication header, routing header, or hop-by-hop option header, +between IPv6 header and TCP header. +The BPF code emitted by this primitive is complex and +cannot be optimized by the BPF optimizer code, and is not supported by +filter engines in the kernel, so this can be somewhat slow, and may +cause more packets to be dropped. +.IP "\fBip protochain \fIprotocol\fR" +Equivalent to \fBip6 protochain \fIprotocol\fR, but this is for IPv4. +.IP "\fBprotochain \fIprotocol\fR" +True if the packet is an IPv4 or IPv6 packet of protocol type +\fIprotocol\fP. Note that this primitive chases the protocol +header chain. +.IP "\fBether broadcast\fR" +True if the packet is an Ethernet broadcast packet. +The \fIether\fP +keyword is optional. +.IP "\fBip broadcast\fR" +True if the packet is an IPv4 broadcast packet. +It checks for both the all-zeroes and all-ones broadcast conventions, +and looks up the subnet mask on the interface on which the capture is +being done. +.IP +If the subnet mask of the interface on which the capture is being done +is not available, either because the interface on which capture is being +done has no netmask or because the capture is being done on the Linux +"any" interface, which can capture on more than one interface, this +check will not work correctly. +.IP "\fBether multicast\fR" +True if the packet is an Ethernet multicast packet. +The \fBether\fP +keyword is optional. +This is shorthand for `\fBether[0] & 1 != 0\fP'. +.IP "\fBip multicast\fR" +True if the packet is an IPv4 multicast packet. +.IP "\fBip6 multicast\fR" +True if the packet is an IPv6 multicast packet. +.IP "\fBether proto \fIprotocol\fR" +True if the packet is of ether type \fIprotocol\fR. +\fIProtocol\fP can be a number or one of the names +\fBip\fP, \fBip6\fP, \fBarp\fP, \fBrarp\fP, \fBatalk\fP, \fBaarp\fP, +\fBdecnet\fP, \fBsca\fP, \fBlat\fP, \fBmopdl\fP, \fBmoprc\fP, +\fBiso\fP, \fBstp\fP, \fBipx\fP, or \fBnetbeui\fP. +Note these identifiers are also keywords +and must be escaped via backslash (\\). +.IP +[In the case of FDDI (e.g., `\fBfddi protocol arp\fR'), Token Ring +(e.g., `\fBtr protocol arp\fR'), and IEEE 802.11 wireless LANS (e.g., +`\fBwlan protocol arp\fR'), for most of those protocols, the +protocol identification comes from the 802.2 Logical Link Control (LLC) +header, which is usually layered on top of the FDDI, Token Ring, or +802.11 header. +.IP +When filtering for most protocol identifiers on FDDI, Token Ring, or +802.11, the filter checks only the protocol ID field of an LLC header +in so-called SNAP format with an Organizational Unit Identifier (OUI) of +0x000000, for encapsulated Ethernet; it doesn't check whether the packet +is in SNAP format with an OUI of 0x000000. +The exceptions are: +.RS +.TP +\fBiso\fP +the filter checks the DSAP (Destination Service Access Point) and +SSAP (Source Service Access Point) fields of the LLC header; +.TP +\fBstp\fP and \fBnetbeui\fP +the filter checks the DSAP of the LLC header; +.TP +\fBatalk\fP +the filter checks for a SNAP-format packet with an OUI of 0x080007 +and the AppleTalk etype. +.RE +.IP +In the case of Ethernet, the filter checks the Ethernet type field +for most of those protocols. The exceptions are: +.RS +.TP +\fBiso\fP, \fBstp\fP, and \fBnetbeui\fP +the filter checks for an 802.3 frame and then checks the LLC header as +it does for FDDI, Token Ring, and 802.11; +.TP +\fBatalk\fP +the filter checks both for the AppleTalk etype in an Ethernet frame and +for a SNAP-format packet as it does for FDDI, Token Ring, and 802.11; +.TP +\fBaarp\fP +the filter checks for the AppleTalk ARP etype in either an Ethernet +frame or an 802.2 SNAP frame with an OUI of 0x000000; +.TP +\fBipx\fP +the filter checks for the IPX etype in an Ethernet frame, the IPX +DSAP in the LLC header, the 802.3-with-no-LLC-header encapsulation of +IPX, and the IPX etype in a SNAP frame. +.RE +.IP "\fBip\fR, \fBip6\fR, \fBarp\fR, \fBrarp\fR, \fBatalk\fR, \fBaarp\fR, \fBdecnet\fR, \fBiso\fR, \fBstp\fR, \fBipx\fR, \fBnetbeui\fP" +Abbreviations for: +.in +.5i +.nf +\fBether proto \fIp\fR +.fi +.in -.5i +where \fIp\fR is one of the above protocols. +.IP "\fBlat\fR, \fBmoprc\fR, \fBmopdl\fR" +Abbreviations for: +.in +.5i +.nf +\fBether proto \fIp\fR +.fi +.in -.5i +where \fIp\fR is one of the above protocols. +Note that not all applications using +.BR pcap (3PCAP) +currently know how to parse these protocols. +.IP "\fBdecnet src \fIhost\fR" +True if the DECNET source address is +.IR host , +which may be an address of the form ``10.123'', or a DECNET host +name. +[DECNET host name support is only available on ULTRIX systems +that are configured to run DECNET.] +.IP "\fBdecnet dst \fIhost\fR" +True if the DECNET destination address is +.IR host . +.IP "\fBdecnet host \fIhost\fR" +True if either the DECNET source or destination address is +.IR host . +.IP \fBllc\fP +True if the packet has an 802.2 LLC header. This includes: +.IP +Ethernet packets with a length field rather than a type field that +aren't raw NetWare-over-802.3 packets; +.IP +IEEE 802.11 data packets; +.IP +Token Ring packets (no check is done for LLC frames); +.IP +FDDI packets (no check is done for LLC frames); +.IP +LLC-encapsulated ATM packets, for SunATM on Solaris. +.IP + +.IP "\fBllc\fP \Fitype\fR" +True if the packet has an 802.2 LLC header and has the specified +.IR type . +.I type +can be one of: +.RS +.TP +\fBi\fR +Information (I) PDUs +.TP +\fBs\fR +Supervisory (S) PDUs +.TP +\fBu\fR +Unnumbered (U) PDUs +.TP +\fBrr\fR +Receiver Ready (RR) S PDUs +.TP +\fBrnr\fR +Receiver Not Ready (RNR) S PDUs +.TP +\fBrej\fR +Reject (REJ) S PDUs +.TP +\fBui\fR +Unnumbered Information (UI) U PDUs +.TP +\fBua\fR +Unnumbered Acknowledgment (UA) U PDUs +.TP +\fBdisc\fR +Disconnect (DISC) U PDUs +.TP +\fBsabme\fR +Set Asynchronous Balanced Mode Extended (SABME) U PDUs +.TP +\fBtest\fR +Test (TEST) U PDUs +.TP +\fBxid\fR +Exchange Identification (XID) U PDUs +.TP +\fBfrmr\fR +Frame Reject (FRMR) U PDUs +.RE +.IP "\fBifname \fIinterface\fR" +True if the packet was logged as coming from the specified interface (applies +only to packets logged by OpenBSD's or FreeBSD's +.BR pf (4)). +.IP "\fBon \fIinterface\fR" +Synonymous with the +.B ifname +modifier. +.IP "\fBrnr \fInum\fR" +True if the packet was logged as matching the specified PF rule number +(applies only to packets logged by OpenBSD's or FreeBSD's +.BR pf (4)). +.IP "\fBrulenum \fInum\fR" +Synonymous with the +.B rnr +modifier. +.IP "\fBreason \fIcode\fR" +True if the packet was logged with the specified PF reason code. The known +codes are: +.BR match , +.BR bad-offset , +.BR fragment , +.BR short , +.BR normalize , +and +.B memory +(applies only to packets logged by OpenBSD's or FreeBSD's +.BR pf (4)). +.IP "\fBrset \fIname\fR" +True if the packet was logged as matching the specified PF ruleset +name of an anchored ruleset (applies only to packets logged by OpenBSD's +or FreeBSD's +.BR pf (4)). +.IP "\fBruleset \fIname\fR" +Synonymous with the +.B rset +modifier. +.IP "\fBsrnr \fInum\fR" +True if the packet was logged as matching the specified PF rule number +of an anchored ruleset (applies only to packets logged by OpenBSD's or +FreeBSD's +.BR pf (4)). +.IP "\fBsubrulenum \fInum\fR" +Synonymous with the +.B srnr +modifier. +.IP "\fBaction \fIact\fR" +True if PF took the specified action when the packet was logged. Known actions +are: +.B pass +and +.B block +and, with later versions of +.BR pf (4)), +.BR nat , +.BR rdr , +.B binat +and +.B scrub +(applies only to packets logged by OpenBSD's or FreeBSD's +.BR pf (4)). +.IP "\fBwlan ra \fIehost\fR" +True if the IEEE 802.11 RA is +.IR ehost . +The RA field is used in all frames except for management frames. +.IP "\fBwlan ta \fIehost\fR" +True if the IEEE 802.11 TA is +.IR ehost . +The TA field is used in all frames except for management frames and +CTS (Clear To Send) and ACK (Acknowledgment) control frames. +.IP "\fBwlan addr1 \fIehost\fR" +True if the first IEEE 802.11 address is +.IR ehost . +.IP "\fBwlan addr2 \fIehost\fR" +True if the second IEEE 802.11 address, if present, is +.IR ehost . +The second address field is used in all frames except for CTS (Clear To +Send) and ACK (Acknowledgment) control frames. +.IP "\fBwlan addr3 \fIehost\fR" +True if the third IEEE 802.11 address, if present, is +.IR ehost . +The third address field is used in management and data frames, but not +in control frames. +.IP "\fBwlan addr4 \fIehost\fR" +True if the fourth IEEE 802.11 address, if present, is +.IR ehost . +The fourth address field is only used for +WDS (Wireless Distribution System) frames. +.IP "\fBtype \fIwlan_type\fR" +True if the IEEE 802.11 frame type matches the specified \fIwlan_type\fR. +Valid \fIwlan_type\fRs are: +\fBmgt\fP, +\fBctl\fP +and \fBdata\fP. +.IP "\fBtype \fIwlan_type \fBsubtype \fIwlan_subtype\fR" +True if the IEEE 802.11 frame type matches the specified \fIwlan_type\fR +and frame subtype matches the specified \fIwlan_subtype\fR. +.IP +If the specified \fIwlan_type\fR is \fBmgt\fP, +then valid \fIwlan_subtype\fRs are: +\fBassoc-req\fP, +\fBassoc-resp\fP, +\fBreassoc-req\fP, +\fBreassoc-resp\fP, +\fBprobe-req\fP, +\fBprobe-resp\fP, +\fBbeacon\fP, +\fBatim\fP, +\fBdisassoc\fP, +\fBauth\fP and +\fBdeauth\fP. +.IP +If the specified \fIwlan_type\fR is \fBctl\fP, +then valid \fIwlan_subtype\fRs are: +\fBps-poll\fP, +\fBrts\fP, +\fBcts\fP, +\fBack\fP, +\fBcf-end\fP and +\fBcf-end-ack\fP. +.IP +If the specified \fIwlan_type\fR is \fBdata\fP, +then valid \fIwlan_subtype\fRs are: +\fBdata\fP, +\fBdata-cf-ack\fP, +\fBdata-cf-poll\fP, +\fBdata-cf-ack-poll\fP, +\fBnull\fP, +\fBcf-ack\fP, +\fBcf-poll\fP, +\fBcf-ack-poll\fP, +\fBqos-data\fP, +\fBqos-data-cf-ack\fP, +\fBqos-data-cf-poll\fP, +\fBqos-data-cf-ack-poll\fP, +\fBqos\fP, +\fBqos-cf-poll\fP and +\fBqos-cf-ack-poll\fP. +.IP "\fBsubtype \fIwlan_subtype\fR" +True if the IEEE 802.11 frame subtype matches the specified \fIwlan_subtype\fR +and frame has the type to which the specified \fIwlan_subtype\fR belongs. +.IP "\fBdir \fIdir\fR" +True if the IEEE 802.11 frame direction matches the specified +.IR dir . +Valid directions are: +.BR nods , +.BR tods , +.BR fromds , +.BR dstods , +or a numeric value. +.IP "\fBvlan \fI[vlan_id]\fR" +True if the packet is an IEEE 802.1Q VLAN packet. +If \fI[vlan_id]\fR is specified, only true if the packet has the specified +\fIvlan_id\fR. +Note that the first \fBvlan\fR keyword encountered in \fIexpression\fR +changes the decoding offsets for the remainder of \fIexpression\fR on +the assumption that the packet is a VLAN packet. The \fBvlan +\fI[vlan_id]\fR expression may be used more than once, to filter on VLAN +hierarchies. Each use of that expression increments the filter offsets +by 4. +.IP +For example: +.in +.5i +.nf +\fBvlan 100 && vlan 200\fR +.fi +.in -.5i +filters on VLAN 200 encapsulated within VLAN 100, and +.in +.5i +.nf +\fBvlan && vlan 300 && ip\fR +.fi +.in -.5i +filters IPv4 protocols encapsulated in VLAN 300 encapsulated within any +higher order VLAN. +.IP "\fBmpls \fI[label_num]\fR" +True if the packet is an MPLS packet. +If \fI[label_num]\fR is specified, only true is the packet has the specified +\fIlabel_num\fR. +Note that the first \fBmpls\fR keyword encountered in \fIexpression\fR +changes the decoding offsets for the remainder of \fIexpression\fR on +the assumption that the packet is a MPLS-encapsulated IP packet. The +\fBmpls \fI[label_num]\fR expression may be used more than once, to +filter on MPLS hierarchies. Each use of that expression increments the +filter offsets by 4. +.IP +For example: +.in +.5i +.nf +\fBmpls 100000 && mpls 1024\fR +.fi +.in -.5i +filters packets with an outer label of 100000 and an inner label of +1024, and +.in +.5i +.nf +\fBmpls && mpls 1024 && host 192.9.200.1\fR +.fi +.in -.5i +filters packets to or from 192.9.200.1 with an inner label of 1024 and +any outer label. +.IP \fBpppoed\fP +True if the packet is a PPP-over-Ethernet Discovery packet (Ethernet +type 0x8863). +.IP "\fBpppoes \fI[session_id]\fR" +True if the packet is a PPP-over-Ethernet Session packet (Ethernet +type 0x8864). +If \fI[session_id]\fR is specified, only true if the packet has the specified +\fIsession_id\fR. +Note that the first \fBpppoes\fR keyword encountered in \fIexpression\fR +changes the decoding offsets for the remainder of \fIexpression\fR on +the assumption that the packet is a PPPoE session packet. +.IP +For example: +.in +.5i +.nf +\fBpppoes 0x27 && ip\fR +.fi +.in -.5i +filters IPv4 protocols encapsulated in PPPoE session id 0x27. +.IP "\fBgeneve \fI[vni]\fR" +True if the packet is a Geneve packet (UDP port 6081). If \fI[vni]\fR +is specified, only true if the packet has the specified \fIvni\fR. +Note that when the \fBgeneve\fR keyword is encountered in +\fIexpression\fR, it changes the decoding offsets for the remainder of +\fIexpression\fR on the assumption that the packet is a Geneve packet. +.IP +For example: +.in +.5i +.nf +\fBgeneve 0xb && ip\fR +.fi +.in -.5i +filters IPv4 protocols encapsulated in Geneve with VNI 0xb. This will +match both IP directly encapsulated in Geneve as well as IP contained +inside an Ethernet frame. +.IP "\fBiso proto \fIprotocol\fR" +True if the packet is an OSI packet of protocol type \fIprotocol\fP. +\fIProtocol\fP can be a number or one of the names +\fBclnp\fP, \fBesis\fP, or \fBisis\fP. +.IP "\fBclnp\fR, \fBesis\fR, \fBisis\fR" +Abbreviations for: +.in +.5i +.nf +\fBiso proto \fIp\fR +.fi +.in -.5i +where \fIp\fR is one of the above protocols. +.IP "\fBl1\fR, \fBl2\fR, \fBiih\fR, \fBlsp\fR, \fBsnp\fR, \fBcsnp\fR, \fBpsnp\fR" +Abbreviations for IS-IS PDU types. +.IP "\fBvpi\fP \fIn\fR" +True if the packet is an ATM packet, for SunATM on Solaris, with a +virtual path identifier of +.IR n . +.IP "\fBvci\fP \fIn\fR" +True if the packet is an ATM packet, for SunATM on Solaris, with a +virtual channel identifier of +.IR n . +.IP \fBlane\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +an ATM LANE packet. +Note that the first \fBlane\fR keyword encountered in \fIexpression\fR +changes the tests done in the remainder of \fIexpression\fR +on the assumption that the packet is either a LANE emulated Ethernet +packet or a LANE LE Control packet. If \fBlane\fR isn't specified, the +tests are done under the assumption that the packet is an +LLC-encapsulated packet. +.IP \fBoamf4s\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +a segment OAM F4 flow cell (VPI=0 & VCI=3). +.IP \fBoamf4e\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +an end-to-end OAM F4 flow cell (VPI=0 & VCI=4). +.IP \fBoamf4\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +a segment or end-to-end OAM F4 flow cell (VPI=0 & (VCI=3 | VCI=4)). +.IP \fBoam\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +a segment or end-to-end OAM F4 flow cell (VPI=0 & (VCI=3 | VCI=4)). +.IP \fBmetac\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on a meta signaling circuit (VPI=0 & VCI=1). +.IP \fBbcc\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on a broadcast signaling circuit (VPI=0 & VCI=2). +.IP \fBsc\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on a signaling circuit (VPI=0 & VCI=5). +.IP \fBilmic\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on an ILMI circuit (VPI=0 & VCI=16). +.IP \fBconnectmsg\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on a signaling circuit and is a Q.2931 Setup, Call Proceeding, Connect, +Connect Ack, Release, or Release Done message. +.IP \fBmetaconnect\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on a meta signaling circuit and is a Q.2931 Setup, Call Proceeding, Connect, +Release, or Release Done message. +.IP "\fIexpr relop expr\fR" +True if the relation holds, where \fIrelop\fR is one of >, <, >=, <=, =, +!=, and \fIexpr\fR is an arithmetic expression composed of integer +constants (expressed in standard C syntax), the normal binary operators +[+, -, *, /, %, &, |, ^, <<, >>], a length operator, and special packet data +accessors. Note that all comparisons are unsigned, so that, for example, +0x80000000 and 0xffffffff are > 0. +.IP +The % and ^ operators are currently only supported for filtering in the +kernel on Linux with 3.7 and later kernels; on all other systems, if +those operators are used, filtering will be done in user mode, which +will increase the overhead of capturing packets and may cause more +packets to be dropped. +.IP +To access data inside the packet, use the following syntax: +.in +.5i +.nf +\fIproto\fB [ \fIexpr\fB : \fIsize\fB ]\fR +.fi +.in -.5i +\fIProto\fR is one of \fBether, fddi, tr, wlan, ppp, slip, link, +ip, arp, rarp, tcp, udp, icmp, ip6\fR or \fBradio\fR, and +indicates the protocol layer for the index operation. +(\fBether, fddi, wlan, tr, ppp, slip\fR and \fBlink\fR all refer to the +link layer. \fBradio\fR refers to the "radio header" added to some +802.11 captures.) +Note that \fItcp, udp\fR and other upper-layer protocol types only +apply to IPv4, not IPv6 (this will be fixed in the future). +The byte offset, relative to the indicated protocol layer, is +given by \fIexpr\fR. +\fISize\fR is optional and indicates the number of bytes in the +field of interest; it can be either one, two, or four, and defaults to one. +The length operator, indicated by the keyword \fBlen\fP, gives the +length of the packet. + +For example, `\fBether[0] & 1 != 0\fP' catches all multicast traffic. +The expression `\fBip[0] & 0xf != 5\fP' +catches all IPv4 packets with options. +The expression +`\fBip[6:2] & 0x1fff = 0\fP' +catches only unfragmented IPv4 datagrams and frag zero of fragmented +IPv4 datagrams. +This check is implicitly applied to the \fBtcp\fP and \fBudp\fP +index operations. +For instance, \fBtcp[0]\fP always means the first +byte of the TCP \fIheader\fP, and never means the first byte of an +intervening fragment. + +Some offsets and field values may be expressed as names rather than +as numeric values. +The following protocol header field offsets are +available: \fBicmptype\fP (ICMP type field), \fBicmpcode\fP (ICMP +code field), and \fBtcpflags\fP (TCP flags field). + +The following ICMP type field values are available: \fBicmp-echoreply\fP, +\fBicmp-unreach\fP, \fBicmp-sourcequench\fP, \fBicmp-redirect\fP, +\fBicmp-echo\fP, \fBicmp-routeradvert\fP, \fBicmp-routersolicit\fP, +\fBicmp-timxceed\fP, \fBicmp-paramprob\fP, \fBicmp-tstamp\fP, +\fBicmp-tstampreply\fP, \fBicmp-ireq\fP, \fBicmp-ireqreply\fP, +\fBicmp-maskreq\fP, \fBicmp-maskreply\fP. + +The following TCP flags field values are available: \fBtcp-fin\fP, +\fBtcp-syn\fP, \fBtcp-rst\fP, \fBtcp-push\fP, +\fBtcp-ack\fP, \fBtcp-urg\fP. +.LP +Primitives may be combined using: +.IP +A parenthesized group of primitives and operators +(parentheses are special to the Shell and must be escaped). +.IP +Negation (`\fB!\fP' or `\fBnot\fP'). +.IP +Concatenation (`\fB&&\fP' or `\fBand\fP'). +.IP +Alternation (`\fB||\fP' or `\fBor\fP'). +.LP +Negation has highest precedence. +Alternation and concatenation have equal precedence and associate +left to right. +Note that explicit \fBand\fR tokens, not juxtaposition, +are now required for concatenation. +.LP +If an identifier is given without a keyword, the most recent keyword +is assumed. +For example, +.in +.5i +.nf +\fBnot host vs and ace\fR +.fi +.in -.5i +is short for +.in +.5i +.nf +\fBnot host vs and host ace\fR +.fi +.in -.5i +which should not be confused with +.in +.5i +.nf +\fBnot ( host vs or ace )\fR +.fi +.in -.5i +.SH EXAMPLES +.LP +To select all packets arriving at or departing from \fIsundown\fP: +.RS +.nf +\fBhost sundown\fP +.fi +.RE +.LP +To select traffic between \fIhelios\fR and either \fIhot\fR or \fIace\fR: +.RS +.nf +\fBhost helios and \\( hot or ace \\)\fP +.fi +.RE +.LP +To select all IP packets between \fIace\fR and any host except \fIhelios\fR: +.RS +.nf +\fBip host ace and not helios\fP +.fi +.RE +.LP +To select all traffic between local hosts and hosts at Berkeley: +.RS +.nf +.B +net ucb-ether +.fi +.RE +.LP +To select all ftp traffic through internet gateway \fIsnup\fP: +.RS +.nf +.B +gateway snup and (port ftp or ftp-data) +.fi +.RE +.LP +To select traffic neither sourced from nor destined for local hosts +(if you gateway to one other net, this stuff should never make it +onto your local net). +.RS +.nf +.B +ip and not net \fIlocalnet\fP +.fi +.RE +.LP +To select the start and end packets (the SYN and FIN packets) of each +TCP conversation that involves a non-local host. +.RS +.nf +.B +tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net \fIlocalnet\fP +.fi +.RE +.LP +To select all IPv4 HTTP packets to and from port 80, i.e. print only +packets that contain data, not, for example, SYN and FIN packets and +ACK-only packets. (IPv6 is left as an exercise for the reader.) +.RS +.nf +.B +tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0) +.fi +.RE +.LP +To select IP packets longer than 576 bytes sent through gateway \fIsnup\fP: +.RS +.nf +.B +gateway snup and ip[2:2] > 576 +.fi +.RE +.LP +To select IP broadcast or multicast packets that were +.I not +sent via Ethernet broadcast or multicast: +.RS +.nf +.B +ether[0] & 1 = 0 and ip[16] >= 224 +.fi +.RE +.LP +To select all ICMP packets that are not echo requests/replies (i.e., not +ping packets): +.RS +.nf +.B +icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply +.fi +.RE +.SH "SEE ALSO" +pcap(3PCAP) +.SH BUGS +Please send problems, bugs, questions, desirable enhancements, etc. to: +.LP +.RS +tcpdump-workers@lists.tcpdump.org +.RE +.LP +Filter expressions on fields other than those in Token Ring headers will +not correctly handle source-routed Token Ring packets. +.LP +Filter expressions on fields other than those in 802.11 headers will not +correctly handle 802.11 data packets with both To DS and From DS set. +.LP +.BR "ip6 proto" +should chase header chain, but at this moment it does not. +.BR "ip6 protochain" +is supplied for this behavior. +.LP +Arithmetic expression against transport layer headers, like \fBtcp[0]\fP, +does not work against IPv6 packets. +It only looks at IPv4 packets. diff --git a/tcpdump/jni/libpcap/pcap-int.h b/tcpdump/jni/libpcap/pcap-int.h new file mode 100644 index 0000000..2f71e11 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-int.h @@ -0,0 +1,463 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef pcap_int_h +#define pcap_int_h + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +#include +extern CRITICAL_SECTION g_PcapCompileCriticalSection; +#endif /* WIN32 */ + +#ifdef MSDOS +#include +#include +#endif + +#if (defined(_MSC_VER) && (_MSC_VER <= 1200)) /* we are compiling with Visual Studio 6, that doesn't support the LL suffix*/ + +/* + * Swap byte ordering of unsigned long long timestamp on a big endian + * machine. + */ +#define SWAPLL(ull) ((ull & 0xff00000000000000) >> 56) | \ + ((ull & 0x00ff000000000000) >> 40) | \ + ((ull & 0x0000ff0000000000) >> 24) | \ + ((ull & 0x000000ff00000000) >> 8) | \ + ((ull & 0x00000000ff000000) << 8) | \ + ((ull & 0x0000000000ff0000) << 24) | \ + ((ull & 0x000000000000ff00) << 40) | \ + ((ull & 0x00000000000000ff) << 56) + +#else /* A recent Visual studio compiler or not VC */ + +/* + * Swap byte ordering of unsigned long long timestamp on a big endian + * machine. + */ +#define SWAPLL(ull) ((ull & 0xff00000000000000LL) >> 56) | \ + ((ull & 0x00ff000000000000LL) >> 40) | \ + ((ull & 0x0000ff0000000000LL) >> 24) | \ + ((ull & 0x000000ff00000000LL) >> 8) | \ + ((ull & 0x00000000ff000000LL) << 8) | \ + ((ull & 0x0000000000ff0000LL) << 24) | \ + ((ull & 0x000000000000ff00LL) << 40) | \ + ((ull & 0x00000000000000ffLL) << 56) + +#endif /* _MSC_VER */ + +/* + * Maximum snapshot length. + * + * Somewhat arbitrary, but chosen to be: + * + * 1) big enough for maximum-size Linux loopback packets (65549) + * and some USB packets captured with USBPcap: + * + * http://desowin.org/usbpcap/ + * + * (> 131072, < 262144) + * + * and + * + * 2) small enough not to cause attempts to allocate huge amounts of + * memory; some applications might use the snapshot length in a + * savefile header to control the size of the buffer they allocate, + * so a size of, say, 2^31-1 might not work well. + * + * We don't enforce this in pcap_set_snaplen(), but we use it internally. + */ +#define MAXIMUM_SNAPLEN 262144 + +struct pcap_opt { + char *source; + int timeout; /* timeout for buffering */ + int buffer_size; + int promisc; + int rfmon; /* monitor mode */ + int immediate; /* immediate mode - deliver packets as soon as they arrive */ + int tstamp_type; + int tstamp_precision; +}; + +typedef int (*activate_op_t)(pcap_t *); +typedef int (*can_set_rfmon_op_t)(pcap_t *); +typedef int (*read_op_t)(pcap_t *, int cnt, pcap_handler, u_char *); +typedef int (*inject_op_t)(pcap_t *, const void *, size_t); +typedef int (*setfilter_op_t)(pcap_t *, struct bpf_program *); +typedef int (*setdirection_op_t)(pcap_t *, pcap_direction_t); +typedef int (*set_datalink_op_t)(pcap_t *, int); +typedef int (*getnonblock_op_t)(pcap_t *, char *); +typedef int (*setnonblock_op_t)(pcap_t *, int, char *); +typedef int (*stats_op_t)(pcap_t *, struct pcap_stat *); +#ifdef WIN32 +typedef int (*setbuff_op_t)(pcap_t *, int); +typedef int (*setmode_op_t)(pcap_t *, int); +typedef int (*setmintocopy_op_t)(pcap_t *, int); +typedef Adapter *(*getadapter_op_t)(pcap_t *); +#endif +typedef void (*cleanup_op_t)(pcap_t *); + +/* + * We put all the stuff used in the read code path at the beginning, + * to try to keep it together in the same cache line or lines. + */ +struct pcap { + /* + * Method to call to read packets on a live capture. + */ + read_op_t read_op; + + /* + * Method to call to read to read packets from a savefile. + */ + int (*next_packet_op)(pcap_t *, struct pcap_pkthdr *, u_char **); + +#ifdef WIN32 + ADAPTER *adapter; + LPPACKET Packet; + int nonblock; +#else + int fd; + int selectable_fd; +#endif /* WIN32 */ + + /* + * Read buffer. + */ + int bufsize; + u_char *buffer; + u_char *bp; + int cc; + + int break_loop; /* flag set to force break from packet-reading loop */ + + void *priv; /* private data for methods */ + + int swapped; + FILE *rfile; /* null if live capture, non-null if savefile */ + int fddipad; + struct pcap *next; /* list of open pcaps that need stuff cleared on close */ + + /* + * File version number; meaningful only for a savefile, but we + * keep it here so that apps that (mistakenly) ask for the + * version numbers will get the same zero values that they + * always did. + */ + int version_major; + int version_minor; + + int snapshot; + int linktype; /* Network linktype */ + int linktype_ext; /* Extended information stored in the linktype field of a file */ + int tzoff; /* timezone offset */ + int offset; /* offset for proper alignment */ + int activated; /* true if the capture is really started */ + int oldstyle; /* if we're opening with pcap_open_live() */ + + struct pcap_opt opt; + + /* + * Place holder for pcap_next(). + */ + u_char *pkt; + + /* We're accepting only packets in this direction/these directions. */ + pcap_direction_t direction; + + /* + * Flags to affect BPF code generation. + */ + int bpf_codegen_flags; + + /* + * Placeholder for filter code if bpf not in kernel. + */ + struct bpf_program fcode; + + char errbuf[PCAP_ERRBUF_SIZE + 1]; + int dlt_count; + u_int *dlt_list; + int tstamp_type_count; + u_int *tstamp_type_list; + int tstamp_precision_count; + u_int *tstamp_precision_list; + + struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */ + + /* + * More methods. + */ + activate_op_t activate_op; + can_set_rfmon_op_t can_set_rfmon_op; + inject_op_t inject_op; + setfilter_op_t setfilter_op; + setdirection_op_t setdirection_op; + set_datalink_op_t set_datalink_op; + getnonblock_op_t getnonblock_op; + setnonblock_op_t setnonblock_op; + stats_op_t stats_op; + + /* + * Routine to use as callback for pcap_next()/pcap_next_ex(). + */ + pcap_handler oneshot_callback; + +#ifdef WIN32 + /* + * These are, at least currently, specific to the Win32 NPF + * driver. + */ + setbuff_op_t setbuff_op; + setmode_op_t setmode_op; + setmintocopy_op_t setmintocopy_op; + getadapter_op_t getadapter_op; +#endif + cleanup_op_t cleanup_op; +}; + +/* + * BPF code generation flags. + */ +#define BPF_SPECIAL_VLAN_HANDLING 0x00000001 /* special VLAN handling for Linux */ + +/* + * This is a timeval as stored in a savefile. + * It has to use the same types everywhere, independent of the actual + * `struct timeval'; `struct timeval' has 32-bit tv_sec values on some + * platforms and 64-bit tv_sec values on other platforms, and writing + * out native `struct timeval' values would mean files could only be + * read on systems with the same tv_sec size as the system on which + * the file was written. + */ + +struct pcap_timeval { + bpf_int32 tv_sec; /* seconds */ + bpf_int32 tv_usec; /* microseconds */ +}; + +/* + * This is a `pcap_pkthdr' as actually stored in a savefile. + * + * Do not change the format of this structure, in any way (this includes + * changes that only affect the length of fields in this structure), + * and do not make the time stamp anything other than seconds and + * microseconds (e.g., seconds and nanoseconds). Instead: + * + * introduce a new structure for the new format; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed record + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old record header as well as files with the new record header + * (using the magic number to determine the header format). + * + * Then supply the changes by forking the branch at + * + * https://github.com/the-tcpdump-group/libpcap/issues + * + * and issuing a pull request, so that future versions of libpcap and + * programs that use it (such as tcpdump) will be able to read your new + * capture file format. + */ + +struct pcap_sf_pkthdr { + struct pcap_timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +}; + +/* + * How a `pcap_pkthdr' is actually stored in savefiles written + * by some patched versions of libpcap (e.g. the ones in Red + * Hat Linux 6.1 and 6.2). + * + * Do not change the format of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * Instead, introduce a new structure, as per the above. + */ + +struct pcap_sf_patched_pkthdr { + struct pcap_timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ + int index; + unsigned short protocol; + unsigned char pkt_type; +}; + +/* + * User data structure for the one-shot callback used for pcap_next() + * and pcap_next_ex(). + */ +struct oneshot_userdata { + struct pcap_pkthdr *hdr; + const u_char **pkt; + pcap_t *pd; +}; + +int yylex(void); + +#ifndef min +#define min(a, b) ((a) > (b) ? (b) : (a)) +#endif + +/* XXX should these be in pcap.h? */ +int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *); +int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *); + +#ifndef HAVE_STRLCPY +#define strlcpy(x, y, z) \ + (strncpy((x), (y), (z)), \ + ((z) <= 0 ? 0 : ((x)[(z) - 1] = '\0')), \ + strlen((y))) +#endif + +#include + +#if !defined(HAVE_SNPRINTF) +#define snprintf pcap_snprintf +extern int snprintf (char *, size_t, const char *, ...); +#endif + +#if !defined(HAVE_VSNPRINTF) +#define vsnprintf pcap_vsnprintf +extern int vsnprintf (char *, size_t, const char *, va_list ap); +#endif + +/* + * Does the packet count argument to a module's read routine say + * "supply packets until you run out of packets"? + */ +#define PACKET_COUNT_IS_UNLIMITED(count) ((count) <= 0) + +/* + * Routines that most pcap implementations can use for non-blocking mode. + */ +#if !defined(WIN32) && !defined(MSDOS) +int pcap_getnonblock_fd(pcap_t *, char *); +int pcap_setnonblock_fd(pcap_t *p, int, char *); +#endif + +/* + * Internal interfaces for "pcap_create()". + * + * "pcap_create_interface()" is the routine to do a pcap_create on + * a regular network interface. There are multiple implementations + * of this, one for each platform type (Linux, BPF, DLPI, etc.), + * with the one used chosen by the configure script. + * + * "pcap_create_common()" allocates and fills in a pcap_t, for use + * by pcap_create routines. + */ +pcap_t *pcap_create_interface(const char *, char *); +pcap_t *pcap_create_common(const char *, char *, size_t); +int pcap_do_addexit(pcap_t *); +void pcap_add_to_pcaps_to_close(pcap_t *); +void pcap_remove_from_pcaps_to_close(pcap_t *); +void pcap_cleanup_live_common(pcap_t *); +int pcap_not_initialized(pcap_t *); +int pcap_check_activated(pcap_t *); + +/* + * Internal interfaces for "pcap_findalldevs()". + * + * "pcap_findalldevs_interfaces()" finds interfaces using the + * "standard" mechanisms (SIOCGIFCONF, "getifaddrs()", etc.). + * + * "pcap_platform_finddevs()" is a platform-dependent routine to + * add devices not found by the "standard" mechanisms. + * + * "pcap_add_if()" adds an interface to the list of interfaces, for + * use by various "find interfaces" routines. + */ +int pcap_findalldevs_interfaces(pcap_if_t **, char *); +int pcap_platform_finddevs(pcap_if_t **, char *); +int add_addr_to_iflist(pcap_if_t **, const char *, u_int, struct sockaddr *, + size_t, struct sockaddr *, size_t, struct sockaddr *, size_t, + struct sockaddr *, size_t, char *); +int add_addr_to_dev(pcap_if_t *, struct sockaddr *, size_t, + struct sockaddr *, size_t, struct sockaddr *, size_t, + struct sockaddr *dstaddr, size_t, char *errbuf); +int pcap_add_if(pcap_if_t **, const char *, u_int, const char *, char *); +struct sockaddr *dup_sockaddr(struct sockaddr *, size_t); +int add_or_find_if(pcap_if_t **, pcap_if_t **, const char *, u_int, + const char *, char *); + +/* + * Internal interfaces for "pcap_open_offline()". + * + * "pcap_open_offline_common()" allocates and fills in a pcap_t, for use + * by pcap_open_offline routines. + * + * "sf_cleanup()" closes the file handle associated with a pcap_t, if + * appropriate, and frees all data common to all modules for handling + * savefile types. + */ +pcap_t *pcap_open_offline_common(char *ebuf, size_t size); +void sf_cleanup(pcap_t *p); + +/* + * Internal interfaces for both "pcap_create()" and routines that + * open savefiles. + * + * "pcap_oneshot()" is the standard one-shot callback for "pcap_next()" + * and "pcap_next_ex()". + */ +void pcap_oneshot(u_char *, const struct pcap_pkthdr *, const u_char *); + +#ifdef WIN32 +char *pcap_win32strerror(void); +#endif + +int install_bpf_program(pcap_t *, struct bpf_program *); + +int pcap_strcasecmp(const char *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tcpdump/jni/libpcap/pcap-libdlpi.c b/tcpdump/jni/libpcap/pcap-libdlpi.c new file mode 100644 index 0000000..333e532 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-libdlpi.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * This code contributed by Sagun Shakya (sagun.shakya@sun.com) + */ +/* + * Packet capture routines for DLPI using libdlpi under SunOS 5.11. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" +#include "dlpisubs.h" + +/* Forwards. */ +static int dlpromiscon(pcap_t *, bpf_u_int32); +static int pcap_read_libdlpi(pcap_t *, int, pcap_handler, u_char *); +static int pcap_inject_libdlpi(pcap_t *, const void *, size_t); +static void pcap_libdlpi_err(const char *, const char *, int, char *); +static void pcap_cleanup_libdlpi(pcap_t *); + +/* + * list_interfaces() will list all the network links that are + * available on a system. + */ +static boolean_t list_interfaces(const char *, void *); + +typedef struct linknamelist { + char linkname[DLPI_LINKNAME_MAX]; + struct linknamelist *lnl_next; +} linknamelist_t; + +typedef struct linkwalk { + linknamelist_t *lw_list; + int lw_err; +} linkwalk_t; + +/* + * The caller of this function should free the memory allocated + * for each linknamelist_t "entry" allocated. + */ +static boolean_t +list_interfaces(const char *linkname, void *arg) +{ + linkwalk_t *lwp = arg; + linknamelist_t *entry; + + if ((entry = calloc(1, sizeof(linknamelist_t))) == NULL) { + lwp->lw_err = ENOMEM; + return (B_TRUE); + } + (void) strlcpy(entry->linkname, linkname, DLPI_LINKNAME_MAX); + + if (lwp->lw_list == NULL) { + lwp->lw_list = entry; + } else { + entry->lnl_next = lwp->lw_list; + lwp->lw_list = entry; + } + + return (B_FALSE); +} + +static int +pcap_activate_libdlpi(pcap_t *p) +{ + struct pcap_dlpi *pd = p->priv; + int status = 0; + int retv; + dlpi_handle_t dh; + dlpi_info_t dlinfo; + + /* + * Enable Solaris raw and passive DLPI extensions; + * dlpi_open() will not fail if the underlying link does not support + * passive mode. See dlpi(7P) for details. + */ + retv = dlpi_open(p->opt.source, &dh, DLPI_RAW|DLPI_PASSIVE); + if (retv != DLPI_SUCCESS) { + if (retv == DLPI_ELINKNAMEINVAL || retv == DLPI_ENOLINK) + status = PCAP_ERROR_NO_SUCH_DEVICE; + else if (retv == DL_SYSERR && + (errno == EPERM || errno == EACCES)) + status = PCAP_ERROR_PERM_DENIED; + else + status = PCAP_ERROR; + pcap_libdlpi_err(p->opt.source, "dlpi_open", retv, + p->errbuf); + return (status); + } + pd->dlpi_hd = dh; + + if (p->opt.rfmon) { + /* + * This device exists, but we don't support monitor mode + * any platforms that support DLPI. + */ + status = PCAP_ERROR_RFMON_NOTSUP; + goto bad; + } + + /* Bind with DLPI_ANY_SAP. */ + if ((retv = dlpi_bind(pd->dlpi_hd, DLPI_ANY_SAP, 0)) != DLPI_SUCCESS) { + status = PCAP_ERROR; + pcap_libdlpi_err(p->opt.source, "dlpi_bind", retv, p->errbuf); + goto bad; + } + + /* Enable promiscuous mode. */ + if (p->opt.promisc) { + retv = dlpromiscon(p, DL_PROMISC_PHYS); + if (retv < 0) { + /* + * "You don't have permission to capture on + * this device" and "you don't have permission + * to capture in promiscuous mode on this + * device" are different; let the user know, + * so if they can't get permission to + * capture in promiscuous mode, they can at + * least try to capture in non-promiscuous + * mode. + * + * XXX - you might have to capture in + * promiscuous mode to see outgoing packets. + */ + if (retv == PCAP_ERROR_PERM_DENIED) + status = PCAP_ERROR_PROMISC_PERM_DENIED; + else + status = retv; + goto bad; + } + } else { + /* Try to enable multicast. */ + retv = dlpromiscon(p, DL_PROMISC_MULTI); + if (retv < 0) { + status = retv; + goto bad; + } + } + + /* Try to enable SAP promiscuity. */ + retv = dlpromiscon(p, DL_PROMISC_SAP); + if (retv < 0) { + /* + * Not fatal, since the DL_PROMISC_PHYS mode worked. + * Report it as a warning, however. + */ + if (p->opt.promisc) + status = PCAP_WARNING; + else { + status = retv; + goto bad; + } + } + + /* Determine link type. */ + if ((retv = dlpi_info(pd->dlpi_hd, &dlinfo, 0)) != DLPI_SUCCESS) { + status = PCAP_ERROR; + pcap_libdlpi_err(p->opt.source, "dlpi_info", retv, p->errbuf); + goto bad; + } + + if (pcap_process_mactype(p, dlinfo.di_mactype) != 0) { + status = PCAP_ERROR; + goto bad; + } + + p->fd = dlpi_fd(pd->dlpi_hd); + + /* Push and configure bufmod. */ + if (pcap_conf_bufmod(p, p->snapshot) != 0) { + status = PCAP_ERROR; + goto bad; + } + + /* + * Flush the read side. + */ + if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { + status = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", + pcap_strerror(errno)); + goto bad; + } + + /* Allocate data buffer. */ + if (pcap_alloc_databuf(p) != 0) { + status = PCAP_ERROR; + goto bad; + } + + /* + * "p->fd" is a FD for a STREAMS device, so "select()" and + * "poll()" should work on it. + */ + p->selectable_fd = p->fd; + + p->read_op = pcap_read_libdlpi; + p->inject_op = pcap_inject_libdlpi; + p->setfilter_op = install_bpf_program; /* No kernel filtering */ + p->setdirection_op = NULL; /* Not implemented */ + p->set_datalink_op = NULL; /* Can't change data link type */ + p->getnonblock_op = pcap_getnonblock_fd; + p->setnonblock_op = pcap_setnonblock_fd; + p->stats_op = pcap_stats_dlpi; + p->cleanup_op = pcap_cleanup_libdlpi; + + return (status); +bad: + pcap_cleanup_libdlpi(p); + return (status); +} + +#define STRINGIFY(n) #n + +static int +dlpromiscon(pcap_t *p, bpf_u_int32 level) +{ + struct pcap_dlpi *pd = p->priv; + int retv; + int err; + + retv = dlpi_promiscon(pd->dlpi_hd, level); + if (retv != DLPI_SUCCESS) { + if (retv == DL_SYSERR && + (errno == EPERM || errno == EACCES)) + err = PCAP_ERROR_PERM_DENIED; + else + err = PCAP_ERROR; + pcap_libdlpi_err(p->opt.source, "dlpi_promiscon" STRINGIFY(level), + retv, p->errbuf); + return (err); + } + return (0); +} + +/* + * In Solaris, the "standard" mechanism" i.e SIOCGLIFCONF will only find + * network links that are plumbed and are up. dlpi_walk(3DLPI) will find + * additional network links present in the system. + */ +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + int retv = 0; + + linknamelist_t *entry, *next; + linkwalk_t lw = {NULL, 0}; + int save_errno; + + /* dlpi_walk() for loopback will be added here. */ + + dlpi_walk(list_interfaces, &lw, 0); + + if (lw.lw_err != 0) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "dlpi_walk: %s", pcap_strerror(lw.lw_err)); + retv = -1; + goto done; + } + + /* Add linkname if it does not exist on the list. */ + for (entry = lw.lw_list; entry != NULL; entry = entry->lnl_next) { + if (pcap_add_if(alldevsp, entry->linkname, 0, NULL, errbuf) < 0) + retv = -1; + } +done: + save_errno = errno; + for (entry = lw.lw_list; entry != NULL; entry = next) { + next = entry->lnl_next; + free(entry); + } + errno = save_errno; + + return (retv); +} + +/* + * Read data received on DLPI handle. Returns -2 if told to terminate, else + * returns the number of packets read. + */ +static int +pcap_read_libdlpi(pcap_t *p, int count, pcap_handler callback, u_char *user) +{ + struct pcap_dlpi *pd = p->priv; + int len; + u_char *bufp; + size_t msglen; + int retv; + + len = p->cc; + if (len != 0) { + bufp = p->bp; + goto process_pkts; + } + do { + /* Has "pcap_breakloop()" been called? */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it has, + * and return -2 to indicate that we were told to + * break out of the loop. + */ + p->break_loop = 0; + return (-2); + } + + msglen = p->bufsize; + bufp = p->buffer + p->offset; + + retv = dlpi_recv(pd->dlpi_hd, NULL, NULL, bufp, + &msglen, -1, NULL); + if (retv != DLPI_SUCCESS) { + /* + * This is most likely a call to terminate out of the + * loop. So, do not return an error message, instead + * check if "pcap_breakloop()" has been called above. + */ + if (retv == DL_SYSERR && errno == EINTR) { + len = 0; + continue; + } + pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), + "dlpi_recv", retv, p->errbuf); + return (-1); + } + len = msglen; + } while (len == 0); + +process_pkts: + return (pcap_process_pkts(p, callback, user, count, bufp, len)); +} + +static int +pcap_inject_libdlpi(pcap_t *p, const void *buf, size_t size) +{ + struct pcap_dlpi *pd = p->priv; + int retv; + + retv = dlpi_send(pd->dlpi_hd, NULL, 0, buf, size, NULL); + if (retv != DLPI_SUCCESS) { + pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), "dlpi_send", retv, + p->errbuf); + return (-1); + } + /* + * dlpi_send(3DLPI) does not provide a way to return the number of + * bytes sent on the wire. Based on the fact that DLPI_SUCCESS was + * returned we are assuming 'size' bytes were sent. + */ + return (size); +} + +/* + * Close dlpi handle. + */ +static void +pcap_cleanup_libdlpi(pcap_t *p) +{ + struct pcap_dlpi *pd = p->priv; + + if (pd->dlpi_hd != NULL) { + dlpi_close(pd->dlpi_hd); + pd->dlpi_hd = NULL; + p->fd = -1; + } + pcap_cleanup_live_common(p); +} + +/* + * Write error message to buffer. + */ +static void +pcap_libdlpi_err(const char *linkname, const char *func, int err, char *errbuf) +{ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s", + func, linkname, dlpi_strerror(err)); +} + +pcap_t * +pcap_create_interface(const char *device, char *ebuf) +{ + pcap_t *p; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_dlpi)); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_libdlpi; + return (p); +} diff --git a/tcpdump/jni/libpcap/pcap-linktype.manmisc.in b/tcpdump/jni/libpcap/pcap-linktype.manmisc.in new file mode 100644 index 0000000..e42c5b3 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-linktype.manmisc.in @@ -0,0 +1,48 @@ +.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP-LINKTYPE @MAN_MISC_INFO@ "12 March 2011" +.SH NAME +pcap-linktype \- link-layer header types supported by libpcap +.SH DESCRIPTION +For a live capture or ``savefile'', libpcap supplies, as the return +value of the +.BR pcap_datalink (3PCAP) +routine, a value that indicates the type of link-layer header at the +beginning of the packets it provides. This is not necessarily the type +of link-layer header that the packets being captured have on the network +from which they're being captured; for example, packets from an IEEE +802.11 network might be provided by libpcap with Ethernet headers that +the network adapter or the network adapter driver generates from the +802.11 headers. The names for those values begin with +.BR DLT_ , +so they are sometimes called "DLT_ values". +.PP +The values stored in the link-layer header type field in the savefile +header are, in most but not all cases, the same as the values returned +by +.BR pcap_datalink() . +The names for those values begin with +.BR LINKTYPE_ . +.PP +The link-layer header types supported by libpcap are described at +http://www.tcpdump.org/linktypes.html. +.SH SEE ALSO +pcap_datalink(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap-linux.c b/tcpdump/jni/libpcap/pcap-linux.c new file mode 100644 index 0000000..2a13382 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-linux.c @@ -0,0 +1,6605 @@ +/* + * pcap-linux.c: Packet capture interface to the Linux kernel + * + * Copyright (c) 2000 Torsten Landschoff + * Sebastian Krahmer + * + * License: BSD + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Modifications: Added PACKET_MMAP support + * Paolo Abeni + * Added TPACKET_V3 support + * Gabor Tatarka + * + * based on previous works of: + * Simon Patarin + * Phil Wood + * + * Monitor-mode support for mac80211 includes code taken from the iw + * command; the copyright notice for that code is + * + * Copyright (c) 2007, 2008 Johannes Berg + * Copyright (c) 2007 Andy Lutomirski + * Copyright (c) 2007 Mike Kershaw + * Copyright (c) 2008 Gábor Stefanik + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Known problems with 2.0[.x] kernels: + * + * - The loopback device gives every packet twice; on 2.2[.x] kernels, + * if we use PF_PACKET, we can filter out the transmitted version + * of the packet by using data in the "sockaddr_ll" returned by + * "recvfrom()", but, on 2.0[.x] kernels, we have to use + * PF_INET/SOCK_PACKET, which means "recvfrom()" supplies a + * "sockaddr_pkt" which doesn't give us enough information to let + * us do that. + * + * - We have to set the interface's IFF_PROMISC flag ourselves, if + * we're to run in promiscuous mode, which means we have to turn + * it off ourselves when we're done; the kernel doesn't keep track + * of how many sockets are listening promiscuously, which means + * it won't get turned off automatically when no sockets are + * listening promiscuously. We catch "pcap_close()" and, for + * interfaces we put into promiscuous mode, take them out of + * promiscuous mode - which isn't necessarily the right thing to + * do, if another socket also requested promiscuous mode between + * the time when we opened the socket and the time when we close + * the socket. + * + * - MSG_TRUNC isn't supported, so you can't specify that "recvfrom()" + * return the amount of data that you could have read, rather than + * the amount that was returned, so we can't just allocate a buffer + * whose size is the snapshot length and pass the snapshot length + * as the byte count, and also pass MSG_TRUNC, so that the return + * value tells us how long the packet was on the wire. + * + * This means that, if we want to get the actual size of the packet, + * so we can return it in the "len" field of the packet header, + * we have to read the entire packet, not just the part that fits + * within the snapshot length, and thus waste CPU time copying data + * from the kernel that our caller won't see. + * + * We have to get the actual size, and supply it in "len", because + * otherwise, the IP dissector in tcpdump, for example, will complain + * about "truncated-ip", as the packet will appear to have been + * shorter, on the wire, than the IP header said it should have been. + */ + + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" +#include "pcap/sll.h" +#include "pcap/vlan.h" + +/* + * If PF_PACKET is defined, we can use {SOCK_RAW,SOCK_DGRAM}/PF_PACKET + * sockets rather than SOCK_PACKET sockets. + * + * To use them, we include rather than + * ; we do so because + * + * some Linux distributions (e.g., Slackware 4.0) have 2.2 or + * later kernels and libc5, and don't provide a + * file; + * + * not all versions of glibc2 have a file + * that defines stuff needed for some of the 2.4-or-later-kernel + * features, so if the system has a 2.4 or later kernel, we + * still can't use those features. + * + * We're already including a number of other headers, and + * this code is Linux-specific (no other OS has PF_PACKET sockets as + * a raw packet capture mechanism), so it's not as if you gain any + * useful portability by using + * + * XXX - should we just include even if PF_PACKET + * isn't defined? It only defines one data structure in 2.0.x, so + * it shouldn't cause any problems. + */ +#ifdef PF_PACKET +# include + + /* + * On at least some Linux distributions (for example, Red Hat 5.2), + * there's no file, but PF_PACKET is defined if + * you include , but doesn't define + * any of the PF_PACKET stuff such as "struct sockaddr_ll" or any of + * the PACKET_xxx stuff. + * + * So we check whether PACKET_HOST is defined, and assume that we have + * PF_PACKET sockets only if it is defined. + */ +# ifdef PACKET_HOST +# define HAVE_PF_PACKET_SOCKETS +# ifdef PACKET_AUXDATA +# define HAVE_PACKET_AUXDATA +# endif /* PACKET_AUXDATA */ +# endif /* PACKET_HOST */ + + + /* check for memory mapped access avaibility. We assume every needed + * struct is defined if the macro TPACKET_HDRLEN is defined, because it + * uses many ring related structs and macros */ +# ifdef PCAP_SUPPORT_PACKET_RING +# ifdef TPACKET_HDRLEN +# define HAVE_PACKET_RING +# ifdef TPACKET3_HDRLEN +# define HAVE_TPACKET3 +# endif /* TPACKET3_HDRLEN */ +# ifdef TPACKET2_HDRLEN +# define HAVE_TPACKET2 +# else /* TPACKET2_HDRLEN */ +# define TPACKET_V1 0 /* Old kernel with only V1, so no TPACKET_Vn defined */ +# endif /* TPACKET2_HDRLEN */ +# endif /* TPACKET_HDRLEN */ +# endif /* PCAP_SUPPORT_PACKET_RING */ +#endif /* PF_PACKET */ + +#ifdef SO_ATTACH_FILTER +#include +#include +#endif + +#ifdef HAVE_LINUX_NET_TSTAMP_H +#include +#endif + +#ifdef HAVE_LINUX_SOCKIOS_H +#include +#endif + +#ifdef HAVE_LINUX_IF_BONDING_H +#include +#endif + +/* + * Got Wireless Extensions? + */ +#ifdef HAVE_LINUX_WIRELESS_H +#include +#endif /* HAVE_LINUX_WIRELESS_H */ + +/* + * Got libnl? + */ +#ifdef HAVE_LIBNL +#include + +#include +#include +#include +#include +#include +#endif /* HAVE_LIBNL */ + +/* + * Got ethtool support? + */ +#ifdef HAVE_LINUX_ETHTOOL_H +#include +#endif + +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif + +#ifndef MSG_TRUNC +/* + * This is being compiled on a system that lacks MSG_TRUNC; define it + * with the value it has in the 2.2 and later kernels, so that, on + * those kernels, when we pass it in the flags argument to "recvfrom()" + * we're passing the right value and thus get the MSG_TRUNC behavior + * we want. (We don't get that behavior on 2.0[.x] kernels, because + * they didn't support MSG_TRUNC.) + */ +#define MSG_TRUNC 0x20 +#endif + +#ifndef SOL_PACKET +/* + * This is being compiled on a system that lacks SOL_PACKET; define it + * with the value it has in the 2.2 and later kernels, so that we can + * set promiscuous mode in the good modern way rather than the old + * 2.0-kernel crappy way. + */ +#define SOL_PACKET 263 +#endif + +#define MAX_LINKHEADER_SIZE 256 + +/* + * When capturing on all interfaces we use this as the buffer size. + * Should be bigger then all MTUs that occur in real life. + * 64kB should be enough for now. + */ +#define BIGGER_THAN_ALL_MTUS (64*1024) + +/* + * Private data for capturing on Linux SOCK_PACKET or PF_PACKET sockets. + */ +struct pcap_linux { + u_int packets_read; /* count of packets read with recvfrom() */ + long proc_dropped; /* packets reported dropped by /proc/net/dev */ + struct pcap_stat stat; + + char *device; /* device name */ + int filter_in_userland; /* must filter in userland */ + int blocks_to_filter_in_userland; + int must_do_on_close; /* stuff we must do when we close */ + int timeout; /* timeout for buffering */ + int sock_packet; /* using Linux 2.0 compatible interface */ + int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */ + int ifindex; /* interface index of device we're bound to */ + int lo_ifindex; /* interface index of the loopback device */ + bpf_u_int32 oldmode; /* mode to restore when turning monitor mode off */ + char *mondevice; /* mac80211 monitor device we created */ + u_char *mmapbuf; /* memory-mapped region pointer */ + size_t mmapbuflen; /* size of region */ + int vlan_offset; /* offset at which to insert vlan tags; if -1, don't insert */ + u_int tp_version; /* version of tpacket_hdr for mmaped ring */ + u_int tp_hdrlen; /* hdrlen of tpacket_hdr for mmaped ring */ + u_char *oneshot_buffer; /* buffer for copy of packet */ +#ifdef HAVE_TPACKET3 + unsigned char *current_packet; /* Current packet within the TPACKET_V3 block. Move to next block if NULL. */ + int packets_left; /* Unhandled packets left within the block from previous call to pcap_read_linux_mmap_v3 in case of TPACKET_V3. */ +#endif +}; + +/* + * Stuff to do when we close. + */ +#define MUST_CLEAR_PROMISC 0x00000001 /* clear promiscuous mode */ +#define MUST_CLEAR_RFMON 0x00000002 /* clear rfmon (monitor) mode */ +#define MUST_DELETE_MONIF 0x00000004 /* delete monitor-mode interface */ + +/* + * Prototypes for internal functions and methods. + */ +static void map_arphrd_to_dlt(pcap_t *, int, int, const char *, int); +#ifdef HAVE_PF_PACKET_SOCKETS +static short int map_packet_type_to_sll_type(short int); +#endif +static int pcap_activate_linux(pcap_t *); +static int activate_old(pcap_t *); +static int activate_new(pcap_t *); +static int activate_mmap(pcap_t *, int *); +static int pcap_can_set_rfmon_linux(pcap_t *); +static int pcap_read_linux(pcap_t *, int, pcap_handler, u_char *); +static int pcap_read_packet(pcap_t *, pcap_handler, u_char *); +static int pcap_inject_linux(pcap_t *, const void *, size_t); +static int pcap_stats_linux(pcap_t *, struct pcap_stat *); +static int pcap_setfilter_linux(pcap_t *, struct bpf_program *); +static int pcap_setdirection_linux(pcap_t *, pcap_direction_t); +static int pcap_set_datalink_linux(pcap_t *, int); +static void pcap_cleanup_linux(pcap_t *); + +/* + * This is what the header structure looks like in a 64-bit kernel; + * we use this, rather than struct tpacket_hdr, if we're using + * TPACKET_V1 in 32-bit code running on a 64-bit kernel. + */ +struct tpacket_hdr_64 { + uint64_t tp_status; + unsigned int tp_len; + unsigned int tp_snaplen; + unsigned short tp_mac; + unsigned short tp_net; + unsigned int tp_sec; + unsigned int tp_usec; +}; + +/* + * We use this internally as the tpacket version for TPACKET_V1 in + * 32-bit code on a 64-bit kernel. + */ +#define TPACKET_V1_64 99 + +union thdr { + struct tpacket_hdr *h1; + struct tpacket_hdr_64 *h1_64; +#ifdef HAVE_TPACKET2 + struct tpacket2_hdr *h2; +#endif +#ifdef HAVE_TPACKET3 + struct tpacket_block_desc *h3; +#endif + void *raw; +}; + +#ifdef HAVE_PACKET_RING +#define RING_GET_FRAME(h) (((union thdr **)h->buffer)[h->offset]) + +static void destroy_ring(pcap_t *handle); +static int create_ring(pcap_t *handle, int *status); +static int prepare_tpacket_socket(pcap_t *handle); +static void pcap_cleanup_linux_mmap(pcap_t *); +static int pcap_read_linux_mmap_v1(pcap_t *, int, pcap_handler , u_char *); +static int pcap_read_linux_mmap_v1_64(pcap_t *, int, pcap_handler , u_char *); +#ifdef HAVE_TPACKET2 +static int pcap_read_linux_mmap_v2(pcap_t *, int, pcap_handler , u_char *); +#endif +#ifdef HAVE_TPACKET3 +static int pcap_read_linux_mmap_v3(pcap_t *, int, pcap_handler , u_char *); +#endif +static int pcap_setfilter_linux_mmap(pcap_t *, struct bpf_program *); +static int pcap_setnonblock_mmap(pcap_t *p, int nonblock, char *errbuf); +static int pcap_getnonblock_mmap(pcap_t *p, char *errbuf); +static void pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h, + const u_char *bytes); +#endif + +#ifdef TP_STATUS_VLAN_TPID_VALID +# define VLAN_TPID(hdr, hv) (((hv)->tp_vlan_tpid || ((hdr)->tp_status & TP_STATUS_VLAN_TPID_VALID)) ? (hv)->tp_vlan_tpid : ETH_P_8021Q) +#else +# define VLAN_TPID(hdr, hv) ETH_P_8021Q +#endif + +/* + * Wrap some ioctl calls + */ +#ifdef HAVE_PF_PACKET_SOCKETS +static int iface_get_id(int fd, const char *device, char *ebuf); +#endif /* HAVE_PF_PACKET_SOCKETS */ +static int iface_get_mtu(int fd, const char *device, char *ebuf); +static int iface_get_arptype(int fd, const char *device, char *ebuf); +#ifdef HAVE_PF_PACKET_SOCKETS +static int iface_bind(int fd, int ifindex, char *ebuf); +#ifdef IW_MODE_MONITOR +static int has_wext(int sock_fd, const char *device, char *ebuf); +#endif /* IW_MODE_MONITOR */ +static int enter_rfmon_mode(pcap_t *handle, int sock_fd, + const char *device); +#endif /* HAVE_PF_PACKET_SOCKETS */ +#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) +static int iface_ethtool_get_ts_info(pcap_t *handle, char *ebuf); +#endif +#ifdef HAVE_PACKET_RING +static int iface_get_offload(pcap_t *handle); +#endif +static int iface_bind_old(int fd, const char *device, char *ebuf); + +#ifdef SO_ATTACH_FILTER +static int fix_program(pcap_t *handle, struct sock_fprog *fcode, + int is_mapped); +static int fix_offset(struct bpf_insn *p); +static int set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode); +static int reset_kernel_filter(pcap_t *handle); + +static struct sock_filter total_insn + = BPF_STMT(BPF_RET | BPF_K, 0); +static struct sock_fprog total_fcode + = { 1, &total_insn }; +#endif /* SO_ATTACH_FILTER */ + +pcap_t * +pcap_create_interface(const char *device, char *ebuf) +{ + pcap_t *handle; + + handle = pcap_create_common(device, ebuf, sizeof (struct pcap_linux)); + if (handle == NULL) + return NULL; + + handle->activate_op = pcap_activate_linux; + handle->can_set_rfmon_op = pcap_can_set_rfmon_linux; + +#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) + /* + * See what time stamp types we support. + */ + if (iface_ethtool_get_ts_info(handle, ebuf) == -1) { + free(handle); + return NULL; + } +#endif + +#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) + /* + * We claim that we support microsecond and nanosecond time + * stamps. + * + * XXX - with adapter-supplied time stamps, can we choose + * microsecond or nanosecond time stamps on arbitrary + * adapters? + */ + handle->tstamp_precision_count = 2; + handle->tstamp_precision_list = malloc(2 * sizeof(u_int)); + if (handle->tstamp_precision_list == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + if (handle->tstamp_type_list != NULL) + free(handle->tstamp_type_list); + free(handle); + return NULL; + } + handle->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; + handle->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; +#endif /* defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) */ + + return handle; +} + +#ifdef HAVE_LIBNL +/* + * If interface {if} is a mac80211 driver, the file + * /sys/class/net/{if}/phy80211 is a symlink to + * /sys/class/ieee80211/{phydev}, for some {phydev}. + * + * On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at + * least, has a "wmaster0" device and a "wlan0" device; the + * latter is the one with the IP address. Both show up in + * "tcpdump -D" output. Capturing on the wmaster0 device + * captures with 802.11 headers. + * + * airmon-ng searches through /sys/class/net for devices named + * monN, starting with mon0; as soon as one *doesn't* exist, + * it chooses that as the monitor device name. If the "iw" + * command exists, it does "iw dev {if} interface add {monif} + * type monitor", where {monif} is the monitor device. It + * then (sigh) sleeps .1 second, and then configures the + * device up. Otherwise, if /sys/class/ieee80211/{phydev}/add_iface + * is a file, it writes {mondev}, without a newline, to that file, + * and again (sigh) sleeps .1 second, and then iwconfig's that + * device into monitor mode and configures it up. Otherwise, + * you can't do monitor mode. + * + * All these devices are "glued" together by having the + * /sys/class/net/{device}/phy80211 links pointing to the same + * place, so, given a wmaster, wlan, or mon device, you can + * find the other devices by looking for devices with + * the same phy80211 link. + * + * To turn monitor mode off, delete the monitor interface, + * either with "iw dev {monif} interface del" or by sending + * {monif}, with no NL, down /sys/class/ieee80211/{phydev}/remove_iface + * + * Note: if you try to create a monitor device named "monN", and + * there's already a "monN" device, it fails, as least with + * the netlink interface (which is what iw uses), with a return + * value of -ENFILE. (Return values are negative errnos.) We + * could probably use that to find an unused device. + * + * Yes, you can have multiple monitor devices for a given + * physical device. +*/ + +/* + * Is this a mac80211 device? If so, fill in the physical device path and + * return 1; if not, return 0. On an error, fill in handle->errbuf and + * return PCAP_ERROR. + */ +static int +get_mac80211_phydev(pcap_t *handle, const char *device, char *phydev_path, + size_t phydev_max_pathlen) +{ + char *pathstr; + ssize_t bytes_read; + + /* + * Generate the path string for the symlink to the physical device. + */ + if (asprintf(&pathstr, "/sys/class/net/%s/phy80211", device) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't generate path name string for /sys/class/net device", + device); + return PCAP_ERROR; + } + bytes_read = readlink(pathstr, phydev_path, phydev_max_pathlen); + if (bytes_read == -1) { + if (errno == ENOENT || errno == EINVAL) { + /* + * Doesn't exist, or not a symlink; assume that + * means it's not a mac80211 device. + */ + free(pathstr); + return 0; + } + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't readlink %s: %s", device, pathstr, + strerror(errno)); + free(pathstr); + return PCAP_ERROR; + } + free(pathstr); + phydev_path[bytes_read] = '\0'; + return 1; +} + +#ifdef HAVE_LIBNL_SOCKETS +#define get_nl_errmsg nl_geterror +#else +/* libnl 2.x compatibility code */ + +#define nl_sock nl_handle + +static inline struct nl_handle * +nl_socket_alloc(void) +{ + return nl_handle_alloc(); +} + +static inline void +nl_socket_free(struct nl_handle *h) +{ + nl_handle_destroy(h); +} + +#define get_nl_errmsg strerror + +static inline int +__genl_ctrl_alloc_cache(struct nl_handle *h, struct nl_cache **cache) +{ + struct nl_cache *tmp = genl_ctrl_alloc_cache(h); + if (!tmp) + return -ENOMEM; + *cache = tmp; + return 0; +} +#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache +#endif /* !HAVE_LIBNL_SOCKETS */ + +struct nl80211_state { + struct nl_sock *nl_sock; + struct nl_cache *nl_cache; + struct genl_family *nl80211; +}; + +static int +nl80211_init(pcap_t *handle, struct nl80211_state *state, const char *device) +{ + int err; + + state->nl_sock = nl_socket_alloc(); + if (!state->nl_sock) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: failed to allocate netlink handle", device); + return PCAP_ERROR; + } + + if (genl_connect(state->nl_sock)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: failed to connect to generic netlink", device); + goto out_handle_destroy; + } + + err = genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache); + if (err < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: failed to allocate generic netlink cache: %s", + device, get_nl_errmsg(-err)); + goto out_handle_destroy; + } + + state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211"); + if (!state->nl80211) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl80211 not found", device); + goto out_cache_free; + } + + return 0; + +out_cache_free: + nl_cache_free(state->nl_cache); +out_handle_destroy: + nl_socket_free(state->nl_sock); + return PCAP_ERROR; +} + +static void +nl80211_cleanup(struct nl80211_state *state) +{ + genl_family_put(state->nl80211); + nl_cache_free(state->nl_cache); + nl_socket_free(state->nl_sock); +} + +static int +add_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, + const char *device, const char *mondevice) +{ + int ifindex; + struct nl_msg *msg; + int err; + + ifindex = iface_get_id(sock_fd, device, handle->errbuf); + if (ifindex == -1) + return PCAP_ERROR; + + msg = nlmsg_alloc(); + if (!msg) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: failed to allocate netlink msg", device); + return PCAP_ERROR; + } + + genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, + 0, NL80211_CMD_NEW_INTERFACE, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice); + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); + + err = nl_send_auto_complete(state->nl_sock, msg); + if (err < 0) { +#if defined HAVE_LIBNL_NLE + if (err == -NLE_FAILURE) { +#else + if (err == -ENFILE) { +#endif + /* + * Device not available; our caller should just + * keep trying. (libnl 2.x maps ENFILE to + * NLE_FAILURE; it can also map other errors + * to that, but there's not much we can do + * about that.) + */ + nlmsg_free(msg); + return 0; + } else { + /* + * Real failure, not just "that device is not + * available. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_send_auto_complete failed adding %s interface: %s", + device, mondevice, get_nl_errmsg(-err)); + nlmsg_free(msg); + return PCAP_ERROR; + } + } + err = nl_wait_for_ack(state->nl_sock); + if (err < 0) { +#if defined HAVE_LIBNL_NLE + if (err == -NLE_FAILURE) { +#else + if (err == -ENFILE) { +#endif + /* + * Device not available; our caller should just + * keep trying. (libnl 2.x maps ENFILE to + * NLE_FAILURE; it can also map other errors + * to that, but there's not much we can do + * about that.) + */ + nlmsg_free(msg); + return 0; + } else { + /* + * Real failure, not just "that device is not + * available. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_wait_for_ack failed adding %s interface: %s", + device, mondevice, get_nl_errmsg(-err)); + nlmsg_free(msg); + return PCAP_ERROR; + } + } + + /* + * Success. + */ + nlmsg_free(msg); + return 1; + +nla_put_failure: + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_put failed adding %s interface", + device, mondevice); + nlmsg_free(msg); + return PCAP_ERROR; +} + +static int +del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, + const char *device, const char *mondevice) +{ + int ifindex; + struct nl_msg *msg; + int err; + + ifindex = iface_get_id(sock_fd, mondevice, handle->errbuf); + if (ifindex == -1) + return PCAP_ERROR; + + msg = nlmsg_alloc(); + if (!msg) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: failed to allocate netlink msg", device); + return PCAP_ERROR; + } + + genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, + 0, NL80211_CMD_DEL_INTERFACE, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + + err = nl_send_auto_complete(state->nl_sock, msg); + if (err < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_send_auto_complete failed deleting %s interface: %s", + device, mondevice, get_nl_errmsg(-err)); + nlmsg_free(msg); + return PCAP_ERROR; + } + err = nl_wait_for_ack(state->nl_sock); + if (err < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_wait_for_ack failed adding %s interface: %s", + device, mondevice, get_nl_errmsg(-err)); + nlmsg_free(msg); + return PCAP_ERROR; + } + + /* + * Success. + */ + nlmsg_free(msg); + return 1; + +nla_put_failure: + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_put failed deleting %s interface", + device, mondevice); + nlmsg_free(msg); + return PCAP_ERROR; +} + +static int +enter_rfmon_mode_mac80211(pcap_t *handle, int sock_fd, const char *device) +{ + struct pcap_linux *handlep = handle->priv; + int ret; + char phydev_path[PATH_MAX+1]; + struct nl80211_state nlstate; + struct ifreq ifr; + u_int n; + + /* + * Is this a mac80211 device? + */ + ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX); + if (ret < 0) + return ret; /* error */ + if (ret == 0) + return 0; /* no error, but not mac80211 device */ + + /* + * XXX - is this already a monN device? + * If so, we're done. + * Is that determined by old Wireless Extensions ioctls? + */ + + /* + * OK, it's apparently a mac80211 device. + * Try to find an unused monN device for it. + */ + ret = nl80211_init(handle, &nlstate, device); + if (ret != 0) + return ret; + for (n = 0; n < UINT_MAX; n++) { + /* + * Try mon{n}. + */ + char mondevice[3+10+1]; /* mon{UINT_MAX}\0 */ + + snprintf(mondevice, sizeof mondevice, "mon%u", n); + ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice); + if (ret == 1) { + handlep->mondevice = strdup(mondevice); + goto added; + } + if (ret < 0) { + /* + * Hard failure. Just return ret; handle->errbuf + * has already been set. + */ + nl80211_cleanup(&nlstate); + return ret; + } + } + + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: No free monN interfaces", device); + nl80211_cleanup(&nlstate); + return PCAP_ERROR; + +added: + +#if 0 + /* + * Sleep for .1 seconds. + */ + delay.tv_sec = 0; + delay.tv_nsec = 500000000; + nanosleep(&delay, NULL); +#endif + + /* + * If we haven't already done so, arrange to have + * "pcap_close_all()" called when we exit. + */ + if (!pcap_do_addexit(handle)) { + /* + * "atexit()" failed; don't put the interface + * in rfmon mode, just give up. + */ + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* + * Now configure the monitor interface up. + */ + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name)); + if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't get flags for %s: %s", device, + handlep->mondevice, strerror(errno)); + del_mon_if(handle, sock_fd, &nlstate, device, + handlep->mondevice); + nl80211_cleanup(&nlstate); + return PCAP_ERROR; + } + ifr.ifr_flags |= IFF_UP|IFF_RUNNING; + if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't set flags for %s: %s", device, + handlep->mondevice, strerror(errno)); + del_mon_if(handle, sock_fd, &nlstate, device, + handlep->mondevice); + nl80211_cleanup(&nlstate); + return PCAP_ERROR; + } + + /* + * Success. Clean up the libnl state. + */ + nl80211_cleanup(&nlstate); + + /* + * Note that we have to delete the monitor device when we close + * the handle. + */ + handlep->must_do_on_close |= MUST_DELETE_MONIF; + + /* + * Add this to the list of pcaps to close when we exit. + */ + pcap_add_to_pcaps_to_close(handle); + + return 1; +} +#endif /* HAVE_LIBNL */ + +#ifdef IW_MODE_MONITOR +/* + * Bonding devices mishandle unknown ioctls; they fail with ENODEV + * rather than ENOTSUP, EOPNOTSUPP, or ENOTTY, so Wireless Extensions + * will fail with ENODEV if we try to do them on a bonding device, + * making us return a "no such device" indication rather than just + * saying "no Wireless Extensions". + * + * So we check for bonding devices, if we can, before trying those + * ioctls, by trying a bonding device information query ioctl to see + * whether it succeeds. + */ +static int +is_bonding_device(int fd, const char *device) +{ +#if defined(BOND_INFO_QUERY_OLD) || defined(SIOCBONDINFOQUERY) + struct ifreq ifr; + ifbond ifb; + + memset(&ifr, 0, sizeof ifr); + strlcpy(ifr.ifr_name, device, sizeof ifr.ifr_name); + memset(&ifb, 0, sizeof ifb); + ifr.ifr_data = (caddr_t)&ifb; +#ifdef SIOCBONDINFOQUERY + if (ioctl(fd, SIOCBONDINFOQUERY, &ifr) == 0) +#else /* SIOCBONDINFOQUERY */ + if (ioctl(fd, BOND_INFO_QUERY_OLD, &ifr) == 0) +#endif /* SIOCBONDINFOQUERY */ + return 1; /* success, so it's a bonding device */ +#endif /* defined(BOND_INFO_QUERY_OLD) || defined(SIOCBONDINFOQUERY) */ + + return 0; /* no, it's not a bonding device */ +} +#endif /* IW_MODE_MONITOR */ + +static int +pcap_can_set_rfmon_linux(pcap_t *handle) +{ +#ifdef HAVE_LIBNL + char phydev_path[PATH_MAX+1]; + int ret; +#endif +#ifdef IW_MODE_MONITOR + int sock_fd; + struct iwreq ireq; +#endif + + if (strcmp(handle->opt.source, "any") == 0) { + /* + * Monitor mode makes no sense on the "any" device. + */ + return 0; + } + +#ifdef HAVE_LIBNL + /* + * Bleah. There doesn't seem to be a way to ask a mac80211 + * device, through libnl, whether it supports monitor mode; + * we'll just check whether the device appears to be a + * mac80211 device and, if so, assume the device supports + * monitor mode. + * + * wmaster devices don't appear to support the Wireless + * Extensions, but we can create a mon device for a + * wmaster device, so we don't bother checking whether + * a mac80211 device supports the Wireless Extensions. + */ + ret = get_mac80211_phydev(handle, handle->opt.source, phydev_path, + PATH_MAX); + if (ret < 0) + return ret; /* error */ + if (ret == 1) + return 1; /* mac80211 device */ +#endif + +#ifdef IW_MODE_MONITOR + /* + * Bleah. There doesn't appear to be an ioctl to use to ask + * whether a device supports monitor mode; we'll just do + * SIOCGIWMODE and, if it succeeds, assume the device supports + * monitor mode. + * + * Open a socket on which to attempt to get the mode. + * (We assume that if we have Wireless Extensions support + * we also have PF_PACKET support.) + */ + sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (sock_fd == -1) { + (void)snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + return PCAP_ERROR; + } + + if (is_bonding_device(sock_fd, handle->opt.source)) { + /* It's a bonding device, so don't even try. */ + close(sock_fd); + return 0; + } + + /* + * Attempt to get the current mode. + */ + strlcpy(ireq.ifr_ifrn.ifrn_name, handle->opt.source, + sizeof ireq.ifr_ifrn.ifrn_name); + if (ioctl(sock_fd, SIOCGIWMODE, &ireq) != -1) { + /* + * Well, we got the mode; assume we can set it. + */ + close(sock_fd); + return 1; + } + if (errno == ENODEV) { + /* The device doesn't even exist. */ + (void)snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIWMODE failed: %s", pcap_strerror(errno)); + close(sock_fd); + return PCAP_ERROR_NO_SUCH_DEVICE; + } + close(sock_fd); +#endif + return 0; +} + +/* + * Grabs the number of dropped packets by the interface from /proc/net/dev. + * + * XXX - what about /sys/class/net/{interface name}/rx_*? There are + * individual devices giving, in ASCII, various rx_ and tx_ statistics. + * + * Or can we get them in binary form from netlink? + */ +static long int +linux_if_drops(const char * if_name) +{ + char buffer[512]; + char * bufptr; + FILE * file; + int field_to_convert = 3, if_name_sz = strlen(if_name); + long int dropped_pkts = 0; + + file = fopen("/proc/net/dev", "r"); + if (!file) + return 0; + + while (!dropped_pkts && fgets( buffer, sizeof(buffer), file )) + { + /* search for 'bytes' -- if its in there, then + that means we need to grab the fourth field. otherwise + grab the third field. */ + if (field_to_convert != 4 && strstr(buffer, "bytes")) + { + field_to_convert = 4; + continue; + } + + /* find iface and make sure it actually matches -- space before the name and : after it */ + if ((bufptr = strstr(buffer, if_name)) && + (bufptr == buffer || *(bufptr-1) == ' ') && + *(bufptr + if_name_sz) == ':') + { + bufptr = bufptr + if_name_sz + 1; + + /* grab the nth field from it */ + while( --field_to_convert && *bufptr != '\0') + { + while (*bufptr != '\0' && *(bufptr++) == ' '); + while (*bufptr != '\0' && *(bufptr++) != ' '); + } + + /* get rid of any final spaces */ + while (*bufptr != '\0' && *bufptr == ' ') bufptr++; + + if (*bufptr != '\0') + dropped_pkts = strtol(bufptr, NULL, 10); + + break; + } + } + + fclose(file); + return dropped_pkts; +} + + +/* + * With older kernels promiscuous mode is kind of interesting because we + * have to reset the interface before exiting. The problem can't really + * be solved without some daemon taking care of managing usage counts. + * If we put the interface into promiscuous mode, we set a flag indicating + * that we must take it out of that mode when the interface is closed, + * and, when closing the interface, if that flag is set we take it out + * of promiscuous mode. + * + * Even with newer kernels, we have the same issue with rfmon mode. + */ + +static void pcap_cleanup_linux( pcap_t *handle ) +{ + struct pcap_linux *handlep = handle->priv; + struct ifreq ifr; +#ifdef HAVE_LIBNL + struct nl80211_state nlstate; + int ret; +#endif /* HAVE_LIBNL */ +#ifdef IW_MODE_MONITOR + int oldflags; + struct iwreq ireq; +#endif /* IW_MODE_MONITOR */ + + if (handlep->must_do_on_close != 0) { + /* + * There's something we have to do when closing this + * pcap_t. + */ + if (handlep->must_do_on_close & MUST_CLEAR_PROMISC) { + /* + * We put the interface into promiscuous mode; + * take it out of promiscuous mode. + * + * XXX - if somebody else wants it in promiscuous + * mode, this code cannot know that, so it'll take + * it out of promiscuous mode. That's not fixable + * in 2.0[.x] kernels. + */ + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, handlep->device, + sizeof(ifr.ifr_name)); + if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { + fprintf(stderr, + "Can't restore interface %s flags (SIOCGIFFLAGS failed: %s).\n" + "Please adjust manually.\n" + "Hint: This can't happen with Linux >= 2.2.0.\n", + handlep->device, strerror(errno)); + } else { + if (ifr.ifr_flags & IFF_PROMISC) { + /* + * Promiscuous mode is currently on; + * turn it off. + */ + ifr.ifr_flags &= ~IFF_PROMISC; + if (ioctl(handle->fd, SIOCSIFFLAGS, + &ifr) == -1) { + fprintf(stderr, + "Can't restore interface %s flags (SIOCSIFFLAGS failed: %s).\n" + "Please adjust manually.\n" + "Hint: This can't happen with Linux >= 2.2.0.\n", + handlep->device, + strerror(errno)); + } + } + } + } + +#ifdef HAVE_LIBNL + if (handlep->must_do_on_close & MUST_DELETE_MONIF) { + ret = nl80211_init(handle, &nlstate, handlep->device); + if (ret >= 0) { + ret = del_mon_if(handle, handle->fd, &nlstate, + handlep->device, handlep->mondevice); + nl80211_cleanup(&nlstate); + } + if (ret < 0) { + fprintf(stderr, + "Can't delete monitor interface %s (%s).\n" + "Please delete manually.\n", + handlep->mondevice, handle->errbuf); + } + } +#endif /* HAVE_LIBNL */ + +#ifdef IW_MODE_MONITOR + if (handlep->must_do_on_close & MUST_CLEAR_RFMON) { + /* + * We put the interface into rfmon mode; + * take it out of rfmon mode. + * + * XXX - if somebody else wants it in rfmon + * mode, this code cannot know that, so it'll take + * it out of rfmon mode. + */ + + /* + * First, take the interface down if it's up; + * otherwise, we might get EBUSY. + * If we get errors, just drive on and print + * a warning if we can't restore the mode. + */ + oldflags = 0; + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, handlep->device, + sizeof(ifr.ifr_name)); + if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) != -1) { + if (ifr.ifr_flags & IFF_UP) { + oldflags = ifr.ifr_flags; + ifr.ifr_flags &= ~IFF_UP; + if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) + oldflags = 0; /* didn't set, don't restore */ + } + } + + /* + * Now restore the mode. + */ + strlcpy(ireq.ifr_ifrn.ifrn_name, handlep->device, + sizeof ireq.ifr_ifrn.ifrn_name); + ireq.u.mode = handlep->oldmode; + if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) { + /* + * Scientist, you've failed. + */ + fprintf(stderr, + "Can't restore interface %s wireless mode (SIOCSIWMODE failed: %s).\n" + "Please adjust manually.\n", + handlep->device, strerror(errno)); + } + + /* + * Now bring the interface back up if we brought + * it down. + */ + if (oldflags != 0) { + ifr.ifr_flags = oldflags; + if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) { + fprintf(stderr, + "Can't bring interface %s back up (SIOCSIFFLAGS failed: %s).\n" + "Please adjust manually.\n", + handlep->device, strerror(errno)); + } + } + } +#endif /* IW_MODE_MONITOR */ + + /* + * Take this pcap out of the list of pcaps for which we + * have to take the interface out of some mode. + */ + pcap_remove_from_pcaps_to_close(handle); + } + + if (handlep->mondevice != NULL) { + free(handlep->mondevice); + handlep->mondevice = NULL; + } + if (handlep->device != NULL) { + free(handlep->device); + handlep->device = NULL; + } + pcap_cleanup_live_common(handle); +} + +/* + * Get a handle for a live capture from the given device. You can + * pass NULL as device to get all packages (without link level + * information of course). If you pass 1 as promisc the interface + * will be set to promiscous mode (XXX: I think this usage should + * be deprecated and functions be added to select that later allow + * modification of that values -- Torsten). + */ +static int +pcap_activate_linux(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + const char *device; + struct ifreq ifr; + int status = 0; + int ret; + + device = handle->opt.source; + + /* + * Make sure the name we were handed will fit into the ioctls we + * might perform on the device; if not, return a "No such device" + * indication, as the Linux kernel shouldn't support creating + * a device whose name won't fit into those ioctls. + * + * "Will fit" means "will fit, complete with a null terminator", + * so if the length, which does *not* include the null terminator, + * is greater than *or equal to* the size of the field into which + * we'll be copying it, that won't fit. + */ + if (strlen(device) >= sizeof(ifr.ifr_name)) { + status = PCAP_ERROR_NO_SUCH_DEVICE; + goto fail; + } + + handle->inject_op = pcap_inject_linux; + handle->setfilter_op = pcap_setfilter_linux; + handle->setdirection_op = pcap_setdirection_linux; + handle->set_datalink_op = pcap_set_datalink_linux; + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->cleanup_op = pcap_cleanup_linux; + handle->read_op = pcap_read_linux; + handle->stats_op = pcap_stats_linux; + + /* + * The "any" device is a special device which causes us not + * to bind to a particular device and thus to look at all + * devices. + */ + if (strcmp(device, "any") == 0) { + if (handle->opt.promisc) { + handle->opt.promisc = 0; + /* Just a warning. */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Promiscuous mode not supported on the \"any\" device"); + status = PCAP_WARNING_PROMISC_NOTSUP; + } + } + + handlep->device = strdup(device); + if (handlep->device == NULL) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", + pcap_strerror(errno) ); + return PCAP_ERROR; + } + + /* copy timeout value */ + handlep->timeout = handle->opt.timeout; + + /* + * If we're in promiscuous mode, then we probably want + * to see when the interface drops packets too, so get an + * initial count from /proc/net/dev + */ + if (handle->opt.promisc) + handlep->proc_dropped = linux_if_drops(handlep->device); + + /* + * Current Linux kernels use the protocol family PF_PACKET to + * allow direct access to all packets on the network while + * older kernels had a special socket type SOCK_PACKET to + * implement this feature. + * While this old implementation is kind of obsolete we need + * to be compatible with older kernels for a while so we are + * trying both methods with the newer method preferred. + */ + ret = activate_new(handle); + if (ret < 0) { + /* + * Fatal error with the new way; just fail. + * ret has the error return; if it's PCAP_ERROR, + * handle->errbuf has been set appropriately. + */ + status = ret; + goto fail; + } + if (ret == 1) { + /* + * Success. + * Try to use memory-mapped access. + */ + switch (activate_mmap(handle, &status)) { + + case 1: + /* + * We succeeded. status has been + * set to the status to return, + * which might be 0, or might be + * a PCAP_WARNING_ value. + */ + return status; + + case 0: + /* + * Kernel doesn't support it - just continue + * with non-memory-mapped access. + */ + break; + + case -1: + /* + * We failed to set up to use it, or the kernel + * supports it, but we failed to enable it. + * ret has been set to the error status to + * return and, if it's PCAP_ERROR, handle->errbuf + * contains the error message. + */ + status = ret; + goto fail; + } + } + else if (ret == 0) { + /* Non-fatal error; try old way */ + if ((ret = activate_old(handle)) != 1) { + /* + * Both methods to open the packet socket failed. + * Tidy up and report our failure (handle->errbuf + * is expected to be set by the functions above). + */ + status = ret; + goto fail; + } + } + + /* + * We set up the socket, but not with memory-mapped access. + */ + if (handle->opt.buffer_size != 0) { + /* + * Set the socket buffer size to the specified value. + */ + if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, + &handle->opt.buffer_size, + sizeof(handle->opt.buffer_size)) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "SO_RCVBUF: %s", pcap_strerror(errno)); + status = PCAP_ERROR; + goto fail; + } + } + + /* Allocate the buffer */ + + handle->buffer = malloc(handle->bufsize + handle->offset); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + status = PCAP_ERROR; + goto fail; + } + + /* + * "handle->fd" is a socket, so "select()" and "poll()" + * should work on it. + */ + handle->selectable_fd = handle->fd; + + return status; + +fail: + pcap_cleanup_linux(handle); + return status; +} + +/* + * Read at most max_packets from the capture stream and call the callback + * for each of them. Returns the number of packets handled or -1 if an + * error occured. + */ +static int +pcap_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + /* + * Currently, on Linux only one packet is delivered per read, + * so we don't loop. + */ + return pcap_read_packet(handle, callback, user); +} + +static int +pcap_set_datalink_linux(pcap_t *handle, int dlt) +{ + handle->linktype = dlt; + return 0; +} + +/* + * linux_check_direction() + * + * Do checks based on packet direction. + */ +static inline int +linux_check_direction(const pcap_t *handle, const struct sockaddr_ll *sll) +{ + struct pcap_linux *handlep = handle->priv; + + if (sll->sll_pkttype == PACKET_OUTGOING) { + /* + * Outgoing packet. + * If this is from the loopback device, reject it; + * we'll see the packet as an incoming packet as well, + * and we don't want to see it twice. + */ + if (sll->sll_ifindex == handlep->lo_ifindex) + return 0; + + /* + * If the user only wants incoming packets, reject it. + */ + if (handle->direction == PCAP_D_IN) + return 0; + } else { + /* + * Incoming packet. + * If the user only wants outgoing packets, reject it. + */ + if (handle->direction == PCAP_D_OUT) + return 0; + } + return 1; +} + +/* + * Read a packet from the socket calling the handler provided by + * the user. Returns the number of packets received or -1 if an + * error occured. + */ +static int +pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) +{ + struct pcap_linux *handlep = handle->priv; + u_char *bp; + int offset; +#ifdef HAVE_PF_PACKET_SOCKETS + struct sockaddr_ll from; + struct sll_header *hdrp; +#else + struct sockaddr from; +#endif +#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) + struct iovec iov; + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr cmsg; + char buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))]; + } cmsg_buf; +#else /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ + socklen_t fromlen; +#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ + int packet_len, caplen; + struct pcap_pkthdr pcap_header; + + struct bpf_aux_data aux_data; +#ifdef HAVE_PF_PACKET_SOCKETS + /* + * If this is a cooked device, leave extra room for a + * fake packet header. + */ + if (handlep->cooked) + offset = SLL_HDR_LEN; + else + offset = 0; +#else + /* + * This system doesn't have PF_PACKET sockets, so it doesn't + * support cooked devices. + */ + offset = 0; +#endif + + /* + * Receive a single packet from the kernel. + * We ignore EINTR, as that might just be due to a signal + * being delivered - if the signal should interrupt the + * loop, the signal handler should call pcap_breakloop() + * to set handle->break_loop (we ignore it on other + * platforms as well). + * We also ignore ENETDOWN, so that we can continue to + * capture traffic if the interface goes down and comes + * back up again; comments in the kernel indicate that + * we'll just block waiting for packets if we try to + * receive from a socket that delivered ENETDOWN, and, + * if we're using a memory-mapped buffer, we won't even + * get notified of "network down" events. + */ + bp = handle->buffer + handle->offset; + +#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) + msg.msg_name = &from; + msg.msg_namelen = sizeof(from); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = &cmsg_buf; + msg.msg_controllen = sizeof(cmsg_buf); + msg.msg_flags = 0; + + iov.iov_len = handle->bufsize - offset; + iov.iov_base = bp + offset; +#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ + + do { + /* + * Has "pcap_breakloop()" been called? + */ + if (handle->break_loop) { + /* + * Yes - clear the flag that indicates that it has, + * and return PCAP_ERROR_BREAK as an indication that + * we were told to break out of the loop. + */ + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + +#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) + packet_len = recvmsg(handle->fd, &msg, MSG_TRUNC); +#else /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ + fromlen = sizeof(from); + packet_len = recvfrom( + handle->fd, bp + offset, + handle->bufsize - offset, MSG_TRUNC, + (struct sockaddr *) &from, &fromlen); +#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ + } while (packet_len == -1 && errno == EINTR); + + /* Check if an error occured */ + + if (packet_len == -1) { + switch (errno) { + + case EAGAIN: + return 0; /* no packet there */ + + case ENETDOWN: + /* + * The device on which we're capturing went away. + * + * XXX - we should really return + * PCAP_ERROR_IFACE_NOT_UP, but pcap_dispatch() + * etc. aren't defined to return that. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "The interface went down"); + return PCAP_ERROR; + + default: + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "recvfrom: %s", pcap_strerror(errno)); + return PCAP_ERROR; + } + } + +#ifdef HAVE_PF_PACKET_SOCKETS + if (!handlep->sock_packet) { + /* + * Unfortunately, there is a window between socket() and + * bind() where the kernel may queue packets from any + * interface. If we're bound to a particular interface, + * discard packets not from that interface. + * + * (If socket filters are supported, we could do the + * same thing we do when changing the filter; however, + * that won't handle packet sockets without socket + * filter support, and it's a bit more complicated. + * It would save some instructions per packet, however.) + */ + if (handlep->ifindex != -1 && + from.sll_ifindex != handlep->ifindex) + return 0; + + /* + * Do checks based on packet direction. + * We can only do this if we're using PF_PACKET; the + * address returned for SOCK_PACKET is a "sockaddr_pkt" + * which lacks the relevant packet type information. + */ + if (!linux_check_direction(handle, &from)) + return 0; + } +#endif + +#ifdef HAVE_PF_PACKET_SOCKETS + /* + * If this is a cooked device, fill in the fake packet header. + */ + if (handlep->cooked) { + /* + * Add the length of the fake header to the length + * of packet data we read. + */ + packet_len += SLL_HDR_LEN; + + hdrp = (struct sll_header *)bp; + hdrp->sll_pkttype = map_packet_type_to_sll_type(from.sll_pkttype); + hdrp->sll_hatype = htons(from.sll_hatype); + hdrp->sll_halen = htons(from.sll_halen); + memcpy(hdrp->sll_addr, from.sll_addr, + (from.sll_halen > SLL_ADDRLEN) ? + SLL_ADDRLEN : + from.sll_halen); + hdrp->sll_protocol = from.sll_protocol; + } + +#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) + if (handlep->vlan_offset != -1) { + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + struct tpacket_auxdata *aux; + unsigned int len; + struct vlan_tag *tag; + + if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) || + cmsg->cmsg_level != SOL_PACKET || + cmsg->cmsg_type != PACKET_AUXDATA) + continue; + + aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg); +#if defined(TP_STATUS_VLAN_VALID) + if ((aux->tp_vlan_tci == 0) && !(aux->tp_status & TP_STATUS_VLAN_VALID)) +#else + if (aux->tp_vlan_tci == 0) /* this is ambigious but without the + TP_STATUS_VLAN_VALID flag, there is + nothing that we can do */ +#endif + continue; + + len = packet_len > iov.iov_len ? iov.iov_len : packet_len; + if (len < (unsigned int) handlep->vlan_offset) + break; + + bp -= VLAN_TAG_LEN; + memmove(bp, bp + VLAN_TAG_LEN, handlep->vlan_offset); + + tag = (struct vlan_tag *)(bp + handlep->vlan_offset); + tag->vlan_tpid = htons(VLAN_TPID(aux, aux)); + tag->vlan_tci = htons(aux->tp_vlan_tci); + + /* store vlan tci to bpf_aux_data struct for userland bpf filter */ +#if defined(TP_STATUS_VLAN_VALID) + aux_data.vlan_tag = htons(aux->tp_vlan_tci) & 0x0fff; + aux_data.vlan_tag_present = (aux->tp_status & TP_STATUS_VLAN_VALID); +#endif + packet_len += VLAN_TAG_LEN; + } + } +#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */ +#endif /* HAVE_PF_PACKET_SOCKETS */ + + /* + * XXX: According to the kernel source we should get the real + * packet len if calling recvfrom with MSG_TRUNC set. It does + * not seem to work here :(, but it is supported by this code + * anyway. + * To be honest the code RELIES on that feature so this is really + * broken with 2.2.x kernels. + * I spend a day to figure out what's going on and I found out + * that the following is happening: + * + * The packet comes from a random interface and the packet_rcv + * hook is called with a clone of the packet. That code inserts + * the packet into the receive queue of the packet socket. + * If a filter is attached to that socket that filter is run + * first - and there lies the problem. The default filter always + * cuts the packet at the snaplen: + * + * # tcpdump -d + * (000) ret #68 + * + * So the packet filter cuts down the packet. The recvfrom call + * says "hey, it's only 68 bytes, it fits into the buffer" with + * the result that we don't get the real packet length. This + * is valid at least until kernel 2.2.17pre6. + * + * We currently handle this by making a copy of the filter + * program, fixing all "ret" instructions with non-zero + * operands to have an operand of MAXIMUM_SNAPLEN so that the + * filter doesn't truncate the packet, and supplying that modified + * filter to the kernel. + */ + + caplen = packet_len; + if (caplen > handle->snapshot) + caplen = handle->snapshot; + + /* Run the packet filter if not using kernel filter */ + if (handlep->filter_in_userland && handle->fcode.bf_insns) { + if (bpf_filter_with_aux_data(handle->fcode.bf_insns, bp, + packet_len, caplen, &aux_data) == 0) { + /* rejected by filter */ + return 0; + } + } + + /* Fill in our own header data */ + + /* get timestamp for this packet */ +#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) + if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) { + if (ioctl(handle->fd, SIOCGSTAMPNS, &pcap_header.ts) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "SIOCGSTAMPNS: %s", pcap_strerror(errno)); + return PCAP_ERROR; + } + } else +#endif + { + if (ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "SIOCGSTAMP: %s", pcap_strerror(errno)); + return PCAP_ERROR; + } + } + + pcap_header.caplen = caplen; + pcap_header.len = packet_len; + + /* + * Count the packet. + * + * Arguably, we should count them before we check the filter, + * as on many other platforms "ps_recv" counts packets + * handed to the filter rather than packets that passed + * the filter, but if filtering is done in the kernel, we + * can't get a count of packets that passed the filter, + * and that would mean the meaning of "ps_recv" wouldn't + * be the same on all Linux systems. + * + * XXX - it's not the same on all systems in any case; + * ideally, we should have a "get the statistics" call + * that supplies more counts and indicates which of them + * it supplies, so that we supply a count of packets + * handed to the filter only on platforms where that + * information is available. + * + * We count them here even if we can get the packet count + * from the kernel, as we can only determine at run time + * whether we'll be able to get it from the kernel (if + * HAVE_TPACKET_STATS isn't defined, we can't get it from + * the kernel, but if it is defined, the library might + * have been built with a 2.4 or later kernel, but we + * might be running on a 2.2[.x] kernel without Alexey + * Kuznetzov's turbopacket patches, and thus the kernel + * might not be able to supply those statistics). We + * could, I guess, try, when opening the socket, to get + * the statistics, and if we can not increment the count + * here, but it's not clear that always incrementing + * the count is more expensive than always testing a flag + * in memory. + * + * We keep the count in "handlep->packets_read", and use that + * for "ps_recv" if we can't get the statistics from the kernel. + * We do that because, if we *can* get the statistics from + * the kernel, we use "handlep->stat.ps_recv" and + * "handlep->stat.ps_drop" as running counts, as reading the + * statistics from the kernel resets the kernel statistics, + * and if we directly increment "handlep->stat.ps_recv" here, + * that means it will count packets *twice* on systems where + * we can get kernel statistics - once here, and once in + * pcap_stats_linux(). + */ + handlep->packets_read++; + + /* Call the user supplied callback function */ + callback(userdata, &pcap_header, bp); + + return 1; +} + +static int +pcap_inject_linux(pcap_t *handle, const void *buf, size_t size) +{ + struct pcap_linux *handlep = handle->priv; + int ret; + +#ifdef HAVE_PF_PACKET_SOCKETS + if (!handlep->sock_packet) { + /* PF_PACKET socket */ + if (handlep->ifindex == -1) { + /* + * We don't support sending on the "any" device. + */ + strlcpy(handle->errbuf, + "Sending packets isn't supported on the \"any\" device", + PCAP_ERRBUF_SIZE); + return (-1); + } + + if (handlep->cooked) { + /* + * We don't support sending on the "any" device. + * + * XXX - how do you send on a bound cooked-mode + * socket? + * Is a "sendto()" required there? + */ + strlcpy(handle->errbuf, + "Sending packets isn't supported in cooked mode", + PCAP_ERRBUF_SIZE); + return (-1); + } + } +#endif + + ret = send(handle->fd, buf, size, 0); + if (ret == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "send: %s", + pcap_strerror(errno)); + return (-1); + } + return (ret); +} + +/* + * Get the statistics for the given packet capture handle. + * Reports the number of dropped packets iff the kernel supports + * the PACKET_STATISTICS "getsockopt()" argument (2.4 and later + * kernels, and 2.2[.x] kernels with Alexey Kuznetzov's turbopacket + * patches); otherwise, that information isn't available, and we lie + * and report 0 as the count of dropped packets. + */ +static int +pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_linux *handlep = handle->priv; +#ifdef HAVE_TPACKET_STATS +#ifdef HAVE_TPACKET3 + /* + * For sockets using TPACKET_V1 or TPACKET_V2, the extra + * stuff at the end of a struct tpacket_stats_v3 will not + * be filled in, and we don't look at it so this is OK even + * for those sockets. In addition, the PF_PACKET socket + * code in the kernel only uses the length parameter to + * compute how much data to copy out and to indicate how + * much data was copied out, so it's OK to base it on the + * size of a struct tpacket_stats. + * + * XXX - it's probably OK, in fact, to just use a + * struct tpacket_stats for V3 sockets, as we don't + * care about the tp_freeze_q_cnt stat. + */ + struct tpacket_stats_v3 kstats; +#else /* HAVE_TPACKET3 */ + struct tpacket_stats kstats; +#endif /* HAVE_TPACKET3 */ + socklen_t len = sizeof (struct tpacket_stats); +#endif /* HAVE_TPACKET_STATS */ + + long if_dropped = 0; + + /* + * To fill in ps_ifdrop, we parse /proc/net/dev for the number + */ + if (handle->opt.promisc) + { + if_dropped = handlep->proc_dropped; + handlep->proc_dropped = linux_if_drops(handlep->device); + handlep->stat.ps_ifdrop += (handlep->proc_dropped - if_dropped); + } + +#ifdef HAVE_TPACKET_STATS + /* + * Try to get the packet counts from the kernel. + */ + if (getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS, + &kstats, &len) > -1) { + /* + * On systems where the PACKET_STATISTICS "getsockopt()" + * argument is supported on PF_PACKET sockets: + * + * "ps_recv" counts only packets that *passed* the + * filter, not packets that didn't pass the filter. + * This includes packets later dropped because we + * ran out of buffer space. + * + * "ps_drop" counts packets dropped because we ran + * out of buffer space. It doesn't count packets + * dropped by the interface driver. It counts only + * packets that passed the filter. + * + * See above for ps_ifdrop. + * + * Both statistics include packets not yet read from + * the kernel by libpcap, and thus not yet seen by + * the application. + * + * In "linux/net/packet/af_packet.c", at least in the + * 2.4.9 kernel, "tp_packets" is incremented for every + * packet that passes the packet filter *and* is + * successfully queued on the socket; "tp_drops" is + * incremented for every packet dropped because there's + * not enough free space in the socket buffer. + * + * When the statistics are returned for a PACKET_STATISTICS + * "getsockopt()" call, "tp_drops" is added to "tp_packets", + * so that "tp_packets" counts all packets handed to + * the PF_PACKET socket, including packets dropped because + * there wasn't room on the socket buffer - but not + * including packets that didn't pass the filter. + * + * In the BSD BPF, the count of received packets is + * incremented for every packet handed to BPF, regardless + * of whether it passed the filter. + * + * We can't make "pcap_stats()" work the same on both + * platforms, but the best approximation is to return + * "tp_packets" as the count of packets and "tp_drops" + * as the count of drops. + * + * Keep a running total because each call to + * getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS, .... + * resets the counters to zero. + */ + handlep->stat.ps_recv += kstats.tp_packets; + handlep->stat.ps_drop += kstats.tp_drops; + *stats = handlep->stat; + return 0; + } + else + { + /* + * If the error was EOPNOTSUPP, fall through, so that + * if you build the library on a system with + * "struct tpacket_stats" and run it on a system + * that doesn't, it works as it does if the library + * is built on a system without "struct tpacket_stats". + */ + if (errno != EOPNOTSUPP) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "pcap_stats: %s", pcap_strerror(errno)); + return -1; + } + } +#endif + /* + * On systems where the PACKET_STATISTICS "getsockopt()" argument + * is not supported on PF_PACKET sockets: + * + * "ps_recv" counts only packets that *passed* the filter, + * not packets that didn't pass the filter. It does not + * count packets dropped because we ran out of buffer + * space. + * + * "ps_drop" is not supported. + * + * "ps_ifdrop" is supported. It will return the number + * of drops the interface reports in /proc/net/dev, + * if that is available. + * + * "ps_recv" doesn't include packets not yet read from + * the kernel by libpcap. + * + * We maintain the count of packets processed by libpcap in + * "handlep->packets_read", for reasons described in the comment + * at the end of pcap_read_packet(). We have no idea how many + * packets were dropped by the kernel buffers -- but we know + * how many the interface dropped, so we can return that. + */ + + stats->ps_recv = handlep->packets_read; + stats->ps_drop = 0; + stats->ps_ifdrop = handlep->stat.ps_ifdrop; + return 0; +} + +static int +add_linux_if(pcap_if_t **devlistp, const char *ifname, int fd, char *errbuf) +{ + const char *p; + char name[512]; /* XXX - pick a size */ + char *q, *saveq; + struct ifreq ifrflags; + + /* + * Get the interface name. + */ + p = ifname; + q = &name[0]; + while (*p != '\0' && isascii(*p) && !isspace(*p)) { + if (*p == ':') { + /* + * This could be the separator between a + * name and an alias number, or it could be + * the separator between a name with no + * alias number and the next field. + * + * If there's a colon after digits, it + * separates the name and the alias number, + * otherwise it separates the name and the + * next field. + */ + saveq = q; + while (isascii(*p) && isdigit(*p)) + *q++ = *p++; + if (*p != ':') { + /* + * That was the next field, + * not the alias number. + */ + q = saveq; + } + break; + } else + *q++ = *p++; + } + *q = '\0'; + + /* + * Get the flags for this interface. + */ + strlcpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) { + if (errno == ENXIO || errno == ENODEV) + return (0); /* device doesn't actually exist - ignore it */ + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFFLAGS: %.*s: %s", + (int)sizeof(ifrflags.ifr_name), + ifrflags.ifr_name, + pcap_strerror(errno)); + return (-1); + } + + /* + * Add an entry for this interface, with no addresses. + */ + if (pcap_add_if(devlistp, name, ifrflags.ifr_flags, NULL, + errbuf) == -1) { + /* + * Failure. + */ + return (-1); + } + + return (0); +} + +/* + * Get from "/sys/class/net" all interfaces listed there; if they're + * already in the list of interfaces we have, that won't add another + * instance, but if they're not, that'll add them. + * + * We don't bother getting any addresses for them; it appears you can't + * use SIOCGIFADDR on Linux to get IPv6 addresses for interfaces, and, + * although some other types of addresses can be fetched with SIOCGIFADDR, + * we don't bother with them for now. + * + * We also don't fail if we couldn't open "/sys/class/net"; we just leave + * the list of interfaces as is, and return 0, so that we can try + * scanning /proc/net/dev. + * + * Otherwise, we return 1 if we don't get an error and -1 if we do. + */ +static int +scan_sys_class_net(pcap_if_t **devlistp, char *errbuf) +{ + DIR *sys_class_net_d; + int fd; + struct dirent *ent; + char subsystem_path[PATH_MAX+1]; + struct stat statb; + int ret = 1; + + sys_class_net_d = opendir("/sys/class/net"); + if (sys_class_net_d == NULL) { + /* + * Don't fail if it doesn't exist at all. + */ + if (errno == ENOENT) + return (0); + + /* + * Fail if we got some other error. + */ + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Can't open /sys/class/net: %s", pcap_strerror(errno)); + return (-1); + } + + /* + * Create a socket from which to fetch interface information. + */ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + (void)closedir(sys_class_net_d); + return (-1); + } + + for (;;) { + errno = 0; + ent = readdir(sys_class_net_d); + if (ent == NULL) { + /* + * Error or EOF; if errno != 0, it's an error. + */ + break; + } + + /* + * Ignore "." and "..". + */ + if (strcmp(ent->d_name, ".") == 0 || + strcmp(ent->d_name, "..") == 0) + continue; + + /* + * Ignore plain files; they do not have subdirectories + * and thus have no attributes. + */ + if (ent->d_type == DT_REG) + continue; + + /* + * Is there an "ifindex" file under that name? + * (We don't care whether it's a directory or + * a symlink; older kernels have directories + * for devices, newer kernels have symlinks to + * directories.) + */ + snprintf(subsystem_path, sizeof subsystem_path, + "/sys/class/net/%s/ifindex", ent->d_name); + if (lstat(subsystem_path, &statb) != 0) { + /* + * Stat failed. Either there was an error + * other than ENOENT, and we don't know if + * this is an interface, or it's ENOENT, + * and either some part of "/sys/class/net/{if}" + * disappeared, in which case it probably means + * the interface disappeared, or there's no + * "ifindex" file, which means it's not a + * network interface. + */ + continue; + } + + /* + * Attempt to add the interface. + */ + if (add_linux_if(devlistp, &ent->d_name[0], fd, errbuf) == -1) { + /* Fail. */ + ret = -1; + break; + } + } + if (ret != -1) { + /* + * Well, we didn't fail for any other reason; did we + * fail due to an error reading the directory? + */ + if (errno != 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Error reading /sys/class/net: %s", + pcap_strerror(errno)); + ret = -1; + } + } + + (void)close(fd); + (void)closedir(sys_class_net_d); + return (ret); +} + +/* + * Get from "/proc/net/dev" all interfaces listed there; if they're + * already in the list of interfaces we have, that won't add another + * instance, but if they're not, that'll add them. + * + * See comments from scan_sys_class_net(). + */ +static int +scan_proc_net_dev(pcap_if_t **devlistp, char *errbuf) +{ + FILE *proc_net_f; + int fd; + char linebuf[512]; + int linenum; + char *p; + int ret = 0; + + proc_net_f = fopen("/proc/net/dev", "r"); + if (proc_net_f == NULL) { + /* + * Don't fail if it doesn't exist at all. + */ + if (errno == ENOENT) + return (0); + + /* + * Fail if we got some other error. + */ + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Can't open /proc/net/dev: %s", pcap_strerror(errno)); + return (-1); + } + + /* + * Create a socket from which to fetch interface information. + */ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + (void)fclose(proc_net_f); + return (-1); + } + + for (linenum = 1; + fgets(linebuf, sizeof linebuf, proc_net_f) != NULL; linenum++) { + /* + * Skip the first two lines - they're headers. + */ + if (linenum <= 2) + continue; + + p = &linebuf[0]; + + /* + * Skip leading white space. + */ + while (*p != '\0' && isascii(*p) && isspace(*p)) + p++; + if (*p == '\0' || *p == '\n') + continue; /* blank line */ + + /* + * Attempt to add the interface. + */ + if (add_linux_if(devlistp, p, fd, errbuf) == -1) { + /* Fail. */ + ret = -1; + break; + } + } + if (ret != -1) { + /* + * Well, we didn't fail for any other reason; did we + * fail due to an error reading the file? + */ + if (ferror(proc_net_f)) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Error reading /proc/net/dev: %s", + pcap_strerror(errno)); + ret = -1; + } + } + + (void)close(fd); + (void)fclose(proc_net_f); + return (ret); +} + +/* + * Description string for the "any" device. + */ +static const char any_descr[] = "Pseudo-device that captures on all interfaces"; + +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + int ret; + + /* + * Read "/sys/class/net", and add to the list of interfaces all + * interfaces listed there that we don't already have, because, + * on Linux, SIOCGIFCONF reports only interfaces with IPv4 addresses, + * and even getifaddrs() won't return information about + * interfaces with no addresses, so you need to read "/sys/class/net" + * to get the names of the rest of the interfaces. + */ + ret = scan_sys_class_net(alldevsp, errbuf); + if (ret == -1) + return (-1); /* failed */ + if (ret == 0) { + /* + * No /sys/class/net; try reading /proc/net/dev instead. + */ + if (scan_proc_net_dev(alldevsp, errbuf) == -1) + return (-1); + } + + /* + * Add the "any" device. + */ + if (pcap_add_if(alldevsp, "any", IFF_UP|IFF_RUNNING, + any_descr, errbuf) < 0) + return (-1); + + return (0); +} + +/* + * Attach the given BPF code to the packet capture device. + */ +static int +pcap_setfilter_linux_common(pcap_t *handle, struct bpf_program *filter, + int is_mmapped) +{ + struct pcap_linux *handlep; +#ifdef SO_ATTACH_FILTER + struct sock_fprog fcode; + int can_filter_in_kernel; + int err = 0; +#endif + + if (!handle) + return -1; + if (!filter) { + strlcpy(handle->errbuf, "setfilter: No filter specified", + PCAP_ERRBUF_SIZE); + return -1; + } + + handlep = handle->priv; + + /* Make our private copy of the filter */ + + if (install_bpf_program(handle, filter) < 0) + /* install_bpf_program() filled in errbuf */ + return -1; + + /* + * Run user level packet filter by default. Will be overriden if + * installing a kernel filter succeeds. + */ + handlep->filter_in_userland = 1; + + /* Install kernel level filter if possible */ + +#ifdef SO_ATTACH_FILTER +#ifdef USHRT_MAX + if (handle->fcode.bf_len > USHRT_MAX) { + /* + * fcode.len is an unsigned short for current kernel. + * I have yet to see BPF-Code with that much + * instructions but still it is possible. So for the + * sake of correctness I added this check. + */ + fprintf(stderr, "Warning: Filter too complex for kernel\n"); + fcode.len = 0; + fcode.filter = NULL; + can_filter_in_kernel = 0; + } else +#endif /* USHRT_MAX */ + { + /* + * Oh joy, the Linux kernel uses struct sock_fprog instead + * of struct bpf_program and of course the length field is + * of different size. Pointed out by Sebastian + * + * Oh, and we also need to fix it up so that all "ret" + * instructions with non-zero operands have MAXIMUM_SNAPLEN + * as the operand if we're not capturing in memory-mapped + * mode, and so that, if we're in cooked mode, all memory- + * reference instructions use special magic offsets in + * references to the link-layer header and assume that the + * link-layer payload begins at 0; "fix_program()" will do + * that. + */ + switch (fix_program(handle, &fcode, is_mmapped)) { + + case -1: + default: + /* + * Fatal error; just quit. + * (The "default" case shouldn't happen; we + * return -1 for that reason.) + */ + return -1; + + case 0: + /* + * The program performed checks that we can't make + * work in the kernel. + */ + can_filter_in_kernel = 0; + break; + + case 1: + /* + * We have a filter that'll work in the kernel. + */ + can_filter_in_kernel = 1; + break; + } + } + + /* + * NOTE: at this point, we've set both the "len" and "filter" + * fields of "fcode". As of the 2.6.32.4 kernel, at least, + * those are the only members of the "sock_fprog" structure, + * so we initialize every member of that structure. + * + * If there is anything in "fcode" that is not initialized, + * it is either a field added in a later kernel, or it's + * padding. + * + * If a new field is added, this code needs to be updated + * to set it correctly. + * + * If there are no other fields, then: + * + * if the Linux kernel looks at the padding, it's + * buggy; + * + * if the Linux kernel doesn't look at the padding, + * then if some tool complains that we're passing + * uninitialized data to the kernel, then the tool + * is buggy and needs to understand that it's just + * padding. + */ + if (can_filter_in_kernel) { + if ((err = set_kernel_filter(handle, &fcode)) == 0) + { + /* + * Installation succeded - using kernel filter, + * so userland filtering not needed. + */ + handlep->filter_in_userland = 0; + } + else if (err == -1) /* Non-fatal error */ + { + /* + * Print a warning if we weren't able to install + * the filter for a reason other than "this kernel + * isn't configured to support socket filters. + */ + if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) { + fprintf(stderr, + "Warning: Kernel filter failed: %s\n", + pcap_strerror(errno)); + } + } + } + + /* + * If we're not using the kernel filter, get rid of any kernel + * filter that might've been there before, e.g. because the + * previous filter could work in the kernel, or because some other + * code attached a filter to the socket by some means other than + * calling "pcap_setfilter()". Otherwise, the kernel filter may + * filter out packets that would pass the new userland filter. + */ + if (handlep->filter_in_userland) { + if (reset_kernel_filter(handle) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't remove kernel filter: %s", + pcap_strerror(errno)); + err = -2; /* fatal error */ + } + } + + /* + * Free up the copy of the filter that was made by "fix_program()". + */ + if (fcode.filter != NULL) + free(fcode.filter); + + if (err == -2) + /* Fatal error */ + return -1; +#endif /* SO_ATTACH_FILTER */ + + return 0; +} + +static int +pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter) +{ + return pcap_setfilter_linux_common(handle, filter, 0); +} + + +/* + * Set direction flag: Which packets do we accept on a forwarding + * single device? IN, OUT or both? + */ +static int +pcap_setdirection_linux(pcap_t *handle, pcap_direction_t d) +{ +#ifdef HAVE_PF_PACKET_SOCKETS + struct pcap_linux *handlep = handle->priv; + + if (!handlep->sock_packet) { + handle->direction = d; + return 0; + } +#endif + /* + * We're not using PF_PACKET sockets, so we can't determine + * the direction of the packet. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Setting direction is not supported on SOCK_PACKET sockets"); + return -1; +} + +#ifdef HAVE_PF_PACKET_SOCKETS +/* + * Map the PACKET_ value to a LINUX_SLL_ value; we + * want the same numerical value to be used in + * the link-layer header even if the numerical values + * for the PACKET_ #defines change, so that programs + * that look at the packet type field will always be + * able to handle DLT_LINUX_SLL captures. + */ +static short int +map_packet_type_to_sll_type(short int sll_pkttype) +{ + switch (sll_pkttype) { + + case PACKET_HOST: + return htons(LINUX_SLL_HOST); + + case PACKET_BROADCAST: + return htons(LINUX_SLL_BROADCAST); + + case PACKET_MULTICAST: + return htons(LINUX_SLL_MULTICAST); + + case PACKET_OTHERHOST: + return htons(LINUX_SLL_OTHERHOST); + + case PACKET_OUTGOING: + return htons(LINUX_SLL_OUTGOING); + + default: + return -1; + } +} +#endif + +static int +is_wifi(int sock_fd +#ifndef IW_MODE_MONITOR +_U_ +#endif +, const char *device) +{ + char *pathstr; + struct stat statb; +#ifdef IW_MODE_MONITOR + char errbuf[PCAP_ERRBUF_SIZE]; +#endif + + /* + * See if there's a sysfs wireless directory for it. + * If so, it's a wireless interface. + */ + if (asprintf(&pathstr, "/sys/class/net/%s/wireless", device) == -1) { + /* + * Just give up here. + */ + return 0; + } + if (stat(pathstr, &statb) == 0) { + free(pathstr); + return 1; + } + free(pathstr); + +#ifdef IW_MODE_MONITOR + /* + * OK, maybe it's not wireless, or maybe this kernel doesn't + * support sysfs. Try the wireless extensions. + */ + if (has_wext(sock_fd, device, errbuf) == 1) { + /* + * It supports the wireless extensions, so it's a Wi-Fi + * device. + */ + return 1; + } +#endif + return 0; +} + +/* + * Linux uses the ARP hardware type to identify the type of an + * interface. pcap uses the DLT_xxx constants for this. This + * function takes a pointer to a "pcap_t", and an ARPHRD_xxx + * constant, as arguments, and sets "handle->linktype" to the + * appropriate DLT_XXX constant and sets "handle->offset" to + * the appropriate value (to make "handle->offset" plus link-layer + * header length be a multiple of 4, so that the link-layer payload + * will be aligned on a 4-byte boundary when capturing packets). + * (If the offset isn't set here, it'll be 0; add code as appropriate + * for cases where it shouldn't be 0.) + * + * If "cooked_ok" is non-zero, we can use DLT_LINUX_SLL and capture + * in cooked mode; otherwise, we can't use cooked mode, so we have + * to pick some type that works in raw mode, or fail. + * + * Sets the link type to -1 if unable to map the type. + */ +static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype, + const char *device, int cooked_ok) +{ + static const char cdma_rmnet[] = "cdma_rmnet"; + + switch (arptype) { + + case ARPHRD_ETHER: + /* + * For various annoying reasons having to do with DHCP + * software, some versions of Android give the mobile- + * phone-network interface an ARPHRD_ value of + * ARPHRD_ETHER, even though the packets supplied by + * that interface have no link-layer header, and begin + * with an IP header, so that the ARPHRD_ value should + * be ARPHRD_NONE. + * + * Detect those devices by checking the device name, and + * use DLT_RAW for them. + */ + if (strncmp(device, cdma_rmnet, sizeof cdma_rmnet - 1) == 0) { + handle->linktype = DLT_RAW; + return; + } + + /* + * Is this a real Ethernet device? If so, give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + * + * XXX - are there any other sorts of "fake Ethernet" that + * have ARPHRD_ETHER but that shouldn't offer DLT_DOCSIS as + * a Cisco CMTS won't put traffic onto it or get traffic + * bridged onto it? ISDN is handled in "activate_new()", + * as we fall back on cooked mode there, and we use + * is_wifi() to check for 802.11 devices; are there any + * others? + */ + if (!is_wifi(sock_fd, device)) { + /* + * It's not a Wi-Fi device; offer DOCSIS. + */ + handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (handle->dlt_list != NULL) { + handle->dlt_list[0] = DLT_EN10MB; + handle->dlt_list[1] = DLT_DOCSIS; + handle->dlt_count = 2; + } + } + /* FALLTHROUGH */ + + case ARPHRD_METRICOM: + case ARPHRD_LOOPBACK: + handle->linktype = DLT_EN10MB; + handle->offset = 2; + break; + + case ARPHRD_EETHER: + handle->linktype = DLT_EN3MB; + break; + + case ARPHRD_AX25: + handle->linktype = DLT_AX25_KISS; + break; + + case ARPHRD_PRONET: + handle->linktype = DLT_PRONET; + break; + + case ARPHRD_CHAOS: + handle->linktype = DLT_CHAOS; + break; +#ifndef ARPHRD_CAN +#define ARPHRD_CAN 280 +#endif + case ARPHRD_CAN: + handle->linktype = DLT_CAN_SOCKETCAN; + break; + +#ifndef ARPHRD_IEEE802_TR +#define ARPHRD_IEEE802_TR 800 /* From Linux 2.4 */ +#endif + case ARPHRD_IEEE802_TR: + case ARPHRD_IEEE802: + handle->linktype = DLT_IEEE802; + handle->offset = 2; + break; + + case ARPHRD_ARCNET: + handle->linktype = DLT_ARCNET_LINUX; + break; + +#ifndef ARPHRD_FDDI /* From Linux 2.2.13 */ +#define ARPHRD_FDDI 774 +#endif + case ARPHRD_FDDI: + handle->linktype = DLT_FDDI; + handle->offset = 3; + break; + +#ifndef ARPHRD_ATM /* FIXME: How to #include this? */ +#define ARPHRD_ATM 19 +#endif + case ARPHRD_ATM: + /* + * The Classical IP implementation in ATM for Linux + * supports both what RFC 1483 calls "LLC Encapsulation", + * in which each packet has an LLC header, possibly + * with a SNAP header as well, prepended to it, and + * what RFC 1483 calls "VC Based Multiplexing", in which + * different virtual circuits carry different network + * layer protocols, and no header is prepended to packets. + * + * They both have an ARPHRD_ type of ARPHRD_ATM, so + * you can't use the ARPHRD_ type to find out whether + * captured packets will have an LLC header, and, + * while there's a socket ioctl to *set* the encapsulation + * type, there's no ioctl to *get* the encapsulation type. + * + * This means that + * + * programs that dissect Linux Classical IP frames + * would have to check for an LLC header and, + * depending on whether they see one or not, dissect + * the frame as LLC-encapsulated or as raw IP (I + * don't know whether there's any traffic other than + * IP that would show up on the socket, or whether + * there's any support for IPv6 in the Linux + * Classical IP code); + * + * filter expressions would have to compile into + * code that checks for an LLC header and does + * the right thing. + * + * Both of those are a nuisance - and, at least on systems + * that support PF_PACKET sockets, we don't have to put + * up with those nuisances; instead, we can just capture + * in cooked mode. That's what we'll do, if we can. + * Otherwise, we'll just fail. + */ + if (cooked_ok) + handle->linktype = DLT_LINUX_SLL; + else + handle->linktype = -1; + break; + +#ifndef ARPHRD_IEEE80211 /* From Linux 2.4.6 */ +#define ARPHRD_IEEE80211 801 +#endif + case ARPHRD_IEEE80211: + handle->linktype = DLT_IEEE802_11; + break; + +#ifndef ARPHRD_IEEE80211_PRISM /* From Linux 2.4.18 */ +#define ARPHRD_IEEE80211_PRISM 802 +#endif + case ARPHRD_IEEE80211_PRISM: + handle->linktype = DLT_PRISM_HEADER; + break; + +#ifndef ARPHRD_IEEE80211_RADIOTAP /* new */ +#define ARPHRD_IEEE80211_RADIOTAP 803 +#endif + case ARPHRD_IEEE80211_RADIOTAP: + handle->linktype = DLT_IEEE802_11_RADIO; + break; + + case ARPHRD_PPP: + /* + * Some PPP code in the kernel supplies no link-layer + * header whatsoever to PF_PACKET sockets; other PPP + * code supplies PPP link-layer headers ("syncppp.c"); + * some PPP code might supply random link-layer + * headers (PPP over ISDN - there's code in Ethereal, + * for example, to cope with PPP-over-ISDN captures + * with which the Ethereal developers have had to cope, + * heuristically trying to determine which of the + * oddball link-layer headers particular packets have). + * + * As such, we just punt, and run all PPP interfaces + * in cooked mode, if we can; otherwise, we just treat + * it as DLT_RAW, for now - if somebody needs to capture, + * on a 2.0[.x] kernel, on PPP devices that supply a + * link-layer header, they'll have to add code here to + * map to the appropriate DLT_ type (possibly adding a + * new DLT_ type, if necessary). + */ + if (cooked_ok) + handle->linktype = DLT_LINUX_SLL; + else { + /* + * XXX - handle ISDN types here? We can't fall + * back on cooked sockets, so we'd have to + * figure out from the device name what type of + * link-layer encapsulation it's using, and map + * that to an appropriate DLT_ value, meaning + * we'd map "isdnN" devices to DLT_RAW (they + * supply raw IP packets with no link-layer + * header) and "isdY" devices to a new DLT_I4L_IP + * type that has only an Ethernet packet type as + * a link-layer header. + * + * But sometimes we seem to get random crap + * in the link-layer header when capturing on + * ISDN devices.... + */ + handle->linktype = DLT_RAW; + } + break; + +#ifndef ARPHRD_CISCO +#define ARPHRD_CISCO 513 /* previously ARPHRD_HDLC */ +#endif + case ARPHRD_CISCO: + handle->linktype = DLT_C_HDLC; + break; + + /* Not sure if this is correct for all tunnels, but it + * works for CIPE */ + case ARPHRD_TUNNEL: +#ifndef ARPHRD_SIT +#define ARPHRD_SIT 776 /* From Linux 2.2.13 */ +#endif + case ARPHRD_SIT: + case ARPHRD_CSLIP: + case ARPHRD_SLIP6: + case ARPHRD_CSLIP6: + case ARPHRD_ADAPT: + case ARPHRD_SLIP: +#ifndef ARPHRD_RAWHDLC +#define ARPHRD_RAWHDLC 518 +#endif + case ARPHRD_RAWHDLC: +#ifndef ARPHRD_DLCI +#define ARPHRD_DLCI 15 +#endif + case ARPHRD_DLCI: + /* + * XXX - should some of those be mapped to DLT_LINUX_SLL + * instead? Should we just map all of them to DLT_LINUX_SLL? + */ + handle->linktype = DLT_RAW; + break; + +#ifndef ARPHRD_FRAD +#define ARPHRD_FRAD 770 +#endif + case ARPHRD_FRAD: + handle->linktype = DLT_FRELAY; + break; + + case ARPHRD_LOCALTLK: + handle->linktype = DLT_LTALK; + break; + + case 18: + /* + * RFC 4338 defines an encapsulation for IP and ARP + * packets that's compatible with the RFC 2625 + * encapsulation, but that uses a different ARP + * hardware type and hardware addresses. That + * ARP hardware type is 18; Linux doesn't define + * any ARPHRD_ value as 18, but if it ever officially + * supports RFC 4338-style IP-over-FC, it should define + * one. + * + * For now, we map it to DLT_IP_OVER_FC, in the hopes + * that this will encourage its use in the future, + * should Linux ever officially support RFC 4338-style + * IP-over-FC. + */ + handle->linktype = DLT_IP_OVER_FC; + break; + +#ifndef ARPHRD_FCPP +#define ARPHRD_FCPP 784 +#endif + case ARPHRD_FCPP: +#ifndef ARPHRD_FCAL +#define ARPHRD_FCAL 785 +#endif + case ARPHRD_FCAL: +#ifndef ARPHRD_FCPL +#define ARPHRD_FCPL 786 +#endif + case ARPHRD_FCPL: +#ifndef ARPHRD_FCFABRIC +#define ARPHRD_FCFABRIC 787 +#endif + case ARPHRD_FCFABRIC: + /* + * Back in 2002, Donald Lee at Cray wanted a DLT_ for + * IP-over-FC: + * + * http://www.mail-archive.com/tcpdump-workers@sandelman.ottawa.on.ca/msg01043.html + * + * and one was assigned. + * + * In a later private discussion (spun off from a message + * on the ethereal-users list) on how to get that DLT_ + * value in libpcap on Linux, I ended up deciding that + * the best thing to do would be to have him tweak the + * driver to set the ARPHRD_ value to some ARPHRD_FCxx + * type, and map all those types to DLT_IP_OVER_FC: + * + * I've checked into the libpcap and tcpdump CVS tree + * support for DLT_IP_OVER_FC. In order to use that, + * you'd have to modify your modified driver to return + * one of the ARPHRD_FCxxx types, in "fcLINUXfcp.c" - + * change it to set "dev->type" to ARPHRD_FCFABRIC, for + * example (the exact value doesn't matter, it can be + * any of ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, or + * ARPHRD_FCFABRIC). + * + * 11 years later, Christian Svensson wanted to map + * various ARPHRD_ values to DLT_FC_2 and + * DLT_FC_2_WITH_FRAME_DELIMS for raw Fibre Channel + * frames: + * + * https://github.com/mcr/libpcap/pull/29 + * + * There doesn't seem to be any network drivers that uses + * any of the ARPHRD_FC* values for IP-over-FC, and + * it's not exactly clear what the "Dummy types for non + * ARP hardware" are supposed to mean (link-layer + * header type? Physical network type?), so it's + * not exactly clear why the ARPHRD_FC* types exist + * in the first place. + * + * For now, we map them to DLT_FC_2, and provide an + * option of DLT_FC_2_WITH_FRAME_DELIMS, as well as + * DLT_IP_OVER_FC just in case there's some old + * driver out there that uses one of those types for + * IP-over-FC on which somebody wants to capture + * packets. + */ + handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (handle->dlt_list != NULL) { + handle->dlt_list[0] = DLT_FC_2; + handle->dlt_list[1] = DLT_FC_2_WITH_FRAME_DELIMS; + handle->dlt_list[2] = DLT_IP_OVER_FC; + handle->dlt_count = 3; + } + handle->linktype = DLT_FC_2; + break; + +#ifndef ARPHRD_IRDA +#define ARPHRD_IRDA 783 +#endif + case ARPHRD_IRDA: + /* Don't expect IP packet out of this interfaces... */ + handle->linktype = DLT_LINUX_IRDA; + /* We need to save packet direction for IrDA decoding, + * so let's use "Linux-cooked" mode. Jean II + * + * XXX - this is handled in activate_new(). */ + //handlep->cooked = 1; + break; + + /* ARPHRD_LAPD is unofficial and randomly allocated, if reallocation + * is needed, please report it to */ +#ifndef ARPHRD_LAPD +#define ARPHRD_LAPD 8445 +#endif + case ARPHRD_LAPD: + /* Don't expect IP packet out of this interfaces... */ + handle->linktype = DLT_LINUX_LAPD; + break; + +#ifndef ARPHRD_NONE +#define ARPHRD_NONE 0xFFFE +#endif + case ARPHRD_NONE: + /* + * No link-layer header; packets are just IP + * packets, so use DLT_RAW. + */ + handle->linktype = DLT_RAW; + break; + +#ifndef ARPHRD_IEEE802154 +#define ARPHRD_IEEE802154 804 +#endif + case ARPHRD_IEEE802154: + handle->linktype = DLT_IEEE802_15_4_NOFCS; + break; + +#ifndef ARPHRD_NETLINK +#define ARPHRD_NETLINK 824 +#endif + case ARPHRD_NETLINK: + handle->linktype = DLT_NETLINK; + /* + * We need to use cooked mode, so that in sll_protocol we + * pick up the netlink protocol type such as NETLINK_ROUTE, + * NETLINK_GENERIC, NETLINK_FIB_LOOKUP, etc. + * + * XXX - this is handled in activate_new(). + */ + //handlep->cooked = 1; + break; + + default: + handle->linktype = -1; + break; + } +} + +/* ===== Functions to interface to the newer kernels ================== */ + +/* + * Try to open a packet socket using the new kernel PF_PACKET interface. + * Returns 1 on success, 0 on an error that means the new interface isn't + * present (so the old SOCK_PACKET interface should be tried), and a + * PCAP_ERROR_ value on an error that means that the old mechanism won't + * work either (so it shouldn't be tried). + */ +static int +activate_new(pcap_t *handle) +{ +#ifdef HAVE_PF_PACKET_SOCKETS + struct pcap_linux *handlep = handle->priv; + const char *device = handle->opt.source; + int is_any_device = (strcmp(device, "any") == 0); + int sock_fd = -1, arptype; +#ifdef HAVE_PACKET_AUXDATA + int val; +#endif + int err = 0; + struct packet_mreq mr; +#ifdef SO_BPF_EXTENSIONS + int bpf_extensions; + socklen_t len = sizeof(bpf_extensions); +#endif + + /* + * Open a socket with protocol family packet. If the + * "any" device was specified, we open a SOCK_DGRAM + * socket for the cooked interface, otherwise we first + * try a SOCK_RAW socket for the raw interface. + */ + sock_fd = is_any_device ? + socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)) : + socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + + if (sock_fd == -1) { + if (errno == EINVAL || errno == EAFNOSUPPORT) { + /* + * We don't support PF_PACKET/SOCK_whatever + * sockets; try the old mechanism. + */ + return 0; + } + + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "socket: %s", + pcap_strerror(errno) ); + if (errno == EPERM || errno == EACCES) { + /* + * You don't have permission to open the + * socket. + */ + return PCAP_ERROR_PERM_DENIED; + } else { + /* + * Other error. + */ + return PCAP_ERROR; + } + } + + /* It seems the kernel supports the new interface. */ + handlep->sock_packet = 0; + + /* + * Get the interface index of the loopback device. + * If the attempt fails, don't fail, just set the + * "handlep->lo_ifindex" to -1. + * + * XXX - can there be more than one device that loops + * packets back, i.e. devices other than "lo"? If so, + * we'd need to find them all, and have an array of + * indices for them, and check all of them in + * "pcap_read_packet()". + */ + handlep->lo_ifindex = iface_get_id(sock_fd, "lo", handle->errbuf); + + /* + * Default value for offset to align link-layer payload + * on a 4-byte boundary. + */ + handle->offset = 0; + + /* + * What kind of frames do we have to deal with? Fall back + * to cooked mode if we have an unknown interface type + * or a type we know doesn't work well in raw mode. + */ + if (!is_any_device) { + /* Assume for now we don't need cooked mode. */ + handlep->cooked = 0; + + if (handle->opt.rfmon) { + /* + * We were asked to turn on monitor mode. + * Do so before we get the link-layer type, + * because entering monitor mode could change + * the link-layer type. + */ + err = enter_rfmon_mode(handle, sock_fd, device); + if (err < 0) { + /* Hard failure */ + close(sock_fd); + return err; + } + if (err == 0) { + /* + * Nothing worked for turning monitor mode + * on. + */ + close(sock_fd); + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* + * Either monitor mode has been turned on for + * the device, or we've been given a different + * device to open for monitor mode. If we've + * been given a different device, use it. + */ + if (handlep->mondevice != NULL) + device = handlep->mondevice; + } + arptype = iface_get_arptype(sock_fd, device, handle->errbuf); + if (arptype < 0) { + close(sock_fd); + return arptype; + } + map_arphrd_to_dlt(handle, sock_fd, arptype, device, 1); + if (handle->linktype == -1 || + handle->linktype == DLT_LINUX_SLL || + handle->linktype == DLT_LINUX_IRDA || + handle->linktype == DLT_LINUX_LAPD || + handle->linktype == DLT_NETLINK || + (handle->linktype == DLT_EN10MB && + (strncmp("isdn", device, 4) == 0 || + strncmp("isdY", device, 4) == 0))) { + /* + * Unknown interface type (-1), or a + * device we explicitly chose to run + * in cooked mode (e.g., PPP devices), + * or an ISDN device (whose link-layer + * type we can only determine by using + * APIs that may be different on different + * kernels) - reopen in cooked mode. + */ + if (close(sock_fd) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "close: %s", pcap_strerror(errno)); + return PCAP_ERROR; + } + sock_fd = socket(PF_PACKET, SOCK_DGRAM, + htons(ETH_P_ALL)); + if (sock_fd == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + if (errno == EPERM || errno == EACCES) { + /* + * You don't have permission to + * open the socket. + */ + return PCAP_ERROR_PERM_DENIED; + } else { + /* + * Other error. + */ + return PCAP_ERROR; + } + } + handlep->cooked = 1; + + /* + * Get rid of any link-layer type list + * we allocated - this only supports cooked + * capture. + */ + if (handle->dlt_list != NULL) { + free(handle->dlt_list); + handle->dlt_list = NULL; + handle->dlt_count = 0; + } + + if (handle->linktype == -1) { + /* + * Warn that we're falling back on + * cooked mode; we may want to + * update "map_arphrd_to_dlt()" + * to handle the new type. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "arptype %d not " + "supported by libpcap - " + "falling back to cooked " + "socket", + arptype); + } + + /* + * IrDA capture is not a real "cooked" capture, + * it's IrLAP frames, not IP packets. The + * same applies to LAPD capture. + */ + if (handle->linktype != DLT_LINUX_IRDA && + handle->linktype != DLT_LINUX_LAPD && + handle->linktype != DLT_NETLINK) + handle->linktype = DLT_LINUX_SLL; + } + + handlep->ifindex = iface_get_id(sock_fd, device, + handle->errbuf); + if (handlep->ifindex == -1) { + close(sock_fd); + return PCAP_ERROR; + } + + if ((err = iface_bind(sock_fd, handlep->ifindex, + handle->errbuf)) != 1) { + close(sock_fd); + if (err < 0) + return err; + else + return 0; /* try old mechanism */ + } + } else { + /* + * The "any" device. + */ + if (handle->opt.rfmon) { + /* + * It doesn't support monitor mode. + */ + close(sock_fd); + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* + * It uses cooked mode. + */ + handlep->cooked = 1; + handle->linktype = DLT_LINUX_SLL; + + /* + * We're not bound to a device. + * For now, we're using this as an indication + * that we can't transmit; stop doing that only + * if we figure out how to transmit in cooked + * mode. + */ + handlep->ifindex = -1; + } + + /* + * Select promiscuous mode on if "promisc" is set. + * + * Do not turn allmulti mode on if we don't select + * promiscuous mode - on some devices (e.g., Orinoco + * wireless interfaces), allmulti mode isn't supported + * and the driver implements it by turning promiscuous + * mode on, and that screws up the operation of the + * card as a normal networking interface, and on no + * other platform I know of does starting a non- + * promiscuous capture affect which multicast packets + * are received by the interface. + */ + + /* + * Hmm, how can we set promiscuous mode on all interfaces? + * I am not sure if that is possible at all. For now, we + * silently ignore attempts to turn promiscuous mode on + * for the "any" device (so you don't have to explicitly + * disable it in programs such as tcpdump). + */ + + if (!is_any_device && handle->opt.promisc) { + memset(&mr, 0, sizeof(mr)); + mr.mr_ifindex = handlep->ifindex; + mr.mr_type = PACKET_MR_PROMISC; + if (setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, + &mr, sizeof(mr)) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "setsockopt: %s", pcap_strerror(errno)); + close(sock_fd); + return PCAP_ERROR; + } + } + + /* Enable auxillary data if supported and reserve room for + * reconstructing VLAN headers. */ +#ifdef HAVE_PACKET_AUXDATA + val = 1; + if (setsockopt(sock_fd, SOL_PACKET, PACKET_AUXDATA, &val, + sizeof(val)) == -1 && errno != ENOPROTOOPT) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "setsockopt: %s", pcap_strerror(errno)); + close(sock_fd); + return PCAP_ERROR; + } + handle->offset += VLAN_TAG_LEN; +#endif /* HAVE_PACKET_AUXDATA */ + + /* + * This is a 2.2[.x] or later kernel (we know that + * because we're not using a SOCK_PACKET socket - + * PF_PACKET is supported only in 2.2 and later + * kernels). + * + * We can safely pass "recvfrom()" a byte count + * based on the snapshot length. + * + * If we're in cooked mode, make the snapshot length + * large enough to hold a "cooked mode" header plus + * 1 byte of packet data (so we don't pass a byte + * count of 0 to "recvfrom()"). + */ + if (handlep->cooked) { + if (handle->snapshot < SLL_HDR_LEN + 1) + handle->snapshot = SLL_HDR_LEN + 1; + } + handle->bufsize = handle->snapshot; + + /* + * Set the offset at which to insert VLAN tags. + */ + switch (handle->linktype) { + + case DLT_EN10MB: + handlep->vlan_offset = 2 * ETH_ALEN; + break; + + case DLT_LINUX_SLL: + handlep->vlan_offset = 14; + break; + + default: + handlep->vlan_offset = -1; /* unknown */ + break; + } + +#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) + if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) { + int nsec_tstamps = 1; + + if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, &nsec_tstamps, sizeof(nsec_tstamps)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: unable to set SO_TIMESTAMPNS"); + close(sock_fd); + return PCAP_ERROR; + } + } +#endif /* defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) */ + + /* + * We've succeeded. Save the socket FD in the pcap structure. + */ + handle->fd = sock_fd; + +#ifdef SO_BPF_EXTENSIONS + /* + * Can we generate special code for VLAN checks? + * (XXX - what if we need the special code but it's not supported + * by the OS? Is that possible?) + */ + if (getsockopt(sock_fd, SOL_SOCKET, SO_BPF_EXTENSIONS, + &bpf_extensions, &len) == 0) { + if (bpf_extensions >= SKF_AD_VLAN_TAG_PRESENT) { + /* + * Yes, we can. Request that we do so. + */ + handle->bpf_codegen_flags |= BPF_SPECIAL_VLAN_HANDLING; + } + } +#endif /* SO_BPF_EXTENSIONS */ + + return 1; +#else /* HAVE_PF_PACKET_SOCKETS */ + strlcpy(ebuf, + "New packet capturing interface not supported by build " + "environment", PCAP_ERRBUF_SIZE); + return 0; +#endif /* HAVE_PF_PACKET_SOCKETS */ +} + +#ifdef HAVE_PACKET_RING +/* + * Attempt to activate with memory-mapped access. + * + * On success, returns 1, and sets *status to 0 if there are no warnings + * or to a PCAP_WARNING_ code if there is a warning. + * + * On failure due to lack of support for memory-mapped capture, returns + * 0. + * + * On error, returns -1, and sets *status to the appropriate error code; + * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message. + */ +static int +activate_mmap(pcap_t *handle, int *status) +{ + struct pcap_linux *handlep = handle->priv; + int ret; + + /* + * Attempt to allocate a buffer to hold the contents of one + * packet, for use by the oneshot callback. + */ + handlep->oneshot_buffer = malloc(handle->snapshot); + if (handlep->oneshot_buffer == NULL) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't allocate oneshot buffer: %s", + pcap_strerror(errno)); + *status = PCAP_ERROR; + return -1; + } + + if (handle->opt.buffer_size == 0) { + /* by default request 2M for the ring buffer */ + handle->opt.buffer_size = 2*1024*1024; + } + ret = prepare_tpacket_socket(handle); + if (ret == -1) { + free(handlep->oneshot_buffer); + *status = PCAP_ERROR; + return ret; + } + ret = create_ring(handle, status); + if (ret == 0) { + /* + * We don't support memory-mapped capture; our caller + * will fall back on reading from the socket. + */ + free(handlep->oneshot_buffer); + return 0; + } + if (ret == -1) { + /* + * Error attempting to enable memory-mapped capture; + * fail. create_ring() has set *status. + */ + free(handlep->oneshot_buffer); + return -1; + } + + /* + * Success. *status has been set either to 0 if there are no + * warnings or to a PCAP_WARNING_ value if there is a warning. + * + * Override some defaults and inherit the other fields from + * activate_new. + * handle->offset is used to get the current position into the rx ring. + * handle->cc is used to store the ring size. + */ + + switch (handlep->tp_version) { + case TPACKET_V1: + handle->read_op = pcap_read_linux_mmap_v1; + break; + case TPACKET_V1_64: + handle->read_op = pcap_read_linux_mmap_v1_64; + break; +#ifdef HAVE_TPACKET2 + case TPACKET_V2: + handle->read_op = pcap_read_linux_mmap_v2; + break; +#endif +#ifdef HAVE_TPACKET3 + case TPACKET_V3: + handle->read_op = pcap_read_linux_mmap_v3; + break; +#endif + } + handle->cleanup_op = pcap_cleanup_linux_mmap; + handle->setfilter_op = pcap_setfilter_linux_mmap; + handle->setnonblock_op = pcap_setnonblock_mmap; + handle->getnonblock_op = pcap_getnonblock_mmap; + handle->oneshot_callback = pcap_oneshot_mmap; + handle->selectable_fd = handle->fd; + return 1; +} +#else /* HAVE_PACKET_RING */ +static int +activate_mmap(pcap_t *handle _U_, int *status _U_) +{ + return 0; +} +#endif /* HAVE_PACKET_RING */ + +#ifdef HAVE_PACKET_RING + +#if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3) +/* + * Attempt to set the socket to the specified version of the memory-mapped + * header. + * + * Return 0 if we succeed; return 1 if we fail because that version isn't + * supported; return -1 on any other error, and set handle->errbuf. + */ +static int +init_tpacket(pcap_t *handle, int version, const char *version_str) +{ + struct pcap_linux *handlep = handle->priv; + int val = version; + socklen_t len = sizeof(val); + + /* + * Probe whether kernel supports the specified TPACKET version; + * this also gets the length of the header for that version. + */ + if (getsockopt(handle->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { + if (errno == ENOPROTOOPT || errno == EINVAL) + return 1; /* no */ + + /* Failed to even find out; this is a fatal error. */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't get %s header len on packet socket: %s", + version_str, + pcap_strerror(errno)); + return -1; + } + handlep->tp_hdrlen = val; + + val = version; + if (setsockopt(handle->fd, SOL_PACKET, PACKET_VERSION, &val, + sizeof(val)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't activate %s on packet socket: %s", + version_str, + pcap_strerror(errno)); + return -1; + } + handlep->tp_version = version; + + /* Reserve space for VLAN tag reconstruction */ + val = VLAN_TAG_LEN; + if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, &val, + sizeof(val)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't set up reserve on packet socket: %s", + pcap_strerror(errno)); + return -1; + } + + return 0; +} +#endif /* defined HAVE_TPACKET2 || defined HAVE_TPACKET3 */ + +/* + * If the instruction set for which we're compiling has both 32-bit + * and 64-bit versions, and Linux support for the 64-bit version + * predates TPACKET_V2, define ISA_64_BIT as the .machine value + * you get from uname() for the 64-bit version. Otherwise, leave + * it undefined. (This includes ARM, which has a 64-bit version, + * but Linux support for it appeared well after TPACKET_V2 support + * did, so there should never be a case where 32-bit ARM code is + * running o a 64-bit kernel that only supports TPACKET_V1.) + * + * If we've omitted your favorite such architecture, please contribute + * a patch. (No patch is needed for architectures that are 32-bit-only + * or for which Linux has no support for 32-bit userland - or for which, + * as noted, 64-bit support appeared in Linux after TPACKET_V2 support + * did.) + */ +#if defined(__i386__) +#define ISA_64_BIT "x86_64" +#elif defined(__ppc__) +#define ISA_64_BIT "ppc64" +#elif defined(__sparc__) +#define ISA_64_BIT "sparc64" +#elif defined(__s390__) +#define ISA_64_BIT "s390x" +#elif defined(__mips__) +#define ISA_64_BIT "mips64" +#elif defined(__hppa__) +#define ISA_64_BIT "parisc64" +#endif + +/* + * Attempt to set the socket to version 3 of the memory-mapped header and, + * if that fails because version 3 isn't supported, attempt to fall + * back to version 2. If version 2 isn't supported, just leave it at + * version 1. + * + * Return 1 if we succeed or if we fail because neither version 2 nor 3 is + * supported; return -1 on any other error, and set handle->errbuf. + */ +static int +prepare_tpacket_socket(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; +#if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3) + int ret; +#endif + +#ifdef HAVE_TPACKET3 + /* + * Try setting the version to TPACKET_V3. + * + * The only mode in which buffering is done on PF_PACKET + * sockets, so that packets might not be delivered + * immediately, is TPACKET_V3 mode. + * + * The buffering cannot be disabled in that mode, so + * if the user has requested immediate mode, we don't + * use TPACKET_V3. + */ + if (!handle->opt.immediate) { + ret = init_tpacket(handle, TPACKET_V3, "TPACKET_V3"); + if (ret == 0) { + /* + * Success. + */ + return 1; + } + if (ret == -1) { + /* + * We failed for some reason other than "the + * kernel doesn't support TPACKET_V3". + */ + return -1; + } + } +#endif /* HAVE_TPACKET3 */ + +#ifdef HAVE_TPACKET2 + /* + * Try setting the version to TPACKET_V2. + */ + ret = init_tpacket(handle, TPACKET_V2, "TPACKET_V2"); + if (ret == 0) { + /* + * Success. + */ + return 1; + } + if (ret == -1) { + /* + * We failed for some reason other than "the + * kernel doesn't support TPACKET_V2". + */ + return -1; + } +#endif /* HAVE_TPACKET2 */ + + /* + * OK, we're using TPACKET_V1, as that's all the kernel supports. + */ + handlep->tp_version = TPACKET_V1; + handlep->tp_hdrlen = sizeof(struct tpacket_hdr); + +#ifdef ISA_64_BIT + /* + * 32-bit userspace + 64-bit kernel + TPACKET_V1 are not compatible with + * each other due to platform-dependent data type size differences. + * + * If we have a 32-bit userland and a 64-bit kernel, use an + * internally-defined TPACKET_V1_64, with which we use a 64-bit + * version of the data structures. + */ + if (sizeof(long) == 4) { + /* + * This is 32-bit code. + */ + struct utsname utsname; + + if (uname(&utsname) == -1) { + /* + * Failed. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "uname failed: %s", pcap_strerror(errno)); + return -1; + } + if (strcmp(utsname.machine, ISA_64_BIT) == 0) { + /* + * uname() tells us the machine is 64-bit, + * so we presumably have a 64-bit kernel. + * + * XXX - this presumes that uname() won't lie + * in 32-bit code and claim that the machine + * has the 32-bit version of the ISA. + */ + handlep->tp_version = TPACKET_V1_64; + handlep->tp_hdrlen = sizeof(struct tpacket_hdr_64); + } + } +#endif + + return 1; +} + +/* + * Attempt to set up memory-mapped access. + * + * On success, returns 1, and sets *status to 0 if there are no warnings + * or to a PCAP_WARNING_ code if there is a warning. + * + * On failure due to lack of support for memory-mapped capture, returns + * 0. + * + * On error, returns -1, and sets *status to the appropriate error code; + * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message. + */ +static int +create_ring(pcap_t *handle, int *status) +{ + struct pcap_linux *handlep = handle->priv; + unsigned i, j, frames_per_block; +#ifdef HAVE_TPACKET3 + /* + * For sockets using TPACKET_V1 or TPACKET_V2, the extra + * stuff at the end of a struct tpacket_req3 will be + * ignored, so this is OK even for those sockets. + */ + struct tpacket_req3 req; +#else + struct tpacket_req req; +#endif + socklen_t len; + unsigned int sk_type, tp_reserve, maclen, tp_hdrlen, netoff, macoff; + unsigned int frame_size; + + /* + * Start out assuming no warnings or errors. + */ + *status = 0; + + switch (handlep->tp_version) { + + case TPACKET_V1: + case TPACKET_V1_64: +#ifdef HAVE_TPACKET2 + case TPACKET_V2: +#endif + /* Note that with large snapshot length (say 64K, which is + * the default for recent versions of tcpdump, the value that + * "-s 0" has given for a long time with tcpdump, and the + * default in Wireshark/TShark/dumpcap), if we use the snapshot + * length to calculate the frame length, only a few frames + * will be available in the ring even with pretty + * large ring size (and a lot of memory will be unused). + * + * Ideally, we should choose a frame length based on the + * minimum of the specified snapshot length and the maximum + * packet size. That's not as easy as it sounds; consider, + * for example, an 802.11 interface in monitor mode, where + * the frame would include a radiotap header, where the + * maximum radiotap header length is device-dependent. + * + * So, for now, we just do this for Ethernet devices, where + * there's no metadata header, and the link-layer header is + * fixed length. We can get the maximum packet size by + * adding 18, the Ethernet header length plus the CRC length + * (just in case we happen to get the CRC in the packet), to + * the MTU of the interface; we fetch the MTU in the hopes + * that it reflects support for jumbo frames. (Even if the + * interface is just being used for passive snooping, the + * driver might set the size of buffers in the receive ring + * based on the MTU, so that the MTU limits the maximum size + * of packets that we can receive.) + * + * We don't do that if segmentation/fragmentation or receive + * offload are enabled, so we don't get rudely surprised by + * "packets" bigger than the MTU. */ + frame_size = handle->snapshot; + if (handle->linktype == DLT_EN10MB) { + int mtu; + int offload; + + offload = iface_get_offload(handle); + if (offload == -1) { + *status = PCAP_ERROR; + return -1; + } + if (!offload) { + mtu = iface_get_mtu(handle->fd, handle->opt.source, + handle->errbuf); + if (mtu == -1) { + *status = PCAP_ERROR; + return -1; + } + if (frame_size > mtu + 18) + frame_size = mtu + 18; + } + } + + /* NOTE: calculus matching those in tpacket_rcv() + * in linux-2.6/net/packet/af_packet.c + */ + len = sizeof(sk_type); + if (getsockopt(handle->fd, SOL_SOCKET, SO_TYPE, &sk_type, + &len) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "getsockopt: %s", pcap_strerror(errno)); + *status = PCAP_ERROR; + return -1; + } +#ifdef PACKET_RESERVE + len = sizeof(tp_reserve); + if (getsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, + &tp_reserve, &len) < 0) { + if (errno != ENOPROTOOPT) { + /* + * ENOPROTOOPT means "kernel doesn't support + * PACKET_RESERVE", in which case we fall back + * as best we can. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "getsockopt: %s", pcap_strerror(errno)); + *status = PCAP_ERROR; + return -1; + } + tp_reserve = 0; /* older kernel, reserve not supported */ + } +#else + tp_reserve = 0; /* older kernel, reserve not supported */ +#endif + maclen = (sk_type == SOCK_DGRAM) ? 0 : MAX_LINKHEADER_SIZE; + /* XXX: in the kernel maclen is calculated from + * LL_ALLOCATED_SPACE(dev) and vnet_hdr.hdr_len + * in: packet_snd() in linux-2.6/net/packet/af_packet.c + * then packet_alloc_skb() in linux-2.6/net/packet/af_packet.c + * then sock_alloc_send_pskb() in linux-2.6/net/core/sock.c + * but I see no way to get those sizes in userspace, + * like for instance with an ifreq ioctl(); + * the best thing I've found so far is MAX_HEADER in + * the kernel part of linux-2.6/include/linux/netdevice.h + * which goes up to 128+48=176; since pcap-linux.c + * defines a MAX_LINKHEADER_SIZE of 256 which is + * greater than that, let's use it.. maybe is it even + * large enough to directly replace macoff.. + */ + tp_hdrlen = TPACKET_ALIGN(handlep->tp_hdrlen) + sizeof(struct sockaddr_ll) ; + netoff = TPACKET_ALIGN(tp_hdrlen + (maclen < 16 ? 16 : maclen)) + tp_reserve; + /* NOTE: AFAICS tp_reserve may break the TPACKET_ALIGN + * of netoff, which contradicts + * linux-2.6/Documentation/networking/packet_mmap.txt + * documenting that: + * "- Gap, chosen so that packet data (Start+tp_net) + * aligns to TPACKET_ALIGNMENT=16" + */ + /* NOTE: in linux-2.6/include/linux/skbuff.h: + * "CPUs often take a performance hit + * when accessing unaligned memory locations" + */ + macoff = netoff - maclen; + req.tp_frame_size = TPACKET_ALIGN(macoff + frame_size); + req.tp_frame_nr = handle->opt.buffer_size/req.tp_frame_size; + break; + +#ifdef HAVE_TPACKET3 + case TPACKET_V3: + /* The "frames" for this are actually buffers that + * contain multiple variable-sized frames. + * + * We pick a "frame" size of 128K to leave enough + * room for at least one reasonably-sized packet + * in the "frame". */ + req.tp_frame_size = MAXIMUM_SNAPLEN; + req.tp_frame_nr = handle->opt.buffer_size/req.tp_frame_size; + break; +#endif + default: + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Internal error: unknown TPACKET_ value %u", + handlep->tp_version); + *status = PCAP_ERROR; + return -1; + } + + /* compute the minumum block size that will handle this frame. + * The block has to be page size aligned. + * The max block size allowed by the kernel is arch-dependent and + * it's not explicitly checked here. */ + req.tp_block_size = getpagesize(); + while (req.tp_block_size < req.tp_frame_size) + req.tp_block_size <<= 1; + + frames_per_block = req.tp_block_size/req.tp_frame_size; + + /* + * PACKET_TIMESTAMP was added after linux/net_tstamp.h was, + * so we check for PACKET_TIMESTAMP. We check for + * linux/net_tstamp.h just in case a system somehow has + * PACKET_TIMESTAMP but not linux/net_tstamp.h; that might + * be unnecessary. + * + * SIOCSHWTSTAMP was introduced in the patch that introduced + * linux/net_tstamp.h, so we don't bother checking whether + * SIOCSHWTSTAMP is defined (if your Linux system has + * linux/net_tstamp.h but doesn't define SIOCSHWTSTAMP, your + * Linux system is badly broken). + */ +#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) + /* + * If we were told to do so, ask the kernel and the driver + * to use hardware timestamps. + * + * Hardware timestamps are only supported with mmapped + * captures. + */ + if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER || + handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER_UNSYNCED) { + struct hwtstamp_config hwconfig; + struct ifreq ifr; + int timesource; + + /* + * Ask for hardware time stamps on all packets, + * including transmitted packets. + */ + memset(&hwconfig, 0, sizeof(hwconfig)); + hwconfig.tx_type = HWTSTAMP_TX_ON; + hwconfig.rx_filter = HWTSTAMP_FILTER_ALL; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name)); + ifr.ifr_data = (void *)&hwconfig; + + if (ioctl(handle->fd, SIOCSHWTSTAMP, &ifr) < 0) { + switch (errno) { + + case EPERM: + /* + * Treat this as an error, as the + * user should try to run this + * with the appropriate privileges - + * and, if they can't, shouldn't + * try requesting hardware time stamps. + */ + *status = PCAP_ERROR_PERM_DENIED; + return -1; + + case EOPNOTSUPP: + /* + * Treat this as a warning, as the + * only way to fix the warning is to + * get an adapter that supports hardware + * time stamps. We'll just fall back + * on the standard host time stamps. + */ + *status = PCAP_WARNING_TSTAMP_TYPE_NOTSUP; + break; + + default: + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "SIOCSHWTSTAMP failed: %s", + pcap_strerror(errno)); + *status = PCAP_ERROR; + return -1; + } + } else { + /* + * Well, that worked. Now specify the type of + * hardware time stamp we want for this + * socket. + */ + if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER) { + /* + * Hardware timestamp, synchronized + * with the system clock. + */ + timesource = SOF_TIMESTAMPING_SYS_HARDWARE; + } else { + /* + * PCAP_TSTAMP_ADAPTER_UNSYNCED - hardware + * timestamp, not synchronized with the + * system clock. + */ + timesource = SOF_TIMESTAMPING_RAW_HARDWARE; + } + if (setsockopt(handle->fd, SOL_PACKET, PACKET_TIMESTAMP, + (void *)×ource, sizeof(timesource))) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't set PACKET_TIMESTAMP: %s", + pcap_strerror(errno)); + *status = PCAP_ERROR; + return -1; + } + } + } +#endif /* HAVE_LINUX_NET_TSTAMP_H && PACKET_TIMESTAMP */ + + /* ask the kernel to create the ring */ +retry: + req.tp_block_nr = req.tp_frame_nr / frames_per_block; + + /* req.tp_frame_nr is requested to match frames_per_block*req.tp_block_nr */ + req.tp_frame_nr = req.tp_block_nr * frames_per_block; + +#ifdef HAVE_TPACKET3 + /* timeout value to retire block - use the configured buffering timeout, or default if <0. */ + req.tp_retire_blk_tov = (handlep->timeout>=0)?handlep->timeout:0; + /* private data not used */ + req.tp_sizeof_priv = 0; + /* Rx ring - feature request bits - none (rxhash will not be filled) */ + req.tp_feature_req_word = 0; +#endif + + if (setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING, + (void *) &req, sizeof(req))) { + if ((errno == ENOMEM) && (req.tp_block_nr > 1)) { + /* + * Memory failure; try to reduce the requested ring + * size. + * + * We used to reduce this by half -- do 5% instead. + * That may result in more iterations and a longer + * startup, but the user will be much happier with + * the resulting buffer size. + */ + if (req.tp_frame_nr < 20) + req.tp_frame_nr -= 1; + else + req.tp_frame_nr -= req.tp_frame_nr/20; + goto retry; + } + if (errno == ENOPROTOOPT) { + /* + * We don't have ring buffer support in this kernel. + */ + return 0; + } + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't create rx ring on packet socket: %s", + pcap_strerror(errno)); + *status = PCAP_ERROR; + return -1; + } + + /* memory map the rx ring */ + handlep->mmapbuflen = req.tp_block_nr * req.tp_block_size; + handlep->mmapbuf = mmap(0, handlep->mmapbuflen, + PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); + if (handlep->mmapbuf == MAP_FAILED) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't mmap rx ring: %s", pcap_strerror(errno)); + + /* clear the allocated ring on error*/ + destroy_ring(handle); + *status = PCAP_ERROR; + return -1; + } + + /* allocate a ring for each frame header pointer*/ + handle->cc = req.tp_frame_nr; + handle->buffer = malloc(handle->cc * sizeof(union thdr *)); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't allocate ring of frame headers: %s", + pcap_strerror(errno)); + + destroy_ring(handle); + *status = PCAP_ERROR; + return -1; + } + + /* fill the header ring with proper frame ptr*/ + handle->offset = 0; + for (i=0; immapbuf[i*req.tp_block_size]; + for (j=0; joffset) { + RING_GET_FRAME(handle) = base; + base += req.tp_frame_size; + } + } + + handle->bufsize = req.tp_frame_size; + handle->offset = 0; + return 1; +} + +/* free all ring related resources*/ +static void +destroy_ring(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + + /* tell the kernel to destroy the ring*/ + struct tpacket_req req; + memset(&req, 0, sizeof(req)); + /* do not test for setsockopt failure, as we can't recover from any error */ + (void)setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING, + (void *) &req, sizeof(req)); + + /* if ring is mapped, unmap it*/ + if (handlep->mmapbuf) { + /* do not test for mmap failure, as we can't recover from any error */ + (void)munmap(handlep->mmapbuf, handlep->mmapbuflen); + handlep->mmapbuf = NULL; + } +} + +/* + * Special one-shot callback, used for pcap_next() and pcap_next_ex(), + * for Linux mmapped capture. + * + * The problem is that pcap_next() and pcap_next_ex() expect the packet + * data handed to the callback to be valid after the callback returns, + * but pcap_read_linux_mmap() has to release that packet as soon as + * the callback returns (otherwise, the kernel thinks there's still + * at least one unprocessed packet available in the ring, so a select() + * will immediately return indicating that there's data to process), so, + * in the callback, we have to make a copy of the packet. + * + * Yes, this means that, if the capture is using the ring buffer, using + * pcap_next() or pcap_next_ex() requires more copies than using + * pcap_loop() or pcap_dispatch(). If that bothers you, don't use + * pcap_next() or pcap_next_ex(). + */ +static void +pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h, + const u_char *bytes) +{ + struct oneshot_userdata *sp = (struct oneshot_userdata *)user; + pcap_t *handle = sp->pd; + struct pcap_linux *handlep = handle->priv; + + *sp->hdr = *h; + memcpy(handlep->oneshot_buffer, bytes, h->caplen); + *sp->pkt = handlep->oneshot_buffer; +} + +static void +pcap_cleanup_linux_mmap( pcap_t *handle ) +{ + struct pcap_linux *handlep = handle->priv; + + destroy_ring(handle); + if (handlep->oneshot_buffer != NULL) { + free(handlep->oneshot_buffer); + handlep->oneshot_buffer = NULL; + } + pcap_cleanup_linux(handle); +} + + +static int +pcap_getnonblock_mmap(pcap_t *p, char *errbuf) +{ + struct pcap_linux *handlep = p->priv; + + /* use negative value of timeout to indicate non blocking ops */ + return (handlep->timeout<0); +} + +static int +pcap_setnonblock_mmap(pcap_t *p, int nonblock, char *errbuf) +{ + struct pcap_linux *handlep = p->priv; + + /* + * Set the file descriptor to non-blocking mode, as we use + * it for sending packets. + */ + if (pcap_setnonblock_fd(p, nonblock, errbuf) == -1) + return -1; + + /* + * Map each value to their corresponding negation to + * preserve the timeout value provided with pcap_set_timeout. + */ + if (nonblock) { + if (handlep->timeout >= 0) { + /* + * Indicate that we're switching to + * non-blocking mode. + */ + handlep->timeout = ~handlep->timeout; + } + } else { + if (handlep->timeout < 0) { + handlep->timeout = ~handlep->timeout; + } + } + return 0; +} + +static inline union thdr * +pcap_get_ring_frame(pcap_t *handle, int status) +{ + struct pcap_linux *handlep = handle->priv; + union thdr h; + + h.raw = RING_GET_FRAME(handle); + switch (handlep->tp_version) { + case TPACKET_V1: + if (status != (h.h1->tp_status ? TP_STATUS_USER : + TP_STATUS_KERNEL)) + return NULL; + break; + case TPACKET_V1_64: + if (status != (h.h1_64->tp_status ? TP_STATUS_USER : + TP_STATUS_KERNEL)) + return NULL; + break; +#ifdef HAVE_TPACKET2 + case TPACKET_V2: + if (status != (h.h2->tp_status ? TP_STATUS_USER : + TP_STATUS_KERNEL)) + return NULL; + break; +#endif +#ifdef HAVE_TPACKET3 + case TPACKET_V3: + if (status != (h.h3->hdr.bh1.block_status ? TP_STATUS_USER : + TP_STATUS_KERNEL)) + return NULL; + break; +#endif + } + return h.raw; +} + +#ifndef POLLRDHUP +#define POLLRDHUP 0 +#endif + +/* wait for frames availability.*/ +static int pcap_wait_for_frames_mmap(pcap_t *handle) +{ + if (!pcap_get_ring_frame(handle, TP_STATUS_USER)) { + struct pcap_linux *handlep = handle->priv; + int timeout; + char c; + struct pollfd pollinfo; + int ret; + + pollinfo.fd = handle->fd; + pollinfo.events = POLLIN; + + if (handlep->timeout == 0) { +#ifdef HAVE_TPACKET3 + /* + * XXX - due to a set of (mis)features in the + * TPACKET_V3 kernel code, blocking forever with + * a TPACKET_V3 socket can, if few packets + * are arriving and passing the socket filter, + * cause most packets to be dropped. See + * libpcap issue #335 for the full painful + * story. The workaround is to have poll() + * time out very quickly, so we grab the + * frames handed to us, and return them to + * the kernel, ASAP. + * + * If those issues are ever fixed, we might + * want to check the kernel version and block + * forever with TPACKET_V3 if we're running + * with a kernel that has the fix. + */ + if (handlep->tp_version == TPACKET_V3) + timeout = 1; /* don't block for very long */ + else +#endif + timeout = -1; /* block forever */ + } else if (handlep->timeout > 0) + timeout = handlep->timeout; /* block for that amount of time */ + else + timeout = 0; /* non-blocking mode - poll to pick up errors */ + do { + ret = poll(&pollinfo, 1, timeout); + if (ret < 0 && errno != EINTR) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't poll on packet socket: %s", + pcap_strerror(errno)); + return PCAP_ERROR; + } else if (ret > 0 && + (pollinfo.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { + /* + * There's some indication other than + * "you can read on this descriptor" on + * the descriptor. + */ + if (pollinfo.revents & (POLLHUP | POLLRDHUP)) { + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "Hangup on packet socket"); + return PCAP_ERROR; + } + if (pollinfo.revents & POLLERR) { + /* + * A recv() will give us the + * actual error code. + * + * XXX - make the socket non-blocking? + */ + if (recv(handle->fd, &c, sizeof c, + MSG_PEEK) != -1) + continue; /* what, no error? */ + if (errno == ENETDOWN) { + /* + * The device on which we're + * capturing went away. + * + * XXX - we should really return + * PCAP_ERROR_IFACE_NOT_UP, + * but pcap_dispatch() etc. + * aren't defined to return + * that. + */ + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "The interface went down"); + } else { + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "Error condition on packet socket: %s", + strerror(errno)); + } + return PCAP_ERROR; + } + if (pollinfo.revents & POLLNVAL) { + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "Invalid polling request on packet socket"); + return PCAP_ERROR; + } + } + /* check for break loop condition on interrupted syscall*/ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } while (ret < 0); + } + return 0; +} + +/* handle a single memory mapped packet */ +static int pcap_handle_packet_mmap( + pcap_t *handle, + pcap_handler callback, + u_char *user, + unsigned char *frame, + unsigned int tp_len, + unsigned int tp_mac, + unsigned int tp_snaplen, + unsigned int tp_sec, + unsigned int tp_usec, + int tp_vlan_tci_valid, + __u16 tp_vlan_tci, + __u16 tp_vlan_tpid) +{ + struct pcap_linux *handlep = handle->priv; + unsigned char *bp; + struct sockaddr_ll *sll; + struct pcap_pkthdr pcaphdr; + + /* perform sanity check on internal offset. */ + if (tp_mac + tp_snaplen > handle->bufsize) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "corrupted frame on kernel ring mac " + "offset %u + caplen %u > frame len %d", + tp_mac, tp_snaplen, handle->bufsize); + return -1; + } + + /* run filter on received packet + * If the kernel filtering is enabled we need to run the + * filter until all the frames present into the ring + * at filter creation time are processed. + * In this case, blocks_to_filter_in_userland is used + * as a counter for the packet we need to filter. + * Note: alternatively it could be possible to stop applying + * the filter when the ring became empty, but it can possibly + * happen a lot later... */ + bp = frame + tp_mac; + + /* if required build in place the sll header*/ + sll = (void *)frame + TPACKET_ALIGN(handlep->tp_hdrlen); + if (handlep->cooked) { + struct sll_header *hdrp; + + /* + * The kernel should have left us with enough + * space for an sll header; back up the packet + * data pointer into that space, as that'll be + * the beginning of the packet we pass to the + * callback. + */ + bp -= SLL_HDR_LEN; + + /* + * Let's make sure that's past the end of + * the tpacket header, i.e. >= + * ((u_char *)thdr + TPACKET_HDRLEN), so we + * don't step on the header when we construct + * the sll header. + */ + if (bp < (u_char *)frame + + TPACKET_ALIGN(handlep->tp_hdrlen) + + sizeof(struct sockaddr_ll)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "cooked-mode frame doesn't have room for sll header"); + return -1; + } + + /* + * OK, that worked; construct the sll header. + */ + hdrp = (struct sll_header *)bp; + hdrp->sll_pkttype = map_packet_type_to_sll_type( + sll->sll_pkttype); + hdrp->sll_hatype = htons(sll->sll_hatype); + hdrp->sll_halen = htons(sll->sll_halen); + memcpy(hdrp->sll_addr, sll->sll_addr, SLL_ADDRLEN); + hdrp->sll_protocol = sll->sll_protocol; + } + + if (handlep->filter_in_userland && handle->fcode.bf_insns) { + struct bpf_aux_data aux_data; + + aux_data.vlan_tag = tp_vlan_tci & 0x0fff; + aux_data.vlan_tag_present = tp_vlan_tci_valid; + + if (bpf_filter_with_aux_data(handle->fcode.bf_insns, bp, + tp_len, tp_snaplen, &aux_data) == 0) + return 0; + } + + if (!linux_check_direction(handle, sll)) + return 0; + + /* get required packet info from ring header */ + pcaphdr.ts.tv_sec = tp_sec; + pcaphdr.ts.tv_usec = tp_usec; + pcaphdr.caplen = tp_snaplen; + pcaphdr.len = tp_len; + + /* if required build in place the sll header*/ + if (handlep->cooked) { + /* update packet len */ + pcaphdr.caplen += SLL_HDR_LEN; + pcaphdr.len += SLL_HDR_LEN; + } + +#if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3) + if (tp_vlan_tci_valid && + handlep->vlan_offset != -1 && + tp_snaplen >= (unsigned int) handlep->vlan_offset) + { + struct vlan_tag *tag; + + bp -= VLAN_TAG_LEN; + memmove(bp, bp + VLAN_TAG_LEN, handlep->vlan_offset); + + tag = (struct vlan_tag *)(bp + handlep->vlan_offset); + tag->vlan_tpid = htons(tp_vlan_tpid); + tag->vlan_tci = htons(tp_vlan_tci); + + pcaphdr.caplen += VLAN_TAG_LEN; + pcaphdr.len += VLAN_TAG_LEN; + } +#endif + + /* + * The only way to tell the kernel to cut off the + * packet at a snapshot length is with a filter program; + * if there's no filter program, the kernel won't cut + * the packet off. + * + * Trim the snapshot length to be no longer than the + * specified snapshot length. + */ + if (pcaphdr.caplen > handle->snapshot) + pcaphdr.caplen = handle->snapshot; + + /* pass the packet to the user */ + callback(user, &pcaphdr, bp); + + return 1; +} + +static int +pcap_read_linux_mmap_v1(pcap_t *handle, int max_packets, pcap_handler callback, + u_char *user) +{ + struct pcap_linux *handlep = handle->priv; + int pkts = 0; + int ret; + + /* wait for frames availability.*/ + ret = pcap_wait_for_frames_mmap(handle); + if (ret) { + return ret; + } + + /* non-positive values of max_packets are used to require all + * packets currently available in the ring */ + while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) { + union thdr h; + + h.raw = pcap_get_ring_frame(handle, TP_STATUS_USER); + if (!h.raw) + break; + + ret = pcap_handle_packet_mmap( + handle, + callback, + user, + h.raw, + h.h1->tp_len, + h.h1->tp_mac, + h.h1->tp_snaplen, + h.h1->tp_sec, + h.h1->tp_usec, + 0, + 0, + 0); + if (ret == 1) { + pkts++; + handlep->packets_read++; + } else if (ret < 0) { + return ret; + } + + /* + * Hand this block back to the kernel, and, if we're + * counting blocks that need to be filtered in userland + * after having been filtered by the kernel, count + * the one we've just processed. + */ + h.h1->tp_status = TP_STATUS_KERNEL; + if (handlep->blocks_to_filter_in_userland > 0) { + handlep->blocks_to_filter_in_userland--; + if (handlep->blocks_to_filter_in_userland == 0) { + /* + * No more blocks need to be filtered + * in userland. + */ + handlep->filter_in_userland = 0; + } + } + + /* next block */ + if (++handle->offset >= handle->cc) + handle->offset = 0; + + /* check for break loop condition*/ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } + return pkts; +} + +static int +pcap_read_linux_mmap_v1_64(pcap_t *handle, int max_packets, pcap_handler callback, + u_char *user) +{ + struct pcap_linux *handlep = handle->priv; + int pkts = 0; + int ret; + + /* wait for frames availability.*/ + ret = pcap_wait_for_frames_mmap(handle); + if (ret) { + return ret; + } + + /* non-positive values of max_packets are used to require all + * packets currently available in the ring */ + while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) { + union thdr h; + + h.raw = pcap_get_ring_frame(handle, TP_STATUS_USER); + if (!h.raw) + break; + + ret = pcap_handle_packet_mmap( + handle, + callback, + user, + h.raw, + h.h1_64->tp_len, + h.h1_64->tp_mac, + h.h1_64->tp_snaplen, + h.h1_64->tp_sec, + h.h1_64->tp_usec, + 0, + 0, + 0); + if (ret == 1) { + pkts++; + handlep->packets_read++; + } else if (ret < 0) { + return ret; + } + + /* + * Hand this block back to the kernel, and, if we're + * counting blocks that need to be filtered in userland + * after having been filtered by the kernel, count + * the one we've just processed. + */ + h.h1_64->tp_status = TP_STATUS_KERNEL; + if (handlep->blocks_to_filter_in_userland > 0) { + handlep->blocks_to_filter_in_userland--; + if (handlep->blocks_to_filter_in_userland == 0) { + /* + * No more blocks need to be filtered + * in userland. + */ + handlep->filter_in_userland = 0; + } + } + + /* next block */ + if (++handle->offset >= handle->cc) + handle->offset = 0; + + /* check for break loop condition*/ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } + return pkts; +} + +#ifdef HAVE_TPACKET2 +static int +pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback, + u_char *user) +{ + struct pcap_linux *handlep = handle->priv; + int pkts = 0; + int ret; + + /* wait for frames availability.*/ + ret = pcap_wait_for_frames_mmap(handle); + if (ret) { + return ret; + } + + /* non-positive values of max_packets are used to require all + * packets currently available in the ring */ + while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) { + union thdr h; + + h.raw = pcap_get_ring_frame(handle, TP_STATUS_USER); + if (!h.raw) + break; + + ret = pcap_handle_packet_mmap( + handle, + callback, + user, + h.raw, + h.h2->tp_len, + h.h2->tp_mac, + h.h2->tp_snaplen, + h.h2->tp_sec, + handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? h.h2->tp_nsec : h.h2->tp_nsec / 1000, +#if defined(TP_STATUS_VLAN_VALID) + (h.h2->tp_vlan_tci || (h.h2->tp_status & TP_STATUS_VLAN_VALID)), +#else + h.h2->tp_vlan_tci != 0, +#endif + h.h2->tp_vlan_tci, + VLAN_TPID(h.h2, h.h2)); + if (ret == 1) { + pkts++; + handlep->packets_read++; + } else if (ret < 0) { + return ret; + } + + /* + * Hand this block back to the kernel, and, if we're + * counting blocks that need to be filtered in userland + * after having been filtered by the kernel, count + * the one we've just processed. + */ + h.h2->tp_status = TP_STATUS_KERNEL; + if (handlep->blocks_to_filter_in_userland > 0) { + handlep->blocks_to_filter_in_userland--; + if (handlep->blocks_to_filter_in_userland == 0) { + /* + * No more blocks need to be filtered + * in userland. + */ + handlep->filter_in_userland = 0; + } + } + + /* next block */ + if (++handle->offset >= handle->cc) + handle->offset = 0; + + /* check for break loop condition*/ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } + return pkts; +} +#endif /* HAVE_TPACKET2 */ + +#ifdef HAVE_TPACKET3 +static int +pcap_read_linux_mmap_v3(pcap_t *handle, int max_packets, pcap_handler callback, + u_char *user) +{ + struct pcap_linux *handlep = handle->priv; + union thdr h; + int pkts = 0; + int ret; + +again: + if (handlep->current_packet == NULL) { + /* wait for frames availability.*/ + ret = pcap_wait_for_frames_mmap(handle); + if (ret) { + return ret; + } + } + h.raw = pcap_get_ring_frame(handle, TP_STATUS_USER); + if (!h.raw) { + if (pkts == 0 && handlep->timeout == 0) { + /* Block until we see a packet. */ + goto again; + } + return pkts; + } + + /* non-positive values of max_packets are used to require all + * packets currently available in the ring */ + while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) { + if (handlep->current_packet == NULL) { + h.raw = pcap_get_ring_frame(handle, TP_STATUS_USER); + if (!h.raw) + break; + + handlep->current_packet = h.raw + h.h3->hdr.bh1.offset_to_first_pkt; + handlep->packets_left = h.h3->hdr.bh1.num_pkts; + } + int packets_to_read = handlep->packets_left; + + if (!PACKET_COUNT_IS_UNLIMITED(max_packets) && packets_to_read > max_packets) { + packets_to_read = max_packets; + } + + while(packets_to_read--) { + struct tpacket3_hdr* tp3_hdr = (struct tpacket3_hdr*) handlep->current_packet; + ret = pcap_handle_packet_mmap( + handle, + callback, + user, + handlep->current_packet, + tp3_hdr->tp_len, + tp3_hdr->tp_mac, + tp3_hdr->tp_snaplen, + tp3_hdr->tp_sec, + handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? tp3_hdr->tp_nsec : tp3_hdr->tp_nsec / 1000, +#if defined(TP_STATUS_VLAN_VALID) + (tp3_hdr->hv1.tp_vlan_tci || (tp3_hdr->tp_status & TP_STATUS_VLAN_VALID)), +#else + tp3_hdr->hv1.tp_vlan_tci != 0, +#endif + tp3_hdr->hv1.tp_vlan_tci, + VLAN_TPID(tp3_hdr, &tp3_hdr->hv1)); + if (ret == 1) { + pkts++; + handlep->packets_read++; + } else if (ret < 0) { + handlep->current_packet = NULL; + return ret; + } + handlep->current_packet += tp3_hdr->tp_next_offset; + handlep->packets_left--; + } + + if (handlep->packets_left <= 0) { + /* + * Hand this block back to the kernel, and, if + * we're counting blocks that need to be + * filtered in userland after having been + * filtered by the kernel, count the one we've + * just processed. + */ + h.h3->hdr.bh1.block_status = TP_STATUS_KERNEL; + if (handlep->blocks_to_filter_in_userland > 0) { + handlep->blocks_to_filter_in_userland--; + if (handlep->blocks_to_filter_in_userland == 0) { + /* + * No more blocks need to be filtered + * in userland. + */ + handlep->filter_in_userland = 0; + } + } + + /* next block */ + if (++handle->offset >= handle->cc) + handle->offset = 0; + + handlep->current_packet = NULL; + } + + /* check for break loop condition*/ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } + if (pkts == 0 && handlep->timeout == 0) { + /* Block until we see a packet. */ + goto again; + } + return pkts; +} +#endif /* HAVE_TPACKET3 */ + +static int +pcap_setfilter_linux_mmap(pcap_t *handle, struct bpf_program *filter) +{ + struct pcap_linux *handlep = handle->priv; + int n, offset; + int ret; + + /* + * Don't rewrite "ret" instructions; we don't need to, as + * we're not reading packets with recvmsg(), and we don't + * want to, as, by not rewriting them, the kernel can avoid + * copying extra data. + */ + ret = pcap_setfilter_linux_common(handle, filter, 1); + if (ret < 0) + return ret; + + /* + * If we're filtering in userland, there's nothing to do; + * the new filter will be used for the next packet. + */ + if (handlep->filter_in_userland) + return ret; + + /* + * We're filtering in the kernel; the packets present in + * all blocks currently in the ring were already filtered + * by the old filter, and so will need to be filtered in + * userland by the new filter. + * + * Get an upper bound for the number of such blocks; first, + * walk the ring backward and count the free blocks. + */ + offset = handle->offset; + if (--handle->offset < 0) + handle->offset = handle->cc - 1; + for (n=0; n < handle->cc; ++n) { + if (--handle->offset < 0) + handle->offset = handle->cc - 1; + if (!pcap_get_ring_frame(handle, TP_STATUS_KERNEL)) + break; + } + + /* + * If we found free blocks, decrement the count of free + * blocks by 1, just in case we lost a race with another + * thread of control that was adding a packet while + * we were counting and that had run the filter before + * we changed it. + * + * XXX - could there be more than one block added in + * this fashion? + * + * XXX - is there a way to avoid that race, e.g. somehow + * wait for all packets that passed the old filter to + * be added to the ring? + */ + if (n != 0) + n--; + + /* be careful to not change current ring position */ + handle->offset = offset; + + /* + * Set the count of blocks worth of packets to filter + * in userland to the total number of blocks in the + * ring minus the number of free blocks we found, and + * turn on userland filtering. (The count of blocks + * worth of packets to filter in userland is guaranteed + * not to be zero - n, above, couldn't be set to a + * value > handle->cc, and if it were equal to + * handle->cc, it wouldn't be zero, and thus would + * be decremented to handle->cc - 1.) + */ + handlep->blocks_to_filter_in_userland = handle->cc - n; + handlep->filter_in_userland = 1; + return ret; +} + +#endif /* HAVE_PACKET_RING */ + + +#ifdef HAVE_PF_PACKET_SOCKETS +/* + * Return the index of the given device name. Fill ebuf and return + * -1 on failure. + */ +static int +iface_get_id(int fd, const char *device, char *ebuf) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "SIOCGIFINDEX: %s", pcap_strerror(errno)); + return -1; + } + + return ifr.ifr_ifindex; +} + +/* + * Bind the socket associated with FD to the given device. + * Return 1 on success, 0 if we should try a SOCK_PACKET socket, + * or a PCAP_ERROR_ value on a hard error. + */ +static int +iface_bind(int fd, int ifindex, char *ebuf) +{ + struct sockaddr_ll sll; + int err; + socklen_t errlen = sizeof(err); + + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_ifindex = ifindex; + sll.sll_protocol = htons(ETH_P_ALL); + + if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) { + if (errno == ENETDOWN) { + /* + * Return a "network down" indication, so that + * the application can report that rather than + * saying we had a mysterious failure and + * suggest that they report a problem to the + * libpcap developers. + */ + return PCAP_ERROR_IFACE_NOT_UP; + } else { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "bind: %s", pcap_strerror(errno)); + return PCAP_ERROR; + } + } + + /* Any pending errors, e.g., network is down? */ + + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "getsockopt: %s", pcap_strerror(errno)); + return 0; + } + + if (err == ENETDOWN) { + /* + * Return a "network down" indication, so that + * the application can report that rather than + * saying we had a mysterious failure and + * suggest that they report a problem to the + * libpcap developers. + */ + return PCAP_ERROR_IFACE_NOT_UP; + } else if (err > 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "bind: %s", pcap_strerror(err)); + return 0; + } + + return 1; +} + +#ifdef IW_MODE_MONITOR +/* + * Check whether the device supports the Wireless Extensions. + * Returns 1 if it does, 0 if it doesn't, PCAP_ERROR_NO_SUCH_DEVICE + * if the device doesn't even exist. + */ +static int +has_wext(int sock_fd, const char *device, char *ebuf) +{ + struct iwreq ireq; + + if (is_bonding_device(sock_fd, device)) + return 0; /* bonding device, so don't even try */ + + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + if (ioctl(sock_fd, SIOCGIWNAME, &ireq) >= 0) + return 1; /* yes */ + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "%s: SIOCGIWNAME: %s", device, pcap_strerror(errno)); + if (errno == ENODEV) + return PCAP_ERROR_NO_SUCH_DEVICE; + return 0; +} + +/* + * Per me si va ne la citta dolente, + * Per me si va ne l'etterno dolore, + * ... + * Lasciate ogne speranza, voi ch'intrate. + * + * XXX - airmon-ng does special stuff with the Orinoco driver and the + * wlan-ng driver. + */ +typedef enum { + MONITOR_WEXT, + MONITOR_HOSTAP, + MONITOR_PRISM, + MONITOR_PRISM54, + MONITOR_ACX100, + MONITOR_RT2500, + MONITOR_RT2570, + MONITOR_RT73, + MONITOR_RTL8XXX +} monitor_type; + +/* + * Use the Wireless Extensions, if we have them, to try to turn monitor mode + * on if it's not already on. + * + * Returns 1 on success, 0 if we don't support the Wireless Extensions + * on this device, or a PCAP_ERROR_ value if we do support them but + * we weren't able to turn monitor mode on. + */ +static int +enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) +{ + /* + * XXX - at least some adapters require non-Wireless Extensions + * mechanisms to turn monitor mode on. + * + * Atheros cards might require that a separate "monitor virtual access + * point" be created, with later versions of the madwifi driver. + * airmon-ng does "wlanconfig ath create wlandev {if} wlanmode + * monitor -bssid", which apparently spits out a line "athN" + * where "athN" is the monitor mode device. To leave monitor + * mode, it destroys the monitor mode device. + * + * Some Intel Centrino adapters might require private ioctls to get + * radio headers; the ipw2200 and ipw3945 drivers allow you to + * configure a separate "rtapN" interface to capture in monitor + * mode without preventing the adapter from operating normally. + * (airmon-ng doesn't appear to use that, though.) + * + * It would be Truly Wonderful if mac80211 and nl80211 cleaned this + * up, and if all drivers were converted to mac80211 drivers. + * + * If interface {if} is a mac80211 driver, the file + * /sys/class/net/{if}/phy80211 is a symlink to + * /sys/class/ieee80211/{phydev}, for some {phydev}. + * + * On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at + * least, has a "wmaster0" device and a "wlan0" device; the + * latter is the one with the IP address. Both show up in + * "tcpdump -D" output. Capturing on the wmaster0 device + * captures with 802.11 headers. + * + * airmon-ng searches through /sys/class/net for devices named + * monN, starting with mon0; as soon as one *doesn't* exist, + * it chooses that as the monitor device name. If the "iw" + * command exists, it does "iw dev {if} interface add {monif} + * type monitor", where {monif} is the monitor device. It + * then (sigh) sleeps .1 second, and then configures the + * device up. Otherwise, if /sys/class/ieee80211/{phydev}/add_iface + * is a file, it writes {mondev}, without a newline, to that file, + * and again (sigh) sleeps .1 second, and then iwconfig's that + * device into monitor mode and configures it up. Otherwise, + * you can't do monitor mode. + * + * All these devices are "glued" together by having the + * /sys/class/net/{device}/phy80211 links pointing to the same + * place, so, given a wmaster, wlan, or mon device, you can + * find the other devices by looking for devices with + * the same phy80211 link. + * + * To turn monitor mode off, delete the monitor interface, + * either with "iw dev {monif} interface del" or by sending + * {monif}, with no NL, down /sys/class/ieee80211/{phydev}/remove_iface + * + * Note: if you try to create a monitor device named "monN", and + * there's already a "monN" device, it fails, as least with + * the netlink interface (which is what iw uses), with a return + * value of -ENFILE. (Return values are negative errnos.) We + * could probably use that to find an unused device. + */ + struct pcap_linux *handlep = handle->priv; + int err; + struct iwreq ireq; + struct iw_priv_args *priv; + monitor_type montype; + int i; + __u32 cmd; + struct ifreq ifr; + int oldflags; + int args[2]; + int channel; + + /* + * Does this device *support* the Wireless Extensions? + */ + err = has_wext(sock_fd, device, handle->errbuf); + if (err <= 0) + return err; /* either it doesn't or the device doesn't even exist */ + /* + * Start out assuming we have no private extensions to control + * radio metadata. + */ + montype = MONITOR_WEXT; + cmd = 0; + + /* + * Try to get all the Wireless Extensions private ioctls + * supported by this device. + * + * First, get the size of the buffer we need, by supplying no + * buffer and a length of 0. If the device supports private + * ioctls, it should return E2BIG, with ireq.u.data.length set + * to the length we need. If it doesn't support them, it should + * return EOPNOTSUPP. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + ireq.u.data.pointer = (void *)args; + ireq.u.data.length = 0; + ireq.u.data.flags = 0; + if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) != -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: SIOCGIWPRIV with a zero-length buffer didn't fail!", + device); + return PCAP_ERROR; + } + if (errno != EOPNOTSUPP) { + /* + * OK, it's not as if there are no private ioctls. + */ + if (errno != E2BIG) { + /* + * Failed. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: SIOCGIWPRIV: %s", device, + pcap_strerror(errno)); + return PCAP_ERROR; + } + + /* + * OK, try to get the list of private ioctls. + */ + priv = malloc(ireq.u.data.length * sizeof (struct iw_priv_args)); + if (priv == NULL) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return PCAP_ERROR; + } + ireq.u.data.pointer = (void *)priv; + if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: SIOCGIWPRIV: %s", device, + pcap_strerror(errno)); + free(priv); + return PCAP_ERROR; + } + + /* + * Look for private ioctls to turn monitor mode on or, if + * monitor mode is on, to set the header type. + */ + for (i = 0; i < ireq.u.data.length; i++) { + if (strcmp(priv[i].name, "monitor_type") == 0) { + /* + * Hostap driver, use this one. + * Set monitor mode first. + * You can set it to 0 to get DLT_IEEE80211, + * 1 to get DLT_PRISM, 2 to get + * DLT_IEEE80211_RADIO_AVS, and, with more + * recent versions of the driver, 3 to get + * DLT_IEEE80211_RADIO. + */ + if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) + break; + if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED)) + break; + if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1) + break; + montype = MONITOR_HOSTAP; + cmd = priv[i].cmd; + break; + } + if (strcmp(priv[i].name, "set_prismhdr") == 0) { + /* + * Prism54 driver, use this one. + * Set monitor mode first. + * You can set it to 2 to get DLT_IEEE80211 + * or 3 or get DLT_PRISM. + */ + if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) + break; + if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED)) + break; + if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1) + break; + montype = MONITOR_PRISM54; + cmd = priv[i].cmd; + break; + } + if (strcmp(priv[i].name, "forceprismheader") == 0) { + /* + * RT2570 driver, use this one. + * Do this after turning monitor mode on. + * You can set it to 1 to get DLT_PRISM or 2 + * to get DLT_IEEE80211. + */ + if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) + break; + if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED)) + break; + if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1) + break; + montype = MONITOR_RT2570; + cmd = priv[i].cmd; + break; + } + if (strcmp(priv[i].name, "forceprism") == 0) { + /* + * RT73 driver, use this one. + * Do this after turning monitor mode on. + * Its argument is a *string*; you can + * set it to "1" to get DLT_PRISM or "2" + * to get DLT_IEEE80211. + */ + if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_CHAR) + break; + if (priv[i].set_args & IW_PRIV_SIZE_FIXED) + break; + montype = MONITOR_RT73; + cmd = priv[i].cmd; + break; + } + if (strcmp(priv[i].name, "prismhdr") == 0) { + /* + * One of the RTL8xxx drivers, use this one. + * It can only be done after monitor mode + * has been turned on. You can set it to 1 + * to get DLT_PRISM or 0 to get DLT_IEEE80211. + */ + if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) + break; + if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED)) + break; + if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1) + break; + montype = MONITOR_RTL8XXX; + cmd = priv[i].cmd; + break; + } + if (strcmp(priv[i].name, "rfmontx") == 0) { + /* + * RT2500 or RT61 driver, use this one. + * It has one one-byte parameter; set + * u.data.length to 1 and u.data.pointer to + * point to the parameter. + * It doesn't itself turn monitor mode on. + * You can set it to 1 to allow transmitting + * in monitor mode(?) and get DLT_IEEE80211, + * or set it to 0 to disallow transmitting in + * monitor mode(?) and get DLT_PRISM. + */ + if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) + break; + if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 2) + break; + montype = MONITOR_RT2500; + cmd = priv[i].cmd; + break; + } + if (strcmp(priv[i].name, "monitor") == 0) { + /* + * Either ACX100 or hostap, use this one. + * It turns monitor mode on. + * If it takes two arguments, it's ACX100; + * the first argument is 1 for DLT_PRISM + * or 2 for DLT_IEEE80211, and the second + * argument is the channel on which to + * run. If it takes one argument, it's + * HostAP, and the argument is 2 for + * DLT_IEEE80211 and 3 for DLT_PRISM. + * + * If we see this, we don't quit, as this + * might be a version of the hostap driver + * that also supports "monitor_type". + */ + if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) + break; + if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED)) + break; + switch (priv[i].set_args & IW_PRIV_SIZE_MASK) { + + case 1: + montype = MONITOR_PRISM; + cmd = priv[i].cmd; + break; + + case 2: + montype = MONITOR_ACX100; + cmd = priv[i].cmd; + break; + + default: + break; + } + } + } + free(priv); + } + + /* + * XXX - ipw3945? islism? + */ + + /* + * Get the old mode. + */ + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + if (ioctl(sock_fd, SIOCGIWMODE, &ireq) == -1) { + /* + * We probably won't be able to set the mode, either. + */ + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* + * Is it currently in monitor mode? + */ + if (ireq.u.mode == IW_MODE_MONITOR) { + /* + * Yes. Just leave things as they are. + * We don't offer multiple link-layer types, as + * changing the link-layer type out from under + * somebody else capturing in monitor mode would + * be considered rude. + */ + return 1; + } + /* + * No. We have to put the adapter into rfmon mode. + */ + + /* + * If we haven't already done so, arrange to have + * "pcap_close_all()" called when we exit. + */ + if (!pcap_do_addexit(handle)) { + /* + * "atexit()" failed; don't put the interface + * in rfmon mode, just give up. + */ + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* + * Save the old mode. + */ + handlep->oldmode = ireq.u.mode; + + /* + * Put the adapter in rfmon mode. How we do this depends + * on whether we have a special private ioctl or not. + */ + if (montype == MONITOR_PRISM) { + /* + * We have the "monitor" private ioctl, but none of + * the other private ioctls. Use this, and select + * the Prism header. + * + * If it fails, just fall back on SIOCSIWMODE. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + ireq.u.data.length = 1; /* 1 argument */ + args[0] = 3; /* request Prism header */ + memcpy(ireq.u.name, args, sizeof (int)); + if (ioctl(sock_fd, cmd, &ireq) != -1) { + /* + * Success. + * Note that we have to put the old mode back + * when we close the device. + */ + handlep->must_do_on_close |= MUST_CLEAR_RFMON; + + /* + * Add this to the list of pcaps to close + * when we exit. + */ + pcap_add_to_pcaps_to_close(handle); + + return 1; + } + + /* + * Failure. Fall back on SIOCSIWMODE. + */ + } + + /* + * First, take the interface down if it's up; otherwise, we + * might get EBUSY. + */ + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't get flags: %s", device, strerror(errno)); + return PCAP_ERROR; + } + oldflags = 0; + if (ifr.ifr_flags & IFF_UP) { + oldflags = ifr.ifr_flags; + ifr.ifr_flags &= ~IFF_UP; + if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't set flags: %s", device, strerror(errno)); + return PCAP_ERROR; + } + } + + /* + * Then turn monitor mode on. + */ + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + ireq.u.mode = IW_MODE_MONITOR; + if (ioctl(sock_fd, SIOCSIWMODE, &ireq) == -1) { + /* + * Scientist, you've failed. + * Bring the interface back up if we shut it down. + */ + ifr.ifr_flags = oldflags; + if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't set flags: %s", device, strerror(errno)); + return PCAP_ERROR; + } + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* + * XXX - airmon-ng does "iwconfig {if} key off" after setting + * monitor mode and setting the channel, and then does + * "iwconfig up". + */ + + /* + * Now select the appropriate radio header. + */ + switch (montype) { + + case MONITOR_WEXT: + /* + * We don't have any private ioctl to set the header. + */ + break; + + case MONITOR_HOSTAP: + /* + * Try to select the radiotap header. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + args[0] = 3; /* request radiotap header */ + memcpy(ireq.u.name, args, sizeof (int)); + if (ioctl(sock_fd, cmd, &ireq) != -1) + break; /* success */ + + /* + * That failed. Try to select the AVS header. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + args[0] = 2; /* request AVS header */ + memcpy(ireq.u.name, args, sizeof (int)); + if (ioctl(sock_fd, cmd, &ireq) != -1) + break; /* success */ + + /* + * That failed. Try to select the Prism header. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + args[0] = 1; /* request Prism header */ + memcpy(ireq.u.name, args, sizeof (int)); + ioctl(sock_fd, cmd, &ireq); + break; + + case MONITOR_PRISM: + /* + * The private ioctl failed. + */ + break; + + case MONITOR_PRISM54: + /* + * Select the Prism header. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + args[0] = 3; /* request Prism header */ + memcpy(ireq.u.name, args, sizeof (int)); + ioctl(sock_fd, cmd, &ireq); + break; + + case MONITOR_ACX100: + /* + * Get the current channel. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + if (ioctl(sock_fd, SIOCGIWFREQ, &ireq) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: SIOCGIWFREQ: %s", device, + pcap_strerror(errno)); + return PCAP_ERROR; + } + channel = ireq.u.freq.m; + + /* + * Select the Prism header, and set the channel to the + * current value. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + args[0] = 1; /* request Prism header */ + args[1] = channel; /* set channel */ + memcpy(ireq.u.name, args, 2*sizeof (int)); + ioctl(sock_fd, cmd, &ireq); + break; + + case MONITOR_RT2500: + /* + * Disallow transmission - that turns on the + * Prism header. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + args[0] = 0; /* disallow transmitting */ + memcpy(ireq.u.name, args, sizeof (int)); + ioctl(sock_fd, cmd, &ireq); + break; + + case MONITOR_RT2570: + /* + * Force the Prism header. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + args[0] = 1; /* request Prism header */ + memcpy(ireq.u.name, args, sizeof (int)); + ioctl(sock_fd, cmd, &ireq); + break; + + case MONITOR_RT73: + /* + * Force the Prism header. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + ireq.u.data.length = 1; /* 1 argument */ + ireq.u.data.pointer = "1"; + ireq.u.data.flags = 0; + ioctl(sock_fd, cmd, &ireq); + break; + + case MONITOR_RTL8XXX: + /* + * Force the Prism header. + */ + memset(&ireq, 0, sizeof ireq); + strlcpy(ireq.ifr_ifrn.ifrn_name, device, + sizeof ireq.ifr_ifrn.ifrn_name); + args[0] = 1; /* request Prism header */ + memcpy(ireq.u.name, args, sizeof (int)); + ioctl(sock_fd, cmd, &ireq); + break; + } + + /* + * Now bring the interface back up if we brought it down. + */ + if (oldflags != 0) { + ifr.ifr_flags = oldflags; + if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't set flags: %s", device, strerror(errno)); + + /* + * At least try to restore the old mode on the + * interface. + */ + if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) { + /* + * Scientist, you've failed. + */ + fprintf(stderr, + "Can't restore interface wireless mode (SIOCSIWMODE failed: %s).\n" + "Please adjust manually.\n", + strerror(errno)); + } + return PCAP_ERROR; + } + } + + /* + * Note that we have to put the old mode back when we + * close the device. + */ + handlep->must_do_on_close |= MUST_CLEAR_RFMON; + + /* + * Add this to the list of pcaps to close when we exit. + */ + pcap_add_to_pcaps_to_close(handle); + + return 1; +} +#endif /* IW_MODE_MONITOR */ + +/* + * Try various mechanisms to enter monitor mode. + */ +static int +enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device) +{ +#if defined(HAVE_LIBNL) || defined(IW_MODE_MONITOR) + int ret; +#endif + +#ifdef HAVE_LIBNL + ret = enter_rfmon_mode_mac80211(handle, sock_fd, device); + if (ret < 0) + return ret; /* error attempting to do so */ + if (ret == 1) + return 1; /* success */ +#endif /* HAVE_LIBNL */ + +#ifdef IW_MODE_MONITOR + ret = enter_rfmon_mode_wext(handle, sock_fd, device); + if (ret < 0) + return ret; /* error attempting to do so */ + if (ret == 1) + return 1; /* success */ +#endif /* IW_MODE_MONITOR */ + + /* + * Either none of the mechanisms we know about work or none + * of those mechanisms are available, so we can't do monitor + * mode. + */ + return 0; +} + +#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) +/* + * Map SOF_TIMESTAMPING_ values to PCAP_TSTAMP_ values. + */ +static const struct { + int soft_timestamping_val; + int pcap_tstamp_val; +} sof_ts_type_map[3] = { + { SOF_TIMESTAMPING_SOFTWARE, PCAP_TSTAMP_HOST }, + { SOF_TIMESTAMPING_SYS_HARDWARE, PCAP_TSTAMP_ADAPTER }, + { SOF_TIMESTAMPING_RAW_HARDWARE, PCAP_TSTAMP_ADAPTER_UNSYNCED } +}; +#define NUM_SOF_TIMESTAMPING_TYPES (sizeof sof_ts_type_map / sizeof sof_ts_type_map[0]) + +static void +iface_set_default_ts_types(pcap_t *handle) +{ + int i; + + handle->tstamp_type_count = NUM_SOF_TIMESTAMPING_TYPES; + handle->tstamp_type_list = malloc(NUM_SOF_TIMESTAMPING_TYPES * sizeof(u_int)); + for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) + handle->tstamp_type_list[i] = sof_ts_type_map[i].pcap_tstamp_val; +} + +#ifdef ETHTOOL_GET_TS_INFO +/* + * Get a list of time stamping capabilities. + */ +static int +iface_ethtool_get_ts_info(pcap_t *handle, char *ebuf) +{ + int fd; + struct ifreq ifr; + struct ethtool_ts_info info; + int num_ts_types; + int i, j; + + /* + * This doesn't apply to the "any" device; you have to ask + * specific devices for their capabilities, so just default + * to saying we support all of them. + */ + if (strcmp(handle->opt.source, "any") == 0) { + iface_set_default_ts_types(handle); + return 0; + } + + /* + * Create a socket from which to fetch time stamping capabilities. + */ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, + "socket for SIOCETHTOOL(ETHTOOL_GET_TS_INFO): %s", pcap_strerror(errno)); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name)); + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GET_TS_INFO; + ifr.ifr_data = (caddr_t)&info; + if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) { + close(fd); + if (errno == EOPNOTSUPP || errno == EINVAL) { + /* + * OK, let's just return all the possible time + * stamping types. + */ + iface_set_default_ts_types(handle); + return 0; + } + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "%s: SIOCETHTOOL(ETHTOOL_GET_TS_INFO) ioctl failed: %s", handle->opt.source, + strerror(errno)); + return -1; + } + close(fd); + + num_ts_types = 0; + for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) { + if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) + num_ts_types++; + } + handle->tstamp_type_count = num_ts_types; + if (num_ts_types != 0) { + handle->tstamp_type_list = malloc(num_ts_types * sizeof(u_int)); + for (i = 0, j = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) { + if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) { + handle->tstamp_type_list[j] = sof_ts_type_map[i].pcap_tstamp_val; + j++; + } + } + } else + handle->tstamp_type_list = NULL; + + return 0; +} +#else /* ETHTOOL_GET_TS_INFO */ +static int +iface_ethtool_get_ts_info(pcap_t *handle, char *ebuf _U_) +{ + /* + * We don't have an ioctl to use to ask what's supported, + * so say we support everything. + */ + iface_set_default_ts_types(handle); + return 0; +} +#endif /* ETHTOOL_GET_TS_INFO */ + +#endif /* defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) */ + +#ifdef HAVE_PACKET_RING +/* + * Find out if we have any form of fragmentation/reassembly offloading. + * + * We do so using SIOCETHTOOL checking for various types of offloading; + * if SIOCETHTOOL isn't defined, or we don't have any #defines for any + * of the types of offloading, there's nothing we can do to check, so + * we just say "no, we don't". + */ +#if defined(SIOCETHTOOL) && (defined(ETHTOOL_GTSO) || defined(ETHTOOL_GUFO) || defined(ETHTOOL_GGSO) || defined(ETHTOOL_GFLAGS) || defined(ETHTOOL_GGRO)) +static int +iface_ethtool_flag_ioctl(pcap_t *handle, int cmd, const char *cmdname) +{ + struct ifreq ifr; + struct ethtool_value eval; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name)); + eval.cmd = cmd; + eval.data = 0; + ifr.ifr_data = (caddr_t)&eval; + if (ioctl(handle->fd, SIOCETHTOOL, &ifr) == -1) { + if (errno == EOPNOTSUPP || errno == EINVAL) { + /* + * OK, let's just return 0, which, in our + * case, either means "no, what we're asking + * about is not enabled" or "all the flags + * are clear (i.e., nothing is enabled)". + */ + return 0; + } + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: SIOCETHTOOL(%s) ioctl failed: %s", handle->opt.source, + cmdname, strerror(errno)); + return -1; + } + return eval.data; +} + +static int +iface_get_offload(pcap_t *handle) +{ + int ret; + +#ifdef ETHTOOL_GTSO + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GTSO, "ETHTOOL_GTSO"); + if (ret == -1) + return -1; + if (ret) + return 1; /* TCP segmentation offloading on */ +#endif + +#ifdef ETHTOOL_GUFO + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GUFO, "ETHTOOL_GUFO"); + if (ret == -1) + return -1; + if (ret) + return 1; /* UDP fragmentation offloading on */ +#endif + +#ifdef ETHTOOL_GGSO + /* + * XXX - will this cause large unsegmented packets to be + * handed to PF_PACKET sockets on transmission? If not, + * this need not be checked. + */ + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGSO, "ETHTOOL_GGSO"); + if (ret == -1) + return -1; + if (ret) + return 1; /* generic segmentation offloading on */ +#endif + +#ifdef ETHTOOL_GFLAGS + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS"); + if (ret == -1) + return -1; + if (ret & ETH_FLAG_LRO) + return 1; /* large receive offloading on */ +#endif + +#ifdef ETHTOOL_GGRO + /* + * XXX - will this cause large reassembled packets to be + * handed to PF_PACKET sockets on receipt? If not, + * this need not be checked. + */ + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGRO, "ETHTOOL_GGRO"); + if (ret == -1) + return -1; + if (ret) + return 1; /* generic (large) receive offloading on */ +#endif + + return 0; +} +#else /* SIOCETHTOOL */ +static int +iface_get_offload(pcap_t *handle _U_) +{ + /* + * XXX - do we need to get this information if we don't + * have the ethtool ioctls? If so, how do we do that? + */ + return 0; +} +#endif /* SIOCETHTOOL */ + +#endif /* HAVE_PACKET_RING */ + +#endif /* HAVE_PF_PACKET_SOCKETS */ + +/* ===== Functions to interface to the older kernels ================== */ + +/* + * Try to open a packet socket using the old kernel interface. + * Returns 1 on success and a PCAP_ERROR_ value on an error. + */ +static int +activate_old(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + int arptype; + struct ifreq ifr; + const char *device = handle->opt.source; + struct utsname utsname; + int mtu; + + /* Open the socket */ + + handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); + if (handle->fd == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + if (errno == EPERM || errno == EACCES) { + /* + * You don't have permission to open the + * socket. + */ + return PCAP_ERROR_PERM_DENIED; + } else { + /* + * Other error. + */ + return PCAP_ERROR; + } + } + + /* It worked - we are using the old interface */ + handlep->sock_packet = 1; + + /* ...which means we get the link-layer header. */ + handlep->cooked = 0; + + /* Bind to the given device */ + + if (strcmp(device, "any") == 0) { + strlcpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems", + PCAP_ERRBUF_SIZE); + return PCAP_ERROR; + } + if (iface_bind_old(handle->fd, device, handle->errbuf) == -1) + return PCAP_ERROR; + + /* + * Try to get the link-layer type. + */ + arptype = iface_get_arptype(handle->fd, device, handle->errbuf); + if (arptype < 0) + return PCAP_ERROR; + + /* + * Try to find the DLT_ type corresponding to that + * link-layer type. + */ + map_arphrd_to_dlt(handle, handle->fd, arptype, device, 0); + if (handle->linktype == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "unknown arptype %d", arptype); + return PCAP_ERROR; + } + + /* Go to promisc mode if requested */ + + if (handle->opt.promisc) { + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFFLAGS: %s", pcap_strerror(errno)); + return PCAP_ERROR; + } + if ((ifr.ifr_flags & IFF_PROMISC) == 0) { + /* + * Promiscuous mode isn't currently on, + * so turn it on, and remember that + * we should turn it off when the + * pcap_t is closed. + */ + + /* + * If we haven't already done so, arrange + * to have "pcap_close_all()" called when + * we exit. + */ + if (!pcap_do_addexit(handle)) { + /* + * "atexit()" failed; don't put + * the interface in promiscuous + * mode, just give up. + */ + return PCAP_ERROR; + } + + ifr.ifr_flags |= IFF_PROMISC; + if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "SIOCSIFFLAGS: %s", + pcap_strerror(errno)); + return PCAP_ERROR; + } + handlep->must_do_on_close |= MUST_CLEAR_PROMISC; + + /* + * Add this to the list of pcaps + * to close when we exit. + */ + pcap_add_to_pcaps_to_close(handle); + } + } + + /* + * Compute the buffer size. + * + * We're using SOCK_PACKET, so this might be a 2.0[.x] + * kernel, and might require special handling - check. + */ + if (uname(&utsname) < 0 || + strncmp(utsname.release, "2.0", 3) == 0) { + /* + * Either we couldn't find out what kernel release + * this is, or it's a 2.0[.x] kernel. + * + * In the 2.0[.x] kernel, a "recvfrom()" on + * a SOCK_PACKET socket, with MSG_TRUNC set, will + * return the number of bytes read, so if we pass + * a length based on the snapshot length, it'll + * return the number of bytes from the packet + * copied to userland, not the actual length + * of the packet. + * + * This means that, for example, the IP dissector + * in tcpdump will get handed a packet length less + * than the length in the IP header, and will + * complain about "truncated-ip". + * + * So we don't bother trying to copy from the + * kernel only the bytes in which we're interested, + * but instead copy them all, just as the older + * versions of libpcap for Linux did. + * + * The buffer therefore needs to be big enough to + * hold the largest packet we can get from this + * device. Unfortunately, we can't get the MRU + * of the network; we can only get the MTU. The + * MTU may be too small, in which case a packet larger + * than the buffer size will be truncated *and* we + * won't get the actual packet size. + * + * However, if the snapshot length is larger than + * the buffer size based on the MTU, we use the + * snapshot length as the buffer size, instead; + * this means that with a sufficiently large snapshot + * length we won't artificially truncate packets + * to the MTU-based size. + * + * This mess just one of many problems with packet + * capture on 2.0[.x] kernels; you really want a + * 2.2[.x] or later kernel if you want packet capture + * to work well. + */ + mtu = iface_get_mtu(handle->fd, device, handle->errbuf); + if (mtu == -1) + return PCAP_ERROR; + handle->bufsize = MAX_LINKHEADER_SIZE + mtu; + if (handle->bufsize < handle->snapshot) + handle->bufsize = handle->snapshot; + } else { + /* + * This is a 2.2[.x] or later kernel. + * + * We can safely pass "recvfrom()" a byte count + * based on the snapshot length. + */ + handle->bufsize = handle->snapshot; + } + + /* + * Default value for offset to align link-layer payload + * on a 4-byte boundary. + */ + handle->offset = 0; + + /* + * SOCK_PACKET sockets don't supply information from + * stripped VLAN tags. + */ + handlep->vlan_offset = -1; /* unknown */ + + return 1; +} + +/* + * Bind the socket associated with FD to the given device using the + * interface of the old kernels. + */ +static int +iface_bind_old(int fd, const char *device, char *ebuf) +{ + struct sockaddr saddr; + int err; + socklen_t errlen = sizeof(err); + + memset(&saddr, 0, sizeof(saddr)); + strlcpy(saddr.sa_data, device, sizeof(saddr.sa_data)); + if (bind(fd, &saddr, sizeof(saddr)) == -1) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "bind: %s", pcap_strerror(errno)); + return -1; + } + + /* Any pending errors, e.g., network is down? */ + + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "getsockopt: %s", pcap_strerror(errno)); + return -1; + } + + if (err > 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "bind: %s", pcap_strerror(err)); + return -1; + } + + return 0; +} + + +/* ===== System calls available on all supported kernels ============== */ + +/* + * Query the kernel for the MTU of the given interface. + */ +static int +iface_get_mtu(int fd, const char *device, char *ebuf) +{ + struct ifreq ifr; + + if (!device) + return BIGGER_THAN_ALL_MTUS; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "SIOCGIFMTU: %s", pcap_strerror(errno)); + return -1; + } + + return ifr.ifr_mtu; +} + +/* + * Get the hardware type of the given interface as ARPHRD_xxx constant. + */ +static int +iface_get_arptype(int fd, const char *device, char *ebuf) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "SIOCGIFHWADDR: %s", pcap_strerror(errno)); + if (errno == ENODEV) { + /* + * No such device. + */ + return PCAP_ERROR_NO_SUCH_DEVICE; + } + return PCAP_ERROR; + } + + return ifr.ifr_hwaddr.sa_family; +} + +#ifdef SO_ATTACH_FILTER +static int +fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mmapped) +{ + struct pcap_linux *handlep = handle->priv; + size_t prog_size; + register int i; + register struct bpf_insn *p; + struct bpf_insn *f; + int len; + + /* + * Make a copy of the filter, and modify that copy if + * necessary. + */ + prog_size = sizeof(*handle->fcode.bf_insns) * handle->fcode.bf_len; + len = handle->fcode.bf_len; + f = (struct bpf_insn *)malloc(prog_size); + if (f == NULL) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return -1; + } + memcpy(f, handle->fcode.bf_insns, prog_size); + fcode->len = len; + fcode->filter = (struct sock_filter *) f; + + for (i = 0; i < len; ++i) { + p = &f[i]; + /* + * What type of instruction is this? + */ + switch (BPF_CLASS(p->code)) { + + case BPF_RET: + /* + * It's a return instruction; are we capturing + * in memory-mapped mode? + */ + if (!is_mmapped) { + /* + * No; is the snapshot length a constant, + * rather than the contents of the + * accumulator? + */ + if (BPF_MODE(p->code) == BPF_K) { + /* + * Yes - if the value to be returned, + * i.e. the snapshot length, is + * anything other than 0, make it + * MAXIMUM_SNAPLEN, so that the packet + * is truncated by "recvfrom()", + * not by the filter. + * + * XXX - there's nothing we can + * easily do if it's getting the + * value from the accumulator; we'd + * have to insert code to force + * non-zero values to be + * MAXIMUM_SNAPLEN. + */ + if (p->k != 0) + p->k = MAXIMUM_SNAPLEN; + } + } + break; + + case BPF_LD: + case BPF_LDX: + /* + * It's a load instruction; is it loading + * from the packet? + */ + switch (BPF_MODE(p->code)) { + + case BPF_ABS: + case BPF_IND: + case BPF_MSH: + /* + * Yes; are we in cooked mode? + */ + if (handlep->cooked) { + /* + * Yes, so we need to fix this + * instruction. + */ + if (fix_offset(p) < 0) { + /* + * We failed to do so. + * Return 0, so our caller + * knows to punt to userland. + */ + return 0; + } + } + break; + } + break; + } + } + return 1; /* we succeeded */ +} + +static int +fix_offset(struct bpf_insn *p) +{ + /* + * What's the offset? + */ + if (p->k >= SLL_HDR_LEN) { + /* + * It's within the link-layer payload; that starts at an + * offset of 0, as far as the kernel packet filter is + * concerned, so subtract the length of the link-layer + * header. + */ + p->k -= SLL_HDR_LEN; + } else if (p->k == 0) { + /* + * It's the packet type field; map it to the special magic + * kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PKTTYPE; + } else if (p->k == 14) { + /* + * It's the protocol field; map it to the special magic + * kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PROTOCOL; + } else if ((bpf_int32)(p->k) > 0) { + /* + * It's within the header, but it's not one of those + * fields; we can't do that in the kernel, so punt + * to userland. + */ + return -1; + } + return 0; +} + +static int +set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode) +{ + int total_filter_on = 0; + int save_mode; + int ret; + int save_errno; + + /* + * The socket filter code doesn't discard all packets queued + * up on the socket when the filter is changed; this means + * that packets that don't match the new filter may show up + * after the new filter is put onto the socket, if those + * packets haven't yet been read. + * + * This means, for example, that if you do a tcpdump capture + * with a filter, the first few packets in the capture might + * be packets that wouldn't have passed the filter. + * + * We therefore discard all packets queued up on the socket + * when setting a kernel filter. (This isn't an issue for + * userland filters, as the userland filtering is done after + * packets are queued up.) + * + * To flush those packets, we put the socket in read-only mode, + * and read packets from the socket until there are no more to + * read. + * + * In order to keep that from being an infinite loop - i.e., + * to keep more packets from arriving while we're draining + * the queue - we put the "total filter", which is a filter + * that rejects all packets, onto the socket before draining + * the queue. + * + * This code deliberately ignores any errors, so that you may + * get bogus packets if an error occurs, rather than having + * the filtering done in userland even if it could have been + * done in the kernel. + */ + if (setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER, + &total_fcode, sizeof(total_fcode)) == 0) { + char drain[1]; + + /* + * Note that we've put the total filter onto the socket. + */ + total_filter_on = 1; + + /* + * Save the socket's current mode, and put it in + * non-blocking mode; we drain it by reading packets + * until we get an error (which is normally a + * "nothing more to be read" error). + */ + save_mode = fcntl(handle->fd, F_GETFL, 0); + if (save_mode == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't get FD flags when changing filter: %s", + pcap_strerror(errno)); + return -2; + } + if (fcntl(handle->fd, F_SETFL, save_mode | O_NONBLOCK) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't set nonblocking mode when changing filter: %s", + pcap_strerror(errno)); + return -2; + } + while (recv(handle->fd, &drain, sizeof drain, MSG_TRUNC) >= 0) + ; + save_errno = errno; + if (save_errno != EAGAIN) { + /* + * Fatal error. + * + * If we can't restore the mode or reset the + * kernel filter, there's nothing we can do. + */ + (void)fcntl(handle->fd, F_SETFL, save_mode); + (void)reset_kernel_filter(handle); + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "recv failed when changing filter: %s", + pcap_strerror(save_errno)); + return -2; + } + if (fcntl(handle->fd, F_SETFL, save_mode) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't restore FD flags when changing filter: %s", + pcap_strerror(save_errno)); + return -2; + } + } + + /* + * Now attach the new filter. + */ + ret = setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER, + fcode, sizeof(*fcode)); + if (ret == -1 && total_filter_on) { + /* + * Well, we couldn't set that filter on the socket, + * but we could set the total filter on the socket. + * + * This could, for example, mean that the filter was + * too big to put into the kernel, so we'll have to + * filter in userland; in any case, we'll be doing + * filtering in userland, so we need to remove the + * total filter so we see packets. + */ + save_errno = errno; + + /* + * If this fails, we're really screwed; we have the + * total filter on the socket, and it won't come off. + * Report it as a fatal error. + */ + if (reset_kernel_filter(handle) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "can't remove kernel total filter: %s", + pcap_strerror(errno)); + return -2; /* fatal error */ + } + + errno = save_errno; + } + return ret; +} + +static int +reset_kernel_filter(pcap_t *handle) +{ + /* + * setsockopt() barfs unless it get a dummy parameter. + * valgrind whines unless the value is initialized, + * as it has no idea that setsockopt() ignores its + * parameter. + */ + int dummy = 0; + + return setsockopt(handle->fd, SOL_SOCKET, SO_DETACH_FILTER, + &dummy, sizeof(dummy)); +} +#endif diff --git a/tcpdump/jni/libpcap/pcap-namedb.h b/tcpdump/jni/libpcap/pcap-namedb.h new file mode 100644 index 0000000..d5908c9 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-namedb.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/tcpdump/jni/libpcap/pcap-netfilter-linux.c b/tcpdump/jni/libpcap/pcap-netfilter-linux.c new file mode 100644 index 0000000..3ee6faa --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-netfilter-linux.c @@ -0,0 +1,655 @@ +/* + * Copyright (c) 2011 Jakub Zawadzki + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pcap-int.h" + +#ifdef NEED_STRERROR_H +#include "strerror.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* NOTE: if your program drops privilages after pcap_activate() it WON'T work with nfqueue. + * It took me quite some time to debug ;/ + * + * Sending any data to nfnetlink socket requires CAP_NET_ADMIN privilages, + * and in nfqueue we need to send verdict reply after recving packet. + * + * In tcpdump you can disable dropping privilages with -Z root + */ + +#include "pcap-netfilter-linux.h" + +#define HDR_LENGTH (NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg)))) + +#define NFLOG_IFACE "nflog" +#define NFQUEUE_IFACE "nfqueue" + +typedef enum { OTHER = -1, NFLOG, NFQUEUE } nftype_t; + +/* + * Private data for capturing on Linux netfilter sockets. + */ +struct pcap_netfilter { + u_int packets_read; /* count of packets read with recvfrom() */ +}; + +static int nfqueue_send_verdict(const pcap_t *handle, u_int16_t group_id, u_int32_t id, u_int32_t verdict); + +static int +netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + struct pcap_netfilter *handlep = handle->priv; + const unsigned char *buf; + int count = 0; + int len; + + /* ignore interrupt system call error */ + do { + len = recv(handle->fd, handle->buffer, handle->bufsize, 0); + if (handle->break_loop) { + handle->break_loop = 0; + return -2; + } + } while ((len == -1) && (errno == EINTR)); + + if (len < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", errno, pcap_strerror(errno)); + return -1; + } + + buf = handle->buffer; + while (len >= NLMSG_SPACE(0)) { + const struct nlmsghdr *nlh = (const struct nlmsghdr *) buf; + u_int32_t msg_len; + nftype_t type = OTHER; + + if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || len < nlh->nlmsg_len) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %d) (nlmsg_len: %u)", len, nlh->nlmsg_len); + return -1; + } + + if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG && + NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET) + type = NFLOG; + else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE && + NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET) + type = NFQUEUE; + + if (type != OTHER) { + const unsigned char *payload = NULL; + struct pcap_pkthdr pkth; + + const struct nfgenmsg *nfg = NULL; + int id = 0; + + if (handle->linktype != DLT_NFLOG) { + const struct nfattr *payload_attr = NULL; + + if (nlh->nlmsg_len < HDR_LENGTH) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len); + return -1; + } + + nfg = NLMSG_DATA(nlh); + if (nlh->nlmsg_len > HDR_LENGTH) { + struct nfattr *attr = NFM_NFA(nfg); + int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH); + + while (NFA_OK(attr, attr_len)) { + if (type == NFQUEUE) { + switch (NFA_TYPE(attr)) { + case NFQA_PACKET_HDR: + { + const struct nfqnl_msg_packet_hdr *pkt_hdr = (const struct nfqnl_msg_packet_hdr *) NFA_DATA(attr); + + id = ntohl(pkt_hdr->packet_id); + break; + } + case NFQA_PAYLOAD: + payload_attr = attr; + break; + } + + } else if (type == NFLOG) { + switch (NFA_TYPE(attr)) { + case NFULA_PAYLOAD: + payload_attr = attr; + break; + } + } + attr = NFA_NEXT(attr, attr_len); + } + } + + if (payload_attr) { + payload = NFA_DATA(payload_attr); + pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr); + } + + } else { + payload = NLMSG_DATA(nlh); + pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr)); + } + + if (payload) { + /* pkth.caplen = min (payload_len, handle->snapshot); */ + + gettimeofday(&pkth.ts, NULL); + if (handle->fcode.bf_insns == NULL || + bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen)) + { + handlep->packets_read++; + callback(user, &pkth, payload); + count++; + } + } + + if (type == NFQUEUE) { + /* XXX, possible responses: NF_DROP, NF_ACCEPT, NF_STOLEN, NF_QUEUE, NF_REPEAT, NF_STOP */ + /* if type == NFQUEUE, handle->linktype is always != DLT_NFLOG, + so nfg is always initialized to NLMSG_DATA(nlh). */ + if (nfg != NULL) + nfqueue_send_verdict(handle, ntohs(nfg->res_id), id, NF_ACCEPT); + } + } + + msg_len = NLMSG_ALIGN(nlh->nlmsg_len); + if (msg_len > len) + msg_len = len; + + len -= msg_len; + buf += msg_len; + } + return count; +} + +static int +netfilter_set_datalink(pcap_t *handle, int dlt) +{ + handle->linktype = dlt; + return 0; +} + +static int +netfilter_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_netfilter *handlep = handle->priv; + + stats->ps_recv = handlep->packets_read; + stats->ps_drop = 0; + stats->ps_ifdrop = 0; + return 0; +} + +static int +netfilter_inject_linux(pcap_t *handle, const void *buf, size_t size) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on netfilter devices"); + return (-1); +} + +struct my_nfattr { + u_int16_t nfa_len; + u_int16_t nfa_type; + void *data; +}; + +static int +netfilter_send_config_msg(const pcap_t *handle, u_int16_t msg_type, int ack, u_int8_t family, u_int16_t res_id, const struct my_nfattr *mynfa) +{ + char buf[1024] __attribute__ ((aligned)); + + struct nlmsghdr *nlh = (struct nlmsghdr *) buf; + struct nfgenmsg *nfg = (struct nfgenmsg *) (buf + sizeof(struct nlmsghdr)); + + struct sockaddr_nl snl; + static unsigned int seq_id; + + if (!seq_id) + seq_id = time(NULL); + ++seq_id; + + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg)); + nlh->nlmsg_type = msg_type; + nlh->nlmsg_flags = NLM_F_REQUEST | (ack ? NLM_F_ACK : 0); + nlh->nlmsg_pid = 0; /* to kernel */ + nlh->nlmsg_seq = seq_id; + + nfg->nfgen_family = family; + nfg->version = NFNETLINK_V0; + nfg->res_id = htons(res_id); + + if (mynfa) { + struct nfattr *nfa = (struct nfattr *) (buf + NLMSG_ALIGN(nlh->nlmsg_len)); + + nfa->nfa_type = mynfa->nfa_type; + nfa->nfa_len = NFA_LENGTH(mynfa->nfa_len); + memcpy(NFA_DATA(nfa), mynfa->data, mynfa->nfa_len); + nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + NFA_ALIGN(nfa->nfa_len); + } + + memset(&snl, 0, sizeof(snl)); + snl.nl_family = AF_NETLINK; + + if (sendto(handle->fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *) &snl, sizeof(snl)) == -1) + return -1; + + if (!ack) + return 0; + + /* waiting for reply loop */ + do { + socklen_t addrlen = sizeof(snl); + int len; + + /* ignore interrupt system call error */ + do { + len = recvfrom(handle->fd, buf, sizeof(buf), 0, (struct sockaddr *) &snl, &addrlen); + } while ((len == -1) && (errno == EINTR)); + + if (len <= 0) + return len; + + if (addrlen != sizeof(snl) || snl.nl_family != AF_NETLINK) { + errno = EINVAL; + return -1; + } + + nlh = (struct nlmsghdr *) buf; + if (snl.nl_pid != 0 || seq_id != nlh->nlmsg_seq) /* if not from kernel or wrong sequence skip */ + continue; + + while (len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, len)) { + if (nlh->nlmsg_type == NLMSG_ERROR || (nlh->nlmsg_type == NLMSG_DONE && nlh->nlmsg_flags & NLM_F_MULTI)) { + if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) { + errno = EBADMSG; + return -1; + } + errno = -(*((int *)NLMSG_DATA(nlh))); + return (errno == 0) ? 0 : -1; + } + nlh = NLMSG_NEXT(nlh, len); + } + } while (1); + + return -1; /* never here */ +} + +static int +nflog_send_config_msg(const pcap_t *handle, u_int8_t family, u_int16_t group_id, const struct my_nfattr *mynfa) +{ + return netfilter_send_config_msg(handle, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG, 1, family, group_id, mynfa); +} + +static int +nflog_send_config_cmd(const pcap_t *handle, u_int16_t group_id, u_int8_t cmd, u_int8_t family) +{ + struct nfulnl_msg_config_cmd msg; + struct my_nfattr nfa; + + msg.command = cmd; + + nfa.data = &msg; + nfa.nfa_type = NFULA_CFG_CMD; + nfa.nfa_len = sizeof(msg); + + return nflog_send_config_msg(handle, family, group_id, &nfa); +} + +static int +nflog_send_config_mode(const pcap_t *handle, u_int16_t group_id, u_int8_t copy_mode, u_int32_t copy_range) +{ + struct nfulnl_msg_config_mode msg; + struct my_nfattr nfa; + + msg.copy_range = htonl(copy_range); + msg.copy_mode = copy_mode; + + nfa.data = &msg; + nfa.nfa_type = NFULA_CFG_MODE; + nfa.nfa_len = sizeof(msg); + + return nflog_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); +} + +static int +nfqueue_send_verdict(const pcap_t *handle, u_int16_t group_id, u_int32_t id, u_int32_t verdict) +{ + struct nfqnl_msg_verdict_hdr msg; + struct my_nfattr nfa; + + msg.id = htonl(id); + msg.verdict = htonl(verdict); + + nfa.data = &msg; + nfa.nfa_type = NFQA_VERDICT_HDR; + nfa.nfa_len = sizeof(msg); + + return netfilter_send_config_msg(handle, (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT, 0, AF_UNSPEC, group_id, &nfa); +} + +static int +nfqueue_send_config_msg(const pcap_t *handle, u_int8_t family, u_int16_t group_id, const struct my_nfattr *mynfa) +{ + return netfilter_send_config_msg(handle, (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG, 1, family, group_id, mynfa); +} + +static int +nfqueue_send_config_cmd(const pcap_t *handle, u_int16_t group_id, u_int8_t cmd, u_int16_t pf) +{ + struct nfqnl_msg_config_cmd msg; + struct my_nfattr nfa; + + msg.command = cmd; + msg.pf = htons(pf); + + nfa.data = &msg; + nfa.nfa_type = NFQA_CFG_CMD; + nfa.nfa_len = sizeof(msg); + + return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); +} + +static int +nfqueue_send_config_mode(const pcap_t *handle, u_int16_t group_id, u_int8_t copy_mode, u_int32_t copy_range) +{ + struct nfqnl_msg_config_params msg; + struct my_nfattr nfa; + + msg.copy_range = htonl(copy_range); + msg.copy_mode = copy_mode; + + nfa.data = &msg; + nfa.nfa_type = NFQA_CFG_PARAMS; + nfa.nfa_len = sizeof(msg); + + return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); +} + +static int +netfilter_activate(pcap_t* handle) +{ + const char *dev = handle->opt.source; + unsigned short groups[32]; + int group_count = 0; + nftype_t type = OTHER; + int i; + + if (strncmp(dev, NFLOG_IFACE, strlen(NFLOG_IFACE)) == 0) { + dev += strlen(NFLOG_IFACE); + type = NFLOG; + + } else if (strncmp(dev, NFQUEUE_IFACE, strlen(NFQUEUE_IFACE)) == 0) { + dev += strlen(NFQUEUE_IFACE); + type = NFQUEUE; + } + + if (type != OTHER && *dev == ':') { + dev++; + while (*dev) { + long int group_id; + char *end_dev; + + if (group_count == 32) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Maximum 32 netfilter groups! dev: %s", + handle->opt.source); + return PCAP_ERROR; + } + + group_id = strtol(dev, &end_dev, 0); + if (end_dev != dev) { + if (group_id < 0 || group_id > 65535) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Netfilter group range from 0 to 65535 (got %ld)", + group_id); + return PCAP_ERROR; + } + + groups[group_count++] = (unsigned short) group_id; + dev = end_dev; + } + if (*dev != ',') + break; + dev++; + } + } + + if (type == OTHER || *dev) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't get netfilter group(s) index from %s", + handle->opt.source); + return PCAP_ERROR; + } + + /* if no groups, add default: 0 */ + if (!group_count) { + groups[0] = 0; + group_count = 1; + } + + /* Initialize some components of the pcap structure. */ + handle->bufsize = 128 + handle->snapshot; + handle->offset = 0; + handle->read_op = netfilter_read_linux; + handle->inject_op = netfilter_inject_linux; + handle->setfilter_op = install_bpf_program; /* no kernel filtering */ + handle->setdirection_op = NULL; + handle->set_datalink_op = netfilter_set_datalink; + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->stats_op = netfilter_stats_linux; + + /* Create netlink socket */ + handle->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); + if (handle->fd < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s", errno, pcap_strerror(errno)); + return PCAP_ERROR; + } + + if (type == NFLOG) { + handle->linktype = DLT_NFLOG; + handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (handle->dlt_list != NULL) { + handle->dlt_list[0] = DLT_NFLOG; + handle->dlt_list[1] = DLT_IPV4; + handle->dlt_count = 2; + } + + } else + handle->linktype = DLT_IPV4; + + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", pcap_strerror(errno)); + goto close_fail; + } + + if (type == NFLOG) { + if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_CFG_CMD_PF_UNBIND: %s", pcap_strerror(errno)); + goto close_fail; + } + + if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_BIND, AF_INET) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_CFG_CMD_PF_BIND: %s", pcap_strerror(errno)); + goto close_fail; + } + + /* Bind socket to the nflog groups */ + for (i = 0; i < group_count; i++) { + if (nflog_send_config_cmd(handle, groups[i], NFULNL_CFG_CMD_BIND, AF_UNSPEC) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't listen on group group index: %s", pcap_strerror(errno)); + goto close_fail; + } + + if (nflog_send_config_mode(handle, groups[i], NFULNL_COPY_PACKET, handle->snapshot) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_COPY_PACKET: %s", pcap_strerror(errno)); + goto close_fail; + } + } + + } else { + if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_CFG_CMD_PF_UNBIND: %s", pcap_strerror(errno)); + goto close_fail; + } + + if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_BIND, AF_INET) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_CFG_CMD_PF_BIND: %s", pcap_strerror(errno)); + goto close_fail; + } + + /* Bind socket to the nfqueue groups */ + for (i = 0; i < group_count; i++) { + if (nfqueue_send_config_cmd(handle, groups[i], NFQNL_CFG_CMD_BIND, AF_UNSPEC) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't listen on group group index: %s", pcap_strerror(errno)); + goto close_fail; + } + + if (nfqueue_send_config_mode(handle, groups[i], NFQNL_COPY_PACKET, handle->snapshot) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_COPY_PACKET: %s", pcap_strerror(errno)); + goto close_fail; + } + } + } + + if (handle->opt.rfmon) { + /* + * Monitor mode doesn't apply to netfilter devices. + */ + pcap_cleanup_live_common(handle); + return PCAP_ERROR_RFMON_NOTSUP; + } + + if (handle->opt.buffer_size != 0) { + /* + * Set the socket buffer size to the specified value. + */ + if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, &handle->opt.buffer_size, sizeof(handle->opt.buffer_size)) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SO_RCVBUF: %s", pcap_strerror(errno)); + goto close_fail; + } + } + + handle->selectable_fd = handle->fd; + return 0; + +close_fail: + pcap_cleanup_live_common(handle); + return PCAP_ERROR; +} + +pcap_t * +netfilter_create(const char *device, char *ebuf, int *is_ours) +{ + const char *cp; + pcap_t *p; + + /* Does this look like an netfilter device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + + /* Does it begin with NFLOG_IFACE or NFQUEUE_IFACE? */ + if (strncmp(cp, NFLOG_IFACE, sizeof NFLOG_IFACE - 1) == 0) + cp += sizeof NFLOG_IFACE - 1; + else if (strncmp(cp, NFQUEUE_IFACE, sizeof NFQUEUE_IFACE - 1) == 0) + cp += sizeof NFQUEUE_IFACE - 1; + else { + /* Nope, doesn't begin with NFLOG_IFACE nor NFQUEUE_IFACE */ + *is_ours = 0; + return NULL; + } + + /* + * Yes - is that either the end of the name, or is it followed + * by a colon? + */ + if (*cp != ':' && *cp != '\0') { + /* Nope */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_netfilter)); + if (p == NULL) + return (NULL); + + p->activate_op = netfilter_activate; + return (p); +} + +int +netfilter_findalldevs(pcap_if_t **alldevsp, char *err_str) +{ + int sock; + + sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); + if (sock < 0) { + /* if netlink is not supported this is not fatal */ + if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) + return 0; + snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't open netlink socket %d:%s", + errno, pcap_strerror(errno)); + return -1; + } + close(sock); + + if (pcap_add_if(alldevsp, NFLOG_IFACE, 0, "Linux netfilter log (NFLOG) interface", err_str) < 0) + return -1; + if (pcap_add_if(alldevsp, NFQUEUE_IFACE, 0, "Linux netfilter queue (NFQUEUE) interface", err_str) < 0) + return -1; + return 0; +} diff --git a/tcpdump/jni/libpcap/pcap-netfilter-linux.h b/tcpdump/jni/libpcap/pcap-netfilter-linux.h new file mode 100644 index 0000000..01d9b39 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-netfilter-linux.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Jakub Zawadzki + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Prototypes for netlink-related functions + */ +int netfilter_findalldevs(pcap_if_t **alldevsp, char *err_str); +pcap_t *netfilter_create(const char *device, char *ebuf, int *is_ours); diff --git a/tcpdump/jni/libpcap/pcap-nit.c b/tcpdump/jni/libpcap/pcap-nit.c new file mode 100644 index 0000000..a8355f9 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-nit.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * The chunk size for NIT. This is the amount of buffering + * done for read calls. + */ +#define CHUNKSIZE (2*1024) + +/* + * The total buffer space used by NIT. + */ +#define BUFSPACE (4*CHUNKSIZE) + +/* Forwards */ +static int nit_setflags(int, int, int, char *); + +/* + * Private data for capturing on NIT devices. + */ +struct pcap_nit { + struct pcap_stat stat; +}; + +static int +pcap_stats_nit(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_nit *pn = p->priv; + + /* + * "ps_recv" counts packets handed to the filter, not packets + * that passed the filter. As filtering is done in userland, + * this does not include packets dropped because we ran out + * of buffer space. + * + * "ps_drop" presumably counts packets dropped by the socket + * because of flow control requirements or resource exhaustion; + * it doesn't count packets dropped by the interface driver. + * As filtering is done in userland, it counts packets regardless + * of whether they would've passed the filter. + * + * These statistics don't include packets not yet read from the + * kernel by libpcap or packets not yet read from libpcap by the + * application. + */ + *ps = pn->stat; + return (0); +} + +static int +pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_nit *pn = p->priv; + register int cc, n; + register u_char *bp, *cp, *ep; + register struct nit_hdr *nh; + register int caplen; + + cc = p->cc; + if (cc == 0) { + cc = read(p->fd, (char *)p->buffer, p->bufsize); + if (cc < 0) { + if (errno == EWOULDBLOCK) + return (0); + snprintf(p->errbuf, sizeof(p->errbuf), "pcap_read: %s", + pcap_strerror(errno)); + return (-1); + } + bp = p->buffer; + } else + bp = p->bp; + + /* + * Loop through each packet. The increment expression + * rounds up to the next int boundary past the end of + * the previous packet. + */ + n = 0; + ep = bp + cc; + while (bp < ep) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->cc = ep - bp; + p->bp = bp; + return (n); + } + } + + nh = (struct nit_hdr *)bp; + cp = bp + sizeof(*nh); + + switch (nh->nh_state) { + + case NIT_CATCH: + break; + + case NIT_NOMBUF: + case NIT_NOCLUSTER: + case NIT_NOSPACE: + pn->stat.ps_drop = nh->nh_dropped; + continue; + + case NIT_SEQNO: + continue; + + default: + snprintf(p->errbuf, sizeof(p->errbuf), + "bad nit state %d", nh->nh_state); + return (-1); + } + ++pn->stat.ps_recv; + bp += ((sizeof(struct nit_hdr) + nh->nh_datalen + + sizeof(int) - 1) & ~(sizeof(int) - 1)); + + caplen = nh->nh_wirelen; + if (caplen > p->snapshot) + caplen = p->snapshot; + if (bpf_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) { + struct pcap_pkthdr h; + h.ts = nh->nh_timestamp; + h.len = nh->nh_wirelen; + h.caplen = caplen; + (*callback)(user, &h, cp); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + p->cc = ep - bp; + p->bp = bp; + return (n); + } + } + } + p->cc = 0; + return (n); +} + +static int +pcap_inject_nit(pcap_t *p, const void *buf, size_t size) +{ + struct sockaddr sa; + int ret; + + memset(&sa, 0, sizeof(sa)); + strncpy(sa.sa_data, device, sizeof(sa.sa_data)); + ret = sendto(p->fd, buf, size, 0, &sa, sizeof(sa)); + if (ret == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", + pcap_strerror(errno)); + return (-1); + } + return (ret); +} + +static int +nit_setflags(pcap_t *p) +{ + struct nit_ioc nioc; + + memset(&nioc, 0, sizeof(nioc)); + nioc.nioc_typetomatch = NT_ALLTYPES; + nioc.nioc_snaplen = p->snapshot; + nioc.nioc_bufalign = sizeof(int); + nioc.nioc_bufoffset = 0; + + if (p->opt.buffer_size != 0) + nioc.nioc_bufspace = p->opt.buffer_size; + else { + /* Default buffer size */ + nioc.nioc_bufspace = BUFSPACE; + } + + if (p->opt.immediate) { + /* + * XXX - will this cause packets to be delivered immediately? + * XXX - given that this is for SunOS prior to 4.0, do + * we care? + */ + nioc.nioc_chunksize = 0; + } else + nioc.nioc_chunksize = CHUNKSIZE; + if (p->opt.timeout != 0) { + nioc.nioc_flags |= NF_TIMEOUT; + nioc.nioc_timeout.tv_sec = p->opt.timeout / 1000; + nioc.nioc_timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; + } + if (p->opt.promisc) + nioc.nioc_flags |= NF_PROMISC; + + if (ioctl(p->fd, SIOCSNIT, &nioc) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNIT: %s", + pcap_strerror(errno)); + return (-1); + } + return (0); +} + +static int +pcap_activate_nit(pcap_t *p) +{ + int fd; + struct sockaddr_nit snit; + + if (p->opt.rfmon) { + /* + * No monitor mode on SunOS 3.x or earlier (no + * Wi-Fi *devices* for the hardware that supported + * them!). + */ + return (PCAP_ERROR_RFMON_NOTSUP); + } + + if (p->snapshot < 96) + /* + * NIT requires a snapshot length of at least 96. + */ + p->snapshot = 96; + + memset(p, 0, sizeof(*p)); + p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW); + if (fd < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + goto bad; + } + snit.snit_family = AF_NIT; + (void)strncpy(snit.snit_ifname, p->opt.source, NITIFSIZ); + + if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "bind: %s: %s", snit.snit_ifname, pcap_strerror(errno)); + goto bad; + } + if (nit_setflags(p) < 0) + goto bad; + + /* + * NIT supports only ethernets. + */ + p->linktype = DLT_EN10MB; + + p->bufsize = BUFSPACE; + p->buffer = (u_char *)malloc(p->bufsize); + if (p->buffer == NULL) { + strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); + goto bad; + } + + /* + * "p->fd" is a socket, so "select()" should work on it. + */ + p->selectable_fd = p->fd; + + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (p->dlt_list != NULL) { + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + } + + p->read_op = pcap_read_nit; + p->inject_op = pcap_inject_nit; + p->setfilter_op = install_bpf_program; /* no kernel filtering */ + p->setdirection_op = NULL; /* Not implemented. */ + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcap_getnonblock_fd; + p->setnonblock_op = pcap_setnonblock_fd; + p->stats_op = pcap_stats_nit; + + return (0); + bad: + pcap_cleanup_live_common(p); + return (PCAP_ERROR); +} + +pcap_t * +pcap_create_interface(const char *device, char *ebuf) +{ + pcap_t *p; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_nit)); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_nit; + return (p); +} + +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + return (0); +} diff --git a/tcpdump/jni/libpcap/pcap-null.c b/tcpdump/jni/libpcap/pcap-null.c new file mode 100644 index 0000000..934fb2c --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-null.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* optionally get BSD define */ + +#include + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#include "pcap-int.h" + +static char nosup[] = "live packet capture not supported on this system"; + +pcap_t * +pcap_create_interface(const char *device, char *ebuf) +{ + (void)strlcpy(ebuf, nosup, PCAP_ERRBUF_SIZE); + return (NULL); +} + +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + return (0); +} diff --git a/tcpdump/jni/libpcap/pcap-pf.c b/tcpdump/jni/libpcap/pcap-pf.c new file mode 100644 index 0000000..e03b2ed --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-pf.c @@ -0,0 +1,609 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * packet filter subroutines for tcpdump + * Extraction/creation by Jeffrey Mogul, DECWRL + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +struct mbuf; +struct rtentry; +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the + * native OS version, as we need various BPF ioctls from it. + */ +#define PCAP_DONT_INCLUDE_PCAP_BPF_H +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * FDDI packets are padded to make everything line up on a nice boundary. + */ +#define PCAP_FDDIPAD 3 + +/* + * Private data for capturing on Ultrix and DEC OSF/1^WDigital UNIX^W^W + * Tru64 UNIX packetfilter devices. + */ +struct pcap_pf { + int filtering_in_kernel; /* using kernel filter */ + u_long TotPkts; /* can't oflow for 79 hrs on ether */ + u_long TotAccepted; /* count accepted by filter */ + u_long TotDrops; /* count of dropped packets */ + long TotMissed; /* missed by i/f during this run */ + long OrigMissed; /* missed by i/f before this run */ +}; + +static int pcap_setfilter_pf(pcap_t *, struct bpf_program *); + +/* + * BUFSPACE is the size in bytes of the packet read buffer. Most tcpdump + * applications aren't going to need more than 200 bytes of packet header + * and the read shouldn't return more packets than packetfilter's internal + * queue limit (bounded at 256). + */ +#define BUFSPACE (200 * 256) + +static int +pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_pf *pf = pc->priv; + register u_char *p, *bp; + register int cc, n, buflen, inc; + register struct enstamp *sp; +#ifdef LBL_ALIGN + struct enstamp stamp; +#endif + register int pad; + + again: + cc = pc->cc; + if (cc == 0) { + cc = read(pc->fd, (char *)pc->buffer + pc->offset, pc->bufsize); + if (cc < 0) { + if (errno == EWOULDBLOCK) + return (0); + if (errno == EINVAL && + lseek(pc->fd, 0L, SEEK_CUR) + pc->bufsize < 0) { + /* + * Due to a kernel bug, after 2^31 bytes, + * the kernel file offset overflows and + * read fails with EINVAL. The lseek() + * to 0 will fix things. + */ + (void)lseek(pc->fd, 0L, SEEK_SET); + goto again; + } + snprintf(pc->errbuf, sizeof(pc->errbuf), "pf read: %s", + pcap_strerror(errno)); + return (-1); + } + bp = pc->buffer + pc->offset; + } else + bp = pc->bp; + /* + * Loop through each packet. + */ + n = 0; + pad = pc->fddipad; + while (cc > 0) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (pc->break_loop) { + if (n == 0) { + pc->break_loop = 0; + return (-2); + } else { + pc->cc = cc; + pc->bp = bp; + return (n); + } + } + if (cc < sizeof(*sp)) { + snprintf(pc->errbuf, sizeof(pc->errbuf), + "pf short read (%d)", cc); + return (-1); + } +#ifdef LBL_ALIGN + if ((long)bp & 3) { + sp = &stamp; + memcpy((char *)sp, (char *)bp, sizeof(*sp)); + } else +#endif + sp = (struct enstamp *)bp; + if (sp->ens_stamplen != sizeof(*sp)) { + snprintf(pc->errbuf, sizeof(pc->errbuf), + "pf short stamplen (%d)", + sp->ens_stamplen); + return (-1); + } + + p = bp + sp->ens_stamplen; + buflen = sp->ens_count; + if (buflen > pc->snapshot) + buflen = pc->snapshot; + + /* Calculate inc before possible pad update */ + inc = ENALIGN(buflen + sp->ens_stamplen); + cc -= inc; + bp += inc; + pf->TotPkts++; + pf->TotDrops += sp->ens_dropped; + pf->TotMissed = sp->ens_ifoverflows; + if (pf->OrigMissed < 0) + pf->OrigMissed = pf->TotMissed; + + /* + * Short-circuit evaluation: if using BPF filter + * in kernel, no need to do it now - we already know + * the packet passed the filter. + * + * Note: the filter code was generated assuming + * that pc->fddipad was the amount of padding + * before the header, as that's what's required + * in the kernel, so we run the filter before + * skipping that padding. + */ + if (pf->filtering_in_kernel || + bpf_filter(pc->fcode.bf_insns, p, sp->ens_count, buflen)) { + struct pcap_pkthdr h; + pf->TotAccepted++; + h.ts = sp->ens_tstamp; + h.len = sp->ens_count - pad; + p += pad; + buflen -= pad; + h.caplen = buflen; + (*callback)(user, &h, p); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + pc->cc = cc; + pc->bp = bp; + return (n); + } + } + } + pc->cc = 0; + return (n); +} + +static int +pcap_inject_pf(pcap_t *p, const void *buf, size_t size) +{ + int ret; + + ret = write(p->fd, buf, size); + if (ret == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", + pcap_strerror(errno)); + return (-1); + } + return (ret); +} + +static int +pcap_stats_pf(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_pf *pf = p->priv; + + /* + * If packet filtering is being done in the kernel: + * + * "ps_recv" counts only packets that passed the filter. + * This does not include packets dropped because we + * ran out of buffer space. (XXX - perhaps it should, + * by adding "ps_drop" to "ps_recv", for compatibility + * with some other platforms. On the other hand, on + * some platforms "ps_recv" counts only packets that + * passed the filter, and on others it counts packets + * that didn't pass the filter....) + * + * "ps_drop" counts packets that passed the kernel filter + * (if any) but were dropped because the input queue was + * full. + * + * "ps_ifdrop" counts packets dropped by the network + * inteface (regardless of whether they would have passed + * the input filter, of course). + * + * If packet filtering is not being done in the kernel: + * + * "ps_recv" counts only packets that passed the filter. + * + * "ps_drop" counts packets that were dropped because the + * input queue was full, regardless of whether they passed + * the userland filter. + * + * "ps_ifdrop" counts packets dropped by the network + * inteface (regardless of whether they would have passed + * the input filter, of course). + * + * These statistics don't include packets not yet read from + * the kernel by libpcap, but they may include packets not + * yet read from libpcap by the application. + */ + ps->ps_recv = pf->TotAccepted; + ps->ps_drop = pf->TotDrops; + ps->ps_ifdrop = pf->TotMissed - pf->OrigMissed; + return (0); +} + +/* + * We include the OS's , not our "pcap/bpf.h", so we probably + * don't get DLT_DOCSIS defined. + */ +#ifndef DLT_DOCSIS +#define DLT_DOCSIS 143 +#endif + +static int +pcap_activate_pf(pcap_t *p) +{ + struct pcap_pf *pf = p->priv; + short enmode; + int backlog = -1; /* request the most */ + struct enfilter Filter; + struct endevp devparams; + + /* + * Initially try a read/write open (to allow the inject + * method to work). If that fails due to permission + * issues, fall back to read-only. This allows a + * non-root user to be granted specific access to pcap + * capabilities via file permissions. + * + * XXX - we should have an API that has a flag that + * controls whether to open read-only or read-write, + * so that denial of permission to send (or inability + * to send, if sending packets isn't supported on + * the device in question) can be indicated at open + * time. + * + * XXX - we assume here that "pfopen()" does not, in fact, modify + * its argument, even though it takes a "char *" rather than a + * "const char *" as its first argument. That appears to be + * the case, at least on Digital UNIX 4.0. + */ + p->fd = pfopen(p->opt.source, O_RDWR); + if (p->fd == -1 && errno == EACCES) + p->fd = pfopen(p->opt.source, O_RDONLY); + if (p->fd < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "pf open: %s: %s\n\ +your system may not be properly configured; see the packetfilter(4) man page\n", + p->opt.source, pcap_strerror(errno)); + goto bad; + } + pf->OrigMissed = -1; + enmode = ENTSTAMP|ENNONEXCL; + if (!p->opt.immediate) + enmode |= ENBATCH; + if (p->opt.promisc) + enmode |= ENPROMISC; + if (ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCMBIS: %s", + pcap_strerror(errno)); + goto bad; + } +#ifdef ENCOPYALL + /* Try to set COPYALL mode so that we see packets to ourself */ + enmode = ENCOPYALL; + (void)ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode);/* OK if this fails */ +#endif + /* set the backlog */ + if (ioctl(p->fd, EIOCSETW, (caddr_t)&backlog) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSETW: %s", + pcap_strerror(errno)); + goto bad; + } + /* discover interface type */ + if (ioctl(p->fd, EIOCDEVP, (caddr_t)&devparams) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCDEVP: %s", + pcap_strerror(errno)); + goto bad; + } + /* HACK: to compile prior to Ultrix 4.2 */ +#ifndef ENDT_FDDI +#define ENDT_FDDI 4 +#endif + switch (devparams.end_dev_type) { + + case ENDT_10MB: + p->linktype = DLT_EN10MB; + p->offset = 2; + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (p->dlt_list != NULL) { + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + } + break; + + case ENDT_FDDI: + p->linktype = DLT_FDDI; + break; + +#ifdef ENDT_SLIP + case ENDT_SLIP: + p->linktype = DLT_SLIP; + break; +#endif + +#ifdef ENDT_PPP + case ENDT_PPP: + p->linktype = DLT_PPP; + break; +#endif + +#ifdef ENDT_LOOPBACK + case ENDT_LOOPBACK: + /* + * It appears to use Ethernet framing, at least on + * Digital UNIX 4.0. + */ + p->linktype = DLT_EN10MB; + p->offset = 2; + break; +#endif + +#ifdef ENDT_TRN + case ENDT_TRN: + p->linktype = DLT_IEEE802; + break; +#endif + + default: + /* + * XXX - what about ENDT_IEEE802? The pfilt.h header + * file calls this "IEEE 802 networks (non-Ethernet)", + * but that doesn't specify a specific link layer type; + * it could be 802.4, or 802.5 (except that 802.5 is + * ENDT_TRN), or 802.6, or 802.11, or.... That's why + * DLT_IEEE802 was hijacked to mean Token Ring in various + * BSDs, and why we went along with that hijacking. + * + * XXX - what about ENDT_HDLC and ENDT_NULL? + * Presumably, as ENDT_OTHER is just "Miscellaneous + * framing", there's not much we can do, as that + * doesn't specify a particular type of header. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "unknown data-link type %u", devparams.end_dev_type); + goto bad; + } + /* set truncation */ + if (p->linktype == DLT_FDDI) { + p->fddipad = PCAP_FDDIPAD; + + /* packetfilter includes the padding in the snapshot */ + p->snapshot += PCAP_FDDIPAD; + } else + p->fddipad = 0; + if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&p->snapshot) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCTRUNCATE: %s", + pcap_strerror(errno)); + goto bad; + } + /* accept all packets */ + memset(&Filter, 0, sizeof(Filter)); + Filter.enf_Priority = 37; /* anything > 2 */ + Filter.enf_FilterLen = 0; /* means "always true" */ + if (ioctl(p->fd, EIOCSETF, (caddr_t)&Filter) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSETF: %s", + pcap_strerror(errno)); + goto bad; + } + + if (p->opt.timeout != 0) { + struct timeval timeout; + timeout.tv_sec = p->opt.timeout / 1000; + timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; + if (ioctl(p->fd, EIOCSRTIMEOUT, (caddr_t)&timeout) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSRTIMEOUT: %s", + pcap_strerror(errno)); + goto bad; + } + } + + p->bufsize = BUFSPACE; + p->buffer = (u_char*)malloc(p->bufsize + p->offset); + if (p->buffer == NULL) { + strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); + goto bad; + } + + /* + * "select()" and "poll()" work on packetfilter devices. + */ + p->selectable_fd = p->fd; + + p->read_op = pcap_read_pf; + p->inject_op = pcap_inject_pf; + p->setfilter_op = pcap_setfilter_pf; + p->setdirection_op = NULL; /* Not implemented. */ + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcap_getnonblock_fd; + p->setnonblock_op = pcap_setnonblock_fd; + p->stats_op = pcap_stats_pf; + + return (0); + bad: + pcap_cleanup_live_common(p); + return (PCAP_ERROR); +} + +pcap_t * +pcap_create_interface(const char *device, char *ebuf) +{ + pcap_t *p; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_pf)); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_pf; + return (p); +} + +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + return (0); +} + +static int +pcap_setfilter_pf(pcap_t *p, struct bpf_program *fp) +{ + struct pcap_pf *pf = p->priv; + struct bpf_version bv; + + /* + * See if BIOCVERSION works. If not, we assume the kernel doesn't + * support BPF-style filters (it's not documented in the bpf(7) + * or packetfiler(7) man pages, but the code used to fail if + * BIOCSETF worked but BIOCVERSION didn't, and I've seen it do + * kernel filtering in DU 4.0, so presumably BIOCVERSION works + * there, at least). + */ + if (ioctl(p->fd, BIOCVERSION, (caddr_t)&bv) >= 0) { + /* + * OK, we have the version of the BPF interpreter; + * is it the same major version as us, and the same + * or better minor version? + */ + if (bv.bv_major == BPF_MAJOR_VERSION && + bv.bv_minor >= BPF_MINOR_VERSION) { + /* + * Yes. Try to install the filter. + */ + if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { + snprintf(p->errbuf, sizeof(p->errbuf), + "BIOCSETF: %s", pcap_strerror(errno)); + return (-1); + } + + /* + * OK, that succeeded. We're doing filtering in + * the kernel. (We assume we don't have a + * userland filter installed - that'd require + * a previous version check to have failed but + * this one to succeed.) + * + * XXX - this message should be supplied to the + * application as a warning of some sort, + * except that if it's a GUI application, it's + * not clear that it should be displayed in + * a window to annoy the user. + */ + fprintf(stderr, "tcpdump: Using kernel BPF filter\n"); + pf->filtering_in_kernel = 1; + + /* + * Discard any previously-received packets, + * as they might have passed whatever filter + * was formerly in effect, but might not pass + * this filter (BIOCSETF discards packets buffered + * in the kernel, so you can lose packets in any + * case). + */ + p->cc = 0; + return (0); + } + + /* + * We can't use the kernel's BPF interpreter; don't give + * up, just log a message and be inefficient. + * + * XXX - this should really be supplied to the application + * as a warning of some sort. + */ + fprintf(stderr, + "tcpdump: Requires BPF language %d.%d or higher; kernel is %d.%d\n", + BPF_MAJOR_VERSION, BPF_MINOR_VERSION, + bv.bv_major, bv.bv_minor); + } + + /* + * We couldn't do filtering in the kernel; do it in userland. + */ + if (install_bpf_program(p, fp) < 0) + return (-1); + + /* + * XXX - this message should be supplied by the application as + * a warning of some sort. + */ + fprintf(stderr, "tcpdump: Filtering in user process\n"); + pf->filtering_in_kernel = 0; + return (0); +} diff --git a/tcpdump/jni/libpcap/pcap-savefile.manfile.in b/tcpdump/jni/libpcap/pcap-savefile.manfile.in new file mode 100644 index 0000000..622f6c6 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-savefile.manfile.in @@ -0,0 +1,133 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP-SAVEFILE @MAN_FILE_FORMATS@ "29 July 2013" +.SH NAME +pcap-savefile \- libpcap savefile format +.SH DESCRIPTION +NOTE: applications and libraries should, if possible, use libpcap to +read savefiles, rather than having their own code to read savefiles. +If, in the future, a new file format is supported by libpcap, +applications and libraries using libpcap to read savefiles will be able +to read the new format of savefiles, but applications and libraries +using their own code to read savefiles will have to be changed to +support the new file format. +.PP +``Savefiles'' read and written by libpcap and applications using libpcap +start with a per-file header. The format of the per-file header is: +.RS +.TS +box; +c s +c | c +c s. +Magic number +_ +Major version Minor version +_ +Time zone offset +_ +Time stamp accuracy +_ +Snapshot length +_ +Link-layer header type +.TE +.RE +.PP +All fields in the per-file header are in the byte order of the host +writing the file. Normally, the first field in the per-file header is a +4-byte magic number, with the value 0xa1b2c3d4. The magic number, when +read by a host with the same byte order as the host that wrote the file, +will have the value 0xa1b2c3d4, and, when read by a host with the +opposite byte order as the host that wrote the file, will have the value +0xd4c3b2a1. That allows software reading the file to determine whether +the byte order of the host that wrote the file is the same as the byte +order of the host on which the file is being read, and thus whether the +values in the per-file and per-packet headers need to be byte-swapped. +.PP +If the magic number has the value 0xa1b23c4d (with the two nibbles of +the two lower-order bytes of the magic number swapped), which would be +read as 0xa1b23c4d by a host with the same byte order as the host that +wrote the file and as 0x4d3cb2a1 by a host with the opposite byte order +as the host that wrote the file, the file format is the same as for +regular files, except that the time stamps for packets are given in +seconds and nanoseconds rather than seconds and microseconds. +.PP +Following this are: +.IP +A 2-byte file format major version number; the current version number is +2. +.IP +A 2-byte file format minor version number; the current version number is +4. +.IP +A 4-byte time zone offset; this is always 0. +.IP +A 4-byte number giving the accuracy of time stamps in the file; this is +always 0. +.IP +A 4-byte number giving the "snapshot length" of the capture; packets +longer than the snapshot length are truncated to the snapshot length, so +that, if the snapshot length is +.IR N , +only the first +.I N +bytes of a packet longer than +.I N +bytes will be saved in the capture. +.IP +a 4-byte number giving the link-layer header type for packets in the +capture; see +.BR pcap-linktype (@MAN_MISC_INFO@) +for the +.B LINKTYPE_ +values that can appear in this field. +.PP +Following the per-file header are zero or more packets; each packet +begins with a per-packet header, which is immediately followed by the +raw packet data. The format of the per-packet header is: +.RS +.TS +box; +c. +Time stamp, seconds value +_ +Time stamp, microseconds or nanoseconds value +_ +Length of captured packet data +_ +Un-truncated length of the packet data +.TE +.RE +.PP +All fields in the per-packet header are in the byte order of the host +writing the file. The per-packet header begins with a time stamp giving +the approximate time the packet was captured; the time stamp consists of +a 4-byte value, giving the time in seconds since January 1, 1970, +00:00:00 UTC, followed by a 4-byte value, giving the time in +microseconds or nanoseconds since that second, depending on the magic +number in the file header. Following that are a 4-byte value giving the +number of bytes of captured data that follow the per-packet header and a +4-byte value giving the number of bytes that would have been present had +the packet not been truncated by the snapshot length. The two lengths +will be equal if the number of bytes of packet data are less than or +equal to the snapshot length. +.SH SEE ALSO +pcap(3PCAP), pcap-linktype(@MAN_MISC_INFO@) diff --git a/tcpdump/jni/libpcap/pcap-septel.c b/tcpdump/jni/libpcap/pcap-septel.c new file mode 100644 index 0000000..61cd2f5 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-septel.c @@ -0,0 +1,293 @@ +/* + * pcap-septel.c: Packet capture interface for Intel/Septel card. + * + * The functionality of this code attempts to mimic that of pcap-linux as much + * as possible. This code is compiled in several different ways depending on + * whether SEPTEL_ONLY and HAVE_SEPTEL_API are defined. If HAVE_SEPTEL_API is + * not defined it should not get compiled in, otherwise if SEPTEL_ONLY is + * defined then the 'septel_' function calls are renamed to 'pcap_' + * equivalents. If SEPTEL_ONLY is not defined then nothing is altered - the + * septel_ functions will be called as required from their + * pcap-linux/equivalents. + * + * Authors: Gilbert HOYEK (gil_hoyek@hotmail.com), Elias M. KHOURY + * (+961 3 485243) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include + +#include "pcap-int.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pcap-septel.h" + +static int septel_setfilter(pcap_t *p, struct bpf_program *fp); +static int septel_stats(pcap_t *p, struct pcap_stat *ps); +static int septel_setnonblock(pcap_t *p, int nonblock, char *errbuf); + +/* + * Private data for capturing on Septel devices. + */ +struct pcap_septel { + struct pcap_stat stat; +} + +/* + * Read at most max_packets from the capture queue and call the callback + * for each of them. Returns the number of packets handled, -1 if an + * error occured, or -2 if we were told to break out of the loop. + */ +static int septel_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { + + struct pcap_septel *ps = p->priv; + HDR *h; + MSG *m; + int processed = 0 ; + int t = 0 ; + + /* identifier for the message queue of the module(upe) from which we are capturing + * packets.These IDs are defined in system.txt . By default it is set to 0x2d + * so change it to 0xdd for technical reason and therefore the module id for upe becomes: + * LOCAL 0xdd * upe - Example user part task */ + unsigned int id = 0xdd; + + /* process the packets */ + do { + + unsigned short packet_len = 0; + int caplen = 0; + int counter = 0; + struct pcap_pkthdr pcap_header; + u_char *dp ; + + /* + * Has "pcap_breakloop()" been called? + */ +loop: + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that + * it has, and return -2 to indicate that + * we were told to break out of the loop. + */ + p->break_loop = 0; + return -2; + } + + /*repeat until a packet is read + *a NULL message means : + * when no packet is in queue or all packets in queue already read */ + do { + /* receive packet in non-blocking mode + * GCT_grab is defined in the septel library software */ + h = GCT_grab(id); + + m = (MSG*)h; + /* a couter is added here to avoid an infinite loop + * that will cause our capture program GUI to freeze while waiting + * for a packet*/ + counter++ ; + + } + while ((m == NULL)&& (counter< 100)) ; + + if (m != NULL) { + + t = h->type ; + + /* catch only messages with type = 0xcf00 or 0x8f01 corrsponding to ss7 messages*/ + /* XXX = why not use API_MSG_TX_REQ for 0xcf00 and API_MSG_RX_IND + * for 0x8f01? */ + if ((t != 0xcf00) && (t != 0x8f01)) { + relm(h); + goto loop ; + } + + /* XXX - is API_MSG_RX_IND for an MTP2 or MTP3 message? */ + dp = get_param(m);/* get pointer to MSG parameter area (m->param) */ + packet_len = m->len; + caplen = p->snapshot ; + + + if (caplen > packet_len) { + + caplen = packet_len; + } + /* Run the packet filter if there is one. */ + if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { + + + /* get a time stamp , consisting of : + * + * pcap_header.ts.tv_sec: + * ---------------------- + * a UNIX format time-in-seconds when he packet was captured, + * i.e. the number of seconds since Epoch time (January 1,1970, 00:00:00 GMT) + * + * pcap_header.ts.tv_usec : + * ------------------------ + * the number of microseconds since that second + * when the packet was captured + */ + + (void)gettimeofday(&pcap_header.ts, NULL); + + /* Fill in our own header data */ + pcap_header.caplen = caplen; + pcap_header.len = packet_len; + + /* Count the packet. */ + ps->stat.ps_recv++; + + /* Call the user supplied callback function */ + callback(user, &pcap_header, dp); + + processed++ ; + + } + /* after being processed the packet must be + *released in order to receive another one */ + relm(h); + }else + processed++; + + } + while (processed < cnt) ; + + return processed ; +} + + +static int +septel_inject(pcap_t *handle, const void *buf _U_, size_t size _U_) +{ + strlcpy(handle->errbuf, "Sending packets isn't supported on Septel cards", + PCAP_ERRBUF_SIZE); + return (-1); +} + +/* + * Activate a handle for a live capture from the given Septel device. Always pass a NULL device + * The promisc flag is ignored because Septel cards have built-in tracing. + * The timeout is also ignored as it is not supported in hardware. + * + * See also pcap(3). + */ +static pcap_t *septel_activate(pcap_t* handle) { + /* Initialize some components of the pcap structure. */ + handle->linktype = DLT_MTP2; + + handle->bufsize = 0; + + /* + * "select()" and "poll()" don't work on Septel queues + */ + handle->selectable_fd = -1; + + handle->read_op = septel_read; + handle->inject_op = septel_inject; + handle->setfilter_op = septel_setfilter; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = septel_setnonblock; + handle->stats_op = septel_stats; + + return 0; +} + +pcap_t *septel_create(const char *device, char *ebuf, int *is_ours) { + const char *cp; + pcap_t *p; + + /* Does this look like the Septel device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + if (strcmp(cp, "septel") != 0) { + /* Nope, it's not "septel" */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_septel)); + if (p == NULL) + return NULL; + + p->activate_op = septel_activate; + return p; +} + +static int septel_stats(pcap_t *p, struct pcap_stat *ps) { + struct pcap_septel *handlep = p->priv; + /*handlep->stat.ps_recv = 0;*/ + /*handlep->stat.ps_drop = 0;*/ + + *ps = handlep->stat; + + return 0; +} + + +int +septel_findalldevs(pcap_if_t **devlistp, char *errbuf) +{ + return (pcap_add_if(devlistp,"septel",0, + "Intel/Septel device",errbuf)); +} + + +/* + * Installs the given bpf filter program in the given pcap structure. There is + * no attempt to store the filter in kernel memory as that is not supported + * with Septel cards. + */ +static int septel_setfilter(pcap_t *p, struct bpf_program *fp) { + if (!p) + return -1; + if (!fp) { + strncpy(p->errbuf, "setfilter: No filter specified", + sizeof(p->errbuf)); + return -1; + } + + /* Make our private copy of the filter */ + + if (install_bpf_program(p, fp) < 0) { + snprintf(p->errbuf, sizeof(p->errbuf), + "malloc: %s", pcap_strerror(errno)); + return -1; + } + + return (0); +} + + +static int +septel_setnonblock(pcap_t *p, int nonblock, char *errbuf) +{ + fprintf(errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices"); + return (-1); +} diff --git a/tcpdump/jni/libpcap/pcap-septel.h b/tcpdump/jni/libpcap/pcap-septel.h new file mode 100644 index 0000000..b6e1168 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-septel.h @@ -0,0 +1,13 @@ +/* + * pcap-septel.c: Packet capture interface for Intel Septel card + * + * The functionality of this code attempts to mimic that of pcap-linux as much + * as possible. This code is only needed when compiling in the Intel/Septel + * card code at the same time as another type of device. + * + * Authors: Gilbert HOYEK (gil_hoyek@hotmail.com), Elias M. KHOURY + * (+961 3 485343); + */ + +pcap_t *septel_create(const char *device, char *ebuf, int *is_ours); +int septel_findalldevs(pcap_if_t **devlistp, char *errbuf); diff --git a/tcpdump/jni/libpcap/pcap-sita.c b/tcpdump/jni/libpcap/pcap-sita.c new file mode 100644 index 0000000..b35b106 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-sita.c @@ -0,0 +1,1019 @@ +/* + * pcap-sita.c: Packet capture interface additions for SITA ACN devices + * + * Copyright (c) 2007 Fulko Hew, SITA INC Canada, Inc + * + * License: BSD + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pcap-int.h" + +#include "pcap-sita.h" + + /* non-configureable manifests follow */ + +#define IOP_SNIFFER_PORT 49152 /* TCP port on the IOP used for 'distributed pcap' usage */ +#define MAX_LINE_SIZE 255 /* max size of a buffer/line in /etc/hosts we allow */ +#define MAX_CHASSIS 8 /* number of chassis in an ACN site */ +#define MAX_GEOSLOT 8 /* max number of access units in an ACN site */ + +#define FIND 0 +#define LIVE 1 + +typedef struct iface { + struct iface *next; /* a pointer to the next interface */ + char *name; /* this interface's name */ + char *IOPname; /* this interface's name on an IOP */ + uint32_t iftype; /* the type of interface (DLT values) */ +} iface_t; + +typedef struct unit { + char *ip; /* this unit's IP address (as extracted from /etc/hosts) */ + int fd; /* the connection to this unit (if it exists) */ + int find_fd; /* a big kludge to avoid my programming limitations since I could have this unit open for findalldevs purposes */ + int first_time; /* 0 = just opened via acn_open_live(), ie. the first time, NZ = nth time */ + struct sockaddr_in *serv_addr; /* the address control block for comms to this unit */ + int chassis; + int geoslot; + iface_t *iface; /* a pointer to a linked list of interface structures */ + char *imsg; /* a pointer to an inbound message */ + int len; /* the current size of the inbound message */ +} unit_t; + +static unit_t units[MAX_CHASSIS+1][MAX_GEOSLOT+1]; /* we use indexes of 1 through 8, but we reserve/waste index 0 */ +static fd_set readfds; /* a place to store the file descriptors for the connections to the IOPs */ +static int max_fs; + +pcap_if_t *acn_if_list; /* pcap's list of available interfaces */ + +static void dump_interface_list(void) { + pcap_if_t *iff; + pcap_addr_t *addr; + int longest_name_len = 0; + char *n, *d, *f; + int if_number = 0; + + iff = acn_if_list; + while (iff) { + if (iff->name && (strlen(iff->name) > longest_name_len)) longest_name_len = strlen(iff->name); + iff = iff->next; + } + iff = acn_if_list; + printf("Interface List:\n"); + while (iff) { + n = (iff->name) ? iff->name : ""; + d = (iff->description) ? iff->description : ""; + f = (iff->flags == PCAP_IF_LOOPBACK) ? "L" : ""; + printf("%3d: %*s %s '%s'\n", if_number++, longest_name_len, n, f, d); + addr = iff->addresses; + while (addr) { + printf("%*s ", (5 + longest_name_len), ""); /* add some indentation */ + printf("%15s ", (addr->addr) ? inet_ntoa(((struct sockaddr_in *)addr->addr)->sin_addr) : ""); + printf("%15s ", (addr->netmask) ? inet_ntoa(((struct sockaddr_in *)addr->netmask)->sin_addr) : ""); + printf("%15s ", (addr->broadaddr) ? inet_ntoa(((struct sockaddr_in *)addr->broadaddr)->sin_addr) : ""); + printf("%15s ", (addr->dstaddr) ? inet_ntoa(((struct sockaddr_in *)addr->dstaddr)->sin_addr) : ""); + printf("\n"); + addr = addr->next; + } + iff = iff->next; + } +} + +static void dump(unsigned char *ptr, int i, int indent) { + fprintf(stderr, "%*s", indent, " "); + for (; i > 0; i--) { + fprintf(stderr, "%2.2x ", *ptr++); + } + fprintf(stderr, "\n"); +} + +static void dump_interface_list_p(void) { + pcap_if_t *iff; + pcap_addr_t *addr; + int if_number = 0; + + iff = acn_if_list; + printf("Interface Pointer @ %p is %p:\n", &acn_if_list, iff); + while (iff) { + printf("%3d: %p %p next: %p\n", if_number++, iff->name, iff->description, iff->next); + dump((unsigned char *)iff, sizeof(pcap_if_t), 5); + addr = iff->addresses; + while (addr) { + printf(" %p %p %p %p, next: %p\n", addr->addr, addr->netmask, addr->broadaddr, addr->dstaddr, addr->next); + dump((unsigned char *)addr, sizeof(pcap_addr_t), 10); + addr = addr->next; + } + iff = iff->next; + } +} + +static void dump_unit_table(void) { + int chassis, geoslot; + iface_t *p; + + printf("%c:%c %s %s\n", 'C', 'S', "fd", "IP Address"); + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { + if (units[chassis][geoslot].ip != NULL) + printf("%d:%d %2d %s\n", chassis, geoslot, units[chassis][geoslot].fd, units[chassis][geoslot].ip); + p = units[chassis][geoslot].iface; + while (p) { + char *n = (p->name) ? p->name : ""; + char *i = (p->IOPname) ? p->IOPname : ""; + p = p->next; + printf(" %12s -> %12s\n", i, n); + } + } + } +} + +static int find_unit_by_fd(int fd, int *chassis, int *geoslot, unit_t **unit_ptr) { + int c, s; + + for (c = 0; c <= MAX_CHASSIS; c++) { + for (s = 0; s <= MAX_GEOSLOT; s++) { + if (units[c][s].fd == fd || units[c][s].find_fd == fd) { + if (chassis) *chassis = c; + if (geoslot) *geoslot = s; + if (unit_ptr) *unit_ptr = &units[c][s]; + return 1; + } + } + } + return 0; +} + +static int read_client_nbytes(int fd, int count, unsigned char *buf) { + unit_t *u; + int chassis, geoslot; + int len; + + find_unit_by_fd(fd, &chassis, &geoslot, &u); + while (count) { + if ((len = recv(fd, buf, count, 0)) <= 0) return -1; /* read in whatever data was sent to us */ + count -= len; + buf += len; + } /* till we have everything we are looking for */ + return 0; +} + +static void empty_unit_iface(unit_t *u) { + iface_t *p, *cur; + + cur = u->iface; + while (cur) { /* loop over all the interface entries */ + if (cur->name) free(cur->name); /* throwing away the contents if they exist */ + if (cur->IOPname) free(cur->IOPname); + p = cur->next; + free(cur); /* then throw away the structure itself */ + cur = p; + } + u->iface = 0; /* and finally remember that there are no remaining structure */ +} + +static void empty_unit(int chassis, int geoslot) { + unit_t *u = &units[chassis][geoslot]; + + empty_unit_iface(u); + if (u->imsg) { /* then if an inbound message buffer exists */ + u->imsg = (char *)realloc(u->imsg, 1); /* and re-allocate the old large buffer into a new small one */ + if (u->imsg == NULL) { /* oops, realloc call failed */ + fprintf(stderr, "Warning...call to realloc() failed, value of errno is %d\n", errno); + + } +} + +static void empty_unit_table(void) { + int chassis, geoslot; + + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { + if (units[chassis][geoslot].ip != NULL) { + free(units[chassis][geoslot].ip); /* get rid of the malloc'ed space that holds the IP address */ + units[chassis][geoslot].ip = 0; /* then set the pointer to NULL */ + } + empty_unit(chassis, geoslot); + } + } +} + +static char *find_nth_interface_name(int n) { + int chassis, geoslot; + iface_t *p; + char *last_name = 0; + + if (n < 0) n = 0; /* ensure we are working with a valid number */ + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { /* scan the table... */ + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { + if (units[chassis][geoslot].ip != NULL) { + p = units[chassis][geoslot].iface; + while (p) { /* and all interfaces... */ + if (p->IOPname) last_name = p->name; /* remembering the last name found */ + if (n-- == 0) return last_name; /* and if we hit the instance requested */ + p = p->next; + } + } + } + } + /* if we couldn't fine the selected entry */ + if (last_name) return last_name; /* ... but we did have at least one entry... return the last entry found */ + return ""; /* ... but if there wasn't any entry... return an empty string instead */ +} + +int acn_parse_hosts_file(char *errbuf) { /* returns: -1 = error, 0 = OK */ + FILE *fp; + char buf[MAX_LINE_SIZE]; + char *ptr, *ptr2; + int pos; + int chassis, geoslot; + unit_t *u; + + empty_unit_table(); + if ((fp = fopen("/etc/hosts", "r")) == NULL) { /* try to open the hosts file and if it fails */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading."); /* return the nohostsfile error response */ + return -1; + } + while (fgets(buf, MAX_LINE_SIZE-1, fp)) { /* while looping over the file */ + + pos = strcspn(buf, "#\n\r"); /* find the first comment character or EOL */ + *(buf + pos) = '\0'; /* and clobber it and anything that follows it */ + + pos = strspn(buf, " \t"); /* then find the first non-white space */ + if (pos == strlen(buf)) /* if there is nothing but white space on the line */ + continue; /* ignore that empty line */ + ptr = buf + pos; /* and skip over any of that leading whitespace */ + + if ((ptr2 = strstr(ptr, "_I_")) == NULL) /* skip any lines that don't have names that look like they belong to IOPs */ + continue; + if (*(ptr2 + 4) != '_') /* and skip other lines that have names that don't look like ACN components */ + continue; + *(ptr + strcspn(ptr, " \t")) = '\0'; /* null terminate the IP address so its a standalone string */ + + chassis = *(ptr2 + 3) - '0'; /* extract the chassis number */ + geoslot = *(ptr2 + 5) - '0'; /* and geo-slot number */ + if (chassis < 1 || chassis > MAX_CHASSIS || + geoslot < 1 || geoslot > MAX_GEOSLOT) { /* if the chassis and/or slot numbers appear to be bad... */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'."); /* warn the user */ + continue; /* and ignore the entry */ + } + if ((ptr2 = (char *)malloc(strlen(ptr) + 1)) == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); + continue; + } + strcpy(ptr2, ptr); /* copy the IP address into our malloc'ed memory */ + u = &units[chassis][geoslot]; + u->ip = ptr2; /* and remember the whole shebang */ + u->chassis = chassis; + u->geoslot = geoslot; + } + fclose(fp); + if (*errbuf) return -1; + else return 0; +} + +static int open_with_IOP(unit_t *u, int flag) { + int sockfd; + char *ip; + + if (u->serv_addr == NULL) { + u->serv_addr = malloc(sizeof(struct sockaddr_in)); + + /* since we called malloc(), lets check to see if we actually got the memory */ + if (u->serv_addr == NULL) { /* oops, we didn't get the memory requested */ + fprintf(stderr, "malloc() request for u->serv_addr failed, value of errno is: %d\n", errno); + return 0; + } + + } + ip = u->ip; + /* bzero() is deprecated, replaced with memset() */ + memset((char *)u->serv_addr, 0, sizeof(struct sockaddr_in)); + u->serv_addr->sin_family = AF_INET; + u->serv_addr->sin_addr.s_addr = inet_addr(ip); + u->serv_addr->sin_port = htons(IOP_SNIFFER_PORT); + + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "pcap can't open a socket for connecting to IOP at %s\n", ip); + return 0; + } + if (connect(sockfd, (struct sockaddr *)u->serv_addr, sizeof(struct sockaddr_in)) < 0) { + fprintf(stderr, "pcap can't connect to IOP at %s\n", ip); + return 0; + } + if (flag == LIVE) u->fd = sockfd; + else u->find_fd = sockfd; + u->first_time = 0; + return sockfd; /* return the non-zero file descriptor as a 'success' indicator */ +} + +static void close_with_IOP(int chassis, int geoslot, int flag) { + int *id; + + if (flag == LIVE) id = &units[chassis][geoslot].fd; + else id = &units[chassis][geoslot].find_fd; + + if (*id) { /* this was the last time, so... if we are connected... */ + close(*id); /* disconnect us */ + *id = 0; /* and forget that the descriptor exists because we are not open */ + } +} + +static void pcap_cleanup_acn(pcap_t *handle) { + int chassis, geoslot; + unit_t *u; + + if (find_unit_by_fd(handle->fd, &chassis, &geoslot, &u) == 0) + return; + close_with_IOP(chassis, geoslot, LIVE); + if (u) + u->first_time = 0; + pcap_cleanup_live_common(handle); +} + +static void send_to_fd(int fd, int len, unsigned char *str) { + int nwritten; + int chassis, geoslot; + + while (len > 0) { + if ((nwritten = write(fd, str, len)) <= 0) { + find_unit_by_fd(fd, &chassis, &geoslot, NULL); + if (units[chassis][geoslot].fd == fd) close_with_IOP(chassis, geoslot, LIVE); + else if (units[chassis][geoslot].find_fd == fd) close_with_IOP(chassis, geoslot, FIND); + empty_unit(chassis, geoslot); + return; + } + len -= nwritten; + str += nwritten; + } +} + +static void acn_freealldevs(void) { + + pcap_if_t *iff, *next_iff; + pcap_addr_t *addr, *next_addr; + + for (iff = acn_if_list; iff != NULL; iff = next_iff) { + next_iff = iff->next; + for (addr = iff->addresses; addr != NULL; addr = next_addr) { + next_addr = addr->next; + if (addr->addr) free(addr->addr); + if (addr->netmask) free(addr->netmask); + if (addr->broadaddr) free(addr->broadaddr); + if (addr->dstaddr) free(addr->dstaddr); + free(addr); + } + if (iff->name) free(iff->name); + if (iff->description) free(iff->description); + free(iff); + } +} + +static void nonUnified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u) { + + snprintf(buf, bufsize, "%s_%d_%d", proto, u->chassis, u->geoslot); +} + +static void unified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u, int IOPportnum) { + int portnum; + + portnum = ((u->chassis - 1) * 64) + ((u->geoslot - 1) * 8) + IOPportnum + 1; + snprintf(buf, bufsize, "%s_%d", proto, portnum); +} + +static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 iftype) { + iface_t *iface_ptr, *iface; + char *name; + char buf[32]; + char *proto; + char *port; + int IOPportnum = 0; + + iface = malloc(sizeof(iface_t)); /* get memory for a structure */ + if (iface == NULL) { /* oops, we didn't get the memory requested */ + fprintf(stderr, "Error...couldn't allocate memory for interface structure...value of errno is: %d\n", errno); + return NULL; + } + memset((char *)iface, 0, sizeof(iface_t)); /* bzero is deprecated(), replaced with memset() */ + + iface->iftype = iftype; /* remember the interface type of this interface */ + + name = malloc(strlen(IOPname) + 1); /* get memory for the IOP's name */ + if (name == NULL) { /* oops, we didn't get the memory requested */ + fprintf(stderr, "Error...couldn't allocate memory for IOPname...value of errno is: %d\n", errno); + return NULL; + } + + strcpy(name, IOPname); /* and copy it in */ + iface->IOPname = name; /* and stick it into the structure */ + + if (strncmp(IOPname, "lo", 2) == 0) { + IOPportnum = atoi(&IOPname[2]); + switch (iftype) { + case DLT_EN10MB: + nonUnified_IOP_port_name(buf, sizeof buf, "lo", u); + break; + default: + unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum); + break; + } + } else if (strncmp(IOPname, "eth", 3) == 0) { + IOPportnum = atoi(&IOPname[3]); + switch (iftype) { + case DLT_EN10MB: + nonUnified_IOP_port_name(buf, sizeof buf, "eth", u); + break; + default: + unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum); + break; + } + } else if (strncmp(IOPname, "wan", 3) == 0) { + IOPportnum = atoi(&IOPname[3]); + switch (iftype) { + case DLT_SITA: + unified_IOP_port_name(buf, sizeof buf, "wan", u, IOPportnum); + break; + default: + unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum); + break; + } + } else { + fprintf(stderr, "Error... invalid IOP name %s\n", IOPname); + return NULL; + } + + name = malloc(strlen(buf) + 1); /* get memory for that name */ + if (name == NULL) { /* oops, we didn't get the memory requested */ + fprintf(stderr, "Error...couldn't allocate memory for IOP port name...value of errno is: %d\n", errno); + return NULL; + } + + strcpy(name, buf); /* and copy it in */ + iface->name = name; /* and stick it into the structure */ + + if (u->iface == 0) { /* if this is the first name */ + u->iface = iface; /* stick this entry at the head of the list */ + } else { + iface_ptr = u->iface; + while (iface_ptr->next) { /* othewise scan the list */ + iface_ptr = iface_ptr->next; /* till we're at the last entry */ + } + iface_ptr->next = iface; /* then tack this entry on the end of the list */ + } + return iface->name; +} + +static int if_sort(char *s1, char *s2) { + char *s1_p2, *s2_p2; + char str1[MAX_LINE_SIZE], str2[MAX_LINE_SIZE]; + int s1_p1_len, s2_p1_len; + int retval; + + if ((s1_p2 = strchr(s1, '_'))) { /* if an underscore is found... */ + s1_p1_len = s1_p2 - s1; /* the prefix length is the difference in pointers */ + s1_p2++; /* the suffix actually starts _after_ the underscore */ + } else { /* otherwise... */ + s1_p1_len = strlen(s1); /* the prefix length is the length of the string itself */ + s1_p2 = 0; /* and there is no suffix */ + } + if ((s2_p2 = strchr(s2, '_'))) { /* now do the same for the second string */ + s2_p1_len = s2_p2 - s2; + s2_p2++; + } else { + s2_p1_len = strlen(s2); + s2_p2 = 0; + } + strncpy(str1, s1, (s1_p1_len > sizeof(str1)) ? s1_p1_len : sizeof(str1)); *(str1 + s1_p1_len) = 0; + strncpy(str2, s2, (s2_p1_len > sizeof(str2)) ? s2_p1_len : sizeof(str2)); *(str2 + s2_p1_len) = 0; + retval = strcmp(str1, str2); + if (retval != 0) return retval; /* if they are not identical, then we can quit now and return the indication */ + return strcmp(s1_p2, s2_p2); /* otherwise we return the result of comparing the 2nd half of the string */ +} + +static void sort_if_table(void) { + pcap_if_t *p1, *p2, *prev, *temp; + int has_swapped; + + if (!acn_if_list) return; /* nothing to do if the list is empty */ + + while (1) { + p1 = acn_if_list; /* start at the head of the list */ + prev = 0; + has_swapped = 0; + while ((p2 = p1->next)) { + if (if_sort(p1->name, p2->name) > 0) { + if (prev) { /* we are swapping things that are _not_ at the head of the list */ + temp = p2->next; + prev->next = p2; + p2->next = p1; + p1->next = temp; + } else { /* special treatment if we are swapping with the head of the list */ + temp = p2->next; + acn_if_list= p2; + p2->next = p1; + p1->next = temp; + } + p1 = p2; + prev = p1; + has_swapped = 1; + } + prev = p1; + p1 = p1->next; + } + if (has_swapped == 0) + return; + } + return; +} + +static int process_client_data (char *errbuf) { /* returns: -1 = error, 0 = OK */ + int chassis, geoslot; + unit_t *u; + pcap_if_t *iff, *prev_iff; + pcap_addr_t *addr, *prev_addr; + char *ptr; + int address_count; + struct sockaddr_in *s; + char *newname; + bpf_u_int32 interfaceType; + unsigned char flags; + + prev_iff = 0; + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { /* now loop over all the devices */ + u = &units[chassis][geoslot]; + empty_unit_iface(u); + ptr = u->imsg; /* point to the start of the msg for this IOP */ + while (ptr < (u->imsg + u->len)) { + if ((iff = malloc(sizeof(pcap_if_t))) == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); + return -1; + } + memset((char *)iff, 0, sizeof(pcap_if_t)); /* bzero() is deprecated, replaced with memset() */ + if (acn_if_list == 0) acn_if_list = iff; /* remember the head of the list */ + if (prev_iff) prev_iff->next = iff; /* insert a forward link */ + + if (*ptr) { /* if there is a count for the name */ + if ((iff->name = malloc(*ptr + 1)) == NULL) { /* get that amount of space */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); + return -1; + } + memcpy(iff->name, (ptr + 1), *ptr); /* copy the name into the malloc'ed space */ + *(iff->name + *ptr) = 0; /* and null terminate the string */ + ptr += *ptr; /* now move the pointer forwards by the length of the count plus the length of the string */ + } + ptr++; + + if (*ptr) { /* if there is a count for the description */ + if ((iff->description = malloc(*ptr + 1)) == NULL) { /* get that amount of space */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); + return -1; + } + memcpy(iff->description, (ptr + 1), *ptr); /* copy the name into the malloc'ed space */ + *(iff->description + *ptr) = 0; /* and null terminate the string */ + ptr += *ptr; /* now move the pointer forwards by the length of the count plus the length of the string */ + } + ptr++; + + interfaceType = ntohl(*(bpf_u_int32 *)ptr); + ptr += 4; /* skip over the interface type */ + + flags = *ptr++; + if (flags) iff->flags = PCAP_IF_LOOPBACK; /* if this is a loopback style interface, lets mark it as such */ + + address_count = *ptr++; + + prev_addr = 0; + while (address_count--) { + if ((addr = malloc(sizeof(pcap_addr_t))) == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); + return -1; + } ++ memset((char *)addr, 0, sizeof(pcap_addr_t)); /* bzero() is deprecated, replaced with memset() */ + if (iff->addresses == 0) iff->addresses = addr; + if (prev_addr) prev_addr->next = addr; /* insert a forward link */ + if (*ptr) { /* if there is a count for the address */ + if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { /* get that amount of space */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); + return -1; + } + memset((char *)s, 0, sizeof(struct sockaddr_in)); /* bzero() is deprecated, replaced with memset() */ + addr->addr = (struct sockaddr *)s; + s->sin_family = AF_INET; + s->sin_addr.s_addr = *(bpf_u_int32 *)(ptr + 1); /* copy the address in */ + ptr += *ptr; /* now move the pointer forwards according to the specified length of the address */ + } + ptr++; /* then forwards one more for the 'length of the address' field */ + if (*ptr) { /* process any netmask */ + if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); + return -1; + } + /* bzero() is deprecated, replaced with memset() */ + memset((char *)s, 0, sizeof(struct sockaddr_in)); + + addr->netmask = (struct sockaddr *)s; + s->sin_family = AF_INET; + s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1); + ptr += *ptr; + } + ptr++; + if (*ptr) { /* process any broadcast address */ + if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); + return -1; + } + /* bzero() is deprecated, replaced with memset() */ + memset((char *)s, 0, sizeof(struct sockaddr_in)); + + addr->broadaddr = (struct sockaddr *)s; + s->sin_family = AF_INET; + s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1); + ptr += *ptr; + } + ptr++; + if (*ptr) { /* process any destination address */ + if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); + return -1; + } + /* bzero() is deprecated, replaced with memset() */ + memset((char *)s, 0, sizeof(struct sockaddr_in)); + + addr->dstaddr = (struct sockaddr *)s; + s->sin_family = AF_INET; + s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1); + ptr += *ptr; + } + ptr++; + prev_addr = addr; + } + prev_iff = iff; + + newname = translate_IOP_to_pcap_name(u, iff->name, interfaceType); /* add a translation entry and get a point to the mangled name */ + if ((iff->name = realloc(iff->name, strlen(newname) + 1)) == NULL) { /* we now re-write the name stored in the interface list */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "realloc: %s", pcap_strerror(errno)); + return -1; + } + strcpy(iff->name, newname); /* to this new name */ + } + } + } + return 0; +} + +static int read_client_data (int fd) { + unsigned char buf[256]; + int chassis, geoslot; + unit_t *u; + int len; + + find_unit_by_fd(fd, &chassis, &geoslot, &u); + + if ((len = recv(fd, buf, sizeof(buf), 0)) <= 0) return 0; /* read in whatever data was sent to us */ + + if ((u->imsg = realloc(u->imsg, (u->len + len))) == NULL) /* extend the buffer for the new data */ + return 0; + memcpy((u->imsg + u->len), buf, len); /* append the new data */ + u->len += len; + return 1; +} + +static void wait_for_all_answers(void) { + int retval; + struct timeval tv; + int fd; + int chassis, geoslot; + + tv.tv_sec = 2; + tv.tv_usec = 0; + + while (1) { + int flag = 0; + fd_set working_set; + + for (fd = 0; fd <= max_fs; fd++) { /* scan the list of descriptors we may be listening to */ + if (FD_ISSET(fd, &readfds)) flag = 1; /* and see if there are any still set */ + } + if (flag == 0) return; /* we are done, when they are all gone */ + + memcpy(&working_set, &readfds, sizeof(readfds)); /* otherwise, we still have to listen for more stuff, till we timeout */ + retval = select(max_fs + 1, &working_set, NULL, NULL, &tv); + if (retval == -1) { /* an error occured !!!!! */ + return; + } else if (retval == 0) { /* timeout occured, so process what we've got sofar and return */ + printf("timeout\n"); + return; + } else { + for (fd = 0; fd <= max_fs; fd++) { /* scan the list of things to do, and do them */ + if (FD_ISSET(fd, &working_set)) { + if (read_client_data(fd) == 0) { /* if the socket has closed */ + FD_CLR(fd, &readfds); /* and descriptors we listen to for errors */ + find_unit_by_fd(fd, &chassis, &geoslot, NULL); + close_with_IOP(chassis, geoslot, FIND); /* and close out connection to him */ + } + } + } + } + } +} + +static char *get_error_response(int fd, char *errbuf) { /* return a pointer on error, NULL on no error */ + char byte; + int len = 0; + + while (1) { + recv(fd, &byte, 1, 0); /* read another byte in */ + if (errbuf && (len++ < PCAP_ERRBUF_SIZE)) { /* and if there is still room in the buffer */ + *errbuf++ = byte; /* stick it in */ + *errbuf = '\0'; /* ensure the string is null terminated just in case we might exceed the buffer's size */ + } + if (byte == '\0') { + if (len > 1) { return errbuf; } + else { return NULL; } + } + } +} + +int acn_findalldevs(char *errbuf) { /* returns: -1 = error, 0 = OK */ + int chassis, geoslot; + unit_t *u; + + FD_ZERO(&readfds); + max_fs = 0; + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { + u = &units[chassis][geoslot]; + if (u->ip && (open_with_IOP(u, FIND))) { /* connect to the remote IOP */ + send_to_fd(u->find_fd, 1, (unsigned char *)"\0"); + if (get_error_response(u->find_fd, errbuf)) + close_with_IOP(chassis, geoslot, FIND); + else { + if (u->find_fd > max_fs) + max_fs = u->find_fd; /* remember the highest number currently in use */ + FD_SET(u->find_fd, &readfds); /* we are going to want to read this guy's response to */ + u->len = 0; + send_to_fd(u->find_fd, 1, (unsigned char *)"Q"); /* this interface query request */ + } + } + } + } + wait_for_all_answers(); + if (process_client_data(errbuf)) + return -1; + sort_if_table(); + return 0; +} + +static int pcap_stats_acn(pcap_t *handle, struct pcap_stat *ps) { + unsigned char buf[12]; + + send_to_fd(handle->fd, 1, (unsigned char *)"S"); /* send the get_stats command to the IOP */ + + if (read_client_nbytes(handle->fd, sizeof(buf), buf) == -1) return -1; /* try reading the required bytes */ + + ps->ps_recv = ntohl(*(uint32_t *)&buf[0]); /* break the buffer into its three 32 bit components */ + ps->ps_drop = ntohl(*(uint32_t *)&buf[4]); + ps->ps_ifdrop = ntohl(*(uint32_t *)&buf[8]); + + return 0; +} + +static int acn_open_live(const char *name, char *errbuf, int *linktype) { /* returns 0 on error, else returns the file descriptor */ + int chassis, geoslot; + unit_t *u; + iface_t *p; + pcap_if_t *alldevsp; + + pcap_findalldevs_interfaces(&alldevsp, errbuf); + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { /* scan the table... */ + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { + u = &units[chassis][geoslot]; + if (u->ip != NULL) { + p = u->iface; + while (p) { /* and all interfaces... */ + if (p->IOPname && p->name && (strcmp(p->name, name) == 0)) { /* and if we found the interface we want... */ + *linktype = p->iftype; + open_with_IOP(u, LIVE); /* start a connection with that IOP */ + send_to_fd(u->fd, strlen(p->IOPname)+1, (unsigned char *)p->IOPname); /* send the IOP's interface name, and a terminating null */ + if (get_error_response(u->fd, errbuf)) { + return -1; + } + return u->fd; /* and return that open descriptor */ + } + p = p->next; + } + } + } + } + return -1; /* if the interface wasn't found, return an error */ +} + +static void acn_start_monitor(int fd, int snaplen, int timeout, int promiscuous, int direction) { + unsigned char buf[8]; + unit_t *u; + + //printf("acn_start_monitor()\n"); // fulko + find_unit_by_fd(fd, NULL, NULL, &u); + if (u->first_time == 0) { + buf[0] = 'M'; + *(uint32_t *)&buf[1] = htonl(snaplen); + buf[5] = timeout; + buf[6] = promiscuous; + buf[7] = direction; + //printf("acn_start_monitor() first time\n"); // fulko + send_to_fd(fd, 8, buf); /* send the start monitor command with its parameters to the IOP */ + u->first_time = 1; + } + //printf("acn_start_monitor() complete\n"); // fulko +} + +static int pcap_inject_acn(pcap_t *p, const void *buf _U_, size_t size _U_) { + strlcpy(p->errbuf, "Sending packets isn't supported on ACN adapters", + PCAP_ERRBUF_SIZE); + return (-1); +} + +static int pcap_setfilter_acn(pcap_t *handle, struct bpf_program *bpf) { + int fd = handle->fd; + int count; + struct bpf_insn *p; + uint16_t shortInt; + uint32_t longInt; + + send_to_fd(fd, 1, (unsigned char *)"F"); /* BPF filter follows command */ + count = bpf->bf_len; + longInt = htonl(count); + send_to_fd(fd, 4, (unsigned char *)&longInt); /* send the instruction sequence count */ + p = bpf->bf_insns; + while (count--) { /* followed by the list of instructions */ + shortInt = htons(p->code); + longInt = htonl(p->k); + send_to_fd(fd, 2, (unsigned char *)&shortInt); + send_to_fd(fd, 1, (unsigned char *)&p->jt); + send_to_fd(fd, 1, (unsigned char *)&p->jf); + send_to_fd(fd, 4, (unsigned char *)&longInt); + p++; + } + if (get_error_response(fd, NULL)) + return -1; + return 0; +} + +static int pcap_setdirection_acn(pcap_t *handle, pcap_direction_t d) { + snprintf(handle->errbuf, sizeof(handle->errbuf), + "Setting direction is not supported on ACN adapters"); + return -1; +} + +static int acn_read_n_bytes_with_timeout(pcap_t *handle, int count) { + struct timeval tv; + int retval, fd; + fd_set r_fds; + fd_set w_fds; + u_char *bp; + int len = 0; + int offset = 0; + + tv.tv_sec = 5; + tv.tv_usec = 0; + + fd = handle->fd; + FD_ZERO(&r_fds); + FD_SET(fd, &r_fds); + memcpy(&w_fds, &r_fds, sizeof(r_fds)); + bp = handle->bp; + while (count) { + retval = select(fd + 1, &w_fds, NULL, NULL, &tv); + if (retval == -1) { /* an error occured !!!!! */ +// fprintf(stderr, "error during packet data read\n"); + return -1; /* but we need to return a good indication to prevent unneccessary popups */ + } else if (retval == 0) { /* timeout occured, so process what we've got sofar and return */ +// fprintf(stderr, "timeout during packet data read\n"); + return -1; + } else { + if ((len = recv(fd, (bp + offset), count, 0)) <= 0) { +// fprintf(stderr, "premature exit during packet data rx\n"); + return -1; + } + count -= len; + offset += len; + } + } + return 0; +} + +static int pcap_read_acn(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { + #define HEADER_SIZE (4 * 4) + unsigned char packet_header[HEADER_SIZE]; + struct pcap_pkthdr pcap_header; + + //printf("pcap_read_acn()\n"); // fulko + acn_start_monitor(handle->fd, handle->snapshot, handle->opt.timeout, handle->opt.promisc, handle->direction); /* maybe tell him to start monitoring */ + //printf("pcap_read_acn() after start monitor\n"); // fulko + + handle->bp = packet_header; + if (acn_read_n_bytes_with_timeout(handle, HEADER_SIZE) == -1) return 0; /* try to read a packet header in so we can get the sizeof the packet data */ + + pcap_header.ts.tv_sec = ntohl(*(uint32_t *)&packet_header[0]); /* tv_sec */ + pcap_header.ts.tv_usec = ntohl(*(uint32_t *)&packet_header[4]); /* tv_usec */ + pcap_header.caplen = ntohl(*(uint32_t *)&packet_header[8]); /* caplen */ + pcap_header.len = ntohl(*(uint32_t *)&packet_header[12]); /* len */ + + handle->bp = handle->buffer + handle->offset; /* start off the receive pointer at the right spot */ + if (acn_read_n_bytes_with_timeout(handle, pcap_header.caplen) == -1) return 0; /* then try to read in the rest of the data */ + + callback(user, &pcap_header, handle->bp); /* call the user supplied callback function */ + return 1; +} + +static int pcap_activate_sita(pcap_t *handle) { + int fd; + + if (handle->opt.rfmon) { + /* + * No monitor mode on SITA devices (they're not Wi-Fi + * devices). + */ + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* Initialize some components of the pcap structure. */ + + handle->inject_op = pcap_inject_acn; + handle->setfilter_op = pcap_setfilter_acn; + handle->setdirection_op = pcap_setdirection_acn; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->cleanup_op = pcap_cleanup_acn; + handle->read_op = pcap_read_acn; + handle->stats_op = pcap_stats_acn; + + fd = acn_open_live(handle->opt.source, handle->errbuf, + &handle->linktype); + if (fd == -1) + return PCAP_ERROR; + handle->fd = fd; + handle->bufsize = handle->snapshot; + + /* Allocate the buffer */ + + handle->buffer = malloc(handle->bufsize + handle->offset); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + pcap_cleanup_acn(handle); + return PCAP_ERROR; + } + + /* + * "handle->fd" is a socket, so "select()" and "poll()" + * should work on it. + */ + handle->selectable_fd = handle->fd; + + return 0; +} + +pcap_t *pcap_create_interface(const char *device, char *ebuf) { + pcap_t *p; + + p = pcap_create_common(device, ebuf, 0); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_sita; + return (p); +} diff --git a/tcpdump/jni/libpcap/pcap-sita.h b/tcpdump/jni/libpcap/pcap-sita.h new file mode 100644 index 0000000..9c35c6a --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-sita.h @@ -0,0 +1,8 @@ +/* + * pcap-sita.h: Packet capture interface for SITA WAN devices + * + * Authors: Fulko Hew (fulko.hew@sita.aero) (+1 905 6815570); + */ + +extern int acn_parse_hosts_file(char *errbuf); +extern int acn_findalldevs(char *errbuf); diff --git a/tcpdump/jni/libpcap/pcap-sita.html b/tcpdump/jni/libpcap/pcap-sita.html new file mode 100644 index 0000000..97408d8 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-sita.html @@ -0,0 +1,943 @@ + + + + + + + + +
    + A "Distributed Pcap" for
    Remote Monitoring LANs & WANs

    + (Design Notes for the SITA ACN device)
    +
    + Fulko Hew
    SITA INC Canada, Inc.
    Revised: October 2, 2007 +
    + + +

    SUMMARY

    +
      + Note: This document is part of the libpcap Git and was derived from 'pcap.3' (circa Aug/07). +

      + The ACN provides a customized/distributed version of this library that alows SMPs to + interact with the various IOPs within the site providing a standard mechanism + to capture LAN and WAN message traffic. +

      +

      + + + + + + + + + +
      SMPThe Supervisory Management Processor where Wireshark (or equivalent) + runs in conjuction with a libpcap front-end.
      IOPI/O Processors where the monitored ports exist in conjunction + with a custom device driver/libpcap back-end.
      +
      +

      + Each IOP will be capable of supporting multiple connections from an SMP + enabling monitoring of more than one interface at a time, each through + its own seperate connection. The IOP is responsible to ensure and report + an error if any attempt is made to monitor the same interface more than once. +

      + There are three applications that will be supported by the ACN version of libpcap. + They each use a slightly different mode for looping/capturing and termination + as summarized in the following table: +

      +

      + + + + + + + + + + + + + + +
      Application Capture Termination
      wiresharkpcap_dispatch(all packets in one buffer of capture only)pcap_breakloop()
      tsharkpcap_dispatch(one buffer of capture only)Since a CTRL-C was used to terminate the application, pcap_breakloop() is never called.
      tcpdumppcap_loop(all packets in the next buffer, and loop forever)pcap_breakloop()
      +
      +

      + Note: In all cases, the termination of capturing is always (apparently) followed by + pcap_close(). Pcap_breakloop() is only used to stop/suspend looping/processing, + and upon close interpretation of the function definitions, it is possible to resume + capturing following a pcap_breakloop() without any re-initialization. +

      +

      ACN Limitations

      +
        +
      1. Monitoring of backup IOPs is not currently supported. +
      2. Ethernet interfaces cannot be monitored in promiscuous mode. +
      + +
    + +

    ROUTINES

    +
      + The following list of functions is the sub-set of Pcap functions that have been + altered/enhanced to support the ACN remote monitoring facility. The remainder of the Pcap + functions continue to perform their duties un-altered. Libpcap only supports this + mode of operation if it has been configured/compiled for SITA/ACN support. +

      +

        + pcap_findalldevs
        + pcap_freealldevs
        + pcap_open_live
        + pcap_close
        + pcap_setfilter
        + pcap_dispatch
        + pcap_loop
        + pcap_next
        + pcap_next_ex
        + pcap_stats
        +
      + + These subroutines have been modified for the ACN specific distributed and remote monitoring + ability perform the following basic functions. More detail is provided in the + "SMP/IOP Inter-Process Communication Protocol" section. +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      pcap_open_live()Used to obtain a packet capture descriptor to look at packets on the network.
      + + + + + + +
      SMP -> IOP + The SMP will open a connection to the selected IOP on its 'sniffer' port + to ensure it is available. It sends a null terminated string identifying + the interface to be monitored. +
      IOP -> SMP + After any required processing is complete, the IOP will return a + null terminated string containing an error message if one occured. + If no error occured, a empty string is still returned. + Errors are: +
        +
      • "Interface (xxx) does not exist." +
      • "Interface (xxx) not configured." +
      • "Interface (xxx) already being monitored." +
      +
      pcap_findalldevs()It constructs a list of network devices that can be opened with pcap_open_live().
      + + + + + + + + + + + + + + + +
      SMP + It obtains a list of IOPs currently available (via /etc/hosts). +
      SMP -> IOP + The SMP will sequentially open a connection to each IOP on its 'sniffer' port to ensure + the IOP is available. + It sends a null terminated empty interface ID followed by the query request command. +
      IOP -> SMPThe IOP returns an error response and its list of devices. +
      SMP -> IOP + The SMP closes the TCP connection with each IOP. +
      SMP + The SMP adds the received information to its internal structure. +
      pcap_freealldevs()Used to free a list allocated by pcap_findalldevs().
      + + + +
      SMP + The SMP frees the structure it built as a result of the previous + invocation of pcap_findalldevs(). +
      pcap_dispatch()Used to collect and process packets.
      + + + + + + + + + + + + +
      SMP -> IOP + On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), + the SMP will pass down the monitor start command and various parameters the IOP should use. +
      IOP -> SMP + The IOP now sends a stream of captured data. +
      SMP + The SMP will read the reverse channel of the connection between the SMP and the + IOP that provides the captured data (via 'p->read_op' which is 'pcap_read_linux()' + until the select() call returns a 'no more data' indication. + It will the process (at most) the next 'cnt' packets and invoke the specified + callback function for each packet processed. +
      IOP + The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP. +
      pcap_loop() + Is similar to pcap_dispatch() except it keeps reading packets until + the requested number of packets are processed or an error occurs. +
      + + + + + + + + + + + + +
      SMP -> IOP + On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), + the SMP will pass down the monitor start command and various parameters the IOP should use. +
      IOP -> SMP + The IOP now sends a stream of captured data. +
      SMP + The SMP continuously reads the next packet from the reverse channel of the connection + between the SMP and the IOP that provides the captured data (via 'p->read_op' + which is 'pcap_read_linux()' until 'cnt' packets have been received. + The specified callback function will be invoked for each packet received. +
      IOP + The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP. +
      pcap_next() + It reads the next packet (by calling pcap_dispatch() with a count of 1) + and returns a pointer to the data in that packet. +
      + + + + + + + + + + + + +
      SMP -> IOP + On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), + the SMP will pass down the monitor start command and various parameters the IOP should use. +
      IOP -> SMP + The IOP now sends a stream of captured data. +
      SMP + The SMP reads only the next packet from the reverse channel of the connection + between the SMP and the IOP that provides the captured data (via calling pcap_dispatch() + with a count of 1) and returns a pointer to that data by invoking an internal callback. +
      IOP + The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP. +
      pcap_next_ex()Reads the next packet and returns a success/failure indication.
      + + + + + + + + + + + + +
      SMP -> IOP + On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), + the SMP will pass down the monitor start command and various parameters the IOP should use. +
      IOP -> SMP + The IOP now sends a stream of captured data. +
      SMP + The SMP reads only the next packet from the reverse channel of the connection + between the SMP and the IOP that provides the captured data (via calling pcap_dispatch() + with a count of 1) and returns seperate pointers to both the + packet header and packet data by invoking an internal callback. +
      IOP + The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP. +
      pcap_setfilter()Used to specify a filter program.
      + + + + + + +
      SMP -> IOP + The SMP sends a 'set filter' command followed by the BPF commands. +
      IOP -> SMP + The IOP returns a null terminated error string if it failed to accept the filter. + If no error occured, then a NULL terminated empty string is returned instead. + Errors are: +
        +
      • "Invalid BPF." +
      • "Insufficient resources for BPF." +
      +
      pcap_stats()Fills in a pcap_stat struct with packet statistics.
      + + + + + + + + + +
      SMP -> IOP + The SMP sends a message to the IOP requesting its statistics. +
      IOP -> SMP + The IOP returns the statistics. +
      SMP + The SMP fills in the structure provided with the information retrieved from the IOP. +
      pcap_close()Closes the file and deallocates resources.
      + + + + + + +
      SMP -> IOP + The SMP closes the file descriptor, and if the descriptor is that of + the comminucation session with an IOP, it too is terminated. +
      IOP + If the IOP detects that its communication session with an SMP + has closed, it will terminate any monitoring in progress, + release any resources and close its end of the session. + It will not maintain persistance of any information or prior mode of operation. +
      +

    + +

    +

    SMP/IOP Inter-Process Communication Protocol

    + +
      +
    • Communications between an SMP and an IOP consists of a TCP session + between an ephemeral port on the SMP and the well known port of 49152 + (which is the first available port in the 'dynamic and/or private port' + range) on an IOP. +

    • Following a TCP open operation the IOP receives a null terminated + 'interface ID' string to determine the type of operation that follows: +

    • Every command received by an IOP implies a 'stop trace/stop forwarding' operation must + occur before executing the received command. +

    • A session is closed when the SMP closes the TCP session with the IOP. + Obviously monitoring and forwarding is also stopped at that time. + + Note: All multi-octet entities are sent in network neutral order. +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      pcap_findalldevs()SMP -> IOPOpen socket (to each IOP), and sends: +

      + + + + + + + + + + + +
      Name/
      Purpose
      Size
      (in bytes)
      Description
      Interface ID1A NULL to indicate an an empty 'interface ID'.
      +

      IOP -> SMPSend its (possibly empty) NULL terminated error response string.
      SMP -> IOPSends the 'interface query request': +

      + + + + + + + + + + + +
      Name/
      Purpose
      Size
      (in bytes)
      Description
      Interface ID1A 'Q' (indicating 'interface query request').
      +

      IOP -> SMPThe IOP returns a list of sequences of information as + defined by the return parameter of this function call (as shown in the following table). + Elements are specified by providing an unsigned byte preceeding the actual data that contains length information. +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Notes:Name/
      Purpose
      Size
      (in bytes)
      Description
       length1The number of octets in the name field that follows.
      Name1-255The name of the interface. The format of the name is an alphabetic string (indicating + the type of interface) followed by an optional numeric string (indicating the interface's + sequence number). + Sequence numbers (if needed) will begin at zero and progress monotonically upwards. + (i.e. 'eth0', 'lo', 'wan0', etc.) +

      + For an IOP, the alphabetic string will be one of: 'eth', 'wan', and 'lo' + for Ethernet, WAN ports and the IP loopback device respectively. + An IOP currently supports: 'eth0', 'eth1', 'lo', 'wan0' ... 'wan7'. +

      + Note: IOPs and ACNs will not currently support the concept of 'any' interface.

      length1The number of octets in the interface description field that follows.
      Interface Description0-255A description of the interface or it may be an empty string. (i.e. 'ALC')
      Interface Type4The type of interface as defined in the description for pcap_datalink() (in network neutral order).
      Loopback Flag11 = if the interface is a loopback interface, zero = otherwise.
      count1# of address entries that follow. + Each entry is a series of bytes in network neutral order. + See the parameter definition above for more details.
      Repeated 'count' number of times.length1The number of octets in the address field that follows.
      Address1-255The address of this interface (in network neutral order).
      length1The number of octets in the netmask field that follows.
      Network Mask0-255The network mask used on this interface (if applicable) (in network neutral order).
      length1The number of octets in the broadcast address field that follows.
      Broadcast Address0-255The broadcast address of this interface (if applicable) (in network neutral order).
      length1The number of octets in the destination address field that follows.
      Destination Address0-255The destination address of this interface (if applicable) (in network neutral order).
      +

      SMP -> IOPClose the socket.
      IOP -> SMPClose the socket.

      pcap_open_live()SMP -> IOPOpen socket, and sends: +

      + + + + + + + + + + + +
      Name/
      Purpose
      Size
      (in bytes)
      Description
      Interface ID'n''n' octets containing a NULL terminated interface name string.
      +

      IOP -> SMPSend its NULL terminated error response string.

      pcap_dispatch()
      pcap_loop()
      pcap_next()
      pcap_next_ex()
      SMP -> IOPOn the first invocation following a pcap_open_live() or pcap_breakloop() additional information is sent: +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Name/
      Purpose
      Size
      (in bytes)
      Description
      command1'M' (indicating 'monitor start')
      snaplen4snaplen
      timeout1timeout value (in milliseconds)
      promiscuous1A flag indicating that the interface being monitored show operate + in promiscuous mode. [off(0) / on(NZ)]
      direction1A flag indicating the direction of traffic that should be captuted [both(0) / in(1) / out(2)]
      +

      IOP -> SMPSends captured packets.

      pcap_setfilter()SMP -> IOPAt any time, the SMP can issue a set filter command which contains + an indicator, a count of the number of statements in the filter, + followed by the sequence of filter commands represented as a sequence + of C-style structures. +

      + + + + + + + + + + + + + + + + + + + + + +
      Name/
      Purpose
      Size
      (in bytes)
      Description
      command1'F' (indicating 'filter')
      count4The number of command in the Berkeley Packet Filter that follow.
      BPF program'n'8 bytes of each command (repeated 'n' times).
      + Each command consists of that C-style structure which contains: +

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Name/
      Purpose
      Size
      (in bytes)
      Description
      opcode2The command's opcode.
      'jt'1The 'jump if true' program counter offset.
      'jf'1The 'jump if false' program counter offset.
      'k'4The 'other' data field.
      +

      + Refer to the bpf(4) man page for more details. +

      +

      IOP -> SMPIn return the IOP will send its (possibly empty) NULL terminated error response string.

      pcap_stats()SMP -> IOPAt any time, the SMP can issue a 'retrieve statistics' command which contains:
      +

      + + + + + + + + + + + +
      Name/
      Purpose
      Size
      (in bytes)
      Description
      command1'S' (indicating 'request statistics')
      +

      IOP -> SMPIn return the IOP will send: +

      + + + + + + + + + + + + + + + + + + + + + +
      Name/
      Purpose
      Size
      (in bytes)
      Description
      ps_recv4The number of packets that passed the filter.
      ps_drop4The number of packets that were dropped because the input queue was full, + regardless of whether they passed the filter.
      ps_ifdrop4The number of packets dropped by the network inteface + (regardless of whether they would have passed the input filter).
      +


      pcap_close()SMP -> IOPAt any time, the SMP can close the TCP session with the IOP.

      +

    + +

    Interface ID Naming Convention

    +
      + Each interface within an IOP will be referred to uniquely. Since an currently contains + 8 monitorable WAN ports and a monitorable Ethernet port, the naming convention is: +

      +

      + + + + + + + + + + + + +
      Interface # Type Name
      1 WAN wan0
      2 WAN wan1
      3 WAN wan2
      4 WAN wan3
      5 WAN wan4
      6 WAN wan5
      7 WAN wan6
      8 WAN wan7
      9 Ethernet eth0
      10 Ethernet eth1
      +
      +
    + +

    Packet Trace Data Format

    +
      + The format of the trace data that is sent to the SMP follows a portion of the libpcap file format + and is summarized here. This format specifies the generic requirements needed to + be able to decode packets, but does not cover ACN specifics such as custom MAC addressing + and WAN protocol support. +

      + + Although a libpcap file begins with a global header followed by zero or + more records for each captured packet, trace data sent to the SMP does NOT begin with a global header. + A trace sequence looks like this: +

      + + + + + + + + + + +
       [Packet Header]  [Packet Data]  [Packet Header]  [Packet Data]  [Packet Header]  [Packet Data] ...
      + +

      Packet Header

      +
        + Each captured packet starts with a header that contains the following values + (in network neutral order): + + +
        + uint32 tv_sec;  /* timestamp seconds */
        + uint32 tv_usec; /* timestamp microseconds */
        + uint32 caplen;  /* number of octets in the following packet */
        + uint32 len;     /* original length of packet on the wire */
        +		
        +
        + + + + + + + + + + + + + + + + + + +
        tv_secThe date and time when this packet was captured. + This value is in seconds since January 1, 1970 00:00:00 GMT; + this is also known as a UN*X time_t. You can use the ANSI C + time() function from time.h to get this value, + but you might use a more optimized way to get this timestamp value. + If this timestamp isn't based on GMT (UTC), use thiszone + from the global header for adjustments.
        tv_usecThe microseconds when this packet was captured, as an offset to ts_sec. + Beware: this value must never reach 1 second (1,000,000), + in this case ts_sec must be increased instead!
        caplenThe number of bytes actually provided in the capture record. + This value should never become larger than len or the + snaplen value specified during the capture.
        lenThe length of the packet "on the wire" when it was captured. + If caplen and len differ, the actually + saved packet size was limited by the value of snaplen specified + during one of the capture directives such as pcap_dispatch().
        +
      + +

      Packet Data

      +
        + The actual packet data will immediately follow the packet header as a sequence of caplen octets. + Depending on the DLT encoding number assigned to the interface, the packet data will contain an additional + custom header used to convey WAN port related information. +
      + +

      ACN Custom Packet Header

      +
        + PCAP, Wireshark and Tcpdump enhancements have been added to the ACN to support + monitoring of its ports, however each of these facilities were focused on capturing + and displaying traffic from LAN interfaces. The SITA extentions to these facilities + are used to also provide the ability to capture, filter, and display information from + an ACN's WAN ports. +

        + Although each packet follows the standard libpcap format, since there are + two types of interfaces that can be monitored, the format of the data + packet varies slightly. +

        +

          +
        • For Ethernet (like) devices, the packet format is unchanged from the standard Pcap format. +
        • For WAN devices, the packet contains a 5 byte header that preceeds the actual captured data + described by the following table: +
        +

        +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        OctetNameMask/ValueDefinition
        0Control / Statusxxxxxxx0Transmitted by capture device(see 'Errors' octets)
        xxxxxxx1Received by capture device
        1xxxxxxxNo buffer was available during capture of previous packet.
        1Signalsxxxxxxx1 DSR asserted
        xxxxxx1x DTR asserted
        xxxxx1xx CTS asserted
        xxxx1xxx RTS asserted
        xxx1xxxx DCD asserted
        xx1xxxxx Undefined
        x1xxxxxx Undefined
        1xxxxxxx Undefined
        2Errors
        (octet 1)
          Tx Rx
        xxxxxxx1 Underrun Framing
        xxxxxx1x CTS Lost Parity
        xxxxx1xx UART Error Collision
        xxxx1xxx Re-Tx Limit Reached Long Frame
        xxx1xxxx Undefined Short Frame
        xx1xxxxx Undefined Undefined
        x1xxxxxx Undefined Undefined
        1xxxxxxx Undefined Undefined
        3Errors
        (octet 2)
          Tx Rx
        xxxxxxx1 Undefined Non-Octet Aligned
        xxxxxx1x Undefined Abort Received
        xxxxx1xx Undefined CD Lost
        xxxx1xxx Undefined Digital PLL Error
        xxx1xxxx Undefined Overrun
        xx1xxxxx Undefined Frame Length Violation
        x1xxxxxx Undefined CRC Error
        1xxxxxxx Undefined Break Received
        4Protocol +
        + + + + + + + + + + + + + +
        0x01 - LAPB (BOP)  
        0x02 - Ethernet 1
        0x03 - Async (Interrupt IO)  
        0x04 - Async (Block IO)  
        0x05 - IPARS  
        0x06 - UTS  
        0x07 - PPP (HDLC)  
        0x08 - SDLC  
        0x09 - Token Ring 1
        0x10 - I2C  
        0x11 - DPM Link  
        0x12 - Frame Relay (BOP)  
        +
        +

        + Note 1: + Ethernet and Token Ring frames will never be sent as DLT_SITA (with the 5 octet header), + but will be sent as their corresponding DLT types instead. +

        +
        +
      +

      +

    + diff --git a/tcpdump/jni/libpcap/pcap-snf.c b/tcpdump/jni/libpcap/pcap-snf.c new file mode 100644 index 0000000..03dc08d --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-snf.c @@ -0,0 +1,497 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#if SNF_VERSION_API >= 0x0003 +#define SNF_HAVE_INJECT_API +#endif + +#include "pcap-int.h" +#include "pcap-snf.h" + +/* + * Private data for capturing on SNF devices. + */ +struct pcap_snf { + snf_handle_t snf_handle; /* opaque device handle */ + snf_ring_t snf_ring; /* opaque device ring handle */ +#ifdef SNF_HAVE_INJECT_API + snf_inject_t snf_inj; /* inject handle, if inject is used */ +#endif + int snf_timeout; + int snf_boardnum; +}; + +static int +snf_set_datalink(pcap_t *p, int dlt) +{ + p->linktype = dlt; + return (0); +} + +static int +snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) +{ + struct snf_ring_stats stats; + struct pcap_snf *snfps = p->priv; + int rc; + + if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s", + pcap_strerror(rc)); + return -1; + } + ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; + ps->ps_drop = stats.ring_pkt_overflow; + ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; + return 0; +} + +static void +snf_platform_cleanup(pcap_t *p) +{ + struct pcap_snf *ps = p->priv; + + if (p == NULL) + return; + +#ifdef SNF_HAVE_INJECT_API + if (ps->snf_inj) + snf_inject_close(ps->snf_inj); +#endif + snf_ring_close(ps->snf_ring); + snf_close(ps->snf_handle); + pcap_cleanup_live_common(p); +} + +static int +snf_getnonblock(pcap_t *p, char *errbuf) +{ + struct pcap_snf *ps = p->priv; + + return (ps->snf_timeout == 0); +} + +static int +snf_setnonblock(pcap_t *p, int nonblock, char *errbuf) +{ + struct pcap_snf *ps = p->priv; + + if (nonblock) + ps->snf_timeout = 0; + else { + if (p->opt.timeout <= 0) + ps->snf_timeout = -1; /* forever */ + else + ps->snf_timeout = p->opt.timeout; + } + return (0); +} + +#define _NSEC_PER_SEC 1000000000 + +static inline +struct timeval +snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision) +{ + struct timeval tv; + long tv_nsec; + + if (ts_nanosec == 0) + return (struct timeval) { 0, 0 }; + + tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; + tv_nsec = (ts_nanosec % _NSEC_PER_SEC); + + /* libpcap expects tv_usec to be nanos if using nanosecond precision. */ + if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) + tv.tv_usec = tv_nsec; + else + tv.tv_usec = tv_nsec / 1000; + + return tv; +} + +static int +snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_snf *ps = p->priv; + struct pcap_pkthdr hdr; + int i, flags, err, caplen, n; + struct snf_recv_req req; + int nonblock, timeout; + + if (!p) + return -1; + + n = 0; + timeout = ps->snf_timeout; + while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + return (n); + } + } + + err = snf_ring_recv(ps->snf_ring, timeout, &req); + + if (err) { + if (err == EBUSY || err == EAGAIN) { + return (n); + } + else if (err == EINTR) { + timeout = 0; + continue; + } + else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", + pcap_strerror(err)); + return -1; + } + } + + caplen = req.length; + if (caplen > p->snapshot) + caplen = p->snapshot; + + if ((p->fcode.bf_insns == NULL) || + bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { + hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); + hdr.caplen = caplen; + hdr.len = req.length; + callback(user, &hdr, req.pkt_addr); + } + n++; + + /* After one successful packet is received, we won't block + * again for that timeout. */ + if (timeout != 0) + timeout = 0; + } + return (n); +} + +static int +snf_setfilter(pcap_t *p, struct bpf_program *fp) +{ + if (!p) + return -1; + if (!fp) { + strncpy(p->errbuf, "setfilter: No filter specified", + sizeof(p->errbuf)); + return -1; + } + + /* Make our private copy of the filter */ + + if (install_bpf_program(p, fp) < 0) + return -1; + + return (0); +} + +static int +snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) +{ +#ifdef SNF_HAVE_INJECT_API + struct pcap_snf *ps = p->priv; + int rc; + if (ps->snf_inj == NULL) { + rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); + if (rc) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snf_inject_open: %s", pcap_strerror(rc)); + return (-1); + } + } + + rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); + if (!rc) { + return (size); + } + else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_inject_send: %s", + pcap_strerror(rc)); + return (-1); + } +#else + strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", + PCAP_ERRBUF_SIZE); + return (-1); +#endif +} + +static int +snf_activate(pcap_t* p) +{ + struct pcap_snf *ps = p->priv; + char *device = p->opt.source; + const char *nr = NULL; + int err; + int flags = -1, ring_id = -1; + + if (device == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "device is NULL: %s", pcap_strerror(errno)); + return -1; + } + + /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. + * Since libpcap isn't thread-safe */ + if ((nr = getenv("SNF_FLAGS")) && *nr) + flags = strtol(nr, NULL, 0); + else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) + flags = SNF_F_PSHARED; + else + nr = NULL; + + err = snf_open(ps->snf_boardnum, + 0, /* let SNF API parse SNF_NUM_RINGS, if set */ + NULL, /* default RSS, or use SNF_RSS_FLAGS env */ + 0, /* default to SNF_DATARING_SIZE from env */ + flags, /* may want pshared */ + &ps->snf_handle); + if (err != 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snf_open failed: %s", pcap_strerror(err)); + return -1; + } + + if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { + ring_id = (int) strtol(nr, NULL, 0); + } + err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); + if (err != 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snf_ring_open_id(ring=%d) failed: %s", + ring_id, pcap_strerror(err)); + return -1; + } + + if (p->opt.timeout <= 0) + ps->snf_timeout = -1; + else + ps->snf_timeout = p->opt.timeout; + + err = snf_start(ps->snf_handle); + if (err != 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snf_start failed: %s", pcap_strerror(err)); + return -1; + } + + /* + * "select()" and "poll()" don't work on snf descriptors. + */ + p->selectable_fd = -1; + p->linktype = DLT_EN10MB; + p->read_op = snf_read; + p->inject_op = snf_inject; + p->setfilter_op = snf_setfilter; + p->setdirection_op = NULL; /* Not implemented.*/ + p->set_datalink_op = snf_set_datalink; + p->getnonblock_op = snf_getnonblock; + p->setnonblock_op = snf_setnonblock; + p->stats_op = snf_pcap_stats; + p->cleanup_op = snf_platform_cleanup; +#ifdef SNF_HAVE_INJECT_API + ps->snf_inj = NULL; +#endif + return 0; +} + +#define MAX_DESC_LENGTH 128 +int +snf_findalldevs(pcap_if_t **devlistp, char *errbuf) +{ + pcap_if_t *devlist = NULL,*curdev,*prevdev; + pcap_addr_t *curaddr; + struct snf_ifaddrs *ifaddrs, *ifa; + char desc[MAX_DESC_LENGTH]; + int ret; + + if (snf_init(SNF_VERSION_API)) + return (-1); + + if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) + { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_getifaddrs: %s", pcap_strerror(errno)); + return (-1); + } + ifa = ifaddrs; + while (ifa) + { + /* + * Allocate a new entry + */ + curdev = (pcap_if_t *)malloc(sizeof(pcap_if_t)); + if (curdev == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_findalldevs malloc: %s", pcap_strerror(errno)); + return (-1); + } + if (devlist == NULL) /* save first entry */ + devlist = curdev; + else + prevdev->next = curdev; + /* + * Fill in the entry. + */ + curdev->next = NULL; + curdev->name = strdup(ifa->snf_ifa_name); + if (curdev->name == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_findalldevs strdup: %s", pcap_strerror(errno)); + free(curdev); + return (-1); + } + (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom snf%d", + ifa->snf_ifa_portnum); + curdev->description = strdup(desc); + if (curdev->description == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_findalldevs strdup1: %s", pcap_strerror(errno)); + free(curdev->name); + free(curdev); + return (-1); + } + curdev->addresses = NULL; + curdev->flags = 0; + + curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t)); + if (curaddr == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_findalldevs malloc1: %s", pcap_strerror(errno)); + free(curdev->description); + free(curdev->name); + free(curdev); + return (-1); + } + curdev->addresses = curaddr; + curaddr->next = NULL; + curaddr->addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage)); + if (curaddr->addr == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc2: %s", pcap_strerror(errno)); + free(curdev->description); + free(curdev->name); + free(curaddr); + free(curdev); + return (-1); + } + curaddr->addr->sa_family = AF_INET; + curaddr->netmask = NULL; + curaddr->broadaddr = NULL; + curaddr->dstaddr = NULL; + curaddr->next = NULL; + + prevdev = curdev; + ifa = ifa->snf_ifa_next; + } + snf_freeifaddrs(ifaddrs); + *devlistp = devlist; + + /* + * There are no platform-specific devices since each device + * exists as a regular Ethernet device. + */ + return 0; +} + +pcap_t * +snf_create(const char *device, char *ebuf, int *is_ours) +{ + pcap_t *p; + int boardnum = -1; + struct snf_ifaddrs *ifaddrs, *ifa; + size_t devlen; + struct pcap_snf *ps; + + if (snf_init(SNF_VERSION_API)) { + /* Can't initialize the API, so no SNF devices */ + *is_ours = 0; + return NULL; + } + + /* + * Match a given interface name to our list of interface names, from + * which we can obtain the intended board number + */ + if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { + /* Can't get SNF addresses */ + *is_ours = 0; + return NULL; + } + devlen = strlen(device) + 1; + ifa = ifaddrs; + while (ifa) { + if (!strncmp(device, ifa->snf_ifa_name, devlen)) { + boardnum = ifa->snf_ifa_boardnum; + break; + } + ifa = ifa->snf_ifa_next; + } + snf_freeifaddrs(ifaddrs); + + if (ifa == NULL) { + /* + * If we can't find the device by name, support the name "snfX" + * and "snf10gX" where X is the board number. + */ + if (sscanf(device, "snf10g%d", &boardnum) != 1 && + sscanf(device, "snf%d", &boardnum) != 1) { + /* Nope, not a supported name */ + *is_ours = 0; + return NULL; + } + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_snf)); + if (p == NULL) + return NULL; + ps = p->priv; + + /* + * We support microsecond and nanosecond time stamps. + */ + p->tstamp_precision_count = 2; + p->tstamp_precision_list = malloc(2 * sizeof(u_int)); + if (p->tstamp_precision_list == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + if (p->tstamp_type_list != NULL) + free(p->tstamp_type_list); + free(p); + return NULL; + } + p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; + p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; + + p->activate_op = snf_activate; + ps->snf_boardnum = boardnum; + return p; +} diff --git a/tcpdump/jni/libpcap/pcap-snf.h b/tcpdump/jni/libpcap/pcap-snf.h new file mode 100644 index 0000000..c9d7722 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-snf.h @@ -0,0 +1,2 @@ +pcap_t *snf_create(const char *, char *, int *); +int snf_findalldevs(pcap_if_t **devlistp, char *errbuf); diff --git a/tcpdump/jni/libpcap/pcap-snit.c b/tcpdump/jni/libpcap/pcap-snit.c new file mode 100644 index 0000000..0ce7860 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-snit.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Modifications made to accommodate the new SunOS4.0 NIT facility by + * Micky Liu, micky@cunixc.cc.columbia.edu, Columbia University in May, 1989. + * This module now handles the STREAMS based NIT. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * The chunk size for NIT. This is the amount of buffering + * done for read calls. + */ +#define CHUNKSIZE (2*1024) + +/* + * The total buffer space used by NIT. + */ +#define BUFSPACE (4*CHUNKSIZE) + +/* Forwards */ +static int nit_setflags(int, int, int, char *); + +/* + * Private data for capturing on STREAMS NIT devices. + */ +struct pcap_snit { + struct pcap_stat stat; +}; + +static int +pcap_stats_snit(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_snit *psn = p->priv; + + /* + * "ps_recv" counts packets handed to the filter, not packets + * that passed the filter. As filtering is done in userland, + * this does not include packets dropped because we ran out + * of buffer space. + * + * "ps_drop" counts packets dropped inside the "/dev/nit" + * device because of flow control requirements or resource + * exhaustion; it doesn't count packets dropped by the + * interface driver, or packets dropped upstream. As filtering + * is done in userland, it counts packets regardless of whether + * they would've passed the filter. + * + * These statistics don't include packets not yet read from the + * kernel by libpcap or packets not yet read from libpcap by the + * application. + */ + *ps = psn->stat; + return (0); +} + +static int +pcap_read_snit(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_snit *psn = p->priv; + register int cc, n; + register u_char *bp, *cp, *ep; + register struct nit_bufhdr *hdrp; + register struct nit_iftime *ntp; + register struct nit_iflen *nlp; + register struct nit_ifdrops *ndp; + register int caplen; + + cc = p->cc; + if (cc == 0) { + cc = read(p->fd, (char *)p->buffer, p->bufsize); + if (cc < 0) { + if (errno == EWOULDBLOCK) + return (0); + snprintf(p->errbuf, sizeof(p->errbuf), "pcap_read: %s", + pcap_strerror(errno)); + return (-1); + } + bp = p->buffer; + } else + bp = p->bp; + + /* + * loop through each snapshot in the chunk + */ + n = 0; + ep = bp + cc; + while (bp < ep) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->bp = bp; + p->cc = ep - bp; + return (n); + } + } + + ++psn->stat.ps_recv; + cp = bp; + + /* get past NIT buffer */ + hdrp = (struct nit_bufhdr *)cp; + cp += sizeof(*hdrp); + + /* get past NIT timer */ + ntp = (struct nit_iftime *)cp; + cp += sizeof(*ntp); + + ndp = (struct nit_ifdrops *)cp; + psn->stat.ps_drop = ndp->nh_drops; + cp += sizeof *ndp; + + /* get past packet len */ + nlp = (struct nit_iflen *)cp; + cp += sizeof(*nlp); + + /* next snapshot */ + bp += hdrp->nhb_totlen; + + caplen = nlp->nh_pktlen; + if (caplen > p->snapshot) + caplen = p->snapshot; + + if (bpf_filter(p->fcode.bf_insns, cp, nlp->nh_pktlen, caplen)) { + struct pcap_pkthdr h; + h.ts = ntp->nh_timestamp; + h.len = nlp->nh_pktlen; + h.caplen = caplen; + (*callback)(user, &h, cp); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + p->cc = ep - bp; + p->bp = bp; + return (n); + } + } + } + p->cc = 0; + return (n); +} + +static int +pcap_inject_snit(pcap_t *p, const void *buf, size_t size) +{ + struct strbuf ctl, data; + + /* + * XXX - can we just do + * + ret = write(pd->f, buf, size); + */ + ctl.len = sizeof(*sa); /* XXX - what was this? */ + ctl.buf = (char *)sa; + data.buf = buf; + data.len = size; + ret = putmsg(p->fd, &ctl, &data); + if (ret == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", + pcap_strerror(errno)); + return (-1); + } + return (ret); +} + +static int +nit_setflags(pcap_t *p) +{ + bpf_u_int32 flags; + struct strioctl si; + u_int zero = 0; + struct timeval timeout; + + if (p->opt.immediate) { + /* + * Set the chunk size to zero, so that chunks get sent + * up immediately. + */ + si.ic_cmd = NIOCSCHUNK; + si.ic_len = sizeof(zero); + si.ic_dp = (char *)&zero; + if (ioctl(p->fd, I_STR, (char *)&si) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSCHUNK: %s", + pcap_strerror(errno)); + return (-1); + } + } + si.ic_timout = INFTIM; + if (p->opt.timeout != 0) { + timeout.tv_sec = p->opt.timeout / 1000; + timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; + si.ic_cmd = NIOCSTIME; + si.ic_len = sizeof(timeout); + si.ic_dp = (char *)&timeout; + if (ioctl(p->fd, I_STR, (char *)&si) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSTIME: %s", + pcap_strerror(errno)); + return (-1); + } + } + flags = NI_TIMESTAMP | NI_LEN | NI_DROPS; + if (p->opt.promisc) + flags |= NI_PROMISC; + si.ic_cmd = NIOCSFLAGS; + si.ic_len = sizeof(flags); + si.ic_dp = (char *)&flags; + if (ioctl(p->fd, I_STR, (char *)&si) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSFLAGS: %s", + pcap_strerror(errno)); + return (-1); + } + return (0); +} + +static int +pcap_activate_snit(pcap_t *p) +{ + struct strioctl si; /* struct for ioctl() */ + struct ifreq ifr; /* interface request struct */ + int chunksize = CHUNKSIZE; + int fd; + static char dev[] = "/dev/nit"; + + if (p->opt.rfmon) { + /* + * No monitor mode on SunOS 4.x (no Wi-Fi devices on + * hardware supported by SunOS 4.x). + */ + return (PCAP_ERROR_RFMON_NOTSUP); + } + + if (p->snapshot < 96) + /* + * NIT requires a snapshot length of at least 96. + */ + p->snapshot = 96; + + /* + * Initially try a read/write open (to allow the inject + * method to work). If that fails due to permission + * issues, fall back to read-only. This allows a + * non-root user to be granted specific access to pcap + * capabilities via file permissions. + * + * XXX - we should have an API that has a flag that + * controls whether to open read-only or read-write, + * so that denial of permission to send (or inability + * to send, if sending packets isn't supported on + * the device in question) can be indicated at open + * time. + */ + p->fd = fd = open(dev, O_RDWR); + if (fd < 0 && errno == EACCES) + p->fd = fd = open(dev, O_RDONLY); + if (fd < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dev, + pcap_strerror(errno)); + goto bad; + } + + /* arrange to get discrete messages from the STREAM and use NIT_BUF */ + if (ioctl(fd, I_SRDOPT, (char *)RMSGD) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "I_SRDOPT: %s", + pcap_strerror(errno)); + goto bad; + } + if (ioctl(fd, I_PUSH, "nbuf") < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "push nbuf: %s", + pcap_strerror(errno)); + goto bad; + } + /* set the chunksize */ + si.ic_cmd = NIOCSCHUNK; + si.ic_timout = INFTIM; + si.ic_len = sizeof(chunksize); + si.ic_dp = (char *)&chunksize; + if (ioctl(fd, I_STR, (char *)&si) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSCHUNK: %s", + pcap_strerror(errno)); + goto bad; + } + + /* request the interface */ + strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name)); + ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; + si.ic_cmd = NIOCBIND; + si.ic_len = sizeof(ifr); + si.ic_dp = (char *)𝔦 + if (ioctl(fd, I_STR, (char *)&si) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCBIND: %s: %s", + ifr.ifr_name, pcap_strerror(errno)); + goto bad; + } + + /* set the snapshot length */ + si.ic_cmd = NIOCSSNAP; + si.ic_len = sizeof(p->snapshot); + si.ic_dp = (char *)&p->snapshot; + if (ioctl(fd, I_STR, (char *)&si) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSSNAP: %s", + pcap_strerror(errno)); + goto bad; + } + if (nit_setflags(p) < 0) + goto bad; + + (void)ioctl(fd, I_FLUSH, (char *)FLUSHR); + /* + * NIT supports only ethernets. + */ + p->linktype = DLT_EN10MB; + + p->bufsize = BUFSPACE; + p->buffer = (u_char *)malloc(p->bufsize); + if (p->buffer == NULL) { + strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); + goto bad; + } + + /* + * "p->fd" is an FD for a STREAMS device, so "select()" and + * "poll()" should work on it. + */ + p->selectable_fd = p->fd; + + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (p->dlt_list != NULL) { + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + } + + p->read_op = pcap_read_snit; + p->inject_op = pcap_inject_snit; + p->setfilter_op = install_bpf_program; /* no kernel filtering */ + p->setdirection_op = NULL; /* Not implemented. */ + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcap_getnonblock_fd; + p->setnonblock_op = pcap_setnonblock_fd; + p->stats_op = pcap_stats_snit; + + return (0); + bad: + pcap_cleanup_live_common(p); + return (PCAP_ERROR); +} + +pcap_t * +pcap_create_interface(const char *device, char *ebuf) +{ + pcap_t *p; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_snit)); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_snit; + return (p); +} + +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + return (0); +} diff --git a/tcpdump/jni/libpcap/pcap-snoop.c b/tcpdump/jni/libpcap/pcap-snoop.c new file mode 100644 index 0000000..f622f31 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-snoop.c @@ -0,0 +1,418 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * Private data for capturing on snoop devices. + */ +struct pcap_snoop { + struct pcap_stat stat; +}; + +static int +pcap_read_snoop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_snoop *psn = p->priv; + int cc; + register struct snoopheader *sh; + register u_int datalen; + register u_int caplen; + register u_char *cp; + +again: + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return -2 to indicate that we were + * told to break out of the loop. + */ + p->break_loop = 0; + return (-2); + } + cc = read(p->fd, (char *)p->buffer, p->bufsize); + if (cc < 0) { + /* Don't choke when we get ptraced */ + switch (errno) { + + case EINTR: + goto again; + + case EWOULDBLOCK: + return (0); /* XXX */ + } + snprintf(p->errbuf, sizeof(p->errbuf), + "read: %s", pcap_strerror(errno)); + return (-1); + } + sh = (struct snoopheader *)p->buffer; + datalen = sh->snoop_packetlen; + + /* + * XXX - Sigh, snoop_packetlen is a 16 bit quantity. If we + * got a short length, but read a full sized snoop pakcet, + * assume we overflowed and add back the 64K... + */ + if (cc == (p->snapshot + sizeof(struct snoopheader)) && + (datalen < p->snapshot)) + datalen += (64 * 1024); + + caplen = (datalen < p->snapshot) ? datalen : p->snapshot; + cp = (u_char *)(sh + 1) + p->offset; /* XXX */ + + /* + * XXX unfortunately snoop loopback isn't exactly like + * BSD's. The address family is encoded in the first 2 + * bytes rather than the first 4 bytes! Luckily the last + * two snoop loopback bytes are zeroed. + */ + if (p->linktype == DLT_NULL && *((short *)(cp + 2)) == 0) { + u_int *uip = (u_int *)cp; + *uip >>= 16; + } + + if (p->fcode.bf_insns == NULL || + bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) { + struct pcap_pkthdr h; + ++psn->stat.ps_recv; + h.ts.tv_sec = sh->snoop_timestamp.tv_sec; + h.ts.tv_usec = sh->snoop_timestamp.tv_usec; + h.len = datalen; + h.caplen = caplen; + (*callback)(user, &h, cp); + return (1); + } + return (0); +} + +static int +pcap_inject_snoop(pcap_t *p, const void *buf, size_t size) +{ + int ret; + + /* + * XXX - libnet overwrites the source address with what I + * presume is the interface's address; is that required? + */ + ret = write(p->fd, buf, size); + if (ret == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", + pcap_strerror(errno)); + return (-1); + } + return (ret); +} + +static int +pcap_stats_snoop(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_snoop *psn = p->priv; + register struct rawstats *rs; + struct rawstats rawstats; + + rs = &rawstats; + memset(rs, 0, sizeof(*rs)); + if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) { + snprintf(p->errbuf, sizeof(p->errbuf), + "SIOCRAWSTATS: %s", pcap_strerror(errno)); + return (-1); + } + + /* + * "ifdrops" are those dropped by the network interface + * due to resource shortages or hardware errors. + * + * "sbdrops" are those dropped due to socket buffer limits. + * + * As filter is done in userland, "sbdrops" counts packets + * regardless of whether they would've passed the filter. + * + * XXX - does this count *all* Snoop or Drain sockets, + * rather than just this socket? If not, why does it have + * both Snoop and Drain statistics? + */ + psn->stat.ps_drop = + rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops + + rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops; + + /* + * "ps_recv" counts only packets that passed the filter. + * As filtering is done in userland, this does not include + * packets dropped because we ran out of buffer space. + */ + *ps = psn->stat; + return (0); +} + +/* XXX can't disable promiscuous */ +static int +pcap_activate_snoop(pcap_t *p) +{ + int fd; + struct sockaddr_raw sr; + struct snoopfilter sf; + u_int v; + int ll_hdrlen; + int snooplen; + struct ifreq ifr; + + fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP); + if (fd < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop socket: %s", + pcap_strerror(errno)); + goto bad; + } + p->fd = fd; + memset(&sr, 0, sizeof(sr)); + sr.sr_family = AF_RAW; + (void)strncpy(sr.sr_ifname, p->opt.source, sizeof(sr.sr_ifname)); + if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop bind: %s", + pcap_strerror(errno)); + goto bad; + } + memset(&sf, 0, sizeof(sf)); + if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCADDSNOOP: %s", + pcap_strerror(errno)); + goto bad; + } + if (p->opt.buffer_size != 0) + v = p->opt.buffer_size; + else + v = 64 * 1024; /* default to 64K buffer size */ + (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v)); + /* + * XXX hack - map device name to link layer type + */ + if (strncmp("et", p->opt.source, 2) == 0 || /* Challenge 10 Mbit */ + strncmp("ec", p->opt.source, 2) == 0 || /* Indigo/Indy 10 Mbit, + O2 10/100 */ + strncmp("ef", p->opt.source, 2) == 0 || /* O200/2000 10/100 Mbit */ + strncmp("eg", p->opt.source, 2) == 0 || /* Octane/O2xxx/O3xxx Gigabit */ + strncmp("gfe", p->opt.source, 3) == 0 || /* GIO 100 Mbit */ + strncmp("fxp", p->opt.source, 3) == 0 || /* Challenge VME Enet */ + strncmp("ep", p->opt.source, 2) == 0 || /* Challenge 8x10 Mbit EPLEX */ + strncmp("vfe", p->opt.source, 3) == 0 || /* Challenge VME 100Mbit */ + strncmp("fa", p->opt.source, 2) == 0 || + strncmp("qaa", p->opt.source, 3) == 0 || + strncmp("cip", p->opt.source, 3) == 0 || + strncmp("el", p->opt.source, 2) == 0) { + p->linktype = DLT_EN10MB; + p->offset = RAW_HDRPAD(sizeof(struct ether_header)); + ll_hdrlen = sizeof(struct ether_header); + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + * + * XXX - are there any sorts of "fake Ethernet" that have + * Ethernet link-layer headers but that *shouldn't offer + * DLT_DOCSIS as a Cisco CMTS won't put traffic onto it + * or get traffic bridged onto it? "el" is for ATM LANE + * Ethernet devices, so that might be the case for them; + * the same applies for "qaa" classical IP devices. If + * "fa" devices are for FORE SPANS, that'd apply to them + * as well; what are "cip" devices - some other ATM + * Classical IP devices? + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (p->dlt_list != NULL) { + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + } + } else if (strncmp("ipg", p->opt.source, 3) == 0 || + strncmp("rns", p->opt.source, 3) == 0 || /* O2/200/2000 FDDI */ + strncmp("xpi", p->opt.source, 3) == 0) { + p->linktype = DLT_FDDI; + p->offset = 3; /* XXX yeah? */ + ll_hdrlen = 13; + } else if (strncmp("ppp", p->opt.source, 3) == 0) { + p->linktype = DLT_RAW; + ll_hdrlen = 0; /* DLT_RAW meaning "no PPP header, just the IP packet"? */ + } else if (strncmp("qfa", p->opt.source, 3) == 0) { + p->linktype = DLT_IP_OVER_FC; + ll_hdrlen = 24; + } else if (strncmp("pl", p->opt.source, 2) == 0) { + p->linktype = DLT_RAW; + ll_hdrlen = 0; /* Cray UNICOS/mp pseudo link */ + } else if (strncmp("lo", p->opt.source, 2) == 0) { + p->linktype = DLT_NULL; + ll_hdrlen = 4; + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snoop: unknown physical layer type"); + goto bad; + } + + if (p->opt.rfmon) { + /* + * No monitor mode on Irix (no Wi-Fi devices on + * hardware supported by Irix). + */ + return (PCAP_ERROR_RFMON_NOTSUP); + } + +#ifdef SIOCGIFMTU + /* + * XXX - IRIX appears to give you an error if you try to set the + * capture length to be greater than the MTU, so let's try to get + * the MTU first and, if that succeeds, trim the snap length + * to be no greater than the MTU. + */ + (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s", + pcap_strerror(errno)); + goto bad; + } + /* + * OK, we got it. + * + * XXX - some versions of IRIX 6.5 define "ifr_mtu" and have an + * "ifru_metric" member of the "ifr_ifru" union in an "ifreq" + * structure, others don't. + * + * I've no idea what's going on, so, if "ifr_mtu" isn't defined, + * we define it as "ifr_metric", as using that field appears to + * work on the versions that lack "ifr_mtu" (and, on those that + * don't lack it, "ifru_metric" and "ifru_mtu" are both "int" + * members of the "ifr_ifru" union, which suggests that they + * may be interchangeable in this case). + */ +#ifndef ifr_mtu +#define ifr_mtu ifr_metric +#endif + if (p->snapshot > ifr.ifr_mtu + ll_hdrlen) + p->snapshot = ifr.ifr_mtu + ll_hdrlen; +#endif + + /* + * The argument to SIOCSNOOPLEN is the number of link-layer + * payload bytes to capture - it doesn't count link-layer + * header bytes. + */ + snooplen = p->snapshot - ll_hdrlen; + if (snooplen < 0) + snooplen = 0; + if (ioctl(fd, SIOCSNOOPLEN, &snooplen) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPLEN: %s", + pcap_strerror(errno)); + goto bad; + } + v = 1; + if (ioctl(fd, SIOCSNOOPING, &v) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPING: %s", + pcap_strerror(errno)); + goto bad; + } + + p->bufsize = 4096; /* XXX */ + p->buffer = (u_char *)malloc(p->bufsize); + if (p->buffer == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + goto bad; + } + + /* + * "p->fd" is a socket, so "select()" should work on it. + */ + p->selectable_fd = p->fd; + + p->read_op = pcap_read_snoop; + p->inject_op = pcap_inject_snoop; + p->setfilter_op = install_bpf_program; /* no kernel filtering */ + p->setdirection_op = NULL; /* Not implemented. */ + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcap_getnonblock_fd; + p->setnonblock_op = pcap_setnonblock_fd; + p->stats_op = pcap_stats_snoop; + + return (0); + bad: + pcap_cleanup_live_common(p); + return (PCAP_ERROR); +} + +pcap_t * +pcap_create_interface(const char *device, char *ebuf) +{ + pcap_t *p; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_snoop)); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_snoop; + return (p); +} + +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + return (0); +} diff --git a/tcpdump/jni/libpcap/pcap-stdinc.h b/tcpdump/jni/libpcap/pcap-stdinc.h new file mode 100644 index 0000000..f70dcce --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-stdinc.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef pcap_stdinc_h +#define pcap_stdinc_h + +/* + * Avoids a compiler warning in case this was already defined + * (someone defined _WINSOCKAPI_ when including 'windows.h', in order + * to prevent it from including 'winsock.h') + */ +#ifdef _WINSOCKAPI_ +#undef _WINSOCKAPI_ +#endif + +#include +#include +#include +#include + +#include "bittypes.h" +#include "IP6_misc.h" + +#define caddr_t char* + +#if defined(_MSC_VER) + #define snprintf _snprintf + #define vsnprintf _vsnprintf + #define strdup _strdup +#endif + +#define inline __inline + +#ifdef __MINGW32__ + #include +#else + #ifndef _UINTPTR_T_DEFINED + #ifdef _WIN64 + typedef unsigned __int64 uintptr_t; + #else + typedef _W64 unsigned int uintptr_t; + #endif + #define _UINTPTR_T_DEFINED + #endif + + #ifndef _INTPTR_T_DEFINED + #ifdef _WIN64 + typedef __int64 intptr_t; + #else + typedef _W64 int intptr_t; + #endif + #define _INTPTR_T_DEFINED + #endif +#endif /*__MINGW32__*/ + +#endif /* pcap_stdinc_h */ diff --git a/tcpdump/jni/libpcap/pcap-tstamp.manmisc.in b/tcpdump/jni/libpcap/pcap-tstamp.manmisc.in new file mode 100644 index 0000000..74a9a35 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-tstamp.manmisc.in @@ -0,0 +1,175 @@ +.\" +.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP-TSTAMP @MAN_MISC_INFO@ "21 December 2013" +.SH NAME +pcap-tstamp \- packet time stamps in libpcap +.SH DESCRIPTION +When capturing traffic, each packet is given a time stamp representing, +for incoming packets, the arrival time of the packet and, for outgoing +packets, the transmission time of the packet. This time is an +approximation of the arrival or transmission time. If it is supplied by +the operating system running on the host on which the capture is being +done, there are several reasons why it might not precisely represent the +arrival or transmission time: +.IP +if the time stamp is applied to the packet when the networking stack +receives the packet, the networking stack might not see the packet until +an interrupt is delivered for the packet or a timer event causes the +networking device driver to poll for packets, and the time stamp might +not be applied until the packet has had some processing done by other +code in the networking stack, so there might be a significant delay +between the time when the last bit of the packet is received by the +capture device and when the networking stack time-stamps the packet; +.IP +the timer used to generate the time stamps might have low resolution, +for example, it might be a timer updated once per host operating system +timer tick, with the host operating system timer ticking once every few +milliseconds; +.IP +a high-resolution timer might use a counter that runs at a rate +dependent on the processor clock speed, and that clock speed might be +adjusted upwards or downwards over time and the timer might not be able +to compensate for all those adjustments; +.IP +the host operating system's clock might be adjusted over time to match a +time standard to which the host is being synchronized, which might be +done by temporarily slowing down or speeding up the clock or by making a +single adjustment; +.IP +different CPU cores on a multi-core or multi-processor system might be +running at different speeds, or might not have time counters all +synchronized, so packets time-stamped by different cores might not have +consistent time stamps. +.LP +In addition, packets time-stamped by different cores might be +time-stamped in one order and added to the queue of packets for libpcap +to read in another order, so time stamps might not be monotonically +increasing. +.LP +Some capture devices on some platforms can provide time stamps for +packets; those time stamps are usually high-resolution time stamps, and +are usually applied to the packet when the first or last bit of the +packet arrives, and are thus more accurate than time stamps provided by +the host operating system. Those time stamps might not, however, be +synchronized with the host operating system's clock, so that, for +example, the time stamp of a packet might not correspond to the time +stamp of an event on the host triggered by the arrival of that packet. +.LP +Depending on the capture device and the software on the host, libpcap +might allow different types of time stamp to be used. The +.BR pcap_list_tstamp_types (3PCAP) +routine provides, for a packet capture handle created by +.BR pcap_create (3PCAP) +but not yet activated by +.BR pcap_activate (3PCAP), +a list of time stamp types supported by the capture device for that +handle. +The list might be empty, in which case no choice of time stamp type is +offered for that capture device. If the list is not empty, the +.BR pcap_set_tstamp_type (3PCAP) +routine can be used after a +.B pcap_create() +call and before a +.B pcap_activate() +call to specify the type of time stamp to be used on the device. +The time stamp types are listed here; the first value is the #define to +use in code, the second value is the value returned by +.B pcap_tstamp_type_val_to_name() +and accepted by +.BR pcap_tstamp_type_name_to_val() . +.RS 5 +.TP 5 +.BR PCAP_TSTAMP_HOST " - " host +Time stamp provided by the host on which the capture is being done. The +precision of this time stamp is unspecified; it might or might not be +synchronized with the host operating system's clock. +.TP 5 +.BR PCAP_TSTAMP_HOST_LOWPREC " - " host_lowprec +Time stamp provided by the host on which the capture is being done. +This is a low-precision time stamp, synchronized with the host operating +system's clock. +.TP 5 +.BR PCAP_TSTAMP_HOST_HIPREC " - " host_hiprec +Time stamp provided by the host on which the capture is being done. +This is a high-precision time stamp; it might or might not be +synchronized with the host operating system's clock. It might be more +expensive to fetch than +.BR PCAP_TSTAMP_HOST_LOWPREC . +.TP 5 +.BR PCAP_TSTAMP_ADAPTER " - " adapter +Time stamp provided by the network adapter on which the capture is being +done. This is a high-precision time stamp, synchronized with the host +operating system's clock. +.TP 5 +.BR PCAP_TSTAMP_ADAPTER_UNSYNCED " - " adapter_unsynced +Time stamp provided by the network adapter on which the capture is being +done. This is a high-precision time stamp; it is not synchronized with +the host operating system's clock. +.RE +.LP +By default, when performing a live capture or reading from a savefile, +time stamps are supplied as seconds since January 1, 1970, 00:00:00 UTC, +and microseconds since that seconds value, even if higher-resolution +time stamps are available from the capture device or in the savefile. +If, when reading a savefile, the time stamps in the file have a higher +resolution than one microsecond, the additional digits of resolution are +discarded. +.LP +The +.BR pcap_set_tstamp_precision (3PCAP) +routine can be used after a +.B pcap_create() +call and after a +.B pcap_activate() +call to specify the resolution of the time stamps to get for the device. +If the hardware or software cannot supply a higher-resolution time +stamp, the +.B pcap_set_tstamp_precision() +call will fail, and the time stamps supplied after the +.B pcap_activate() +call will have microsecond resolution. +.LP +When opening a savefile, the +.BR pcap_open_offline_with_tstamp_precision (3PCAP) +and +.BR pcap_fopen_offline_with_tstamp_precision (3PCAP) +routines can be used to specify the resolution of time stamps to be read +from the file; if the time stamps in the file have a lower resolution, +the fraction-of-a-second portion of the time stamps will be scaled to +the specified resolution. +.LP +The +.BR pcap_get_tstamp_precision (3PCAP) +routine returns the resolution of time stamps that will be supplied; +when capturing packets, this does not reflect the actual precision of +the time stamp supplied by the hardware or operating system and, when +reading a savefile, this does not indicate the actual precision of time +stamps in the file. +.SH SEE ALSO +pcap_set_tstamp_type(3PCAP), +pcap_list_tstamp_types(3PCAP), +pcap_tstamp_type_val_to_name(3PCAP), +pcap_tstamp_type_name_to_val(3PCAP), +pcap_set_tstamp_precision(3PCAP), +pcap_open_offline_with_tstamp_precision(3PCAP), +pcap_fopen_offline_with_tstamp_precision(3PCAP), +pcap_get_tstamp_precision(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap-usb-linux.c b/tcpdump/jni/libpcap/pcap-usb-linux.c new file mode 100644 index 0000000..957273a --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-usb-linux.c @@ -0,0 +1,939 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * USB sniffing API implementation for Linux platform + * By Paolo Abeni + * Modifications: Kris Katterjohn + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pcap-int.h" +#include "pcap-usb-linux.h" +#include "pcap/usb.h" + +#ifdef NEED_STRERROR_H +#include "strerror.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LINUX_USBDEVICE_FS_H +/* + * We might need to define __user for + * . + */ +#ifdef HAVE_LINUX_COMPILER_H +#include +#endif /* HAVE_LINUX_COMPILER_H */ +#include +#endif /* HAVE_LINUX_USBDEVICE_FS_H */ + +#define USB_IFACE "usbmon" +#define USB_TEXT_DIR_OLD "/sys/kernel/debug/usbmon" +#define USB_TEXT_DIR "/sys/kernel/debug/usb/usbmon" +#define SYS_USB_BUS_DIR "/sys/bus/usb/devices" +#define PROC_USB_BUS_DIR "/proc/bus/usb" +#define USB_LINE_LEN 4096 + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define htols(s) s +#define htoll(l) l +#define htol64(ll) ll +#else +#define htols(s) bswap_16(s) +#define htoll(l) bswap_32(l) +#define htol64(ll) bswap_64(ll) +#endif + +struct mon_bin_stats { + u_int32_t queued; + u_int32_t dropped; +}; + +struct mon_bin_get { + pcap_usb_header *hdr; + void *data; + size_t data_len; /* Length of data (can be zero) */ +}; + +struct mon_bin_mfetch { + int32_t *offvec; /* Vector of events fetched */ + int32_t nfetch; /* Number of events to fetch (out: fetched) */ + int32_t nflush; /* Number of events to flush */ +}; + +#define MON_IOC_MAGIC 0x92 + +#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1) +#define MON_IOCX_URB _IOWR(MON_IOC_MAGIC, 2, struct mon_bin_hdr) +#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) +#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4) +#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5) +#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) +#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) +#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) + +#define MON_BIN_SETUP 0x1 /* setup hdr is present*/ +#define MON_BIN_SETUP_ZERO 0x2 /* setup buffer is not available */ +#define MON_BIN_DATA_ZERO 0x4 /* data buffer is not available */ +#define MON_BIN_ERROR 0x8 + +/* + * Private data for capturing on Linux USB. + */ +struct pcap_usb_linux { + u_char *mmapbuf; /* memory-mapped region pointer */ + size_t mmapbuflen; /* size of region */ + int bus_index; + u_int packets_read; +}; + +/* forward declaration */ +static int usb_activate(pcap_t *); +static int usb_stats_linux(pcap_t *, struct pcap_stat *); +static int usb_stats_linux_bin(pcap_t *, struct pcap_stat *); +static int usb_read_linux(pcap_t *, int , pcap_handler , u_char *); +static int usb_read_linux_bin(pcap_t *, int , pcap_handler , u_char *); +static int usb_read_linux_mmap(pcap_t *, int , pcap_handler , u_char *); +static int usb_inject_linux(pcap_t *, const void *, size_t); +static int usb_setdirection_linux(pcap_t *, pcap_direction_t); +static void usb_cleanup_linux_mmap(pcap_t *); + +/* facility to add an USB device to the device list*/ +static int +usb_dev_add(pcap_if_t** alldevsp, int n, char *err_str) +{ + char dev_name[10]; + char dev_descr[30]; + snprintf(dev_name, 10, USB_IFACE"%d", n); + snprintf(dev_descr, 30, "USB bus number %d", n); + + if (pcap_add_if(alldevsp, dev_name, 0, + dev_descr, err_str) < 0) + return -1; + return 0; +} + +int +usb_findalldevs(pcap_if_t **alldevsp, char *err_str) +{ + struct dirent* data; + int ret = 0; + DIR* dir; + int n; + char* name; + size_t len; + + /* try scanning sysfs usb bus directory */ + dir = opendir(SYS_USB_BUS_DIR); + if (dir != NULL) { + while ((ret == 0) && ((data = readdir(dir)) != 0)) { + name = data->d_name; + + if (strncmp(name, "usb", 3) != 0) + continue; + + if (sscanf(&name[3], "%d", &n) == 0) + continue; + + ret = usb_dev_add(alldevsp, n, err_str); + } + + closedir(dir); + return ret; + } + + /* that didn't work; try scanning procfs usb bus directory */ + dir = opendir(PROC_USB_BUS_DIR); + if (dir != NULL) { + while ((ret == 0) && ((data = readdir(dir)) != 0)) { + name = data->d_name; + len = strlen(name); + + /* if this file name does not end with a number it's not of our interest */ + if ((len < 1) || !isdigit(name[--len])) + continue; + while (isdigit(name[--len])); + if (sscanf(&name[len+1], "%d", &n) != 1) + continue; + + ret = usb_dev_add(alldevsp, n, err_str); + } + + closedir(dir); + return ret; + } + + /* neither of them worked */ + return 0; +} + +static +int usb_mmap(pcap_t* handle) +{ + struct pcap_usb_linux *handlep = handle->priv; + int len = ioctl(handle->fd, MON_IOCQ_RING_SIZE); + if (len < 0) + return 0; + + handlep->mmapbuflen = len; + handlep->mmapbuf = mmap(0, handlep->mmapbuflen, PROT_READ, + MAP_SHARED, handle->fd, 0); + return handlep->mmapbuf != MAP_FAILED; +} + +#ifdef HAVE_LINUX_USBDEVICE_FS_H + +#define CTRL_TIMEOUT (5*1000) /* milliseconds */ + +#define USB_DIR_IN 0x80 +#define USB_TYPE_STANDARD 0x00 +#define USB_RECIP_DEVICE 0x00 + +#define USB_REQ_GET_DESCRIPTOR 6 + +#define USB_DT_DEVICE 1 + +/* probe the descriptors of the devices attached to the bus */ +/* the descriptors will end up in the captured packet stream */ +/* and be decoded by external apps like wireshark */ +/* without these identifying probes packet data can't be fully decoded */ +static void +probe_devices(int bus) +{ + struct usbdevfs_ctrltransfer ctrl; + struct dirent* data; + int ret = 0; + char buf[40]; + DIR* dir; + + /* scan usb bus directories for device nodes */ + snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d", bus); + dir = opendir(buf); + if (!dir) + return; + + while ((ret >= 0) && ((data = readdir(dir)) != 0)) { + int fd; + char* name = data->d_name; + + if (name[0] == '.') + continue; + + snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d/%s", bus, data->d_name); + + fd = open(buf, O_RDWR); + if (fd == -1) + continue; + + /* + * Sigh. Different kernels have different member names + * for this structure. + */ +#ifdef HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE + ctrl.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; + ctrl.wValue = USB_DT_DEVICE << 8; + ctrl.wIndex = 0; + ctrl.wLength = sizeof(buf); +#else + ctrl.requesttype = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + ctrl.request = USB_REQ_GET_DESCRIPTOR; + ctrl.value = USB_DT_DEVICE << 8; + ctrl.index = 0; + ctrl.length = sizeof(buf); +#endif + ctrl.data = buf; + ctrl.timeout = CTRL_TIMEOUT; + + ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl); + + close(fd); + } + closedir(dir); +} +#endif /* HAVE_LINUX_USBDEVICE_FS_H */ + +pcap_t * +usb_create(const char *device, char *ebuf, int *is_ours) +{ + const char *cp; + char *cpend; + long devnum; + pcap_t *p; + + /* Does this look like a USB monitoring device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + /* Does it begin with USB_IFACE? */ + if (strncmp(cp, USB_IFACE, sizeof USB_IFACE - 1) != 0) { + /* Nope, doesn't begin with USB_IFACE */ + *is_ours = 0; + return NULL; + } + /* Yes - is USB_IFACE followed by a number? */ + cp += sizeof USB_IFACE - 1; + devnum = strtol(cp, &cpend, 10); + if (cpend == cp || *cpend != '\0') { + /* Not followed by a number. */ + *is_ours = 0; + return NULL; + } + if (devnum < 0) { + /* Followed by a non-valid number. */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = pcap_create_common(device, ebuf, sizeof (struct pcap_usb_linux)); + if (p == NULL) + return (NULL); + + p->activate_op = usb_activate; + return (p); +} + +static int +usb_activate(pcap_t* handle) +{ + struct pcap_usb_linux *handlep = handle->priv; + char full_path[USB_LINE_LEN]; + + /* Initialize some components of the pcap structure. */ + handle->bufsize = handle->snapshot; + handle->offset = 0; + handle->linktype = DLT_USB_LINUX; + + handle->inject_op = usb_inject_linux; + handle->setfilter_op = install_bpf_program; /* no kernel filtering */ + handle->setdirection_op = usb_setdirection_linux; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + + /*get usb bus index from device name */ + if (sscanf(handle->opt.source, USB_IFACE"%d", &handlep->bus_index) != 1) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't get USB bus index from %s", handle->opt.source); + return PCAP_ERROR; + } + + /*now select the read method: try to open binary interface */ + snprintf(full_path, USB_LINE_LEN, LINUX_USB_MON_DEV"%d", handlep->bus_index); + handle->fd = open(full_path, O_RDONLY, 0); + if (handle->fd >= 0) + { + if (handle->opt.rfmon) { + /* + * Monitor mode doesn't apply to USB devices. + */ + close(handle->fd); + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* binary api is available, try to use fast mmap access */ + if (usb_mmap(handle)) { + handle->linktype = DLT_USB_LINUX_MMAPPED; + handle->stats_op = usb_stats_linux_bin; + handle->read_op = usb_read_linux_mmap; + handle->cleanup_op = usb_cleanup_linux_mmap; +#ifdef HAVE_LINUX_USBDEVICE_FS_H + probe_devices(handlep->bus_index); +#endif + + /* + * "handle->fd" is a real file, so "select()" and + * "poll()" work on it. + */ + handle->selectable_fd = handle->fd; + return 0; + } + + /* can't mmap, use plain binary interface access */ + handle->stats_op = usb_stats_linux_bin; + handle->read_op = usb_read_linux_bin; +#ifdef HAVE_LINUX_USBDEVICE_FS_H + probe_devices(handlep->bus_index); +#endif + } + else { + /*Binary interface not available, try open text interface */ + snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR"/%dt", handlep->bus_index); + handle->fd = open(full_path, O_RDONLY, 0); + if (handle->fd < 0) + { + if (errno == ENOENT) + { + /* + * Not found at the new location; try + * the old location. + */ + snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%dt", handlep->bus_index); + handle->fd = open(full_path, O_RDONLY, 0); + } + if (handle->fd < 0) { + /* no more fallback, give it up*/ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't open USB bus file %s: %s", full_path, strerror(errno)); + return PCAP_ERROR; + } + } + + if (handle->opt.rfmon) { + /* + * Monitor mode doesn't apply to USB devices. + */ + close(handle->fd); + return PCAP_ERROR_RFMON_NOTSUP; + } + + handle->stats_op = usb_stats_linux; + handle->read_op = usb_read_linux; + } + + /* + * "handle->fd" is a real file, so "select()" and "poll()" + * work on it. + */ + handle->selectable_fd = handle->fd; + + /* for plain binary access and text access we need to allocate the read + * buffer */ + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + close(handle->fd); + return PCAP_ERROR; + } + return 0; +} + +static inline int +ascii_to_int(char c) +{ + return c < 'A' ? c- '0': ((c<'a') ? c - 'A' + 10: c-'a'+10); +} + +/* + * see /Documentation/usb/usbmon.txt and + * /drivers/usb/mon/mon_text.c for urb string + * format description + */ +static int +usb_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + /* see: + * /usr/src/linux/Documentation/usb/usbmon.txt + * for message format + */ + struct pcap_usb_linux *handlep = handle->priv; + unsigned timestamp; + int tag, cnt, ep_num, dev_addr, dummy, ret, urb_len, data_len; + char etype, pipeid1, pipeid2, status[16], urb_tag, line[USB_LINE_LEN]; + char *string = line; + u_char * rawdata = handle->buffer; + struct pcap_pkthdr pkth; + pcap_usb_header* uhdr = (pcap_usb_header*)handle->buffer; + u_char urb_transfer=0; + int incoming=0; + + /* ignore interrupt system call errors */ + do { + ret = read(handle->fd, line, USB_LINE_LEN - 1); + if (handle->break_loop) + { + handle->break_loop = 0; + return -2; + } + } while ((ret == -1) && (errno == EINTR)); + if (ret < 0) + { + if (errno == EAGAIN) + return 0; /* no data there */ + + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't read from fd %d: %s", handle->fd, strerror(errno)); + return -1; + } + + /* read urb header; %n argument may increment return value, but it's + * not mandatory, so does not count on it*/ + string[ret] = 0; + ret = sscanf(string, "%x %d %c %c%c:%d:%d %s%n", &tag, ×tamp, &etype, + &pipeid1, &pipeid2, &dev_addr, &ep_num, status, + &cnt); + if (ret < 8) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)", + string, ret); + return -1; + } + uhdr->id = tag; + uhdr->device_address = dev_addr; + uhdr->bus_id = handlep->bus_index; + uhdr->status = 0; + string += cnt; + + /* don't use usbmon provided timestamp, since it have low precision*/ + if (gettimeofday(&pkth.ts, NULL) < 0) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't get timestamp for message '%s' %d:%s", + string, errno, strerror(errno)); + return -1; + } + uhdr->ts_sec = pkth.ts.tv_sec; + uhdr->ts_usec = pkth.ts.tv_usec; + + /* parse endpoint information */ + if (pipeid1 == 'C') + urb_transfer = URB_CONTROL; + else if (pipeid1 == 'Z') + urb_transfer = URB_ISOCHRONOUS; + else if (pipeid1 == 'I') + urb_transfer = URB_INTERRUPT; + else if (pipeid1 == 'B') + urb_transfer = URB_BULK; + if (pipeid2 == 'i') { + ep_num |= URB_TRANSFER_IN; + incoming = 1; + } + if (etype == 'C') + incoming = !incoming; + + /* direction check*/ + if (incoming) + { + if (handle->direction == PCAP_D_OUT) + return 0; + } + else + if (handle->direction == PCAP_D_IN) + return 0; + uhdr->event_type = etype; + uhdr->transfer_type = urb_transfer; + uhdr->endpoint_number = ep_num; + pkth.caplen = sizeof(pcap_usb_header); + rawdata += sizeof(pcap_usb_header); + + /* check if this is a setup packet */ + ret = sscanf(status, "%d", &dummy); + if (ret != 1) + { + /* this a setup packet, setup data can be filled with underscore if + * usbmon has not been able to read them, so we must parse this fields as + * strings */ + pcap_usb_setup* shdr; + char str1[3], str2[3], str3[5], str4[5], str5[5]; + ret = sscanf(string, "%s %s %s %s %s%n", str1, str2, str3, str4, + str5, &cnt); + if (ret < 5) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't parse USB bus message '%s', too few tokens (expected 5 got %d)", + string, ret); + return -1; + } + string += cnt; + + /* try to convert to corresponding integer */ + shdr = &uhdr->setup; + shdr->bmRequestType = strtoul(str1, 0, 16); + shdr->bRequest = strtoul(str2, 0, 16); + shdr->wValue = htols(strtoul(str3, 0, 16)); + shdr->wIndex = htols(strtoul(str4, 0, 16)); + shdr->wLength = htols(strtoul(str5, 0, 16)); + + uhdr->setup_flag = 0; + } + else + uhdr->setup_flag = 1; + + /* read urb data */ + ret = sscanf(string, " %d%n", &urb_len, &cnt); + if (ret < 1) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't parse urb length from '%s'", string); + return -1; + } + string += cnt; + + /* urb tag is not present if urb length is 0, so we can stop here + * text parsing */ + pkth.len = urb_len+pkth.caplen; + uhdr->urb_len = urb_len; + uhdr->data_flag = 1; + data_len = 0; + if (uhdr->urb_len == 0) + goto got; + + /* check for data presence; data is present if and only if urb tag is '=' */ + if (sscanf(string, " %c", &urb_tag) != 1) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't parse urb tag from '%s'", string); + return -1; + } + + if (urb_tag != '=') + goto got; + + /* skip urb tag and following space */ + string += 3; + + /* if we reach this point we got some urb data*/ + uhdr->data_flag = 0; + + /* read all urb data; if urb length is greater then the usbmon internal + * buffer length used by the kernel to spool the URB, we get only + * a partial information. + * At least until linux 2.6.17 there is no way to set usbmon intenal buffer + * length and default value is 130. */ + while ((string[0] != 0) && (string[1] != 0) && (pkth.caplen < handle->snapshot)) + { + rawdata[0] = ascii_to_int(string[0]) * 16 + ascii_to_int(string[1]); + rawdata++; + string+=2; + if (string[0] == ' ') + string++; + pkth.caplen++; + data_len++; + } + +got: + uhdr->data_len = data_len; + if (pkth.caplen > handle->snapshot) + pkth.caplen = handle->snapshot; + + if (handle->fcode.bf_insns == NULL || + bpf_filter(handle->fcode.bf_insns, handle->buffer, + pkth.len, pkth.caplen)) { + handlep->packets_read++; + callback(user, &pkth, handle->buffer); + return 1; + } + return 0; /* didn't pass filter */ +} + +static int +usb_inject_linux(pcap_t *handle, const void *buf, size_t size) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " + "USB devices"); + return (-1); +} + +static int +usb_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_usb_linux *handlep = handle->priv; + int dummy, ret, consumed, cnt; + char string[USB_LINE_LEN]; + char token[USB_LINE_LEN]; + char * ptr = string; + int fd; + + snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handlep->bus_index); + fd = open(string, O_RDONLY, 0); + if (fd < 0) + { + if (errno == ENOENT) + { + /* + * Not found at the new location; try the old + * location. + */ + snprintf(string, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%ds", handlep->bus_index); + fd = open(string, O_RDONLY, 0); + } + if (fd < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't open USB stats file %s: %s", + string, strerror(errno)); + return -1; + } + } + + /* read stats line */ + do { + ret = read(fd, string, USB_LINE_LEN-1); + } while ((ret == -1) && (errno == EINTR)); + close(fd); + + if (ret < 0) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't read stats from fd %d ", fd); + return -1; + } + string[ret] = 0; + + /* extract info on dropped urbs */ + for (consumed=0; consumed < ret; ) { + /* from the sscanf man page: + * The C standard says: "Execution of a %n directive does + * not increment the assignment count returned at the completion + * of execution" but the Corrigendum seems to contradict this. + * Do not make any assumptions on the effect of %n conversions + * on the return value and explicitly check for cnt assignmet*/ + int ntok; + + cnt = -1; + ntok = sscanf(ptr, "%s%n", token, &cnt); + if ((ntok < 1) || (cnt < 0)) + break; + consumed += cnt; + ptr += cnt; + if (strcmp(token, "nreaders") == 0) + ret = sscanf(ptr, "%d", &stats->ps_drop); + else + ret = sscanf(ptr, "%d", &dummy); + if (ntok != 1) + break; + consumed += cnt; + ptr += cnt; + } + + stats->ps_recv = handlep->packets_read; + stats->ps_ifdrop = 0; + return 0; +} + +static int +usb_setdirection_linux(pcap_t *p, pcap_direction_t d) +{ + p->direction = d; + return 0; +} + + +static int +usb_stats_linux_bin(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_usb_linux *handlep = handle->priv; + int ret; + struct mon_bin_stats st; + ret = ioctl(handle->fd, MON_IOCG_STATS, &st); + if (ret < 0) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't read stats from fd %d:%s ", handle->fd, strerror(errno)); + return -1; + } + + stats->ps_recv = handlep->packets_read + st.queued; + stats->ps_drop = st.dropped; + stats->ps_ifdrop = 0; + return 0; +} + +/* + * see /Documentation/usb/usbmon.txt and + * /drivers/usb/mon/mon_bin.c binary ABI + */ +static int +usb_read_linux_bin(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + struct pcap_usb_linux *handlep = handle->priv; + struct mon_bin_get info; + int ret; + struct pcap_pkthdr pkth; + int clen = handle->snapshot - sizeof(pcap_usb_header); + + /* the usb header is going to be part of 'packet' data*/ + info.hdr = (pcap_usb_header*) handle->buffer; + info.data = handle->buffer + sizeof(pcap_usb_header); + info.data_len = clen; + + /* ignore interrupt system call errors */ + do { + ret = ioctl(handle->fd, MON_IOCX_GET, &info); + if (handle->break_loop) + { + handle->break_loop = 0; + return -2; + } + } while ((ret == -1) && (errno == EINTR)); + if (ret < 0) + { + if (errno == EAGAIN) + return 0; /* no data there */ + + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't read from fd %d: %s", handle->fd, strerror(errno)); + return -1; + } + + /* we can get less that than really captured from kernel, depending on + * snaplen, so adjust header accordingly */ + if (info.hdr->data_len < clen) + clen = info.hdr->data_len; + info.hdr->data_len = clen; + pkth.caplen = clen + sizeof(pcap_usb_header); + pkth.len = info.hdr->data_len + sizeof(pcap_usb_header); + pkth.ts.tv_sec = info.hdr->ts_sec; + pkth.ts.tv_usec = info.hdr->ts_usec; + + if (handle->fcode.bf_insns == NULL || + bpf_filter(handle->fcode.bf_insns, handle->buffer, + pkth.len, pkth.caplen)) { + handlep->packets_read++; + callback(user, &pkth, handle->buffer); + return 1; + } + + return 0; /* didn't pass filter */ +} + +/* + * see /Documentation/usb/usbmon.txt and + * /drivers/usb/mon/mon_bin.c binary ABI + */ +#define VEC_SIZE 32 +static int +usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + struct pcap_usb_linux *handlep = handle->priv; + struct mon_bin_mfetch fetch; + int32_t vec[VEC_SIZE]; + struct pcap_pkthdr pkth; + pcap_usb_header* hdr; + int nflush = 0; + int packets = 0; + int clen, max_clen; + + max_clen = handle->snapshot - sizeof(pcap_usb_header); + + for (;;) { + int i, ret; + int limit = max_packets - packets; + if (limit <= 0) + limit = VEC_SIZE; + if (limit > VEC_SIZE) + limit = VEC_SIZE; + + /* try to fetch as many events as possible*/ + fetch.offvec = vec; + fetch.nfetch = limit; + fetch.nflush = nflush; + /* ignore interrupt system call errors */ + do { + ret = ioctl(handle->fd, MON_IOCX_MFETCH, &fetch); + if (handle->break_loop) + { + handle->break_loop = 0; + return -2; + } + } while ((ret == -1) && (errno == EINTR)); + if (ret < 0) + { + if (errno == EAGAIN) + return 0; /* no data there */ + + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't mfetch fd %d: %s", handle->fd, strerror(errno)); + return -1; + } + + /* keep track of processed events, we will flush them later */ + nflush = fetch.nfetch; + for (i=0; immapbuf[vec[i]]; + if (hdr->event_type == '@') + continue; + + /* we can get less that than really captured from kernel, depending on + * snaplen, so adjust header accordingly */ + clen = max_clen; + if (hdr->data_len < clen) + clen = hdr->data_len; + + /* get packet info from header*/ + pkth.caplen = clen + sizeof(pcap_usb_header_mmapped); + pkth.len = hdr->data_len + sizeof(pcap_usb_header_mmapped); + pkth.ts.tv_sec = hdr->ts_sec; + pkth.ts.tv_usec = hdr->ts_usec; + + if (handle->fcode.bf_insns == NULL || + bpf_filter(handle->fcode.bf_insns, (u_char*) hdr, + pkth.len, pkth.caplen)) { + handlep->packets_read++; + callback(user, &pkth, (u_char*) hdr); + packets++; + } + } + + /* with max_packets specifying "unlimited" we stop afer the first chunk*/ + if (PACKET_COUNT_IS_UNLIMITED(max_packets) || (packets == max_packets)) + break; + } + + /* flush pending events*/ + if (ioctl(handle->fd, MON_IOCH_MFLUSH, nflush) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't mflush fd %d: %s", handle->fd, strerror(errno)); + return -1; + } + return packets; +} + +static void +usb_cleanup_linux_mmap(pcap_t* handle) +{ + struct pcap_usb_linux *handlep = handle->priv; + + /* if we have a memory-mapped buffer, unmap it */ + if (handlep->mmapbuf != NULL) { + munmap(handlep->mmapbuf, handlep->mmapbuflen); + handlep->mmapbuf = NULL; + } + pcap_cleanup_live_common(handle); +} diff --git a/tcpdump/jni/libpcap/pcap-usb-linux.h b/tcpdump/jni/libpcap/pcap-usb-linux.h new file mode 100644 index 0000000..234a262 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-usb-linux.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * USB sniffing API implementation for Linux platform + * By Paolo Abeni + */ + +/* + * Prototypes for USB-related functions + */ +int usb_findalldevs(pcap_if_t **alldevsp, char *err_str); +pcap_t *usb_create(const char *device, char *ebuf, int *is_ours); diff --git a/tcpdump/jni/libpcap/pcap-win32.c b/tcpdump/jni/libpcap/pcap-win32.c new file mode 100644 index 0000000..f449f79 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap-win32.c @@ -0,0 +1,951 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#ifdef __MINGW32__ +#ifdef __MINGW64__ +#include +#else /*__MINGW64__*/ +#include +#include +#endif /*__MINGW64__*/ +#else /*__MINGW32__*/ +#include +#endif /*__MINGW32__*/ +#ifdef HAVE_DAG_API +#include +#include +#endif /* HAVE_DAG_API */ +#ifdef __MINGW32__ +int* _errno(); +#define errno (*_errno()) +#endif /* __MINGW32__ */ + +static int pcap_setfilter_win32_npf(pcap_t *, struct bpf_program *); +static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *); +static int pcap_getnonblock_win32(pcap_t *, char *); +static int pcap_setnonblock_win32(pcap_t *, int, char *); + +/*dimension of the buffer in the pcap_t structure*/ +#define WIN32_DEFAULT_USER_BUFFER_SIZE 256000 + +/*dimension of the buffer in the kernel driver NPF */ +#define WIN32_DEFAULT_KERNEL_BUFFER_SIZE 1000000 + +/* Equivalent to ntohs(), but a lot faster under Windows */ +#define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8) + +/* + * Private data for capturing on WinPcap devices. + */ +struct pcap_win { + int nonblock; + + int filtering_in_kernel; /* using kernel filter */ + +#ifdef HAVE_DAG_API + int dag_fcs_bits; /* Number of checksum bits from link layer */ +#endif +}; + +/* + * Header that the WinPcap driver associates to the packets. + * Once was in bpf.h + */ +struct bpf_hdr { + struct timeval bh_tstamp; /* time stamp */ + bpf_u_int32 bh_caplen; /* length of captured portion */ + bpf_u_int32 bh_datalen; /* original length of packet */ + u_short bh_hdrlen; /* length of bpf header (this struct + plus alignment padding) */ +}; + +CRITICAL_SECTION g_PcapCompileCriticalSection; + +BOOL WINAPI DllMain( + HANDLE hinstDLL, + DWORD dwReason, + LPVOID lpvReserved +) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + InitializeCriticalSection(&g_PcapCompileCriticalSection); + } + + return TRUE; +} + +/* Start winsock */ +int +wsockinit() +{ + WORD wVersionRequested; + WSADATA wsaData; + static int err = -1; + static int done = 0; + + if (done) + return err; + + wVersionRequested = MAKEWORD( 1, 1); + err = WSAStartup( wVersionRequested, &wsaData ); + atexit ((void(*)(void))WSACleanup); + InitializeCriticalSection(&g_PcapCompileCriticalSection); + done = 1; + + if ( err != 0 ) + err = -1; + return err; +} + +int pcap_wsockinit() +{ + return wsockinit(); +} + +static int +pcap_stats_win32(pcap_t *p, struct pcap_stat *ps) +{ + + if(PacketGetStats(p->adapter, (struct bpf_stat*)ps) != TRUE){ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "PacketGetStats error: %s", pcap_win32strerror()); + return -1; + } + + return 0; +} + +/* Set the dimension of the kernel-level capture buffer */ +static int +pcap_setbuff_win32(pcap_t *p, int dim) +{ + if(PacketSetBuff(p->adapter,dim)==FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); + return -1; + } + return 0; +} + +/* Set the driver working mode */ +static int +pcap_setmode_win32(pcap_t *p, int mode) +{ + if(PacketSetMode(p->adapter,mode)==FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized"); + return -1; + } + + return 0; +} + +/*set the minimum amount of data that will release a read call*/ +static int +pcap_setmintocopy_win32(pcap_t *p, int size) +{ + if(PacketSetMinToCopy(p->adapter, size)==FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size"); + return -1; + } + return 0; +} + +/*return the Adapter for a pcap_t*/ +static Adapter * +pcap_getadapter_win32(pcap_t *p) +{ + return p->adapter; +} + +static int +pcap_read_win32_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + int cc; + int n = 0; + register u_char *bp, *ep; + u_char *datap; + struct pcap_win *pw = p->priv; + + cc = p->cc; + if (p->cc == 0) { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return PCAP_ERROR_BREAK to indicate + * that we were told to break out of the loop. + */ + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } + + /* capture the packets */ + if(PacketReceivePacket(p->adapter,p->Packet,TRUE)==FALSE){ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); + return (PCAP_ERROR); + } + + cc = p->Packet->ulBytesReceived; + + bp = p->Packet->Buffer; + } + else + bp = p->bp; + + /* + * Loop through each packet. + */ +#define bhp ((struct bpf_hdr *)bp) + ep = bp + cc; + while (1) { + register int caplen, hdrlen; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return PCAP_ERROR_BREAK + * to indicate that we were told to break out of the loop, + * otherwise leave the flag set, so that the *next* call + * will break out of the loop without having read any + * packets, and return the number of packets we've + * processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } else { + p->bp = bp; + p->cc = ep - bp; + return (n); + } + } + if (bp >= ep) + break; + + caplen = bhp->bh_caplen; + hdrlen = bhp->bh_hdrlen; + datap = bp + hdrlen; + + /* + * Short-circuit evaluation: if using BPF filter + * in kernel, no need to do it now - we already know + * the packet passed the filter. + * + * XXX - bpf_filter() should always return TRUE if + * handed a null pointer for the program, but it might + * just try to "run" the filter, so we check here. + */ + if (pw->filtering_in_kernel || + p->fcode.bf_insns == NULL || + bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { + /* + * XXX A bpf_hdr matches a pcap_pkthdr. + */ + (*callback)(user, (struct pcap_pkthdr*)bp, datap); + bp += Packet_WORDALIGN(caplen + hdrlen); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + p->bp = bp; + p->cc = ep - bp; + return (n); + } + } else { + /* + * Skip this packet. + */ + bp += Packet_WORDALIGN(caplen + hdrlen); + } + } +#undef bhp + p->cc = 0; + return (n); +} + +#ifdef HAVE_DAG_API +static int +pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_win *pw = p->priv; + u_char *dp = NULL; + int packet_len = 0, caplen = 0; + struct pcap_pkthdr pcap_header; + u_char *endofbuf; + int n = 0; + dag_record_t *header; + unsigned erf_record_len; + ULONGLONG ts; + int cc; + unsigned swt; + unsigned dfp = p->adapter->DagFastProcess; + + cc = p->cc; + if (cc == 0) /* Get new packets only if we have processed all the ones of the previous read */ + { + /* Get new packets from the network */ + if(PacketReceivePacket(p->adapter, p->Packet, TRUE)==FALSE){ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); + return (-1); + } + + cc = p->Packet->ulBytesReceived; + if(cc == 0) + /* The timeout has expired but we no packets arrived */ + return 0; + header = (dag_record_t*)p->adapter->DagBuffer; + } + else + header = (dag_record_t*)p->bp; + + endofbuf = (char*)header + cc; + + /* + * Cycle through the packets + */ + do + { + erf_record_len = SWAPS(header->rlen); + if((char*)header + erf_record_len > endofbuf) + break; + + /* Increase the number of captured packets */ + pw->stat.ps_recv++; + + /* Find the beginning of the packet */ + dp = ((u_char *)header) + dag_record_size; + + /* Determine actual packet len */ + switch(header->type) + { + case TYPE_ATM: + packet_len = ATM_SNAPLEN; + caplen = ATM_SNAPLEN; + dp += 4; + + break; + + case TYPE_ETH: + swt = SWAPS(header->wlen); + packet_len = swt - (pw->dag_fcs_bits); + caplen = erf_record_len - dag_record_size - 2; + if (caplen > packet_len) + { + caplen = packet_len; + } + dp += 2; + + break; + + case TYPE_HDLC_POS: + swt = SWAPS(header->wlen); + packet_len = swt - (pw->dag_fcs_bits); + caplen = erf_record_len - dag_record_size; + if (caplen > packet_len) + { + caplen = packet_len; + } + + break; + } + + if(caplen > p->snapshot) + caplen = p->snapshot; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) + { + if (n == 0) + { + p->break_loop = 0; + return (-2); + } + else + { + p->bp = (char*)header; + p->cc = endofbuf - (char*)header; + return (n); + } + } + + if(!dfp) + { + /* convert between timestamp formats */ + ts = header->ts; + pcap_header.ts.tv_sec = (int)(ts >> 32); + ts = (ts & 0xffffffffi64) * 1000000; + ts += 0x80000000; /* rounding */ + pcap_header.ts.tv_usec = (int)(ts >> 32); + if (pcap_header.ts.tv_usec >= 1000000) { + pcap_header.ts.tv_usec -= 1000000; + pcap_header.ts.tv_sec++; + } + } + + /* No underlaying filtering system. We need to filter on our own */ + if (p->fcode.bf_insns) + { + if (bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0) + { + /* Move to next packet */ + header = (dag_record_t*)((char*)header + erf_record_len); + continue; + } + } + + /* Fill the header for the user suppplied callback function */ + pcap_header.caplen = caplen; + pcap_header.len = packet_len; + + /* Call the callback function */ + (*callback)(user, &pcap_header, dp); + + /* Move to next packet */ + header = (dag_record_t*)((char*)header + erf_record_len); + + /* Stop if the number of packets requested by user has been reached*/ + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) + { + p->bp = (char*)header; + p->cc = endofbuf - (char*)header; + return (n); + } + } + while((u_char*)header < endofbuf); + + return 1; +} +#endif /* HAVE_DAG_API */ + +/* Send a packet to the network */ +static int +pcap_inject_win32(pcap_t *p, const void *buf, size_t size){ + LPPACKET PacketToSend; + + PacketToSend=PacketAllocatePacket(); + + if (PacketToSend == NULL) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketAllocatePacket failed"); + return -1; + } + + PacketInitPacket(PacketToSend,(PVOID)buf,size); + if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed"); + PacketFreePacket(PacketToSend); + return -1; + } + + PacketFreePacket(PacketToSend); + + /* + * We assume it all got sent if "PacketSendPacket()" succeeded. + * "pcap_inject()" is expected to return the number of bytes + * sent. + */ + return size; +} + +static void +pcap_cleanup_win32(pcap_t *p) +{ + if (p->adapter != NULL) { + PacketCloseAdapter(p->adapter); + p->adapter = NULL; + } + if (p->Packet) { + PacketFreePacket(p->Packet); + p->Packet = NULL; + } + pcap_cleanup_live_common(p); +} + +static int +pcap_activate_win32(pcap_t *p) +{ + struct pcap_win *pw = p->priv; + NetType type; + + if (p->opt.rfmon) { + /* + * No monitor mode on Windows. It could be done on + * Vista with drivers that support the native 802.11 + * mechanism and monitor mode. + */ + return (PCAP_ERROR_RFMON_NOTSUP); + } + + /* Init WinSock */ + wsockinit(); + + p->adapter = PacketOpenAdapter(p->opt.source); + + if (p->adapter == NULL) + { + /* Adapter detected but we are not able to open it. Return failure. */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror()); + return PCAP_ERROR; + } + + /*get network type*/ + if(PacketGetNetType (p->adapter,&type) == FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror()); + goto bad; + } + + /*Set the linktype*/ + switch (type.LinkType) + { + case NdisMediumWan: + p->linktype = DLT_EN10MB; + break; + + case NdisMedium802_3: + p->linktype = DLT_EN10MB; + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (p->dlt_list != NULL) { + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + } + break; + + case NdisMediumFddi: + p->linktype = DLT_FDDI; + break; + + case NdisMedium802_5: + p->linktype = DLT_IEEE802; + break; + + case NdisMediumArcnetRaw: + p->linktype = DLT_ARCNET; + break; + + case NdisMediumArcnet878_2: + p->linktype = DLT_ARCNET; + break; + + case NdisMediumAtm: + p->linktype = DLT_ATM_RFC1483; + break; + + case NdisMediumCHDLC: + p->linktype = DLT_CHDLC; + break; + + case NdisMediumPPPSerial: + p->linktype = DLT_PPP_SERIAL; + break; + + case NdisMediumNull: + p->linktype = DLT_NULL; + break; + + case NdisMediumBare80211: + p->linktype = DLT_IEEE802_11; + break; + + case NdisMediumRadio80211: + p->linktype = DLT_IEEE802_11_RADIO; + break; + + case NdisMediumPpi: + p->linktype = DLT_PPI; + break; + + default: + p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/ + break; + } + + /* Set promiscuous mode */ + if (p->opt.promisc) + { + + if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode"); + goto bad; + } + } + else + { + if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL) == FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode"); + goto bad; + } + } + + /* Set the buffer size */ + p->bufsize = WIN32_DEFAULT_USER_BUFFER_SIZE; + + /* allocate Packet structure used during the capture */ + if((p->Packet = PacketAllocatePacket())==NULL) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure"); + goto bad; + } + + if(!(p->adapter->Flags & INFO_FLAG_DAG_CARD)) + { + /* + * Traditional Adapter + */ + /* + * If the buffer size wasn't explicitly set, default to + * WIN32_DEFAULT_USER_BUFFER_SIZE. + */ + if (p->opt.buffer_size == 0) + p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE; + + if(PacketSetBuff(p->adapter,p->opt.buffer_size)==FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); + goto bad; + } + + p->buffer = (u_char *)malloc(p->bufsize); + if (p->buffer == NULL) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); + goto bad; + } + + PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize); + + if (p->opt.immediate) + { + /* tell the driver to copy the buffer as soon as data arrives */ + if(PacketSetMinToCopy(p->adapter,0)==FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s", pcap_win32strerror()); + goto bad; + } + } + else + { + /* tell the driver to copy the buffer only if it contains at least 16K */ + if(PacketSetMinToCopy(p->adapter,16000)==FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s", pcap_win32strerror()); + goto bad; + } + } + } + else +#ifdef HAVE_DAG_API + { + /* + * Dag Card + */ + LONG status; + HKEY dagkey; + DWORD lptype; + DWORD lpcbdata; + int postype = 0; + char keyname[512]; + + snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s", + "SYSTEM\\CurrentControlSet\\Services\\DAG", + strstr(_strlwr(p->opt.source), "dag")); + do + { + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &dagkey); + if(status != ERROR_SUCCESS) + break; + + status = RegQueryValueEx(dagkey, + "PosType", + NULL, + &lptype, + (char*)&postype, + &lpcbdata); + + if(status != ERROR_SUCCESS) + { + postype = 0; + } + + RegCloseKey(dagkey); + } + while(FALSE); + + + p->snapshot = PacketSetSnapLen(p->adapter, snaplen); + + /* Set the length of the FCS associated to any packet. This value + * will be subtracted to the packet length */ + pw->dag_fcs_bits = p->adapter->DagFcsLen; + } +#else + goto bad; +#endif /* HAVE_DAG_API */ + + PacketSetReadTimeout(p->adapter, p->opt.timeout); + +#ifdef HAVE_DAG_API + if(p->adapter->Flags & INFO_FLAG_DAG_CARD) + { + /* install dag specific handlers for read and setfilter */ + p->read_op = pcap_read_win32_dag; + p->setfilter_op = pcap_setfilter_win32_dag; + } + else + { +#endif /* HAVE_DAG_API */ + /* install traditional npf handlers for read and setfilter */ + p->read_op = pcap_read_win32_npf; + p->setfilter_op = pcap_setfilter_win32_npf; +#ifdef HAVE_DAG_API + } +#endif /* HAVE_DAG_API */ + p->setdirection_op = NULL; /* Not implemented. */ + /* XXX - can this be implemented on some versions of Windows? */ + p->inject_op = pcap_inject_win32; + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcap_getnonblock_win32; + p->setnonblock_op = pcap_setnonblock_win32; + p->stats_op = pcap_stats_win32; + p->setbuff_op = pcap_setbuff_win32; + p->setmode_op = pcap_setmode_win32; + p->setmintocopy_op = pcap_setmintocopy_win32; + p->getadapter_op = pcap_getadapter_win32; + p->cleanup_op = pcap_cleanup_win32; + + return (0); +bad: + pcap_cleanup_win32(p); + return (PCAP_ERROR); +} + +pcap_t * +pcap_create_interface(const char *device, char *ebuf) +{ + pcap_t *p; + + if (strlen(device) == 1) + { + /* + * It's probably a unicode string + * Convert to ascii and pass it to pcap_create_common + * + * This wonderful hack is needed because pcap_lookupdev still returns + * unicode strings, and it's used by windump when no device is specified + * in the command line + */ + size_t length; + char* deviceAscii; + + length = wcslen((wchar_t*)device); + + deviceAscii = (char*)malloc(length + 1); + + if (deviceAscii == NULL) + { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "Malloc failed"); + return NULL; + } + + snprintf(deviceAscii, length + 1, "%ws", (wchar_t*)device); + p = pcap_create_common(deviceAscii, ebuf, sizeof (struct pcap_win)); + free(deviceAscii); + } + else + { + p = pcap_create_common(device, ebuf, sizeof (struct pcap_win)); + } + + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_win32; + return (p); +} + +static int +pcap_setfilter_win32_npf(pcap_t *p, struct bpf_program *fp) +{ + struct pcap_win *pw = p->priv; + + if(PacketSetBpf(p->adapter,fp)==FALSE){ + /* + * Kernel filter not installed. + * + * XXX - we don't know whether this failed because: + * + * the kernel rejected the filter program as invalid, + * in which case we should fall back on userland + * filtering; + * + * the kernel rejected the filter program as too big, + * in which case we should again fall back on + * userland filtering; + * + * there was some other problem, in which case we + * should probably report an error. + * + * For NPF devices, the Win32 status will be + * STATUS_INVALID_DEVICE_REQUEST for invalid + * filters, but I don't know what it'd be for + * other problems, and for some other devices + * it might not be set at all. + * + * So we just fall back on userland filtering in + * all cases. + */ + + /* + * install_bpf_program() validates the program. + * + * XXX - what if we already have a filter in the kernel? + */ + if (install_bpf_program(p, fp) < 0) + return (-1); + pw->filtering_in_kernel = 0; /* filtering in userland */ + return (0); + } + + /* + * It worked. + */ + pw->filtering_in_kernel = 1; /* filtering in the kernel */ + + /* + * Discard any previously-received packets, as they might have + * passed whatever filter was formerly in effect, but might + * not pass this filter (BIOCSETF discards packets buffered + * in the kernel, so you can lose packets in any case). + */ + p->cc = 0; + return (0); +} + +/* + * We filter at user level, since the kernel driver does't process the packets + */ +static int +pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) { + + if(!fp) + { + strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); + return -1; + } + + /* Install a user level filter */ + if (install_bpf_program(p, fp) < 0) + { + snprintf(p->errbuf, sizeof(p->errbuf), + "setfilter, unable to install the filter: %s", pcap_strerror(errno)); + return -1; + } + + return (0); +} + +static int +pcap_getnonblock_win32(pcap_t *p, char *errbuf) +{ + struct pcap_win *pw = p->priv; + + /* + * XXX - if there were a PacketGetReadTimeout() call, we + * would use it, and return 1 if the timeout is -1 + * and 0 otherwise. + */ + return (pw->nonblock); +} + +static int +pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf) +{ + struct pcap_win *pw = p->priv; + int newtimeout; + + if (nonblock) { + /* + * Set the read timeout to -1 for non-blocking mode. + */ + newtimeout = -1; + } else { + /* + * Restore the timeout set when the device was opened. + * (Note that this may be -1, in which case we're not + * really leaving non-blocking mode.) + */ + newtimeout = p->opt.timeout; + } + if (!PacketSetReadTimeout(p->adapter, newtimeout)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "PacketSetReadTimeout: %s", pcap_win32strerror()); + return (-1); + } + pw->nonblock = (newtimeout == -1); + return (0); +} + +/*platform-dependent routine to add devices other than NDIS interfaces*/ +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + return (0); +} diff --git a/tcpdump/jni/libpcap/pcap.3pcap.in b/tcpdump/jni/libpcap/pcap.3pcap.in new file mode 100644 index 0000000..c02ac43 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap.3pcap.in @@ -0,0 +1,937 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP 3PCAP "16 April 2014" +.SH NAME +pcap \- Packet Capture library +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +.ft +.fi +.SH DESCRIPTION +The Packet Capture library +provides a high level interface to packet capture systems. All packets +on the network, even those destined for other hosts, are accessible +through this mechanism. +It also supports saving captured packets to a ``savefile'', and reading +packets from a ``savefile''. +.SS Opening a capture handle for reading +To open a handle for a live capture, given the name of the network or +other interface on which the capture should be done, call +.BR pcap_create (), +set the appropriate options on the handle, and then activate it with +.BR pcap_activate (). +.PP +To obtain a list of devices that can be opened for a live capture, call +.BR pcap_findalldevs (); +to free the list returned by +.BR pcap_findalldevs (), +call +.BR pcap_freealldevs (). +.BR pcap_lookupdev () +will return the first device on that list that is not a ``loopback`` +network interface. +.PP +To open a handle for a ``savefile'' from which to read packets, given the +pathname of the ``savefile'', call +.BR pcap_open_offline (); +to set up a handle for a ``savefile'', given a +.B "FILE\ *" +referring to a file already opened for reading, call +.BR pcap_fopen_offline (). +.PP +In order to get a ``fake'' +.B pcap_t +for use in routines that require a +.B pcap_t +as an argument, such as routines to open a ``savefile'' for writing and +to compile a filter expression, call +.BR pcap_open_dead (). +.PP +.BR pcap_create (), +.BR pcap_open_offline (), +.BR pcap_fopen_offline (), +and +.BR pcap_open_dead () +return a pointer to a +.BR pcap_t , +which is the handle used for reading packets from the capture stream or +the ``savefile'', and for finding out information about the capture +stream or ``savefile''. +To close a handle, use +.BR pcap_close (). +.PP +The options that can be set on a capture handle include +.IP "snapshot length" +If, when capturing, you capture the entire contents of the packet, that +requires more CPU time to copy the packet to your application, more disk +and possibly network bandwidth to write the packet data to a file, and +more disk space to save the packet. If you don't need the entire +contents of the packet - for example, if you are only interested in the +TCP headers of packets - you can set the "snapshot length" for the +capture to an appropriate value. If the snapshot length is set to +.IR snaplen , +and +.I snaplen +is less +than the size of a packet that is captured, only the first +.I snaplen +bytes of that packet will be captured and provided as packet data. +.IP +A snapshot length of 65535 should be sufficient, on most if not all +networks, to capture all the data available from the packet. +.IP +The snapshot length is set with +.BR pcap_set_snaplen (). +.IP "promiscuous mode" +On broadcast LANs such as Ethernet, if the network isn't switched, or if +the adapter is connected to a "mirror port" on a switch to which all +packets passing through the switch are sent, a network adapter receives +all packets on the LAN, including unicast or multicast packets not sent +to a network address that the network adapter isn't configured to +recognize. +.IP +Normally, the adapter will discard those packets; however, many network +adapters support "promiscuous mode", which is a mode in which all +packets, even if they are not sent to an address that the adapter +recognizes, are provided to the host. This is useful for passively +capturing traffic between two or more other hosts for analysis. +.IP +Note that even if an application does not set promiscuous mode, the +adapter could well be in promiscuous mode for some other reason. +.IP +For now, this doesn't work on the "any" device; if an argument of "any" +or NULL is supplied, the setting of promiscuous mode is ignored. +.IP +Promiscuous mode is set with +.BR pcap_set_promisc (). +.IP "monitor mode" +On IEEE 802.11 wireless LANs, even if an adapter is in promiscuous mode, +it will supply to the host only frames for the network with which it's +associated. It might also supply only data frames, not management or +control frames, and might not provide the 802.11 header or radio +information pseudo-header for those frames. +.IP +In "monitor mode", sometimes also called "rfmon mode" (for "Radio +Frequency MONitor"), the adapter will supply all frames that it +receives, with 802.11 headers, and might supply a pseudo-header with +radio information about the frame as well. +.IP +Note that in monitor mode the adapter might disassociate from the +network with which it's associated, so that you will not be able to use +any wireless networks with that adapter. This could prevent accessing +files on a network server, or resolving host names or network addresses, +if you are capturing in monitor mode and are not connected to another +network with another adapter. +.IP +Monitor mode is set with +.BR pcap_set_rfmon (), +and +.BR pcap_can_set_rfmon () +can be used to determine whether an adapter can be put into monitor +mode. +.IP "read timeout" +If, when capturing, packets are delivered as soon as they arrive, the +application capturing the packets will be woken up for each packet as it +arrives, and might have to make one or more calls to the operating +system to fetch each packet. +.IP +If, instead, packets are not delivered as soon as they arrive, but are +delivered after a short delay (called a "read timeout"), more than one +packet can be accumulated before the packets are delivered, so that a +single wakeup would be done for multiple packets, and each set of calls +made to the operating system would supply multiple packets, rather than +a single packet. This reduces the per-packet CPU overhead if packets +are arriving at a high rate, increasing the number of packets per second +that can be captured. +.IP +The read timeout is required so that an application won't wait for the +operating system's capture buffer to fill up before packets are +delivered; if packets are arriving slowly, that wait could take an +arbitrarily long period of time. +.IP +Not all platforms support a read timeout; on platforms that +don't, the read timeout is ignored. A zero value for the timeout, +on platforms that support a read timeout, +will cause a read to wait forever to allow enough packets to +arrive, with no timeout. +.IP +.BR NOTE : +the read timeout cannot be used to cause calls that read +packets to return within a limited period of time, because, on some +platforms, the read timeout isn't supported, and, on other platforms, +the timer doesn't start until at least one packet arrives. This means +that the read timeout should +.B NOT +be used, for example, in an interactive application to allow the packet +capture loop to ``poll'' for user input periodically, as there's no +guarantee that a call reading packets will return after the timeout +expires even if no packets have arrived. +.IP +The read timeout is set with +.BR pcap_set_timeout (). +.IP "buffer size" +Packets that arrive for a capture are stored in a buffer, so that they +do not have to be read by the application as soon as they arrive. On +some platforms, the buffer's size can be set; a size that's too small +could mean that, if too many packets are being captured and the snapshot +length doesn't limit the amount of data that's buffered, packets could +be dropped if the buffer fills up before the application can read +packets from it, while a size that's too large could use more +non-pageable operating system memory than is necessary to prevent +packets from being dropped. +.IP +The buffer size is set with +.BR pcap_set_buffer_size (). +.IP "timestamp type" +On some platforms, the time stamp given to packets on live captures can +come from different sources that can have different resolutions or that +can have different relationships to the time values for the current time +supplied by routines on the native operating system. See +.BR pcap-tstamp (@MAN_MISC_INFO@) +for a list of time stamp types. +.IP +The time stamp type is set with +.BR pcap_set_tstamp_type (). +.PP +Reading packets from a network interface may require that you have +special privileges: +.TP +.B Under SunOS 3.x or 4.x with NIT or BPF: +You must have read access to +.I /dev/nit +or +.IR /dev/bpf* . +.TP +.B Under Solaris with DLPI: +You must have read/write access to the network pseudo device, e.g. +.IR /dev/le . +On at least some versions of Solaris, however, this is not sufficient to +allow +.I tcpdump +to capture in promiscuous mode; on those versions of Solaris, you must +be root, or the application capturing packets +must be installed setuid to root, in order to capture in promiscuous +mode. Note that, on many (perhaps all) interfaces, if you don't capture +in promiscuous mode, you will not see any outgoing packets, so a capture +not done in promiscuous mode may not be very useful. +.IP +In newer versions of Solaris, you must have been given the +.B net_rawaccess +privilege; this is both necessary and sufficient to give you access to the +network pseudo-device - there is no need to change the privileges on +that device. A user can be given that privilege by, for example, adding +that privilege to the user's +.B defaultpriv +key with the +.B usermod (1M) +command. +.TP +.B Under HP-UX with DLPI: +You must be root or the application capturing packets must be installed +setuid to root. +.TP +.B Under IRIX with snoop: +You must be root or the application capturing packets must be installed +setuid to root. +.TP +.B Under Linux: +You must be root or the application capturing packets must be installed +setuid to root (unless your distribution has a kernel +that supports capability bits such as CAP_NET_RAW and code to allow +those capability bits to be given to particular accounts and to cause +those bits to be set on a user's initial processes when they log in, in +which case you must have CAP_NET_RAW in order to capture and +CAP_NET_ADMIN to enumerate network devices with, for example, the +.B \-D +flag). +.TP +.B Under ULTRIX and Digital UNIX/Tru64 UNIX: +Any user may capture network traffic. +However, no user (not even the super-user) can capture in promiscuous +mode on an interface unless the super-user has enabled promiscuous-mode +operation on that interface using +.IR pfconfig (8), +and no user (not even the super-user) can capture unicast traffic +received by or sent by the machine on an interface unless the super-user +has enabled copy-all-mode operation on that interface using +.IR pfconfig , +so +.I useful +packet capture on an interface probably requires that either +promiscuous-mode or copy-all-mode operation, or both modes of +operation, be enabled on that interface. +.TP +.B Under BSD (this includes Mac OS X): +You must have read access to +.I /dev/bpf* +on systems that don't have a cloning BPF device, or to +.I /dev/bpf +on systems that do. +On BSDs with a devfs (this includes Mac OS X), this might involve more +than just having somebody with super-user access setting the ownership +or permissions on the BPF devices - it might involve configuring devfs +to set the ownership or permissions every time the system is booted, +if the system even supports that; if it doesn't support that, you might +have to find some other way to make that happen at boot time. +.PP +Reading a saved packet file doesn't require special privileges. +.PP +The packets read from the handle may include a ``pseudo-header'' +containing various forms of packet meta-data, and probably includes a +link-layer header whose contents can differ for different network +interfaces. To determine the format of the packets supplied by the +handle, call +.BR pcap_datalink (); +.I http://www.tcpdump.org/linktypes.html +lists the values it returns and describes the packet formats that +correspond to those values. +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. +.PP +To obtain the +.B "FILE\ *" +corresponding to a +.B pcap_t +opened for a ``savefile'', call +.BR pcap_file (). +.TP +.B Routines +.RS +.TP +.BR pcap_create (3PCAP) +get a +.B pcap_t +for live capture +.TP +.BR pcap_activate (3PCAP) +activate a +.B pcap_t +for live capture +.TP +.BR pcap_findalldevs (3PCAP) +get a list of devices that can be opened for a live capture +.TP +.BR pcap_freealldevs (3PCAP) +free list of devices +.TP +.BR pcap_lookupdev (3PCAP) +get first non-loopback device on that list +.TP +.BR pcap_open_offline (3PCAP) +open a +.B pcap_t +for a ``savefile'', given a pathname +.TP +.BR pcap_open_offline_with_tstamp_precision (3PCAP) +open a +.B pcap_t +for a ``savefile'', given a pathname, and specify the precision to +provide for packet time stamps +.TP +.BR pcap_fopen_offline (3PCAP) +open a +.B pcap_t +for a ``savefile'', given a +.B "FILE\ *" +.TP +.BR pcap_fopen_offline_with_tstamp_precision (3PCAP) +open a +.B pcap_t +for a ``savefile'', given a +.BR "FILE\ *" , +and specify the precision to provide for packet time stamps +.TP +.BR pcap_open_dead (3PCAP) +create a ``fake'' +.B pcap_t +.TP +.BR pcap_close (3PCAP) +close a +.B pcap_t +.TP +.BR pcap_set_snaplen (3PCAP) +set the snapshot length for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_snapshot (3PCAP) +get the snapshot length for a +.B pcap_t +.TP +.BR pcap_set_promisc (3PCAP) +set promiscuous mode for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_set_rfmon (3PCAP) +set monitor mode for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_can_set_rfmon (3PCAP) +determine whether monitor mode can be set for a +.B pcap_t +for live capture +.TP +.BR pcap_set_timeout (3PCAP) +set read timeout for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_set_buffer_size (3PCAP) +set buffer size for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_set_tstamp_type (3PCAP) +set time stamp type for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_list_tstamp_types (3PCAP) +get list of available time stamp types for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_free_tstamp_types (3PCAP) +free list of available time stamp types +.TP +.BR pcap_tstamp_type_val_to_name (3PCAP) +get name for a time stamp type +.TP +.BR pcap_tstamp_type_val_to_description (3PCAP) +get description for a time stamp type +.TP +.BR pcap_tstamp_type_name_to_val (3PCAP) +get time stamp type corresponding to a name +.TP +.BR pcap_set_tstamp_precision (3PCAP) +set time stamp precision for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_get_tstamp_precision (3PCAP) +get the time stamp precision of a +.B pcap_t +for live capture +.TP +.BR pcap_datalink (3PCAP) +get link-layer header type for a +.B pcap_t +.TP +.BR pcap_file (3PCAP) +get the +.B "FILE\ *" +for a +.B pcap_t +opened for a ``savefile'' +.TP +.BR pcap_is_swapped (3PCAP) +determine whether a ``savefile'' being read came from a machine with the +opposite byte order +.TP +.BR pcap_major_version (3PCAP) +.PD 0 +.TP +.BR pcap_minor_version (3PCAP) +get the major and minor version of the file format version for a +``savefile'' +.PD +.RE +.SS Selecting a link-layer header type for a live capture +Some devices may provide more than one link-layer header type. To +obtain a list of all link-layer header types provided by a device, call +.BR pcap_list_datalinks () +on an activated +.B pcap_t +for the device. +To free a list of link-layer header types, call +.BR pcap_free_datalinks (). +To set the link-layer header type for a device, call +.BR pcap_set_datalink (). +This should be done after the device has been activated but before any +packets are read and before any filters are compiled or installed. +.TP +.B Routines +.RS +.TP +.BR pcap_list_datalinks (3PCAP) +get a list of link-layer header types for a device +.TP +.BR pcap_free_datalinks (3PCAP) +free list of link-layer header types +.TP +.BR pcap_set_datalink (3PCAP) +set link-layer header type for a device +.TP +.BR pcap_datalink_val_to_name (3PCAP) +get name for a link-layer header type +.TP +.BR pcap_datalink_val_to_description (3PCAP) +get description for a link-layer header type +.TP +.BR pcap_datalink_name_to_val (3PCAP) +get link-layer header type corresponding to a name +.RE +.SS Reading packets +Packets are read with +.BR pcap_dispatch () +or +.BR pcap_loop (), +which process one or more packets, calling a callback routine for each +packet, or with +.BR pcap_next () +or +.BR pcap_next_ex (), +which return the next packet. +The callback for +.BR pcap_dispatch () +and +.BR pcap_loop () +is supplied a pointer to a +.IR "struct pcap_pkthdr" , +which includes the following members: +.RS +.TP +.B ts +a +.I struct timeval +containing the time when the packet was captured +.TP +.B caplen +a +.I bpf_u_int32 +giving the number of bytes of the packet that are available from the +capture +.TP +.B len +a +.I bpf_u_int32 +giving the length of the packet, in bytes (which might be more than the +number of bytes available from the capture, if the length of the packet +is larger than the maximum number of bytes to capture). +.RE +.PP +The callback is also supplied a +.I const u_char +pointer to the first +.B caplen +(as given in the +.I struct pcap_pkthdr +mentioned above) +bytes of data from the packet. This won't necessarily be the entire +packet; to capture the entire packet, you will have to provide a value +for +.I snaplen +in your call to +.BR pcap_set_snaplen () +that is sufficiently large to get all of the packet's data - a value of +65535 should be sufficient on most if not all networks). When reading +from a ``savefile'', the snapshot length specified when the capture was +performed will limit the amount of packet data available. +.PP +.BR pcap_next () +is passed an argument that points to a +.I struct pcap_pkthdr +structure, and fills it in with the time stamp and length values for the +packet. It returns a +.I const u_char +to the first +.B caplen +bytes of the packet on success, and NULL on error. +.PP +.BR pcap_next_ex () +is passed two pointer arguments, one of which points to a +.IR struct pcap_pkthdr * +and one of which points to a +.IR "const u_char" *. +It sets the first pointer to point to a +.I struct pcap_pkthdr +structure with the time stamp and length values for the packet, and sets +the second pointer to point to the first +.B caplen +bytes of the packet. +.PP +To force the loop in +.BR pcap_dispatch () +or +.BR pcap_loop () +to terminate, call +.BR pcap_breakloop (). +.PP +By default, when reading packets from an interface opened for a live +capture, +.BR pcap_dispatch (), +.BR pcap_next (), +and +.BR pcap_next_ex () +will, if no packets are currently available to be read, block waiting +for packets to become available. On some, but +.I not +all, platforms, if a read timeout was specified, the wait will terminate +after the read timeout expires; applications should be prepared for +this, as it happens on some platforms, but should not rely on it, as it +does not happen on other platforms. Note that the wait might, or might +not, terminate even if no packets are available; applications should be +prepared for this to happen, but must not rely on it happening. +.PP +A handle can be put into ``non-blocking mode'', so that those routines +will, rather than blocking, return an indication that no packets are +available to read. Call +.BR pcap_setnonblock () +to put a handle into non-blocking mode or to take it out of non-blocking +mode; call +.BR pcap_getnonblock () +to determine whether a handle is in non-blocking mode. Note that +non-blocking mode does not work correctly in Mac OS X 10.6. +.PP +Non-blocking mode is often combined with routines such as +.BR select (2) +or +.BR poll (2) +or other routines a platform offers to wait for any of a set of +descriptors to be ready to read. To obtain, for a handle, a descriptor +that can be used in those routines, call +.BR pcap_get_selectable_fd (). +Not all handles have such a descriptor available; +.BR pcap_get_selectable_fd () +will return \-1 if no such descriptor exists. In addition, for various +reasons, one or more of those routines will not work properly with the +descriptor; the documentation for +.BR pcap_get_selectable_fd () +gives details. Note that, just as an attempt to read packets from a +.B pcap_t +may not return any packets if the read timeout expires, a +.BR select (), +.BR poll (), +or other such call may, if the read timeout expires, indicate that a +descriptor is ready to read even if there are no packets available to +read. +.TP +.B Routines +.RS +.TP +.BR pcap_dispatch (3PCAP) +read a bufferful of packets from a +.B pcap_t +open for a live capture or the full set of packets from a +.B pcap_t +open for a ``savefile'' +.TP +.BR pcap_loop (3PCAP) +read packets from a +.B pcap_t +until an interrupt or error occurs +.TP +.BR pcap_next (3PCAP) +read the next packet from a +.B pcap_t +without an indication whether an error occurred +.TP +.BR pcap_next_ex (3PCAP) +read the next packet from a +.B pcap_t +with an error indication on an error +.TP +.BR pcap_breakloop (3PCAP) +prematurely terminate the loop in +.BR pcap_dispatch () +or +.BR pcap_loop () +.TP +.BR pcap_setnonblock (3PCAP) +set or clear non-blocking mode on a +.B pcap_t +.TP +.BR pcap_getnonblock (3PCAP) +get the state of non-blocking mode for a +.B pcap_t +.TP +.BR pcap_get_selectable_fd (3PCAP) +attempt to get a descriptor for a +.B pcap_t +that can be used in calls such as +.BR select (2) +and +.BR poll (2) +.RE +.SS Filters +In order to cause only certain packets to be returned when reading +packets, a filter can be set on a handle. For a live capture, the +filtering will be performed in kernel mode, if possible, to avoid +copying ``uninteresting'' packets from the kernel to user mode. +.PP +A filter can be specified as a text string; the syntax and semantics of +the string are as described by +.BR pcap-filter (@MAN_MISC_INFO@). +A filter string is compiled into a program in a pseudo-machine-language +by +.BR pcap_compile () +and the resulting program can be made a filter for a handle with +.BR pcap_setfilter (). +The result of +.BR pcap_compile () +can be freed with a call to +.BR pcap_freecode (). +.BR pcap_compile () +may require a network mask for certain expressions in the filter string; +.BR pcap_lookupnet () +can be used to find the network address and network mask for a given +capture device. +.PP +A compiled filter can also be applied directly to a packet that has been +read using +.BR pcap_offline_filter (). +.TP +.B Routines +.RS +.TP +.BR pcap_compile (3PCAP) +compile filter expression to a pseudo-machine-language code program +.TP +.BR pcap_freecode (3PCAP) +free a filter program +.TP +.BR pcap_setfilter (3PCAP) +set filter for a +.B pcap_t +.TP +.BR pcap_lookupnet (3PCAP) +get network address and network mask for a capture device +.TP +.BR pcap_offline_filter (3PCAP) +apply a filter program to a packet +.RE +.SS Incoming and outgoing packets +By default, libpcap will attempt to capture both packets sent by the +machine and packets received by the machine. To limit it to capturing +only packets received by the machine or, if possible, only packets sent +by the machine, call +.BR pcap_setdirection (). +.TP +.BR Routines +.RS +.TP +.BR pcap_setdirection (3PCAP) +specify whether to capture incoming packets, outgoing packets, or both +.RE +.SS Capture statistics +To get statistics about packets received and dropped in a live capture, +call +.BR pcap_stats (). +.TP +.B Routines +.RS +.TP +.BR pcap_stats (3PCAP) +get capture statistics +.RE +.SS Opening a handle for writing captured packets +To open a ``savefile`` to which to write packets, given the pathname the +``savefile'' should have, call +.BR pcap_dump_open (). +To open a ``savefile`` to which to write packets, given the pathname the +``savefile'' should have, call +.BR pcap_dump_open (); +to set up a handle for a ``savefile'', given a +.B "FILE\ *" +referring to a file already opened for writing, call +.BR pcap_dump_fopen (). +They each return pointers to a +.BR pcap_dumper_t , +which is the handle used for writing packets to the ``savefile''. If it +succeeds, it will have created the file if it doesn't exist and +truncated the file if it does exist. +To close a +.BR pcap_dumper_t , +call +.BR pcap_dump_close (). +.TP +.B Routines +.RS +.TP +.BR pcap_dump_open (3PCAP) +open a +.B pcap_dumper_t +for a ``savefile``, given a pathname +.TP +.BR pcap_dump_fopen (3PCAP) +open a +.B pcap_dumper_t +for a ``savefile``, given a +.B "FILE\ *" +.TP +.BR pcap_dump_close (3PCAP) +close a +.B pcap_dumper_t +.TP +.BR pcap_dump_file (3PCAP) +get the +.B "FILE\ *" +for a +.B pcap_dumper_t +opened for a ``savefile'' +.RE +.SS Writing packets +To write a packet to a +.BR pcap_dumper_t , +call +.BR pcap_dump (). +Packets written with +.BR pcap_dump () +may be buffered, rather than being immediately written to the +``savefile''. Closing the +.B pcap_dumper_t +will cause all buffered-but-not-yet-written packets to be written to the +``savefile''. +To force all packets written to the +.BR pcap_dumper_t , +and not yet written to the ``savefile'' because they're buffered by the +.BR pcap_dumper_t , +to be written to the ``savefile'', without closing the +.BR pcap_dumper_t , +call +.BR pcap_dump_flush (). +.TP +.B Routines +.RS +.TP +.BR pcap_dump (3PCAP) +write packet to a +.B pcap_dumper_t +.TP +.BR pcap_dump_flush (3PCAP) +flush buffered packets written to a +.B pcap_dumper_t +to the ``savefile'' +.TP +.BR pcap_dump_ftell (3PCAP) +get current file position for a +.B pcap_dumper_t +.RE +.SS Injecting packets +If you have the required privileges, you can inject packets onto a +network with a +.B pcap_t +for a live capture, using +.BR pcap_inject () +or +.BR pcap_sendpacket (). +(The two routines exist for compatibility with both OpenBSD and WinPcap; +they perform the same function, but have different return values.) +.TP +.B Routines +.RS +.TP +.BR pcap_inject (3PCAP) +.PD 0 +.TP +.BR pcap_sendpacket (3PCAP) +transmit a packet +.PD +.RE +.SS Reporting errors +Some routines return error or warning status codes; to convert them to a +string, use +.BR pcap_statustostr (). +.TP +.B Routines +.RS +.TP +.BR pcap_statustostr (3PCAP) +get a string for an error or warning status code +.RE +.SS Getting library version information +To get a string giving version information about libpcap, call +.BR pcap_lib_version (). +.TP +.B Routines +.RS +.TP +.BR pcap_lib_version (3PCAP) +get library version string +.RE +.SH BACKWARDS COMPATIBILITY +.PP +In versions of libpcap prior to 1.0, the +.B pcap.h +header file was not in a +.B pcap +directory on most platforms; if you are writing an application that must +work on versions of libpcap prior to 1.0, include +.BR , +which will include +.B +for you, rather than including +.BR . +.PP +.BR pcap_create () +and +.BR pcap_activate () +were not available in versions of libpcap prior to 1.0; if you are +writing an application that must work on versions of libpcap prior to +1.0, either use +.BR pcap_open_live () +to get a handle for a live capture or, if you want to be able to use the +additional capabilities offered by using +.BR pcap_create () +and +.BR pcap_activate (), +use an +.BR autoconf (1) +script or some other configuration script to check whether the libpcap +1.0 APIs are available and use them only if they are. +.SH SEE ALSO +autoconf(1), tcpdump(1), tcpslice(1), pcap-filter(@MAN_MISC_INFO@), pfconfig(8), +usermod(1M) +.SH AUTHORS +The original authors of libpcap are: +.LP +Van Jacobson, +Craig Leres and +Steven McCanne, all of the +Lawrence Berkeley National Laboratory, University of California, Berkeley, CA. +.LP +The current version is available from "The Tcpdump Group"'s Web site at +.LP +.RS +.I http://www.tcpdump.org/ +.RE +.SH BUGS +Please send problems, bugs, questions, desirable enhancements, etc. to: +.LP +.RS +tcpdump-workers@lists.tcpdump.org +.RE diff --git a/tcpdump/jni/libpcap/pcap.c b/tcpdump/jni/libpcap/pcap.c new file mode 100644 index 0000000..4e9c94a --- /dev/null +++ b/tcpdump/jni/libpcap/pcap.c @@ -0,0 +1,2029 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#endif /* WIN32 */ + +#include +#include +#include +#if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__MINGW32__) +#include +#endif +#include +#include + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#ifdef MSDOS +#include "pcap-dos.h" +#endif + +#include "pcap-int.h" + +#ifdef HAVE_DAG_API +#include "pcap-dag.h" +#endif /* HAVE_DAG_API */ + +#ifdef HAVE_SEPTEL_API +#include "pcap-septel.h" +#endif /* HAVE_SEPTEL_API */ + +#ifdef HAVE_SNF_API +#include "pcap-snf.h" +#endif /* HAVE_SNF_API */ + +#ifdef PCAP_SUPPORT_USB +#include "pcap-usb-linux.h" +#endif + +#ifdef PCAP_SUPPORT_BT +#include "pcap-bt-linux.h" +#endif + +#ifdef PCAP_SUPPORT_BT_MONITOR +#include "pcap-bt-monitor-linux.h" +#endif + +#ifdef PCAP_SUPPORT_CAN +#include "pcap-can-linux.h" +#endif + +#ifdef PCAP_SUPPORT_CANUSB +#include "pcap-canusb-linux.h" +#endif + +#ifdef PCAP_SUPPORT_NETFILTER +#include "pcap-netfilter-linux.h" +#endif + +#ifdef PCAP_SUPPORT_DBUS +#include "pcap-dbus.h" +#endif + +int +pcap_not_initialized(pcap_t *pcap _U_) +{ + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +#ifdef WIN32 +Adapter * +pcap_no_adapter(pcap_t *pcap _U_) +{ + return (NULL); +} +#endif + +/* + * Returns 1 if rfmon mode can be set on the pcap_t, 0 if it can't, + * a PCAP_ERROR value on an error. + */ +int +pcap_can_set_rfmon(pcap_t *p) +{ + return (p->can_set_rfmon_op(p)); +} + +/* + * For systems where rfmon mode is never supported. + */ +static int +pcap_cant_set_rfmon(pcap_t *p _U_) +{ + return (0); +} + +/* + * Sets *tstamp_typesp to point to an array 1 or more supported time stamp + * types; the return value is the number of supported time stamp types. + * The list should be freed by a call to pcap_free_tstamp_types() when + * you're done with it. + * + * A return value of 0 means "you don't get a choice of time stamp type", + * in which case *tstamp_typesp is set to null. + * + * PCAP_ERROR is returned on error. + */ +int +pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp) +{ + if (p->tstamp_type_count == 0) { + /* + * We don't support multiple time stamp types. + */ + *tstamp_typesp = NULL; + } else { + *tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp), + p->tstamp_type_count); + if (*tstamp_typesp == NULL) { + (void)snprintf(p->errbuf, sizeof(p->errbuf), + "malloc: %s", pcap_strerror(errno)); + return (PCAP_ERROR); + } + (void)memcpy(*tstamp_typesp, p->tstamp_type_list, + sizeof(**tstamp_typesp) * p->tstamp_type_count); + } + return (p->tstamp_type_count); +} + +/* + * In Windows, you might have a library built with one version of the + * C runtime library and an application built with another version of + * the C runtime library, which means that the library might use one + * version of malloc() and free() and the application might use another + * version of malloc() and free(). If so, that means something + * allocated by the library cannot be freed by the application, so we + * need to have a pcap_free_tstamp_types() routine to free up the list + * allocated by pcap_list_tstamp_types(), even though it's just a wrapper + * around free(). + */ +void +pcap_free_tstamp_types(int *tstamp_type_list) +{ + free(tstamp_type_list); +} + +/* + * Default one-shot callback; overridden for capture types where the + * packet data cannot be guaranteed to be available after the callback + * returns, so that a copy must be made. + */ +void +pcap_oneshot(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt) +{ + struct oneshot_userdata *sp = (struct oneshot_userdata *)user; + + *sp->hdr = *h; + *sp->pkt = pkt; +} + +const u_char * +pcap_next(pcap_t *p, struct pcap_pkthdr *h) +{ + struct oneshot_userdata s; + const u_char *pkt; + + s.hdr = h; + s.pkt = &pkt; + s.pd = p; + if (pcap_dispatch(p, 1, p->oneshot_callback, (u_char *)&s) <= 0) + return (0); + return (pkt); +} + +int +pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, + const u_char **pkt_data) +{ + struct oneshot_userdata s; + + s.hdr = &p->pcap_header; + s.pkt = pkt_data; + s.pd = p; + + /* Saves a pointer to the packet headers */ + *pkt_header= &p->pcap_header; + + if (p->rfile != NULL) { + int status; + + /* We are on an offline capture */ + status = pcap_offline_read(p, 1, p->oneshot_callback, + (u_char *)&s); + + /* + * Return codes for pcap_offline_read() are: + * - 0: EOF + * - -1: error + * - >1: OK + * The first one ('0') conflicts with the return code of + * 0 from pcap_read() meaning "no packets arrived before + * the timeout expired", so we map it to -2 so you can + * distinguish between an EOF from a savefile and a + * "no packets arrived before the timeout expired, try + * again" from a live capture. + */ + if (status == 0) + return (-2); + else + return (status); + } + + /* + * Return codes for pcap_read() are: + * - 0: timeout + * - -1: error + * - -2: loop was broken out of with pcap_breakloop() + * - >1: OK + * The first one ('0') conflicts with the return code of 0 from + * pcap_offline_read() meaning "end of file". + */ + return (p->read_op(p, 1, p->oneshot_callback, (u_char *)&s)); +} + +#if defined(DAG_ONLY) +int +pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) +{ + return (dag_findalldevs(alldevsp, errbuf)); +} + +pcap_t * +pcap_create(const char *source, char *errbuf) +{ + int is_ours; + return (dag_create(source, errbuf, &is_ours)); +} +#elif defined(SEPTEL_ONLY) +int +pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) +{ + return (septel_findalldevs(alldevsp, errbuf)); +} + +pcap_t * +pcap_create(const char *source, char *errbuf) +{ + int is_ours; + return (septel_create(source, errbuf, &is_ours)); +} +#elif defined(SNF_ONLY) +int +pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) +{ + return (snf_findalldevs(alldevsp, errbuf)); +} + +pcap_t * +pcap_create(const char *source, char *errbuf) +{ + int is_ours; + return (snf_create(source, errbuf, &is_ours)); +} +#else /* regular pcap */ +struct capture_source_type { + int (*findalldevs_op)(pcap_if_t **, char *); + pcap_t *(*create_op)(const char *, char *, int *); +} capture_source_types[] = { +#ifdef HAVE_DAG_API + { dag_findalldevs, dag_create }, +#endif +#ifdef HAVE_SEPTEL_API + { septel_findalldevs, septel_create }, +#endif +#ifdef HAVE_SNF_API + { snf_findalldevs, snf_create }, +#endif +#ifdef PCAP_SUPPORT_BT + { bt_findalldevs, bt_create }, +#endif +#ifdef PCAP_SUPPORT_BT_MONITOR + { bt_monitor_findalldevs, bt_monitor_create }, +#endif +#if PCAP_SUPPORT_CANUSB + { canusb_findalldevs, canusb_create }, +#endif +#ifdef PCAP_SUPPORT_CAN + { can_findalldevs, can_create }, +#endif +#ifdef PCAP_SUPPORT_USB + { usb_findalldevs, usb_create }, +#endif +#ifdef PCAP_SUPPORT_NETFILTER + { netfilter_findalldevs, netfilter_create }, +#endif +#ifdef PCAP_SUPPORT_DBUS + { dbus_findalldevs, dbus_create }, +#endif + { NULL, NULL } +}; + +/* + * Get a list of all capture sources that are up and that we can open. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * were up and could be opened. + */ +int +pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) +{ + size_t i; + + /* + * Get the list of regular interfaces first. + */ + if (pcap_findalldevs_interfaces(alldevsp, errbuf) == -1) + return (-1); /* failure */ + + /* + * Add any interfaces that need a platform-specific mechanism + * to find. + */ + if (pcap_platform_finddevs(alldevsp, errbuf) == -1) { + /* + * We had an error; free the list we've been + * constructing. + */ + if (*alldevsp != NULL) { + pcap_freealldevs(*alldevsp); + *alldevsp = NULL; + } + return (-1); + } + + /* + * Ask each of the non-local-network-interface capture + * source types what interfaces they have. + */ + for (i = 0; capture_source_types[i].findalldevs_op != NULL; i++) { + if (capture_source_types[i].findalldevs_op(alldevsp, errbuf) == -1) { + /* + * We had an error; free the list we've been + * constructing. + */ + if (*alldevsp != NULL) { + pcap_freealldevs(*alldevsp); + *alldevsp = NULL; + } + return (-1); + } + } + + return (0); +} + +pcap_t * +pcap_create(const char *source, char *errbuf) +{ + size_t i; + int is_theirs; + pcap_t *p; + + /* + * A null source name is equivalent to the "any" device - + * which might not be supported on this platform, but + * this means that you'll get a "not supported" error + * rather than, say, a crash when we try to dereference + * the null pointer. + */ + if (source == NULL) + source = "any"; + + /* + * Try each of the non-local-network-interface capture + * source types until we find one that works for this + * device or run out of types. + */ + for (i = 0; capture_source_types[i].create_op != NULL; i++) { + is_theirs = 0; + p = capture_source_types[i].create_op(source, errbuf, &is_theirs); + if (is_theirs) { + /* + * The device name refers to a device of the + * type in question; either it succeeded, + * in which case p refers to a pcap_t to + * later activate for the device, or it + * failed, in which case p is null and we + * should return that to report the failure + * to create. + */ + return (p); + } + } + + /* + * OK, try it as a regular network interface. + */ + return (pcap_create_interface(source, errbuf)); +} +#endif + +static void +initialize_ops(pcap_t *p) +{ + /* + * Set operation pointers for operations that only work on + * an activated pcap_t to point to a routine that returns + * a "this isn't activated" error. + */ + p->read_op = (read_op_t)pcap_not_initialized; + p->inject_op = (inject_op_t)pcap_not_initialized; + p->setfilter_op = (setfilter_op_t)pcap_not_initialized; + p->setdirection_op = (setdirection_op_t)pcap_not_initialized; + p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized; + p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized; + p->setnonblock_op = (setnonblock_op_t)pcap_not_initialized; + p->stats_op = (stats_op_t)pcap_not_initialized; +#ifdef WIN32 + p->setbuff_op = (setbuff_op_t)pcap_not_initialized; + p->setmode_op = (setmode_op_t)pcap_not_initialized; + p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized; + p->getadapter_op = pcap_no_adapter; +#endif + + /* + * Default cleanup operation - implementations can override + * this, but should call pcap_cleanup_live_common() after + * doing their own additional cleanup. + */ + p->cleanup_op = pcap_cleanup_live_common; + + /* + * In most cases, the standard one-shot callback can + * be used for pcap_next()/pcap_next_ex(). + */ + p->oneshot_callback = pcap_oneshot; +} + +static pcap_t * +pcap_alloc_pcap_t(char *ebuf, size_t size) +{ + char *chunk; + pcap_t *p; + + /* + * Allocate a chunk of memory big enough for a pcap_t + * plus a structure following it of size "size". The + * structure following it is a private data structure + * for the routines that handle this pcap_t. + */ + chunk = malloc(sizeof (pcap_t) + size); + if (chunk == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + return (NULL); + } + memset(chunk, 0, sizeof (pcap_t) + size); + + /* + * Get a pointer to the pcap_t at the beginning. + */ + p = (pcap_t *)chunk; + +#ifndef WIN32 + p->fd = -1; /* not opened yet */ + p->selectable_fd = -1; +#endif + + if (size == 0) { + /* No private data was requested. */ + p->priv = NULL; + } else { + /* + * Set the pointer to the private data; that's the structure + * of size "size" following the pcap_t. + */ + p->priv = (void *)(chunk + sizeof (pcap_t)); + } + + return (p); +} + +pcap_t * +pcap_create_common(const char *source, char *ebuf, size_t size) +{ + pcap_t *p; + + p = pcap_alloc_pcap_t(ebuf, size); + if (p == NULL) + return (NULL); + + p->opt.source = strdup(source); + if (p->opt.source == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + free(p); + return (NULL); + } + + /* + * Default to "can't set rfmon mode"; if it's supported by + * a platform, the create routine that called us can set + * the op to its routine to check whether a particular + * device supports it. + */ + p->can_set_rfmon_op = pcap_cant_set_rfmon; + + initialize_ops(p); + + /* put in some defaults*/ + pcap_set_snaplen(p, MAXIMUM_SNAPLEN); /* max packet size */ + p->opt.timeout = 0; /* no timeout specified */ + p->opt.buffer_size = 0; /* use the platform's default */ + p->opt.promisc = 0; + p->opt.rfmon = 0; + p->opt.immediate = 0; + p->opt.tstamp_type = -1; /* default to not setting time stamp type */ + p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO; + + /* + * Start out with no BPF code generation flags set. + */ + p->bpf_codegen_flags = 0; + + return (p); +} + +int +pcap_check_activated(pcap_t *p) +{ + if (p->activated) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform " + " operation on activated capture"); + return (-1); + } + return (0); +} + +int +pcap_set_snaplen(pcap_t *p, int snaplen) +{ + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->snapshot = snaplen; + return (0); +} + +int +pcap_set_promisc(pcap_t *p, int promisc) +{ + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.promisc = promisc; + return (0); +} + +int +pcap_set_rfmon(pcap_t *p, int rfmon) +{ + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.rfmon = rfmon; + return (0); +} + +int +pcap_set_timeout(pcap_t *p, int timeout_ms) +{ + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.timeout = timeout_ms; + return (0); +} + +int +pcap_set_tstamp_type(pcap_t *p, int tstamp_type) +{ + int i; + + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + + /* + * If p->tstamp_type_count is 0, we only support PCAP_TSTAMP_HOST; + * the default time stamp type is PCAP_TSTAMP_HOST. + */ + if (p->tstamp_type_count == 0) { + if (tstamp_type == PCAP_TSTAMP_HOST) { + p->opt.tstamp_type = tstamp_type; + return (0); + } + } else { + /* + * Check whether we claim to support this type of time stamp. + */ + for (i = 0; i < p->tstamp_type_count; i++) { + if (p->tstamp_type_list[i] == tstamp_type) { + /* + * Yes. + */ + p->opt.tstamp_type = tstamp_type; + return (0); + } + } + } + + /* + * We don't support this type of time stamp. + */ + return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP); +} + +int +pcap_set_immediate_mode(pcap_t *p, int immediate) +{ + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.immediate = immediate; + return (0); +} + +int +pcap_set_buffer_size(pcap_t *p, int buffer_size) +{ + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.buffer_size = buffer_size; + return (0); +} + +int +pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision) +{ + int i; + + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + + /* + * If p->tstamp_precision_count is 0, we only support setting + * the time stamp precision to microsecond precision; every + * pcap module *MUST* support microsecond precision, even if + * it does so by converting the native precision to + * microseconds. + */ + if (p->tstamp_precision_count == 0) { + if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO) { + p->opt.tstamp_precision = tstamp_precision; + return (0); + } + } else { + /* + * Check whether we claim to support this precision of + * time stamp. + */ + for (i = 0; i < p->tstamp_precision_count; i++) { + if (p->tstamp_precision_list[i] == tstamp_precision) { + /* + * Yes. + */ + p->opt.tstamp_precision = tstamp_precision; + return (0); + } + } + } + + /* + * We don't support this time stamp precision. + */ + return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP); +} + +int +pcap_get_tstamp_precision(pcap_t *p) +{ + return (p->opt.tstamp_precision); +} + +int +pcap_activate(pcap_t *p) +{ + int status; + + /* + * Catch attempts to re-activate an already-activated + * pcap_t; this should, for example, catch code that + * calls pcap_open_live() followed by pcap_activate(), + * as some code that showed up in a Stack Exchange + * question did. + */ + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + status = p->activate_op(p); + if (status >= 0) + p->activated = 1; + else { + if (p->errbuf[0] == '\0') { + /* + * No error message supplied by the activate routine; + * for the benefit of programs that don't specially + * handle errors other than PCAP_ERROR, return the + * error message corresponding to the status. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", + pcap_statustostr(status)); + } + + /* + * Undo any operation pointer setting, etc. done by + * the activate operation. + */ + initialize_ops(p); + } + return (status); +} + +pcap_t * +pcap_open_live(const char *source, int snaplen, int promisc, int to_ms, char *errbuf) +{ + pcap_t *p; + int status; + + p = pcap_create(source, errbuf); + if (p == NULL) + return (NULL); + status = pcap_set_snaplen(p, snaplen); + if (status < 0) + goto fail; + status = pcap_set_promisc(p, promisc); + if (status < 0) + goto fail; + status = pcap_set_timeout(p, to_ms); + if (status < 0) + goto fail; + /* + * Mark this as opened with pcap_open_live(), so that, for + * example, we show the full list of DLT_ values, rather + * than just the ones that are compatible with capturing + * when not in monitor mode. That allows existing applications + * to work the way they used to work, but allows new applications + * that know about the new open API to, for example, find out the + * DLT_ values that they can select without changing whether + * the adapter is in monitor mode or not. + */ + p->oldstyle = 1; + status = pcap_activate(p); + if (status < 0) + goto fail; + return (p); +fail: + if (status == PCAP_ERROR) + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, + p->errbuf); + else if (status == PCAP_ERROR_NO_SUCH_DEVICE || + status == PCAP_ERROR_PERM_DENIED || + status == PCAP_ERROR_PROMISC_PERM_DENIED) + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", source, + pcap_statustostr(status), p->errbuf); + else + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, + pcap_statustostr(status)); + pcap_close(p); + return (NULL); +} + +pcap_t * +pcap_open_offline_common(char *ebuf, size_t size) +{ + pcap_t *p; + + p = pcap_alloc_pcap_t(ebuf, size); + if (p == NULL) + return (NULL); + + p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO; + p->opt.source = strdup("(savefile)"); + if (p->opt.source == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + free(p); + return (NULL); + } + + return (p); +} + +int +pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + return (p->read_op(p, cnt, callback, user)); +} + +/* + * XXX - is this necessary? + */ +int +pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + + return (p->read_op(p, cnt, callback, user)); +} + +int +pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + register int n; + + for (;;) { + if (p->rfile != NULL) { + /* + * 0 means EOF, so don't loop if we get 0. + */ + n = pcap_offline_read(p, cnt, callback, user); + } else { + /* + * XXX keep reading until we get something + * (or an error occurs) + */ + do { + n = p->read_op(p, cnt, callback, user); + } while (n == 0); + } + if (n <= 0) + return (n); + if (!PACKET_COUNT_IS_UNLIMITED(cnt)) { + cnt -= n; + if (cnt <= 0) + return (0); + } + } +} + +/* + * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate. + */ +void +pcap_breakloop(pcap_t *p) +{ + p->break_loop = 1; +} + +int +pcap_datalink(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->linktype); +} + +int +pcap_datalink_ext(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->linktype_ext); +} + +int +pcap_list_datalinks(pcap_t *p, int **dlt_buffer) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + if (p->dlt_count == 0) { + /* + * We couldn't fetch the list of DLTs, which means + * this platform doesn't support changing the + * DLT for an interface. Return a list of DLTs + * containing only the DLT this device supports. + */ + *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer)); + if (*dlt_buffer == NULL) { + (void)snprintf(p->errbuf, sizeof(p->errbuf), + "malloc: %s", pcap_strerror(errno)); + return (PCAP_ERROR); + } + **dlt_buffer = p->linktype; + return (1); + } else { + *dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count); + if (*dlt_buffer == NULL) { + (void)snprintf(p->errbuf, sizeof(p->errbuf), + "malloc: %s", pcap_strerror(errno)); + return (PCAP_ERROR); + } + (void)memcpy(*dlt_buffer, p->dlt_list, + sizeof(**dlt_buffer) * p->dlt_count); + return (p->dlt_count); + } +} + +/* + * In Windows, you might have a library built with one version of the + * C runtime library and an application built with another version of + * the C runtime library, which means that the library might use one + * version of malloc() and free() and the application might use another + * version of malloc() and free(). If so, that means something + * allocated by the library cannot be freed by the application, so we + * need to have a pcap_free_datalinks() routine to free up the list + * allocated by pcap_list_datalinks(), even though it's just a wrapper + * around free(). + */ +void +pcap_free_datalinks(int *dlt_list) +{ + free(dlt_list); +} + +int +pcap_set_datalink(pcap_t *p, int dlt) +{ + int i; + const char *dlt_name; + + if (p->dlt_count == 0 || p->set_datalink_op == NULL) { + /* + * We couldn't fetch the list of DLTs, or we don't + * have a "set datalink" operation, which means + * this platform doesn't support changing the + * DLT for an interface. Check whether the new + * DLT is the one this interface supports. + */ + if (p->linktype != dlt) + goto unsupported; + + /* + * It is, so there's nothing we need to do here. + */ + return (0); + } + for (i = 0; i < p->dlt_count; i++) + if (p->dlt_list[i] == dlt) + break; + if (i >= p->dlt_count) + goto unsupported; + if (p->dlt_count == 2 && p->dlt_list[0] == DLT_EN10MB && + dlt == DLT_DOCSIS) { + /* + * This is presumably an Ethernet device, as the first + * link-layer type it offers is DLT_EN10MB, and the only + * other type it offers is DLT_DOCSIS. That means that + * we can't tell the driver to supply DOCSIS link-layer + * headers - we're just pretending that's what we're + * getting, as, presumably, we're capturing on a dedicated + * link to a Cisco Cable Modem Termination System, and + * it's putting raw DOCSIS frames on the wire inside low-level + * Ethernet framing. + */ + p->linktype = dlt; + return (0); + } + if (p->set_datalink_op(p, dlt) == -1) + return (-1); + p->linktype = dlt; + return (0); + +unsupported: + dlt_name = pcap_datalink_val_to_name(dlt); + if (dlt_name != NULL) { + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "%s is not one of the DLTs supported by this device", + dlt_name); + } else { + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "DLT %d is not one of the DLTs supported by this device", + dlt); + } + return (-1); +} + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +static const u_char charmap[] = { + (u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003', + (u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007', + (u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013', + (u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017', + (u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023', + (u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027', + (u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033', + (u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037', + (u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043', + (u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047', + (u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053', + (u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057', + (u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063', + (u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067', + (u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073', + (u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077', + (u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143', + (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147', + (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153', + (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157', + (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163', + (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167', + (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133', + (u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137', + (u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143', + (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147', + (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153', + (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157', + (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163', + (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167', + (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173', + (u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177', + (u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203', + (u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207', + (u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213', + (u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217', + (u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223', + (u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227', + (u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233', + (u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237', + (u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243', + (u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247', + (u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253', + (u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257', + (u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263', + (u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267', + (u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273', + (u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277', + (u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343', + (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347', + (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353', + (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357', + (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363', + (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367', + (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333', + (u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337', + (u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343', + (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347', + (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353', + (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357', + (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363', + (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367', + (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373', + (u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377', +}; + +int +pcap_strcasecmp(const char *s1, const char *s2) +{ + register const u_char *cm = charmap, + *us1 = (const u_char *)s1, + *us2 = (const u_char *)s2; + + while (cm[*us1] == cm[*us2++]) + if (*us1++ == '\0') + return(0); + return (cm[*us1] - cm[*--us2]); +} + +struct dlt_choice { + const char *name; + const char *description; + int dlt; +}; + +#define DLT_CHOICE(code, description) { #code, description, code } +#define DLT_CHOICE_SENTINEL { NULL, NULL, 0 } + +static struct dlt_choice dlt_choices[] = { + DLT_CHOICE(DLT_NULL, "BSD loopback"), + DLT_CHOICE(DLT_EN10MB, "Ethernet"), + DLT_CHOICE(DLT_IEEE802, "Token ring"), + DLT_CHOICE(DLT_ARCNET, "BSD ARCNET"), + DLT_CHOICE(DLT_SLIP, "SLIP"), + DLT_CHOICE(DLT_PPP, "PPP"), + DLT_CHOICE(DLT_FDDI, "FDDI"), + DLT_CHOICE(DLT_ATM_RFC1483, "RFC 1483 LLC-encapsulated ATM"), + DLT_CHOICE(DLT_RAW, "Raw IP"), + DLT_CHOICE(DLT_SLIP_BSDOS, "BSD/OS SLIP"), + DLT_CHOICE(DLT_PPP_BSDOS, "BSD/OS PPP"), + DLT_CHOICE(DLT_ATM_CLIP, "Linux Classical IP-over-ATM"), + DLT_CHOICE(DLT_PPP_SERIAL, "PPP over serial"), + DLT_CHOICE(DLT_PPP_ETHER, "PPPoE"), + DLT_CHOICE(DLT_SYMANTEC_FIREWALL, "Symantec Firewall"), + DLT_CHOICE(DLT_C_HDLC, "Cisco HDLC"), + DLT_CHOICE(DLT_IEEE802_11, "802.11"), + DLT_CHOICE(DLT_FRELAY, "Frame Relay"), + DLT_CHOICE(DLT_LOOP, "OpenBSD loopback"), + DLT_CHOICE(DLT_ENC, "OpenBSD encapsulated IP"), + DLT_CHOICE(DLT_LINUX_SLL, "Linux cooked"), + DLT_CHOICE(DLT_LTALK, "Localtalk"), + DLT_CHOICE(DLT_PFLOG, "OpenBSD pflog file"), + DLT_CHOICE(DLT_PFSYNC, "Packet filter state syncing"), + DLT_CHOICE(DLT_PRISM_HEADER, "802.11 plus Prism header"), + DLT_CHOICE(DLT_IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"), + DLT_CHOICE(DLT_SUNATM, "Sun raw ATM"), + DLT_CHOICE(DLT_IEEE802_11_RADIO, "802.11 plus radiotap header"), + DLT_CHOICE(DLT_ARCNET_LINUX, "Linux ARCNET"), + DLT_CHOICE(DLT_JUNIPER_MLPPP, "Juniper Multi-Link PPP"), + DLT_CHOICE(DLT_JUNIPER_MLFR, "Juniper Multi-Link Frame Relay"), + DLT_CHOICE(DLT_JUNIPER_ES, "Juniper Encryption Services PIC"), + DLT_CHOICE(DLT_JUNIPER_GGSN, "Juniper GGSN PIC"), + DLT_CHOICE(DLT_JUNIPER_MFR, "Juniper FRF.16 Frame Relay"), + DLT_CHOICE(DLT_JUNIPER_ATM2, "Juniper ATM2 PIC"), + DLT_CHOICE(DLT_JUNIPER_SERVICES, "Juniper Advanced Services PIC"), + DLT_CHOICE(DLT_JUNIPER_ATM1, "Juniper ATM1 PIC"), + DLT_CHOICE(DLT_APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"), + DLT_CHOICE(DLT_MTP2_WITH_PHDR, "SS7 MTP2 with Pseudo-header"), + DLT_CHOICE(DLT_MTP2, "SS7 MTP2"), + DLT_CHOICE(DLT_MTP3, "SS7 MTP3"), + DLT_CHOICE(DLT_SCCP, "SS7 SCCP"), + DLT_CHOICE(DLT_DOCSIS, "DOCSIS"), + DLT_CHOICE(DLT_LINUX_IRDA, "Linux IrDA"), + DLT_CHOICE(DLT_IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"), + DLT_CHOICE(DLT_JUNIPER_MONITOR, "Juniper Passive Monitor PIC"), + DLT_CHOICE(DLT_BACNET_MS_TP, "BACnet MS/TP"), + DLT_CHOICE(DLT_PPP_PPPD, "PPP for pppd, with direction flag"), + DLT_CHOICE(DLT_JUNIPER_PPPOE, "Juniper PPPoE"), + DLT_CHOICE(DLT_JUNIPER_PPPOE_ATM, "Juniper PPPoE/ATM"), + DLT_CHOICE(DLT_GPRS_LLC, "GPRS LLC"), + DLT_CHOICE(DLT_GPF_T, "GPF-T"), + DLT_CHOICE(DLT_GPF_F, "GPF-F"), + DLT_CHOICE(DLT_JUNIPER_PIC_PEER, "Juniper PIC Peer"), + DLT_CHOICE(DLT_ERF_ETH, "Ethernet with Endace ERF header"), + DLT_CHOICE(DLT_ERF_POS, "Packet-over-SONET with Endace ERF header"), + DLT_CHOICE(DLT_LINUX_LAPD, "Linux vISDN LAPD"), + DLT_CHOICE(DLT_JUNIPER_ETHER, "Juniper Ethernet"), + DLT_CHOICE(DLT_JUNIPER_PPP, "Juniper PPP"), + DLT_CHOICE(DLT_JUNIPER_FRELAY, "Juniper Frame Relay"), + DLT_CHOICE(DLT_JUNIPER_CHDLC, "Juniper C-HDLC"), + DLT_CHOICE(DLT_MFR, "FRF.16 Frame Relay"), + DLT_CHOICE(DLT_JUNIPER_VP, "Juniper Voice PIC"), + DLT_CHOICE(DLT_A429, "Arinc 429"), + DLT_CHOICE(DLT_A653_ICM, "Arinc 653 Interpartition Communication"), + DLT_CHOICE(DLT_USB, "USB"), + DLT_CHOICE(DLT_BLUETOOTH_HCI_H4, "Bluetooth HCI UART transport layer"), + DLT_CHOICE(DLT_IEEE802_16_MAC_CPS, "IEEE 802.16 MAC Common Part Sublayer"), + DLT_CHOICE(DLT_USB_LINUX, "USB with Linux header"), + DLT_CHOICE(DLT_CAN20B, "Controller Area Network (CAN) v. 2.0B"), + DLT_CHOICE(DLT_IEEE802_15_4_LINUX, "IEEE 802.15.4 with Linux padding"), + DLT_CHOICE(DLT_PPI, "Per-Packet Information"), + DLT_CHOICE(DLT_IEEE802_16_MAC_CPS_RADIO, "IEEE 802.16 MAC Common Part Sublayer plus radiotap header"), + DLT_CHOICE(DLT_JUNIPER_ISM, "Juniper Integrated Service Module"), + DLT_CHOICE(DLT_IEEE802_15_4, "IEEE 802.15.4 with FCS"), + DLT_CHOICE(DLT_SITA, "SITA pseudo-header"), + DLT_CHOICE(DLT_ERF, "Endace ERF header"), + DLT_CHOICE(DLT_RAIF1, "Ethernet with u10 Networks pseudo-header"), + DLT_CHOICE(DLT_IPMB, "IPMB"), + DLT_CHOICE(DLT_JUNIPER_ST, "Juniper Secure Tunnel"), + DLT_CHOICE(DLT_BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"), + DLT_CHOICE(DLT_AX25_KISS, "AX.25 with KISS header"), + DLT_CHOICE(DLT_IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"), + DLT_CHOICE(DLT_MPLS, "MPLS with label as link-layer header"), + DLT_CHOICE(DLT_LINUX_EVDEV, "Linux evdev events"), + DLT_CHOICE(DLT_USB_LINUX_MMAPPED, "USB with padded Linux header"), + DLT_CHOICE(DLT_DECT, "DECT"), + DLT_CHOICE(DLT_AOS, "AOS Space Data Link protocol"), + DLT_CHOICE(DLT_WIHART, "Wireless HART"), + DLT_CHOICE(DLT_FC_2, "Fibre Channel FC-2"), + DLT_CHOICE(DLT_FC_2_WITH_FRAME_DELIMS, "Fibre Channel FC-2 with frame delimiters"), + DLT_CHOICE(DLT_IPNET, "Solaris ipnet"), + DLT_CHOICE(DLT_CAN_SOCKETCAN, "CAN-bus with SocketCAN headers"), + DLT_CHOICE(DLT_IPV4, "Raw IPv4"), + DLT_CHOICE(DLT_IPV6, "Raw IPv6"), + DLT_CHOICE(DLT_IEEE802_15_4_NOFCS, "IEEE 802.15.4 without FCS"), + DLT_CHOICE(DLT_DBUS, "D-Bus"), + DLT_CHOICE(DLT_JUNIPER_VS, "Juniper Virtual Server"), + DLT_CHOICE(DLT_JUNIPER_SRX_E2E, "Juniper SRX E2E"), + DLT_CHOICE(DLT_JUNIPER_FIBRECHANNEL, "Juniper Fibre Channel"), + DLT_CHOICE(DLT_DVB_CI, "DVB-CI"), + DLT_CHOICE(DLT_MUX27010, "MUX27010"), + DLT_CHOICE(DLT_STANAG_5066_D_PDU, "STANAG 5066 D_PDUs"), + DLT_CHOICE(DLT_JUNIPER_ATM_CEMIC, "Juniper ATM CEMIC"), + DLT_CHOICE(DLT_NFLOG, "Linux netfilter log messages"), + DLT_CHOICE(DLT_NETANALYZER, "Ethernet with Hilscher netANALYZER pseudo-header"), + DLT_CHOICE(DLT_NETANALYZER_TRANSPARENT, "Ethernet with Hilscher netANALYZER pseudo-header and with preamble and SFD"), + DLT_CHOICE(DLT_IPOIB, "RFC 4391 IP-over-Infiniband"), + DLT_CHOICE(DLT_MPEG_2_TS, "MPEG-2 transport stream"), + DLT_CHOICE(DLT_NG40, "ng40 protocol tester Iub/Iur"), + DLT_CHOICE(DLT_NFC_LLCP, "NFC LLCP PDUs with pseudo-header"), + DLT_CHOICE(DLT_INFINIBAND, "InfiniBand"), + DLT_CHOICE(DLT_SCTP, "SCTP"), + DLT_CHOICE(DLT_USBPCAP, "USB with USBPcap header"), + DLT_CHOICE(DLT_RTAC_SERIAL, "Schweitzer Engineering Laboratories RTAC packets"), + DLT_CHOICE(DLT_BLUETOOTH_LE_LL, "Bluetooth Low Energy air interface"), + DLT_CHOICE(DLT_NETLINK, "Linux netlink"), + DLT_CHOICE(DLT_BLUETOOTH_LINUX_MONITOR, "Bluetooth Linux Monitor"), + DLT_CHOICE(DLT_BLUETOOTH_BREDR_BB, "Bluetooth Basic Rate/Enhanced Data Rate baseband packets"), + DLT_CHOICE(DLT_BLUETOOTH_LE_LL_WITH_PHDR, "Bluetooth Low Energy air interface with pseudo-header"), + DLT_CHOICE(DLT_PROFIBUS_DL, "PROFIBUS data link layer"), + DLT_CHOICE(DLT_PKTAP, "Apple DLT_PKTAP"), + DLT_CHOICE(DLT_EPON, "Ethernet with 802.3 Clause 65 EPON preamble"), + DLT_CHOICE_SENTINEL +}; + +int +pcap_datalink_name_to_val(const char *name) +{ + int i; + + for (i = 0; dlt_choices[i].name != NULL; i++) { + if (pcap_strcasecmp(dlt_choices[i].name + sizeof("DLT_") - 1, + name) == 0) + return (dlt_choices[i].dlt); + } + return (-1); +} + +const char * +pcap_datalink_val_to_name(int dlt) +{ + int i; + + for (i = 0; dlt_choices[i].name != NULL; i++) { + if (dlt_choices[i].dlt == dlt) + return (dlt_choices[i].name + sizeof("DLT_") - 1); + } + return (NULL); +} + +const char * +pcap_datalink_val_to_description(int dlt) +{ + int i; + + for (i = 0; dlt_choices[i].name != NULL; i++) { + if (dlt_choices[i].dlt == dlt) + return (dlt_choices[i].description); + } + return (NULL); +} + +struct tstamp_type_choice { + const char *name; + const char *description; + int type; +}; + +static struct tstamp_type_choice tstamp_type_choices[] = { + { "host", "Host", PCAP_TSTAMP_HOST }, + { "host_lowprec", "Host, low precision", PCAP_TSTAMP_HOST_LOWPREC }, + { "host_hiprec", "Host, high precision", PCAP_TSTAMP_HOST_HIPREC }, + { "adapter", "Adapter", PCAP_TSTAMP_ADAPTER }, + { "adapter_unsynced", "Adapter, not synced with system time", PCAP_TSTAMP_ADAPTER_UNSYNCED }, + { NULL, NULL, 0 } +}; + +int +pcap_tstamp_type_name_to_val(const char *name) +{ + int i; + + for (i = 0; tstamp_type_choices[i].name != NULL; i++) { + if (pcap_strcasecmp(tstamp_type_choices[i].name, name) == 0) + return (tstamp_type_choices[i].type); + } + return (PCAP_ERROR); +} + +const char * +pcap_tstamp_type_val_to_name(int tstamp_type) +{ + int i; + + for (i = 0; tstamp_type_choices[i].name != NULL; i++) { + if (tstamp_type_choices[i].type == tstamp_type) + return (tstamp_type_choices[i].name); + } + return (NULL); +} + +const char * +pcap_tstamp_type_val_to_description(int tstamp_type) +{ + int i; + + for (i = 0; tstamp_type_choices[i].name != NULL; i++) { + if (tstamp_type_choices[i].type == tstamp_type) + return (tstamp_type_choices[i].description); + } + return (NULL); +} + +int +pcap_snapshot(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->snapshot); +} + +int +pcap_is_swapped(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->swapped); +} + +int +pcap_major_version(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->version_major); +} + +int +pcap_minor_version(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->version_minor); +} + +FILE * +pcap_file(pcap_t *p) +{ + return (p->rfile); +} + +int +pcap_fileno(pcap_t *p) +{ +#ifndef WIN32 + return (p->fd); +#else + if (p->adapter != NULL) + return ((int)(DWORD)p->adapter->hFile); + else + return (PCAP_ERROR); +#endif +} + +#if !defined(WIN32) && !defined(MSDOS) +int +pcap_get_selectable_fd(pcap_t *p) +{ + return (p->selectable_fd); +} +#endif + +void +pcap_perror(pcap_t *p, char *prefix) +{ + fprintf(stderr, "%s: %s\n", prefix, p->errbuf); +} + +char * +pcap_geterr(pcap_t *p) +{ + return (p->errbuf); +} + +int +pcap_getnonblock(pcap_t *p, char *errbuf) +{ + int ret; + + ret = p->getnonblock_op(p, errbuf); + if (ret == -1) { + /* + * In case somebody depended on the bug wherein + * the error message was put into p->errbuf + * by pcap_getnonblock_fd(). + */ + strlcpy(p->errbuf, errbuf, PCAP_ERRBUF_SIZE); + } + return (ret); +} + +/* + * Get the current non-blocking mode setting, under the assumption that + * it's just the standard POSIX non-blocking flag. + * + * We don't look at "p->nonblock", in case somebody tweaked the FD + * directly. + */ +#if !defined(WIN32) && !defined(MSDOS) +int +pcap_getnonblock_fd(pcap_t *p, char *errbuf) +{ + int fdflags; + + fdflags = fcntl(p->fd, F_GETFL, 0); + if (fdflags == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", + pcap_strerror(errno)); + return (-1); + } + if (fdflags & O_NONBLOCK) + return (1); + else + return (0); +} +#endif + +int +pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf) +{ + int ret; + + ret = p->setnonblock_op(p, nonblock, errbuf); + if (ret == -1) { + /* + * In case somebody depended on the bug wherein + * the error message was put into p->errbuf + * by pcap_setnonblock_fd(). + */ + strlcpy(p->errbuf, errbuf, PCAP_ERRBUF_SIZE); + } + return (ret); +} + +#if !defined(WIN32) && !defined(MSDOS) +/* + * Set non-blocking mode, under the assumption that it's just the + * standard POSIX non-blocking flag. (This can be called by the + * per-platform non-blocking-mode routine if that routine also + * needs to do some additional work.) + */ +int +pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf) +{ + int fdflags; + + fdflags = fcntl(p->fd, F_GETFL, 0); + if (fdflags == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", + pcap_strerror(errno)); + return (-1); + } + if (nonblock) + fdflags |= O_NONBLOCK; + else + fdflags &= ~O_NONBLOCK; + if (fcntl(p->fd, F_SETFL, fdflags) == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s", + pcap_strerror(errno)); + return (-1); + } + return (0); +} +#endif + +#ifdef WIN32 +/* + * Generate a string for the last Win32-specific error (i.e. an error generated when + * calling a Win32 API). + * For errors occurred during standard C calls, we still use pcap_strerror() + */ +char * +pcap_win32strerror(void) +{ + DWORD error; + static char errbuf[PCAP_ERRBUF_SIZE+1]; + int errlen; + char *p; + + error = GetLastError(); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, + PCAP_ERRBUF_SIZE, NULL); + + /* + * "FormatMessage()" "helpfully" sticks CR/LF at the end of the + * message. Get rid of it. + */ + errlen = strlen(errbuf); + if (errlen >= 2) { + errbuf[errlen - 1] = '\0'; + errbuf[errlen - 2] = '\0'; + } + p = strchr(errbuf, '\0'); + snprintf (p, sizeof(errbuf)-(p-errbuf), " (%lu)", error); + return (errbuf); +} +#endif + +/* + * Generate error strings for PCAP_ERROR_ and PCAP_WARNING_ values. + */ +const char * +pcap_statustostr(int errnum) +{ + static char ebuf[15+10+1]; + + switch (errnum) { + + case PCAP_WARNING: + return("Generic warning"); + + case PCAP_WARNING_TSTAMP_TYPE_NOTSUP: + return ("That type of time stamp is not supported by that device"); + + case PCAP_WARNING_PROMISC_NOTSUP: + return ("That device doesn't support promiscuous mode"); + + case PCAP_ERROR: + return("Generic error"); + + case PCAP_ERROR_BREAK: + return("Loop terminated by pcap_breakloop"); + + case PCAP_ERROR_NOT_ACTIVATED: + return("The pcap_t has not been activated"); + + case PCAP_ERROR_ACTIVATED: + return ("The setting can't be changed after the pcap_t is activated"); + + case PCAP_ERROR_NO_SUCH_DEVICE: + return ("No such device exists"); + + case PCAP_ERROR_RFMON_NOTSUP: + return ("That device doesn't support monitor mode"); + + case PCAP_ERROR_NOT_RFMON: + return ("That operation is supported only in monitor mode"); + + case PCAP_ERROR_PERM_DENIED: + return ("You don't have permission to capture on that device"); + + case PCAP_ERROR_IFACE_NOT_UP: + return ("That device is not up"); + + case PCAP_ERROR_CANTSET_TSTAMP_TYPE: + return ("That device doesn't support setting the time stamp type"); + + case PCAP_ERROR_PROMISC_PERM_DENIED: + return ("You don't have permission to capture in promiscuous mode on that device"); + + case PCAP_ERROR_TSTAMP_PRECISION_NOTSUP: + return ("That device doesn't support that time stamp precision"); + } + (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); + return(ebuf); +} + +/* + * Not all systems have strerror(). + */ +const char * +pcap_strerror(int errnum) +{ +#ifdef HAVE_STRERROR + return (strerror(errnum)); +#else + extern int sys_nerr; + extern const char *const sys_errlist[]; + static char ebuf[15+10+1]; + + if ((unsigned int)errnum < sys_nerr) + return ((char *)sys_errlist[errnum]); + (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); + return(ebuf); +#endif +} + +int +pcap_setfilter(pcap_t *p, struct bpf_program *fp) +{ + return (p->setfilter_op(p, fp)); +} + +/* + * Set direction flag, which controls whether we accept only incoming + * packets, only outgoing packets, or both. + * Note that, depending on the platform, some or all direction arguments + * might not be supported. + */ +int +pcap_setdirection(pcap_t *p, pcap_direction_t d) +{ + if (p->setdirection_op == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Setting direction is not implemented on this platform"); + return (-1); + } else + return (p->setdirection_op(p, d)); +} + +int +pcap_stats(pcap_t *p, struct pcap_stat *ps) +{ + return (p->stats_op(p, ps)); +} + +static int +pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Statistics aren't available from a pcap_open_dead pcap_t"); + return (-1); +} + +#ifdef WIN32 +int +pcap_setbuff(pcap_t *p, int dim) +{ + return (p->setbuff_op(p, dim)); +} + +static int +pcap_setbuff_dead(pcap_t *p, int dim) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The kernel buffer size cannot be set on a pcap_open_dead pcap_t"); + return (-1); +} + +int +pcap_setmode(pcap_t *p, int mode) +{ + return (p->setmode_op(p, mode)); +} + +static int +pcap_setmode_dead(pcap_t *p, int mode) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "impossible to set mode on a pcap_open_dead pcap_t"); + return (-1); +} + +int +pcap_setmintocopy(pcap_t *p, int size) +{ + return (p->setmintocopy_op(p, size)); +} + +Adapter * +pcap_get_adapter(pcap_t *p) +{ + return (p->getadapter_op(p)); +} + +static int +pcap_setmintocopy_dead(pcap_t *p, int size) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t"); + return (-1); +} +#endif + +/* + * On some platforms, we need to clean up promiscuous or monitor mode + * when we close a device - and we want that to happen even if the + * application just exits without explicitl closing devices. + * On those platforms, we need to register a "close all the pcaps" + * routine to be called when we exit, and need to maintain a list of + * pcaps that need to be closed to clean up modes. + * + * XXX - not thread-safe. + */ + +/* + * List of pcaps on which we've done something that needs to be + * cleaned up. + * If there are any such pcaps, we arrange to call "pcap_close_all()" + * when we exit, and have it close all of them. + */ +static struct pcap *pcaps_to_close; + +/* + * TRUE if we've already called "atexit()" to cause "pcap_close_all()" to + * be called on exit. + */ +static int did_atexit; + +static void +pcap_close_all(void) +{ + struct pcap *handle; + + while ((handle = pcaps_to_close) != NULL) + pcap_close(handle); +} + +int +pcap_do_addexit(pcap_t *p) +{ + /* + * If we haven't already done so, arrange to have + * "pcap_close_all()" called when we exit. + */ + if (!did_atexit) { + if (atexit(pcap_close_all) == -1) { + /* + * "atexit()" failed; let our caller know. + */ + strncpy(p->errbuf, "atexit failed", + PCAP_ERRBUF_SIZE); + return (0); + } + did_atexit = 1; + } + return (1); +} + +void +pcap_add_to_pcaps_to_close(pcap_t *p) +{ + p->next = pcaps_to_close; + pcaps_to_close = p; +} + +void +pcap_remove_from_pcaps_to_close(pcap_t *p) +{ + pcap_t *pc, *prevpc; + + for (pc = pcaps_to_close, prevpc = NULL; pc != NULL; + prevpc = pc, pc = pc->next) { + if (pc == p) { + /* + * Found it. Remove it from the list. + */ + if (prevpc == NULL) { + /* + * It was at the head of the list. + */ + pcaps_to_close = pc->next; + } else { + /* + * It was in the middle of the list. + */ + prevpc->next = pc->next; + } + break; + } + } +} + +void +pcap_cleanup_live_common(pcap_t *p) +{ + if (p->buffer != NULL) { + free(p->buffer); + p->buffer = NULL; + } + if (p->dlt_list != NULL) { + free(p->dlt_list); + p->dlt_list = NULL; + p->dlt_count = 0; + } + if (p->tstamp_type_list != NULL) { + free(p->tstamp_type_list); + p->tstamp_type_list = NULL; + p->tstamp_type_count = 0; + } + if (p->tstamp_precision_list != NULL) { + free(p->tstamp_precision_list); + p->tstamp_precision_list = NULL; + p->tstamp_precision_count = 0; + } + pcap_freecode(&p->fcode); +#if !defined(WIN32) && !defined(MSDOS) + if (p->fd >= 0) { + close(p->fd); + p->fd = -1; + } + p->selectable_fd = -1; +#endif +} + +static void +pcap_cleanup_dead(pcap_t *p _U_) +{ + /* Nothing to do. */ +} + +pcap_t * +pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision) +{ + pcap_t *p; + + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + case PCAP_TSTAMP_PRECISION_NANO: + break; + + default: + return NULL; + } + p = malloc(sizeof(*p)); + if (p == NULL) + return NULL; + memset (p, 0, sizeof(*p)); + p->snapshot = snaplen; + p->linktype = linktype; + p->opt.tstamp_precision = precision; + p->stats_op = pcap_stats_dead; +#ifdef WIN32 + p->setbuff_op = pcap_setbuff_dead; + p->setmode_op = pcap_setmode_dead; + p->setmintocopy_op = pcap_setmintocopy_dead; +#endif + p->cleanup_op = pcap_cleanup_dead; + + /* + * A "dead" pcap_t never requires special BPF code generation. + */ + p->bpf_codegen_flags = 0; + + p->activated = 1; + return (p); +} + +pcap_t * +pcap_open_dead(int linktype, int snaplen) +{ + return (pcap_open_dead_with_tstamp_precision(linktype, snaplen, + PCAP_TSTAMP_PRECISION_MICRO)); +} + +/* + * API compatible with WinPcap's "send a packet" routine - returns -1 + * on error, 0 otherwise. + * + * XXX - what if we get a short write? + */ +int +pcap_sendpacket(pcap_t *p, const u_char *buf, int size) +{ + if (p->inject_op(p, buf, size) == -1) + return (-1); + return (0); +} + +/* + * API compatible with OpenBSD's "send a packet" routine - returns -1 on + * error, number of bytes written otherwise. + */ +int +pcap_inject(pcap_t *p, const void *buf, size_t size) +{ + return (p->inject_op(p, buf, size)); +} + +void +pcap_close(pcap_t *p) +{ + if (p->opt.source != NULL) + free(p->opt.source); + p->cleanup_op(p); + free(p); +} + +/* + * Given a BPF program, a pcap_pkthdr structure for a packet, and the raw + * data for the packet, check whether the packet passes the filter. + * Returns the return value of the filter program, which will be zero if + * the packet doesn't pass and non-zero if the packet does pass. + */ +int +pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h, + const u_char *pkt) +{ + const struct bpf_insn *fcode = fp->bf_insns; + + if (fcode != NULL) + return (bpf_filter(fcode, pkt, h->len, h->caplen)); + else + return (0); +} + +/* + * We make the version string static, and return a pointer to it, rather + * than exporting the version string directly. On at least some UNIXes, + * if you import data from a shared library into an program, the data is + * bound into the program binary, so if the string in the version of the + * library with which the program was linked isn't the same as the + * string in the version of the library with which the program is being + * run, various undesirable things may happen (warnings, the string + * being the one from the version of the library with which the program + * was linked, or even weirder things, such as the string being the one + * from the library but being truncated). + */ +#ifdef HAVE_VERSION_H +#include "version.h" +#else +static const char pcap_version_string[] = "libpcap version 1.x.y"; +#endif + +#ifdef WIN32 +/* + * XXX - it'd be nice if we could somehow generate the WinPcap and libpcap + * version numbers when building WinPcap. (It'd be nice to do so for + * the packet.dll version number as well.) + */ +static const char wpcap_version_string[] = "4.0"; +static const char pcap_version_string_fmt[] = + "WinPcap version %s, based on %s"; +static const char pcap_version_string_packet_dll_fmt[] = + "WinPcap version %s (packet.dll version %s), based on %s"; +static char *full_pcap_version_string; + +const char * +pcap_lib_version(void) +{ + char *packet_version_string; + size_t full_pcap_version_string_len; + + if (full_pcap_version_string == NULL) { + /* + * Generate the version string. + */ + packet_version_string = PacketGetVersion(); + if (strcmp(wpcap_version_string, packet_version_string) == 0) { + /* + * WinPcap version string and packet.dll version + * string are the same; just report the WinPcap + * version. + */ + full_pcap_version_string_len = + (sizeof pcap_version_string_fmt - 4) + + strlen(wpcap_version_string) + + strlen(pcap_version_string); + full_pcap_version_string = + malloc(full_pcap_version_string_len); + if (full_pcap_version_string == NULL) + return (NULL); + sprintf(full_pcap_version_string, + pcap_version_string_fmt, wpcap_version_string, + pcap_version_string); + } else { + /* + * WinPcap version string and packet.dll version + * string are different; that shouldn't be the + * case (the two libraries should come from the + * same version of WinPcap), so we report both + * versions. + */ + full_pcap_version_string_len = + (sizeof pcap_version_string_packet_dll_fmt - 6) + + strlen(wpcap_version_string) + + strlen(packet_version_string) + + strlen(pcap_version_string); + full_pcap_version_string = malloc(full_pcap_version_string_len); + if (full_pcap_version_string == NULL) + return (NULL); + sprintf(full_pcap_version_string, + pcap_version_string_packet_dll_fmt, + wpcap_version_string, packet_version_string, + pcap_version_string); + } + } + return (full_pcap_version_string); +} + +#elif defined(MSDOS) + +static char *full_pcap_version_string; + +const char * +pcap_lib_version (void) +{ + char *packet_version_string; + size_t full_pcap_version_string_len; + static char dospfx[] = "DOS-"; + + if (full_pcap_version_string == NULL) { + /* + * Generate the version string. + */ + full_pcap_version_string_len = + sizeof dospfx + strlen(pcap_version_string); + full_pcap_version_string = + malloc(full_pcap_version_string_len); + if (full_pcap_version_string == NULL) + return (NULL); + strcpy(full_pcap_version_string, dospfx); + strcat(full_pcap_version_string, pcap_version_string); + } + return (full_pcap_version_string); +} + +#else /* UN*X */ + +const char * +pcap_lib_version(void) +{ + return (pcap_version_string); +} +#endif diff --git a/tcpdump/jni/libpcap/pcap.h b/tcpdump/jni/libpcap/pcap.h new file mode 100644 index 0000000..174e32d --- /dev/null +++ b/tcpdump/jni/libpcap/pcap.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Many applications + * expect to be able to include , and at least some of them + * go through contortions in their configure scripts to try to detect + * OSes that have "helpfully" moved pcap.h to without + * leaving behind a file. + */ +#include diff --git a/tcpdump/jni/libpcap/pcap/bluetooth.h b/tcpdump/jni/libpcap/pcap/bluetooth.h new file mode 100644 index 0000000..01bd5a2 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap/bluetooth.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * bluetooth data struct + * By Paolo Abeni + */ + +#ifndef _PCAP_BLUETOOTH_STRUCTS_H__ +#define _PCAP_BLUETOOTH_STRUCTS_H__ + +/* + * Header prepended libpcap to each bluetooth h4 frame, + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_h4_header { + u_int32_t direction; /* if first bit is set direction is incoming */ +} pcap_bluetooth_h4_header; + +/* + * Header prepended libpcap to each bluetooth linux monitor frame, + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_linux_monitor_header { + u_int16_t adapter_id; + u_int16_t opcode; +} pcap_bluetooth_linux_monitor_header; + + +#endif diff --git a/tcpdump/jni/libpcap/pcap/bpf.h b/tcpdump/jni/libpcap/pcap/bpf.h new file mode 100644 index 0000000..215d5ca --- /dev/null +++ b/tcpdump/jni/libpcap/pcap/bpf.h @@ -0,0 +1,1514 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + */ + +/* + * This is libpcap's cut-down version of bpf.h; it includes only + * the stuff needed for the code generator and the userland BPF + * interpreter, and the libpcap APIs for setting filters, etc.. + * + * "pcap-bpf.c" will include the native OS version, as it deals with + * the OS's BPF implementation. + * + * At least two programs found by Google Code Search explicitly includes + * (even though / includes it for you), + * so moving that stuff to would break the build for some + * programs. + */ + +/* + * If we've already included , don't re-define this stuff. + * We assume BSD-style multiple-include protection in , + * which is true of all but the oldest versions of FreeBSD and NetBSD, + * or Tru64 UNIX-style multiple-include protection (or, at least, + * Tru64 UNIX 5.x-style; I don't have earlier versions available to check), + * or AIX-style multiple-include protection (or, at least, AIX 5.x-style; + * I don't have earlier versions available to check), or QNX-style + * multiple-include protection (as per GitHub pull request #394). + * + * We do not check for BPF_MAJOR_VERSION, as that's defined by + * , which is directly or indirectly included in some + * programs that also include pcap.h, and doesn't + * define stuff we need. + * + * This also provides our own multiple-include protection. + */ +#if !defined(_NET_BPF_H_) && !defined(_NET_BPF_H_INCLUDED) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) +#define lib_pcap_bpf_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + * + * Tcpdump's print-pflog.c uses this, so we define it here. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Link-layer header type codes. + * + * Do *NOT* add new values to this list without asking + * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run + * the risk of using a value that's already being used for some other + * purpose, and of having tools that read libpcap-format captures not + * being able to handle captures with your new DLT_ value, with no hope + * that they will ever be changed to do so (as that would destroy their + * ability to read captures using that value for that other purpose). + * + * See + * + * http://www.tcpdump.org/linktypes.html + * + * for detailed descriptions of some of these link-layer header types. + */ + +/* + * These are the types that are the same on all platforms, and that + * have been defined by for ages. + */ +#define DLT_NULL 0 /* BSD loopback encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* 802.5 Token Ring */ +#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are types that are different on some platforms, and that + * have been defined by for ages. We use #ifdefs to + * detect the BSDs that define them differently from the traditional + * libpcap + * + * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, + * but I don't know what the right #define is for BSD/OS. + */ +#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ + +#ifdef __OpenBSD__ +#define DLT_RAW 14 /* raw IP */ +#else +#define DLT_RAW 12 /* raw IP */ +#endif + +/* + * Given that the only OS that currently generates BSD/OS SLIP or PPP + * is, well, BSD/OS, arguably everybody should have chosen its values + * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they + * didn't. So it goes. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +/* + * 17 was used for DLT_PFLOG in OpenBSD; it no longer is. + * + * It was DLT_LANE8023 in SuSE 6.3, so we defined LINKTYPE_PFLOG + * as 117 so that pflog captures would use a link-layer header type + * value that didn't collide with any other values. On all + * platforms other than OpenBSD, we defined DLT_PFLOG as 117, + * and we mapped between LINKTYPE_PFLOG and DLT_PFLOG. + * + * OpenBSD eventually switched to using 117 for DLT_PFLOG as well. + * + * Don't use 17 for anything else. + */ + +/* + * 18 is used for DLT_PFSYNC in OpenBSD, NetBSD, DragonFly BSD and + * Mac OS X; don't use it for anything else. (FreeBSD uses 121, + * which collides with DLT_HHDLC, even though it doesn't use 18 + * for anything and doesn't appear to have ever used it for anything.) + * + * We define it as 18 on those platforms; it is, unfortunately, used + * for DLT_CIP in Suse 6.3, so we don't define it as DLT_PFSYNC + * in general. As the packet format for it, like that for + * DLT_PFLOG, is not only OS-dependent but OS-version-dependent, + * we don't support printing it in tcpdump except on OSes that + * have the relevant header files, so it's not that useful on + * other platforms. + */ +#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__) +#define DLT_PFSYNC 18 +#endif + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * Apparently Redback uses this for its SmartEdge 400/800. I hope + * nobody else decided to use it, too. + */ +#define DLT_REDBACK_SMARTEDGE 32 + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses + * a link-layer type of 99 for the tcpdump it supplies. The link-layer + * header has 6 bytes of unknown data, something that appears to be an + * Ethernet type, and 36 bytes that appear to be 0 in at least one capture + * I've seen. + */ +#define DLT_SYMANTEC_FIREWALL 99 + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer header type LINKTYPE_ values corresponding to DLT_ types + * that differ between platforms; don't use those values for new DLT_ + * new types. + */ + +/* + * Values starting with 104 are used for newly-assigned link-layer + * header type values; for those link-layer header types, the DLT_ + * value returned by pcap_datalink() and passed to pcap_open_dead(), + * and the LINKTYPE_ value that appears in capture files, are the + * same. + * + * DLT_MATCHING_MIN is the lowest such value; DLT_MATCHING_MAX is + * the highest such value. + */ +#define DLT_MATCHING_MIN 104 + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, + * except when it isn't. (I.e., sometimes it's just raw IP, and + * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, + * so that we don't have to worry about the link-layer header.) + */ + +/* + * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides + * with other values. + * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header + * (DLCI, etc.). + */ +#define DLT_FRELAY 107 + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so + * we don't use 12 for it in OSes other than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_LOOP 12 +#else +#define DLT_LOOP 108 +#endif + +/* + * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's + * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other + * than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_ENC 13 +#else +#define DLT_ENC 109 +#endif + +/* + * Values between 110 and 112 are reserved for use in capture file headers + * as link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * OpenBSD DLT_PFLOG. + */ +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * For 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Sigh. + * + * This was reserved for Siemens HiPath HDLC on 2002-01-25, as + * requested by Tomas Kukosa. + * + * On 2004-02-25, a FreeBSD checkin to sys/net/bpf.h was made that + * assigned 121 as DLT_PFSYNC. Its libpcap does DLT_ <-> LINKTYPE_ + * mapping, so it probably supports capturing on the pfsync device + * but not saving the captured data to a pcap file. + * + * OpenBSD, from which pf came, however, uses 18 for DLT_PFSYNC; + * their libpcap does no DLT_ <-> LINKTYPE_ mapping, so it would + * use 18 in pcap files as well. + * + * NetBSD and DragonFly BSD also use 18 for DLT_PFSYNC; their + * libpcaps do DLT_ <-> LINKTYPE_ mapping, and neither has an entry + * for DLT_PFSYNC, so it might not be able to write out dump files + * with 18 as the link-layer header type. (Earlier versions might + * not have done mapping, in which case they'd work the same way + * OpenBSD does.) + * + * Mac OS X defines it as 18, but doesn't appear to use it as of + * Mac OS X 10.7.3. Its libpcap does DLT_ <-> LINKTYPE_ mapping. + * + * We'll define DLT_PFSYNC as 121 on FreeBSD and define it as 18 on + * all other platforms. We'll define DLT_HHDLC as 121 on everything + * except for FreeBSD; anybody who wants to compile, on FreeBSD, code + * that uses DLT_HHDLC is out of luck. + * + * We'll define LINKTYPE_PFSYNC as 18, *even on FreeBSD*, and map + * it, so that savefiles won't use 121 for PFSYNC - they'll all + * use 18. Code that uses pcap_datalink() to determine the link-layer + * header type of a savefile won't, when built and run on FreeBSD, + * be able to distinguish between LINKTYPE_PFSYNC and LINKTYPE_HHDLC + * capture files; code that doesn't, such as the code in Wireshark, + * will be able to distinguish between them. + */ +#ifdef __FreeBSD__ +#define DLT_PFSYNC 121 +#else +#define DLT_HHDLC 121 +#endif + +/* + * This is for RFC 2625 IP-over-Fibre Channel. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * This is for Full Frontal ATM on Solaris with SunATM, with a + * pseudo-header followed by an AALn PDU. + * + * There may be other forms of Full Frontal ATM on other OSes, + * with different pseudo-headers. + * + * If ATM software returns a pseudo-header with VPI/VCI information + * (and, ideally, packet type information, e.g. signalling, ILMI, + * LANE, LLC-multiplexed traffic, etc.), it should not use + * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump + * and the like don't have to infer the presence or absence of a + * pseudo-header and the form of the pseudo-header. + */ +#define DLT_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define DLT_RIO 124 /* RapidIO */ +#define DLT_PCI_EXP 125 /* PCI Express */ +#define DLT_AURORA 126 /* Xilinx Aurora link layer */ + +/* + * Header for 802.11 plus a number of bits of link-layer information + * including radio information, used by some recent BSD drivers as + * well as the madwifi Atheros driver for Linux. + */ +#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ + +/* + * BSD's ARCNET headers have the source host, destination host, + * and type at the beginning of the packet; that's what's handed + * up to userland via BPF. + * + * Linux's ARCNET headers, however, have a 2-byte offset field + * between the host IDs and the type; that's what's handed up + * to userland via PF_PACKET sockets. + * + * We therefore have to have separate DLT_ values for them. + */ +#define DLT_ARCNET_LINUX 129 /* ARCNET */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MLPPP 130 +#define DLT_JUNIPER_MLFR 131 +#define DLT_JUNIPER_ES 132 +#define DLT_JUNIPER_GGSN 133 +#define DLT_JUNIPER_MFR 134 +#define DLT_JUNIPER_ATM2 135 +#define DLT_JUNIPER_SERVICES 136 +#define DLT_JUNIPER_ATM1 137 + +/* + * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund + * . The header that's presented is an Ethernet-like + * header: + * + * #define FIREWIRE_EUI64_LEN 8 + * struct firewire_header { + * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; + * u_char firewire_shost[FIREWIRE_EUI64_LEN]; + * u_short firewire_type; + * }; + * + * with "firewire_type" being an Ethernet type value, rather than, + * for example, raw GASP frames being handed up. + */ +#define DLT_APPLE_IP_OVER_IEEE1394 138 + +/* + * Various SS7 encapsulations, as per a request from Jeff Morriss + * and subsequent discussions. + */ +#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ +#define DLT_MTP2 140 /* MTP2, without pseudo-header */ +#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ +#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ + +/* + * DOCSIS MAC frames. + */ +#define DLT_DOCSIS 143 + +/* + * Linux-IrDA packets. Protocol defined at http://www.irda.org. + * Those packets include IrLAP headers and above (IrLMP...), but + * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy + * framing can be handled by the hardware and depend on the bitrate. + * This is exactly the format you would get capturing on a Linux-IrDA + * interface (irdaX), but not on a raw serial port. + * Note the capture is done in "Linux-cooked" mode, so each packet include + * a fake packet header (struct sll_header). This is because IrDA packet + * decoding is dependant on the direction of the packet (incomming or + * outgoing). + * When/if other platform implement IrDA capture, we may revisit the + * issue and define a real DLT_IRDA... + * Jean II + */ +#define DLT_LINUX_IRDA 144 + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define DLT_IBM_SP 145 +#define DLT_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that DLT_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, + * as per the comment above, and use the type you're given. + */ +#define DLT_USER0 147 +#define DLT_USER1 148 +#define DLT_USER2 149 +#define DLT_USER3 150 +#define DLT_USER4 151 +#define DLT_USER5 152 +#define DLT_USER6 153 +#define DLT_USER7 154 +#define DLT_USER8 155 +#define DLT_USER9 156 +#define DLT_USER10 157 +#define DLT_USER11 158 +#define DLT_USER12 159 +#define DLT_USER13 160 +#define DLT_USER14 161 +#define DLT_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but it might be used by some non-AVS drivers now or in the + * future. + */ +#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MONITOR 164 + +/* + * BACnet MS/TP frames. + */ +#define DLT_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accomodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define DLT_PPP_PPPD 166 + +/* + * Names for backwards compatibility with older versions of some PPP + * software; new software should use DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD +#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define DLT_JUNIPER_PPPOE 167 +#define DLT_JUNIPER_PPPOE_ATM 168 + +#define DLT_GPRS_LLC 169 /* GPRS LLC */ +#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define DLT_GCOM_T1E1 172 +#define DLT_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define DLT_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define DLT_ERF_ETH 175 /* Ethernet */ +#define DLT_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define DLT_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define DLT_JUNIPER_ETHER 178 +#define DLT_JUNIPER_PPP 179 +#define DLT_JUNIPER_FRELAY 180 +#define DLT_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define DLT_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define DLT_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define DLT_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define DLT_A653_ICM 185 + +/* + * USB packets, beginning with a USB setup header; requested by + * Paolo Abeni . + */ +#define DLT_USB 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define DLT_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define DLT_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define DLT_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define DLT_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * DLT_ requested by Gianluca Varenni . + */ +#define DLT_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define DLT_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define DLT_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing); requested by Mikko Saarnivala . + * For this one, we expect the FCS to be present at the end of the frame; + * if the frame has no FCS, DLT_IEEE802_15_4_NOFCS should be used. + */ +#define DLT_IEEE802_15_4 195 + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define DLT_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define DLT_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define DLT_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with the I2C slave address, followed + * by the netFn and LUN, etc.. Requested by Chanthy Toeung + * . + */ +#define DLT_IPMB 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define DLT_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define DLT_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define DLT_LAPD 203 + +/* + * Variants of various link-layer headers, with a one-byte direction + * pseudo-header prepended - zero means "received by this host", + * non-zero (any non-zero value) means "sent by this host" - as per + * Will Barker . + */ +#define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ +#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ +#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ +#define DLT_LAPB_WITH_DIR 207 /* LAPB */ + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define DLT_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - http://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define DLT_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define DLT_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define DLT_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define DLT_IEEE802_15_4_NONASK_PHY 215 + +/* + * David Gibson requested this for + * captures from the Linux kernel /dev/input/eventN devices. This + * is used to communicate keystrokes and mouse movements from the + * Linux kernel to display systems, such as Xorg. + */ +#define DLT_LINUX_EVDEV 216 + +/* + * GSM Um and Abis interfaces, preceded by a "gsmtap" header. + * + * Requested by Harald Welte . + */ +#define DLT_GSMTAP_UM 217 +#define DLT_GSMTAP_ABIS 218 + +/* + * MPLS, with an MPLS label as the link-layer header. + * Requested by Michele Marchetto on behalf + * of OpenBSD. + */ +#define DLT_MPLS 219 + +/* + * USB packets, beginning with a Linux USB header, with the USB header + * padded to 64 bytes; required for memory-mapped access. + */ +#define DLT_USB_LINUX_MMAPPED 220 + +/* + * DECT packets, with a pseudo-header; requested by + * Matthias Wenzel . + */ +#define DLT_DECT 221 + +/* + * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" + * Date: Mon, 11 May 2009 11:18:30 -0500 + * + * DLT_AOS. We need it for AOS Space Data Link Protocol. + * I have already written dissectors for but need an OK from + * legal before I can submit a patch. + * + */ +#define DLT_AOS 222 + +/* + * Wireless HART (Highway Addressable Remote Transducer) + * From the HART Communication Foundation + * IES/PAS 62591 + * + * Requested by Sam Roberts . + */ +#define DLT_WIHART 223 + +/* + * Fibre Channel FC-2 frames, beginning with a Frame_Header. + * Requested by Kahou Lei . + */ +#define DLT_FC_2 224 + +/* + * Fibre Channel FC-2 frames, beginning with an encoding of the + * SOF, and ending with an encoding of the EOF. + * + * The encodings represent the frame delimiters as 4-byte sequences + * representing the corresponding ordered sets, with K28.5 + * represented as 0xBC, and the D symbols as the corresponding + * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2, + * is represented as 0xBC 0xB5 0x55 0x55. + * + * Requested by Kahou Lei . + */ +#define DLT_FC_2_WITH_FRAME_DELIMS 225 + +/* + * Solaris ipnet pseudo-header; requested by Darren Reed . + * + * The pseudo-header starts with a one-byte version number; for version 2, + * the pseudo-header is: + * + * struct dl_ipnetinfo { + * u_int8_t dli_version; + * u_int8_t dli_family; + * u_int16_t dli_htype; + * u_int32_t dli_pktlen; + * u_int32_t dli_ifindex; + * u_int32_t dli_grifindex; + * u_int32_t dli_zsrc; + * u_int32_t dli_zdst; + * }; + * + * dli_version is 2 for the current version of the pseudo-header. + * + * dli_family is a Solaris address family value, so it's 2 for IPv4 + * and 26 for IPv6. + * + * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing + * packets, and 2 for packets arriving from another zone on the same + * machine. + * + * dli_pktlen is the length of the packet data following the pseudo-header + * (so the captured length minus dli_pktlen is the length of the + * pseudo-header, assuming the entire pseudo-header was captured). + * + * dli_ifindex is the interface index of the interface on which the + * packet arrived. + * + * dli_grifindex is the group interface index number (for IPMP interfaces). + * + * dli_zsrc is the zone identifier for the source of the packet. + * + * dli_zdst is the zone identifier for the destination of the packet. + * + * A zone number of 0 is the global zone; a zone number of 0xffffffff + * means that the packet arrived from another host on the network, not + * from another zone on the same machine. + * + * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates + * which of those it is. + */ +#define DLT_IPNET 226 + +/* + * CAN (Controller Area Network) frames, with a pseudo-header as supplied + * by Linux SocketCAN. See Documentation/networking/can.txt in the Linux + * source. + * + * Requested by Felix Obenhuber . + */ +#define DLT_CAN_SOCKETCAN 227 + +/* + * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies + * whether it's v4 or v6. Requested by Darren Reed . + */ +#define DLT_IPV4 228 +#define DLT_IPV6 229 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), and with no FCS at the end of the frame; requested by + * Jon Smirl . + */ +#define DLT_IEEE802_15_4_NOFCS 230 + +/* + * Raw D-Bus: + * + * http://www.freedesktop.org/wiki/Software/dbus + * + * messages: + * + * http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages + * + * starting with the endianness flag, followed by the message type, etc., + * but without the authentication handshake before the message sequence: + * + * http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol + * + * Requested by Martin Vidner . + */ +#define DLT_DBUS 231 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + */ +#define DLT_JUNIPER_VS 232 +#define DLT_JUNIPER_SRX_E2E 233 +#define DLT_JUNIPER_FIBRECHANNEL 234 + +/* + * DVB-CI (DVB Common Interface for communication between a PC Card + * module and a DVB receiver). See + * + * http://www.kaiser.cx/pcap-dvbci.html + * + * for the specification. + * + * Requested by Martin Kaiser . + */ +#define DLT_DVB_CI 235 + +/* + * Variant of 3GPP TS 27.010 multiplexing protocol (similar to, but + * *not* the same as, 27.010). Requested by Hans-Christoph Schemmel + * . + */ +#define DLT_MUX27010 236 + +/* + * STANAG 5066 D_PDUs. Requested by M. Baris Demiray + * . + */ +#define DLT_STANAG_5066_D_PDU 237 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + */ +#define DLT_JUNIPER_ATM_CEMIC 238 + +/* + * NetFilter LOG messages + * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets) + * + * Requested by Jakub Zawadzki + */ +#define DLT_NFLOG 239 + +/* + * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type + * for Ethernet packets with a 4-byte pseudo-header and always + * with the payload including the FCS, as supplied by their + * netANALYZER hardware and software. + * + * Requested by Holger P. Frommer + */ +#define DLT_NETANALYZER 240 + +/* + * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type + * for Ethernet packets with a 4-byte pseudo-header and FCS and + * with the Ethernet header preceded by 7 bytes of preamble and + * 1 byte of SFD, as supplied by their netANALYZER hardware and + * software. + * + * Requested by Holger P. Frommer + */ +#define DLT_NETANALYZER_TRANSPARENT 241 + +/* + * IP-over-InfiniBand, as specified by RFC 4391. + * + * Requested by Petr Sumbera . + */ +#define DLT_IPOIB 242 + +/* + * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0). + * + * Requested by Guy Martin . + */ +#define DLT_MPEG_2_TS 243 + +/* + * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as + * used by their ng40 protocol tester. + * + * Requested by Jens Grimmer . + */ +#define DLT_NG40 244 + +/* + * Pseudo-header giving adapter number and flags, followed by an NFC + * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU, + * as specified by NFC Forum Logical Link Control Protocol Technical + * Specification LLCP 1.1. + * + * Requested by Mike Wakerly . + */ +#define DLT_NFC_LLCP 245 + +/* + * 245 is used as LINKTYPE_PFSYNC; do not use it for any other purpose. + * + * DLT_PFSYNC has different values on different platforms, and all of + * them collide with something used elsewhere. On platforms that + * don't already define it, define it as 245. + */ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__APPLE__) +#define DLT_PFSYNC 246 +#endif + +/* + * Raw InfiniBand packets, starting with the Local Routing Header. + * + * Requested by Oren Kladnitsky . + */ +#define DLT_INFINIBAND 247 + +/* + * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6). + * + * Requested by Michael Tuexen . + */ +#define DLT_SCTP 248 + +/* + * USB packets, beginning with a USBPcap header. + * + * Requested by Tomasz Mon + */ +#define DLT_USBPCAP 249 + +/* + * Schweitzer Engineering Laboratories "RTAC" product serial-line + * packets. + * + * Requested by Chris Bontje . + */ +#define DLT_RTAC_SERIAL 250 + +/* + * Bluetooth Low Energy air interface link-layer packets. + * + * Requested by Mike Kershaw . + */ +#define DLT_BLUETOOTH_LE_LL 251 + +/* + * DLT type for upper-protocol layer PDU saves from wireshark. + * + * the actual contents are determined by two TAGs stored with each + * packet: + * EXP_PDU_TAG_LINKTYPE the link type (LINKTYPE_ value) of the + * original packet. + * + * EXP_PDU_TAG_PROTO_NAME the name of the wireshark dissector + * that can make sense of the data stored. + */ +#define DLT_WIRESHARK_UPPER_PDU 252 + +/* + * DLT type for the netlink protocol (nlmon devices). + */ +#define DLT_NETLINK 253 + +/* + * Bluetooth Linux Monitor headers for the BlueZ stack. + */ +#define DLT_BLUETOOTH_LINUX_MONITOR 254 + +/* + * Bluetooth Basic Rate/Enhanced Data Rate baseband packets, as + * captured by Ubertooth. + */ +#define DLT_BLUETOOTH_BREDR_BB 255 + +/* + * Bluetooth Low Energy link layer packets, as captured by Ubertooth. + */ +#define DLT_BLUETOOTH_LE_LL_WITH_PHDR 256 + +/* + * PROFIBUS data link layer. + */ +#define DLT_PROFIBUS_DL 257 + +/* + * Apple's DLT_PKTAP headers. + * + * Sadly, the folks at Apple either had no clue that the DLT_USERn values + * are for internal use within an organization and partners only, and + * didn't know that the right way to get a link-layer header type is to + * ask tcpdump.org for one, or knew and didn't care, so they just + * used DLT_USER2, which causes problems for everything except for + * their version of tcpdump. + * + * So I'll just give them one; hopefully this will show up in a + * libpcap release in time for them to get this into 10.10 Big Sur + * or whatever Mavericks' successor is called. LINKTYPE_PKTAP + * will be 258 *even on OS X*; that is *intentional*, so that + * PKTAP files look the same on *all* OSes (different OSes can have + * different numerical values for a given DLT_, but *MUST NOT* have + * different values for what goes in a file, as files can be moved + * between OSes!). + * + * When capturing, on a system with a Darwin-based OS, on a device + * that returns 149 (DLT_USER2 and Apple's DLT_PKTAP) with this + * version of libpcap, the DLT_ value for the pcap_t will be DLT_PKTAP, + * and that will continue to be DLT_USER2 on Darwin-based OSes. That way, + * binary compatibility with Mavericks is preserved for programs using + * this version of libpcap. This does mean that if you were using + * DLT_USER2 for some capture device on OS X, you can't do so with + * this version of libpcap, just as you can't with Apple's libpcap - + * on OS X, they define DLT_PKTAP to be DLT_USER2, so programs won't + * be able to distinguish between PKTAP and whatever you were using + * DLT_USER2 for. + * + * If the program saves the capture to a file using this version of + * libpcap's pcap_dump code, the LINKTYPE_ value in the file will be + * LINKTYPE_PKTAP, which will be 258, even on Darwin-based OSes. + * That way, the file will *not* be a DLT_USER2 file. That means + * that the latest version of tcpdump, when built with this version + * of libpcap, and sufficiently recent versions of Wireshark will + * be able to read those files and interpret them correctly; however, + * Apple's version of tcpdump in OS X 10.9 won't be able to handle + * them. (Hopefully, Apple will pick up this version of libpcap, + * and the corresponding version of tcpdump, so that tcpdump will + * be able to handle the old LINKTYPE_USER2 captures *and* the new + * LINKTYPE_PKTAP captures.) + */ +#ifdef __APPLE__ +#define DLT_PKTAP DLT_USER2 +#else +#define DLT_PKTAP 258 +#endif + +/* + * Ethernet packets preceded by a header giving the last 6 octets + * of the preamble specified by 802.3-2012 Clause 65, section + * 65.1.3.2 "Transmit". + */ +#define DLT_EPON 259 + +/* + * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format" + * in the PICMG HPM.2 specification. + */ +#define DLT_IPMI_HPM_2 260 + +/* + * per Joshua Wright , formats for Zwave captures. + */ +#define DLT_ZWAVE_R1_R2 261 +#define DLT_ZWAVE_R3 262 + +/* + * per Steve Karg , formats for Wattstopper + * Digital Lighting Management room bus serial protocol captures. + */ +#define DLT_WATTSTOPPER_DLM 263 + +#define DLT_MATCHING_MAX 263 /* highest value in the "matching" range */ + +/* + * DLT and savefile link type values are split into a class and + * a member of that class. A class value of 0 indicates a regular + * DLT_/LINKTYPE_ value. + */ +#define DLT_CLASS(x) ((x) & 0x03ff0000) + +/* + * NetBSD-specific generic "raw" link type. The class value indicates + * that this is the generic raw type, and the lower 16 bits are the + * address family we're dealing with. Those values are NetBSD-specific; + * do not assume that they correspond to AF_ values for your operating + * system. + */ +#define DLT_CLASS_NETBSD_RAWAF 0x02240000 +#define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af)) +#define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) +#define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) + + +/* + * The instruction encodings. + * + * Please inform tcpdump-workers@lists.tcpdump.org if you use any + * of the reserved values, so that we can note that they're used + * (and perhaps implement it in the reference BPF implementation + * and encourage its implementation elsewhere). + */ + +/* + * The upper 8 bits of the opcode aren't used. BSD/OS used 0x8000. + */ + +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +/* 0x18 reserved; used by BSD/OS */ +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 +/* 0xc0 reserved; used by BSD/OS */ +/* 0xe0 reserved; used by BSD/OS */ + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_MOD 0x90 +#define BPF_XOR 0xa0 +/* 0xb0 reserved */ +/* 0xc0 reserved */ +/* 0xd0 reserved */ +/* 0xe0 reserved */ +/* 0xf0 reserved */ + +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +/* 0x50 reserved; used on BSD/OS */ +/* 0x60 reserved */ +/* 0x70 reserved */ +/* 0x80 reserved */ +/* 0x90 reserved */ +/* 0xa0 reserved */ +/* 0xb0 reserved */ +/* 0xc0 reserved */ +/* 0xd0 reserved */ +/* 0xe0 reserved */ +/* 0xf0 reserved */ +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 +/* 0x18 reserved */ + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +/* 0x08 reserved */ +/* 0x10 reserved */ +/* 0x18 reserved */ +/* #define BPF_COP 0x20 NetBSD "coprocessor" extensions */ +/* 0x28 reserved */ +/* 0x30 reserved */ +/* 0x38 reserved */ +/* #define BPF_COPX 0x40 NetBSD "coprocessor" extensions */ +/* also used on BSD/OS */ +/* 0x48 reserved */ +/* 0x50 reserved */ +/* 0x58 reserved */ +/* 0x60 reserved */ +/* 0x68 reserved */ +/* 0x70 reserved */ +/* 0x78 reserved */ +#define BPF_TXA 0x80 +/* 0x88 reserved */ +/* 0x90 reserved */ +/* 0x98 reserved */ +/* 0xa0 reserved */ +/* 0xa8 reserved */ +/* 0xb0 reserved */ +/* 0xb8 reserved */ +/* 0xc0 reserved; used on BSD/OS */ +/* 0xc8 reserved */ +/* 0xd0 reserved */ +/* 0xd8 reserved */ +/* 0xe0 reserved */ +/* 0xe8 reserved */ +/* 0xf0 reserved */ +/* 0xf8 reserved */ + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Auxiliary data, for use when interpreting a filter intended for the + * Linux kernel when the kernel rejects the filter (requiring us to + * run it in userland). It contains VLAN tag information. + */ +struct bpf_aux_data { + u_short vlan_tag_present; + u_short vlan_tag; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(const struct bpf_insn *, int); +extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +extern u_int bpf_filter_with_aux_data(const struct bpf_insn *, const u_char *, u_int, u_int, const struct bpf_aux_data *); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(_NET_BPF_H_) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) */ diff --git a/tcpdump/jni/libpcap/pcap/ipnet.h b/tcpdump/jni/libpcap/pcap/ipnet.h new file mode 100644 index 0000000..5330847 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap/ipnet.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define IPH_AF_INET 2 /* Matches Solaris's AF_INET */ +#define IPH_AF_INET6 26 /* Matches Solaris's AF_INET6 */ + +#define IPNET_OUTBOUND 1 +#define IPNET_INBOUND 2 diff --git a/tcpdump/jni/libpcap/pcap/namedb.h b/tcpdump/jni/libpcap/pcap/namedb.h new file mode 100644 index 0000000..d3a3432 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap/namedb.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lib_pcap_namedb_h +#define lib_pcap_namedb_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * As returned by the pcap_next_etherent() + * XXX this stuff doesn't belong in this interface, but this + * library already must do name to address translation, so + * on systems that don't have support for /etc/ethers, we + * export these hooks since they'll + */ +struct pcap_etherent { + u_char addr[6]; + char name[122]; +}; +#ifndef PCAP_ETHERS_FILE +#define PCAP_ETHERS_FILE "/etc/ethers" +#endif +struct pcap_etherent *pcap_next_etherent(FILE *); +u_char *pcap_ether_hostton(const char*); +u_char *pcap_ether_aton(const char *); + +bpf_u_int32 **pcap_nametoaddr(const char *); +#ifdef INET6 +struct addrinfo *pcap_nametoaddrinfo(const char *); +#endif +bpf_u_int32 pcap_nametonetaddr(const char *); + +int pcap_nametoport(const char *, int *, int *); +int pcap_nametoportrange(const char *, int *, int *, int *); +int pcap_nametoproto(const char *); +int pcap_nametoeproto(const char *); +int pcap_nametollc(const char *); +/* + * If a protocol is unknown, PROTO_UNDEF is returned. + * Also, pcap_nametoport() returns the protocol along with the port number. + * If there are ambiguous entried in /etc/services (i.e. domain + * can be either tcp or udp) PROTO_UNDEF is returned. + */ +#define PROTO_UNDEF -1 + +/* XXX move these to pcap-int.h? */ +int __pcap_atodn(const char *, bpf_u_int32 *); +int __pcap_atoin(const char *, bpf_u_int32 *); +u_short __pcap_nametodnaddr(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tcpdump/jni/libpcap/pcap/nflog.h b/tcpdump/jni/libpcap/pcap/nflog.h new file mode 100644 index 0000000..388dd0c --- /dev/null +++ b/tcpdump/jni/libpcap/pcap/nflog.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013, Petar Alilovic, + * Faculty of Electrical Engineering and Computing, University of Zagreb + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _PCAP_NFLOG_H__ +#define _PCAP_NFLOG_H__ + +/* + * Structure of an NFLOG header and TLV parts, as described at + * http://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html + * + * The NFLOG header is big-endian. + * + * The TLV length and type are in host byte order. The value is either + * big-endian or is an array of bytes in some externally-specified byte + * order (text string, link-layer address, link-layer header, packet + * data, etc.). + */ +typedef struct nflog_hdr { + u_int8_t nflog_family; /* address family */ + u_int8_t nflog_version; /* version */ + u_int16_t nflog_rid; /* resource ID */ +} nflog_hdr_t; + +typedef struct nflog_tlv { + u_int16_t tlv_length; /* tlv length */ + u_int16_t tlv_type; /* tlv type */ + /* value follows this */ +} nflog_tlv_t; + +typedef struct nflog_packet_hdr { + u_int16_t hw_protocol; /* hw protocol */ + u_int8_t hook; /* netfilter hook */ + u_int8_t pad; /* padding to 32 bits */ +} nflog_packet_hdr_t; + +typedef struct nflog_hwaddr { + u_int16_t hw_addrlen; /* address length */ + u_int16_t pad; /* padding to 32-bit boundary */ + u_int8_t hw_addr[8]; /* address, up to 8 bytes */ +} nflog_hwaddr_t; + +typedef struct nflog_timestamp { + u_int64_t sec; + u_int64_t usec; +} nflog_timestamp_t; + +/* + * TLV types. + */ +#define NFULA_PACKET_HDR 1 /* nflog_packet_hdr_t */ +#define NFULA_MARK 2 /* packet mark from skbuff */ +#define NFULA_TIMESTAMP 3 /* nflog_timestamp_t for skbuff's time stamp */ +#define NFULA_IFINDEX_INDEV 4 /* ifindex of device on which packet received (possibly bridge group) */ +#define NFULA_IFINDEX_OUTDEV 5 /* ifindex of device on which packet transmitted (possibly bridge group) */ +#define NFULA_IFINDEX_PHYSINDEV 6 /* ifindex of physical device on which packet received (not bridge group) */ +#define NFULA_IFINDEX_PHYSOUTDEV 7 /* ifindex of physical device on which packet transmitted (not bridge group) */ +#define NFULA_HWADDR 8 /* nflog_hwaddr_t for hardware address */ +#define NFULA_PAYLOAD 9 /* packet payload */ +#define NFULA_PREFIX 10 /* text string - null-terminated, count includes NUL */ +#define NFULA_UID 11 /* UID owning socket on which packet was sent/received */ +#define NFULA_SEQ 12 /* sequence number of packets on this NFLOG socket */ +#define NFULA_SEQ_GLOBAL 13 /* sequence number of pakets on all NFLOG sockets */ +#define NFULA_GID 14 /* GID owning socket on which packet was sent/received */ +#define NFULA_HWTYPE 15 /* ARPHRD_ type of skbuff's device */ +#define NFULA_HWHEADER 16 /* skbuff's MAC-layer header */ +#define NFULA_HWLEN 17 /* length of skbuff's MAC-layer header */ + +#endif diff --git a/tcpdump/jni/libpcap/pcap/pcap.h b/tcpdump/jni/libpcap/pcap/pcap.h new file mode 100644 index 0000000..c9fab4c --- /dev/null +++ b/tcpdump/jni/libpcap/pcap/pcap.h @@ -0,0 +1,485 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lib_pcap_pcap_h +#define lib_pcap_pcap_h + +#if defined(WIN32) + #include +#elif defined(MSDOS) + #include + #include /* u_int, u_char etc. */ +#else /* UN*X */ + #include + #include +#endif /* WIN32/MSDOS/UN*X */ + +#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Version number of the current version of the pcap file format. + * + * NOTE: this is *NOT* the version number of the libpcap library. + * To fetch the version information for the version of libpcap + * you're using, use pcap_lib_version(). + */ +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +#define PCAP_ERRBUF_SIZE 256 + +/* + * Compatibility for systems that have a bpf.h that + * predates the bpf typedefs for 64-bit support. + */ +#if BPF_RELEASE - 0 < 199406 +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +typedef struct pcap pcap_t; +typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are 32 bit ints so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes by forking the branch at + * + * https://github.com/the-tcpdump-group/libpcap/issues + * + * and issuing a pull request, so that future versions of libpcap and + * programs that use it (such as tcpdump) will be able to read your new + * capture file format. + */ +struct pcap_file_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_int32 thiszone; /* gmt to local correction */ + bpf_u_int32 sigfigs; /* accuracy of timestamps */ + bpf_u_int32 snaplen; /* max length saved portion of each pkt */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ +}; + +/* + * Macros for the value returned by pcap_datalink_ext(). + * + * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro + * gives the FCS length of packets in the capture. + */ +#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) +#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) +#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) + +typedef enum { + PCAP_D_INOUT = 0, + PCAP_D_IN, + PCAP_D_OUT +} pcap_direction_t; + +/* + * Generic per-packet information, as supplied by libpcap. + * + * The time stamp can and should be a "struct timeval", regardless of + * whether your system supports 32-bit tv_sec in "struct timeval", + * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit + * and 64-bit applications. The on-disk format of savefiles uses 32-bit + * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit + * and 64-bit versions of libpcap, even if they're on the same platform, + * should supply the appropriate version of "struct timeval", even if + * that's not what the underlying packet capture mechanism supplies. + */ +struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +}; + +/* + * As returned by the pcap_stats() + */ +struct pcap_stat { + u_int ps_recv; /* number of packets received */ + u_int ps_drop; /* number of packets dropped */ + u_int ps_ifdrop; /* drops by interface -- only supported on some platforms */ +#ifdef WIN32 + u_int bs_capt; /* number of packets that reach the application */ +#endif /* WIN32 */ +}; + +#ifdef MSDOS +/* + * As returned by the pcap_stats_ex() + */ +struct pcap_stat_ex { + u_long rx_packets; /* total packets received */ + u_long tx_packets; /* total packets transmitted */ + u_long rx_bytes; /* total bytes received */ + u_long tx_bytes; /* total bytes transmitted */ + u_long rx_errors; /* bad packets received */ + u_long tx_errors; /* packet transmit problems */ + u_long rx_dropped; /* no space in Rx buffers */ + u_long tx_dropped; /* no space available for Tx */ + u_long multicast; /* multicast packets received */ + u_long collisions; + + /* detailed rx_errors: */ + u_long rx_length_errors; + u_long rx_over_errors; /* receiver ring buff overflow */ + u_long rx_crc_errors; /* recv'd pkt with crc error */ + u_long rx_frame_errors; /* recv'd frame alignment error */ + u_long rx_fifo_errors; /* recv'r fifo overrun */ + u_long rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + u_long tx_aborted_errors; + u_long tx_carrier_errors; + u_long tx_fifo_errors; + u_long tx_heartbeat_errors; + u_long tx_window_errors; + }; +#endif + +/* + * Item in a list of interfaces. + */ +struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + bpf_u_int32 flags; /* PCAP_IF_ interface flags */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ +#define PCAP_IF_UP 0x00000002 /* interface is up */ +#define PCAP_IF_RUNNING 0x00000004 /* interface is running */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ +}; + +typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, + const u_char *); + +/* + * Error codes for the pcap API. + * These will all be negative, so you can check for the success or + * failure of a call that returns these codes by checking for a + * negative value. + */ +#define PCAP_ERROR -1 /* generic error code */ +#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ +#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ +#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ +#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ +#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ +#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ +#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ +#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ +#define PCAP_ERROR_CANTSET_TSTAMP_TYPE -10 /* this device doesn't support setting the time stamp type */ +#define PCAP_ERROR_PROMISC_PERM_DENIED -11 /* you don't have permission to capture in promiscuous mode */ +#define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12 /* the requested time stamp precision is not supported */ + +/* + * Warning codes for the pcap API. + * These will all be positive and non-zero, so they won't look like + * errors. + */ +#define PCAP_WARNING 1 /* generic warning code */ +#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ +#define PCAP_WARNING_TSTAMP_TYPE_NOTSUP 3 /* the requested time stamp type is not supported */ + +/* + * Value to pass to pcap_compile() as the netmask if you don't know what + * the netmask is. + */ +#define PCAP_NETMASK_UNKNOWN 0xffffffff + +char *pcap_lookupdev(char *); +int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); + +pcap_t *pcap_create(const char *, char *); +int pcap_set_snaplen(pcap_t *, int); +int pcap_set_promisc(pcap_t *, int); +int pcap_can_set_rfmon(pcap_t *); +int pcap_set_rfmon(pcap_t *, int); +int pcap_set_timeout(pcap_t *, int); +int pcap_set_tstamp_type(pcap_t *, int); +int pcap_set_immediate_mode(pcap_t *, int); +int pcap_set_buffer_size(pcap_t *, int); +int pcap_set_tstamp_precision(pcap_t *, int); +int pcap_get_tstamp_precision(pcap_t *); +int pcap_activate(pcap_t *); + +int pcap_list_tstamp_types(pcap_t *, int **); +void pcap_free_tstamp_types(int *); +int pcap_tstamp_type_name_to_val(const char *); +const char *pcap_tstamp_type_val_to_name(int); +const char *pcap_tstamp_type_val_to_description(int); + +/* + * Time stamp types. + * Not all systems and interfaces will necessarily support all of these. + * + * A system that supports PCAP_TSTAMP_HOST is offering time stamps + * provided by the host machine, rather than by the capture device, + * but not committing to any characteristics of the time stamp; + * it will not offer any of the PCAP_TSTAMP_HOST_ subtypes. + * + * PCAP_TSTAMP_HOST_LOWPREC is a time stamp, provided by the host machine, + * that's low-precision but relatively cheap to fetch; it's normally done + * using the system clock, so it's normally synchronized with times you'd + * fetch from system calls. + * + * PCAP_TSTAMP_HOST_HIPREC is a time stamp, provided by the host machine, + * that's high-precision; it might be more expensive to fetch. It might + * or might not be synchronized with the system clock, and might have + * problems with time stamps for packets received on different CPUs, + * depending on the platform. + * + * PCAP_TSTAMP_ADAPTER is a high-precision time stamp supplied by the + * capture device; it's synchronized with the system clock. + * + * PCAP_TSTAMP_ADAPTER_UNSYNCED is a high-precision time stamp supplied by + * the capture device; it's not synchronized with the system clock. + * + * Note that time stamps synchronized with the system clock can go + * backwards, as the system clock can go backwards. If a clock is + * not in sync with the system clock, that could be because the + * system clock isn't keeping accurate time, because the other + * clock isn't keeping accurate time, or both. + * + * Note that host-provided time stamps generally correspond to the + * time when the time-stamping code sees the packet; this could + * be some unknown amount of time after the first or last bit of + * the packet is received by the network adapter, due to batching + * of interrupts for packet arrival, queueing delays, etc.. + */ +#define PCAP_TSTAMP_HOST 0 /* host-provided, unknown characteristics */ +#define PCAP_TSTAMP_HOST_LOWPREC 1 /* host-provided, low precision */ +#define PCAP_TSTAMP_HOST_HIPREC 2 /* host-provided, high precision */ +#define PCAP_TSTAMP_ADAPTER 3 /* device-provided, synced with the system clock */ +#define PCAP_TSTAMP_ADAPTER_UNSYNCED 4 /* device-provided, not synced with the system clock */ + +/* + * Time stamp resolution types. + * Not all systems and interfaces will necessarily support all of these + * resolutions when doing live captures; all of them can be requested + * when reading a savefile. + */ +#define PCAP_TSTAMP_PRECISION_MICRO 0 /* use timestamps with microsecond precision, default */ +#define PCAP_TSTAMP_PRECISION_NANO 1 /* use timestamps with nanosecond precision */ + +pcap_t *pcap_open_live(const char *, int, int, int, char *); +pcap_t *pcap_open_dead(int, int); +pcap_t *pcap_open_dead_with_tstamp_precision(int, int, u_int); +pcap_t *pcap_open_offline_with_tstamp_precision(const char *, u_int, char *); +pcap_t *pcap_open_offline(const char *, char *); +#if defined(WIN32) +pcap_t *pcap_hopen_offline_with_tstamp_precision(intptr_t, u_int, char *); +pcap_t *pcap_hopen_offline(intptr_t, char *); +#if !defined(LIBPCAP_EXPORTS) +#define pcap_fopen_offline_with_tstamp_precision(f,p,b) \ + pcap_hopen_offline_with_tstamp_precision(_get_osfhandle(_fileno(f)), p, b) +#define pcap_fopen_offline(f,b) \ + pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) +#else /*LIBPCAP_EXPORTS*/ +static pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *); +static pcap_t *pcap_fopen_offline(FILE *, char *); +#endif +#else /*WIN32*/ +pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *); +pcap_t *pcap_fopen_offline(FILE *, char *); +#endif /*WIN32*/ + +void pcap_close(pcap_t *); +int pcap_loop(pcap_t *, int, pcap_handler, u_char *); +int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); +const u_char* + pcap_next(pcap_t *, struct pcap_pkthdr *); +int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); +int pcap_stats(pcap_t *, struct pcap_stat *); +int pcap_setfilter(pcap_t *, struct bpf_program *); +int pcap_setdirection(pcap_t *, pcap_direction_t); +int pcap_getnonblock(pcap_t *, char *); +int pcap_setnonblock(pcap_t *, int, char *); +int pcap_inject(pcap_t *, const void *, size_t); +int pcap_sendpacket(pcap_t *, const u_char *, int); +const char *pcap_statustostr(int); +const char *pcap_strerror(int); +char *pcap_geterr(pcap_t *); +void pcap_perror(pcap_t *, char *); +int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, + bpf_u_int32); +int pcap_compile_nopcap(int, int, struct bpf_program *, + const char *, int, bpf_u_int32); +void pcap_freecode(struct bpf_program *); +int pcap_offline_filter(const struct bpf_program *, + const struct pcap_pkthdr *, const u_char *); +int pcap_datalink(pcap_t *); +int pcap_datalink_ext(pcap_t *); +int pcap_list_datalinks(pcap_t *, int **); +int pcap_set_datalink(pcap_t *, int); +void pcap_free_datalinks(int *); +int pcap_datalink_name_to_val(const char *); +const char *pcap_datalink_val_to_name(int); +const char *pcap_datalink_val_to_description(int); +int pcap_snapshot(pcap_t *); +int pcap_is_swapped(pcap_t *); +int pcap_major_version(pcap_t *); +int pcap_minor_version(pcap_t *); + +/* XXX */ +FILE *pcap_file(pcap_t *); +int pcap_fileno(pcap_t *); + +pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +pcap_dumper_t *pcap_dump_open_append(pcap_t *, const char *); +FILE *pcap_dump_file(pcap_dumper_t *); +long pcap_dump_ftell(pcap_dumper_t *); +int pcap_dump_flush(pcap_dumper_t *); +void pcap_dump_close(pcap_dumper_t *); +void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); + +int pcap_findalldevs(pcap_if_t **, char *); +void pcap_freealldevs(pcap_if_t *); + +const char *pcap_lib_version(void); + +/* + * On at least some versions of NetBSD and QNX, we don't want to declare + * bpf_filter() here, as it's also be declared in , with a + * different signature, but, on other BSD-flavored UN*Xes, it's not + * declared in , so we *do* want to declare it here, so it's + * declared when we build pcap-bpf.c. + */ +#if !defined(__NetBSD__) && !defined(__QNX__) +u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +#endif +int bpf_validate(const struct bpf_insn *f, int len); +char *bpf_image(const struct bpf_insn *, int); +void bpf_dump(const struct bpf_program *, int); + +#if defined(WIN32) + +/* + * Win32 definitions + */ + +int pcap_setbuff(pcap_t *p, int dim); +int pcap_setmode(pcap_t *p, int mode); +int pcap_setmintocopy(pcap_t *p, int size); +Adapter *pcap_get_adapter(pcap_t *p); + +#ifdef WPCAP +/* Include file with the wpcap-specific extensions */ +#include +#endif /* WPCAP */ + +#define MODE_CAPT 0 +#define MODE_STAT 1 +#define MODE_MON 2 + +#elif defined(MSDOS) + +/* + * MS-DOS definitions + */ + +int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); +u_long pcap_mac_packets (void); + +#else /* UN*X */ + +/* + * UN*X definitions + */ + +int pcap_get_selectable_fd(pcap_t *); + +#endif /* WIN32/MSDOS/UN*X */ + +#ifdef __cplusplus +} +#endif + +#endif /* lib_pcap_pcap_h */ diff --git a/tcpdump/jni/libpcap/pcap/sll.h b/tcpdump/jni/libpcap/pcap/sll.h new file mode 100644 index 0000000..38da29f --- /dev/null +++ b/tcpdump/jni/libpcap/pcap/sll.h @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * For captures on Linux cooked sockets, we construct a fake header + * that includes: + * + * a 2-byte "packet type" which is one of: + * + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; + * + * a 2-byte Ethernet protocol field; + * + * a 2-byte link-layer type; + * + * a 2-byte link-layer address length; + * + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. + * + * All fields except for the link-layer address are in network byte order. + * + * DO NOT change the layout of this structure, or change any of the + * LINUX_SLL_ values below. If you must change the link-layer header + * for a "cooked" Linux capture, introduce a new DLT_ type (ask + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the + * new header in captures of that type, so that programs that can + * handle DLT_LINUX_SLL captures will continue to handle them correctly + * without any change, and so that capture files with different headers + * can be told apart and programs that read them can dissect the + * packets in them. + */ + +#ifndef lib_pcap_sll_h +#define lib_pcap_sll_h + +/* + * A DLT_LINUX_SLL fake link-layer header. + */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ + +struct sll_header { + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ + u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + u_int16_t sll_protocol; /* protocol */ +}; + +/* + * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the + * PACKET_ values on Linux, but are defined here so that they're + * available even on systems other than Linux, and so that they + * don't change even if the PACKET_ values change. + */ +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 + +/* + * The LINUX_SLL_ values for "sll_protocol"; these correspond to the + * ETH_P_ values on Linux, but are defined here so that they're + * available even on systems other than Linux. We assume, for now, + * that the ETH_P_ values won't change in Linux; if they do, then: + * + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; + * + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. + * + * Add other values here as necessary, for handling packet types that + * might show up on non-Ethernet, non-802.x networks. (Not all the ones + * in the Linux "if_ether.h" will, I suspect, actually show up in + * captures.) + */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ + +#endif diff --git a/tcpdump/jni/libpcap/pcap/usb.h b/tcpdump/jni/libpcap/pcap/usb.h new file mode 100644 index 0000000..8395527 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap/usb.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Basic USB data struct + * By Paolo Abeni + */ + +#ifndef _PCAP_USB_STRUCTS_H__ +#define _PCAP_USB_STRUCTS_H__ + +/* + * possible transfer mode + */ +#define URB_TRANSFER_IN 0x80 +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * USB setup header as defined in USB specification. + * Appears at the front of each Control S-type packet in DLT_USB captures. + */ +typedef struct _usb_setup { + u_int8_t bmRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; +} pcap_usb_setup; + +/* + * Information from the URB for Isochronous transfers. + */ +typedef struct _iso_rec { + int32_t error_count; + int32_t numdesc; +} iso_rec; + +/* + * Header prepended by linux kernel to each event. + * Appears at the front of each packet in DLT_USB_LINUX captures. + */ +typedef struct _usb_header { + u_int64_t id; + u_int8_t event_type; + u_int8_t transfer_type; + u_int8_t endpoint_number; + u_int8_t device_address; + u_int16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + u_int32_t urb_len; + u_int32_t data_len; /* amount of urb data really present in this event*/ + pcap_usb_setup setup; +} pcap_usb_header; + +/* + * Header prepended by linux kernel to each event for the 2.6.31 + * and later kernels; for the 2.6.21 through 2.6.30 kernels, the + * "iso_rec" information, and the fields starting with "interval" + * are zeroed-out padding fields. + * + * Appears at the front of each packet in DLT_USB_LINUX_MMAPPED captures. + */ +typedef struct _usb_header_mmapped { + u_int64_t id; + u_int8_t event_type; + u_int8_t transfer_type; + u_int8_t endpoint_number; + u_int8_t device_address; + u_int16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + u_int32_t urb_len; + u_int32_t data_len; /* amount of urb data really present in this event*/ + union { + pcap_usb_setup setup; + iso_rec iso; + } s; + int32_t interval; /* for Interrupt and Isochronous events */ + int32_t start_frame; /* for Isochronous events */ + u_int32_t xfer_flags; /* copy of URB's transfer flags */ + u_int32_t ndesc; /* number of isochronous descriptors */ +} pcap_usb_header_mmapped; + +/* + * Isochronous descriptors; for isochronous transfers there might be + * one or more of these at the beginning of the packet data. The + * number of descriptors is given by the "ndesc" field in the header; + * as indicated, in older kernels that don't put the descriptors at + * the beginning of the packet, that field is zeroed out, so that field + * can be trusted even in captures from older kernels. + */ +typedef struct _usb_isodesc { + int32_t status; + u_int32_t offset; + u_int32_t len; + u_int8_t pad[4]; +} usb_isodesc; + +#endif diff --git a/tcpdump/jni/libpcap/pcap/vlan.h b/tcpdump/jni/libpcap/pcap/vlan.h new file mode 100644 index 0000000..021f612 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap/vlan.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lib_pcap_vlan_h +#define lib_pcap_vlan_h + +struct vlan_tag { + u_int16_t vlan_tpid; /* ETH_P_8021Q */ + u_int16_t vlan_tci; /* VLAN TCI */ +}; + +#define VLAN_TAG_LEN 4 + +#endif diff --git a/tcpdump/jni/libpcap/pcap1.h b/tcpdump/jni/libpcap/pcap1.h new file mode 100644 index 0000000..2cb532f --- /dev/null +++ b/tcpdump/jni/libpcap/pcap1.h @@ -0,0 +1,306 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap1.h,v 1.5 2008-05-30 01:43:21 guy Exp $ (LBL) + */ + +#ifndef lib_pcap_h +#define lib_pcap_h + +#ifdef WIN32 +#include +#else /* WIN32 */ +#include +#include +#endif /* WIN32 */ + +#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCAP_VERSION_MAJOR 3 +#define PCAP_VERSION_MINOR 0 + +#define PCAP_ERRBUF_SIZE 256 + +/* + * Compatibility for systems that have a bpf.h that + * predates the bpf typedefs for 64-bit support. + */ +#if BPF_RELEASE - 0 < 199406 +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +typedef struct pcap pcap_t; +typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are 32 bit ints so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes by forking the branch at + * + * https://github.com/the-tcpdump-group/libpcap/issues + * + * and issuing a pull request, so that future versions of libpcap and + * programs that use it (such as tcpdump) will be able to read your new + * capture file format. + */ + +enum pcap1_info_types { + PCAP_DATACAPTURE, + PCAP_TIMESTAMP, + PCAP_WALLTIME, + PCAP_TIMESKEW, + PCAP_PROBEPLACE, /* aka direction */ + PCAP_COMMENT, /* comment */ +}; + +struct pcap1_info_container { + bpf_u_int32 info_len; /* in bytes */ + bpf_u_int32 info_type; /* enum pcap1_info_types */ + unsigned char info_data[0]; +}; + +struct pcap1_info_timestamp { + struct pcap1_info_container pic; + bpf_u_int32 nanoseconds; /* 10^-9 of seconds */ + bpf_u_int32 seconds; /* seconds since Unix epoch - GMT */ + bpf_u_int16 macroseconds; /* 16 bits more of MSB of time */ + bpf_u_int16 sigfigs; /* accuracy of timestamps - LSB bits */ +}; + +struct pcap1_info_packet { + struct pcap1_info_container pic; + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ + bpf_u_int32 ifIndex; /* abstracted interface index */ + unsigned char packet_data[0]; +}; + +enum pcap1_probe { + INBOUND =1, + OUTBOUND =2, + FORWARD =3, + PREENCAP =4, + POSTDECAP=5, +}; + +struct pcap1_info_probe { + struct pcap1_info_container pic; + bpf_u_int32 probeloc; /* enum pcap1_probe */ + unsigned char probe_desc[0]; +}; + +struct pcap1_info_comment { + struct pcap1_info_container pic; + unsigned char comment[0]; +}; + +struct pcap1_packet_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_u_int32 block_len; + struct pcap1_info_container pics[0]; +}; + +/* + * Each packet in the dump file is prepended with this generic header. + * This gets around the problem of different headers for different + * packet interfaces. + */ + +/* + * As returned by the pcap_stats() + */ +struct pcap_stat { + u_int ps_recv; /* number of packets received */ + u_int ps_drop; /* number of packets dropped */ + u_int ps_ifdrop; /* drops by interface XXX not yet supported */ +#ifdef WIN32 + u_int bs_capt; /* number of packets that reach the application */ +#endif /* WIN32 */ +}; + +/* + * Item in a list of interfaces. + */ +struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + bpf_u_int32 flags; /* PCAP_IF_ interface flags */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ +}; + +typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, + const u_char *); + +char *pcap_lookupdev(char *); +int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); +pcap_t *pcap_open_live(const char *, int, int, int, char *); +pcap_t *pcap_open_dead(int, int); +pcap_t *pcap_open_offline(const char *, char *); +void pcap_close(pcap_t *); +int pcap_loop(pcap_t *, int, pcap_handler, u_char *); +int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); +const u_char* + pcap_next(pcap_t *, struct pcap_pkthdr *); +int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); +int pcap_stats(pcap_t *, struct pcap_stat *); +int pcap_setfilter(pcap_t *, struct bpf_program *); +int pcap_getnonblock(pcap_t *, char *); +int pcap_setnonblock(pcap_t *, int, char *); +void pcap_perror(pcap_t *, char *); +char *pcap_strerror(int); +char *pcap_geterr(pcap_t *); +int pcap_compile(pcap_t *, struct bpf_program *, char *, int, + bpf_u_int32); +int pcap_compile_nopcap(int, int, struct bpf_program *, + char *, int, bpf_u_int32); +void pcap_freecode(struct bpf_program *); +int pcap_datalink(pcap_t *); +int pcap_list_datalinks(pcap_t *, int **); +int pcap_set_datalink(pcap_t *, int); +int pcap_datalink_name_to_val(const char *); +const char *pcap_datalink_val_to_name(int); +const char *pcap_datalink_val_to_description(int); +int pcap_snapshot(pcap_t *); +int pcap_is_swapped(pcap_t *); +int pcap_major_version(pcap_t *); +int pcap_minor_version(pcap_t *); + +/* XXX */ +FILE *pcap_file(pcap_t *); +int pcap_fileno(pcap_t *); + +pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +int pcap_dump_flush(pcap_dumper_t *); +void pcap_dump_close(pcap_dumper_t *); +void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); +FILE *pcap_dump_file(pcap_dumper_t *); + +int pcap_findalldevs(pcap_if_t **, char *); +void pcap_freealldevs(pcap_if_t *); + +const char *pcap_lib_version(void); + +/* XXX this guy lives in the bpf tree */ +u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int); +int bpf_validate(struct bpf_insn *f, int len); +char *bpf_image(struct bpf_insn *, int); +void bpf_dump(struct bpf_program *, int); + +#ifdef WIN32 +/* + * Win32 definitions + */ + +int pcap_setbuff(pcap_t *p, int dim); +int pcap_setmode(pcap_t *p, int mode); +int pcap_sendpacket(pcap_t *p, u_char *buf, int size); +int pcap_setmintocopy(pcap_t *p, int size); + +#ifdef WPCAP +/* Include file with the wpcap-specific extensions */ +#include +#endif + +#define MODE_CAPT 0 +#define MODE_STAT 1 + +#else +/* + * UN*X definitions + */ + +int pcap_get_selectable_fd(pcap_t *); + +#endif /* WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tcpdump/jni/libpcap/pcap_activate.3pcap b/tcpdump/jni/libpcap/pcap_activate.3pcap new file mode 100644 index 0000000..61887a7 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_activate.3pcap @@ -0,0 +1,95 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_ACTIVATE 3PCAP "21 September 2010" +.SH NAME +pcap_activate \- activate a capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_activate(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_activate() +is used to activate a packet capture handle to look +at packets on the network, with the options that were set on the handle +being in effect. +.SH RETURN VALUE +.B pcap_activate() +returns 0 on success without warnings, +.B PCAP_WARNING_PROMISC_NOTSUP +on success on a device that doesn't support promiscuous mode if +promiscuous mode was requested, +.B PCAP_WARNING_TSTAMP_TYPE_NOTSUP +on success if the time stamp type specified in a previous +.B pcap_set_tstamp_type() +call isn't supported by the capture source (the time stamp type is +left as the default), +.B PCAP_WARNING +on success with any other warning, +.B PCAP_ERROR_ACTIVATED +if the handle has already been activated, +.B PCAP_ERROR_NO_SUCH_DEVICE +if the capture source specified when the handle was created doesn't +exist, +.B PCAP_ERROR_PERM_DENIED +if the process doesn't have permission to open the capture source, +.B PCAP_ERROR_PROMISC_PERM_DENIED +if the process has permission to open the capture source but doesn't +have permission to put it into promiscuous mode, +.B PCAP_ERROR_RFMON_NOTSUP +if monitor mode was specified but the capture source doesn't support +monitor mode, +.B PCAP_ERROR_IFACE_NOT_UP +if the capture source is not up, and +.B PCAP_ERROR +if another error occurred. +If +.B PCAP_WARNING +or +.B PCAP_ERROR +is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display a message describing the warning or +error. +If +.BR PCAP_WARNING_PROMISC_NOTSUP , +.BR PCAP_ERROR_NO_SUCH_DEVICE , +or +.B PCAP_ERROR_PERM_DENIED +is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display an message giving additional details +about the problem that might be useful for debugging the problem if it's +unexpected. +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_breakloop.3pcap b/tcpdump/jni/libpcap/pcap_breakloop.3pcap new file mode 100644 index 0000000..6744924 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_breakloop.3pcap @@ -0,0 +1,98 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_BREAKLOOP 3PCAP "5 April 2008" +.SH NAME +pcap_breakloop \- force a pcap_dispatch() or pcap_loop() call to return +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +void pcap_breakloop(pcap_t *); +.ft +.fi +.SH DESCRIPTION +.B pcap_breakloop() +sets a flag that will force +.B pcap_dispatch() +or +.B pcap_loop() +to return rather than looping; they will return the number of packets +that have been processed so far, or \-2 if no packets have been +processed so far. +.PP +This routine is safe to use inside a signal handler on UNIX or a console +control handler on Windows, as it merely sets a flag that is checked +within the loop. +.PP +The flag is checked in loops reading packets from the OS - a signal by +itself will not necessarily terminate those loops - as well as in loops +processing a set of packets returned by the OS. +.ft B +Note that if you are catching signals on UNIX systems that support +restarting system calls after a signal, and calling pcap_breakloop() +in the signal handler, you must specify, when catching those signals, +that system calls should NOT be restarted by that signal. Otherwise, +if the signal interrupted a call reading packets in a live capture, +when your signal handler returns after calling pcap_breakloop(), the +call will be restarted, and the loop will not terminate until more +packets arrive and the call completes. +.ft R +.PP +.ft B +Note also that, in a multi-threaded application, if one thread is +blocked in pcap_dispatch(), pcap_loop(), pcap_next(), or pcap_next_ex(), +a call to pcap_breakloop() in a different thread will not unblock that +thread; you will need to use whatever mechanism the OS provides for +breaking a thread out of blocking calls in order to unblock the thread, +such as thread cancellation in systems that support POSIX threads. +.ft R +.PP +Note that +.B pcap_next() +and +.B pcap_next_ex() +will, on some platforms, loop reading packets from the OS; that loop +will not necessarily be terminated by a signal, so +.B pcap_breakloop() +should be used to terminate packet processing even if +.B pcap_next() +or +.B pcap_next_ex() +is being used. +.PP +.B pcap_breakloop() +does not guarantee that no further packets will be processed by +.B pcap_dispatch() +or +.B pcap_loop() +after it is called; at most one more packet might be processed. +.PP +If \-2 is returned from +.B pcap_dispatch() +or +.BR pcap_loop() , +the flag is cleared, so a subsequent call will resume reading packets. +If a positive number is returned, the flag is not cleared, so a +subsequent call will return \-2 and clear the flag. +.SH SEE ALSO +pcap(3PCAP), pcap_loop(3PCAP), pcap_next_ex(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_can_set_rfmon.3pcap b/tcpdump/jni/libpcap/pcap_can_set_rfmon.3pcap new file mode 100644 index 0000000..b579804 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_can_set_rfmon.3pcap @@ -0,0 +1,62 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_CAN_SET_RFMON 3PCAP "18 May 2010" +.SH NAME +pcap_can_set_rfmon \- check whether monitor mode can be set for a +not-yet-activated capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_can_set_rfmon(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_can_set_rfmon() +checks whether monitor mode could be set on a capture handle when +the handle is activated. +.SH RETURN VALUE +.B pcap_can_set_rfmon() +returns 0 if monitor mode could not be set, +1 if monitor mode could be set, +.B PCAP_ERROR_NO_SUCH_DEVICE +if the capture source specified when the handle was created doesn't +exist, +.B PCAP_ERROR_PERM_DENIED +if the process doesn't have permission to check whether monitor mode +could be supported, +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated, or +.B PCAP_ERROR +if an error occurred. +If +.B PCAP_ERROR +is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), +pcap_set_rfmon(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_close.3pcap b/tcpdump/jni/libpcap/pcap_close.3pcap new file mode 100644 index 0000000..91eb677 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_close.3pcap @@ -0,0 +1,39 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_CLOSE 3PCAP "5 April 2008" +.SH NAME +pcap_close \- close a capture device or savefile +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +void pcap_close(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_close() +closes the files associated with +.I p +and deallocates resources. +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_compile.3pcap.in b/tcpdump/jni/libpcap/pcap_compile.3pcap.in new file mode 100644 index 0000000..0e5276a --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_compile.3pcap.in @@ -0,0 +1,70 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_COMPILE 3PCAP "1 December 2009" +.SH NAME +pcap_compile \- compile a filter expression +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_compile(pcap_t *p, struct bpf_program *fp, +.ti +8 +const char *str, int optimize, bpf_u_int32 netmask); +.ft +.fi +.SH DESCRIPTION +.B pcap_compile() +is used to compile the string +.I str +into a filter program. See +.BR pcap-filter (@MAN_MISC_INFO@) +for the syntax of that string. +.I program +is a pointer to a +.I bpf_program +struct and is filled in by +.BR pcap_compile() . +.I optimize +controls whether optimization on the resulting code is performed. +.I netmask +specifies the IPv4 netmask of the network on which packets are being +captured; it is used only when checking for IPv4 broadcast addresses in +the filter program. If the netmask of the network on which packets are +being captured isn't known to the program, or if packets are being +captured on the Linux "any" pseudo-interface that can capture on more +than one network, a value of PCAP_NETMASK_UNKNOWN can be supplied; tests +for IPv4 broadcast addresses will fail to compile, but all other tests in +the filter program will be OK. +.SH RETURN VALUE +.B pcap_compile() +returns 0 on success and \-1 on failure. +If \-1 is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_setfilter(3PCAP), pcap_freecode(3PCAP), +pcap_geterr(3PCAP), pcap-filter(@MAN_MISC_INFO@) diff --git a/tcpdump/jni/libpcap/pcap_create.3pcap b/tcpdump/jni/libpcap/pcap_create.3pcap new file mode 100644 index 0000000..5c537fc --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_create.3pcap @@ -0,0 +1,72 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_CREATE 3PCAP "5 April 2008" +.SH NAME +pcap_create \- create a live capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +pcap_t *pcap_create(const char *source, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.B pcap_create() +is used to create a packet capture handle to look +at packets on the network. +.I source +is a string that specifies the network device to open; on Linux systems +with 2.2 or later kernels, a +.I source +argument of "any" or +.B NULL +can be used to capture packets from all interfaces. +.PP +The returned handle must be activated with +.B pcap_activate() +before packets can be captured +with it; options for the capture, such as promiscuous mode, can be set +on the handle before activating it. +.SH RETURN VALUE +.B pcap_create() +returns a +.I pcap_t * +on success and +.B NULL +on failure. +If +.B NULL +is returned, +.I errbuf +is filled in with an appropriate error message. +.I errbuf +is assumed to be able to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.SH SEE ALSO +pcap(3PCAP), pcap_activate(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_datalink.3pcap.in b/tcpdump/jni/libpcap/pcap_datalink.3pcap.in new file mode 100644 index 0000000..b07fc28 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_datalink.3pcap.in @@ -0,0 +1,68 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DATALINK 3PCAP "13 October 2013" +.SH NAME +pcap_datalink \- get the link-layer header type +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_datalink(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_datalink() +returns the link-layer header type for the live capture or ``savefile'' +specified by +.IR p . +.PP +It must not be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +.PP +.I http://www.tcpdump.org/linktypes.html +lists the values +.B pcap_datalink() +can return and describes the packet formats that +correspond to those values. +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. +.SH RETURN VALUE +.B pcap_datalink() +returns the link-layer header type on success and +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated. +.SH SEE ALSO +pcap(3PCAP), pcap-linktype(@MAN_MISC_INFO@) diff --git a/tcpdump/jni/libpcap/pcap_datalink_name_to_val.3pcap b/tcpdump/jni/libpcap/pcap_datalink_name_to_val.3pcap new file mode 100644 index 0000000..4bc1728 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_datalink_name_to_val.3pcap @@ -0,0 +1,46 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DATALINK_NAME_TO_VAL 3PCAP "22 August 2010" +.SH NAME +pcap_datalink_name_to_val \- get the link-layer header type value +corresponding to a header type name +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_datalink_name_to_val(const char *name); +.ft +.fi +.SH DESCRIPTION +.B pcap_datalink_name_to_val() +translates a link-layer header type name, which is a +.B DLT_ +name with the +.B DLT_ +removed, to the corresponding link-layer header type value. The +translation is case-insensitive. +.SH RETURN VALUE +.B pcap_datalink_name_to_val() +returns type value on success and \-1 on failure. +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_datalink_val_to_name.3pcap b/tcpdump/jni/libpcap/pcap_datalink_val_to_name.3pcap new file mode 100644 index 0000000..0b17825 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_datalink_val_to_name.3pcap @@ -0,0 +1,46 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DATALINK_VAL_TO_NAME 3PCAP "22 August 2010" +.SH NAME +pcap_datalink_val_to_name, pcap_datalink_val_to_description \- get a +name or description for a link-layer header type value +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_datalink_val_to_name(int dlt); +const char *pcap_datalink_val_to_description(int dlt); +.ft +.fi +.SH DESCRIPTION +.B pcap_datalink_val_to_name() +translates a link-layer header type value to the corresponding +link-layer header type name. +.B NULL +is returned on failure. +.PP +.B pcap_datalink_val_to_description() +translates a link-layer header type value to a short description of that +link-layer header type. +.B NULL +is returned on failure. diff --git a/tcpdump/jni/libpcap/pcap_dump.3pcap b/tcpdump/jni/libpcap/pcap_dump.3pcap new file mode 100644 index 0000000..95f3040 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_dump.3pcap @@ -0,0 +1,51 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP 3PCAP "5 April 2008" +.SH NAME +pcap_dump \- write a packet to a capture file +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +void pcap_dump(u_char *user, struct pcap_pkthdr *h, +.ti +8 +u_char *sp); +.ft +.fi +.SH DESCRIPTION +.B pcap_dump() +outputs a packet to the ``savefile'' opened with +.BR pcap_dump_open() . +Note that its calling arguments are suitable for use with +.B pcap_dispatch() +or +.BR pcap_loop() . +If called directly, the +.I user +parameter is of type +.B pcap_dumper_t +as returned by +.BR pcap_dump_open() . +.SH SEE ALSO +pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dispatch(3PCAP), +pcap_loop(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_dump_close.3pcap b/tcpdump/jni/libpcap/pcap_dump_close.3pcap new file mode 100644 index 0000000..afd00cb --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_dump_close.3pcap @@ -0,0 +1,37 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP_CLOSE 3PCAP "5 April 2008" +.SH NAME +pcap_dump_close \- close a savefile being written to +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +void pcap_dump_close(pcap_dumper_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_dump_close() +closes the ``savefile.'' +.SH SEE ALSO +pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dump(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_dump_file.3pcap b/tcpdump/jni/libpcap/pcap_dump_file.3pcap new file mode 100644 index 0000000..982b0dc --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_dump_file.3pcap @@ -0,0 +1,38 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP_FILE 3PCAP "5 April 2008" +.SH NAME +pcap_dump_file \- get the standard I/O stream for a savefile being written +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +FILE *pcap_dump_file(pcap_dumper_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_dump_file() +returns the standard I/O stream of the ``savefile'' opened by +.BR pcap_dump_open() . +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_dump_flush.3pcap b/tcpdump/jni/libpcap/pcap_dump_flush.3pcap new file mode 100644 index 0000000..ba98dee --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_dump_flush.3pcap @@ -0,0 +1,43 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP_FLUSH 3PCAP "5 April 2008" +.SH NAME +pcap_dump_flush \- flush to a savefile packets dumped +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_dump_flush(pcap_dumper_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_dump_flush() +flushes the output buffer to the ``savefile,'' so that any packets +written with +.B pcap_dump() +but not yet written to the ``savefile'' will be written. +.SH RETURN VALUE +.B pcap_dump_flush() +returns 0 on success and \-1 on failure. +.SH SEE ALSO +pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dump(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_dump_ftell.3pcap b/tcpdump/jni/libpcap/pcap_dump_ftell.3pcap new file mode 100644 index 0000000..6d5c828 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_dump_ftell.3pcap @@ -0,0 +1,42 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP_FTELL 3PCAP "5 April 2008" +.SH NAME +pcap_dump_ftell \- get the current file offset for a savefile being written +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +long pcap_dump_ftell(pcap_dumper_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_dump_ftell() +returns the current file position for the ``savefile'', representing the +number of bytes written by +.B pcap_dump_open() +and +.BR pcap_dump() . +\-1 is returned on error. +.SH SEE ALSO +pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dump(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_dump_open.3pcap.in b/tcpdump/jni/libpcap/pcap_dump_open.3pcap.in new file mode 100644 index 0000000..0b2e3c6 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_dump_open.3pcap.in @@ -0,0 +1,96 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP_OPEN 3PCAP "5 April 2008" +.SH NAME +pcap_dump_open, pcap_dump_fopen \- open a file to which to write packets +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.nf +.LP +.ft B +pcap_dumper_t *pcap_dump_open(pcap_t *p, const char *fname); +pcap_dumper_t *pcap_dump_open_append(pcap_t *p, const char *fname); +pcap_dumper_t *pcap_dump_fopen(pcap_t *p, FILE *fp); +.ft +.fi +.SH DESCRIPTION +.B pcap_dump_open() +is called to open a ``savefile'' for writing. +.I fname +specifies the name of the file to open. The file will have +the same format as those used by +.BR tcpdump (1) +and +.BR tcpslice (1). +The name "-" is a synonym +for +.BR stdout . +.PP +.B pcap_dump_fopen() +is called to write data to an existing open stream +.IR fp . +Note that on Windows, that stream should be opened in binary mode. +.PP +.I p +is a capture or ``savefile'' handle returned by an earlier call to +.B pcap_create() +and activated by an earlier call to +.BR pcap_activate() , +or returned by an earlier call to +.BR pcap_open_offline() , +.BR pcap_open_live() , +or +.BR pcap_open_dead() . +The time stamp precision, link-layer type, and snapshot length from +.I p +are used as the link-layer type and snapshot length of the output file. +.PP +.B pcap_dump_open_append() +is like +.B pcap_dump_open +but does not create the file if it does not exist and, if it does +already exist, and is a pcap file with the same byte order as the host +opening the file, and has the same time stamp precision, link-layer +header type, and snapshot length as +.IR p , +it will write new packets at the end of the file. +.SH RETURN VALUES +A pointer to a +.B pcap_dumper_t +structure to use in subsequent +.B pcap_dump() +and +.B pcap_dump_close() +calls is returned on success. +.B NULL +is returned on failure. +If +.B NULL +is returned, +.B pcap_geterr(\fIp\fB) +can be used to get the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), +pcap_open_offline(3PCAP), pcap_open_live(3PCAP), pcap_open_dead(3PCAP), +pcap_dump(3PCAP), pcap_dump_close(3PCAP), pcap_geterr(3PCAP), +pcap-savefile(@MAN_FILE_FORMATS@) diff --git a/tcpdump/jni/libpcap/pcap_file.3pcap b/tcpdump/jni/libpcap/pcap_file.3pcap new file mode 100644 index 0000000..7b18c81 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_file.3pcap @@ -0,0 +1,57 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_FILE 3PCAP "5 April 2008" +.SH NAME +pcap_file \- get the standard I/O stream for a savefile being read +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +FILE *pcap_file(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_file() +returns the standard I/O stream of the ``savefile,'' if a ``savefile'' +was opened with +.BR pcap_open_offline() , +or NULL, if a network device was opened with +.B pcap_create() +and +.BR pcap_activate() , +or with +.BR pcap_open_live() . +.PP +Note that the Packet Capture library is usually built with large file +support, so the standard I/O stream of the ``savefile'' might refer to +a file larger than 2 gigabytes; applications that use +.B pcap_file() +should, if possible, use calls that support large files on the return +value of +.B pcap_file() +or the value returned by +.B fileno() +when passed the return value of +.BR pcap_file() . +.SH SEE ALSO +pcap(3PCAP), pcap_open_offline(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_fileno.3pcap b/tcpdump/jni/libpcap/pcap_fileno.3pcap new file mode 100644 index 0000000..39d068b --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_fileno.3pcap @@ -0,0 +1,66 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_FILENO 3PCAP "3 November 2009" +.SH NAME +pcap_fileno \- get the file descriptor for a live capture +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_fileno(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +If +.I p +refers to a network device that was opened for a live capture using +a combination of +.B pcap_create() +and +.BR pcap_activate() , +or using +.BR pcap_open_live() , +.B pcap_fileno() +returns the file descriptor from which captured packets are read. +.LP +If +.I p +refers to a ``savefile'' that was opened using functions such as +.BR pcap_open_offline() +or +.BR pcap_fopen_offline() , +a ``dead'' +.B pcap_t +opened using +.BR pcap_open_dead() , +or a +.B pcap_t +that was created with +.B pcap_create() +but that has not yet been activated with +.BR pcap_activate() , +it returns \-1. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), +pcap_open_live(3PCAP), pcap_open_offline(3PCAP), +pcap_fopen_offline(3PCAP), pcap_open_dead(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_findalldevs.3pcap b/tcpdump/jni/libpcap/pcap_findalldevs.3pcap new file mode 100644 index 0000000..00bb911 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_findalldevs.3pcap @@ -0,0 +1,190 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_FINDALLDEVS 3PCAP "10 January 2014" +.SH NAME +pcap_findalldevs, pcap_freealldevs \- get a list of capture devices, and +free that list +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf); +void pcap_freealldevs(pcap_if_t *alldevs); +.ft +.fi +.SH DESCRIPTION +.B pcap_findalldevs() +constructs a list of network devices that can be opened with +.B pcap_create() +and +.B pcap_activate() +or with +.BR pcap_open_live() . +(Note that there may be network devices that cannot be opened by the +process calling +.BR pcap_findalldevs() , +because, for example, that process does not have sufficient privileges +to open them for capturing; if so, those devices will not appear on the +list.) +If +.B pcap_findalldevs() +succeeds, the pointer pointed to by +.I alldevsp +is set to point to the first element of the list, or to +.B NULL +if no devices were found (this is considered success). +Each element of the list is of type +.BR pcap_if_t , +and has the following members: +.RS +.TP +.B next +if not +.BR NULL , +a pointer to the next element in the list; +.B NULL +for the last element of the list +.TP +.B name +a pointer to a string giving a name for the device to pass to +.B pcap_open_live() +.TP +.B description +if not +.BR NULL , +a pointer to a string giving a human-readable description of the device +.TP +.B addresses +a pointer to the first element of a list of network addresses for the +device, +or +.B NULL +if the device has no addresses +.TP +.B flags +device flags: +.RS +.TP +.B PCAP_IF_LOOPBACK +set if the device is a loopback interface +.TP +.B PCAP_IF_UP +set if the device is up +.TP +.B PCAP_IF_RUNNING +set if the device is running +.RE +.RE +.PP +Each element of the list of addresses is of type +.BR pcap_addr_t , +and has the following members: +.RS +.TP +.B next +if not +.BR NULL , +a pointer to the next element in the list; +.B NULL +for the last element of the list +.TP +.B addr +a pointer to a +.B "struct sockaddr" +containing an address +.TP +.B netmask +if not +.BR NULL , +a pointer to a +.B "struct sockaddr" +that contains the netmask corresponding to the address pointed to by +.B addr +.TP +.B broadaddr +if not +.BR NULL , +a pointer to a +.B "struct sockaddr" +that contains the broadcast address corresponding to the address pointed +to by +.BR addr ; +may be null if the device doesn't support broadcasts +.TP +.B dstaddr +if not +.BR NULL , +a pointer to a +.B "struct sockaddr" +that contains the destination address corresponding to the address pointed +to by +.BR addr ; +may be null if the device isn't a point-to-point interface +.RE +.PP +Note that the addresses in the list of addresses might be IPv4 +addresses, IPv6 addresses, or some other type of addresses, so you must +check the +.B sa_family +member of the +.B "struct sockaddr" +before interpreting the contents of the address; do not assume that the +addresses are all IPv4 addresses, or even all IPv4 or IPv6 addresses. +IPv4 addresses have the value +.BR AF_INET , +IPv6 addresses have the value +.B AF_INET6 +(which older operating systems that don't support IPv6 might not +define), and other addresses have other values. Whether other addresses +are returned, and what types they might have is platform-dependent. +For IPv4 addresses, the +.B "struct sockaddr" +pointer can be interpreted as if it pointed to a +.BR "struct sockaddr_in" ; +for IPv6 addresses, it can be interpreted as if it pointed to a +.BR "struct sockaddr_in6". +.PP +The list of devices must be freed with +.BR pcap_freealldevs() , +which frees the list pointed to by +.IR alldevs . +.SH RETURN VALUE +.B pcap_findalldevs() +returns 0 on success and \-1 on failure; as indicated, finding no +devices is considered success, rather than failure, so 0 will be +returned in that case. +If \-1 is returned, +.I errbuf +is filled in with an appropriate error message. +.I errbuf +is assumed to be able to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), +pcap_open_live(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_freecode.3pcap b/tcpdump/jni/libpcap/pcap_freecode.3pcap new file mode 100644 index 0000000..c3c3ea6 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_freecode.3pcap @@ -0,0 +1,43 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_FREECODE 3PCAP "5 April 2008" +.SH NAME +pcap_freecode \- free a BPF program +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +void pcap_freecode(struct bpf_program *); +.ft +.fi +.SH DESCRIPTION +.B pcap_freecode() +is used to free up allocated memory pointed to by a +.I bpf_program +struct generated by +.B pcap_compile() +when that BPF program is no longer needed, for example after it +has been made the filter program for a pcap structure by a call to +.BR pcap_setfilter() . +.SH SEE ALSO +pcap(3PCAP), pcap_compile(3PCAP), pcap_setfilter(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_get_selectable_fd.3pcap b/tcpdump/jni/libpcap/pcap_get_selectable_fd.3pcap new file mode 100644 index 0000000..6640577 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_get_selectable_fd.3pcap @@ -0,0 +1,133 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_GET_SELECTABLE_FD 3PCAP "22 July 2011" +.SH NAME +pcap_get_selectable_fd \- get a file descriptor on which a select() can +be done for a live capture +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_get_selectable_fd(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_get_selectable_fd() +returns, on UNIX, a file descriptor number for a file descriptor on +which one can +do a +.BR select() , +.BR poll() , +or other such call +to wait for it to be possible to read packets without blocking, if such +a descriptor exists, or \-1, if no such descriptor exists. Some network +devices opened with +.B pcap_create() +and +.BR pcap_activate() , +or with +.BR pcap_open_live() , +do not support +.B select() +or +.B poll() +(for example, regular network devices on FreeBSD 4.3 and 4.4, and Endace +DAG devices), so \-1 is returned for those devices. +.PP +Note that a descriptor on which a read can be done without blocking may, +on some platforms, not have any packets to read if the read timeout has +expired. A call to +.B pcap_dispatch() +will return 0 in this case, but will not block. +.PP +Note that in: +.IP +FreeBSD prior to FreeBSD 4.6; +.IP +NetBSD prior to NetBSD 3.0; +.IP +OpenBSD prior to OpenBSD 2.4; +.IP +Mac OS X prior to Mac OS X 10.7; +.PP +.B select() +and +.B poll() +do not work correctly on BPF devices; +.B pcap_get_selectable_fd() +will return a file descriptor on most of those versions (the exceptions +being FreeBSD 4.3 and 4.4), but a simple +.B select() +or +.B poll() +will not indicate that the descriptor is readable until a full buffer's +worth of packets is received, even if the read timeout expires before +then. To work around this, an application that uses +.B select() +or +.B poll() +to wait for packets to arrive must put the +.B pcap_t +in non-blocking mode, and must arrange that the +.B select() +or +.B poll() +have a timeout less than or equal to the read timeout, +and must try to read packets after that timeout expires, regardless of +whether +.B select() +or +.B poll() +indicated that the file descriptor for the +.B pcap_t +is ready to be read or not. (That workaround will not work in FreeBSD +4.3 and later; however, in FreeBSD 4.6 and later, +.B select() +and +.B poll() +work correctly on BPF devices, so the workaround isn't necessary, +although it does no harm.) +.PP +Note also that +.B poll() +doesn't work on character special files, including BPF devices, in Mac +OS X 10.4 and 10.5, so, while +.B select() +can be used on the descriptor returned by +.BR pcap_get_selectable_fd() , +.B poll() +cannot be used on it those versions of Mac OS X. Kqueues also don't +work on that descriptor. +.BR poll() , +but not kqueues, work on that descriptor in Mac OS X releases prior to +10.4; +.B poll() +and kqueues work on that descriptor in Mac OS X 10.6 and later. +.PP +.B pcap_get_selectable_fd() +is not available on Windows. +.SH RETURN VALUE +A selectable file descriptor is returned if one exists; otherwise, \-1 +is returned. +.SH SEE ALSO +pcap(3PCAP), select(2), poll(2) diff --git a/tcpdump/jni/libpcap/pcap_get_tstamp_precision.3pcap.in b/tcpdump/jni/libpcap/pcap_get_tstamp_precision.3pcap.in new file mode 100644 index 0000000..656c142 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_get_tstamp_precision.3pcap.in @@ -0,0 +1,52 @@ +.\"Copyright (c) 2013, Michal Sekletar +.\"All rights reserved. +.\" +.\"Redistribution and use in source and binary forms, with or without +.\"modification, are permitted provided that the following conditions +.\"are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" 3. The names of the authors may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\"THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\"IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +.TH PCAP_GET_TSTAMP_PRECISION 3PCAP "27 August 2013" +.SH NAME +pcap_get_tstamp_precision \- get the time stamp precision returned in +captures +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_get_tstamp_precision(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_get_tstamp_precision() +returns the precision of the time stamp returned in packet captures on the pcap +descriptor. +.SH RETURN VALUE +.B pcap_get_tstamp_precision() +returns +.B PCAP_TSTAMP_PRECISION_MICRO +or +.BR PCAP_TSTAMP_PRECISION_NANO , +which indicates +that pcap captures contains time stamps in microseconds or nanoseconds +respectively. +.SH SEE ALSO +pcap(3PCAP), +pcap_set_tstamp_precision(3PCAP), +pcap-tstamp(@MAN_MISC_INFO@) diff --git a/tcpdump/jni/libpcap/pcap_geterr.3pcap b/tcpdump/jni/libpcap/pcap_geterr.3pcap new file mode 100644 index 0000000..fcabec3 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_geterr.3pcap @@ -0,0 +1,51 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_GETERR 3PCAP "5 April 2008" +.SH NAME +pcap_geterr, pcap_perror \- get or print libpcap error message text +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +char *pcap_geterr(pcap_t *p); +void pcap_perror(pcap_t *p, char *prefix); +.ft +.fi +.SH DESCRIPTION +.B pcap_geterr() +returns the error text pertaining to the last pcap library error. +.BR NOTE : +the pointer it returns will no longer point to a valid error message +string after the +.B pcap_t +passed to it is closed; you must use or copy the string before closing +the +.BR pcap_t . +.PP +.B pcap_perror() +prints the text of the last pcap library error on +.BR stderr , +prefixed by +.IR prefix . +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_inject.3pcap b/tcpdump/jni/libpcap/pcap_inject.3pcap new file mode 100644 index 0000000..7ccdf2c --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_inject.3pcap @@ -0,0 +1,88 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_INJECT 3PCAP "5 April 2008" +.SH NAME +pcap_inject, pcap_sendpacket \- transmit a packet +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_inject(pcap_t *p, const void *buf, size_t size); +int pcap_sendpacket(pcap_t *p, const u_char *buf, int size); +.ft +.fi +.SH DESCRIPTION +.B pcap_inject() +sends a raw packet through the network interface; +.I buf +points to the data of the packet, including the link-layer header, and +.I size +is the number of bytes in the packet. +.PP +Note that, even if you successfully open the network interface, you +might not have permission to send packets on it, or it might not support +sending packets; as +.I pcap_open_live() +doesn't have a flag to indicate whether to open for capturing, sending, +or capturing and sending, you cannot request an open that supports +sending and be notified at open time whether sending will be possible. +Note also that some devices might not support sending packets. +.PP +Note that, on some platforms, the link-layer header of the packet that's +sent might not be the same as the link-layer header of the packet +supplied to +.BR pcap_inject() , +as the source link-layer address, if the header contains such an +address, might be changed to be the address assigned to the interface on +which the packet it sent, if the platform doesn't support sending +completely raw and unchanged packets. Even worse, some drivers on some +platforms might change the link-layer type field to whatever value +libpcap used when attaching to the device, even on platforms that +.I do +nominally support sending completely raw and unchanged packets. +.PP +.B pcap_sendpacket() +is like +.BR pcap_inject() , +but it returns 0 on success, rather than returning the number of bytes +written. +.RB ( pcap_inject() +comes from OpenBSD; +.B pcap_sendpacket() +comes from WinPcap. Both are provided for compatibility.) +.SH RETURN VALUE +.B pcap_inject() +returns the number of bytes written on success and \-1 on failure. +.PP +.B pcap_sendpacket() +returns 0 on success and \-1 on failure. +.PP +If \-1 is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_geterr(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_is_swapped.3pcap b/tcpdump/jni/libpcap/pcap_is_swapped.3pcap new file mode 100644 index 0000000..a120616 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_is_swapped.3pcap @@ -0,0 +1,51 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_IS_SWAPPED 3PCAP "17 September 2013" +.SH NAME +pcap_is_swapped \- find out whether a savefile has the native byte order +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_is_swapped(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_is_swapped() +returns true (1) if +.I p +refers to a ``savefile'' that uses a different byte order +than the current system. For a live capture, it always returns false +(0). +.PP +It must not be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +.SH RETURN VALUE +.B pcap_datalink() +returns true (1) or false (0) on success and +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated. +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_lib_version.3pcap b/tcpdump/jni/libpcap/pcap_lib_version.3pcap new file mode 100644 index 0000000..3ec2e32 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_lib_version.3pcap @@ -0,0 +1,39 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LIB_VERSION 3PCAP "5 April 2008" +.SH NAME +pcap_lib_version \- get the version information for libpcap +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_lib_version(void); +.ft +.fi +.SH DESCRIPTION +.B pcap_lib_version() +returns a pointer to a string giving information about the version of +the libpcap library being used; note that it contains more information +than just a version number. +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_list_datalinks.3pcap.in b/tcpdump/jni/libpcap/pcap_list_datalinks.3pcap.in new file mode 100644 index 0000000..f849346 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_list_datalinks.3pcap.in @@ -0,0 +1,73 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LIST_DATALINKS 3PCAP "17 September 2013" +.SH NAME +pcap_list_datalinks, pcap_free_datalinks \- get a list of link-layer header +types supported by a capture device, and free that list +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_list_datalinks(pcap_t *p, int **dlt_buf); +void pcap_free_datalinks(int *dlt_list); +.ft +.fi +.SH DESCRIPTION +.B pcap_list_datalinks() +is used to get a list of the supported link-layer header types of the +interface associated with the pcap descriptor. +.B pcap_list_datalinks() +allocates an array to hold the list and sets +.IR *dlt_buf +to point to that array. +.LP +The caller is responsible for freeing the array with +.BR pcap_free_datalinks() , +which frees the list of link-layer header types pointed to by +.IR dlt_list . +.LP +It must not be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +.SH RETURN VALUE +.B pcap_list_datalinks() +returns the number of link-layer header types in the array on success, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, +and +.B PCAP_ERROR +(\-1) on other errors. +If +.B PCAP_ERROR +is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_geterr(3PCAP), +pcap_datalink_val_to_name(3PCAP), +pcap-linktype(@MAN_MISC_INFO@) diff --git a/tcpdump/jni/libpcap/pcap_list_tstamp_types.3pcap.in b/tcpdump/jni/libpcap/pcap_list_tstamp_types.3pcap.in new file mode 100644 index 0000000..66d3d66 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_list_tstamp_types.3pcap.in @@ -0,0 +1,70 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "21 August 2010" +.SH NAME +pcap_list_tstamp_types, pcap_free_tstamp_types \- get a list of time +stamp types supported by a capture device, and free that list +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp); +void pcap_free_tstamp_types(int *tstamp_types); +.ft +.fi +.SH DESCRIPTION +.B pcap_list_tstamp_types() +is used to get a list of the supported time stamp types of the interface +associated with the pcap descriptor. +.B pcap_list_tstamp_types() +allocates an array to hold the list and sets +.I *tstamp_typesp +to point to the array. +See +.BR pcap-tstamp (@MAN_MISC_INFO@) +for a list of all the time stamp types. +.PP +The caller is responsible for freeing the array with +.BR pcap_free_tstamp_types() , +which frees the list pointed to by +.IR tstamp_types . +.SH RETURN VALUE +.B pcap_list_tstamp_types() +returns the number of time stamp types in the array on success and +.B PCAP_ERROR +on failure. +A return value of zero means that you cannot specify a time stamp type; +you are limited to the capture device's default time stamp type. +If +.B PCAP_ERROR +is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_geterr(3PCAP), pcap_tstamp_type_val_to_name(3PCAP), +pcap-tstamp(@MAN_MISC_INFO@) diff --git a/tcpdump/jni/libpcap/pcap_lookupdev.3pcap b/tcpdump/jni/libpcap/pcap_lookupdev.3pcap new file mode 100644 index 0000000..79dda42 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_lookupdev.3pcap @@ -0,0 +1,60 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LOOKUPDEV 3PCAP "5 April 2008" +.SH NAME +pcap_lookupdev \- find the default device on which to capture +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +char *pcap_lookupdev(char *errbuf); +.ft +.fi +.SH DESCRIPTION +.B pcap_lookupdev() +returns a pointer to a string giving the name of a network device +suitable for use with +.B pcap_create() +and +.BR pcap_activate() , +or with +.BR pcap_open_live() , +and with +.BR pcap_lookupnet() . +If there is an error, +.B NULL +is returned and +.I errbuf +is filled in with an appropriate error message. +.I errbuf +is assumed to be able to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), +pcap_open_live(3PCAP), pcap_lookupnet(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_lookupnet.3pcap b/tcpdump/jni/libpcap/pcap_lookupnet.3pcap new file mode 100644 index 0000000..a3d14ae --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_lookupnet.3pcap @@ -0,0 +1,63 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LOOKUPNET 3PCAP "5 April 2008" +.SH NAME +pcap_lookupnet \- find the IPv4 network number and netmask for a device +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +int pcap_lookupnet(const char *device, bpf_u_int32 *netp, +.ti +8 +bpf_u_int32 *maskp, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.B pcap_lookupnet() +is used to determine the IPv4 network number and mask +associated with the network device +.IR device . +Both +.I netp +and +.I maskp +are +.I bpf_u_int32 +pointers. +.SH RETURN VALUE +.B pcap_lookupnet() +returns 0 on success and \-1 on failure. +If \-1 is returned, +.I errbuf +is filled in with an appropriate error message. +.I errbuf +is assumed to be able to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_loop.3pcap b/tcpdump/jni/libpcap/pcap_loop.3pcap new file mode 100644 index 0000000..011d85c --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_loop.3pcap @@ -0,0 +1,199 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LOOP 3PCAP "13 October 2013" +.SH NAME +pcap_loop, pcap_dispatch \- process packets from a live capture or savefile +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h, +.ti +8 + const u_char *bytes); +.ft +.LP +.ft B +int pcap_loop(pcap_t *p, int cnt, +.ti +8 +pcap_handler callback, u_char *user); +int pcap_dispatch(pcap_t *p, int cnt, +.ti +8 +pcap_handler callback, u_char *user); +.ft +.fi +.SH DESCRIPTION +.B pcap_loop() +processes packets from a live capture or ``savefile'' until +.I cnt +packets are processed, the end of the ``savefile'' is +reached when reading from a ``savefile'', +.B pcap_breakloop() +is called, or an error occurs. +It does +.B not +return when live read timeouts occur. +A value of \-1 or 0 for +.I cnt +is equivalent to infinity, so that packets are processed until another +ending condition occurs. +.PP +.B pcap_dispatch() +processes packets from a live capture or ``savefile'' until +.I cnt +packets are processed, the end of the current bufferful of packets is +reached when doing a live capture, the end of the ``savefile'' is +reached when reading from a ``savefile'', +.B pcap_breakloop() +is called, or an error occurs. +Thus, when doing a live capture, +.I cnt +is the maximum number of packets to process before returning, but is not +a minimum number; when reading a live capture, only one +bufferful of packets is read at a time, so fewer than +.I cnt +packets may be processed. A value of \-1 or 0 for +.I cnt +causes all the packets received in one buffer to be processed when +reading a live capture, and causes all the packets in the file to be +processed when reading a ``savefile''. +.PP +Note that, when doing a live capture on some platforms, if the read +timeout expires when there are no packets available, +.B pcap_dispatch() +will return 0, even when not in non-blocking mode, as there are no +packets to process. Applications should be prepared for this to happen, +but must not rely on it happening. +.PP +.ft B +(In older versions of libpcap, the behavior when +\fIcnt\fP +was 0 was undefined; different platforms and devices behaved +differently, so code that must work with older versions of libpcap +should use \-1, not 0, as the value of +\fIcnt\fP.) +.ft R +.PP +.I callback +specifies a +.I pcap_handler +routine to be called with three arguments: +a +.I u_char +pointer which is passed in the +.I user +argument to +.B pcap_loop() +or +.BR pcap_dispatch() , +a +.I const struct pcap_pkthdr +pointer pointing to the packet time stamp and lengths, and a +.I const u_char +pointer to the first +.B caplen +(as given in the +.I struct pcap_pkthdr +a pointer to which is passed to the callback routine) +bytes of data from the packet. The +.I struct pcap_pkthdr +and the packet data are not to be freed by the callback routine, and are +not guaranteed to be valid after the callback routine returns; if the +code needs them to be valid after the callback, it must make a copy of +them. +.PP +The bytes of data from the packet begin with a link-layer header. The +format of the link-layer header is indicated by the return value of the +.B pcap_datalink() +routine when handed the +.B pcap_t +value also passed to +.B pcap_loop() +or +.BR pcap_dispatch() . +.I http://www.tcpdump.org/linktypes.html +lists the values +.B pcap_datalink() +can return and describes the packet formats that +correspond to those values. The value it returns will be valid for all +packets received unless and until +.B pcap_set_datalink() +is called; after a successful call to +.BR pcap_set_datalink() , +all subsequent packets will have a link-layer header of the type +specified by the link-layer header type value passed to +.BR pcap_set_datalink() . +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. +.SH RETURN VALUE +.B pcap_loop() +returns 0 if +.I cnt +is exhausted or if, when reading from a ``savefile'', no more packets +are available. It returns \-1 if an error occurs or \-2 if the loop +terminated due to a call to +.B pcap_breakloop() +before any packets were processed. +It does +.B not +return when live read timeouts occur; instead, it attempts to read more +packets. +.PP +.B pcap_dispatch() +returns the number of packets processed on success; this can be 0 if no +packets were read from a live capture (if, for example, they were +discarded because they didn't pass the packet filter, or if, on +platforms that support a read timeout that starts before any packets +arrive, the timeout expires before any packets arrive, or if the file +descriptor for the capture device is in non-blocking mode and no packets +were available to be read) or if no more packets are available in a +``savefile.'' It returns \-1 if an error occurs or \-2 if the loop +terminated due to a call to +.B pcap_breakloop() +before any packets were processed. +.ft B +If your application uses pcap_breakloop(), +make sure that you explicitly check for \-1 and \-2, rather than just +checking for a return value < 0. +.ft R +.PP +If \-1 is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_geterr(3PCAP), pcap_breakloop(3PCAP), +pcap_datalink(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_major_version.3pcap b/tcpdump/jni/libpcap/pcap_major_version.3pcap new file mode 100644 index 0000000..a085838 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_major_version.3pcap @@ -0,0 +1,54 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_MAJOR_VERSION 3PCAP "21 December 2011" +.SH NAME +pcap_major_version, pcap_minor_version \- get the version number of a savefile +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_major_version(pcap_t *p); +int pcap_minor_version(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +If +.I p +refers to a ``savefile'', +.B pcap_major_version() +returns the major number of the file format of the ``savefile'' and +.B pcap_minor_version() +returns the minor number of the file format of the ``savefile''. The +version number is stored in the ``savefile''; note that the meaning of +its values depends on the type of ``savefile'' (for example, pcap or +pcap-NG). +.PP +If +.I p +refers to a live capture, the values returned by +.B pcap_major_version() +and +.B pcap_minor_version() +are not meaningful. +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_next_ex.3pcap b/tcpdump/jni/libpcap/pcap_next_ex.3pcap new file mode 100644 index 0000000..c310c2f --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_next_ex.3pcap @@ -0,0 +1,141 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_NEXT_EX 3PCAP "13 October 2013" +.SH NAME +pcap_next_ex, pcap_next \- read the next packet from a pcap_t +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, +.ti +8 +const u_char **pkt_data); +const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h); +.ft +.fi +.SH DESCRIPTION +.B pcap_next_ex() +reads the next packet and returns a success/failure indication. +If the packet was read without problems, the pointer pointed to by the +.I pkt_header +argument is set to point to the +.I pcap_pkthdr +struct for the packet, and the +pointer pointed to by the +.I pkt_data +argument is set to point to the data in the packet. The +.I struct pcap_pkthdr +and the packet data are not to be freed by the caller, and are not +guaranteed to be valid after the next call to +.BR pcap_next_ex() , +.BR pcap_next() , +.BR pcap_loop() , +or +.BR pcap_dispatch() ; +if the code needs them to remain valid, it must make a copy of them. +.PP +.B pcap_next() +reads the next packet (by calling +.B pcap_dispatch() +with a +.I cnt +of 1) and returns a +.I u_char +pointer to the data in that packet. The +packet data is not to be freed by the caller, and is not +guaranteed to be valid after the next call to +.BR pcap_next_ex() , +.BR pcap_next() , +.BR pcap_loop() , +or +.BR pcap_dispatch() ; +if the code needs it to remain valid, it must make a copy of it. +The +.I pcap_pkthdr +structure pointed to by +.I h +is filled in with the appropriate values for the packet. +.PP +The bytes of data from the packet begin with a link-layer header. The +format of the link-layer header is indicated by the return value of the +.B pcap_datalink() +routine when handed the +.B pcap_t +value also passed to +.B pcap_loop() +or +.BR pcap_dispatch() . +.I http://www.tcpdump.org/linktypes.html +lists the values +.B pcap_datalink() +can return and describes the packet formats that +correspond to those values. The value it returns will be valid for all +packets received unless and until +.B pcap_set_datalink() +is called; after a successful call to +.BR pcap_set_datalink() , +all subsequent packets will have a link-layer header of the type +specified by the link-layer header type value passed to +.BR pcap_set_datalink() . +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. +.SH RETURN VALUE +.B pcap_next_ex() +returns 1 if the packet was read without problems, 0 +if packets are being read from a live capture and the timeout expired, +\-1 if an error occurred while reading the packet, and \-2 if +packets are being read from a ``savefile'' and there are no more +packets to read from the savefile. +If \-1 is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.PP +.B pcap_next() +returns a pointer to the packet data on success, and returns +.B NULL +if an error occurred, or if no packets were read from a live +capture (if, for example, they were discarded because they didn't pass +the packet filter, or if, on platforms that support a read timeout that +starts before any packets arrive, the timeout expires before any packets +arrive, or if the file descriptor for the capture device is in +non-blocking mode and no packets were available to be read), or if no +more packets are available in a ``savefile.'' Unfortunately, there is +no way to determine whether an error occurred or not. +.SH SEE ALSO +pcap(3PCAP), pcap_geterr(3PCAP), pcap_dispatch(3PCAP), +pcap_datalink(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_offline_filter.3pcap b/tcpdump/jni/libpcap/pcap_offline_filter.3pcap new file mode 100644 index 0000000..b471c6a --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_offline_filter.3pcap @@ -0,0 +1,55 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_OFFLINE_FILTER 3PCAP "25 November 2012" +.SH NAME +pcap_offline_filter \- check whether a filter matches a packet +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_offline_filter(const struct bpf_program *fp, +.ti +8 +const struct pcap_pkthdr *h, const u_char *pkt) +.ft +.fi +.SH DESCRIPTION +.B pcap_offline_filter() +checks whether a filter matches a packet. +.I fp +is a pointer to a +.I bpf_program +struct, usually the result of a call to +.BR pcap_compile() . +.I h +points to the +.I pcap_pkthdr +structure for the packet, and +.I pkt +points to the data in the packet. +.SH RETURN VALUE +.B pcap_offline_filter() +returns the return value of the filter program. This will be zero if +the packet doesn't match the filter and non-zero if the packet matches +the filter. +.SH SEE ALSO +pcap(3PCAP), pcap_compile(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_open_dead.3pcap.in b/tcpdump/jni/libpcap/pcap_open_dead.3pcap.in new file mode 100644 index 0000000..2d1b48c --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_open_dead.3pcap.in @@ -0,0 +1,79 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_OPEN_DEAD 3PCAP "1 July 2013" +.SH NAME +pcap_open_dead, pcap_open_dead_with_tstamp_precision \- open a fake +pcap_t for compiling filters or opening a capture for output +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +pcap_t *pcap_open_dead(int linktype, int snaplen); +pcap_t *pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, + u_int precision); +.ft +.fi +.SH DESCRIPTION +.PP +.B pcap_open_dead() +and +.B pcap_open_dead_with_tstamp_precision() +are used for creating a +.B pcap_t +structure to use when calling the other functions in libpcap. It is +typically used when just using libpcap for compiling BPF code; it can +also be used if using +.BR pcap_dump_open() , +.BR pcap_dump() , +and +.B pcap_dump_close() +to write a savefile if there is no +.B pcap_t +that supplies the packets to be written. +.PP +.I linktype +specifies the link-layer type for the +.BR pcap_t . +.PP +.I snaplen +specifies the snapshot length for the +.BR pcap_t . +.PP +When +.BR pcap_open_dead_with_tstamp_precision() , +is used to create a +.B pcap_t +for use with +.BR pcap_dump_open() , +.I precision +specifies the time stamp precision for packets; +.B PCAP_TSTAMP_PRECISION_MICRO +should be specified if the packets to be written have time stamps in +seconds and microseconds, and +.B PCAP_TSTAMP_PRECISION_NANO +should be specified if the packets to be written have time stamps in +seconds and nanoseconds. Its value does not affect +.BR pcap_compile() . +.SH SEE ALSO +pcap(3PCAP), pcap_compile(3PCAP), pcap_dump_open(3PCAP), +pcap-linktype(@MAN_MISC_INFO@) diff --git a/tcpdump/jni/libpcap/pcap_open_live.3pcap b/tcpdump/jni/libpcap/pcap_open_live.3pcap new file mode 100644 index 0000000..715994b --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_open_live.3pcap @@ -0,0 +1,87 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_OPEN_LIVE 3PCAP "5 April 2008" +.SH NAME +pcap_open_live \- open a device for capturing +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +pcap_t *pcap_open_live(const char *device, int snaplen, +.ti +8 +int promisc, int to_ms, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.B pcap_open_live() +is used to obtain a packet capture handle to look +at packets on the network. +.I device +is a string that specifies the network device to open; on Linux systems +with 2.2 or later kernels, a +.I device +argument of "any" or +.B NULL +can be used to capture packets from all interfaces. +.PP +.I snaplen +specifies the snapshot length to be set on the handle. +.PP +.I promisc +specifies if the interface is to be put into promiscuous mode. +.PP +.I to_ms +specifies the read timeout in milliseconds. +.SH RETURN VALUE +.B pcap_open_live() +returns a +.I pcap_t * +on success and +.B NULL +on failure. +If +.B NULL +is returned, +.I errbuf +is filled in with an appropriate error message. +.I errbuf +may also be set to warning text when +.B pcap_open_live() +succeeds; to detect this case the caller should store a zero-length string in +.I errbuf +before calling +.B pcap_open_live() +and display the warning to the user if +.I errbuf +is no longer a zero-length string. +.I errbuf +is assumed to be able to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_open_offline.3pcap.in b/tcpdump/jni/libpcap/pcap_open_offline.3pcap.in new file mode 100644 index 0000000..7239729 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_open_offline.3pcap.in @@ -0,0 +1,109 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_OPEN_OFFLINE 3PCAP "1 July 2013" +.SH NAME +pcap_open_offline, pcap_open_offline_with_tstamp_precision, +pcap_fopen_offline, pcap_fopen_offline_with_tstamp_precision \- open a saved capture file for reading +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +pcap_t *pcap_open_offline(const char *fname, char *errbuf); +pcap_t *pcap_open_offline_with_tstamp_precision(const char *fname, + u_int precision, char *errbuf); +pcap_t *pcap_fopen_offline(FILE *fp, char *errbuf); +pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp, + u_int precision, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.B pcap_open_offline() +and +.B pcap_open_offline_with_tstamp_precision() +are called to open a ``savefile'' for reading. +.PP +.I fname +specifies the name of the file to open. The file can have the pcap file +format as described in +.BR pcap-savefile (@MAN_FILE_FORMATS@), +which is the file format used by, among other programs, +.BR tcpdump (1) +and +.BR tcpslice (1), +or can have the pcap-ng file format, although not all pcap-ng files can +be read. +The name "-" is a synonym for +.BR stdin . +.PP +.B pcap_open_offline_with_tstamp_precision() +takes an additional +.I precision +argument specifying the time stamp precision desired; +if +.B PCAP_TSTAMP_PRECISION_MICRO +is specified, packet time stamps will be supplied in seconds and +microseconds, +and if +.B PCAP_TSTAMP_PRECISION_NANO +is specified, packet time stamps will be supplied in seconds and +nanoseconds. If the time stamps in the file do not have the same +precision as the requested precision, they will be scaled up or down as +necessary before being supplied. +.PP +Alternatively, you may call +.B pcap_fopen_offline() +or +.B pcap_fopen_offline_with_tstamp_precision() +to read dumped data from an existing open stream +.IR fp . +.B pcap_fopen_offline_with_tstamp_precision() takes an additional +.I precision +argument as described above. +Note that on Windows, that stream should be opened in binary mode. +.SH RETURN VALUE +.BR pcap_open_offline() , +.BR pcap_open_offline_with_tstamp_precision() , +.BR pcap_fopen_offline() , +and +.B pcap_fopen_offline_with_tstamp_precision() +return a +.I pcap_t * +on success and +.B NULL +on failure. +If +.B NULL +is returned, +.I errbuf +is filled in with an appropriate error message. +.I errbuf +is assumed to be able to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.SH SEE ALSO +pcap(3PCAP), pcap-savefile(@MAN_FILE_FORMATS@) diff --git a/tcpdump/jni/libpcap/pcap_set_buffer_size.3pcap b/tcpdump/jni/libpcap/pcap_set_buffer_size.3pcap new file mode 100644 index 0000000..fea1df7 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_set_buffer_size.3pcap @@ -0,0 +1,45 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_BUFFER_SIZE 3PCAP "5 April 2008" +.SH NAME +pcap_set_buffer_size \- set the buffer size for a not-yet-activated +capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_buffer_size(pcap_t *p, int buffer_size); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_buffer_size() +sets the buffer size that will be used on a capture handle when +the handle is activated to +.IR buffer_size , +which is in units of bytes. +.SH RETURN VALUE +.B pcap_set_buffer_size() +returns 0 on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_set_datalink.3pcap b/tcpdump/jni/libpcap/pcap_set_datalink.3pcap new file mode 100644 index 0000000..60a7bfc --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_set_datalink.3pcap @@ -0,0 +1,51 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_DATALINK 3PCAP "22 August 2010" +.SH NAME +pcap_set_datalink \- set the link-layer header type to be used by a +capture device +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_set_datalink(pcap_t *p, int dlt); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_datalink() +is used to set the current link-layer header type of the pcap descriptor +to the type specified by +.IR dlt . +.SH RETURN VALUE +.B pcap_set_datalink() +returns 0 on success and \-1 on failure. +If \-1 is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_geterr(3PCAP), +pcap_datalink_name_to_val(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_set_immediate_mode.3pcap b/tcpdump/jni/libpcap/pcap_set_immediate_mode.3pcap new file mode 100644 index 0000000..87ec98b --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_set_immediate_mode.3pcap @@ -0,0 +1,47 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_IMMEDIATE_MODE 3PCAP "8 May 2013" +.SH NAME +pcap_set_immediate_mode \- set immediate mode for a not-yet-activated capture +handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_immediate_mode(pcap_t *p, int immediate_mode); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_immediate_mode() +sets whether immediate mode should be set on a capture handle when +the handle is activated. +If +.I immediate_mode +is non-zero, immediate mode will be set, otherwise it will not be set. +.SH RETURN VALUE +.B pcap_set_immediate_mode() +returns 0 on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_set_promisc.3pcap b/tcpdump/jni/libpcap/pcap_set_promisc.3pcap new file mode 100644 index 0000000..5d17572 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_set_promisc.3pcap @@ -0,0 +1,46 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_PROMISC 3PCAP "5 April 2008" +.SH NAME +pcap_set_promisc \- set promiscuous mode for a not-yet-activated +capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_promisc(pcap_t *p, int promisc); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_promisc() +sets whether promiscuous mode should be set on a capture handle when +the handle is activated. +If +.I promisc +is non-zero, promiscuous mode will be set, otherwise it will not be set. +.SH RETURN VALUE +.B pcap_set_promisc() +returns 0 on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_set_rfmon.3pcap b/tcpdump/jni/libpcap/pcap_set_rfmon.3pcap new file mode 100644 index 0000000..a386e8b --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_set_rfmon.3pcap @@ -0,0 +1,47 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_RFMON 3PCAP "5 April 2008" +.SH NAME +pcap_set_rfmon \- set monitor mode for a not-yet-activated capture +handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_rfmon(pcap_t *p, int rfmon); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_rfmon() +sets whether monitor mode should be set on a capture handle when +the handle is activated. +If +.I rfmon +is non-zero, monitor mode will be set, otherwise it will not be set. +.SH RETURN VALUE +.B pcap_set_rfmon() +returns 0 on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), +pcap_can_set_rfmon(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_set_snaplen.3pcap b/tcpdump/jni/libpcap/pcap_set_snaplen.3pcap new file mode 100644 index 0000000..8080ea1 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_set_snaplen.3pcap @@ -0,0 +1,44 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_SNAPLEN 3PCAP "5 April 2008" +.SH NAME +pcap_set_snaplen \- set the snapshot length for a not-yet-activated +capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_snaplen(pcap_t *p, int snaplen); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_snaplen() +sets the snapshot length to be used on a capture handle when the handle +is activated to +.IR snaplen . +.SH RETURN VALUE +.B pcap_set_snaplen() +returns 0 on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_set_timeout.3pcap b/tcpdump/jni/libpcap/pcap_set_timeout.3pcap new file mode 100644 index 0000000..b728203 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_set_timeout.3pcap @@ -0,0 +1,45 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_TIMEOUT 3PCAP "16 April 2014" +.SH NAME +pcap_set_timeout \- set the read timeout for a not-yet-activated +capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_timeout(pcap_t *p, int to_ms); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_timeout() +sets the read timeout that will be used on a capture handle when +the handle is activated to +.IR to_ms , +which is in units of milliseconds. +.SH RETURN VALUE +.B pcap_set_timeout() +returns 0 on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_set_tstamp_precision.3pcap.in b/tcpdump/jni/libpcap/pcap_set_tstamp_precision.3pcap.in new file mode 100644 index 0000000..85fa84d --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_set_tstamp_precision.3pcap.in @@ -0,0 +1,61 @@ +.\"Copyright (c) 2013, Michal Sekletar +.\"All rights reserved. +.\" +.\"Redistribution and use in source and binary forms, with or without +.\"modification, are permitted provided that the following conditions +.\"are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" 3. The names of the authors may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\"THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\"IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +.TH PCAP_SET_TSTAMP_PRECISION 3PCAP "27 August 2013" +.SH NAME +pcap_set_tstamp_precision \- set the time stamp precision returned in +captures +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_tstamp_precision() +sets the precision of the time stamp desired for packets captured on the pcap +descriptor to the type specified by +.IR tstamp_precision . +It must be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +Two time stamp precisions are supported, microseconds and nanoseconds. One can +use options +.B PCAP_TSTAMP_PRECISION_MICRO and +.B PCAP_TSTAMP_PRECISION_NANO +to request desired precision. By default, time stamps are in microseconds. +.SH RETURN VALUE +.B pcap_set_tstamp_precision() +returns 0 on success if the specified time stamp precision is expected to be +supported by the operating system, +.B PCAP_ERROR_TSTAMP_PRECISION_NOTSUP +if operating system does not support requested time stamp precision, +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +pcap(3PCAP), +pcap_get_tstamp_precision(3PCAP), +pcap-tstamp(@MAN_MISC_INFO@) diff --git a/tcpdump/jni/libpcap/pcap_set_tstamp_type.3pcap.in b/tcpdump/jni/libpcap/pcap_set_tstamp_type.3pcap.in new file mode 100644 index 0000000..fd673bd --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_set_tstamp_type.3pcap.in @@ -0,0 +1,65 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_TSTAMP_TYPE 3PCAP "21 August 2010" +.SH NAME +pcap_set_tstamp_type \- set the time stamp type to be used by a +capture device +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_set_tstamp_type(pcap_t *p, int tstamp_type); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_tstamp_type() +sets the the type of time stamp desired for packets captured on the pcap +descriptor to the type specified by +.IR tstamp_type . +It must be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +.B pcap_list_tstamp_types() +will give a list of the time stamp types supported by a given capture +device. +See +.BR pcap-tstamp (@MAN_MISC_INFO@) +for a list of all the time stamp types. +.SH RETURN VALUE +.B pcap_set_tstamp_type() +returns 0 on success if the specified time stamp type is expected to be +supported by the capture device, +.B PCAP_WARNING_TSTAMP_TYPE_NOTSUP +if the specified time stamp type is not supported by the +capture device, +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated, and +.B PCAP_ERROR_CANTSET_TSTAMP_TYPE +if the capture device doesn't support setting the time stamp type. +.SH SEE ALSO +pcap(3PCAP), +pcap_list_tstamp_types(3PCAP), +pcap_tstamp_type_name_to_val(3PCAP), +pcap-tstamp(@MAN_MISC_INFO@) diff --git a/tcpdump/jni/libpcap/pcap_setdirection.3pcap b/tcpdump/jni/libpcap/pcap_setdirection.3pcap new file mode 100644 index 0000000..871a5b0 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_setdirection.3pcap @@ -0,0 +1,69 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SETDIRECTION 3PCAP "5 April 2008" +.SH NAME +pcap_setdirection \- set the direction for which packets will be captured +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_setdirection(pcap_t *p, pcap_direction_t d); +.ft +.fi +.SH DESCRIPTION +.B pcap_setdirection() +is used to specify a direction that packets will be captured. +.I d +is one of the constants +.BR PCAP_D_IN , +.B PCAP_D_OUT +or +.BR PCAP_D_INOUT . +.B PCAP_D_IN +will only capture packets received by the device, +.B PCAP_D_OUT +will only capture packets sent by the device and +.B PCAP_D_INOUT +will capture packets received by or sent by the device. +.B PCAP_D_INOUT +is the default setting if this function is not called. +.PP +.B pcap_setdirection() +isn't necessarily fully supported on all platforms; some platforms might +return an error for all values, and some other platforms might not +support +.BR PCAP_D_OUT . +.PP +This operation is not supported if a ``savefile'' is being read. +.SH RETURN VALUE +.B pcap_setdirection() +returns 0 on success and \-1 on failure. +If \-1 is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_geterr(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_setfilter.3pcap b/tcpdump/jni/libpcap/pcap_setfilter.3pcap new file mode 100644 index 0000000..c737797 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_setfilter.3pcap @@ -0,0 +1,52 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SETFILTER 3PCAP "13 May 2008" +.SH NAME +pcap_setfilter \- set the filter +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_setfilter(pcap_t *p, struct bpf_program *fp); +.ft +.fi +.SH DESCRIPTION +.B pcap_setfilter() +is used to specify a filter program. +.I fp +is a pointer to a +.I bpf_program +struct, usually the result of a call to +.BR pcap_compile() . +.SH RETURN VALUE +.B pcap_setfilter() +returns 0 on success and \-1 on failure. +If \-1 is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_compile(3PCAP), pcap_geterr(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_setnonblock.3pcap b/tcpdump/jni/libpcap/pcap_setnonblock.3pcap new file mode 100644 index 0000000..a99ea07 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_setnonblock.3pcap @@ -0,0 +1,81 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SETNONBLOCK 3PCAP "5 April 2008" +.SH NAME +pcap_setnonblock, pcap_getnonblock \- set or get the state of +non-blocking mode on a capture device +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf); +int pcap_getnonblock(pcap_t *p, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.B pcap_setnonblock() +puts a capture handle into ``non-blocking'' mode, or takes it out +of ``non-blocking'' mode, depending on whether the +.I nonblock +argument is non-zero or zero. It has no effect on ``savefiles''. +If there is an error, \-1 is returned and +.I errbuf +is filled in with an appropriate error message; otherwise, 0 is +returned. +In +``non-blocking'' mode, an attempt to read from the capture descriptor +with +.B pcap_dispatch() +will, if no packets are currently available to be read, return 0 +immediately rather than blocking waiting for packets to arrive. +.B pcap_loop() +and +.B pcap_next() +will not work in ``non-blocking'' mode. +.PP +When first activated with +.B pcap_activate() +or opened with +.B pcap_open_live() , +a capture handle is not in ``non-blocking mode''; a call to +.B pcap_setnonblock() +is required in order to put it into ``non-blocking'' mode. +.SH RETURN VALUE +.B pcap_getnonblock() +returns the current ``non-blocking'' state of the capture descriptor; it +always returns 0 on ``savefiles''. +If there is an error, \-1 is returned and +.I errbuf +is filled in with an appropriate error message. +.PP +.I errbuf +is assumed to be able to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.SH SEE ALSO +pcap(3PCAP), pcap_loop(3PCAP), pcap_next_ex(3PCAP), pcap_geterr(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_snapshot.3pcap b/tcpdump/jni/libpcap/pcap_snapshot.3pcap new file mode 100644 index 0000000..47eb42a --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_snapshot.3pcap @@ -0,0 +1,52 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SNAPSHOT 3PCAP "17 September 2013" +.SH NAME +pcap_snapshot \- get the snapshot length +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_snapshot(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_snapshot() +returns the snapshot length specified when +.B pcap_set_snapshot() +or +.B pcap_open_live() +was called, for a live capture, or the snapshot length from the capture +file, for a ``savefile''. +.PP +It must not be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +.SH RETURN VALUE +.B pcap_snapshot() +returns the snapshot length on success and +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated. +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_stats.3pcap b/tcpdump/jni/libpcap/pcap_stats.3pcap new file mode 100644 index 0000000..159054e --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_stats.3pcap @@ -0,0 +1,97 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_STATS 3PCAP "7 September 2009" +.SH NAME +pcap_stats \- get capture statistics +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_stats(pcap_t *p, struct pcap_stat *ps); +.ft +.fi +.SH DESCRIPTION +.B pcap_stats() +fills in the +.B struct pcap_stat +pointed to by its second argument. The values represent +packet statistics from the start of the run to the time of the call. +.PP +.B pcap_stats() +is supported only on live captures, not on ``savefiles''; no statistics +are stored in ``savefiles'', so no statistics are available when reading +from a ``savefile''. +.PP +A +.B struct pcap_stat +has the following members: +.RS +.TP +.B ps_recv +number of packets received; +.TP +.B ps_drop +number of packets dropped because there was no room in the operating +system's buffer when they arrived, because packets weren't being read +fast enough; +.TP +.B ps_ifdrop +number of packets dropped by the network interface or its driver. +.RE +.PP +The statistics do not behave the same way on all platforms. +.B ps_recv +might count packets whether they passed any filter set with +.BR pcap_setfilter (3PCAP) +or not, or it might count only packets that pass the filter. +It also might, or might not, count packets dropped because there was no +room in the operating system's buffer when they arrived. +.B ps_drop +is not available on all platforms; it is zero on platforms where it's +not available. If packet filtering is done in libpcap, rather than in +the operating system, it would count packets that don't pass the filter. +Both +.B ps_recv +and +.B ps_drop +might, or might not, count packets not yet read from the operating +system and thus not yet seen by the application. +.B ps_ifdrop +might, or might not, be implemented; if it's zero, that might mean that +no packets were dropped by the interface, or it might mean that the +statistic is unavailable, so it should not be treated as an indication +that the interface did not drop any packets. +.SH RETURN VALUE +.B pcap_stats() +returns 0 on success and returns \-1 if there is an error or if +.I p +doesn't support packet statistics. +If \-1 is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_geterr(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_statustostr.3pcap b/tcpdump/jni/libpcap/pcap_statustostr.3pcap new file mode 100644 index 0000000..77b8c5f --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_statustostr.3pcap @@ -0,0 +1,41 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_STATUSTOSTR 3PCAP "9 April 2008" +.SH NAME +pcap_statustostr \- convert a PCAP_ERROR_ or PCAP_WARNING_ value to a string +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_statustostr(int error); +.ft +.fi +.SH DESCRIPTION +.B pcap_statustostr() +converts a +.B PCAP_ERROR_ +or +.B PCAP_WARNING_ +value returned by a libpcap routine to an error string. +.SH SEE ALSO +pcap(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_strerror.3pcap b/tcpdump/jni/libpcap/pcap_strerror.3pcap new file mode 100644 index 0000000..7185162 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_strerror.3pcap @@ -0,0 +1,40 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_STRERROR 3PCAP "4 April 2008" +.SH NAME +pcap_strerror \- convert an errno value to a string +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_strerror(int error); +.ft +.fi +.SH DESCRIPTION +.B pcap_strerror() +is provided in case +.BR strerror (3) +isn't available. It returns an error message string corresponding to +.IR error . +.SH SEE ALSO +strerror(3) diff --git a/tcpdump/jni/libpcap/pcap_tstamp_type_name_to_val.3pcap b/tcpdump/jni/libpcap/pcap_tstamp_type_name_to_val.3pcap new file mode 100644 index 0000000..22dd15f --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_tstamp_type_name_to_val.3pcap @@ -0,0 +1,45 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_TSTAMP_TYPE_NAME_TO_VAL 3PCAP "21 August 2010" +.SH NAME +pcap_tstamp_type_name_to_val \- get the time stamp type value +corresponding to a time stamp type name +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_tstamp_type_name_to_val(const char *name); +.ft +.fi +.SH DESCRIPTION +.B pcap_tstamp_type_name_to_val() +translates a time stamp type name to the corresponding time stamp type +value. The translation is case-insensitive. +.SH RETURN VALUE +.B pcap_tstamp_type_name_to_val() +returns time stamp type value on success and +.B PCAP_ERROR +on failure. +.SH SEE ALSO +pcap(3PCAP), pcap_tstamp_type_val_to_name(3PCAP) diff --git a/tcpdump/jni/libpcap/pcap_tstamp_type_val_to_name.3pcap b/tcpdump/jni/libpcap/pcap_tstamp_type_val_to_name.3pcap new file mode 100644 index 0000000..903cea7 --- /dev/null +++ b/tcpdump/jni/libpcap/pcap_tstamp_type_val_to_name.3pcap @@ -0,0 +1,49 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_TSTAMP_TYPE_VAL_TO_NAME 3PCAP "21 August 2010" +.SH NAME +pcap_tstamp_type_val_to_name, pcap_tstamp_type_val_to_description \- get +a name or description for a time stamp type value +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_tstamp_type_val_to_name(int tstamp_type); +const char *pcap_tstamp_type_val_to_description(int tstamp_type); +.ft +.fi +.SH DESCRIPTION +.B pcap_tstamp_type_val_to_name() +translates a time stamp type value to the corresponding time stamp type +name. +.B NULL +is returned on failure. +.PP +.B pcap_tstamp_type_val_to_description() +translates a time stamp type value to a short description of that time +stamp type. +.B NULL +is returned on failure. +.SH SEE ALSO +pcap(3PCAP), pcap_tstamp_type_name_to_val(3PCAP) diff --git a/tcpdump/jni/libpcap/ppp.h b/tcpdump/jni/libpcap/ppp.h new file mode 100644 index 0000000..d6e70c1 --- /dev/null +++ b/tcpdump/jni/libpcap/ppp.h @@ -0,0 +1,57 @@ +/* + * Point to Point Protocol (PPP) RFC1331 + * + * Copyright 1989 by Carnegie Mellon. + * + * Permission to use, copy, modify, and distribute this program for any + * purpose and without fee is hereby granted, provided that this copyright + * and permission notice appear on all copies and supporting documentation, + * the name of Carnegie Mellon not be used in advertising or publicity + * pertaining to distribution of the program without specific prior + * permission, and notice be given in supporting documentation that copying + * and distribution is by permission of Carnegie Mellon and Stanford + * University. Carnegie Mellon makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ +#define PPP_ADDRESS 0xff /* The address byte value */ +#define PPP_CONTROL 0x03 /* The control byte value */ + +#define PPP_PPPD_IN 0x00 /* non-standard for DLT_PPP_PPPD */ +#define PPP_PPPD_OUT 0x01 /* non-standard for DLT_PPP_PPPD */ + +/* Protocol numbers */ +#define PPP_IP 0x0021 /* Raw IP */ +#define PPP_OSI 0x0023 /* OSI Network Layer */ +#define PPP_NS 0x0025 /* Xerox NS IDP */ +#define PPP_DECNET 0x0027 /* DECnet Phase IV */ +#define PPP_APPLE 0x0029 /* Appletalk */ +#define PPP_IPX 0x002b /* Novell IPX */ +#define PPP_VJC 0x002d /* Van Jacobson Compressed TCP/IP */ +#define PPP_VJNC 0x002f /* Van Jacobson Uncompressed TCP/IP */ +#define PPP_BRPDU 0x0031 /* Bridging PDU */ +#define PPP_STII 0x0033 /* Stream Protocol (ST-II) */ +#define PPP_VINES 0x0035 /* Banyan Vines */ +#define PPP_IPV6 0x0057 /* Internet Protocol version 6 */ + +#define PPP_HELLO 0x0201 /* 802.1d Hello Packets */ +#define PPP_LUXCOM 0x0231 /* Luxcom */ +#define PPP_SNS 0x0233 /* Sigma Network Systems */ +#define PPP_MPLS_UCAST 0x0281 /* rfc 3032 */ +#define PPP_MPLS_MCAST 0x0283 /* rfc 3022 */ + +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_OSICP 0x8023 /* OSI Network Layer Control Protocol */ +#define PPP_NSCP 0x8025 /* Xerox NS IDP Control Protocol */ +#define PPP_DECNETCP 0x8027 /* DECnet Control Protocol */ +#define PPP_APPLECP 0x8029 /* Appletalk Control Protocol */ +#define PPP_IPXCP 0x802b /* Novell IPX Control Protocol */ +#define PPP_STIICP 0x8033 /* Strean Protocol Control Protocol */ +#define PPP_VINESCP 0x8035 /* Banyan Vines Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#define PPP_MPLSCP 0x8281 /* rfc 3022 */ + +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQM 0xc025 /* Link Quality Monitoring */ +#define PPP_CHAP 0xc223 /* Challenge Handshake Authentication Protocol */ diff --git a/tcpdump/jni/libpcap/runlex.sh b/tcpdump/jni/libpcap/runlex.sh new file mode 100755 index 0000000..06b8bd4 --- /dev/null +++ b/tcpdump/jni/libpcap/runlex.sh @@ -0,0 +1,233 @@ +#! /bin/sh + +# +# runlex.sh +# Script to run Lex/Flex. +# First argument is the (quoted) name of the command; if it's null, that +# means that neither Flex nor Lex was found, so we report an error and +# quit. +# + +# +# Get the name of the command to run, and then shift to get the arguments. +# +if [ $# -eq 0 ] +then + echo "Usage: runlex [ arguments ]" 1>&2 + exit 1 +fi +LEX="$1" +shift + +# +# Check whether we have Lex or Flex. +# +if [ -z "${LEX}" ] +then + echo "Neither lex nor flex was found" 1>&2 + exit 1 +fi + +# +# Process the flags. We don't use getopt because we don't want to +# embed complete knowledge of what options are supported by Lex/Flex. +# +flags="" +outfile=lex.yy.c +while [ $# -ne 0 ] +do + case "$1" in + + -o*) + # + # Set the output file name. + # + outfile=`echo "$1" | sed 's/-o\(.*\)/\1/'` + ;; + + -*) + # + # Add this to the list of flags. + # + flags="$flags $1" + ;; + + --|*) + # + # End of flags. + # + break + ;; + esac + shift +done + +# +# Is it Lex, or is it Flex? +# +if [ "${LEX}" = flex ] +then + # + # It's Flex. + # + have_flex=yes + + # + # Does it support the --noFUNCTION options? If so, we pass + # --nounput, as at least some versions that support those + # options don't support disabling yyunput by defining + # YY_NO_UNPUT. + # + if flex --help | egrep noFUNCTION >/dev/null + then + flags="$flags --nounput" + + # + # Does it support -R, for generating reentrant scanners? + # If so, we're not currently using that feature, but + # it'll generate some unused functions anyway - and there + # won't be any header file declaring them, so there'll be + # defined-but-not-declared warnings. Therefore, we use + # --noFUNCTION options to suppress generating those + # functions. + # + if flex --help | egrep reentrant >/dev/null + then + flags="$flags --noyyget_lineno --noyyget_in --noyyget_out --noyyget_leng --noyyget_text --noyyset_lineno --noyyset_in --noyyset_out" + fi + fi +else + # + # It's Lex. + # + have_flex=no +fi + +# +# OK, run it. +# If it's lex, it doesn't support -o, so we just write to +# lex.yy.c and, if it succeeds, rename it to the right name, +# otherwise we remove lex.yy.c. +# If it's flex, it supports -o, so we use that - flex with -P doesn't +# write to lex.yy.c, it writes to a lex.{prefix from -P}.c. +# +if [ $have_flex = yes ] +then + ${LEX} $flags -o"$outfile" "$@" + + # + # Did it succeed? + # + status=$? + if [ $status -ne 0 ] + then + # + # No. Exit with the failing exit status. + # + exit $status + fi + + # + # Flex has the annoying habit of stripping all but the last + # component of the "-o" flag argument and using that as the + # place to put the output. This gets in the way of building + # in a directory different from the source directory. Try + # to work around this. + # + # Is the outfile where we think it is? + # + outfile_base=`basename "$outfile"` + if [ "$outfile_base" != "$outfile" -a \( ! -r "$outfile" \) -a -r "$outfile_base" ] + then + # + # No, it's not, but it is in the current directory. Put it + # where it's supposed to be. + # + mv "$outfile_base" "$outfile" + + # + # Did that succeed? + # + status=$? + if [ $status -ne 0 ] + then + # + # No. Exit with the failing exit status. + # + exit $status + fi + fi +else + ${LEX} $flags "$@" + + # + # Did it succeed? + # + status=$? + if [ $status -ne 0 ] + then + # + # No. Get rid of any lex.yy.c file we generated, and + # exit with the failing exit status. + # + rm -f lex.yy.c + exit $status + fi + + # + # OK, rename lex.yy.c to the right output file. + # + mv lex.yy.c "$outfile" + + # + # Did that succeed? + # + status=$? + if [ $status -ne 0 ] + then + # + # No. Get rid of any lex.yy.c file we generated, and + # exit with the failing exit status. + # + rm -f lex.yy.c + exit $status + fi +fi + +# +# OK, now let's generate a header file declaring the relevant functions +# defined by the .c file; if the .c file is .../foo.c, the header file +# will be .../foo.h. +# +# This works around some other Flex suckage, wherein it doesn't declare +# the lex routine before defining it, causing compiler warnings. +# XXX - newer versions of Flex support --header-file=, to generate the +# appropriate header file. With those versions, we should use that option. +# + +# +# Get the name of the prefix; scan the source files for a %option prefix +# line. We use the last one. +# +prefix=`sed -n 's/%option[ ][ ]*prefix="\(.*\)".*/\1/p' "$@" | tail -1` +if [ ! -z "$prefix" ] +then + prefixline="#define yylex ${prefix}lex" +fi + +# +# Construct the name of the header file. +# +header_file=`dirname "$outfile"`/`basename "$outfile" .c`.h + +# +# Spew out the declaration. +# +cat <$header_file +/* This is generated by runlex.sh. Do not edit it. */ +$prefixline +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; +EOF diff --git a/tcpdump/jni/libpcap/savefile.c b/tcpdump/jni/libpcap/savefile.c new file mode 100644 index 0000000..783ec45 --- /dev/null +++ b/tcpdump/jni/libpcap/savefile.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * savefile.c - supports offline use of tcpdump + * Extraction/creation by Jeffrey Mogul, DECWRL + * Modified by Steve McCanne, LBL. + * + * Used to save the received packet headers, after filtering, to + * a file, and then read them later. + * The first record in the file contains saved values for the machine + * dependent values so we can print the dump file on any architecture. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#endif /* WIN32 */ + +#include +#include +#include +#include +#include + +#include "pcap-int.h" +#include "pcap/usb.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#include "sf-pcap.h" +#include "sf-pcap-ng.h" + +/* + * Setting O_BINARY on DOS/Windows is a bit tricky + */ +#if defined(WIN32) + #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) +#elif defined(MSDOS) + #if defined(__HIGHC__) + #define SET_BINMODE(f) setmode(f, O_BINARY) + #else + #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) + #endif +#endif + +static int +sf_getnonblock(pcap_t *p, char *errbuf) +{ + /* + * This is a savefile, not a live capture file, so never say + * it's in non-blocking mode. + */ + return (0); +} + +static int +sf_setnonblock(pcap_t *p, int nonblock, char *errbuf) +{ + /* + * This is a savefile, not a live capture file, so reject + * requests to put it in non-blocking mode. (If it's a + * pipe, it could be put in non-blocking mode, but that + * would significantly complicate the code to read packets, + * as it would have to handle reading partial packets and + * keeping the state of the read.) + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Savefiles cannot be put into non-blocking mode"); + return (-1); +} + +static int +sf_stats(pcap_t *p, struct pcap_stat *ps) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Statistics aren't available from savefiles"); + return (-1); +} + +#ifdef WIN32 +static int +sf_setbuff(pcap_t *p, int dim) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The kernel buffer size cannot be set while reading from a file"); + return (-1); +} + +static int +sf_setmode(pcap_t *p, int mode) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "impossible to set mode while reading from a file"); + return (-1); +} + +static int +sf_setmintocopy(pcap_t *p, int size) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The mintocopy parameter cannot be set while reading from a file"); + return (-1); +} +#endif + +static int +sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) +{ + strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", + PCAP_ERRBUF_SIZE); + return (-1); +} + +/* + * Set direction flag: Which packets do we accept on a forwarding + * single device? IN, OUT or both? + */ +static int +sf_setdirection(pcap_t *p, pcap_direction_t d) +{ + snprintf(p->errbuf, sizeof(p->errbuf), + "Setting direction is not supported on savefiles"); + return (-1); +} + +void +sf_cleanup(pcap_t *p) +{ + if (p->rfile != stdin) + (void)fclose(p->rfile); + if (p->buffer != NULL) + free(p->buffer); + pcap_freecode(&p->fcode); +} + +pcap_t * +pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision, + char *errbuf) +{ + FILE *fp; + pcap_t *p; + + if (fname[0] == '-' && fname[1] == '\0') + { + fp = stdin; +#if defined(WIN32) || defined(MSDOS) + /* + * We're reading from the standard input, so put it in binary + * mode, as savefiles are binary files. + */ + SET_BINMODE(fp); +#endif + } + else { +#if !defined(WIN32) && !defined(MSDOS) + fp = fopen(fname, "r"); +#else + fp = fopen(fname, "rb"); +#endif + if (fp == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, + pcap_strerror(errno)); + return (NULL); + } + } + p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf); + if (p == NULL) { + if (fp != stdin) + fclose(fp); + } + return (p); +} + +pcap_t * +pcap_open_offline(const char *fname, char *errbuf) +{ + return (pcap_open_offline_with_tstamp_precision(fname, + PCAP_TSTAMP_PRECISION_MICRO, errbuf)); +} + +#ifdef WIN32 +pcap_t* pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision, + char *errbuf) +{ + int fd; + FILE *file; + + fd = _open_osfhandle(osfd, _O_RDONLY); + if ( fd < 0 ) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); + return NULL; + } + + file = _fdopen(fd, "rb"); + if ( file == NULL ) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); + return NULL; + } + + return pcap_fopen_offline_with_tstamp_precision(file, precision, + errbuf); +} + +pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf) +{ + return pcap_hopen_offline_with_tstamp_precision(osfd, + PCAP_TSTAMP_PRECISION_MICRO, errbuf); +} +#endif + +static pcap_t *(*check_headers[])(bpf_u_int32, FILE *, u_int, char *, int *) = { + pcap_check_header, + pcap_ng_check_header +}; + +#define N_FILE_TYPES (sizeof check_headers / sizeof check_headers[0]) + +#ifdef WIN32 +static +#endif +pcap_t * +pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision, + char *errbuf) +{ + register pcap_t *p; + bpf_u_int32 magic; + size_t amt_read; + u_int i; + int err; + + /* + * Read the first 4 bytes of the file; the network analyzer dump + * file formats we support (pcap and pcap-ng), and several other + * formats we might support in the future (such as snoop, DOS and + * Windows Sniffer, and Microsoft Network Monitor) all have magic + * numbers that are unique in their first 4 bytes. + */ + amt_read = fread((char *)&magic, 1, sizeof(magic), fp); + if (amt_read != sizeof(magic)) { + if (ferror(fp)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + } else { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %lu file header bytes, only got %lu", + (unsigned long)sizeof(magic), + (unsigned long)amt_read); + } + return (NULL); + } + + /* + * Try all file types. + */ + for (i = 0; i < N_FILE_TYPES; i++) { + p = (*check_headers[i])(magic, fp, precision, errbuf, &err); + if (p != NULL) { + /* Yup, that's it. */ + goto found; + } + if (err) { + /* + * Error trying to read the header. + */ + return (NULL); + } + } + + /* + * Well, who knows what this mess is.... + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format"); + return (NULL); + +found: + p->rfile = fp; + + /* Padding only needed for live capture fcode */ + p->fddipad = 0; + +#if !defined(WIN32) && !defined(MSDOS) + /* + * You can do "select()" and "poll()" on plain files on most + * platforms, and should be able to do so on pipes. + * + * You can't do "select()" on anything other than sockets in + * Windows, so, on Win32 systems, we don't have "selectable_fd". + */ + p->selectable_fd = fileno(fp); +#endif + + p->read_op = pcap_offline_read; + p->inject_op = sf_inject; + p->setfilter_op = install_bpf_program; + p->setdirection_op = sf_setdirection; + p->set_datalink_op = NULL; /* we don't support munging link-layer headers */ + p->getnonblock_op = sf_getnonblock; + p->setnonblock_op = sf_setnonblock; + p->stats_op = sf_stats; +#ifdef WIN32 + p->setbuff_op = sf_setbuff; + p->setmode_op = sf_setmode; + p->setmintocopy_op = sf_setmintocopy; +#endif + + /* + * For offline captures, the standard one-shot callback can + * be used for pcap_next()/pcap_next_ex(). + */ + p->oneshot_callback = pcap_oneshot; + + /* + * Savefiles never require special BPF code generation. + */ + p->bpf_codegen_flags = 0; + + p->activated = 1; + + return (p); +} + +#ifdef WIN32 +static +#endif +pcap_t * +pcap_fopen_offline(FILE *fp, char *errbuf) +{ + return (pcap_fopen_offline_with_tstamp_precision(fp, + PCAP_TSTAMP_PRECISION_MICRO, errbuf)); +} + +/* + * Read packets from a capture file, and call the callback for each + * packet. + * If cnt > 0, return after 'cnt' packets, otherwise continue until eof. + */ +int +pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct bpf_insn *fcode; + int status = 0; + int n = 0; + u_char *data; + + while (status == 0) { + struct pcap_pkthdr h; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else + return (n); + } + + status = p->next_packet_op(p, &h, &data); + if (status) { + if (status == 1) + return (0); + return (status); + } + + if ((fcode = p->fcode.bf_insns) == NULL || + bpf_filter(fcode, data, h.len, h.caplen)) { + (*callback)(user, &h, data); + if (++n >= cnt && cnt > 0) + break; + } + } + /*XXX this breaks semantics tcpslice expects */ + return (n); +} diff --git a/tcpdump/jni/libpcap/scanner.c b/tcpdump/jni/libpcap/scanner.c new file mode 100644 index 0000000..e9fc736 --- /dev/null +++ b/tcpdump/jni/libpcap/scanner.c @@ -0,0 +1,4819 @@ +#line 2 "scanner.c" + +#line 4 "scanner.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define yy_create_buffer pcap__create_buffer +#define yy_delete_buffer pcap__delete_buffer +#define yy_flex_debug pcap__flex_debug +#define yy_init_buffer pcap__init_buffer +#define yy_flush_buffer pcap__flush_buffer +#define yy_load_buffer_state pcap__load_buffer_state +#define yy_switch_to_buffer pcap__switch_to_buffer +#define yyin pcap_in +#define yyleng pcap_leng +#define yylex pcap_lex +#define yylineno pcap_lineno +#define yyout pcap_out +#define yyrestart pcap_restart +#define yytext pcap_text +#define yywrap pcap_wrap +#define yyalloc pcap_alloc +#define yyrealloc pcap_realloc +#define yyfree pcap_free + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE pcap_restart(pcap_in ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int pcap_leng; + +extern FILE *pcap_in, *pcap_out; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up pcap_text. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up pcap_text again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via pcap_restart()), so that the user can continue scanning by + * just pointing pcap_in at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when pcap_text is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int pcap_leng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow pcap_wrap()'s to do buffer switches + * instead of setting up a fresh pcap_in. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void pcap_restart (FILE *input_file ); +void pcap__switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE pcap__create_buffer (FILE *file,int size ); +void pcap__delete_buffer (YY_BUFFER_STATE b ); +void pcap__flush_buffer (YY_BUFFER_STATE b ); +void pcap_push_buffer_state (YY_BUFFER_STATE new_buffer ); +void pcap_pop_buffer_state (void ); + +static void pcap_ensure_buffer_stack (void ); +static void pcap__load_buffer_state (void ); +static void pcap__init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER pcap__flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE pcap__scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE pcap__scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE pcap__scan_bytes (yyconst char *bytes,int len ); + +void *pcap_alloc (yy_size_t ); +void *pcap_realloc (void *,yy_size_t ); +void pcap_free (void * ); + +#define yy_new_buffer pcap__create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + pcap_ensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + pcap__create_buffer(pcap_in,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + pcap_ensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + pcap__create_buffer(pcap_in,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +typedef unsigned char YY_CHAR; + +FILE *pcap_in = (FILE *) 0, *pcap_out = (FILE *) 0; + +typedef int yy_state_type; + +extern int pcap_lineno; + +int pcap_lineno = 1; + +extern char *pcap_text; +#define yytext_ptr pcap_text + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up pcap_text. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + pcap_leng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 154 +#define YY_END_OF_BUFFER 155 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[1459] = + { 0, + 0, 0, 155, 152, 112, 112, 112, 113, 152, 113, + 113, 113, 153, 122, 122, 113, 113, 113, 113, 150, + 150, 152, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 113, 152, 116, 120, 67, 0, 150, 122, + 0, 150, 150, 150, 0, 124, 118, 115, 117, 114, + 119, 150, 151, 151, 150, 150, 150, 20, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + + 7, 150, 34, 35, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 91, 150, + 68, 150, 150, 150, 150, 150, 150, 60, 150, 150, + 150, 150, 85, 150, 150, 150, 150, 150, 150, 61, + 150, 4, 150, 150, 150, 150, 150, 150, 150, 68, + 120, 150, 123, 123, 150, 122, 150, 0, 124, 122, + 124, 124, 124, 150, 150, 150, 67, 5, 150, 80, + 150, 150, 150, 150, 150, 150, 150, 55, 106, 1, + 0, 150, 21, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + + 36, 150, 150, 18, 43, 0, 150, 29, 150, 25, + 70, 150, 150, 78, 37, 150, 99, 150, 150, 150, + 150, 100, 150, 46, 69, 81, 105, 150, 14, 150, + 3, 150, 150, 150, 150, 150, 93, 150, 150, 26, + 150, 104, 150, 107, 38, 2, 150, 42, 150, 9, + 150, 10, 88, 150, 87, 150, 150, 0, 150, 150, + 123, 150, 150, 150, 150, 122, 0, 150, 0, 125, + 124, 124, 0, 124, 0, 124, 0, 124, 0, 23, + 150, 150, 150, 150, 64, 16, 41, 150, 39, 150, + 150, 150, 30, 150, 97, 150, 150, 110, 150, 150, + + 103, 109, 45, 108, 111, 11, 150, 12, 13, 150, + 150, 150, 32, 77, 150, 62, 3, 98, 47, 150, + 150, 150, 74, 150, 150, 150, 150, 48, 150, 150, + 40, 150, 6, 150, 92, 150, 8, 94, 150, 150, + 0, 150, 53, 73, 15, 150, 123, 123, 150, 123, + 123, 123, 150, 122, 150, 0, 124, 150, 0, 0, + 124, 0, 124, 125, 124, 0, 0, 0, 0, 124, + 124, 124, 124, 124, 0, 150, 56, 57, 58, 59, + 150, 22, 150, 150, 150, 150, 31, 150, 150, 101, + 102, 0, 19, 150, 150, 150, 86, 150, 33, 150, + + 79, 28, 27, 150, 150, 82, 150, 150, 150, 50, + 17, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 0, 150, 150, 123, 150, 150, 150, + 150, 123, 123, 150, 122, 150, 0, 0, 124, 124, + 124, 0, 0, 125, 124, 124, 125, 124, 0, 0, + 124, 124, 124, 124, 124, 0, 0, 0, 0, 124, + 124, 0, 124, 0, 124, 0, 96, 150, 150, 150, + 24, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 70, 150, 150, 150, 150, + 150, 150, 150, 75, 76, 150, 95, 150, 150, 150, + + 150, 150, 150, 150, 150, 150, 150, 150, 150, 123, + 123, 150, 123, 123, 123, 123, 150, 122, 150, 0, + 124, 124, 0, 124, 0, 0, 124, 0, 124, 125, + 124, 0, 0, 0, 124, 124, 0, 124, 125, 124, + 0, 0, 0, 0, 0, 0, 0, 124, 124, 124, + 124, 124, 0, 150, 150, 150, 150, 52, 63, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 71, 150, 150, 44, 83, 84, 150, 150, 150, + 150, 54, 148, 144, 150, 146, 145, 149, 150, 0, + 150, 150, 123, 150, 150, 150, 123, 150, 122, 150, + + 0, 0, 124, 124, 124, 124, 124, 124, 0, 0, + 125, 124, 124, 124, 0, 0, 124, 124, 124, 124, + 124, 0, 0, 0, 0, 0, 0, 0, 124, 124, + 124, 124, 124, 0, 0, 0, 0, 0, 124, 124, + 0, 124, 0, 124, 0, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 127, 126, + 150, 150, 72, 150, 150, 150, 147, 143, 150, 150, + 123, 123, 123, 123, 150, 122, 150, 0, 124, 124, + 0, 124, 124, 0, 124, 0, 0, 124, 0, 124, + 125, 124, 0, 0, 0, 124, 124, 0, 124, 125, + + 124, 0, 0, 0, 0, 0, 124, 124, 0, 124, + 125, 124, 0, 124, 124, 0, 0, 0, 0, 0, + 0, 0, 124, 124, 124, 124, 124, 0, 65, 150, + 55, 132, 139, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 66, 49, 150, 150, 0, 150, 150, 150, + 150, 150, 122, 150, 0, 0, 124, 124, 124, 124, + 124, 124, 124, 124, 124, 0, 0, 125, 124, 124, + 124, 0, 0, 124, 124, 124, 124, 124, 0, 0, + 0, 0, 0, 0, 0, 124, 124, 124, 124, 124, + 0, 124, 124, 0, 0, 0, 0, 0, 0, 0, + + 124, 124, 124, 124, 124, 0, 0, 0, 0, 0, + 0, 124, 124, 0, 124, 0, 124, 0, 89, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 51, 121, 121, 123, 123, 150, 122, 150, 0, 124, + 124, 0, 124, 124, 0, 124, 124, 0, 124, 0, + 121, 124, 0, 124, 125, 124, 0, 0, 0, 124, + 124, 0, 124, 125, 124, 0, 0, 0, 0, 0, + 124, 124, 0, 124, 125, 124, 0, 0, 0, 0, + 0, 0, 124, 124, 0, 124, 125, 124, 0, 124, + 124, 124, 0, 0, 0, 0, 0, 0, 0, 124, + + 124, 124, 124, 124, 0, 150, 150, 150, 150, 150, + 150, 150, 150, 137, 150, 90, 121, 121, 123, 150, + 121, 121, 0, 0, 124, 124, 124, 124, 124, 124, + 124, 124, 124, 124, 124, 124, 0, 121, 125, 124, + 124, 124, 0, 0, 124, 124, 124, 124, 124, 0, + 0, 0, 0, 0, 0, 0, 124, 124, 124, 124, + 124, 0, 124, 124, 0, 0, 0, 0, 0, 0, + 0, 124, 124, 124, 124, 124, 0, 124, 124, 124, + 0, 0, 0, 0, 0, 0, 0, 124, 124, 124, + 124, 124, 0, 0, 0, 0, 0, 0, 124, 124, + + 0, 124, 0, 124, 0, 150, 150, 150, 141, 150, + 150, 150, 150, 150, 150, 150, 129, 123, 150, 122, + 0, 124, 124, 0, 124, 124, 0, 124, 124, 0, + 124, 124, 0, 124, 0, 0, 0, 124, 0, 0, + 124, 125, 124, 0, 0, 0, 124, 124, 0, 124, + 125, 124, 0, 0, 0, 0, 0, 124, 124, 0, + 124, 125, 124, 0, 0, 0, 0, 0, 0, 124, + 124, 0, 124, 125, 124, 0, 0, 0, 0, 0, + 0, 124, 124, 0, 124, 125, 124, 0, 124, 124, + 124, 0, 0, 0, 0, 0, 0, 0, 124, 124, + + 124, 124, 124, 0, 150, 150, 150, 150, 131, 150, + 150, 150, 135, 150, 121, 0, 0, 124, 124, 124, + 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, + 124, 124, 0, 0, 0, 125, 0, 0, 124, 0, + 0, 124, 124, 124, 0, 0, 0, 0, 0, 0, + 0, 124, 124, 124, 0, 124, 124, 0, 0, 0, + 0, 0, 0, 0, 124, 124, 124, 0, 124, 124, + 124, 0, 0, 0, 0, 0, 0, 0, 124, 124, + 124, 0, 124, 124, 124, 0, 0, 0, 0, 0, + 0, 0, 124, 124, 124, 0, 0, 0, 0, 0, + + 0, 124, 124, 0, 124, 0, 124, 0, 128, 140, + 142, 136, 150, 150, 150, 150, 0, 0, 124, 0, + 124, 0, 124, 124, 0, 124, 124, 0, 124, 124, + 0, 124, 124, 0, 124, 0, 0, 0, 0, 124, + 124, 0, 124, 0, 0, 124, 124, 124, 0, 0, + 0, 0, 124, 124, 124, 0, 0, 0, 0, 0, + 124, 124, 124, 0, 0, 0, 0, 0, 124, 124, + 124, 0, 0, 0, 0, 0, 124, 124, 124, 124, + 124, 124, 0, 0, 0, 0, 0, 0, 0, 124, + 124, 124, 0, 150, 150, 150, 150, 0, 0, 0, + + 124, 124, 124, 124, 124, 124, 0, 0, 0, 0, + 124, 124, 0, 0, 0, 0, 124, 124, 124, 0, + 0, 0, 0, 0, 124, 124, 124, 124, 0, 0, + 0, 0, 0, 124, 124, 124, 124, 0, 0, 0, + 0, 0, 124, 124, 124, 124, 0, 0, 0, 0, + 0, 124, 0, 0, 0, 0, 0, 124, 124, 124, + 150, 150, 150, 138, 124, 124, 124, 124, 124, 124, + 124, 124, 0, 0, 0, 0, 124, 124, 0, 0, + 124, 0, 0, 0, 124, 0, 0, 0, 124, 0, + 0, 0, 124, 0, 0, 0, 124, 124, 124, 124, + + 0, 0, 0, 0, 0, 124, 133, 150, 130, 124, + 0, 0, 124, 124, 0, 124, 124, 124, 0, 124, + 124, 124, 0, 124, 124, 124, 0, 124, 124, 124, + 0, 0, 0, 0, 124, 134, 124, 124, 0, 0, + 0, 0, 0, 0, 124, 124, 124, 0, 0, 124, + 124, 124, 124, 124, 0, 124, 124, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 5, 1, 1, 6, 1, 7, 1, 8, + 8, 9, 9, 1, 10, 11, 9, 12, 13, 14, + 15, 16, 17, 18, 17, 17, 17, 19, 1, 20, + 21, 22, 1, 1, 23, 23, 23, 23, 23, 23, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 25, 24, 24, + 26, 27, 26, 1, 28, 1, 29, 30, 31, 32, + + 33, 34, 35, 36, 37, 24, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 24, 1, 53, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[54] = + { 0, + 1, 2, 2, 1, 2, 1, 3, 2, 1, 4, + 5, 6, 6, 6, 6, 6, 6, 6, 7, 3, + 3, 3, 8, 4, 9, 3, 1, 4, 8, 8, + 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 9, 4, 3 + } ; + +static yyconst flex_int16_t yy_base[1919] = + { 0, + 0, 0, 3907, 53, 7401, 7401, 54, 3884, 60, 3897, + 7401, 82, 7401, 100, 31, 152, 47, 3882, 49, 169, + 211, 169, 61, 44, 126, 61, 30, 63, 76, 158, + 215, 218, 160, 32, 166, 117, 230, 236, 208, 3855, + 174, 3847, 3832, 281, 7401, 0, 7401, 297, 320, 344, + 3865, 368, 0, 375, 0, 409, 7401, 7401, 7401, 7401, + 7401, 279, 297, 0, 3838, 3834, 3848, 0, 3847, 3821, + 3834, 3831, 3819, 3813, 3813, 3816, 3815, 3799, 3808, 3793, + 3806, 3789, 225, 3798, 3801, 3786, 3770, 3783, 3772, 3777, + 3767, 3765, 121, 83, 3770, 3768, 129, 3757, 3752, 3761, + + 148, 228, 0, 0, 37, 169, 3749, 3758, 226, 3741, + 3739, 3742, 3731, 3721, 3729, 3720, 3719, 3724, 0, 3732, + 0, 3715, 3706, 3700, 3701, 3701, 3701, 234, 3710, 3693, + 3690, 3683, 56, 3679, 243, 3677, 160, 3676, 3687, 0, + 3673, 0, 3672, 3656, 3661, 3668, 3659, 3649, 3663, 7401, + 7401, 434, 458, 274, 499, 523, 547, 3657, 554, 3664, + 578, 293, 3655, 3630, 3635, 3625, 0, 0, 3630, 0, + 3639, 3619, 3608, 3607, 3608, 3604, 3604, 3596, 0, 0, + 3591, 3581, 0, 3593, 3588, 3575, 3589, 3592, 3574, 3558, + 3557, 3554, 3569, 3552, 3556, 3536, 3538, 3551, 3536, 3535, + + 0, 3539, 3533, 0, 0, 3537, 3527, 0, 3518, 0, + 3515, 3502, 3509, 0, 0, 3497, 0, 3506, 3514, 272, + 3496, 0, 3480, 3496, 0, 3491, 0, 3494, 0, 3474, + 3478, 3472, 3475, 3471, 3444, 3440, 0, 3438, 3450, 0, + 3438, 0, 3437, 0, 0, 0, 3434, 0, 171, 202, + 3445, 0, 0, 3421, 0, 3418, 3419, 618, 3449, 641, + 665, 3446, 672, 481, 115, 696, 3437, 720, 3436, 3435, + 728, 294, 3420, 3419, 488, 769, 792, 3417, 0, 0, + 3392, 381, 3395, 3399, 0, 0, 0, 3382, 0, 3381, + 3382, 3366, 0, 3364, 0, 3358, 3360, 0, 3343, 3342, + + 0, 0, 0, 0, 0, 595, 3349, 0, 0, 3355, + 3325, 3324, 0, 0, 3313, 0, 0, 0, 0, 3328, + 3311, 3318, 0, 3310, 3294, 3310, 3283, 3279, 3290, 3279, + 0, 3278, 0, 3264, 0, 261, 0, 0, 3247, 3241, + 720, 3247, 0, 0, 0, 817, 841, 296, 882, 3274, + 3273, 405, 905, 929, 953, 3242, 960, 602, 3241, 3240, + 983, 757, 1007, 1030, 3239, 0, 3236, 408, 409, 1054, + 3235, 1078, 297, 3224, 3210, 3179, 0, 0, 0, 0, + 3173, 0, 3183, 3182, 3150, 3148, 0, 3165, 3160, 0, + 0, 1097, 0, 3148, 3126, 3140, 0, 3131, 0, 3135, + + 3112, 0, 0, 3121, 3101, 366, 3089, 3104, 371, 3101, + 0, 3090, 3060, 3063, 3053, 3048, 3059, 3052, 3038, 3039, + 3032, 3038, 3053, 1134, 3062, 1157, 1181, 3059, 1188, 864, + 165, 1212, 314, 1252, 1275, 1299, 3047, 3036, 1307, 315, + 3014, 3013, 3012, 3010, 1348, 317, 3008, 3007, 496, 612, + 1389, 3006, 1413, 321, 2981, 2988, 2979, 871, 0, 352, + 2978, 1101, 1454, 1477, 2976, 0, 0, 2948, 2964, 2930, + 0, 2939, 2923, 2928, 2940, 2925, 2940, 2939, 369, 2911, + 408, 2911, 2916, 2904, 2914, 0, 2904, 2901, 2892, 2896, + 2892, 2881, 2848, 0, 0, 2852, 0, 2847, 2838, 2850, + + 2849, 2843, 2824, 2818, 2816, 2821, 2826, 2824, 1502, 1526, + 404, 1567, 2847, 2846, 614, 1591, 1615, 1622, 1646, 2822, + 1653, 1677, 1700, 2821, 2820, 2819, 1723, 1108, 1747, 1770, + 2818, 0, 1235, 0, 442, 2816, 1242, 1794, 1817, 2815, + 0, 739, 766, 2822, 466, 786, 817, 1841, 2799, 1865, + 433, 2798, 2805, 510, 2769, 2774, 2770, 0, 0, 2775, + 2777, 2748, 2748, 2760, 2743, 2742, 2748, 2740, 2741, 2738, + 2737, 0, 2728, 2722, 0, 0, 0, 2735, 2730, 2735, + 2722, 0, 0, 0, 2711, 0, 0, 0, 2700, 1905, + 2735, 1928, 1952, 2733, 1959, 358, 1983, 2007, 2014, 2038, + + 2724, 2722, 2046, 457, 2721, 2087, 493, 2720, 2705, 2704, + 2703, 2128, 494, 2702, 879, 899, 2169, 2701, 2193, 523, + 2699, 2706, 1128, 1130, 2705, 2689, 1251, 1317, 2234, 2680, + 2258, 524, 2679, 2686, 1331, 0, 1338, 0, 467, 2677, + 1371, 2299, 2322, 2674, 0, 2345, 354, 390, 534, 535, + 622, 276, 591, 2645, 241, 551, 433, 1129, 2630, 2629, + 1247, 2628, 2627, 1343, 854, 503, 2626, 2624, 2383, 2420, + 2456, 2492, 553, 2516, 650, 2524, 2548, 2651, 2555, 2579, + 2602, 2650, 2626, 2649, 2634, 2633, 2632, 2672, 1379, 2696, + 2719, 2631, 0, 1436, 0, 680, 2629, 1443, 2743, 2766, + + 2627, 0, 1549, 0, 1556, 0, 681, 2611, 1888, 2790, + 2813, 2610, 0, 555, 1895, 2617, 1451, 1471, 2616, 2615, + 1502, 1564, 2837, 2605, 2861, 615, 2604, 2611, 617, 688, + 634, 768, 1251, 1388, 2056, 1453, 808, 834, 898, 2083, + 766, 923, 810, 833, 2081, 2085, 2903, 835, 2926, 921, + 2949, 2114, 2973, 2997, 2587, 2586, 3005, 642, 2585, 3046, + 643, 2584, 3087, 671, 2582, 2581, 2580, 2564, 3128, 742, + 2563, 1694, 1904, 3169, 2562, 3193, 902, 2561, 2568, 2056, + 2057, 2566, 2565, 2063, 2123, 3234, 2556, 3258, 930, 2555, + 2541, 931, 2151, 2540, 2124, 2125, 2539, 2538, 2145, 2166, + + 3299, 2529, 3323, 954, 2527, 2534, 0, 2216, 0, 2223, + 0, 737, 2525, 2281, 3364, 3387, 2524, 0, 897, 975, + 976, 1000, 1904, 1001, 1566, 1022, 1046, 2276, 1047, 2105, + 1048, 3412, 3435, 3459, 1029, 3499, 3523, 3547, 2501, 3554, + 3578, 3601, 2500, 3625, 3648, 2499, 3672, 3695, 2498, 2497, + 2495, 3718, 2368, 3742, 3765, 2494, 0, 2406, 0, 969, + 2493, 2443, 3789, 3812, 2492, 0, 2463, 0, 2470, 0, + 1016, 2445, 2477, 3836, 3859, 2443, 0, 0, 2484, 0, + 2884, 0, 1087, 2429, 2891, 3883, 3906, 2428, 0, 0, + 1077, 3028, 2434, 2231, 2295, 2431, 2397, 2296, 2316, 3930, + + 2375, 3954, 1080, 2347, 2354, 2359, 2360, 2361, 2127, 1128, + 2233, 2298, 1071, 2362, 1203, 1072, 1126, 1150, 3996, 4020, + 4029, 1204, 2345, 2331, 4047, 1107, 2330, 4088, 1110, 2329, + 4129, 1157, 2325, 4170, 1158, 2324, 2306, 2305, 4210, 4234, + 1159, 2286, 2414, 2415, 4275, 2283, 4299, 1182, 2282, 2289, + 2596, 2643, 2273, 2269, 2899, 2900, 4340, 2259, 4364, 1187, + 2241, 2248, 1246, 3035, 2247, 2903, 3043, 2244, 2243, 3056, + 3062, 4405, 2202, 4429, 1248, 2201, 2208, 0, 1249, 3110, + 2204, 3063, 3084, 2203, 2183, 3104, 3123, 4470, 2174, 4494, + 1252, 2171, 2167, 0, 3151, 0, 3216, 0, 1166, 2154, + + 3223, 4535, 4558, 2135, 0, 3268, 3269, 3333, 1206, 2399, + 2363, 1407, 3252, 2275, 1469, 1493, 1347, 4583, 4607, 4616, + 2105, 4633, 4657, 4680, 2075, 4704, 4727, 2073, 4751, 4774, + 2070, 4798, 4821, 2068, 2067, 4845, 1276, 2066, 2064, 3286, + 4886, 2054, 2051, 0, 3350, 0, 1535, 2023, 3482, 4910, + 2021, 2020, 0, 3489, 0, 3977, 0, 1576, 2019, 3984, + 4934, 2017, 2016, 0, 0, 4036, 0, 4070, 0, 1599, + 2015, 4077, 4958, 1991, 1989, 0, 0, 4111, 0, 4118, + 0, 1630, 1986, 4152, 4982, 1985, 1911, 0, 0, 1386, + 4159, 1876, 3125, 3145, 1857, 1832, 3164, 3166, 5006, 1819, + + 5030, 1389, 1803, 1807, 1495, 1669, 1670, 1520, 1671, 1741, + 4168, 1692, 1716, 2401, 5072, 1776, 5089, 5113, 1390, 1775, + 5154, 1453, 1753, 5195, 1561, 1752, 5236, 1566, 1730, 5277, + 1568, 1729, 1728, 4196, 5318, 1724, 1709, 0, 1708, 3231, + 3294, 5342, 1705, 1631, 1633, 3333, 3360, 1632, 1602, 3381, + 3412, 5366, 1573, 1569, 1541, 1591, 4257, 1534, 3498, 3595, + 1518, 1517, 3642, 3689, 5390, 1505, 1480, 1469, 0, 1621, + 4264, 1464, 4180, 4181, 1463, 1423, 4205, 4209, 5414, 1394, + 1391, 1398, 0, 1622, 4322, 1363, 4272, 4316, 1361, 1359, + 4335, 4337, 5438, 1350, 1316, 1323, 0, 4387, 0, 4394, + + 0, 1756, 1314, 4452, 5462, 0, 1312, 0, 1740, 1763, + 1764, 1786, 1787, 1974, 4488, 4504, 5486, 1623, 0, 1310, + 5527, 0, 1276, 5551, 0, 1259, 5575, 0, 1253, 5599, + 0, 1221, 5623, 0, 1217, 4402, 4446, 5647, 1196, 1114, + 1108, 88, 138, 4460, 0, 1826, 214, 229, 4521, 0, + 4623, 0, 1850, 322, 345, 0, 4868, 0, 4875, 0, + 1874, 416, 460, 0, 5053, 0, 5060, 0, 1914, 501, + 508, 0, 5079, 0, 5136, 0, 1937, 524, 580, 0, + 1650, 5143, 589, 4531, 4552, 610, 611, 4632, 4674, 5671, + 605, 0, 632, 2418, 1788, 1811, 1834, 5695, 627, 696, + + 0, 0, 0, 0, 0, 0, 5177, 0, 1967, 698, + 699, 0, 4721, 4768, 709, 710, 0, 1652, 5184, 713, + 4815, 4883, 741, 744, 0, 0, 1653, 5218, 778, 5088, + 5192, 801, 803, 0, 0, 1816, 5259, 805, 5212, 5231, + 808, 828, 0, 0, 1838, 5300, 849, 5233, 5253, 856, + 858, 0, 0, 5307, 0, 5509, 0, 1968, 883, 0, + 3083, 2964, 2161, 1921, 0, 7401, 0, 0, 0, 0, + 0, 0, 5315, 5503, 892, 895, 0, 7401, 5517, 0, + 7401, 0, 5718, 0, 7401, 0, 5725, 0, 7401, 0, + 5732, 0, 7401, 0, 5739, 0, 7401, 0, 1840, 5746, + + 898, 5754, 5755, 937, 2022, 0, 1975, 3341, 2062, 0, + 5755, 0, 1841, 5769, 946, 0, 1899, 5776, 973, 0, + 1901, 5783, 976, 0, 1902, 5795, 996, 0, 1929, 5802, + 1020, 0, 5809, 0, 7401, 2185, 1956, 5816, 1040, 0, + 0, 0, 0, 0, 0, 1958, 5823, 1041, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7401, 5841, 5849, + 5853, 5856, 5859, 5862, 5865, 5868, 5871, 5874, 5877, 5880, + 5883, 5886, 5889, 5892, 5895, 5898, 5901, 5905, 5909, 5912, + 5915, 5918, 5921, 5924, 5927, 5930, 5933, 5937, 5941, 5944, + 5947, 5951, 5953, 5956, 5959, 5962, 5965, 5968, 5971, 5974, + + 5977, 5981, 5983, 5986, 5990, 5995, 5999, 6002, 6006, 6009, + 6012, 6015, 6018, 6021, 6024, 6027, 6031, 6035, 6038, 6042, + 6046, 6051, 6055, 6057, 6061, 6064, 6068, 6071, 6074, 6078, + 6080, 6083, 6086, 6089, 6092, 6095, 6098, 6101, 6104, 6107, + 6111, 6113, 6116, 6119, 6122, 6126, 6128, 6131, 6134, 6139, + 6143, 6148, 6152, 6154, 6158, 6161, 6165, 6170, 6174, 6177, + 6180, 6183, 6186, 6189, 6192, 6195, 6199, 6203, 6206, 6210, + 6214, 6219, 6223, 6225, 6229, 6232, 6236, 6239, 6244, 6248, + 6253, 6257, 6259, 6263, 6266, 6270, 6273, 6276, 6279, 6283, + 6285, 6288, 6293, 6297, 6300, 6303, 6306, 6309, 6312, 6315, + + 6318, 6321, 6325, 6327, 6330, 6333, 6336, 6340, 6342, 6345, + 6348, 6351, 6354, 6358, 6360, 6363, 6366, 6369, 6374, 6378, + 6383, 6387, 6389, 6393, 6396, 6400, 6405, 6409, 6412, 6415, + 6418, 6421, 6424, 6427, 6430, 6434, 6438, 6441, 6445, 6449, + 6454, 6458, 6460, 6464, 6467, 6471, 6474, 6479, 6483, 6488, + 6492, 6494, 6498, 6501, 6505, 6508, 6511, 6516, 6520, 6525, + 6529, 6531, 6535, 6538, 6542, 6545, 6548, 6551, 6555, 6557, + 6560, 6565, 6569, 6572, 6575, 6578, 6581, 6584, 6587, 6590, + 6593, 6596, 6599, 6602, 6606, 6608, 6611, 6614, 6617, 6620, + 6624, 6626, 6629, 6632, 6635, 6638, 6641, 6645, 6647, 6650, + + 6653, 6656, 6659, 6662, 6666, 6668, 6671, 6674, 6677, 6680, + 6685, 6689, 6694, 6698, 6700, 6704, 6707, 6711, 6716, 6720, + 6723, 6726, 6729, 6732, 6735, 6738, 6741, 6744, 6747, 6751, + 6755, 6758, 6762, 6766, 6771, 6775, 6777, 6781, 6784, 6788, + 6791, 6796, 6800, 6805, 6809, 6811, 6815, 6818, 6822, 6825, + 6828, 6833, 6837, 6842, 6846, 6848, 6852, 6855, 6859, 6862, + 6865, 6870, 6874, 6879, 6883, 6885, 6889, 6892, 6896, 6899, + 6902, 6905, 6909, 6911, 6914, 6917, 6922, 6926, 6929, 6932, + 6935, 6938, 6941, 6944, 6947, 6950, 6953, 6956, 6959, 6963, + 6967, 6970, 6973, 6977, 6980, 6983, 6987, 6989, 6992, 6995, + + 6999, 7001, 7004, 7007, 7010, 7014, 7016, 7019, 7022, 7025, + 7029, 7031, 7034, 7037, 7040, 7044, 7046, 7049, 7052, 7057, + 7061, 7066, 7070, 7072, 7076, 7079, 7083, 7088, 7092, 7095, + 7098, 7101, 7104, 7107, 7110, 7113, 7116, 7120, 7122, 7125, + 7129, 7134, 7138, 7139, 7142, 7147, 7151, 7156, 7160, 7161, + 7164, 7167, 7172, 7176, 7181, 7185, 7186, 7189, 7192, 7197, + 7201, 7206, 7210, 7211, 7214, 7217, 7222, 7226, 7231, 7235, + 7236, 7239, 7242, 7245, 7249, 7251, 7256, 7260, 7263, 7266, + 7269, 7272, 7275, 7278, 7282, 7287, 7291, 7292, 7295, 7298, + 7301, 7304, 7307, 7310, 7313, 7316, 7319, 7322, 7327, 7331, + + 7334, 7337, 7340, 7344, 7348, 7352, 7356, 7360, 7363, 7366, + 7370, 7373, 7376, 7379, 7382, 7385, 7389, 7392 + } ; + +static yyconst flex_int16_t yy_def[1919] = + { 0, + 1458, 1, 1458, 1458, 1458, 1458, 1458, 1458, 1459, 1458, + 1458, 1458, 1458, 1458, 14, 1458, 1458, 1458, 1458, 14, + 20, 1460, 20, 20, 20, 20, 20, 20, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 1458, 1458, 1458, 1461, 1458, 21, 21, 20, + 1462, 50, 21, 21, 21, 1458, 1458, 1458, 1458, 1458, + 1458, 49, 1460, 1460, 52, 52, 52, 21, 21, 21, + 21, 52, 21, 21, 52, 21, 21, 21, 52, 21, + 21, 21, 21, 21, 52, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 1458, + 1458, 21, 21, 153, 21, 21, 156, 1463, 1458, 54, + 1458, 161, 1464, 21, 21, 157, 21, 21, 21, 157, + 21, 21, 21, 21, 21, 21, 157, 21, 21, 21, + 21, 21, 21, 21, 157, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 260, 261, 157, 1465, 266, 1466, 1467, + 1458, 271, 1468, 1469, 1458, 1458, 1458, 1470, 1471, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 347, 21, 261, + 263, 261, 263, 263, 354, 1472, 1458, 353, 1473, 1474, + 1458, 1458, 1458, 1458, 1475, 1476, 1477, 1478, 1478, 1458, + 1479, 1458, 372, 1480, 1471, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 426, + 427, 427, 432, 426, 354, 435, 1481, 1482, 1458, 439, + 1483, 1458, 1484, 1485, 1458, 445, 1486, 1487, 1488, 1488, + 1458, 1489, 1458, 453, 1490, 1476, 1458, 1458, 1491, 1492, + 1458, 1458, 1458, 1458, 1493, 1494, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 510, 21, 427, 429, 427, 427, 516, 435, 518, 1495, + 1458, 1458, 1458, 1496, 1497, 1498, 1458, 1458, 1458, 1458, + 1499, 1500, 1458, 1501, 1502, 1458, 1458, 1458, 1458, 1503, + 1504, 1505, 1505, 1491, 1492, 1506, 1506, 1458, 1507, 1458, + 550, 1508, 1509, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 593, 593, 597, 518, 599, + + 1510, 1511, 1458, 603, 1512, 1458, 606, 1513, 1458, 1514, + 1515, 1458, 612, 1516, 1517, 1517, 1458, 1518, 1458, 619, + 1519, 1520, 1521, 1521, 1522, 1523, 1524, 1524, 1458, 1525, + 1458, 631, 1526, 1527, 1458, 1528, 1458, 1529, 1530, 1458, + 1458, 1458, 1458, 1531, 1532, 600, 646, 646, 646, 646, + 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, + 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, + 646, 671, 671, 671, 646, 671, 676, 1533, 1458, 1458, + 1458, 1534, 1458, 1458, 1535, 1536, 1537, 1458, 1458, 1458, + 1458, 1538, 1539, 1458, 1540, 1541, 1458, 1458, 1458, 1458, + + 1542, 1543, 1458, 1544, 1458, 1545, 1546, 1458, 1458, 1458, + 1458, 1547, 1548, 1549, 1458, 1550, 1551, 1551, 1552, 1553, + 1554, 1554, 1458, 1555, 1458, 725, 1556, 1557, 1558, 1558, + 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, + 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, 747, 1558, + 747, 751, 751, 753, 1559, 1560, 1458, 757, 1561, 1458, + 760, 1562, 1458, 763, 1563, 1458, 1564, 1565, 1458, 769, + 1566, 1567, 1567, 1458, 1568, 1458, 776, 1569, 1570, 1571, + 1571, 1572, 1573, 1574, 1574, 1458, 1575, 1458, 788, 1576, + 1577, 1578, 1458, 1579, 1580, 1580, 1581, 1582, 1583, 1583, + + 1458, 1584, 1458, 803, 1585, 1586, 1587, 1458, 1588, 1458, + 1589, 1590, 1458, 1458, 1458, 1458, 1591, 1592, 1593, 1593, + 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, + 1593, 1593, 832, 832, 834, 832, 832, 837, 1594, 1458, + 1458, 1458, 1595, 1458, 1458, 1596, 1458, 1458, 1597, 1598, + 1599, 1458, 1458, 1458, 1458, 1600, 1601, 1458, 1602, 1603, + 1458, 1458, 1458, 1458, 1604, 1605, 1458, 1606, 1458, 1607, + 1608, 1458, 1458, 1458, 1458, 1609, 1610, 1611, 1458, 1612, + 1458, 1613, 1614, 1458, 1458, 1458, 1458, 1615, 1616, 1617, + 1618, 1458, 1619, 1620, 1620, 1621, 1622, 1623, 1623, 1458, + + 1624, 1458, 902, 1625, 1626, 1627, 1627, 1627, 1627, 1627, + 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 919, + 1627, 1627, 1628, 1629, 1458, 925, 1630, 1458, 928, 1631, + 1458, 931, 1632, 1458, 934, 1633, 1458, 1634, 1458, 1458, + 940, 1635, 1636, 1636, 1458, 1637, 1458, 947, 1638, 1639, + 1640, 1640, 1641, 1642, 1643, 1643, 1458, 1644, 1458, 959, + 1645, 1646, 1647, 1458, 1648, 1649, 1649, 1650, 1651, 1652, + 1652, 1458, 1653, 1458, 974, 1654, 1655, 1656, 1657, 1458, + 1658, 1659, 1659, 1660, 1661, 1662, 1662, 1458, 1663, 1458, + 990, 1664, 1665, 1666, 1458, 1667, 1458, 1668, 1669, 1458, + + 1458, 1458, 1458, 1670, 1671, 1672, 1672, 1672, 1672, 1672, + 1672, 1672, 1672, 1672, 1672, 1672, 1672, 1672, 1018, 1672, + 1673, 1458, 1458, 1458, 1674, 1458, 1458, 1675, 1458, 1458, + 1676, 1458, 1458, 1677, 1678, 1458, 1036, 1679, 1680, 1458, + 1458, 1681, 1682, 1683, 1458, 1684, 1685, 1458, 1458, 1458, + 1686, 1687, 1688, 1458, 1689, 1458, 1690, 1691, 1458, 1458, + 1458, 1692, 1693, 1694, 1695, 1458, 1696, 1458, 1697, 1698, + 1458, 1458, 1458, 1699, 1700, 1701, 1702, 1458, 1703, 1458, + 1704, 1705, 1458, 1458, 1458, 1706, 1707, 1708, 1709, 1710, + 1458, 1711, 1712, 1712, 1713, 1714, 1715, 1715, 1458, 1716, + + 1458, 1101, 1717, 1718, 1719, 1719, 1719, 1719, 1719, 1719, + 1719, 1719, 1719, 1719, 1719, 1720, 1458, 1458, 1118, 1721, + 1458, 1121, 1722, 1458, 1124, 1723, 1458, 1127, 1724, 1458, + 1130, 1725, 1458, 1458, 1458, 1726, 1727, 1728, 1729, 1730, + 1730, 1458, 1731, 1732, 1733, 1734, 1734, 1735, 1736, 1737, + 1737, 1458, 1738, 1739, 1740, 1741, 1458, 1742, 1743, 1743, + 1744, 1745, 1746, 1746, 1458, 1747, 1748, 1749, 1750, 1751, + 1458, 1752, 1753, 1753, 1754, 1755, 1756, 1756, 1458, 1757, + 1758, 1759, 1760, 1761, 1458, 1762, 1763, 1763, 1764, 1765, + 1766, 1766, 1458, 1767, 1768, 1769, 1770, 1458, 1771, 1458, + + 1772, 1773, 1458, 1458, 1458, 1774, 1775, 1776, 1777, 1777, + 1777, 1777, 1777, 1777, 1777, 1777, 1458, 1217, 1778, 1779, + 1458, 1780, 1781, 1458, 1782, 1783, 1458, 1784, 1785, 1458, + 1786, 1787, 1458, 1788, 1789, 1790, 1790, 1458, 1791, 1792, + 1793, 1794, 1795, 1458, 1796, 1797, 1458, 1798, 1458, 1799, + 1458, 1800, 1801, 1458, 1802, 1803, 1458, 1804, 1458, 1805, + 1806, 1458, 1807, 1808, 1458, 1809, 1458, 1810, 1811, 1458, + 1812, 1813, 1458, 1814, 1458, 1815, 1816, 1458, 1817, 1818, + 1819, 1458, 1820, 1821, 1821, 1822, 1823, 1824, 1824, 1458, + 1825, 1826, 1827, 1828, 1828, 1828, 1828, 1458, 1829, 1830, + + 1831, 1832, 1833, 1834, 1835, 1836, 1458, 1837, 1838, 1458, + 1839, 1840, 1841, 1841, 1842, 1843, 1844, 1845, 1458, 1846, + 1847, 1847, 1848, 1849, 1850, 1851, 1852, 1458, 1853, 1854, + 1854, 1855, 1856, 1857, 1858, 1859, 1458, 1860, 1861, 1861, + 1862, 1863, 1864, 1865, 1866, 1458, 1867, 1868, 1868, 1869, + 1870, 1871, 1872, 1458, 1873, 1458, 1874, 1875, 1458, 1876, + 1877, 1877, 1877, 1877, 1878, 1458, 1879, 1880, 1881, 1882, + 1883, 1884, 1885, 1885, 1886, 1887, 1888, 1458, 1458, 1889, + 1458, 1890, 1458, 1891, 1458, 1892, 1458, 1893, 1458, 1894, + 1458, 1895, 1458, 1896, 1458, 1897, 1458, 1872, 1898, 1458, + + 1873, 1899, 1899, 1874, 1875, 1900, 1877, 1877, 1877, 1901, + 1458, 1902, 1903, 1458, 1889, 1890, 1904, 1458, 1891, 1892, + 1905, 1458, 1893, 1894, 1906, 1458, 1895, 1896, 1907, 1458, + 1897, 1908, 1458, 1909, 1458, 1877, 1910, 1458, 1902, 1911, + 1912, 1913, 1914, 1915, 1908, 1916, 1458, 1909, 1917, 1911, + 1912, 1913, 1914, 1915, 1918, 1917, 1918, 0, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458 + } ; + +static yyconst flex_int16_t yy_nxt[7455] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 11, + 13, 14, 15, 15, 15, 15, 15, 15, 16, 17, + 18, 19, 20, 21, 21, 11, 22, 13, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 21, 32, 33, + 34, 35, 36, 21, 37, 38, 39, 40, 41, 42, + 21, 21, 43, 44, 44, 53, 44, 44, 44, 44, + 44, 44, 44, 44, 116, 44, 57, 58, 44, 60, + 61, 44, 44, 117, 72, 83, 84, 209, 44, 44, + 44, 53, 44, 210, 240, 44, 44, 44, 73, 65, + 44, 66, 67, 79, 85, 74, 68, 80, 1134, 86, + + 44, 69, 241, 81, 87, 70, 82, 71, 44, 48, + 49, 50, 50, 50, 50, 50, 50, 50, 51, 195, + 88, 196, 52, 53, 54, 53, 352, 55, 52, 52, + 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 54, 53, 44, 123, 75, 44, 447, 44, 124, 125, + 44, 126, 127, 193, 76, 204, 194, 77, 199, 63, + 56, 78, 63, 200, 63, 53, 515, 63, 44, 62, + 52, 52, 52, 52, 52, 52, 52, 63, 110, 89, + 246, 90, 111, 53, 118, 63, 91, 92, 205, 93, + + 247, 112, 113, 94, 145, 114, 119, 115, 120, 211, + 121, 341, 146, 122, 212, 339, 147, 340, 148, 53, + 55, 53, 53, 53, 53, 53, 53, 53, 53, 1458, + 103, 104, 1222, 53, 181, 342, 140, 206, 141, 53, + 53, 53, 53, 53, 53, 95, 105, 447, 96, 97, + 106, 98, 142, 99, 107, 100, 108, 101, 128, 143, + 102, 182, 129, 109, 207, 234, 133, 183, 215, 208, + 130, 216, 134, 217, 135, 131, 136, 132, 235, 243, + 137, 44, 138, 139, 44, 738, 44, 53, 244, 44, + 155, 155, 155, 155, 155, 155, 155, 63, 53, 44, + + 63, 413, 63, 321, 735, 63, 414, 44, 152, 152, + 152, 152, 152, 152, 152, 63, 322, 1458, 1458, 152, + 53, 1458, 53, 63, 53, 152, 152, 152, 152, 152, + 152, 153, 154, 154, 154, 154, 154, 154, 53, 1458, + 1225, 1458, 155, 1458, 1458, 1458, 53, 1458, 155, 155, + 155, 155, 155, 155, 49, 156, 156, 156, 156, 156, + 156, 156, 275, 447, 53, 1458, 157, 1458, 53, 673, + 277, 1458, 157, 157, 157, 157, 157, 157, 62, 157, + 157, 157, 157, 157, 157, 157, 160, 160, 160, 160, + 160, 160, 160, 377, 378, 379, 380, 160, 490, 730, + + 53, 564, 494, 160, 160, 160, 160, 160, 160, 44, + 565, 491, 44, 381, 44, 431, 495, 44, 458, 458, + 161, 162, 162, 162, 162, 162, 162, 44, 53, 263, + 731, 163, 459, 1458, 1228, 44, 53, 163, 163, 163, + 163, 163, 163, 258, 567, 259, 259, 259, 259, 259, + 259, 259, 362, 568, 53, 263, 259, 1458, 459, 1458, + 523, 740, 259, 259, 259, 259, 259, 259, 260, 261, + 261, 261, 261, 261, 261, 261, 275, 462, 447, 53, + 262, 1458, 263, 1458, 1458, 464, 262, 262, 262, 262, + 262, 262, 349, 349, 349, 349, 349, 349, 349, 368, + + 369, 369, 369, 369, 369, 369, 533, 1458, 263, 264, + 262, 262, 262, 262, 262, 262, 262, 1458, 1458, 1231, + 534, 262, 377, 378, 379, 380, 447, 262, 262, 262, + 262, 262, 262, 265, 266, 266, 266, 266, 266, 266, + 266, 267, 1234, 1458, 1458, 268, 534, 1458, 1458, 53, + 746, 268, 268, 268, 268, 268, 268, 53, 268, 268, + 268, 268, 268, 268, 268, 271, 272, 272, 272, 272, + 272, 272, 273, 1458, 1458, 732, 274, 595, 733, 807, + 53, 53, 274, 274, 274, 274, 274, 274, 275, 276, + 276, 276, 276, 276, 276, 276, 277, 53, 447, 1198, + + 278, 739, 279, 595, 392, 807, 278, 278, 278, 278, + 278, 278, 393, 434, 434, 434, 434, 434, 434, 434, + 1200, 1001, 533, 1206, 596, 394, 55, 736, 279, 346, + 346, 346, 346, 346, 346, 346, 1458, 53, 429, 1458, + 346, 395, 1204, 55, 55, 1366, 346, 346, 346, 346, + 346, 346, 347, 348, 348, 348, 348, 348, 348, 734, + 752, 55, 1458, 349, 429, 1458, 1458, 1458, 53, 349, + 349, 349, 349, 349, 349, 260, 350, 350, 350, 350, + 350, 350, 350, 351, 351, 351, 351, 351, 351, 351, + 528, 537, 1458, 1458, 351, 1458, 53, 55, 681, 684, + + 351, 351, 351, 351, 351, 351, 353, 354, 354, 354, + 354, 354, 354, 354, 1299, 55, 1299, 447, 355, 1244, + 1040, 1458, 819, 1249, 355, 355, 355, 355, 355, 355, + 358, 355, 355, 355, 355, 355, 355, 355, 362, 363, + 363, 363, 363, 363, 363, 363, 364, 641, 417, 635, + 365, 1251, 366, 418, 1049, 643, 365, 365, 365, 365, + 365, 365, 419, 636, 420, 421, 1458, 422, 449, 450, + 450, 450, 450, 450, 450, 55, 635, 55, 366, 275, + 370, 370, 370, 370, 370, 370, 370, 277, 1257, 636, + 1458, 371, 1458, 55, 829, 55, 637, 371, 371, 371, + + 371, 371, 371, 372, 373, 373, 373, 373, 373, 373, + 638, 1259, 820, 1060, 374, 1265, 1458, 55, 1267, 55, + 374, 374, 374, 374, 374, 374, 424, 637, 425, 425, + 425, 425, 425, 425, 425, 55, 638, 55, 1072, 425, + 825, 1458, 55, 55, 747, 425, 425, 425, 425, 425, + 425, 426, 427, 427, 427, 427, 427, 427, 427, 1273, + 55, 55, 55, 428, 826, 429, 1275, 1458, 1084, 428, + 428, 428, 428, 428, 428, 512, 512, 512, 512, 512, + 512, 512, 542, 543, 543, 543, 543, 543, 543, 694, + 745, 429, 430, 428, 428, 428, 428, 428, 428, 428, + + 53, 1206, 1307, 695, 428, 1134, 55, 55, 1354, 694, + 428, 428, 428, 428, 428, 428, 432, 433, 433, 433, + 433, 433, 433, 1458, 55, 55, 1458, 434, 827, 695, + 55, 749, 55, 434, 434, 434, 434, 434, 434, 265, + 435, 435, 435, 435, 435, 435, 435, 1356, 55, 1458, + 55, 436, 1458, 830, 1458, 878, 1379, 436, 436, 436, + 436, 436, 436, 53, 436, 436, 436, 436, 436, 436, + 436, 439, 440, 440, 440, 440, 440, 440, 1458, 689, + 1458, 878, 441, 1383, 55, 55, 1387, 842, 441, 441, + 441, 441, 441, 441, 445, 446, 446, 446, 446, 446, + + 446, 447, 55, 55, 1458, 448, 1391, 906, 907, 55, + 55, 448, 448, 448, 448, 448, 448, 362, 451, 451, + 451, 451, 451, 451, 451, 364, 698, 55, 55, 452, + 1395, 55, 908, 910, 845, 452, 452, 452, 452, 452, + 452, 453, 454, 454, 454, 454, 454, 454, 447, 55, + 1411, 1433, 455, 53, 912, 55, 55, 55, 455, 455, + 455, 455, 455, 455, 275, 460, 460, 460, 460, 460, + 460, 460, 277, 55, 55, 55, 461, 915, 913, 53, + 55, 55, 461, 461, 461, 461, 461, 461, 462, 463, + 463, 463, 463, 463, 463, 463, 464, 709, 55, 55, + + 465, 994, 466, 1015, 1458, 848, 465, 465, 465, 465, + 465, 465, 546, 547, 547, 547, 547, 547, 547, 615, + 616, 616, 616, 616, 616, 616, 447, 994, 466, 475, + 1458, 1458, 447, 476, 1458, 55, 477, 55, 703, 478, + 703, 479, 480, 481, 482, 509, 509, 509, 509, 509, + 509, 509, 704, 55, 1458, 55, 509, 1458, 1011, 55, + 1458, 741, 509, 509, 509, 509, 509, 509, 510, 511, + 511, 511, 511, 511, 511, 53, 814, 55, 704, 512, + 1458, 1458, 1458, 1458, 816, 512, 512, 512, 512, 512, + 512, 426, 513, 513, 513, 513, 513, 513, 513, 514, + + 514, 514, 514, 514, 514, 514, 1458, 1458, 1458, 1458, + 514, 1458, 55, 55, 1299, 55, 514, 514, 514, 514, + 514, 514, 431, 516, 516, 516, 516, 516, 516, 516, + 55, 55, 1458, 55, 517, 1234, 263, 1458, 1017, 1231, + 517, 517, 517, 517, 517, 517, 623, 624, 624, 624, + 624, 624, 624, 627, 628, 628, 628, 628, 628, 628, + 55, 705, 263, 517, 517, 517, 517, 517, 517, 517, + 1065, 1228, 1458, 1077, 517, 706, 1458, 1225, 55, 742, + 517, 517, 517, 517, 517, 517, 518, 518, 518, 518, + 518, 518, 518, 53, 1222, 821, 1065, 519, 1458, 1077, + + 1458, 706, 1458, 519, 519, 519, 519, 519, 519, 53, + 519, 519, 519, 519, 519, 519, 519, 362, 522, 522, + 522, 522, 522, 522, 522, 523, 1458, 705, 1299, 524, + 1206, 366, 1003, 1084, 447, 524, 524, 524, 524, 524, + 524, 1458, 714, 715, 715, 715, 715, 715, 715, 717, + 718, 718, 718, 718, 718, 718, 55, 366, 528, 529, + 529, 529, 529, 529, 529, 529, 530, 1458, 1234, 885, + 531, 1080, 532, 1078, 55, 744, 531, 531, 531, 531, + 531, 531, 721, 722, 722, 722, 722, 722, 722, 53, + 772, 773, 773, 773, 773, 773, 773, 55, 532, 362, + + 535, 535, 535, 535, 535, 535, 535, 523, 1072, 447, + 1197, 536, 1231, 1458, 1458, 55, 55, 536, 536, 536, + 536, 536, 536, 537, 538, 538, 538, 538, 538, 538, + 538, 539, 822, 873, 55, 540, 1197, 541, 1110, 1458, + 1458, 540, 540, 540, 540, 540, 540, 780, 781, 781, + 781, 781, 781, 781, 784, 785, 785, 785, 785, 785, + 785, 808, 55, 541, 462, 548, 548, 548, 548, 548, + 548, 548, 464, 1068, 1066, 809, 549, 1458, 55, 1060, + 55, 808, 549, 549, 549, 549, 549, 549, 550, 551, + 551, 551, 551, 551, 551, 1458, 55, 824, 447, 552, + + 1113, 809, 55, 1458, 55, 552, 552, 552, 552, 552, + 552, 590, 810, 591, 591, 591, 591, 591, 591, 591, + 55, 1458, 55, 1228, 591, 1114, 811, 862, 1056, 55, + 591, 591, 591, 591, 591, 591, 592, 593, 593, 593, + 593, 593, 593, 593, 1054, 853, 1209, 55, 594, 1212, + 595, 1049, 811, 1024, 594, 594, 594, 594, 594, 594, + 792, 793, 793, 793, 793, 793, 793, 795, 796, 796, + 796, 796, 796, 796, 810, 55, 595, 592, 594, 594, + 594, 594, 594, 594, 594, 1458, 862, 447, 1458, 594, + 1458, 1225, 1458, 55, 1027, 594, 594, 594, 594, 594, + + 594, 431, 597, 597, 597, 597, 597, 597, 597, 873, + 911, 1458, 853, 598, 1458, 1256, 1458, 1030, 1458, 598, + 598, 598, 598, 598, 598, 53, 598, 598, 598, 598, + 598, 598, 598, 599, 599, 599, 599, 599, 599, 599, + 885, 1256, 1045, 1040, 600, 1264, 1272, 1458, 1033, 447, + 600, 600, 600, 600, 600, 600, 53, 600, 600, 600, + 600, 600, 600, 600, 603, 604, 604, 604, 604, 604, + 604, 1264, 1272, 1458, 1353, 605, 1382, 1386, 55, 55, + 55, 605, 605, 605, 605, 605, 605, 362, 451, 451, + 451, 451, 451, 451, 451, 523, 55, 55, 55, 452, + + 1353, 55, 1382, 1386, 858, 452, 452, 452, 452, 452, + 452, 606, 607, 607, 607, 607, 607, 607, 859, 55, + 1210, 1211, 608, 1222, 1215, 55, 447, 1136, 608, 608, + 608, 608, 608, 608, 612, 613, 613, 613, 613, 613, + 613, 447, 1241, 55, 859, 614, 1117, 1234, 1231, 55, + 55, 614, 614, 614, 614, 614, 614, 528, 617, 617, + 617, 617, 617, 617, 617, 530, 1001, 55, 55, 618, + 1228, 1225, 55, 55, 1003, 618, 618, 618, 618, 618, + 618, 619, 620, 620, 620, 620, 620, 620, 447, 1213, + 55, 55, 621, 1222, 1117, 55, 55, 55, 621, 621, + + 621, 621, 621, 621, 537, 629, 629, 629, 629, 629, + 629, 629, 539, 55, 55, 55, 630, 1001, 1362, 1294, + 55, 1206, 630, 630, 630, 630, 630, 630, 631, 632, + 632, 632, 632, 632, 632, 447, 1040, 1003, 55, 633, + 1390, 1363, 814, 55, 1222, 633, 633, 633, 633, 633, + 633, 462, 639, 639, 639, 639, 639, 639, 639, 464, + 1049, 55, 1394, 640, 1432, 1440, 1390, 997, 1225, 640, + 640, 640, 640, 640, 640, 641, 642, 642, 642, 642, + 642, 642, 642, 643, 1060, 1364, 995, 644, 1394, 645, + 1432, 1440, 1228, 644, 644, 644, 644, 644, 644, 799, + + 800, 800, 800, 800, 800, 800, 715, 715, 715, 715, + 715, 715, 715, 55, 858, 645, 669, 669, 669, 669, + 669, 669, 669, 1441, 1072, 1442, 1443, 669, 1458, 1086, + 55, 55, 1231, 669, 669, 669, 669, 669, 669, 670, + 670, 670, 670, 670, 670, 670, 909, 1084, 55, 1441, + 670, 1442, 1443, 1444, 1458, 1234, 670, 670, 670, 670, + 670, 670, 592, 671, 671, 671, 671, 671, 671, 671, + 672, 672, 672, 672, 672, 672, 672, 1134, 1204, 1444, + 1449, 672, 1455, 55, 55, 1299, 1206, 672, 672, 672, + 672, 672, 672, 431, 674, 674, 674, 674, 674, 674, + + 674, 55, 55, 447, 1033, 675, 1449, 1074, 1455, 447, + 1295, 675, 675, 675, 675, 675, 675, 53, 675, 675, + 675, 675, 675, 675, 675, 676, 676, 676, 676, 676, + 676, 676, 1204, 1030, 1062, 447, 677, 1027, 1051, 447, + 1458, 1024, 677, 677, 677, 677, 677, 677, 53, 677, + 677, 677, 677, 677, 677, 677, 528, 680, 680, 680, + 680, 680, 680, 680, 681, 55, 867, 867, 682, 1042, + 532, 55, 447, 869, 682, 682, 682, 682, 682, 682, + 868, 1458, 1136, 55, 447, 1117, 1033, 870, 1030, 55, + 55, 1027, 55, 1024, 55, 823, 532, 537, 683, 683, + + 683, 683, 683, 683, 683, 684, 868, 1458, 55, 685, + 55, 541, 55, 870, 55, 685, 685, 685, 685, 685, + 685, 831, 828, 1117, 338, 836, 836, 836, 836, 836, + 836, 836, 55, 869, 879, 879, 55, 541, 689, 690, + 690, 690, 690, 690, 690, 690, 691, 1458, 880, 1458, + 692, 916, 693, 1003, 55, 881, 692, 692, 692, 692, + 692, 692, 793, 793, 793, 793, 793, 793, 793, 882, + 55, 1010, 816, 1458, 880, 1458, 881, 885, 693, 528, + 696, 696, 696, 696, 696, 696, 696, 681, 55, 1086, + 1458, 697, 1033, 709, 55, 882, 1409, 697, 697, 697, + + 697, 697, 697, 698, 699, 699, 699, 699, 699, 699, + 699, 700, 55, 881, 879, 701, 1458, 702, 873, 1074, + 1030, 701, 701, 701, 701, 701, 701, 891, 892, 892, + 892, 892, 892, 892, 894, 895, 895, 895, 895, 895, + 895, 995, 55, 702, 537, 707, 707, 707, 707, 707, + 707, 707, 684, 698, 869, 996, 708, 867, 862, 1062, + 55, 1012, 708, 708, 708, 708, 708, 708, 709, 710, + 710, 710, 710, 710, 710, 710, 711, 1027, 1013, 689, + 712, 996, 713, 858, 55, 55, 712, 712, 712, 712, + 712, 712, 898, 899, 899, 899, 899, 899, 899, 853, + + 1051, 1024, 55, 55, 1042, 995, 997, 55, 713, 641, + 723, 723, 723, 723, 723, 723, 723, 643, 914, 1458, + 998, 724, 1112, 939, 924, 55, 997, 724, 724, 724, + 724, 724, 724, 725, 726, 726, 726, 726, 726, 726, + 1458, 1014, 1033, 1030, 727, 1458, 998, 1027, 1024, 1022, + 727, 727, 727, 727, 727, 727, 53, 53, 53, 53, + 53, 53, 53, 924, 814, 1003, 1458, 53, 55, 55, + 55, 55, 55, 53, 53, 53, 53, 53, 53, 943, + 944, 944, 944, 944, 944, 944, 55, 55, 55, 55, + 55, 729, 747, 816, 748, 748, 748, 748, 748, 748, + + 748, 1006, 1007, 1008, 1009, 748, 1016, 641, 55, 1109, + 55, 748, 748, 748, 748, 748, 748, 951, 952, 952, + 952, 952, 952, 952, 1045, 1045, 55, 55, 55, 53, + 749, 750, 750, 750, 750, 750, 750, 750, 1046, 1458, + 1108, 810, 750, 1216, 808, 55, 887, 848, 750, 750, + 750, 750, 750, 750, 955, 956, 956, 956, 956, 956, + 956, 875, 1361, 845, 1046, 1458, 53, 671, 671, 671, + 671, 671, 671, 671, 963, 964, 964, 964, 964, 964, + 964, 966, 967, 967, 967, 967, 967, 967, 970, 971, + 971, 971, 971, 971, 971, 979, 980, 980, 980, 980, + + 980, 980, 53, 672, 672, 672, 672, 672, 672, 672, + 864, 842, 855, 939, 672, 924, 848, 845, 842, 924, + 672, 672, 672, 672, 672, 672, 751, 350, 350, 350, + 350, 350, 350, 350, 265, 753, 753, 753, 753, 753, + 753, 753, 816, 643, 709, 887, 754, 848, 537, 705, + 703, 698, 754, 754, 754, 754, 754, 754, 53, 754, + 754, 754, 754, 754, 754, 754, 757, 758, 758, 758, + 758, 758, 758, 875, 845, 528, 694, 759, 689, 864, + 842, 855, 852, 759, 759, 759, 759, 759, 759, 528, + 617, 617, 617, 617, 617, 617, 617, 681, 768, 756, + + 848, 618, 845, 842, 840, 756, 1054, 618, 618, 618, + 618, 618, 618, 760, 761, 761, 761, 761, 761, 761, + 1055, 641, 816, 643, 762, 462, 637, 635, 711, 684, + 762, 762, 762, 762, 762, 762, 537, 629, 629, 629, + 629, 629, 629, 629, 684, 700, 1055, 681, 630, 691, + 768, 756, 684, 1054, 630, 630, 630, 630, 630, 630, + 763, 764, 764, 764, 764, 764, 764, 1458, 681, 756, + 53, 765, 53, 53, 743, 53, 53, 765, 765, 765, + 765, 765, 765, 769, 770, 770, 770, 770, 770, 770, + 447, 737, 643, 1458, 771, 464, 537, 711, 684, 362, + + 771, 771, 771, 771, 771, 771, 689, 774, 774, 774, + 774, 774, 774, 774, 691, 533, 528, 700, 775, 681, + 691, 688, 611, 602, 775, 775, 775, 775, 775, 775, + 776, 777, 777, 777, 777, 777, 777, 447, 684, 681, + 679, 778, 602, 592, 590, 668, 667, 778, 778, 778, + 778, 778, 778, 698, 786, 786, 786, 786, 786, 786, + 786, 700, 666, 665, 664, 787, 663, 662, 661, 660, + 659, 787, 787, 787, 787, 787, 787, 788, 789, 789, + 789, 789, 789, 789, 447, 658, 657, 656, 790, 655, + 654, 653, 652, 651, 790, 790, 790, 790, 790, 790, + + 709, 801, 801, 801, 801, 801, 801, 801, 711, 650, + 649, 648, 802, 647, 646, 462, 643, 464, 802, 802, + 802, 802, 802, 802, 803, 804, 804, 804, 804, 804, + 804, 447, 458, 539, 523, 805, 530, 611, 602, 523, + 602, 805, 805, 805, 805, 805, 805, 641, 812, 812, + 812, 812, 812, 812, 812, 643, 596, 596, 589, 813, + 588, 587, 586, 585, 584, 813, 813, 813, 813, 813, + 813, 814, 815, 815, 815, 815, 815, 815, 815, 816, + 583, 582, 581, 817, 335, 818, 237, 580, 579, 817, + 817, 817, 817, 817, 817, 982, 983, 983, 983, 983, + + 983, 983, 986, 987, 987, 987, 987, 987, 987, 1056, + 1056, 818, 55, 1066, 832, 832, 832, 832, 832, 832, + 832, 578, 577, 1057, 1458, 832, 576, 1067, 575, 574, + 55, 832, 832, 832, 832, 832, 832, 833, 833, 833, + 833, 833, 833, 833, 573, 572, 571, 570, 833, 1057, + 1458, 569, 566, 1067, 833, 833, 833, 833, 833, 833, + 834, 835, 835, 835, 835, 835, 835, 563, 562, 561, + 560, 836, 559, 55, 558, 557, 556, 836, 836, 836, + 836, 836, 836, 265, 837, 837, 837, 837, 837, 837, + 837, 55, 555, 554, 464, 838, 277, 447, 362, 539, + + 1408, 838, 838, 838, 838, 838, 838, 53, 838, 838, + 838, 838, 838, 838, 838, 689, 841, 841, 841, 841, + 841, 841, 841, 842, 523, 530, 447, 843, 527, 693, + 444, 438, 523, 843, 843, 843, 843, 843, 843, 892, + 892, 892, 892, 892, 892, 892, 964, 964, 964, 964, + 964, 964, 964, 1066, 521, 693, 698, 844, 844, 844, + 844, 844, 844, 844, 845, 438, 1068, 1458, 846, 430, + 702, 424, 1068, 1078, 846, 846, 846, 846, 846, 846, + 1069, 508, 507, 506, 505, 504, 1458, 1079, 503, 502, + 501, 500, 55, 1458, 1078, 499, 702, 709, 847, 847, + + 847, 847, 847, 847, 847, 848, 1069, 498, 1458, 849, + 55, 713, 1458, 1079, 1080, 849, 849, 849, 849, 849, + 849, 980, 980, 980, 980, 980, 980, 980, 1081, 1407, + 497, 496, 493, 1080, 1458, 1198, 492, 713, 853, 854, + 854, 854, 854, 854, 854, 854, 855, 1458, 489, 1199, + 856, 488, 857, 487, 1081, 1198, 856, 856, 856, 856, + 856, 856, 1090, 1091, 1091, 1091, 1091, 1091, 1091, 1458, + 486, 485, 119, 1458, 1200, 1199, 1200, 484, 857, 689, + 860, 860, 860, 860, 860, 860, 860, 842, 1201, 483, + 1458, 861, 474, 473, 472, 1458, 471, 861, 861, 861, + + 861, 861, 861, 862, 863, 863, 863, 863, 863, 863, + 863, 864, 470, 469, 1201, 865, 1458, 866, 468, 467, + 275, 865, 865, 865, 865, 865, 865, 1093, 1094, 1094, + 1094, 1094, 1094, 1094, 1097, 1098, 1098, 1098, 1098, 1098, + 1098, 1244, 464, 866, 698, 871, 871, 871, 871, 871, + 871, 871, 845, 277, 447, 1245, 872, 364, 444, 438, + 438, 55, 872, 872, 872, 872, 872, 872, 873, 874, + 874, 874, 874, 874, 874, 874, 875, 55, 55, 55, + 876, 1245, 877, 431, 431, 423, 876, 876, 876, 876, + 876, 876, 416, 1111, 415, 55, 55, 1140, 1141, 1141, + + 1141, 1141, 1141, 1141, 1244, 412, 1105, 1106, 877, 709, + 883, 883, 883, 883, 883, 883, 883, 848, 1458, 411, + 410, 884, 409, 408, 407, 406, 405, 884, 884, 884, + 884, 884, 884, 885, 886, 886, 886, 886, 886, 886, + 886, 887, 55, 1249, 1458, 888, 404, 889, 403, 402, + 55, 888, 888, 888, 888, 888, 888, 1250, 401, 400, + 55, 1146, 1147, 1147, 1147, 1147, 1147, 1147, 55, 399, + 1249, 1107, 398, 889, 814, 900, 900, 900, 900, 900, + 900, 900, 816, 1250, 1458, 397, 901, 1436, 396, 391, + 390, 1251, 901, 901, 901, 901, 901, 901, 902, 903, + + 903, 903, 903, 903, 903, 1252, 389, 388, 317, 904, + 1458, 387, 386, 385, 384, 904, 904, 904, 904, 904, + 904, 55, 1251, 917, 917, 917, 917, 917, 917, 917, + 383, 1252, 382, 376, 917, 277, 1458, 364, 273, 55, + 917, 917, 917, 917, 917, 917, 918, 918, 918, 918, + 918, 918, 918, 361, 270, 357, 264, 918, 258, 142, + 345, 344, 1458, 918, 918, 918, 918, 918, 918, 596, + 919, 919, 919, 919, 919, 919, 919, 343, 338, 317, + 337, 920, 336, 429, 335, 334, 333, 920, 920, 920, + 920, 920, 920, 1150, 1151, 1151, 1151, 1151, 1151, 1151, + + 1156, 1157, 1157, 1157, 1157, 1157, 1157, 332, 1257, 429, + 920, 920, 920, 920, 920, 920, 920, 331, 330, 329, + 328, 920, 1258, 327, 326, 325, 324, 920, 920, 920, + 920, 920, 920, 265, 921, 921, 921, 921, 921, 921, + 921, 323, 320, 319, 318, 922, 317, 316, 1258, 315, + 314, 922, 922, 922, 922, 922, 922, 53, 922, 922, + 922, 922, 922, 922, 922, 925, 926, 926, 926, 926, + 926, 926, 313, 312, 311, 310, 927, 309, 308, 307, + 306, 305, 927, 927, 927, 927, 927, 927, 689, 774, + 774, 774, 774, 774, 774, 774, 842, 304, 303, 302, + + 775, 301, 300, 299, 298, 1257, 775, 775, 775, 775, + 775, 775, 928, 929, 929, 929, 929, 929, 929, 1458, + 297, 296, 295, 930, 142, 294, 293, 292, 291, 930, + 930, 930, 930, 930, 930, 698, 786, 786, 786, 786, + 786, 786, 786, 845, 290, 1458, 289, 787, 288, 287, + 286, 285, 1259, 787, 787, 787, 787, 787, 787, 931, + 932, 932, 932, 932, 932, 932, 1260, 284, 283, 282, + 933, 281, 280, 277, 265, 270, 933, 933, 933, 933, + 933, 933, 709, 801, 801, 801, 801, 801, 801, 801, + 848, 257, 1260, 256, 802, 255, 254, 253, 252, 1259, + + 802, 802, 802, 802, 802, 802, 934, 935, 935, 935, + 935, 935, 935, 1458, 251, 250, 249, 936, 248, 245, + 242, 239, 238, 936, 936, 936, 936, 936, 936, 940, + 941, 941, 941, 941, 941, 941, 447, 237, 236, 1458, + 942, 233, 232, 231, 230, 229, 942, 942, 942, 942, + 942, 942, 853, 945, 945, 945, 945, 945, 945, 945, + 855, 228, 227, 226, 946, 225, 224, 223, 222, 221, + 946, 946, 946, 946, 946, 946, 947, 948, 948, 948, + 948, 948, 948, 447, 220, 219, 218, 949, 214, 213, + 203, 202, 201, 949, 949, 949, 949, 949, 949, 862, + + 957, 957, 957, 957, 957, 957, 957, 864, 198, 197, + 192, 958, 191, 190, 189, 188, 187, 958, 958, 958, + 958, 958, 958, 959, 960, 960, 960, 960, 960, 960, + 447, 186, 185, 184, 961, 180, 179, 178, 177, 176, + 961, 961, 961, 961, 961, 961, 873, 972, 972, 972, + 972, 972, 972, 972, 875, 175, 174, 173, 973, 172, + 171, 170, 169, 168, 973, 973, 973, 973, 973, 973, + 974, 975, 975, 975, 975, 975, 975, 447, 167, 166, + 165, 976, 164, 159, 150, 149, 144, 976, 976, 976, + 976, 976, 976, 885, 988, 988, 988, 988, 988, 988, + + 988, 887, 59, 47, 45, 989, 1458, 1458, 1458, 1458, + 1458, 989, 989, 989, 989, 989, 989, 990, 991, 991, + 991, 991, 991, 991, 447, 1458, 1458, 1458, 992, 1458, + 1458, 1458, 1458, 1458, 992, 992, 992, 992, 992, 992, + 814, 999, 999, 999, 999, 999, 999, 999, 816, 1458, + 1458, 1458, 1000, 1458, 1458, 1458, 1458, 1458, 1000, 1000, + 1000, 1000, 1000, 1000, 1001, 1002, 1002, 1002, 1002, 1002, + 1002, 1002, 1003, 1458, 1458, 1458, 1004, 1458, 1005, 1458, + 1458, 1458, 1004, 1004, 1004, 1004, 1004, 1004, 1159, 1160, + 1160, 1160, 1160, 1160, 1160, 1163, 1164, 1164, 1164, 1164, + + 1164, 1164, 1458, 1458, 1005, 55, 596, 1018, 1018, 1018, + 1018, 1018, 1018, 1018, 1458, 1458, 1458, 1458, 1019, 1458, + 1458, 1458, 1458, 55, 1019, 1019, 1019, 1019, 1019, 1019, + 53, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 55, 265, + 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1170, 1171, 1171, + 1171, 1171, 1171, 1171, 1458, 1458, 55, 853, 1023, 1023, + 1023, 1023, 1023, 1023, 1023, 1024, 1458, 1458, 1458, 1025, + 1458, 857, 1458, 1458, 1458, 1025, 1025, 1025, 1025, 1025, + 1025, 1173, 1174, 1174, 1174, 1174, 1174, 1174, 1177, 1178, + 1178, 1178, 1178, 1178, 1178, 1458, 1458, 857, 862, 1026, + + 1026, 1026, 1026, 1026, 1026, 1026, 1027, 1458, 1458, 1458, + 1028, 1458, 866, 1458, 1458, 1458, 1028, 1028, 1028, 1028, + 1028, 1028, 1184, 1185, 1185, 1185, 1185, 1185, 1185, 1187, + 1188, 1188, 1188, 1188, 1188, 1188, 1458, 1458, 866, 873, + 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1030, 1458, 1458, + 1458, 1031, 1458, 877, 1458, 1458, 1458, 1031, 1031, 1031, + 1031, 1031, 1031, 1191, 1192, 1192, 1192, 1192, 1192, 1192, + 1091, 1091, 1091, 1091, 1091, 1091, 1091, 55, 1458, 877, + 885, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1033, 1458, + 1265, 1265, 1034, 1458, 889, 55, 1458, 1458, 1034, 1034, + + 1034, 1034, 1034, 1034, 1266, 1458, 1214, 1236, 1237, 1237, + 1237, 1237, 1237, 1237, 1458, 1267, 1458, 1458, 1458, 1267, + 889, 1036, 1037, 1037, 1037, 1037, 1037, 1037, 1038, 1268, + 1266, 1458, 1039, 1458, 1458, 1458, 1458, 1458, 1039, 1039, + 1039, 1039, 1039, 1039, 1040, 1041, 1041, 1041, 1041, 1041, + 1041, 1041, 1042, 1458, 1458, 1268, 1043, 1458, 1044, 1458, + 1458, 1458, 1043, 1043, 1043, 1043, 1043, 1043, 1157, 1157, + 1157, 1157, 1157, 1157, 1157, 1171, 1171, 1171, 1171, 1171, + 1171, 1171, 1273, 1458, 1044, 853, 1047, 1047, 1047, 1047, + 1047, 1047, 1047, 1024, 1458, 1458, 1274, 1048, 1458, 1458, + + 1458, 1458, 1458, 1048, 1048, 1048, 1048, 1048, 1048, 1049, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1051, 1458, 1458, + 1458, 1052, 1274, 1053, 1458, 1458, 1273, 1052, 1052, 1052, + 1052, 1052, 1052, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + 1458, 1458, 1458, 1458, 1458, 1275, 1458, 1275, 1458, 1053, + 862, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1027, 1276, + 1458, 1458, 1059, 1458, 1458, 1458, 1458, 1458, 1059, 1059, + 1059, 1059, 1059, 1059, 1060, 1061, 1061, 1061, 1061, 1061, + 1061, 1061, 1062, 1458, 1458, 1276, 1063, 1458, 1064, 1458, + 1458, 1458, 1063, 1063, 1063, 1063, 1063, 1063, 1281, 1282, + + 1282, 1282, 1282, 1282, 1282, 1284, 1285, 1285, 1285, 1285, + 1285, 1285, 1307, 1458, 1064, 873, 1070, 1070, 1070, 1070, + 1070, 1070, 1070, 1030, 1458, 1458, 1308, 1071, 1458, 1458, + 1458, 1458, 1458, 1071, 1071, 1071, 1071, 1071, 1071, 1072, + 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1074, 1458, 1458, + 1458, 1075, 1308, 1076, 1458, 1458, 1307, 1075, 1075, 1075, + 1075, 1075, 1075, 1288, 1289, 1289, 1289, 1289, 1289, 1289, + 1458, 1313, 1314, 1314, 1314, 1314, 1314, 1314, 1458, 1076, + 885, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1033, 1458, + 1458, 1458, 1083, 1458, 1458, 1458, 1458, 55, 1083, 1083, + + 1083, 1083, 1083, 1083, 1084, 1085, 1085, 1085, 1085, 1085, + 1085, 1085, 1086, 55, 1458, 55, 1087, 1458, 1088, 1458, + 1458, 1458, 1087, 1087, 1087, 1087, 1087, 1087, 1296, 1458, + 1458, 55, 1318, 1319, 1319, 1319, 1319, 1319, 1319, 1458, + 1458, 1354, 1297, 1458, 1088, 1001, 1099, 1099, 1099, 1099, + 1099, 1099, 1099, 1003, 1458, 1355, 1458, 1100, 1458, 1458, + 1458, 1458, 1354, 1100, 1100, 1100, 1100, 1100, 1100, 1101, + 1102, 1102, 1102, 1102, 1102, 1102, 1458, 1458, 1458, 1458, + 1103, 1355, 1458, 1458, 1458, 1458, 1103, 1103, 1103, 1103, + 1103, 1103, 55, 596, 1115, 1115, 1115, 1115, 1115, 1115, + + 1115, 1458, 1458, 1458, 1458, 922, 1458, 1458, 1458, 1458, + 55, 922, 922, 922, 922, 922, 922, 53, 922, 922, + 922, 922, 922, 922, 922, 55, 265, 1020, 1020, 1020, + 1020, 1020, 1020, 1020, 1321, 1322, 1322, 1322, 1322, 1322, + 1322, 1458, 1356, 55, 1118, 1119, 1119, 1119, 1119, 1119, + 1119, 1458, 1458, 1458, 1458, 1120, 1357, 1458, 1458, 1458, + 1458, 1120, 1120, 1120, 1120, 1120, 1120, 853, 945, 945, + 945, 945, 945, 945, 945, 1024, 1458, 1458, 1458, 946, + 1458, 1458, 1357, 1458, 1356, 946, 946, 946, 946, 946, + 946, 1121, 1122, 1122, 1122, 1122, 1122, 1122, 1458, 1458, + + 1458, 1458, 1123, 1458, 1458, 1458, 1458, 1458, 1123, 1123, + 1123, 1123, 1123, 1123, 862, 957, 957, 957, 957, 957, + 957, 957, 1027, 1458, 1458, 1458, 958, 1458, 1458, 1458, + 1458, 1379, 958, 958, 958, 958, 958, 958, 1124, 1125, + 1125, 1125, 1125, 1125, 1125, 1380, 1458, 1458, 1458, 1126, + 1458, 1458, 1458, 1458, 1458, 1126, 1126, 1126, 1126, 1126, + 1126, 873, 972, 972, 972, 972, 972, 972, 972, 1030, + 1458, 1380, 1458, 973, 1458, 1458, 1458, 1458, 1379, 973, + 973, 973, 973, 973, 973, 1127, 1128, 1128, 1128, 1128, + 1128, 1128, 1458, 1458, 1458, 1458, 1129, 1458, 1458, 1458, + + 1458, 1458, 1129, 1129, 1129, 1129, 1129, 1129, 885, 988, + 988, 988, 988, 988, 988, 988, 1033, 1458, 1458, 1458, + 989, 1458, 1458, 1458, 1458, 1383, 989, 989, 989, 989, + 989, 989, 1130, 1131, 1131, 1131, 1131, 1131, 1131, 1384, + 1458, 1458, 1458, 1132, 1458, 1458, 1458, 1458, 1458, 1132, + 1132, 1132, 1132, 1132, 1132, 1134, 1135, 1135, 1135, 1135, + 1135, 1135, 1135, 1136, 1458, 1384, 1458, 1137, 1458, 1138, + 1458, 1458, 1458, 1137, 1137, 1137, 1137, 1137, 1137, 1327, + 1328, 1328, 1328, 1328, 1328, 1328, 1330, 1331, 1331, 1331, + 1331, 1331, 1331, 1383, 1458, 1138, 1040, 1142, 1142, 1142, + + 1142, 1142, 1142, 1142, 1042, 1458, 1458, 1458, 1143, 1458, + 1458, 1458, 1458, 1458, 1143, 1143, 1143, 1143, 1143, 1143, + 1049, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1051, 1458, + 1458, 1458, 1153, 1458, 1458, 1458, 1458, 1458, 1153, 1153, + 1153, 1153, 1153, 1153, 1060, 1165, 1165, 1165, 1165, 1165, + 1165, 1165, 1062, 1458, 1458, 1458, 1166, 1458, 1458, 1458, + 1458, 1458, 1166, 1166, 1166, 1166, 1166, 1166, 1072, 1179, + 1179, 1179, 1179, 1179, 1179, 1179, 1074, 1458, 1458, 1458, + 1180, 1458, 1458, 1458, 1458, 1458, 1180, 1180, 1180, 1180, + 1180, 1180, 1084, 1193, 1193, 1193, 1193, 1193, 1193, 1193, + + 1086, 1458, 1458, 1458, 1194, 1458, 1458, 1458, 1458, 1458, + 1194, 1194, 1194, 1194, 1194, 1194, 1001, 1202, 1202, 1202, + 1202, 1202, 1202, 1202, 1003, 1458, 1458, 1458, 1203, 1458, + 1458, 1458, 1458, 1458, 1203, 1203, 1203, 1203, 1203, 1203, + 1204, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1206, 1458, + 1458, 1458, 1207, 1458, 1208, 1458, 1458, 1458, 1207, 1207, + 1207, 1207, 1207, 1207, 1336, 1337, 1337, 1337, 1337, 1337, + 1337, 1339, 1340, 1340, 1340, 1340, 1340, 1340, 1458, 1458, + 1208, 55, 596, 513, 513, 513, 513, 513, 513, 513, + 1345, 1346, 1346, 1346, 1346, 1346, 1346, 1458, 1387, 55, + + 1217, 1218, 1218, 1218, 1218, 1218, 1218, 1219, 1458, 1458, + 1458, 1220, 1388, 1458, 1458, 1458, 1458, 1220, 1220, 1220, + 1220, 1220, 1220, 1040, 1221, 1221, 1221, 1221, 1221, 1221, + 1221, 1222, 1458, 1458, 1458, 1223, 1458, 1044, 1388, 1458, + 1458, 1223, 1223, 1223, 1223, 1223, 1223, 1348, 1349, 1349, + 1349, 1349, 1349, 1349, 1282, 1282, 1282, 1282, 1282, 1282, + 1282, 1458, 1458, 1044, 1049, 1224, 1224, 1224, 1224, 1224, + 1224, 1224, 1225, 1458, 1458, 1458, 1226, 1458, 1053, 1458, + 1458, 1458, 1226, 1226, 1226, 1226, 1226, 1226, 1373, 1374, + 1374, 1374, 1374, 1374, 1374, 1319, 1319, 1319, 1319, 1319, + + 1319, 1319, 1387, 1458, 1053, 1060, 1227, 1227, 1227, 1227, + 1227, 1227, 1227, 1228, 1458, 1458, 1458, 1229, 1458, 1064, + 1458, 1458, 1391, 1229, 1229, 1229, 1229, 1229, 1229, 1328, + 1328, 1328, 1328, 1328, 1328, 1328, 1392, 1458, 1458, 1458, + 1458, 1391, 1458, 1395, 1458, 1064, 1072, 1230, 1230, 1230, + 1230, 1230, 1230, 1230, 1231, 1458, 1458, 1396, 1232, 1458, + 1076, 1458, 1392, 1395, 1232, 1232, 1232, 1232, 1232, 1232, + 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1458, 1458, 1458, + 1458, 1458, 1458, 1396, 1458, 1458, 1076, 1084, 1233, 1233, + 1233, 1233, 1233, 1233, 1233, 1234, 1458, 1458, 1458, 1235, + + 1458, 1088, 1458, 1458, 1458, 1235, 1235, 1235, 1235, 1235, + 1235, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1399, 1400, + 1400, 1400, 1400, 1400, 1400, 1411, 1458, 1088, 1134, 1238, + 1238, 1238, 1238, 1238, 1238, 1238, 1136, 1458, 1458, 1412, + 1239, 1458, 1458, 1458, 1458, 1458, 1239, 1239, 1239, 1239, + 1239, 1239, 1040, 1246, 1246, 1246, 1246, 1246, 1246, 1246, + 1222, 1458, 1458, 1458, 1247, 1412, 1458, 1458, 1458, 1458, + 1247, 1247, 1247, 1247, 1247, 1247, 1049, 1253, 1253, 1253, + 1253, 1253, 1253, 1253, 1225, 1458, 1458, 1458, 1254, 1458, + 1458, 1458, 1458, 1458, 1254, 1254, 1254, 1254, 1254, 1254, + + 1060, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1228, 1458, + 1458, 1458, 1262, 1458, 1458, 1458, 1458, 1458, 1262, 1262, + 1262, 1262, 1262, 1262, 1072, 1269, 1269, 1269, 1269, 1269, + 1269, 1269, 1231, 1458, 1458, 1458, 1270, 1458, 1458, 1458, + 1458, 1458, 1270, 1270, 1270, 1270, 1270, 1270, 1084, 1277, + 1277, 1277, 1277, 1277, 1277, 1277, 1234, 1458, 1458, 1458, + 1278, 1458, 1458, 1458, 1458, 1458, 1278, 1278, 1278, 1278, + 1278, 1278, 1204, 1290, 1290, 1290, 1290, 1290, 1290, 1290, + 1206, 1458, 1458, 1458, 1291, 1458, 1458, 1458, 1458, 1458, + 1291, 1291, 1291, 1291, 1291, 1291, 1134, 1298, 1298, 1298, + + 1298, 1298, 1298, 1298, 1299, 1458, 1458, 1458, 1300, 1458, + 1138, 1458, 1458, 1411, 1300, 1300, 1300, 1300, 1300, 1300, + 1402, 1403, 1403, 1403, 1403, 1403, 1403, 1458, 1413, 1414, + 1414, 1414, 1414, 1414, 1414, 1458, 1138, 1040, 1142, 1142, + 1142, 1142, 1142, 1142, 1142, 1222, 1458, 1458, 1458, 1143, + 1458, 1458, 1458, 1458, 1458, 1143, 1143, 1143, 1143, 1143, + 1143, 1049, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1225, + 1458, 1458, 1458, 1153, 1458, 1458, 1458, 1458, 1458, 1153, + 1153, 1153, 1153, 1153, 1153, 1060, 1165, 1165, 1165, 1165, + 1165, 1165, 1165, 1228, 1458, 1458, 1458, 1166, 1458, 1458, + + 1458, 1458, 1458, 1166, 1166, 1166, 1166, 1166, 1166, 1072, + 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1231, 1458, 1458, + 1458, 1180, 1458, 1458, 1458, 1458, 1458, 1180, 1180, 1180, + 1180, 1180, 1180, 1084, 1193, 1193, 1193, 1193, 1193, 1193, + 1193, 1234, 1458, 1458, 1458, 1194, 1458, 1458, 1458, 1458, + 1458, 1194, 1194, 1194, 1194, 1194, 1194, 1134, 1309, 1309, + 1309, 1309, 1309, 1309, 1309, 1299, 1458, 1458, 1458, 1310, + 1458, 1458, 1458, 1458, 1458, 1310, 1310, 1310, 1310, 1310, + 1310, 1204, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1206, + 1458, 1458, 1458, 1359, 1458, 1458, 1458, 1458, 1458, 1359, + + 1359, 1359, 1359, 1359, 1359, 1134, 1238, 1238, 1238, 1238, + 1238, 1238, 1238, 1299, 1458, 1458, 1458, 1239, 1458, 1458, + 1458, 1458, 1458, 1239, 1239, 1239, 1239, 1239, 1239, 1417, + 1418, 1418, 1418, 1418, 1418, 1418, 1421, 1422, 1422, 1422, + 1422, 1422, 1422, 1425, 1426, 1426, 1426, 1426, 1426, 1426, + 1429, 1430, 1430, 1430, 1430, 1430, 1430, 1400, 1400, 1400, + 1400, 1400, 1400, 1400, 1433, 1433, 1437, 1438, 1438, 1438, + 1438, 1438, 1438, 1458, 1458, 1458, 1458, 1458, 1434, 1458, + 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1418, 1418, 1418, + 1418, 1418, 1418, 1418, 1422, 1422, 1422, 1422, 1422, 1422, + + 1422, 1458, 1458, 1458, 1434, 1458, 1426, 1426, 1426, 1426, + 1426, 1426, 1426, 1430, 1430, 1430, 1430, 1430, 1430, 1430, + 1446, 1447, 1447, 1447, 1447, 1447, 1447, 1438, 1438, 1438, + 1438, 1438, 1438, 1438, 1447, 1447, 1447, 1447, 1447, 1447, + 1447, 46, 1458, 1458, 1458, 1458, 46, 46, 46, 64, + 1458, 64, 64, 64, 64, 64, 64, 64, 151, 1458, + 151, 158, 158, 158, 269, 269, 269, 278, 278, 278, + 356, 356, 356, 359, 359, 359, 360, 360, 360, 367, + 367, 367, 365, 365, 365, 371, 371, 371, 375, 1458, + 375, 437, 437, 437, 442, 442, 442, 443, 443, 443, + + 452, 452, 452, 456, 1458, 456, 457, 457, 457, 369, + 369, 1458, 1458, 369, 461, 461, 461, 465, 465, 465, + 359, 359, 359, 520, 520, 520, 524, 524, 524, 525, + 525, 525, 526, 526, 526, 367, 367, 367, 531, 531, + 531, 450, 450, 1458, 1458, 450, 536, 536, 536, 540, + 540, 540, 544, 1458, 544, 545, 545, 545, 549, 549, + 549, 553, 1458, 553, 601, 601, 601, 452, 452, 452, + 609, 609, 609, 610, 610, 610, 618, 618, 618, 622, + 1458, 622, 625, 1458, 625, 626, 626, 626, 630, 630, + 630, 634, 1458, 634, 543, 543, 1458, 1458, 543, 547, + + 547, 1458, 1458, 547, 640, 640, 640, 644, 644, 644, + 553, 553, 1458, 553, 525, 525, 525, 678, 678, 678, + 682, 682, 682, 685, 685, 685, 686, 686, 686, 687, + 687, 687, 692, 692, 692, 616, 616, 1458, 1458, 616, + 697, 697, 697, 701, 701, 701, 622, 622, 1458, 622, + 624, 624, 1458, 1458, 624, 625, 625, 1458, 625, 626, + 626, 628, 628, 1458, 1458, 628, 708, 708, 708, 712, + 712, 712, 634, 634, 1458, 634, 716, 1458, 716, 719, + 1458, 719, 720, 720, 720, 724, 724, 724, 728, 1458, + 728, 755, 755, 755, 618, 618, 618, 630, 630, 630, + + 766, 766, 766, 767, 767, 767, 775, 775, 775, 779, + 1458, 779, 782, 1458, 782, 783, 783, 783, 787, 787, + 787, 791, 1458, 791, 794, 1458, 794, 797, 1458, 797, + 798, 798, 798, 802, 802, 802, 806, 1458, 806, 715, + 1458, 1458, 715, 716, 716, 1458, 716, 718, 718, 1458, + 1458, 718, 719, 719, 1458, 719, 720, 720, 722, 722, + 1458, 1458, 722, 813, 813, 813, 817, 817, 817, 728, + 728, 1458, 728, 53, 53, 53, 1458, 53, 53, 686, + 686, 686, 839, 839, 839, 843, 843, 843, 846, 846, + 846, 849, 849, 849, 850, 850, 850, 851, 851, 851, + + 856, 856, 856, 773, 773, 1458, 1458, 773, 861, 861, + 861, 865, 865, 865, 779, 779, 1458, 779, 781, 781, + 1458, 1458, 781, 782, 782, 1458, 782, 783, 783, 785, + 785, 1458, 1458, 785, 872, 872, 872, 876, 876, 876, + 791, 791, 1458, 791, 793, 1458, 1458, 793, 794, 794, + 1458, 794, 796, 796, 1458, 1458, 796, 797, 797, 1458, + 797, 798, 798, 800, 800, 1458, 1458, 800, 884, 884, + 884, 888, 888, 888, 806, 806, 1458, 806, 890, 1458, + 890, 893, 1458, 893, 896, 1458, 896, 897, 897, 897, + 901, 901, 901, 905, 1458, 905, 53, 53, 53, 1458, + + 53, 53, 923, 923, 923, 775, 775, 775, 787, 787, + 787, 802, 802, 802, 937, 937, 937, 938, 938, 938, + 946, 946, 946, 950, 1458, 950, 953, 1458, 953, 954, + 954, 954, 958, 958, 958, 962, 1458, 962, 965, 1458, + 965, 968, 1458, 968, 969, 969, 969, 973, 973, 973, + 977, 1458, 977, 978, 1458, 978, 981, 1458, 981, 984, + 1458, 984, 985, 985, 985, 989, 989, 989, 993, 1458, + 993, 890, 1458, 890, 892, 1458, 1458, 892, 893, 893, + 1458, 893, 895, 895, 1458, 1458, 895, 896, 896, 1458, + 896, 897, 897, 899, 899, 1458, 1458, 899, 1000, 1000, + + 1000, 1004, 1004, 1004, 905, 905, 1458, 905, 53, 53, + 53, 1458, 53, 53, 850, 850, 850, 1021, 1021, 1021, + 1025, 1025, 1025, 1028, 1028, 1028, 1031, 1031, 1031, 1034, + 1034, 1034, 1035, 1035, 1035, 1043, 1043, 1043, 944, 944, + 1458, 1458, 944, 1048, 1048, 1048, 1052, 1052, 1052, 950, + 950, 1458, 950, 952, 952, 1458, 1458, 952, 953, 953, + 1458, 953, 954, 954, 956, 956, 1458, 1458, 956, 1059, + 1059, 1059, 1063, 1063, 1063, 962, 962, 1458, 962, 964, + 1458, 1458, 964, 965, 965, 1458, 965, 967, 967, 1458, + 1458, 967, 968, 968, 1458, 968, 969, 969, 971, 971, + + 1458, 1458, 971, 1071, 1071, 1071, 1075, 1075, 1075, 977, + 977, 1458, 977, 978, 1458, 978, 980, 1458, 1458, 980, + 981, 981, 1458, 981, 983, 983, 1458, 1458, 983, 984, + 984, 1458, 984, 985, 985, 987, 987, 1458, 1458, 987, + 1083, 1083, 1083, 1087, 1087, 1087, 993, 993, 1458, 993, + 1089, 1458, 1089, 1092, 1458, 1092, 1095, 1458, 1095, 1096, + 1096, 1096, 1100, 1100, 1100, 1104, 1458, 1104, 53, 53, + 53, 1458, 53, 53, 1116, 1116, 1116, 946, 946, 946, + 958, 958, 958, 973, 973, 973, 989, 989, 989, 1133, + 1133, 1133, 1139, 1139, 1139, 1137, 1137, 1137, 1144, 1144, + + 1144, 1143, 1143, 1143, 1145, 1458, 1145, 1148, 1458, 1148, + 1149, 1149, 1149, 1154, 1154, 1154, 1153, 1153, 1153, 1155, + 1458, 1155, 1158, 1458, 1158, 1161, 1458, 1161, 1162, 1162, + 1162, 1167, 1167, 1167, 1166, 1166, 1166, 1168, 1458, 1168, + 1169, 1458, 1169, 1172, 1458, 1172, 1175, 1458, 1175, 1176, + 1176, 1176, 1181, 1181, 1181, 1180, 1180, 1180, 1182, 1458, + 1182, 1183, 1458, 1183, 1186, 1458, 1186, 1189, 1458, 1189, + 1190, 1190, 1190, 1195, 1195, 1195, 1194, 1194, 1194, 1196, + 1458, 1196, 1089, 1458, 1089, 1091, 1458, 1458, 1091, 1092, + 1092, 1458, 1092, 1094, 1094, 1458, 1458, 1094, 1095, 1095, + + 1458, 1095, 1096, 1096, 1098, 1098, 1458, 1458, 1098, 1203, + 1203, 1203, 1207, 1207, 1207, 1104, 1104, 1458, 1104, 53, + 53, 53, 1458, 53, 53, 1035, 1035, 1035, 1223, 1223, + 1223, 1226, 1226, 1226, 1229, 1229, 1229, 1232, 1232, 1232, + 1235, 1235, 1235, 1240, 1240, 1240, 1239, 1239, 1239, 1242, + 1458, 1242, 1243, 1243, 1243, 1141, 1141, 1458, 1458, 1141, + 1247, 1247, 1247, 1248, 1248, 1248, 1145, 1145, 1458, 1145, + 1147, 1147, 1458, 1458, 1147, 1148, 1148, 1458, 1148, 1149, + 1149, 1151, 1151, 1458, 1458, 1151, 1254, 1254, 1254, 1255, + 1255, 1255, 1155, 1155, 1458, 1155, 1157, 1458, 1458, 1157, + + 1158, 1158, 1458, 1158, 1160, 1160, 1458, 1458, 1160, 1161, + 1161, 1458, 1161, 1162, 1162, 1164, 1164, 1458, 1458, 1164, + 1262, 1262, 1262, 1263, 1263, 1263, 1168, 1168, 1458, 1168, + 1169, 1458, 1169, 1171, 1458, 1458, 1171, 1172, 1172, 1458, + 1172, 1174, 1174, 1458, 1458, 1174, 1175, 1175, 1458, 1175, + 1176, 1176, 1178, 1178, 1458, 1458, 1178, 1270, 1270, 1270, + 1271, 1271, 1271, 1182, 1182, 1458, 1182, 1183, 1458, 1183, + 1185, 1458, 1458, 1185, 1186, 1186, 1458, 1186, 1188, 1188, + 1458, 1458, 1188, 1189, 1189, 1458, 1189, 1190, 1190, 1192, + 1192, 1458, 1458, 1192, 1278, 1278, 1278, 1279, 1279, 1279, + + 1196, 1196, 1458, 1196, 1280, 1458, 1280, 1283, 1458, 1283, + 1286, 1458, 1286, 1287, 1287, 1287, 1292, 1458, 1292, 1291, + 1291, 1291, 1293, 1458, 1293, 53, 53, 53, 1458, 53, + 53, 1301, 1458, 1301, 1300, 1300, 1300, 1302, 1458, 1302, + 1143, 1143, 1143, 1303, 1458, 1303, 1153, 1153, 1153, 1304, + 1458, 1304, 1166, 1166, 1166, 1305, 1458, 1305, 1180, 1180, + 1180, 1306, 1458, 1306, 1194, 1194, 1194, 1237, 1237, 1458, + 1458, 1237, 1310, 1310, 1310, 1311, 1311, 1311, 367, 367, + 367, 1242, 1242, 1458, 1242, 1312, 1312, 1312, 1315, 1458, + 1315, 1316, 1316, 1316, 1317, 1317, 1317, 1320, 1458, 1320, + + 1323, 1458, 1323, 1324, 1324, 1324, 1325, 1325, 1325, 1326, + 1458, 1326, 1329, 1458, 1329, 1332, 1458, 1332, 1333, 1333, + 1333, 1334, 1334, 1334, 1335, 1458, 1335, 1338, 1458, 1338, + 1341, 1458, 1341, 1342, 1342, 1342, 1343, 1343, 1343, 1344, + 1458, 1344, 1347, 1458, 1347, 1350, 1458, 1350, 1351, 1351, + 1351, 1352, 1352, 1352, 1280, 1458, 1280, 1282, 1458, 1458, + 1282, 1283, 1283, 1458, 1283, 1285, 1285, 1458, 1458, 1285, + 1286, 1286, 1458, 1286, 1287, 1287, 1289, 1289, 1458, 1458, + 1289, 1359, 1359, 1359, 1360, 1458, 1360, 1293, 1293, 1458, + 1293, 53, 53, 53, 1458, 53, 53, 1365, 1365, 1365, + + 1239, 1239, 1239, 1367, 1458, 1367, 1368, 1458, 1368, 1369, + 1458, 1369, 1370, 1458, 1370, 1371, 1458, 1371, 1372, 1458, + 1372, 1375, 1458, 1375, 1376, 1376, 1376, 1377, 1377, 1377, + 1378, 1458, 1378, 1314, 1314, 1458, 1458, 1314, 1315, 1315, + 1458, 1315, 1316, 1316, 1381, 1458, 1381, 1319, 1458, 1458, + 1319, 1320, 1320, 1458, 1320, 1322, 1322, 1458, 1458, 1322, + 1323, 1323, 1458, 1323, 1324, 1324, 1385, 1458, 1385, 1326, + 1458, 1326, 1328, 1458, 1458, 1328, 1329, 1329, 1458, 1329, + 1331, 1331, 1458, 1458, 1331, 1332, 1332, 1458, 1332, 1333, + 1333, 1389, 1458, 1389, 1335, 1458, 1335, 1337, 1458, 1458, + + 1337, 1338, 1338, 1458, 1338, 1340, 1340, 1458, 1458, 1340, + 1341, 1341, 1458, 1341, 1342, 1342, 1393, 1458, 1393, 1344, + 1458, 1344, 1346, 1458, 1458, 1346, 1347, 1347, 1458, 1347, + 1349, 1349, 1458, 1458, 1349, 1350, 1350, 1458, 1350, 1351, + 1351, 1397, 1458, 1397, 1398, 1458, 1398, 1401, 1458, 1401, + 1404, 1458, 1404, 1405, 1405, 1405, 1406, 1458, 1406, 53, + 53, 53, 1458, 53, 53, 1410, 1458, 1410, 1312, 1458, + 1312, 1317, 1458, 1317, 1325, 1458, 1325, 1334, 1458, 1334, + 1343, 1458, 1343, 1352, 1458, 1352, 1374, 1374, 1458, 1458, + 1374, 1375, 1375, 1458, 1375, 1376, 1376, 1366, 1458, 1366, + + 1415, 1458, 1415, 1416, 1458, 1416, 1419, 1458, 1419, 1420, + 1458, 1420, 1423, 1458, 1423, 1424, 1458, 1424, 1427, 1458, + 1427, 1428, 1458, 1428, 1431, 1458, 1431, 1400, 1458, 1458, + 1400, 1403, 1403, 1458, 1458, 1403, 1435, 1458, 1435, 1377, + 1458, 1377, 1439, 1458, 1439, 1414, 1458, 1458, 1414, 1418, + 1458, 1458, 1418, 1422, 1458, 1458, 1422, 1426, 1458, 1458, + 1426, 1430, 1458, 1458, 1430, 1445, 1458, 1445, 1448, 1458, + 1448, 1438, 1458, 1458, 1438, 1450, 1458, 1450, 1451, 1458, + 1451, 1452, 1458, 1452, 1453, 1458, 1453, 1454, 1458, 1454, + 1447, 1458, 1458, 1447, 1456, 1458, 1456, 1457, 1458, 1457, + + 3, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458 + } ; + +static yyconst flex_int16_t yy_chk[7455] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4, 7, 15, 4, 7, 4, 7, + 9, 4, 7, 9, 34, 9, 17, 17, 9, 19, + 19, 4, 7, 34, 24, 27, 27, 105, 9, 4, + 7, 15, 12, 105, 133, 12, 9, 12, 24, 23, + 12, 23, 23, 26, 28, 24, 23, 26, 1242, 28, + + 12, 23, 133, 26, 29, 23, 26, 23, 12, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 94, + 29, 94, 14, 14, 14, 265, 265, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 16, 36, 25, 16, 1243, 16, 36, 36, + 16, 36, 36, 93, 25, 101, 93, 25, 97, 22, + 16, 25, 22, 97, 22, 431, 431, 22, 16, 20, + 20, 20, 20, 20, 20, 20, 20, 22, 33, 30, + 137, 30, 33, 20, 35, 22, 30, 30, 101, 30, + + 137, 33, 33, 30, 41, 33, 35, 33, 35, 106, + 35, 250, 41, 35, 106, 249, 41, 249, 41, 20, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 32, 32, 1247, 21, 83, 250, 39, 102, 39, 21, + 21, 21, 21, 21, 21, 31, 32, 1248, 31, 31, + 32, 31, 39, 31, 32, 31, 32, 31, 37, 39, + 31, 83, 37, 32, 102, 128, 38, 83, 109, 102, + 37, 109, 38, 109, 38, 37, 38, 37, 128, 135, + 38, 44, 38, 38, 44, 655, 44, 655, 135, 44, + 62, 62, 62, 62, 62, 62, 62, 63, 154, 44, + + 63, 336, 63, 220, 652, 63, 336, 44, 48, 48, + 48, 48, 48, 48, 48, 63, 220, 162, 272, 48, + 348, 373, 652, 63, 154, 48, 48, 48, 48, 48, + 48, 49, 49, 49, 49, 49, 49, 49, 433, 440, + 1254, 446, 49, 162, 272, 454, 348, 373, 49, 49, + 49, 49, 49, 49, 50, 50, 50, 50, 50, 50, + 50, 50, 460, 1255, 433, 440, 50, 446, 596, 596, + 460, 454, 50, 50, 50, 50, 50, 50, 52, 52, + 52, 52, 52, 52, 52, 52, 54, 54, 54, 54, + 54, 54, 54, 282, 282, 282, 282, 54, 406, 647, + + 647, 479, 409, 54, 54, 54, 54, 54, 54, 56, + 479, 406, 56, 282, 56, 352, 409, 56, 368, 369, + 56, 56, 56, 56, 56, 56, 56, 56, 511, 352, + 648, 56, 368, 369, 1262, 56, 648, 56, 56, 56, + 56, 56, 56, 152, 481, 152, 152, 152, 152, 152, + 152, 152, 535, 481, 511, 352, 152, 551, 368, 369, + 535, 657, 152, 152, 152, 152, 152, 152, 153, 153, + 153, 153, 153, 153, 153, 153, 545, 639, 1263, 657, + 153, 604, 153, 551, 545, 639, 153, 153, 153, 153, + 153, 153, 264, 264, 264, 264, 264, 264, 264, 275, + + 275, 275, 275, 275, 275, 275, 449, 604, 153, 155, + 155, 155, 155, 155, 155, 155, 155, 607, 613, 1270, + 449, 155, 554, 554, 554, 554, 1271, 155, 155, 155, + 155, 155, 155, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 1278, 607, 613, 156, 449, 620, 632, 666, + 666, 156, 156, 156, 156, 156, 156, 157, 157, 157, + 157, 157, 157, 157, 157, 159, 159, 159, 159, 159, + 159, 159, 159, 620, 632, 649, 159, 673, 650, 714, + 649, 650, 159, 159, 159, 159, 159, 159, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 656, 1279, 1283, + + 161, 656, 161, 673, 306, 714, 161, 161, 161, 161, + 161, 161, 306, 358, 358, 358, 358, 358, 358, 358, + 1286, 1287, 450, 1291, 515, 306, 729, 653, 161, 258, + 258, 258, 258, 258, 258, 258, 450, 653, 515, 726, + 258, 306, 1293, 731, 729, 1299, 258, 258, 258, 258, + 258, 258, 260, 260, 260, 260, 260, 260, 260, 651, + 675, 731, 450, 260, 515, 726, 758, 761, 651, 260, + 260, 260, 260, 260, 260, 261, 261, 261, 261, 261, + 261, 261, 261, 263, 263, 263, 263, 263, 263, 263, + 696, 707, 758, 761, 263, 764, 675, 730, 696, 707, + + 263, 263, 263, 263, 263, 263, 266, 266, 266, 266, + 266, 266, 266, 266, 1300, 730, 1310, 1311, 266, 1315, + 1316, 764, 730, 1320, 266, 266, 266, 266, 266, 266, + 268, 268, 268, 268, 268, 268, 268, 268, 271, 271, + 271, 271, 271, 271, 271, 271, 271, 812, 341, 542, + 271, 1323, 271, 341, 1324, 812, 271, 271, 271, 271, + 271, 271, 341, 542, 341, 341, 770, 341, 362, 362, + 362, 362, 362, 362, 362, 741, 543, 732, 271, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 1329, 542, + 543, 276, 770, 741, 741, 732, 546, 276, 276, 276, + + 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, + 546, 1332, 732, 1333, 277, 1338, 543, 737, 1341, 743, + 277, 277, 277, 277, 277, 277, 346, 547, 346, 346, + 346, 346, 346, 346, 346, 737, 546, 743, 1342, 346, + 737, 547, 744, 738, 748, 346, 346, 346, 346, 346, + 346, 347, 347, 347, 347, 347, 347, 347, 347, 1347, + 744, 738, 748, 347, 738, 347, 1350, 547, 1351, 347, + 347, 347, 347, 347, 347, 430, 430, 430, 430, 430, + 430, 430, 458, 458, 458, 458, 458, 458, 458, 615, + 665, 347, 349, 349, 349, 349, 349, 349, 349, 349, + + 665, 1359, 1375, 615, 349, 1376, 819, 739, 1401, 616, + 349, 349, 349, 349, 349, 349, 353, 353, 353, 353, + 353, 353, 353, 616, 819, 739, 777, 353, 739, 615, + 750, 750, 742, 353, 353, 353, 353, 353, 353, 354, + 354, 354, 354, 354, 354, 354, 354, 1404, 750, 616, + 742, 354, 777, 742, 789, 792, 1415, 354, 354, 354, + 354, 354, 354, 355, 355, 355, 355, 355, 355, 355, + 355, 357, 357, 357, 357, 357, 357, 357, 804, 860, + 789, 792, 357, 1419, 820, 821, 1423, 860, 357, 357, + 357, 357, 357, 357, 361, 361, 361, 361, 361, 361, + + 361, 361, 820, 821, 804, 361, 1427, 820, 821, 822, + 824, 361, 361, 361, 361, 361, 361, 363, 363, 363, + 363, 363, 363, 363, 363, 363, 871, 822, 824, 363, + 1431, 826, 822, 824, 871, 363, 363, 363, 363, 363, + 363, 364, 364, 364, 364, 364, 364, 364, 364, 826, + 1439, 1448, 364, 835, 826, 827, 829, 831, 364, 364, + 364, 364, 364, 364, 370, 370, 370, 370, 370, 370, + 370, 370, 370, 827, 829, 831, 370, 829, 827, 835, + 913, 916, 370, 370, 370, 370, 370, 370, 372, 372, + 372, 372, 372, 372, 372, 372, 372, 883, 913, 916, + + 372, 891, 372, 913, 903, 883, 372, 372, 372, 372, + 372, 372, 462, 462, 462, 462, 462, 462, 462, 528, + 528, 528, 528, 528, 528, 528, 1241, 891, 372, 392, + 903, 926, 1240, 392, 929, 917, 392, 910, 623, 392, + 624, 392, 392, 392, 392, 424, 424, 424, 424, 424, + 424, 424, 623, 917, 624, 910, 424, 926, 910, 918, + 929, 658, 424, 424, 424, 424, 424, 424, 426, 426, + 426, 426, 426, 426, 426, 658, 999, 918, 623, 426, + 624, 932, 935, 941, 999, 426, 426, 426, 426, 426, + 426, 427, 427, 427, 427, 427, 427, 427, 427, 429, + + 429, 429, 429, 429, 429, 429, 948, 932, 935, 941, + 429, 960, 915, 922, 1239, 1009, 429, 429, 429, 429, + 429, 429, 432, 432, 432, 432, 432, 432, 432, 432, + 915, 922, 948, 1009, 432, 1235, 432, 960, 915, 1232, + 432, 432, 432, 432, 432, 432, 533, 533, 533, 533, + 533, 533, 533, 537, 537, 537, 537, 537, 537, 537, + 733, 627, 432, 434, 434, 434, 434, 434, 434, 434, + 963, 1229, 975, 979, 434, 627, 991, 1226, 733, 661, + 434, 434, 434, 434, 434, 434, 435, 435, 435, 435, + 435, 435, 435, 661, 1223, 733, 963, 435, 975, 979, + + 1037, 627, 991, 435, 435, 435, 435, 435, 435, 436, + 436, 436, 436, 436, 436, 436, 436, 439, 439, 439, + 439, 439, 439, 439, 439, 439, 1037, 628, 1220, 439, + 1207, 439, 1203, 1196, 1195, 439, 439, 439, 439, 439, + 439, 628, 635, 635, 635, 635, 635, 635, 635, 637, + 637, 637, 637, 637, 637, 637, 1017, 439, 445, 445, + 445, 445, 445, 445, 445, 445, 445, 628, 1194, 1190, + 445, 1189, 445, 1186, 1017, 664, 445, 445, 445, 445, + 445, 445, 641, 641, 641, 641, 641, 641, 641, 664, + 689, 689, 689, 689, 689, 689, 689, 734, 445, 451, + + 451, 451, 451, 451, 451, 451, 451, 451, 1182, 1181, + 1090, 451, 1180, 1102, 1119, 734, 1012, 451, 451, 451, + 451, 451, 451, 453, 453, 453, 453, 453, 453, 453, + 453, 453, 734, 1176, 1012, 453, 1090, 453, 1012, 1102, + 1119, 453, 453, 453, 453, 453, 453, 694, 694, 694, + 694, 694, 694, 694, 698, 698, 698, 698, 698, 698, + 698, 717, 736, 453, 463, 463, 463, 463, 463, 463, + 463, 463, 463, 1175, 1172, 717, 463, 1122, 1015, 1168, + 736, 718, 463, 463, 463, 463, 463, 463, 464, 464, + 464, 464, 464, 464, 464, 718, 1015, 736, 1167, 464, + + 1015, 717, 1016, 1122, 1105, 464, 464, 464, 464, 464, + 464, 509, 721, 509, 509, 509, 509, 509, 509, 509, + 1016, 718, 1105, 1166, 509, 1016, 721, 1162, 1161, 1108, + 509, 509, 509, 509, 509, 509, 510, 510, 510, 510, + 510, 510, 510, 510, 1158, 1047, 1105, 1108, 510, 1108, + 510, 1155, 721, 1047, 510, 510, 510, 510, 510, 510, + 703, 703, 703, 703, 703, 703, 703, 705, 705, 705, + 705, 705, 705, 705, 722, 825, 510, 512, 512, 512, + 512, 512, 512, 512, 512, 1125, 1058, 1154, 722, 512, + 1128, 1153, 1131, 825, 1058, 512, 512, 512, 512, 512, + + 512, 516, 516, 516, 516, 516, 516, 516, 516, 1070, + 825, 1125, 1149, 516, 722, 1156, 1128, 1070, 1131, 516, + 516, 516, 516, 516, 516, 517, 517, 517, 517, 517, + 517, 517, 517, 518, 518, 518, 518, 518, 518, 518, + 1082, 1156, 1148, 1145, 518, 1170, 1184, 1218, 1082, 1144, + 518, 518, 518, 518, 518, 518, 519, 519, 519, 519, + 519, 519, 519, 519, 521, 521, 521, 521, 521, 521, + 521, 1170, 1184, 1218, 1281, 521, 1318, 1327, 1106, 1107, + 1109, 521, 521, 521, 521, 521, 521, 522, 522, 522, + 522, 522, 522, 522, 522, 522, 1106, 1107, 1109, 522, + + 1281, 1112, 1318, 1327, 772, 522, 522, 522, 522, 522, + 522, 523, 523, 523, 523, 523, 523, 523, 772, 1112, + 1106, 1107, 523, 1143, 1112, 1113, 1139, 1137, 523, 523, + 523, 523, 523, 523, 527, 527, 527, 527, 527, 527, + 527, 527, 1136, 1113, 772, 527, 1133, 1132, 1129, 1209, + 1110, 527, 527, 527, 527, 527, 527, 529, 529, 529, + 529, 529, 529, 529, 529, 529, 1202, 1209, 1110, 529, + 1126, 1123, 1210, 1211, 1202, 529, 529, 529, 529, 529, + 529, 530, 530, 530, 530, 530, 530, 530, 530, 1110, + 1210, 1211, 530, 1120, 1116, 1212, 1213, 1295, 530, 530, + + 530, 530, 530, 530, 538, 538, 538, 538, 538, 538, + 538, 538, 538, 1212, 1213, 1295, 538, 1104, 1295, 1213, + 1296, 1103, 538, 538, 538, 538, 538, 538, 539, 539, + 539, 539, 539, 539, 539, 539, 1246, 1100, 1296, 539, + 1336, 1296, 1096, 1297, 1246, 539, 539, 539, 539, 539, + 539, 548, 548, 548, 548, 548, 548, 548, 548, 548, + 1253, 1297, 1345, 548, 1399, 1413, 1336, 1095, 1253, 548, + 548, 548, 548, 548, 548, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 1261, 1297, 1092, 550, 1345, 550, + 1399, 1413, 1261, 550, 550, 550, 550, 550, 550, 709, + + 709, 709, 709, 709, 709, 709, 715, 715, 715, 715, + 715, 715, 715, 823, 773, 550, 590, 590, 590, 590, + 590, 590, 590, 1417, 1269, 1421, 1425, 590, 773, 1087, + 1364, 823, 1269, 590, 590, 590, 590, 590, 590, 592, + 592, 592, 592, 592, 592, 592, 823, 1277, 1364, 1417, + 592, 1421, 1425, 1429, 773, 1277, 592, 592, 592, 592, + 592, 592, 593, 593, 593, 593, 593, 593, 593, 593, + 595, 595, 595, 595, 595, 595, 595, 1309, 1358, 1429, + 1437, 595, 1446, 1214, 1407, 1309, 1358, 595, 595, 595, + 595, 595, 595, 597, 597, 597, 597, 597, 597, 597, + + 597, 1214, 1407, 1086, 1083, 597, 1437, 1075, 1446, 1074, + 1214, 597, 597, 597, 597, 597, 597, 598, 598, 598, + 598, 598, 598, 598, 598, 599, 599, 599, 599, 599, + 599, 599, 1405, 1071, 1063, 1062, 599, 1059, 1052, 1051, + 1405, 1048, 599, 599, 599, 599, 599, 599, 600, 600, + 600, 600, 600, 600, 600, 600, 603, 603, 603, 603, + 603, 603, 603, 603, 603, 735, 780, 781, 603, 1043, + 603, 1409, 1042, 784, 603, 603, 603, 603, 603, 603, + 780, 781, 1039, 735, 1038, 1035, 1034, 784, 1031, 1409, + 745, 1028, 740, 1025, 746, 735, 603, 606, 606, 606, + + 606, 606, 606, 606, 606, 606, 780, 781, 745, 606, + 740, 606, 746, 784, 830, 606, 606, 606, 606, 606, + 606, 745, 740, 1021, 746, 752, 752, 752, 752, 752, + 752, 752, 830, 785, 795, 796, 909, 606, 612, 612, + 612, 612, 612, 612, 612, 612, 612, 785, 795, 796, + 612, 830, 612, 1004, 909, 799, 612, 612, 612, 612, + 612, 612, 793, 793, 793, 793, 793, 793, 793, 799, + 1363, 909, 1000, 785, 795, 796, 800, 993, 612, 617, + 617, 617, 617, 617, 617, 617, 617, 617, 1363, 992, + 800, 617, 989, 985, 1436, 799, 1363, 617, 617, 617, + + 617, 617, 617, 619, 619, 619, 619, 619, 619, 619, + 619, 619, 1436, 984, 981, 619, 800, 619, 977, 976, + 973, 619, 619, 619, 619, 619, 619, 808, 808, 808, + 808, 808, 808, 808, 810, 810, 810, 810, 810, 810, + 810, 894, 911, 619, 629, 629, 629, 629, 629, 629, + 629, 629, 629, 969, 968, 894, 629, 965, 962, 961, + 911, 911, 629, 629, 629, 629, 629, 629, 631, 631, + 631, 631, 631, 631, 631, 631, 631, 958, 911, 954, + 631, 894, 631, 953, 1014, 828, 631, 631, 631, 631, + 631, 631, 814, 814, 814, 814, 814, 814, 814, 950, + + 949, 946, 1014, 828, 942, 895, 898, 912, 631, 642, + 642, 642, 642, 642, 642, 642, 642, 642, 828, 895, + 898, 642, 1014, 938, 937, 912, 899, 642, 642, 642, + 642, 642, 642, 643, 643, 643, 643, 643, 643, 643, + 899, 912, 936, 933, 643, 895, 898, 930, 927, 924, + 643, 643, 643, 643, 643, 643, 646, 646, 646, 646, + 646, 646, 646, 923, 905, 904, 899, 646, 906, 907, + 908, 914, 1011, 646, 646, 646, 646, 646, 646, 853, + 853, 853, 853, 853, 853, 853, 906, 907, 908, 914, + 1011, 646, 669, 901, 669, 669, 669, 669, 669, 669, + + 669, 906, 907, 908, 908, 669, 914, 897, 1010, 1011, + 1114, 669, 669, 669, 669, 669, 669, 858, 858, 858, + 858, 858, 858, 858, 943, 944, 1010, 1294, 1114, 669, + 670, 670, 670, 670, 670, 670, 670, 670, 943, 944, + 1010, 896, 670, 1114, 893, 1294, 888, 884, 670, 670, + 670, 670, 670, 670, 862, 862, 862, 862, 862, 862, + 862, 876, 1294, 872, 943, 944, 670, 671, 671, 671, + 671, 671, 671, 671, 867, 867, 867, 867, 867, 867, + 867, 869, 869, 869, 869, 869, 869, 869, 873, 873, + 873, 873, 873, 873, 873, 879, 879, 879, 879, 879, + + 879, 879, 671, 672, 672, 672, 672, 672, 672, 672, + 865, 861, 856, 851, 672, 850, 849, 846, 843, 839, + 672, 672, 672, 672, 672, 672, 674, 674, 674, 674, + 674, 674, 674, 674, 676, 676, 676, 676, 676, 676, + 676, 676, 817, 813, 806, 805, 676, 802, 798, 797, + 794, 791, 676, 676, 676, 676, 676, 676, 677, 677, + 677, 677, 677, 677, 677, 677, 679, 679, 679, 679, + 679, 679, 679, 790, 787, 783, 782, 679, 779, 778, + 775, 771, 768, 679, 679, 679, 679, 679, 679, 680, + 680, 680, 680, 680, 680, 680, 680, 680, 767, 766, + + 765, 680, 762, 759, 756, 755, 951, 680, 680, 680, + 680, 680, 680, 681, 681, 681, 681, 681, 681, 681, + 951, 728, 727, 724, 681, 720, 719, 716, 712, 708, + 681, 681, 681, 681, 681, 681, 683, 683, 683, 683, + 683, 683, 683, 683, 683, 701, 951, 697, 683, 692, + 687, 686, 685, 952, 683, 683, 683, 683, 683, 683, + 684, 684, 684, 684, 684, 684, 684, 952, 682, 678, + 668, 684, 667, 663, 662, 660, 659, 684, 684, 684, + 684, 684, 684, 688, 688, 688, 688, 688, 688, 688, + 688, 654, 644, 952, 688, 640, 634, 633, 630, 626, + + 688, 688, 688, 688, 688, 688, 690, 690, 690, 690, + 690, 690, 690, 690, 690, 625, 622, 621, 690, 618, + 614, 611, 610, 609, 690, 690, 690, 690, 690, 690, + 691, 691, 691, 691, 691, 691, 691, 691, 608, 605, + 602, 691, 601, 594, 591, 589, 585, 691, 691, 691, + 691, 691, 691, 699, 699, 699, 699, 699, 699, 699, + 699, 699, 581, 580, 579, 699, 578, 574, 573, 571, + 570, 699, 699, 699, 699, 699, 699, 700, 700, 700, + 700, 700, 700, 700, 700, 569, 568, 567, 700, 566, + 565, 564, 563, 562, 700, 700, 700, 700, 700, 700, + + 710, 710, 710, 710, 710, 710, 710, 710, 710, 561, + 560, 557, 710, 556, 555, 553, 552, 549, 710, 710, + 710, 710, 710, 710, 711, 711, 711, 711, 711, 711, + 711, 711, 544, 540, 536, 711, 531, 526, 525, 524, + 520, 711, 711, 711, 711, 711, 711, 723, 723, 723, + 723, 723, 723, 723, 723, 723, 514, 513, 508, 723, + 507, 506, 505, 504, 503, 723, 723, 723, 723, 723, + 723, 725, 725, 725, 725, 725, 725, 725, 725, 725, + 502, 501, 500, 725, 499, 725, 498, 496, 493, 725, + 725, 725, 725, 725, 725, 881, 881, 881, 881, 881, + + 881, 881, 885, 885, 885, 885, 885, 885, 885, 955, + 956, 725, 747, 966, 747, 747, 747, 747, 747, 747, + 747, 492, 491, 955, 956, 747, 490, 966, 489, 488, + 747, 747, 747, 747, 747, 747, 747, 749, 749, 749, + 749, 749, 749, 749, 487, 485, 484, 483, 749, 955, + 956, 482, 480, 966, 749, 749, 749, 749, 749, 749, + 751, 751, 751, 751, 751, 751, 751, 478, 477, 476, + 475, 751, 474, 1362, 473, 472, 470, 751, 751, 751, + 751, 751, 751, 753, 753, 753, 753, 753, 753, 753, + 753, 1362, 469, 468, 465, 753, 461, 457, 456, 455, + + 1362, 753, 753, 753, 753, 753, 753, 754, 754, 754, + 754, 754, 754, 754, 754, 757, 757, 757, 757, 757, + 757, 757, 757, 757, 452, 448, 447, 757, 444, 757, + 443, 442, 441, 757, 757, 757, 757, 757, 757, 892, + 892, 892, 892, 892, 892, 892, 964, 964, 964, 964, + 964, 964, 964, 967, 438, 757, 760, 760, 760, 760, + 760, 760, 760, 760, 760, 437, 970, 967, 760, 428, + 760, 425, 971, 982, 760, 760, 760, 760, 760, 760, + 970, 423, 422, 421, 420, 419, 971, 982, 418, 417, + 416, 415, 1361, 967, 983, 414, 760, 763, 763, 763, + + 763, 763, 763, 763, 763, 763, 970, 413, 983, 763, + 1361, 763, 971, 982, 986, 763, 763, 763, 763, 763, + 763, 980, 980, 980, 980, 980, 980, 980, 986, 1361, + 412, 410, 408, 987, 983, 1093, 407, 763, 769, 769, + 769, 769, 769, 769, 769, 769, 769, 987, 405, 1093, + 769, 404, 769, 401, 986, 1094, 769, 769, 769, 769, + 769, 769, 995, 995, 995, 995, 995, 995, 995, 1094, + 400, 398, 396, 987, 1097, 1093, 1098, 395, 769, 774, + 774, 774, 774, 774, 774, 774, 774, 774, 1097, 394, + 1098, 774, 389, 388, 386, 1094, 385, 774, 774, 774, + + 774, 774, 774, 776, 776, 776, 776, 776, 776, 776, + 776, 776, 384, 383, 1097, 776, 1098, 776, 381, 376, + 375, 776, 776, 776, 776, 776, 776, 997, 997, 997, + 997, 997, 997, 997, 1001, 1001, 1001, 1001, 1001, 1001, + 1001, 1140, 374, 776, 786, 786, 786, 786, 786, 786, + 786, 786, 786, 371, 367, 1140, 786, 365, 360, 359, + 356, 1013, 786, 786, 786, 786, 786, 786, 788, 788, + 788, 788, 788, 788, 788, 788, 788, 1006, 1007, 1013, + 788, 1140, 788, 351, 350, 342, 788, 788, 788, 788, + 788, 788, 340, 1013, 339, 1006, 1007, 1040, 1040, 1040, + + 1040, 1040, 1040, 1040, 1141, 334, 1006, 1007, 788, 801, + 801, 801, 801, 801, 801, 801, 801, 801, 1141, 332, + 330, 801, 329, 328, 327, 326, 325, 801, 801, 801, + 801, 801, 801, 803, 803, 803, 803, 803, 803, 803, + 803, 803, 1008, 1146, 1141, 803, 324, 803, 322, 321, + 1408, 803, 803, 803, 803, 803, 803, 1146, 320, 315, + 1008, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1408, 312, + 1147, 1008, 311, 803, 815, 815, 815, 815, 815, 815, + 815, 815, 815, 1146, 1147, 310, 815, 1408, 307, 300, + 299, 1150, 815, 815, 815, 815, 815, 815, 816, 816, + + 816, 816, 816, 816, 816, 1150, 297, 296, 294, 816, + 1147, 292, 291, 290, 288, 816, 816, 816, 816, 816, + 816, 832, 1151, 832, 832, 832, 832, 832, 832, 832, + 284, 1150, 283, 281, 832, 278, 1151, 274, 273, 832, + 832, 832, 832, 832, 832, 832, 833, 833, 833, 833, + 833, 833, 833, 270, 269, 267, 262, 833, 259, 257, + 256, 254, 1151, 833, 833, 833, 833, 833, 833, 834, + 834, 834, 834, 834, 834, 834, 834, 251, 247, 243, + 241, 834, 239, 834, 238, 236, 235, 834, 834, 834, + 834, 834, 834, 1049, 1049, 1049, 1049, 1049, 1049, 1049, + + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 234, 1159, 834, + 836, 836, 836, 836, 836, 836, 836, 233, 232, 231, + 230, 836, 1159, 228, 226, 224, 223, 836, 836, 836, + 836, 836, 836, 837, 837, 837, 837, 837, 837, 837, + 837, 221, 219, 218, 216, 837, 213, 212, 1159, 211, + 209, 837, 837, 837, 837, 837, 837, 838, 838, 838, + 838, 838, 838, 838, 838, 840, 840, 840, 840, 840, + 840, 840, 207, 206, 203, 202, 840, 200, 199, 198, + 197, 196, 840, 840, 840, 840, 840, 840, 841, 841, + 841, 841, 841, 841, 841, 841, 841, 195, 194, 193, + + 841, 192, 191, 190, 189, 1160, 841, 841, 841, 841, + 841, 841, 842, 842, 842, 842, 842, 842, 842, 1160, + 188, 187, 186, 842, 185, 184, 182, 181, 178, 842, + 842, 842, 842, 842, 842, 844, 844, 844, 844, 844, + 844, 844, 844, 844, 177, 1160, 176, 844, 175, 174, + 173, 172, 1163, 844, 844, 844, 844, 844, 844, 845, + 845, 845, 845, 845, 845, 845, 1163, 171, 169, 166, + 845, 165, 164, 163, 160, 158, 845, 845, 845, 845, + 845, 845, 847, 847, 847, 847, 847, 847, 847, 847, + 847, 149, 1163, 148, 847, 147, 146, 145, 144, 1164, + + 847, 847, 847, 847, 847, 847, 848, 848, 848, 848, + 848, 848, 848, 1164, 143, 141, 139, 848, 138, 136, + 134, 132, 131, 848, 848, 848, 848, 848, 848, 852, + 852, 852, 852, 852, 852, 852, 852, 130, 129, 1164, + 852, 127, 126, 125, 124, 123, 852, 852, 852, 852, + 852, 852, 854, 854, 854, 854, 854, 854, 854, 854, + 854, 122, 120, 118, 854, 117, 116, 115, 114, 113, + 854, 854, 854, 854, 854, 854, 855, 855, 855, 855, + 855, 855, 855, 855, 112, 111, 110, 855, 108, 107, + 100, 99, 98, 855, 855, 855, 855, 855, 855, 863, + + 863, 863, 863, 863, 863, 863, 863, 863, 96, 95, + 92, 863, 91, 90, 89, 88, 87, 863, 863, 863, + 863, 863, 863, 864, 864, 864, 864, 864, 864, 864, + 864, 86, 85, 84, 864, 82, 81, 80, 79, 78, + 864, 864, 864, 864, 864, 864, 874, 874, 874, 874, + 874, 874, 874, 874, 874, 77, 76, 75, 874, 74, + 73, 72, 71, 70, 874, 874, 874, 874, 874, 874, + 875, 875, 875, 875, 875, 875, 875, 875, 69, 67, + 66, 875, 65, 51, 43, 42, 40, 875, 875, 875, + 875, 875, 875, 886, 886, 886, 886, 886, 886, 886, + + 886, 886, 18, 10, 8, 886, 3, 0, 0, 0, + 0, 886, 886, 886, 886, 886, 886, 887, 887, 887, + 887, 887, 887, 887, 887, 0, 0, 0, 887, 0, + 0, 0, 0, 0, 887, 887, 887, 887, 887, 887, + 900, 900, 900, 900, 900, 900, 900, 900, 900, 0, + 0, 0, 900, 0, 0, 0, 0, 0, 900, 900, + 900, 900, 900, 900, 902, 902, 902, 902, 902, 902, + 902, 902, 902, 0, 0, 0, 902, 0, 902, 0, + 0, 0, 902, 902, 902, 902, 902, 902, 1056, 1056, + 1056, 1056, 1056, 1056, 1056, 1060, 1060, 1060, 1060, 1060, + + 1060, 1060, 0, 0, 902, 919, 919, 919, 919, 919, + 919, 919, 919, 919, 0, 0, 0, 0, 919, 0, + 0, 0, 0, 919, 919, 919, 919, 919, 919, 919, + 920, 920, 920, 920, 920, 920, 920, 920, 921, 921, + 921, 921, 921, 921, 921, 921, 921, 1066, 1066, 1066, + 1066, 1066, 1066, 1066, 0, 0, 921, 925, 925, 925, + 925, 925, 925, 925, 925, 925, 0, 0, 0, 925, + 0, 925, 0, 0, 0, 925, 925, 925, 925, 925, + 925, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1072, 1072, + 1072, 1072, 1072, 1072, 1072, 0, 0, 925, 928, 928, + + 928, 928, 928, 928, 928, 928, 928, 0, 0, 0, + 928, 0, 928, 0, 0, 0, 928, 928, 928, 928, + 928, 928, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1080, + 1080, 1080, 1080, 1080, 1080, 1080, 0, 0, 928, 931, + 931, 931, 931, 931, 931, 931, 931, 931, 0, 0, + 0, 931, 0, 931, 0, 0, 0, 931, 931, 931, + 931, 931, 931, 1084, 1084, 1084, 1084, 1084, 1084, 1084, + 1091, 1091, 1091, 1091, 1091, 1091, 1091, 1111, 0, 931, + 934, 934, 934, 934, 934, 934, 934, 934, 934, 0, + 1173, 1174, 934, 0, 934, 1111, 0, 0, 934, 934, + + 934, 934, 934, 934, 1173, 1174, 1111, 1134, 1134, 1134, + 1134, 1134, 1134, 1134, 0, 1177, 0, 0, 0, 1178, + 934, 939, 939, 939, 939, 939, 939, 939, 939, 1177, + 1173, 1174, 939, 1178, 0, 0, 0, 0, 939, 939, + 939, 939, 939, 939, 940, 940, 940, 940, 940, 940, + 940, 940, 940, 0, 0, 1177, 940, 0, 940, 1178, + 0, 0, 940, 940, 940, 940, 940, 940, 1157, 1157, + 1157, 1157, 1157, 1157, 1157, 1171, 1171, 1171, 1171, 1171, + 1171, 1171, 1187, 0, 940, 945, 945, 945, 945, 945, + 945, 945, 945, 945, 0, 0, 1187, 945, 0, 0, + + 0, 0, 0, 945, 945, 945, 945, 945, 945, 947, + 947, 947, 947, 947, 947, 947, 947, 947, 0, 0, + 0, 947, 1187, 947, 0, 0, 1188, 947, 947, 947, + 947, 947, 947, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + 1188, 0, 0, 0, 0, 1191, 0, 1192, 0, 947, + 957, 957, 957, 957, 957, 957, 957, 957, 957, 1191, + 0, 1192, 957, 0, 0, 0, 1188, 0, 957, 957, + 957, 957, 957, 957, 959, 959, 959, 959, 959, 959, + 959, 959, 959, 0, 0, 1191, 959, 1192, 959, 0, + 0, 0, 959, 959, 959, 959, 959, 959, 1198, 1198, + + 1198, 1198, 1198, 1198, 1198, 1200, 1200, 1200, 1200, 1200, + 1200, 1200, 1236, 0, 959, 972, 972, 972, 972, 972, + 972, 972, 972, 972, 0, 0, 1236, 972, 0, 0, + 0, 0, 0, 972, 972, 972, 972, 972, 972, 974, + 974, 974, 974, 974, 974, 974, 974, 974, 0, 0, + 0, 974, 1236, 974, 0, 0, 1237, 974, 974, 974, + 974, 974, 974, 1204, 1204, 1204, 1204, 1204, 1204, 1204, + 1237, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 0, 974, + 988, 988, 988, 988, 988, 988, 988, 988, 988, 0, + 0, 0, 988, 0, 0, 0, 1237, 1215, 988, 988, + + 988, 988, 988, 988, 990, 990, 990, 990, 990, 990, + 990, 990, 990, 1216, 0, 1215, 990, 0, 990, 0, + 0, 0, 990, 990, 990, 990, 990, 990, 1215, 0, + 0, 1216, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 0, + 0, 1284, 1216, 0, 990, 1002, 1002, 1002, 1002, 1002, + 1002, 1002, 1002, 1002, 0, 1284, 0, 1002, 0, 0, + 0, 0, 1285, 1002, 1002, 1002, 1002, 1002, 1002, 1003, + 1003, 1003, 1003, 1003, 1003, 1003, 1285, 0, 0, 0, + 1003, 1284, 0, 0, 0, 0, 1003, 1003, 1003, 1003, + 1003, 1003, 1018, 1018, 1018, 1018, 1018, 1018, 1018, 1018, + + 1018, 0, 1285, 0, 0, 1018, 0, 0, 0, 0, + 1018, 1018, 1018, 1018, 1018, 1018, 1018, 1019, 1019, 1019, + 1019, 1019, 1019, 1019, 1019, 1020, 1020, 1020, 1020, 1020, + 1020, 1020, 1020, 1020, 1251, 1251, 1251, 1251, 1251, 1251, + 1251, 0, 1288, 1020, 1022, 1022, 1022, 1022, 1022, 1022, + 1022, 0, 0, 0, 0, 1022, 1288, 0, 0, 0, + 0, 1022, 1022, 1022, 1022, 1022, 1022, 1023, 1023, 1023, + 1023, 1023, 1023, 1023, 1023, 1023, 0, 0, 0, 1023, + 0, 0, 1288, 0, 1289, 1023, 1023, 1023, 1023, 1023, + 1023, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1289, 0, + + 0, 0, 1024, 0, 0, 0, 0, 0, 1024, 1024, + 1024, 1024, 1024, 1024, 1026, 1026, 1026, 1026, 1026, 1026, + 1026, 1026, 1026, 0, 1289, 0, 1026, 0, 0, 0, + 0, 1313, 1026, 1026, 1026, 1026, 1026, 1026, 1027, 1027, + 1027, 1027, 1027, 1027, 1027, 1313, 0, 0, 0, 1027, + 0, 0, 0, 0, 0, 1027, 1027, 1027, 1027, 1027, + 1027, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, + 0, 1313, 0, 1029, 0, 0, 0, 0, 1314, 1029, + 1029, 1029, 1029, 1029, 1029, 1030, 1030, 1030, 1030, 1030, + 1030, 1030, 1314, 0, 0, 0, 1030, 0, 0, 0, + + 0, 0, 1030, 1030, 1030, 1030, 1030, 1030, 1032, 1032, + 1032, 1032, 1032, 1032, 1032, 1032, 1032, 0, 1314, 0, + 1032, 0, 0, 0, 0, 1321, 1032, 1032, 1032, 1032, + 1032, 1032, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1321, + 0, 0, 0, 1033, 0, 0, 0, 0, 0, 1033, + 1033, 1033, 1033, 1033, 1033, 1036, 1036, 1036, 1036, 1036, + 1036, 1036, 1036, 1036, 0, 1321, 0, 1036, 0, 1036, + 0, 0, 0, 1036, 1036, 1036, 1036, 1036, 1036, 1257, + 1257, 1257, 1257, 1257, 1257, 1257, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1322, 0, 1036, 1041, 1041, 1041, 1041, + + 1041, 1041, 1041, 1041, 1041, 0, 0, 1322, 1041, 0, + 0, 0, 0, 0, 1041, 1041, 1041, 1041, 1041, 1041, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 0, + 0, 0, 1050, 1322, 0, 0, 0, 0, 1050, 1050, + 1050, 1050, 1050, 1050, 1061, 1061, 1061, 1061, 1061, 1061, + 1061, 1061, 1061, 0, 0, 0, 1061, 0, 0, 0, + 0, 0, 1061, 1061, 1061, 1061, 1061, 1061, 1073, 1073, + 1073, 1073, 1073, 1073, 1073, 1073, 1073, 0, 0, 0, + 1073, 0, 0, 0, 0, 0, 1073, 1073, 1073, 1073, + 1073, 1073, 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085, + + 1085, 0, 0, 0, 1085, 0, 0, 0, 0, 0, + 1085, 1085, 1085, 1085, 1085, 1085, 1099, 1099, 1099, 1099, + 1099, 1099, 1099, 1099, 1099, 0, 0, 0, 1099, 0, + 0, 0, 0, 0, 1099, 1099, 1099, 1099, 1099, 1099, + 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 0, + 0, 0, 1101, 0, 1101, 0, 0, 0, 1101, 1101, + 1101, 1101, 1101, 1101, 1265, 1265, 1265, 1265, 1265, 1265, + 1265, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 0, 0, + 1101, 1115, 1115, 1115, 1115, 1115, 1115, 1115, 1115, 1115, + 1273, 1273, 1273, 1273, 1273, 1273, 1273, 0, 1330, 1115, + + 1117, 1117, 1117, 1117, 1117, 1117, 1117, 1117, 0, 0, + 0, 1117, 1330, 0, 0, 0, 0, 1117, 1117, 1117, + 1117, 1117, 1117, 1118, 1118, 1118, 1118, 1118, 1118, 1118, + 1118, 1118, 0, 0, 0, 1118, 0, 1118, 1330, 0, + 0, 1118, 1118, 1118, 1118, 1118, 1118, 1275, 1275, 1275, + 1275, 1275, 1275, 1275, 1282, 1282, 1282, 1282, 1282, 1282, + 1282, 0, 0, 1118, 1121, 1121, 1121, 1121, 1121, 1121, + 1121, 1121, 1121, 0, 0, 0, 1121, 0, 1121, 0, + 0, 0, 1121, 1121, 1121, 1121, 1121, 1121, 1307, 1307, + 1307, 1307, 1307, 1307, 1307, 1319, 1319, 1319, 1319, 1319, + + 1319, 1319, 1331, 0, 1121, 1124, 1124, 1124, 1124, 1124, + 1124, 1124, 1124, 1124, 0, 0, 1331, 1124, 0, 1124, + 0, 0, 1339, 1124, 1124, 1124, 1124, 1124, 1124, 1328, + 1328, 1328, 1328, 1328, 1328, 1328, 1339, 0, 0, 0, + 0, 1340, 1331, 1348, 0, 1124, 1127, 1127, 1127, 1127, + 1127, 1127, 1127, 1127, 1127, 1340, 0, 1348, 1127, 0, + 1127, 0, 1339, 1349, 1127, 1127, 1127, 1127, 1127, 1127, + 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1349, 0, 0, + 0, 1340, 0, 1348, 0, 0, 1127, 1130, 1130, 1130, + 1130, 1130, 1130, 1130, 1130, 1130, 0, 0, 0, 1130, + + 0, 1130, 0, 1349, 0, 1130, 1130, 1130, 1130, 1130, + 1130, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1354, 1354, + 1354, 1354, 1354, 1354, 1354, 1373, 0, 1130, 1135, 1135, + 1135, 1135, 1135, 1135, 1135, 1135, 1135, 0, 0, 1373, + 1135, 0, 0, 0, 0, 0, 1135, 1135, 1135, 1135, + 1135, 1135, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, + 1142, 0, 0, 0, 1142, 1373, 0, 0, 0, 0, + 1142, 1142, 1142, 1142, 1142, 1142, 1152, 1152, 1152, 1152, + 1152, 1152, 1152, 1152, 1152, 0, 0, 0, 1152, 0, + 0, 0, 0, 0, 1152, 1152, 1152, 1152, 1152, 1152, + + 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 0, + 0, 0, 1165, 0, 0, 0, 0, 0, 1165, 1165, + 1165, 1165, 1165, 1165, 1179, 1179, 1179, 1179, 1179, 1179, + 1179, 1179, 1179, 0, 0, 0, 1179, 0, 0, 0, + 0, 0, 1179, 1179, 1179, 1179, 1179, 1179, 1193, 1193, + 1193, 1193, 1193, 1193, 1193, 1193, 1193, 0, 0, 0, + 1193, 0, 0, 0, 0, 0, 1193, 1193, 1193, 1193, + 1193, 1193, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, + 1205, 0, 0, 0, 1205, 0, 0, 0, 0, 0, + 1205, 1205, 1205, 1205, 1205, 1205, 1217, 1217, 1217, 1217, + + 1217, 1217, 1217, 1217, 1217, 0, 0, 0, 1217, 0, + 1217, 0, 0, 1374, 1217, 1217, 1217, 1217, 1217, 1217, + 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1374, 1379, 1379, + 1379, 1379, 1379, 1379, 1379, 0, 1217, 1221, 1221, 1221, + 1221, 1221, 1221, 1221, 1221, 1221, 0, 0, 0, 1221, + 0, 0, 0, 1374, 0, 1221, 1221, 1221, 1221, 1221, + 1221, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, + 0, 0, 0, 1224, 0, 0, 0, 0, 0, 1224, + 1224, 1224, 1224, 1224, 1224, 1227, 1227, 1227, 1227, 1227, + 1227, 1227, 1227, 1227, 0, 0, 0, 1227, 0, 0, + + 0, 0, 0, 1227, 1227, 1227, 1227, 1227, 1227, 1230, + 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 0, 0, + 0, 1230, 0, 0, 0, 0, 0, 1230, 1230, 1230, + 1230, 1230, 1230, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + 1233, 1233, 0, 0, 0, 1233, 0, 0, 0, 0, + 0, 1233, 1233, 1233, 1233, 1233, 1233, 1238, 1238, 1238, + 1238, 1238, 1238, 1238, 1238, 1238, 0, 0, 0, 1238, + 0, 0, 0, 0, 0, 1238, 1238, 1238, 1238, 1238, + 1238, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, + 0, 0, 0, 1290, 0, 0, 0, 0, 0, 1290, + + 1290, 1290, 1290, 1290, 1290, 1298, 1298, 1298, 1298, 1298, + 1298, 1298, 1298, 1298, 0, 0, 0, 1298, 0, 0, + 0, 0, 0, 1298, 1298, 1298, 1298, 1298, 1298, 1383, + 1383, 1383, 1383, 1383, 1383, 1383, 1387, 1387, 1387, 1387, + 1387, 1387, 1387, 1391, 1391, 1391, 1391, 1391, 1391, 1391, + 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1400, 1400, 1400, + 1400, 1400, 1400, 1400, 1402, 1403, 1411, 1411, 1411, 1411, + 1411, 1411, 1411, 0, 0, 0, 0, 0, 1402, 1403, + 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1418, 1418, 1418, + 1418, 1418, 1418, 1418, 1422, 1422, 1422, 1422, 1422, 1422, + + 1422, 0, 0, 0, 1402, 1403, 1426, 1426, 1426, 1426, + 1426, 1426, 1426, 1430, 1430, 1430, 1430, 1430, 1430, 1430, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1438, 1438, 1438, + 1438, 1438, 1438, 1438, 1447, 1447, 1447, 1447, 1447, 1447, + 1447, 1459, 0, 0, 0, 0, 1459, 1459, 1459, 1460, + 0, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1461, 0, + 1461, 1462, 1462, 1462, 1463, 1463, 1463, 1464, 1464, 1464, + 1465, 1465, 1465, 1466, 1466, 1466, 1467, 1467, 1467, 1468, + 1468, 1468, 1469, 1469, 1469, 1470, 1470, 1470, 1471, 0, + 1471, 1472, 1472, 1472, 1473, 1473, 1473, 1474, 1474, 1474, + + 1475, 1475, 1475, 1476, 0, 1476, 1477, 1477, 1477, 1478, + 1478, 0, 0, 1478, 1479, 1479, 1479, 1480, 1480, 1480, + 1481, 1481, 1481, 1482, 1482, 1482, 1483, 1483, 1483, 1484, + 1484, 1484, 1485, 1485, 1485, 1486, 1486, 1486, 1487, 1487, + 1487, 1488, 1488, 0, 0, 1488, 1489, 1489, 1489, 1490, + 1490, 1490, 1491, 0, 1491, 1492, 1492, 1492, 1493, 1493, + 1493, 1494, 0, 1494, 1495, 1495, 1495, 1496, 1496, 1496, + 1497, 1497, 1497, 1498, 1498, 1498, 1499, 1499, 1499, 1500, + 0, 1500, 1501, 0, 1501, 1502, 1502, 1502, 1503, 1503, + 1503, 1504, 0, 1504, 1505, 1505, 0, 0, 1505, 1506, + + 1506, 0, 0, 1506, 1507, 1507, 1507, 1508, 1508, 1508, + 1509, 1509, 0, 1509, 1510, 1510, 1510, 1511, 1511, 1511, + 1512, 1512, 1512, 1513, 1513, 1513, 1514, 1514, 1514, 1515, + 1515, 1515, 1516, 1516, 1516, 1517, 1517, 0, 0, 1517, + 1518, 1518, 1518, 1519, 1519, 1519, 1520, 1520, 0, 1520, + 1521, 1521, 0, 0, 1521, 1522, 1522, 0, 1522, 1523, + 1523, 1524, 1524, 0, 0, 1524, 1525, 1525, 1525, 1526, + 1526, 1526, 1527, 1527, 0, 1527, 1528, 0, 1528, 1529, + 0, 1529, 1530, 1530, 1530, 1531, 1531, 1531, 1532, 0, + 1532, 1533, 1533, 1533, 1534, 1534, 1534, 1535, 1535, 1535, + + 1536, 1536, 1536, 1537, 1537, 1537, 1538, 1538, 1538, 1539, + 0, 1539, 1540, 0, 1540, 1541, 1541, 1541, 1542, 1542, + 1542, 1543, 0, 1543, 1544, 0, 1544, 1545, 0, 1545, + 1546, 1546, 1546, 1547, 1547, 1547, 1548, 0, 1548, 1549, + 0, 0, 1549, 1550, 1550, 0, 1550, 1551, 1551, 0, + 0, 1551, 1552, 1552, 0, 1552, 1553, 1553, 1554, 1554, + 0, 0, 1554, 1555, 1555, 1555, 1556, 1556, 1556, 1557, + 1557, 0, 1557, 1558, 1558, 1558, 0, 1558, 1558, 1559, + 1559, 1559, 1560, 1560, 1560, 1561, 1561, 1561, 1562, 1562, + 1562, 1563, 1563, 1563, 1564, 1564, 1564, 1565, 1565, 1565, + + 1566, 1566, 1566, 1567, 1567, 0, 0, 1567, 1568, 1568, + 1568, 1569, 1569, 1569, 1570, 1570, 0, 1570, 1571, 1571, + 0, 0, 1571, 1572, 1572, 0, 1572, 1573, 1573, 1574, + 1574, 0, 0, 1574, 1575, 1575, 1575, 1576, 1576, 1576, + 1577, 1577, 0, 1577, 1578, 0, 0, 1578, 1579, 1579, + 0, 1579, 1580, 1580, 0, 0, 1580, 1581, 1581, 0, + 1581, 1582, 1582, 1583, 1583, 0, 0, 1583, 1584, 1584, + 1584, 1585, 1585, 1585, 1586, 1586, 0, 1586, 1587, 0, + 1587, 1588, 0, 1588, 1589, 0, 1589, 1590, 1590, 1590, + 1591, 1591, 1591, 1592, 0, 1592, 1593, 1593, 1593, 0, + + 1593, 1593, 1594, 1594, 1594, 1595, 1595, 1595, 1596, 1596, + 1596, 1597, 1597, 1597, 1598, 1598, 1598, 1599, 1599, 1599, + 1600, 1600, 1600, 1601, 0, 1601, 1602, 0, 1602, 1603, + 1603, 1603, 1604, 1604, 1604, 1605, 0, 1605, 1606, 0, + 1606, 1607, 0, 1607, 1608, 1608, 1608, 1609, 1609, 1609, + 1610, 0, 1610, 1611, 0, 1611, 1612, 0, 1612, 1613, + 0, 1613, 1614, 1614, 1614, 1615, 1615, 1615, 1616, 0, + 1616, 1617, 0, 1617, 1618, 0, 0, 1618, 1619, 1619, + 0, 1619, 1620, 1620, 0, 0, 1620, 1621, 1621, 0, + 1621, 1622, 1622, 1623, 1623, 0, 0, 1623, 1624, 1624, + + 1624, 1625, 1625, 1625, 1626, 1626, 0, 1626, 1627, 1627, + 1627, 0, 1627, 1627, 1628, 1628, 1628, 1629, 1629, 1629, + 1630, 1630, 1630, 1631, 1631, 1631, 1632, 1632, 1632, 1633, + 1633, 1633, 1634, 1634, 1634, 1635, 1635, 1635, 1636, 1636, + 0, 0, 1636, 1637, 1637, 1637, 1638, 1638, 1638, 1639, + 1639, 0, 1639, 1640, 1640, 0, 0, 1640, 1641, 1641, + 0, 1641, 1642, 1642, 1643, 1643, 0, 0, 1643, 1644, + 1644, 1644, 1645, 1645, 1645, 1646, 1646, 0, 1646, 1647, + 0, 0, 1647, 1648, 1648, 0, 1648, 1649, 1649, 0, + 0, 1649, 1650, 1650, 0, 1650, 1651, 1651, 1652, 1652, + + 0, 0, 1652, 1653, 1653, 1653, 1654, 1654, 1654, 1655, + 1655, 0, 1655, 1656, 0, 1656, 1657, 0, 0, 1657, + 1658, 1658, 0, 1658, 1659, 1659, 0, 0, 1659, 1660, + 1660, 0, 1660, 1661, 1661, 1662, 1662, 0, 0, 1662, + 1663, 1663, 1663, 1664, 1664, 1664, 1665, 1665, 0, 1665, + 1666, 0, 1666, 1667, 0, 1667, 1668, 0, 1668, 1669, + 1669, 1669, 1670, 1670, 1670, 1671, 0, 1671, 1672, 1672, + 1672, 0, 1672, 1672, 1673, 1673, 1673, 1674, 1674, 1674, + 1675, 1675, 1675, 1676, 1676, 1676, 1677, 1677, 1677, 1678, + 1678, 1678, 1679, 1679, 1679, 1680, 1680, 1680, 1681, 1681, + + 1681, 1682, 1682, 1682, 1683, 0, 1683, 1684, 0, 1684, + 1685, 1685, 1685, 1686, 1686, 1686, 1687, 1687, 1687, 1688, + 0, 1688, 1689, 0, 1689, 1690, 0, 1690, 1691, 1691, + 1691, 1692, 1692, 1692, 1693, 1693, 1693, 1694, 0, 1694, + 1695, 0, 1695, 1696, 0, 1696, 1697, 0, 1697, 1698, + 1698, 1698, 1699, 1699, 1699, 1700, 1700, 1700, 1701, 0, + 1701, 1702, 0, 1702, 1703, 0, 1703, 1704, 0, 1704, + 1705, 1705, 1705, 1706, 1706, 1706, 1707, 1707, 1707, 1708, + 0, 1708, 1709, 0, 1709, 1710, 0, 0, 1710, 1711, + 1711, 0, 1711, 1712, 1712, 0, 0, 1712, 1713, 1713, + + 0, 1713, 1714, 1714, 1715, 1715, 0, 0, 1715, 1716, + 1716, 1716, 1717, 1717, 1717, 1718, 1718, 0, 1718, 1719, + 1719, 1719, 0, 1719, 1719, 1720, 1720, 1720, 1721, 1721, + 1721, 1722, 1722, 1722, 1723, 1723, 1723, 1724, 1724, 1724, + 1725, 1725, 1725, 1726, 1726, 1726, 1727, 1727, 1727, 1728, + 0, 1728, 1729, 1729, 1729, 1730, 1730, 0, 0, 1730, + 1731, 1731, 1731, 1732, 1732, 1732, 1733, 1733, 0, 1733, + 1734, 1734, 0, 0, 1734, 1735, 1735, 0, 1735, 1736, + 1736, 1737, 1737, 0, 0, 1737, 1738, 1738, 1738, 1739, + 1739, 1739, 1740, 1740, 0, 1740, 1741, 0, 0, 1741, + + 1742, 1742, 0, 1742, 1743, 1743, 0, 0, 1743, 1744, + 1744, 0, 1744, 1745, 1745, 1746, 1746, 0, 0, 1746, + 1747, 1747, 1747, 1748, 1748, 1748, 1749, 1749, 0, 1749, + 1750, 0, 1750, 1751, 0, 0, 1751, 1752, 1752, 0, + 1752, 1753, 1753, 0, 0, 1753, 1754, 1754, 0, 1754, + 1755, 1755, 1756, 1756, 0, 0, 1756, 1757, 1757, 1757, + 1758, 1758, 1758, 1759, 1759, 0, 1759, 1760, 0, 1760, + 1761, 0, 0, 1761, 1762, 1762, 0, 1762, 1763, 1763, + 0, 0, 1763, 1764, 1764, 0, 1764, 1765, 1765, 1766, + 1766, 0, 0, 1766, 1767, 1767, 1767, 1768, 1768, 1768, + + 1769, 1769, 0, 1769, 1770, 0, 1770, 1771, 0, 1771, + 1772, 0, 1772, 1773, 1773, 1773, 1774, 0, 1774, 1775, + 1775, 1775, 1776, 0, 1776, 1777, 1777, 1777, 0, 1777, + 1777, 1778, 0, 1778, 1779, 1779, 1779, 1780, 0, 1780, + 1781, 1781, 1781, 1782, 0, 1782, 1783, 1783, 1783, 1784, + 0, 1784, 1785, 1785, 1785, 1786, 0, 1786, 1787, 1787, + 1787, 1788, 0, 1788, 1789, 1789, 1789, 1790, 1790, 0, + 0, 1790, 1791, 1791, 1791, 1792, 1792, 1792, 1793, 1793, + 1793, 1794, 1794, 0, 1794, 1795, 1795, 1795, 1796, 0, + 1796, 1797, 1797, 1797, 1798, 1798, 1798, 1799, 0, 1799, + + 1800, 0, 1800, 1801, 1801, 1801, 1802, 1802, 1802, 1803, + 0, 1803, 1804, 0, 1804, 1805, 0, 1805, 1806, 1806, + 1806, 1807, 1807, 1807, 1808, 0, 1808, 1809, 0, 1809, + 1810, 0, 1810, 1811, 1811, 1811, 1812, 1812, 1812, 1813, + 0, 1813, 1814, 0, 1814, 1815, 0, 1815, 1816, 1816, + 1816, 1817, 1817, 1817, 1818, 0, 1818, 1819, 0, 0, + 1819, 1820, 1820, 0, 1820, 1821, 1821, 0, 0, 1821, + 1822, 1822, 0, 1822, 1823, 1823, 1824, 1824, 0, 0, + 1824, 1825, 1825, 1825, 1826, 0, 1826, 1827, 1827, 0, + 1827, 1828, 1828, 1828, 0, 1828, 1828, 1829, 1829, 1829, + + 1830, 1830, 1830, 1831, 0, 1831, 1832, 0, 1832, 1833, + 0, 1833, 1834, 0, 1834, 1835, 0, 1835, 1836, 0, + 1836, 1837, 0, 1837, 1838, 1838, 1838, 1839, 1839, 1839, + 1840, 0, 1840, 1841, 1841, 0, 0, 1841, 1842, 1842, + 0, 1842, 1843, 1843, 1844, 0, 1844, 1845, 0, 0, + 1845, 1846, 1846, 0, 1846, 1847, 1847, 0, 0, 1847, + 1848, 1848, 0, 1848, 1849, 1849, 1850, 0, 1850, 1851, + 0, 1851, 1852, 0, 0, 1852, 1853, 1853, 0, 1853, + 1854, 1854, 0, 0, 1854, 1855, 1855, 0, 1855, 1856, + 1856, 1857, 0, 1857, 1858, 0, 1858, 1859, 0, 0, + + 1859, 1860, 1860, 0, 1860, 1861, 1861, 0, 0, 1861, + 1862, 1862, 0, 1862, 1863, 1863, 1864, 0, 1864, 1865, + 0, 1865, 1866, 0, 0, 1866, 1867, 1867, 0, 1867, + 1868, 1868, 0, 0, 1868, 1869, 1869, 0, 1869, 1870, + 1870, 1871, 0, 1871, 1872, 0, 1872, 1873, 0, 1873, + 1874, 0, 1874, 1875, 1875, 1875, 1876, 0, 1876, 1877, + 1877, 1877, 0, 1877, 1877, 1878, 0, 1878, 1879, 0, + 1879, 1880, 0, 1880, 1881, 0, 1881, 1882, 0, 1882, + 1883, 0, 1883, 1884, 0, 1884, 1885, 1885, 0, 0, + 1885, 1886, 1886, 0, 1886, 1887, 1887, 1888, 0, 1888, + + 1889, 0, 1889, 1890, 0, 1890, 1891, 0, 1891, 1892, + 0, 1892, 1893, 0, 1893, 1894, 0, 1894, 1895, 0, + 1895, 1896, 0, 1896, 1897, 0, 1897, 1898, 0, 0, + 1898, 1899, 1899, 0, 0, 1899, 1900, 0, 1900, 1901, + 0, 1901, 1902, 0, 1902, 1903, 0, 0, 1903, 1904, + 0, 0, 1904, 1905, 0, 0, 1905, 1906, 0, 0, + 1906, 1907, 0, 0, 1907, 1908, 0, 1908, 1909, 0, + 1909, 1910, 0, 0, 1910, 1911, 0, 1911, 1912, 0, + 1912, 1913, 0, 1913, 1914, 0, 1914, 1915, 0, 1915, + 1916, 0, 0, 1916, 1917, 0, 1917, 1918, 0, 1918, + + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1458, 1458, 1458 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int pcap__flex_debug; +int pcap__flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *pcap_text; +#line 1 "scanner.l" +#line 2 "scanner.l" +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/libpcap/scanner.l,v 1.112 2008-02-06 10:21:30 guy Exp $ (LBL)"; +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#endif /* WIN32 */ + +#include +#include + +#include "pcap-int.h" + +#include "gencode.h" +#ifdef INET6 +#ifdef WIN32 +#include + +#ifdef __MINGW32__ +#include "ip6_misc.h" +#endif +#else /* WIN32 */ +#include /* for "struct sockaddr" in "struct addrinfo" */ +#include /* for "struct addrinfo" */ +#endif /* WIN32 */ + +/* Workaround for AIX 4.3 */ +#if !defined(AI_NUMERICHOST) +#define AI_NUMERICHOST 0x04 +#endif +#endif /*INET6*/ +#include +#include "tokdefs.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +static int stoi(char *); +static inline int xdtoi(int); + +#ifdef FLEX_SCANNER +#define YY_NO_INPUT +#define YY_NO_UNPUT +static YY_BUFFER_STATE in_buffer; +#else +static const char *in_buffer; + +#undef getc +#define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++) +#endif + +#define yylval pcap_lval +extern YYSTYPE yylval; + +#line 2792 "scanner.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int pcap_lex_destroy (void ); + +int pcap_get_debug (void ); + +void pcap_set_debug (int debug_flag ); + +YY_EXTRA_TYPE pcap_get_extra (void ); + +void pcap_set_extra (YY_EXTRA_TYPE user_defined ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int pcap_wrap (void ); +#else +extern int pcap_wrap (void ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( pcap_text, pcap_leng, 1, pcap_out )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( pcap_in )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( pcap_in ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, pcap_in))==0 && ferror(pcap_in)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(pcap_in); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int pcap_lex (void); + +#define YY_DECL int pcap_lex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after pcap_text and pcap_leng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 189 "scanner.l" + +#line 2963 "scanner.c" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! pcap_in ) + pcap_in = stdin; + + if ( ! pcap_out ) + pcap_out = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + pcap_ensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + pcap__create_buffer(pcap_in,YY_BUF_SIZE ); + } + + pcap__load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of pcap_text. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1459 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 7401 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 190 "scanner.l" +return DST; + YY_BREAK +case 2: +YY_RULE_SETUP +#line 191 "scanner.l" +return SRC; + YY_BREAK +case 3: +YY_RULE_SETUP +#line 193 "scanner.l" +return LINK; + YY_BREAK +case 4: +YY_RULE_SETUP +#line 194 "scanner.l" +return LINK; + YY_BREAK +case 5: +YY_RULE_SETUP +#line 195 "scanner.l" +return ARP; + YY_BREAK +case 6: +YY_RULE_SETUP +#line 196 "scanner.l" +return RARP; + YY_BREAK +case 7: +YY_RULE_SETUP +#line 197 "scanner.l" +return IP; + YY_BREAK +case 8: +YY_RULE_SETUP +#line 198 "scanner.l" +return SCTP; + YY_BREAK +case 9: +YY_RULE_SETUP +#line 199 "scanner.l" +return TCP; + YY_BREAK +case 10: +YY_RULE_SETUP +#line 200 "scanner.l" +return UDP; + YY_BREAK +case 11: +YY_RULE_SETUP +#line 201 "scanner.l" +return ICMP; + YY_BREAK +case 12: +YY_RULE_SETUP +#line 202 "scanner.l" +return IGMP; + YY_BREAK +case 13: +YY_RULE_SETUP +#line 203 "scanner.l" +return IGRP; + YY_BREAK +case 14: +YY_RULE_SETUP +#line 204 "scanner.l" +return PIM; + YY_BREAK +case 15: +YY_RULE_SETUP +#line 205 "scanner.l" +return VRRP; + YY_BREAK +case 16: +YY_RULE_SETUP +#line 206 "scanner.l" +return CARP; + YY_BREAK +case 17: +YY_RULE_SETUP +#line 207 "scanner.l" +return RADIO; + YY_BREAK +case 18: +YY_RULE_SETUP +#line 209 "scanner.l" +return IPV6; + YY_BREAK +case 19: +YY_RULE_SETUP +#line 210 "scanner.l" +return ICMPV6; + YY_BREAK +case 20: +YY_RULE_SETUP +#line 211 "scanner.l" +return AH; + YY_BREAK +case 21: +YY_RULE_SETUP +#line 212 "scanner.l" +return ESP; + YY_BREAK +case 22: +YY_RULE_SETUP +#line 214 "scanner.l" +return ATALK; + YY_BREAK +case 23: +YY_RULE_SETUP +#line 215 "scanner.l" +return AARP; + YY_BREAK +case 24: +YY_RULE_SETUP +#line 216 "scanner.l" +return DECNET; + YY_BREAK +case 25: +YY_RULE_SETUP +#line 217 "scanner.l" +return LAT; + YY_BREAK +case 26: +YY_RULE_SETUP +#line 218 "scanner.l" +return SCA; + YY_BREAK +case 27: +YY_RULE_SETUP +#line 219 "scanner.l" +return MOPRC; + YY_BREAK +case 28: +YY_RULE_SETUP +#line 220 "scanner.l" +return MOPDL; + YY_BREAK +case 29: +YY_RULE_SETUP +#line 222 "scanner.l" +return ISO; + YY_BREAK +case 30: +YY_RULE_SETUP +#line 223 "scanner.l" +return ESIS; + YY_BREAK +case 31: +YY_RULE_SETUP +#line 224 "scanner.l" +return ESIS; + YY_BREAK +case 32: +YY_RULE_SETUP +#line 225 "scanner.l" +return ISIS; + YY_BREAK +case 33: +YY_RULE_SETUP +#line 226 "scanner.l" +return ISIS; + YY_BREAK +case 34: +YY_RULE_SETUP +#line 227 "scanner.l" +return L1; + YY_BREAK +case 35: +YY_RULE_SETUP +#line 228 "scanner.l" +return L2; + YY_BREAK +case 36: +YY_RULE_SETUP +#line 229 "scanner.l" +return IIH; + YY_BREAK +case 37: +YY_RULE_SETUP +#line 230 "scanner.l" +return LSP; + YY_BREAK +case 38: +YY_RULE_SETUP +#line 231 "scanner.l" +return SNP; + YY_BREAK +case 39: +YY_RULE_SETUP +#line 232 "scanner.l" +return CSNP; + YY_BREAK +case 40: +YY_RULE_SETUP +#line 233 "scanner.l" +return PSNP; + YY_BREAK +case 41: +YY_RULE_SETUP +#line 235 "scanner.l" +return CLNP; + YY_BREAK +case 42: +YY_RULE_SETUP +#line 237 "scanner.l" +return STP; + YY_BREAK +case 43: +YY_RULE_SETUP +#line 239 "scanner.l" +return IPX; + YY_BREAK +case 44: +YY_RULE_SETUP +#line 241 "scanner.l" +return NETBEUI; + YY_BREAK +case 45: +YY_RULE_SETUP +#line 243 "scanner.l" +return HOST; + YY_BREAK +case 46: +YY_RULE_SETUP +#line 244 "scanner.l" +return NET; + YY_BREAK +case 47: +YY_RULE_SETUP +#line 245 "scanner.l" +return NETMASK; + YY_BREAK +case 48: +YY_RULE_SETUP +#line 246 "scanner.l" +return PORT; + YY_BREAK +case 49: +YY_RULE_SETUP +#line 247 "scanner.l" +return PORTRANGE; + YY_BREAK +case 50: +YY_RULE_SETUP +#line 248 "scanner.l" +return PROTO; + YY_BREAK +case 51: +YY_RULE_SETUP +#line 249 "scanner.l" +{ +#ifdef NO_PROTOCHAIN + bpf_error("%s not supported", pcap_text); +#else + return PROTOCHAIN; +#endif + } + YY_BREAK +case 52: +YY_RULE_SETUP +#line 257 "scanner.l" +return GATEWAY; + YY_BREAK +case 53: +YY_RULE_SETUP +#line 259 "scanner.l" +return TYPE; + YY_BREAK +case 54: +YY_RULE_SETUP +#line 260 "scanner.l" +return SUBTYPE; + YY_BREAK +case 55: +YY_RULE_SETUP +#line 261 "scanner.l" +return DIR; + YY_BREAK +case 56: +YY_RULE_SETUP +#line 262 "scanner.l" +return ADDR1; + YY_BREAK +case 57: +YY_RULE_SETUP +#line 263 "scanner.l" +return ADDR2; + YY_BREAK +case 58: +YY_RULE_SETUP +#line 264 "scanner.l" +return ADDR3; + YY_BREAK +case 59: +YY_RULE_SETUP +#line 265 "scanner.l" +return ADDR4; + YY_BREAK +case 60: +YY_RULE_SETUP +#line 266 "scanner.l" +return RA; + YY_BREAK +case 61: +YY_RULE_SETUP +#line 267 "scanner.l" +return TA; + YY_BREAK +case 62: +YY_RULE_SETUP +#line 269 "scanner.l" +return LESS; + YY_BREAK +case 63: +YY_RULE_SETUP +#line 270 "scanner.l" +return GREATER; + YY_BREAK +case 64: +YY_RULE_SETUP +#line 271 "scanner.l" +return CBYTE; + YY_BREAK +case 65: +YY_RULE_SETUP +#line 272 "scanner.l" +return TK_BROADCAST; + YY_BREAK +case 66: +YY_RULE_SETUP +#line 273 "scanner.l" +return TK_MULTICAST; + YY_BREAK +case 67: +YY_RULE_SETUP +#line 275 "scanner.l" +return AND; + YY_BREAK +case 68: +YY_RULE_SETUP +#line 276 "scanner.l" +return OR; + YY_BREAK +case 69: +YY_RULE_SETUP +#line 277 "scanner.l" +return '!'; + YY_BREAK +case 70: +YY_RULE_SETUP +#line 279 "scanner.l" +return LEN; + YY_BREAK +case 71: +YY_RULE_SETUP +#line 280 "scanner.l" +return INBOUND; + YY_BREAK +case 72: +YY_RULE_SETUP +#line 281 "scanner.l" +return OUTBOUND; + YY_BREAK +case 73: +YY_RULE_SETUP +#line 283 "scanner.l" +return VLAN; + YY_BREAK +case 74: +YY_RULE_SETUP +#line 284 "scanner.l" +return MPLS; + YY_BREAK +case 75: +YY_RULE_SETUP +#line 285 "scanner.l" +return PPPOED; + YY_BREAK +case 76: +YY_RULE_SETUP +#line 286 "scanner.l" +return PPPOES; + YY_BREAK +case 77: +YY_RULE_SETUP +#line 288 "scanner.l" +return LANE; + YY_BREAK +case 78: +YY_RULE_SETUP +#line 289 "scanner.l" +return LLC; + YY_BREAK +case 79: +YY_RULE_SETUP +#line 290 "scanner.l" +return METAC; + YY_BREAK +case 80: +YY_RULE_SETUP +#line 291 "scanner.l" +return BCC; + YY_BREAK +case 81: +YY_RULE_SETUP +#line 292 "scanner.l" +return OAM; + YY_BREAK +case 82: +YY_RULE_SETUP +#line 293 "scanner.l" +return OAMF4; + YY_BREAK +case 83: +YY_RULE_SETUP +#line 294 "scanner.l" +return OAMF4EC; + YY_BREAK +case 84: +YY_RULE_SETUP +#line 295 "scanner.l" +return OAMF4SC; + YY_BREAK +case 85: +YY_RULE_SETUP +#line 296 "scanner.l" +return SC; + YY_BREAK +case 86: +YY_RULE_SETUP +#line 297 "scanner.l" +return ILMIC; + YY_BREAK +case 87: +YY_RULE_SETUP +#line 298 "scanner.l" +return VPI; + YY_BREAK +case 88: +YY_RULE_SETUP +#line 299 "scanner.l" +return VCI; + YY_BREAK +case 89: +YY_RULE_SETUP +#line 300 "scanner.l" +return CONNECTMSG; + YY_BREAK +case 90: +YY_RULE_SETUP +#line 301 "scanner.l" +return METACONNECT; + YY_BREAK +case 91: +YY_RULE_SETUP +#line 303 "scanner.l" +return PF_IFNAME; + YY_BREAK +case 92: +YY_RULE_SETUP +#line 304 "scanner.l" +return PF_RSET; + YY_BREAK +case 93: +YY_RULE_SETUP +#line 305 "scanner.l" +return PF_RNR; + YY_BREAK +case 94: +YY_RULE_SETUP +#line 306 "scanner.l" +return PF_SRNR; + YY_BREAK +case 95: +YY_RULE_SETUP +#line 307 "scanner.l" +return PF_REASON; + YY_BREAK +case 96: +YY_RULE_SETUP +#line 308 "scanner.l" +return PF_ACTION; + YY_BREAK +case 97: +YY_RULE_SETUP +#line 310 "scanner.l" +return FISU; + YY_BREAK +case 98: +YY_RULE_SETUP +#line 311 "scanner.l" +return LSSU; + YY_BREAK +case 99: +YY_RULE_SETUP +#line 312 "scanner.l" +return LSSU; + YY_BREAK +case 100: +YY_RULE_SETUP +#line 313 "scanner.l" +return MSU; + YY_BREAK +case 101: +YY_RULE_SETUP +#line 314 "scanner.l" +return HFISU; + YY_BREAK +case 102: +YY_RULE_SETUP +#line 315 "scanner.l" +return HLSSU; + YY_BREAK +case 103: +YY_RULE_SETUP +#line 316 "scanner.l" +return HMSU; + YY_BREAK +case 104: +YY_RULE_SETUP +#line 317 "scanner.l" +return SIO; + YY_BREAK +case 105: +YY_RULE_SETUP +#line 318 "scanner.l" +return OPC; + YY_BREAK +case 106: +YY_RULE_SETUP +#line 319 "scanner.l" +return DPC; + YY_BREAK +case 107: +YY_RULE_SETUP +#line 320 "scanner.l" +return SLS; + YY_BREAK +case 108: +YY_RULE_SETUP +#line 321 "scanner.l" +return HSIO; + YY_BREAK +case 109: +YY_RULE_SETUP +#line 322 "scanner.l" +return HOPC; + YY_BREAK +case 110: +YY_RULE_SETUP +#line 323 "scanner.l" +return HDPC; + YY_BREAK +case 111: +YY_RULE_SETUP +#line 324 "scanner.l" +return HSLS; + YY_BREAK +case 112: +/* rule 112 can match eol */ +YY_RULE_SETUP +#line 326 "scanner.l" +; + YY_BREAK +case 113: +YY_RULE_SETUP +#line 327 "scanner.l" +return pcap_text[0]; + YY_BREAK +case 114: +YY_RULE_SETUP +#line 328 "scanner.l" +return GEQ; + YY_BREAK +case 115: +YY_RULE_SETUP +#line 329 "scanner.l" +return LEQ; + YY_BREAK +case 116: +YY_RULE_SETUP +#line 330 "scanner.l" +return NEQ; + YY_BREAK +case 117: +YY_RULE_SETUP +#line 331 "scanner.l" +return '='; + YY_BREAK +case 118: +YY_RULE_SETUP +#line 332 "scanner.l" +return LSH; + YY_BREAK +case 119: +YY_RULE_SETUP +#line 333 "scanner.l" +return RSH; + YY_BREAK +case 120: +YY_RULE_SETUP +#line 334 "scanner.l" +{ yylval.e = pcap_ether_aton(((char *)pcap_text)+1); + if (yylval.e == NULL) + bpf_error("malloc"); + return AID; } + YY_BREAK +case 121: +YY_RULE_SETUP +#line 338 "scanner.l" +{ yylval.e = pcap_ether_aton((char *)pcap_text); + if (yylval.e == NULL) + bpf_error("malloc"); + return EID; } + YY_BREAK +case 122: +YY_RULE_SETUP +#line 342 "scanner.l" +{ yylval.i = stoi((char *)pcap_text); return NUM; } + YY_BREAK +case 123: +YY_RULE_SETUP +#line 343 "scanner.l" +{ + yylval.s = sdup((char *)pcap_text); return HID; } + YY_BREAK +case 124: +YY_RULE_SETUP +#line 345 "scanner.l" +{ +#ifdef INET6 + struct addrinfo hints, *res; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(pcap_text, NULL, &hints, &res)) + bpf_error("bogus IPv6 address %s", pcap_text); + else { + freeaddrinfo(res); + yylval.s = sdup((char *)pcap_text); return HID6; + } +#else + bpf_error("IPv6 address %s not supported", pcap_text); +#endif /*INET6*/ + } + YY_BREAK +case 125: +YY_RULE_SETUP +#line 361 "scanner.l" +{ bpf_error("bogus ethernet address %s", pcap_text); } + YY_BREAK +case 126: +YY_RULE_SETUP +#line 362 "scanner.l" +{ yylval.i = 0; return NUM; } + YY_BREAK +case 127: +YY_RULE_SETUP +#line 363 "scanner.l" +{ yylval.i = 1; return NUM; } + YY_BREAK +case 128: +YY_RULE_SETUP +#line 364 "scanner.l" +{ yylval.i = 0; return NUM; } + YY_BREAK +case 129: +YY_RULE_SETUP +#line 365 "scanner.l" +{ yylval.i = 3; return NUM; } + YY_BREAK +case 130: +YY_RULE_SETUP +#line 366 "scanner.l" +{ yylval.i = 4; return NUM; } + YY_BREAK +case 131: +YY_RULE_SETUP +#line 367 "scanner.l" +{ yylval.i = 5; return NUM; } + YY_BREAK +case 132: +YY_RULE_SETUP +#line 368 "scanner.l" +{ yylval.i = 8; return NUM; } + YY_BREAK +case 133: +YY_RULE_SETUP +#line 369 "scanner.l" +{ yylval.i = 9; return NUM; } + YY_BREAK +case 134: +YY_RULE_SETUP +#line 370 "scanner.l" +{ yylval.i = 10; return NUM; } + YY_BREAK +case 135: +YY_RULE_SETUP +#line 371 "scanner.l" +{ yylval.i = 11; return NUM; } + YY_BREAK +case 136: +YY_RULE_SETUP +#line 372 "scanner.l" +{ yylval.i = 12; return NUM; } + YY_BREAK +case 137: +YY_RULE_SETUP +#line 373 "scanner.l" +{ yylval.i = 13; return NUM; } + YY_BREAK +case 138: +YY_RULE_SETUP +#line 374 "scanner.l" +{ yylval.i = 14; return NUM; } + YY_BREAK +case 139: +YY_RULE_SETUP +#line 375 "scanner.l" +{ yylval.i = 15; return NUM; } + YY_BREAK +case 140: +YY_RULE_SETUP +#line 376 "scanner.l" +{ yylval.i = 16; return NUM; } + YY_BREAK +case 141: +YY_RULE_SETUP +#line 377 "scanner.l" +{ yylval.i = 17; return NUM; } + YY_BREAK +case 142: +YY_RULE_SETUP +#line 378 "scanner.l" +{ yylval.i = 18; return NUM; } + YY_BREAK +case 143: +YY_RULE_SETUP +#line 379 "scanner.l" +{ yylval.i = 13; return NUM; } + YY_BREAK +case 144: +YY_RULE_SETUP +#line 380 "scanner.l" +{ yylval.i = 0x01; return NUM; } + YY_BREAK +case 145: +YY_RULE_SETUP +#line 381 "scanner.l" +{ yylval.i = 0x02; return NUM; } + YY_BREAK +case 146: +YY_RULE_SETUP +#line 382 "scanner.l" +{ yylval.i = 0x04; return NUM; } + YY_BREAK +case 147: +YY_RULE_SETUP +#line 383 "scanner.l" +{ yylval.i = 0x08; return NUM; } + YY_BREAK +case 148: +YY_RULE_SETUP +#line 384 "scanner.l" +{ yylval.i = 0x10; return NUM; } + YY_BREAK +case 149: +YY_RULE_SETUP +#line 385 "scanner.l" +{ yylval.i = 0x20; return NUM; } + YY_BREAK +case 150: +YY_RULE_SETUP +#line 386 "scanner.l" +{ + yylval.s = sdup((char *)pcap_text); return ID; } + YY_BREAK +case 151: +YY_RULE_SETUP +#line 388 "scanner.l" +{ yylval.s = sdup((char *)pcap_text + 1); return ID; } + YY_BREAK +case 152: +YY_RULE_SETUP +#line 389 "scanner.l" +{ + bpf_error("illegal token: %s", pcap_text); } + YY_BREAK +case 153: +YY_RULE_SETUP +#line 391 "scanner.l" +{ bpf_error("illegal char '%c'", *pcap_text); } + YY_BREAK +case 154: +YY_RULE_SETUP +#line 392 "scanner.l" +ECHO; + YY_BREAK +#line 3847 "scanner.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed pcap_in at a new source and called + * pcap_lex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = pcap_in; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( pcap_wrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * pcap_text, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of pcap_lex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + pcap_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + pcap_restart(pcap_in ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) pcap_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1459 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1459 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 1458); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + pcap_restart(pcap_in ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( pcap_wrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve pcap_text */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void pcap_restart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + pcap_ensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + pcap__create_buffer(pcap_in,YY_BUF_SIZE ); + } + + pcap__init_buffer(YY_CURRENT_BUFFER,input_file ); + pcap__load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void pcap__switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * pcap_pop_buffer_state(); + * pcap_push_buffer_state(new_buffer); + */ + pcap_ensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + pcap__load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (pcap_wrap()) processing, but the only time this flag + * is looked at is after pcap_wrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void pcap__load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + pcap_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE pcap__create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) pcap_alloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in pcap__create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) pcap_alloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in pcap__create_buffer()" ); + + b->yy_is_our_buffer = 1; + + pcap__init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with pcap__create_buffer() + * + */ + void pcap__delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + pcap_free((void *) b->yy_ch_buf ); + + pcap_free((void *) b ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a pcap_restart() or at EOF. + */ + static void pcap__init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + pcap__flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then pcap__init_buffer was _probably_ + * called from pcap_restart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void pcap__flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + pcap__load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void pcap_push_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + pcap_ensure_buffer_stack(); + + /* This block is copied from pcap__switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from pcap__switch_to_buffer. */ + pcap__load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void pcap_pop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + pcap__delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + pcap__load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void pcap_ensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)pcap_alloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in pcap_ensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)pcap_realloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in pcap_ensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE pcap__scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) pcap_alloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in pcap__scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + pcap__switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to pcap_lex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * pcap__scan_bytes() instead. + */ +YY_BUFFER_STATE pcap__scan_string (yyconst char * yystr ) +{ + + return pcap__scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to pcap_lex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE pcap__scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) pcap_alloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in pcap__scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = pcap__scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in pcap__scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up pcap_text. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + pcap_text[pcap_leng] = (yy_hold_char); \ + (yy_c_buf_p) = pcap_text + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + pcap_leng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current token. + * + */ + +int pcap_get_debug (void) +{ + return pcap__flex_debug; +} + +void pcap_set_debug (int bdebug ) +{ + pcap__flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from pcap_lex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + pcap_in = stdin; + pcap_out = stdout; +#else + pcap_in = (FILE *) 0; + pcap_out = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * pcap_lex_init() + */ + return 0; +} + +/* pcap_lex_destroy is for both reentrant and non-reentrant scanners. */ +int pcap_lex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + pcap__delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + pcap_pop_buffer_state(); + } + + /* Destroy the stack itself. */ + pcap_free((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * pcap_lex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *pcap_alloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *pcap_realloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void pcap_free (void * ptr ) +{ + free( (char *) ptr ); /* see pcap_realloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 392 "scanner.l" + + +void +lex_init(buf) + const char *buf; +{ +#ifdef FLEX_SCANNER + in_buffer = pcap__scan_string(buf); +#else + in_buffer = buf; +#endif +} + +/* + * Do any cleanup necessary after parsing. + */ +void +lex_cleanup() +{ +#ifdef FLEX_SCANNER + if (in_buffer != NULL) + pcap__delete_buffer(in_buffer); + in_buffer = NULL; +#endif +} + +/* + * Also define a pcap_wrap. Note that if we're using flex, it will + * define a macro to map this identifier to pcap_wrap. + */ +int +pcap_wrap() +{ + return 1; +} + +/* Hex digit to integer. */ +static inline int +xdtoi(c) + register int c; +{ + if (isdigit(c)) + return c - '0'; + else if (islower(c)) + return c - 'a' + 10; + else + return c - 'A' + 10; +} + +/* + * Convert string to integer. Just like atoi(), but checks for + * preceding 0x or 0 and uses hex or octal instead of decimal. + */ +static int +stoi(s) + char *s; +{ + int base = 10; + int n = 0; + + if (*s == '0') { + if (s[1] == 'x' || s[1] == 'X') { + s += 2; + base = 16; + } + else { + base = 8; + s += 1; + } + } + while (*s) + n = n * base + xdtoi(*s++); + + return n; +} + diff --git a/tcpdump/jni/libpcap/scanner.c.top b/tcpdump/jni/libpcap/scanner.c.top new file mode 100644 index 0000000..c7cde56 --- /dev/null +++ b/tcpdump/jni/libpcap/scanner.c.top @@ -0,0 +1,3 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif diff --git a/tcpdump/jni/libpcap/scanner.h b/tcpdump/jni/libpcap/scanner.h new file mode 100644 index 0000000..934ca4c --- /dev/null +++ b/tcpdump/jni/libpcap/scanner.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ + +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/tcpdump/jni/libpcap/scanner.l b/tcpdump/jni/libpcap/scanner.l new file mode 100644 index 0000000..72a83f7 --- /dev/null +++ b/tcpdump/jni/libpcap/scanner.l @@ -0,0 +1,457 @@ +%{ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#endif /* WIN32 */ + +#include +#include + +#include "pcap-int.h" + +#include "gencode.h" +#ifdef INET6 +#ifdef WIN32 +#include + +#ifdef __MINGW32__ +#include "ip6_misc.h" +#endif +#else /* WIN32 */ +#include /* for "struct sockaddr" in "struct addrinfo" */ +#include /* for "struct addrinfo" */ +#endif /* WIN32 */ + +/* Workaround for AIX 4.3 */ +#if !defined(AI_NUMERICHOST) +#define AI_NUMERICHOST 0x04 +#endif +#endif /*INET6*/ +#include +#include "tokdefs.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +static int stoi(char *); +static inline int xdtoi(int); + +#ifdef FLEX_SCANNER +#define YY_NO_INPUT +#define YY_NO_UNPUT +static YY_BUFFER_STATE in_buffer; +#else +static const char *in_buffer; + +#undef getc +#define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++) +#endif + +#define yylval pcap_lval +extern YYSTYPE yylval; + +%} + +N ([0-9]+|(0X|0x)[0-9A-Fa-f]+) +B ([0-9A-Fa-f][0-9A-Fa-f]?) +B2 ([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]) +W ([0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?) + +%a 18400 +%o 21500 +%e 7600 +%k 4550 +%p 27600 +%n 2000 + +V680 {W}:{W}:{W}:{W}:{W}:{W}:{W}:{W} + +V670 ::{W}:{W}:{W}:{W}:{W}:{W}:{W} +V671 {W}::{W}:{W}:{W}:{W}:{W}:{W} +V672 {W}:{W}::{W}:{W}:{W}:{W}:{W} +V673 {W}:{W}:{W}::{W}:{W}:{W}:{W} +V674 {W}:{W}:{W}:{W}::{W}:{W}:{W} +V675 {W}:{W}:{W}:{W}:{W}::{W}:{W} +V676 {W}:{W}:{W}:{W}:{W}:{W}::{W} +V677 {W}:{W}:{W}:{W}:{W}:{W}:{W}:: + +V660 ::{W}:{W}:{W}:{W}:{W}:{W} +V661 {W}::{W}:{W}:{W}:{W}:{W} +V662 {W}:{W}::{W}:{W}:{W}:{W} +V663 {W}:{W}:{W}::{W}:{W}:{W} +V664 {W}:{W}:{W}:{W}::{W}:{W} +V665 {W}:{W}:{W}:{W}:{W}::{W} +V666 {W}:{W}:{W}:{W}:{W}:{W}:: + +V650 ::{W}:{W}:{W}:{W}:{W} +V651 {W}::{W}:{W}:{W}:{W} +V652 {W}:{W}::{W}:{W}:{W} +V653 {W}:{W}:{W}::{W}:{W} +V654 {W}:{W}:{W}:{W}::{W} +V655 {W}:{W}:{W}:{W}:{W}:: + +V640 ::{W}:{W}:{W}:{W} +V641 {W}::{W}:{W}:{W} +V642 {W}:{W}::{W}:{W} +V643 {W}:{W}:{W}::{W} +V644 {W}:{W}:{W}:{W}:: + +V630 ::{W}:{W}:{W} +V631 {W}::{W}:{W} +V632 {W}:{W}::{W} +V633 {W}:{W}:{W}:: + +V620 ::{W}:{W} +V621 {W}::{W} +V622 {W}:{W}:: + +V610 ::{W} +V611 {W}:: + +V600 :: + +V6604 {W}:{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} + +V6504 ::{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6514 {W}::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6524 {W}:{W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6534 {W}:{W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N} +V6544 {W}:{W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N} +V6554 {W}:{W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N} + +V6404 ::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6414 {W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6424 {W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N} +V6434 {W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N} +V6444 {W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N} + +V6304 ::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6314 {W}::{W}:{W}:{N}\.{N}\.{N}\.{N} +V6324 {W}:{W}::{W}:{N}\.{N}\.{N}\.{N} +V6334 {W}:{W}:{W}::{N}\.{N}\.{N}\.{N} + +V6204 ::{W}:{W}:{N}\.{N}\.{N}\.{N} +V6214 {W}::{W}:{N}\.{N}\.{N}\.{N} +V6224 {W}:{W}::{N}\.{N}\.{N}\.{N} + +V6104 ::{W}:{N}\.{N}\.{N}\.{N} +V6114 {W}::{N}\.{N}\.{N}\.{N} + +V6004 ::{N}\.{N}\.{N}\.{N} + + +V6 ({V680}|{V670}|{V671}|{V672}|{V673}|{V674}|{V675}|{V676}|{V677}|{V660}|{V661}|{V662}|{V663}|{V664}|{V665}|{V666}|{V650}|{V651}|{V652}|{V653}|{V654}|{V655}|{V640}|{V641}|{V642}|{V643}|{V644}|{V630}|{V631}|{V632}|{V633}|{V620}|{V621}|{V622}|{V610}|{V611}|{V600}|{V6604}|{V6504}|{V6514}|{V6524}|{V6534}|{V6544}|{V6554}|{V6404}|{V6414}|{V6424}|{V6434}|{V6444}|{V6304}|{V6314}|{V6324}|{V6334}|{V6204}|{V6214}|{V6224}|{V6104}|{V6114}|{V6004}) + +MAC ({B}:{B}:{B}:{B}:{B}:{B}|{B}\-{B}\-{B}\-{B}\-{B}\-{B}|{B}\.{B}\.{B}\.{B}\.{B}\.{B}|{B2}\.{B2}\.{B2}|{B2}{3}) + + + +%% +dst return DST; +src return SRC; + +link|ether|ppp|slip return LINK; +fddi|tr|wlan return LINK; +arp return ARP; +rarp return RARP; +ip return IP; +sctp return SCTP; +tcp return TCP; +udp return UDP; +icmp return ICMP; +igmp return IGMP; +igrp return IGRP; +pim return PIM; +vrrp return VRRP; +carp return CARP; +radio return RADIO; + +ip6 return IPV6; +icmp6 return ICMPV6; +ah return AH; +esp return ESP; + +atalk return ATALK; +aarp return AARP; +decnet return DECNET; +lat return LAT; +sca return SCA; +moprc return MOPRC; +mopdl return MOPDL; + +iso return ISO; +esis return ESIS; +es-is return ESIS; +isis return ISIS; +is-is return ISIS; +l1 return L1; +l2 return L2; +iih return IIH; +lsp return LSP; +snp return SNP; +csnp return CSNP; +psnp return PSNP; + +clnp return CLNP; + +stp return STP; + +ipx return IPX; + +netbeui return NETBEUI; + +host return HOST; +net return NET; +mask return NETMASK; +port return PORT; +portrange return PORTRANGE; +proto return PROTO; +protochain { +#ifdef NO_PROTOCHAIN + bpf_error("%s not supported", yytext); +#else + return PROTOCHAIN; +#endif + } + +gateway return GATEWAY; + +type return TYPE; +subtype return SUBTYPE; +direction|dir return DIR; +address1|addr1 return ADDR1; +address2|addr2 return ADDR2; +address3|addr3 return ADDR3; +address4|addr4 return ADDR4; +ra return RA; +ta return TA; + +less return LESS; +greater return GREATER; +byte return CBYTE; +broadcast return TK_BROADCAST; +multicast return TK_MULTICAST; + +and|"&&" return AND; +or|"||" return OR; +not return '!'; + +len|length return LEN; +inbound return INBOUND; +outbound return OUTBOUND; + +vlan return VLAN; +mpls return MPLS; +pppoed return PPPOED; +pppoes return PPPOES; +geneve return GENEVE; + +lane return LANE; +llc return LLC; +metac return METAC; +bcc return BCC; +oam return OAM; +oamf4 return OAMF4; +oamf4ec return OAMF4EC; +oamf4sc return OAMF4SC; +sc return SC; +ilmic return ILMIC; +vpi return VPI; +vci return VCI; +connectmsg return CONNECTMSG; +metaconnect return METACONNECT; + +on|ifname return PF_IFNAME; +rset|ruleset return PF_RSET; +rnr|rulenum return PF_RNR; +srnr|subrulenum return PF_SRNR; +reason return PF_REASON; +action return PF_ACTION; + +fisu return FISU; +lssu return LSSU; +lsu return LSSU; +msu return MSU; +hfisu return HFISU; +hlssu return HLSSU; +hmsu return HMSU; +sio return SIO; +opc return OPC; +dpc return DPC; +sls return SLS; +hsio return HSIO; +hopc return HOPC; +hdpc return HDPC; +hsls return HSLS; + +[ \r\n\t] ; +[+\-*/%:\[\]!<>()&|\^=] return yytext[0]; +">=" return GEQ; +"<=" return LEQ; +"!=" return NEQ; +"==" return '='; +"<<" return LSH; +">>" return RSH; +${B} { yylval.e = pcap_ether_aton(((char *)yytext)+1); + if (yylval.e == NULL) + bpf_error("malloc"); + return AID; } +{MAC} { yylval.e = pcap_ether_aton((char *)yytext); + if (yylval.e == NULL) + bpf_error("malloc"); + return EID; } +{N} { yylval.i = stoi((char *)yytext); return NUM; } +({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) { + yylval.s = sdup((char *)yytext); return HID; } +{V6} { +#ifdef INET6 + struct addrinfo hints, *res; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(yytext, NULL, &hints, &res)) + bpf_error("bogus IPv6 address %s", yytext); + else { + freeaddrinfo(res); + yylval.s = sdup((char *)yytext); return HID6; + } +#else + bpf_error("IPv6 address %s not supported", yytext); +#endif /*INET6*/ + } +{B}:+({B}:+)+ { bpf_error("bogus ethernet address %s", yytext); } +icmptype { yylval.i = 0; return NUM; } +icmpcode { yylval.i = 1; return NUM; } +icmp-echoreply { yylval.i = 0; return NUM; } +icmp-unreach { yylval.i = 3; return NUM; } +icmp-sourcequench { yylval.i = 4; return NUM; } +icmp-redirect { yylval.i = 5; return NUM; } +icmp-echo { yylval.i = 8; return NUM; } +icmp-routeradvert { yylval.i = 9; return NUM; } +icmp-routersolicit { yylval.i = 10; return NUM; } +icmp-timxceed { yylval.i = 11; return NUM; } +icmp-paramprob { yylval.i = 12; return NUM; } +icmp-tstamp { yylval.i = 13; return NUM; } +icmp-tstampreply { yylval.i = 14; return NUM; } +icmp-ireq { yylval.i = 15; return NUM; } +icmp-ireqreply { yylval.i = 16; return NUM; } +icmp-maskreq { yylval.i = 17; return NUM; } +icmp-maskreply { yylval.i = 18; return NUM; } +tcpflags { yylval.i = 13; return NUM; } +tcp-fin { yylval.i = 0x01; return NUM; } +tcp-syn { yylval.i = 0x02; return NUM; } +tcp-rst { yylval.i = 0x04; return NUM; } +tcp-push { yylval.i = 0x08; return NUM; } +tcp-ack { yylval.i = 0x10; return NUM; } +tcp-urg { yylval.i = 0x20; return NUM; } +[A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? { + yylval.s = sdup((char *)yytext); return ID; } +"\\"[^ !()\n\t]+ { yylval.s = sdup((char *)yytext + 1); return ID; } +[^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+ { + bpf_error("illegal token: %s", yytext); } +. { bpf_error("illegal char '%c'", *yytext); } +%% +void +lex_init(buf) + const char *buf; +{ +#ifdef FLEX_SCANNER + in_buffer = yy_scan_string(buf); +#else + in_buffer = buf; +#endif +} + +/* + * Do any cleanup necessary after parsing. + */ +void +lex_cleanup() +{ +#ifdef FLEX_SCANNER + if (in_buffer != NULL) + yy_delete_buffer(in_buffer); + in_buffer = NULL; +#endif +} + +/* + * Also define a yywrap. Note that if we're using flex, it will + * define a macro to map this identifier to pcap_wrap. + */ +int +yywrap() +{ + return 1; +} + +/* Hex digit to integer. */ +static inline int +xdtoi(c) + register int c; +{ + if (isdigit(c)) + return c - '0'; + else if (islower(c)) + return c - 'a' + 10; + else + return c - 'A' + 10; +} + +/* + * Convert string to integer. Just like atoi(), but checks for + * preceding 0x or 0 and uses hex or octal instead of decimal. + */ +static int +stoi(s) + char *s; +{ + int base = 10; + int n = 0; + + if (*s == '0') { + if (s[1] == 'x' || s[1] == 'X') { + s += 2; + base = 16; + } + else { + base = 8; + s += 1; + } + } + while (*s) + n = n * base + xdtoi(*s++); + + return n; +} diff --git a/tcpdump/jni/libpcap/sf-pcap-ng.c b/tcpdump/jni/libpcap/sf-pcap-ng.c new file mode 100644 index 0000000..e2cac04 --- /dev/null +++ b/tcpdump/jni/libpcap/sf-pcap-ng.c @@ -0,0 +1,1274 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * sf-pcap-ng.c - pcap-ng-file-format-specific code from savefile.c + */ + +#ifndef lint +static const char rcsid[] _U_ = + "@(#) $Header$ (LBL)"; +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#endif /* WIN32 */ + +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#include "pcap-common.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#include "sf-pcap-ng.h" + +/* + * Block types. + */ + +/* + * Common part at the beginning of all blocks. + */ +struct block_header { + bpf_u_int32 block_type; + bpf_u_int32 total_length; +}; + +/* + * Common trailer at the end of all blocks. + */ +struct block_trailer { + bpf_u_int32 total_length; +}; + +/* + * Common options. + */ +#define OPT_ENDOFOPT 0 /* end of options */ +#define OPT_COMMENT 1 /* comment string */ + +/* + * Option header. + */ +struct option_header { + u_short option_code; + u_short option_length; +}; + +/* + * Structures for the part of each block type following the common + * part. + */ + +/* + * Section Header Block. + */ +#define BT_SHB 0x0A0D0D0A + +struct section_header_block { + bpf_u_int32 byte_order_magic; + u_short major_version; + u_short minor_version; + u_int64_t section_length; + /* followed by options and trailer */ +}; + +/* + * Byte-order magic value. + */ +#define BYTE_ORDER_MAGIC 0x1A2B3C4D + +/* + * Current version number. If major_version isn't PCAP_NG_VERSION_MAJOR, + * that means that this code can't read the file. + */ +#define PCAP_NG_VERSION_MAJOR 1 + +/* + * Interface Description Block. + */ +#define BT_IDB 0x00000001 + +struct interface_description_block { + u_short linktype; + u_short reserved; + bpf_u_int32 snaplen; + /* followed by options and trailer */ +}; + +/* + * Options in the IDB. + */ +#define IF_NAME 2 /* interface name string */ +#define IF_DESCRIPTION 3 /* interface description string */ +#define IF_IPV4ADDR 4 /* interface's IPv4 address and netmask */ +#define IF_IPV6ADDR 5 /* interface's IPv6 address and prefix length */ +#define IF_MACADDR 6 /* interface's MAC address */ +#define IF_EUIADDR 7 /* interface's EUI address */ +#define IF_SPEED 8 /* interface's speed, in bits/s */ +#define IF_TSRESOL 9 /* interface's time stamp resolution */ +#define IF_TZONE 10 /* interface's time zone */ +#define IF_FILTER 11 /* filter used when capturing on interface */ +#define IF_OS 12 /* string OS on which capture on this interface was done */ +#define IF_FCSLEN 13 /* FCS length for this interface */ +#define IF_TSOFFSET 14 /* time stamp offset for this interface */ + +/* + * Enhanced Packet Block. + */ +#define BT_EPB 0x00000006 + +struct enhanced_packet_block { + bpf_u_int32 interface_id; + bpf_u_int32 timestamp_high; + bpf_u_int32 timestamp_low; + bpf_u_int32 caplen; + bpf_u_int32 len; + /* followed by packet data, options, and trailer */ +}; + +/* + * Simple Packet Block. + */ +#define BT_SPB 0x00000003 + +struct simple_packet_block { + bpf_u_int32 len; + /* followed by packet data and trailer */ +}; + +/* + * Packet Block. + */ +#define BT_PB 0x00000002 + +struct packet_block { + u_short interface_id; + u_short drops_count; + bpf_u_int32 timestamp_high; + bpf_u_int32 timestamp_low; + bpf_u_int32 caplen; + bpf_u_int32 len; + /* followed by packet data, options, and trailer */ +}; + +/* + * Block cursor - used when processing the contents of a block. + * Contains a pointer into the data being processed and a count + * of bytes remaining in the block. + */ +struct block_cursor { + u_char *data; + size_t data_remaining; + bpf_u_int32 block_type; +}; + +typedef enum { + PASS_THROUGH, + SCALE_UP, + SCALE_DOWN +} tstamp_scale_type_t; + +/* + * Per-interface information. + */ +struct pcap_ng_if { + u_int tsresol; /* time stamp resolution */ + u_int64_t tsoffset; /* time stamp offset */ + tstamp_scale_type_t scale_type; /* how to scale */ +}; + +struct pcap_ng_sf { + u_int user_tsresol; /* time stamp resolution requested by the user */ + bpf_u_int32 ifcount; /* number of interfaces seen in this capture */ + bpf_u_int32 ifaces_size; /* size of arrary below */ + struct pcap_ng_if *ifaces; /* array of interface information */ +}; + +static void pcap_ng_cleanup(pcap_t *p); +static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, + u_char **data); + +static int +read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof, + char *errbuf) +{ + size_t amt_read; + + amt_read = fread(buf, 1, bytes_to_read, fp); + if (amt_read != bytes_to_read) { + if (ferror(fp)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + } else { + if (amt_read == 0 && !fail_on_eof) + return (0); /* EOF */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %lu bytes, only got %lu", + (unsigned long)bytes_to_read, + (unsigned long)amt_read); + } + return (-1); + } + return (1); +} + +static int +read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) +{ + int status; + struct block_header bhdr; + + status = read_bytes(fp, &bhdr, sizeof(bhdr), 0, errbuf); + if (status <= 0) + return (status); /* error or EOF */ + + if (p->swapped) { + bhdr.block_type = SWAPLONG(bhdr.block_type); + bhdr.total_length = SWAPLONG(bhdr.total_length); + } + + /* + * Is this block "too big"? + * + * We choose 16MB as "too big", for now, so that we handle + * "reasonably" large buffers but don't chew up all the + * memory if we read a malformed file. + */ + if (bhdr.total_length > 16*1024*1024) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "pcap-ng block size %u > maximum %u", + bhdr.total_length, 16*1024*1024); + return (-1); + } + + /* + * Is this block "too small" - i.e., is it shorter than a block + * header plus a block trailer? + */ + if (bhdr.total_length < sizeof(struct block_header) + + sizeof(struct block_trailer)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "block in pcap-ng dump file has a length of %u < %lu", + bhdr.total_length, + (unsigned long)(sizeof(struct block_header) + sizeof(struct block_trailer))); + return (-1); + } + + /* + * Is the buffer big enough? + */ + if (p->bufsize < bhdr.total_length) { + /* + * No - make it big enough. + */ + p->buffer = realloc(p->buffer, bhdr.total_length); + if (p->buffer == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); + return (-1); + } + } + + /* + * Copy the stuff we've read to the buffer, and read the rest + * of the block. + */ + memcpy(p->buffer, &bhdr, sizeof(bhdr)); + if (read_bytes(fp, p->buffer + sizeof(bhdr), + bhdr.total_length - sizeof(bhdr), 1, errbuf) == -1) + return (-1); + + /* + * Initialize the cursor. + */ + cursor->data = p->buffer + sizeof(bhdr); + cursor->data_remaining = bhdr.total_length - sizeof(bhdr) - + sizeof(struct block_trailer); + cursor->block_type = bhdr.block_type; + return (1); +} + +static void * +get_from_block_data(struct block_cursor *cursor, size_t chunk_size, + char *errbuf) +{ + void *data; + + /* + * Make sure we have the specified amount of data remaining in + * the block data. + */ + if (cursor->data_remaining < chunk_size) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "block of type %u in pcap-ng dump file is too short", + cursor->block_type); + return (NULL); + } + + /* + * Return the current pointer, and skip past the chunk. + */ + data = cursor->data; + cursor->data += chunk_size; + cursor->data_remaining -= chunk_size; + return (data); +} + +static struct option_header * +get_opthdr_from_block_data(pcap_t *p, struct block_cursor *cursor, char *errbuf) +{ + struct option_header *opthdr; + + opthdr = get_from_block_data(cursor, sizeof(*opthdr), errbuf); + if (opthdr == NULL) { + /* + * Option header is cut short. + */ + return (NULL); + } + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + opthdr->option_code = SWAPSHORT(opthdr->option_code); + opthdr->option_length = SWAPSHORT(opthdr->option_length); + } + + return (opthdr); +} + +static void * +get_optvalue_from_block_data(struct block_cursor *cursor, + struct option_header *opthdr, char *errbuf) +{ + size_t padded_option_len; + void *optvalue; + + /* Pad option length to 4-byte boundary */ + padded_option_len = opthdr->option_length; + padded_option_len = ((padded_option_len + 3)/4)*4; + + optvalue = get_from_block_data(cursor, padded_option_len, errbuf); + if (optvalue == NULL) { + /* + * Option value is cut short. + */ + return (NULL); + } + + return (optvalue); +} + +static int +process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, + u_int64_t *tsoffset, char *errbuf) +{ + struct option_header *opthdr; + void *optvalue; + int saw_tsresol, saw_tsoffset; + u_char tsresol_opt; + u_int i; + + saw_tsresol = 0; + saw_tsoffset = 0; + while (cursor->data_remaining != 0) { + /* + * Get the option header. + */ + opthdr = get_opthdr_from_block_data(p, cursor, errbuf); + if (opthdr == NULL) { + /* + * Option header is cut short. + */ + return (-1); + } + + /* + * Get option value. + */ + optvalue = get_optvalue_from_block_data(cursor, opthdr, + errbuf); + if (optvalue == NULL) { + /* + * Option value is cut short. + */ + return (-1); + } + + switch (opthdr->option_code) { + + case OPT_ENDOFOPT: + if (opthdr->option_length != 0) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block has opt_endofopt option with length %u != 0", + opthdr->option_length); + return (-1); + } + goto done; + + case IF_TSRESOL: + if (opthdr->option_length != 1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block has if_tsresol option with length %u != 1", + opthdr->option_length); + return (-1); + } + if (saw_tsresol) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block has more than one if_tsresol option"); + return (-1); + } + saw_tsresol = 1; + memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt)); + if (tsresol_opt & 0x80) { + /* + * Resolution is negative power of 2. + */ + *tsresol = 1 << (tsresol_opt & 0x7F); + } else { + /* + * Resolution is negative power of 10. + */ + *tsresol = 1; + for (i = 0; i < tsresol_opt; i++) + *tsresol *= 10; + } + if (*tsresol == 0) { + /* + * Resolution is too high. + */ + if (tsresol_opt & 0x80) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block if_tsresol option resolution 2^-%u is too high", + tsresol_opt & 0x7F); + } else { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block if_tsresol option resolution 10^-%u is too high", + tsresol_opt); + } + return (-1); + } + break; + + case IF_TSOFFSET: + if (opthdr->option_length != 8) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block has if_tsoffset option with length %u != 8", + opthdr->option_length); + return (-1); + } + if (saw_tsoffset) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block has more than one if_tsoffset option"); + return (-1); + } + saw_tsoffset = 1; + memcpy(tsoffset, optvalue, sizeof(*tsoffset)); + if (p->swapped) + *tsoffset = SWAPLL(*tsoffset); + break; + + default: + break; + } + } + +done: + return (0); +} + +static int +add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf) +{ + struct pcap_ng_sf *ps; + u_int tsresol; + u_int64_t tsoffset; + + ps = p->priv; + + /* + * Count this interface. + */ + ps->ifcount++; + + /* + * Grow the array of per-interface information as necessary. + */ + if (ps->ifcount > ps->ifaces_size) { + /* + * We need to grow the array. + */ + if (ps->ifaces == NULL) { + /* + * It's currently empty. + */ + ps->ifaces_size = 1; + ps->ifaces = malloc(sizeof (struct pcap_ng_if)); + } else { + /* + * It's not currently empty; double its size. + * (Perhaps overkill once we have a lot of interfaces.) + */ + ps->ifaces_size *= 2; + ps->ifaces = realloc(ps->ifaces, ps->ifaces_size * sizeof (struct pcap_ng_if)); + } + if (ps->ifaces == NULL) { + /* + * We ran out of memory. + * Give up. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "out of memory for per-interface information (%u interfaces)", + ps->ifcount); + return (0); + } + } + + /* + * Set the default time stamp resolution and offset. + */ + tsresol = 1000000; /* microsecond resolution */ + tsoffset = 0; /* absolute timestamps */ + + /* + * Now look for various time stamp options, so we know + * how to interpret the time stamps for this interface. + */ + if (process_idb_options(p, cursor, &tsresol, &tsoffset, errbuf) == -1) + return (0); + + ps->ifaces[ps->ifcount - 1].tsresol = tsresol; + ps->ifaces[ps->ifcount - 1].tsoffset = tsoffset; + + /* + * Determine whether we're scaling up or down or not + * at all for this interface. + */ + switch (p->opt.tstamp_precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + if (tsresol == 1000000) { + /* + * The resolution is 1 microsecond, + * so we don't have to do scaling. + */ + ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH; + } else if (tsresol > 1000000) { + /* + * The resolution is greater than + * 1 microsecond, so we have to + * scale the timestamps down. + */ + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN; + } else { + /* + * The resolution is less than 1 + * microsecond, so we have to scale + * the timestamps up. + */ + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP; + } + break; + + case PCAP_TSTAMP_PRECISION_NANO: + if (tsresol == 1000000000) { + /* + * The resolution is 1 nanosecond, + * so we don't have to do scaling. + */ + ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH; + } else if (tsresol > 1000000000) { + /* + * The resolution is greater than + * 1 nanosecond, so we have to + * scale the timestamps down. + */ + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN; + } else { + /* + * The resolution is less than 1 + * nanosecond, so we have to scale + * the timestamps up. + */ + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP; + } + break; + } + return (1); +} + +/* + * Check whether this is a pcap-ng savefile and, if it is, extract the + * relevant information from the header. + */ +pcap_t * +pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, + int *err) +{ + size_t amt_read; + bpf_u_int32 total_length; + bpf_u_int32 byte_order_magic; + struct block_header *bhdrp; + struct section_header_block *shbp; + pcap_t *p; + int swapped = 0; + struct pcap_ng_sf *ps; + int status; + struct block_cursor cursor; + struct interface_description_block *idbp; + + /* + * Assume no read errors. + */ + *err = 0; + + /* + * Check whether the first 4 bytes of the file are the block + * type for a pcap-ng savefile. + */ + if (magic != BT_SHB) { + /* + * XXX - check whether this looks like what the block + * type would be after being munged by mapping between + * UN*X and DOS/Windows text file format and, if it + * does, look for the byte-order magic number in + * the appropriate place and, if we find it, report + * this as possibly being a pcap-ng file transferred + * between UN*X and Windows in text file format? + */ + return (NULL); /* nope */ + } + + /* + * OK, they are. However, that's just \n\r\r\n, so it could, + * conceivably, be an ordinary text file. + * + * It could not, however, conceivably be any other type of + * capture file, so we can read the rest of the putative + * Section Header Block; put the block type in the common + * header, read the rest of the common header and the + * fixed-length portion of the SHB, and look for the byte-order + * magic value. + */ + amt_read = fread(&total_length, 1, sizeof(total_length), fp); + if (amt_read < sizeof(total_length)) { + if (ferror(fp)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + *err = 1; + return (NULL); /* fail */ + } + + /* + * Possibly a weird short text file, so just say + * "not pcap-ng". + */ + return (NULL); + } + amt_read = fread(&byte_order_magic, 1, sizeof(byte_order_magic), fp); + if (amt_read < sizeof(byte_order_magic)) { + if (ferror(fp)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + *err = 1; + return (NULL); /* fail */ + } + + /* + * Possibly a weird short text file, so just say + * "not pcap-ng". + */ + return (NULL); + } + if (byte_order_magic != BYTE_ORDER_MAGIC) { + byte_order_magic = SWAPLONG(byte_order_magic); + if (byte_order_magic != BYTE_ORDER_MAGIC) { + /* + * Not a pcap-ng file. + */ + return (NULL); + } + swapped = 1; + total_length = SWAPLONG(total_length); + } + + /* + * Check the sanity of the total length. + */ + if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Section Header Block in pcap-ng dump file has a length of %u < %lu", + total_length, + (unsigned long)(sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer))); + *err = 1; + return (NULL); + } + + /* + * OK, this is a good pcap-ng file. + * Allocate a pcap_t for it. + */ + p = pcap_open_offline_common(errbuf, sizeof (struct pcap_ng_sf)); + if (p == NULL) { + /* Allocation failed. */ + *err = 1; + return (NULL); + } + p->swapped = swapped; + ps = p->priv; + + /* + * What precision does the user want? + */ + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + ps->user_tsresol = 1000000; + break; + + case PCAP_TSTAMP_PRECISION_NANO: + ps->user_tsresol = 1000000000; + break; + + default: + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unknown time stamp resolution %u", precision); + free(p); + *err = 1; + return (NULL); + } + + p->opt.tstamp_precision = precision; + + /* + * Allocate a buffer into which to read blocks. We default to + * the maximum of: + * + * the total length of the SHB for which we read the header; + * + * 2K, which should be more than large enough for an Enhanced + * Packet Block containing a full-size Ethernet frame, and + * leaving room for some options. + * + * If we find a bigger block, we reallocate the buffer. + */ + p->bufsize = 2048; + if (p->bufsize < total_length) + p->bufsize = total_length; + p->buffer = malloc(p->bufsize); + if (p->buffer == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); + free(p); + *err = 1; + return (NULL); + } + + /* + * Copy the stuff we've read to the buffer, and read the rest + * of the SHB. + */ + bhdrp = (struct block_header *)p->buffer; + shbp = (struct section_header_block *)(p->buffer + sizeof(struct block_header)); + bhdrp->block_type = magic; + bhdrp->total_length = total_length; + shbp->byte_order_magic = byte_order_magic; + if (read_bytes(fp, + p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), + total_length - (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), + 1, errbuf) == -1) + goto fail; + + if (p->swapped) { + /* + * Byte-swap the fields we've read. + */ + shbp->major_version = SWAPSHORT(shbp->major_version); + shbp->minor_version = SWAPSHORT(shbp->minor_version); + + /* + * XXX - we don't care about the section length. + */ + } + if (shbp->major_version != PCAP_NG_VERSION_MAJOR) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unknown pcap-ng savefile major version number %u", + shbp->major_version); + goto fail; + } + p->version_major = shbp->major_version; + p->version_minor = shbp->minor_version; + + /* + * Save the time stamp resolution the user requested. + */ + p->opt.tstamp_precision = precision; + + /* + * Now start looking for an Interface Description Block. + */ + for (;;) { + /* + * Read the next block. + */ + status = read_block(fp, p, &cursor, errbuf); + if (status == 0) { + /* EOF - no IDB in this file */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "the capture file has no Interface Description Blocks"); + goto fail; + } + if (status == -1) + goto fail; /* error */ + switch (cursor.block_type) { + + case BT_IDB: + /* + * Get a pointer to the fixed-length portion of the + * IDB. + */ + idbp = get_from_block_data(&cursor, sizeof(*idbp), + errbuf); + if (idbp == NULL) + goto fail; /* error */ + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + idbp->linktype = SWAPSHORT(idbp->linktype); + idbp->snaplen = SWAPLONG(idbp->snaplen); + } + + /* + * Try to add this interface. + */ + if (!add_interface(p, &cursor, errbuf)) + goto fail; + goto done; + + case BT_EPB: + case BT_SPB: + case BT_PB: + /* + * Saw a packet before we saw any IDBs. That's + * not valid, as we don't know what link-layer + * encapsulation the packet has. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "the capture file has a packet block before any Interface Description Blocks"); + goto fail; + + default: + /* + * Just ignore it. + */ + break; + } + } + +done: + p->tzoff = 0; /* XXX - not used in pcap */ + p->snapshot = idbp->snaplen; + p->linktype = linktype_to_dlt(idbp->linktype); + p->linktype_ext = 0; + + p->next_packet_op = pcap_ng_next_packet; + p->cleanup_op = pcap_ng_cleanup; + + return (p); + +fail: + free(ps->ifaces); + free(p->buffer); + free(p); + *err = 1; + return (NULL); +} + +static void +pcap_ng_cleanup(pcap_t *p) +{ + struct pcap_ng_sf *ps = p->priv; + + free(ps->ifaces); + sf_cleanup(p); +} + +/* + * Read and return the next packet from the savefile. Return the header + * in hdr and a pointer to the contents in data. Return 0 on success, 1 + * if there were no more packets, and -1 on an error. + */ +static int +pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) +{ + struct pcap_ng_sf *ps = p->priv; + struct block_cursor cursor; + int status; + struct enhanced_packet_block *epbp; + struct simple_packet_block *spbp; + struct packet_block *pbp; + bpf_u_int32 interface_id = 0xFFFFFFFF; + struct interface_description_block *idbp; + struct section_header_block *shbp; + FILE *fp = p->rfile; + u_int64_t t, sec, frac; + + /* + * Look for an Enhanced Packet Block, a Simple Packet Block, + * or a Packet Block. + */ + for (;;) { + /* + * Read the block type and length; those are common + * to all blocks. + */ + status = read_block(fp, p, &cursor, p->errbuf); + if (status == 0) + return (1); /* EOF */ + if (status == -1) + return (-1); /* error */ + switch (cursor.block_type) { + + case BT_EPB: + /* + * Get a pointer to the fixed-length portion of the + * EPB. + */ + epbp = get_from_block_data(&cursor, sizeof(*epbp), + p->errbuf); + if (epbp == NULL) + return (-1); /* error */ + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + /* these were written in opposite byte order */ + interface_id = SWAPLONG(epbp->interface_id); + hdr->caplen = SWAPLONG(epbp->caplen); + hdr->len = SWAPLONG(epbp->len); + t = ((u_int64_t)SWAPLONG(epbp->timestamp_high)) << 32 | + SWAPLONG(epbp->timestamp_low); + } else { + interface_id = epbp->interface_id; + hdr->caplen = epbp->caplen; + hdr->len = epbp->len; + t = ((u_int64_t)epbp->timestamp_high) << 32 | + epbp->timestamp_low; + } + goto found; + + case BT_SPB: + /* + * Get a pointer to the fixed-length portion of the + * SPB. + */ + spbp = get_from_block_data(&cursor, sizeof(*spbp), + p->errbuf); + if (spbp == NULL) + return (-1); /* error */ + + /* + * SPB packets are assumed to have arrived on + * the first interface. + */ + interface_id = 0; + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + /* these were written in opposite byte order */ + hdr->len = SWAPLONG(spbp->len); + } else + hdr->len = spbp->len; + + /* + * The SPB doesn't give the captured length; + * it's the minimum of the snapshot length + * and the packet length. + */ + hdr->caplen = hdr->len; + if (hdr->caplen > p->snapshot) + hdr->caplen = p->snapshot; + t = 0; /* no time stamps */ + goto found; + + case BT_PB: + /* + * Get a pointer to the fixed-length portion of the + * PB. + */ + pbp = get_from_block_data(&cursor, sizeof(*pbp), + p->errbuf); + if (pbp == NULL) + return (-1); /* error */ + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + /* these were written in opposite byte order */ + interface_id = SWAPSHORT(pbp->interface_id); + hdr->caplen = SWAPLONG(pbp->caplen); + hdr->len = SWAPLONG(pbp->len); + t = ((u_int64_t)SWAPLONG(pbp->timestamp_high)) << 32 | + SWAPLONG(pbp->timestamp_low); + } else { + interface_id = pbp->interface_id; + hdr->caplen = pbp->caplen; + hdr->len = pbp->len; + t = ((u_int64_t)pbp->timestamp_high) << 32 | + pbp->timestamp_low; + } + goto found; + + case BT_IDB: + /* + * Interface Description Block. Get a pointer + * to its fixed-length portion. + */ + idbp = get_from_block_data(&cursor, sizeof(*idbp), + p->errbuf); + if (idbp == NULL) + return (-1); /* error */ + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + idbp->linktype = SWAPSHORT(idbp->linktype); + idbp->snaplen = SWAPLONG(idbp->snaplen); + } + + /* + * If the link-layer type or snapshot length + * differ from the ones for the first IDB we + * saw, quit. + * + * XXX - just discard packets from those + * interfaces? + */ + if (p->linktype != idbp->linktype) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "an interface has a type %u different from the type of the first interface", + idbp->linktype); + return (-1); + } + if (p->snapshot != idbp->snaplen) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "an interface has a snapshot length %u different from the type of the first interface", + idbp->snaplen); + return (-1); + } + + /* + * Try to add this interface. + */ + if (!add_interface(p, &cursor, p->errbuf)) + return (-1); + break; + + case BT_SHB: + /* + * Section Header Block. Get a pointer + * to its fixed-length portion. + */ + shbp = get_from_block_data(&cursor, sizeof(*shbp), + p->errbuf); + if (shbp == NULL) + return (-1); /* error */ + + /* + * Assume the byte order of this section is + * the same as that of the previous section. + * We'll check for that later. + */ + if (p->swapped) { + shbp->byte_order_magic = + SWAPLONG(shbp->byte_order_magic); + shbp->major_version = + SWAPSHORT(shbp->major_version); + } + + /* + * Make sure the byte order doesn't change; + * pcap_is_swapped() shouldn't change its + * return value in the middle of reading a capture. + */ + switch (shbp->byte_order_magic) { + + case BYTE_ORDER_MAGIC: + /* + * OK. + */ + break; + + case SWAPLONG(BYTE_ORDER_MAGIC): + /* + * Byte order changes. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "the file has sections with different byte orders"); + return (-1); + + default: + /* + * Not a valid SHB. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "the file has a section with a bad byte order magic field"); + return (-1); + } + + /* + * Make sure the major version is the version + * we handle. + */ + if (shbp->major_version != PCAP_NG_VERSION_MAJOR) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "unknown pcap-ng savefile major version number %u", + shbp->major_version); + return (-1); + } + + /* + * Reset the interface count; this section should + * have its own set of IDBs. If any of them + * don't have the same interface type, snapshot + * length, or resolution as the first interface + * we saw, we'll fail. (And if we don't see + * any IDBs, we'll fail when we see a packet + * block.) + */ + ps->ifcount = 0; + break; + + default: + /* + * Not a packet block, IDB, or SHB; ignore it. + */ + break; + } + } + +found: + /* + * Is the interface ID an interface we know? + */ + if (interface_id >= ps->ifcount) { + /* + * Yes. Fail. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "a packet arrived on interface %u, but there's no Interface Description Block for that interface", + interface_id); + return (-1); + } + + /* + * Convert the time stamp to seconds and fractions of a second, + * with the fractions being in units of the file-supplied resolution. + */ + sec = t / ps->ifaces[interface_id].tsresol + ps->ifaces[interface_id].tsoffset; + frac = t % ps->ifaces[interface_id].tsresol; + + /* + * Convert the fractions from units of the file-supplied resolution + * to units of the user-requested resolution. + */ + switch (ps->ifaces[interface_id].scale_type) { + + case PASS_THROUGH: + /* + * The interface resolution is what the user wants, + * so we're done. + */ + break; + + case SCALE_UP: + case SCALE_DOWN: + /* + * The interface resolution is different from what the + * user wants; convert the fractions to units of the + * resolution the user requested by multiplying by the + * quotient of the user-requested resolution and the + * file-supplied resolution. We do that by multiplying + * by the user-requested resolution and dividing by the + * file-supplied resolution, as the quotient might not + * fit in an integer. + * + * XXX - if ps->ifaces[interface_id].tsresol is a power + * of 10, we could just multiply by the quotient of + * ps->user_tsresol and ps->ifaces[interface_id].tsresol + * in the scale-up case, and divide by the quotient of + * ps->ifaces[interface_id].tsresol and ps->user_tsresol + * in the scale-down case, as we know those will be integers. + * That would involve fewer arithmetic operations, and + * would run less risk of overflow. + * + * Is there something clever we could do if + * ps->ifaces[interface_id].tsresol is a power of 2? + */ + frac *= ps->user_tsresol; + frac /= ps->ifaces[interface_id].tsresol; + break; + } + hdr->ts.tv_sec = sec; + hdr->ts.tv_usec = frac; + + /* + * Get a pointer to the packet data. + */ + *data = get_from_block_data(&cursor, hdr->caplen, p->errbuf); + if (*data == NULL) + return (-1); + + if (p->swapped) + swap_pseudo_headers(p->linktype, hdr, *data); + + return (0); +} diff --git a/tcpdump/jni/libpcap/sf-pcap-ng.h b/tcpdump/jni/libpcap/sf-pcap-ng.h new file mode 100644 index 0000000..3c93498 --- /dev/null +++ b/tcpdump/jni/libpcap/sf-pcap-ng.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * sf-pcap-ng.h - pcap-ng-file-format-specific routines + * + * Used to read pcap-ng savefiles. + */ + +#ifndef sf_pcap_ng_h +#define sf_pcap_ng_h + +extern pcap_t *pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, + u_int precision, char *errbuf, int *err); + +#endif diff --git a/tcpdump/jni/libpcap/sf-pcap.c b/tcpdump/jni/libpcap/sf-pcap.c new file mode 100644 index 0000000..eaeddfa --- /dev/null +++ b/tcpdump/jni/libpcap/sf-pcap.c @@ -0,0 +1,894 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * sf-pcap.c - libpcap-file-format-specific code from savefile.c + * Extraction/creation by Jeffrey Mogul, DECWRL + * Modified by Steve McCanne, LBL. + * + * Used to save the received packet headers, after filtering, to + * a file, and then read them later. + * The first record in the file contains saved values for the machine + * dependent values so we can print the dump file on any architecture. + */ + +#ifndef lint +static const char rcsid[] _U_ = + "@(#) $Header$ (LBL)"; +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#include +#endif /* WIN32 */ + +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#include "pcap-common.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#include "sf-pcap.h" + +/* + * Setting O_BINARY on DOS/Windows is a bit tricky + */ +#if defined(WIN32) + #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) +#elif defined(MSDOS) + #if defined(__HIGHC__) + #define SET_BINMODE(f) setmode(f, O_BINARY) + #else + #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) + #endif +#endif + +/* + * Standard libpcap format. + */ +#define TCPDUMP_MAGIC 0xa1b2c3d4 + +/* + * Alexey Kuznetzov's modified libpcap format. + */ +#define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34 + +/* + * Reserved for Francisco Mesquita + * for another modified format. + */ +#define FMESQUITA_TCPDUMP_MAGIC 0xa1b234cd + +/* + * Navtel Communcations' format, with nanosecond timestamps, + * as per a request from Dumas Hwang . + */ +#define NAVTEL_TCPDUMP_MAGIC 0xa12b3c4d + +/* + * Normal libpcap format, except for seconds/nanoseconds timestamps, + * as per a request by Ulf Lamping + */ +#define NSEC_TCPDUMP_MAGIC 0xa1b23c4d + +/* + * Mechanism for storing information about a capture in the upper + * 6 bits of a linktype value in a capture file. + * + * LT_LINKTYPE_EXT(x) extracts the additional information. + * + * The rest of the bits are for a value describing the link-layer + * value. LT_LINKTYPE(x) extracts that value. + */ +#define LT_LINKTYPE(x) ((x) & 0x03FFFFFF) +#define LT_LINKTYPE_EXT(x) ((x) & 0xFC000000) + +static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); + +/* + * Private data for reading pcap savefiles. + */ +typedef enum { + NOT_SWAPPED, + SWAPPED, + MAYBE_SWAPPED +} swapped_type_t; + +typedef enum { + PASS_THROUGH, + SCALE_UP, + SCALE_DOWN +} tstamp_scale_type_t; + +struct pcap_sf { + size_t hdrsize; + swapped_type_t lengths_swapped; + tstamp_scale_type_t scale_type; +}; + +/* + * Check whether this is a pcap savefile and, if it is, extract the + * relevant information from the header. + */ +pcap_t * +pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, + int *err) +{ + struct pcap_file_header hdr; + size_t amt_read; + pcap_t *p; + int swapped = 0; + struct pcap_sf *ps; + + /* + * Assume no read errors. + */ + *err = 0; + + /* + * Check whether the first 4 bytes of the file are the magic + * number for a pcap savefile, or for a byte-swapped pcap + * savefile. + */ + if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && + magic != NSEC_TCPDUMP_MAGIC) { + magic = SWAPLONG(magic); + if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && + magic != NSEC_TCPDUMP_MAGIC) + return (NULL); /* nope */ + swapped = 1; + } + + /* + * They are. Put the magic number in the header, and read + * the rest of the header. + */ + hdr.magic = magic; + amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1, + sizeof(hdr) - sizeof(hdr.magic), fp); + if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) { + if (ferror(fp)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + } else { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %lu file header bytes, only got %lu", + (unsigned long)sizeof(hdr), + (unsigned long)amt_read); + } + *err = 1; + return (NULL); + } + + /* + * If it's a byte-swapped capture file, byte-swap the header. + */ + if (swapped) { + hdr.version_major = SWAPSHORT(hdr.version_major); + hdr.version_minor = SWAPSHORT(hdr.version_minor); + hdr.thiszone = SWAPLONG(hdr.thiszone); + hdr.sigfigs = SWAPLONG(hdr.sigfigs); + hdr.snaplen = SWAPLONG(hdr.snaplen); + hdr.linktype = SWAPLONG(hdr.linktype); + } + + if (hdr.version_major < PCAP_VERSION_MAJOR) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "archaic pcap savefile format"); + *err = 1; + return (NULL); + } + + /* + * OK, this is a good pcap file. + * Allocate a pcap_t for it. + */ + p = pcap_open_offline_common(errbuf, sizeof (struct pcap_sf)); + if (p == NULL) { + /* Allocation failed. */ + *err = 1; + return (NULL); + } + p->swapped = swapped; + p->version_major = hdr.version_major; + p->version_minor = hdr.version_minor; + p->tzoff = hdr.thiszone; + p->snapshot = hdr.snaplen; + p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); + p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); + + p->next_packet_op = pcap_next_packet; + + ps = p->priv; + + p->opt.tstamp_precision = precision; + + /* + * Will we need to scale the timestamps to match what the + * user wants? + */ + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + if (magic == NSEC_TCPDUMP_MAGIC) { + /* + * The file has nanoseconds, the user + * wants microseconds; scale the + * precision down. + */ + ps->scale_type = SCALE_DOWN; + } else { + /* + * The file has microseconds, the + * user wants microseconds; nothing to do. + */ + ps->scale_type = PASS_THROUGH; + } + break; + + case PCAP_TSTAMP_PRECISION_NANO: + if (magic == NSEC_TCPDUMP_MAGIC) { + /* + * The file has nanoseconds, the + * user wants nanoseconds; nothing to do. + */ + ps->scale_type = PASS_THROUGH; + } else { + /* + * The file has microoseconds, the user + * wants nanoseconds; scale the + * precision up. + */ + ps->scale_type = SCALE_UP; + } + break; + + default: + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unknown time stamp resolution %u", precision); + free(p); + *err = 1; + return (NULL); + } + + /* + * We interchanged the caplen and len fields at version 2.3, + * in order to match the bpf header layout. But unfortunately + * some files were written with version 2.3 in their headers + * but without the interchanged fields. + * + * In addition, DG/UX tcpdump writes out files with a version + * number of 543.0, and with the caplen and len fields in the + * pre-2.3 order. + */ + switch (hdr.version_major) { + + case 2: + if (hdr.version_minor < 3) + ps->lengths_swapped = SWAPPED; + else if (hdr.version_minor == 3) + ps->lengths_swapped = MAYBE_SWAPPED; + else + ps->lengths_swapped = NOT_SWAPPED; + break; + + case 543: + ps->lengths_swapped = SWAPPED; + break; + + default: + ps->lengths_swapped = NOT_SWAPPED; + break; + } + + if (magic == KUZNETZOV_TCPDUMP_MAGIC) { + /* + * XXX - the patch that's in some versions of libpcap + * changes the packet header but not the magic number, + * and some other versions with this magic number have + * some extra debugging information in the packet header; + * we'd have to use some hacks^H^H^H^H^Hheuristics to + * detect those variants. + * + * Ethereal does that, but it does so by trying to read + * the first two packets of the file with each of the + * record header formats. That currently means it seeks + * backwards and retries the reads, which doesn't work + * on pipes. We want to be able to read from a pipe, so + * that strategy won't work; we'd have to buffer some + * data ourselves and read from that buffer in order to + * make that work. + */ + ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr); + + if (p->linktype == DLT_EN10MB) { + /* + * This capture might have been done in raw mode + * or cooked mode. + * + * If it was done in cooked mode, p->snapshot was + * passed to recvfrom() as the buffer size, meaning + * that the most packet data that would be copied + * would be p->snapshot. However, a faked Ethernet + * header would then have been added to it, so the + * most data that would be in a packet in the file + * would be p->snapshot + 14. + * + * We can't easily tell whether the capture was done + * in raw mode or cooked mode, so we'll assume it was + * cooked mode, and add 14 to the snapshot length. + * That means that, for a raw capture, the snapshot + * length will be misleading if you use it to figure + * out why a capture doesn't have all the packet data, + * but there's not much we can do to avoid that. + */ + p->snapshot += 14; + } + } else + ps->hdrsize = sizeof(struct pcap_sf_pkthdr); + + /* + * Allocate a buffer for the packet data. + */ + p->bufsize = p->snapshot; + if (p->bufsize <= 0) { + /* + * Bogus snapshot length; use the maximum as a fallback. + */ + p->bufsize = MAXIMUM_SNAPLEN; + } + p->buffer = malloc(p->bufsize); + if (p->buffer == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); + free(p); + *err = 1; + return (NULL); + } + + p->cleanup_op = sf_cleanup; + + return (p); +} + +/* + * Read and return the next packet from the savefile. Return the header + * in hdr and a pointer to the contents in data. Return 0 on success, 1 + * if there were no more packets, and -1 on an error. + */ +static int +pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) +{ + struct pcap_sf *ps = p->priv; + struct pcap_sf_patched_pkthdr sf_hdr; + FILE *fp = p->rfile; + size_t amt_read; + bpf_u_int32 t; + + /* + * Read the packet header; the structure we use as a buffer + * is the longer structure for files generated by the patched + * libpcap, but if the file has the magic number for an + * unpatched libpcap we only read as many bytes as the regular + * header has. + */ + amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp); + if (amt_read != ps->hdrsize) { + if (ferror(fp)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + return (-1); + } else { + if (amt_read != 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %lu header bytes, only got %lu", + (unsigned long)ps->hdrsize, + (unsigned long)amt_read); + return (-1); + } + /* EOF */ + return (1); + } + } + + if (p->swapped) { + /* these were written in opposite byte order */ + hdr->caplen = SWAPLONG(sf_hdr.caplen); + hdr->len = SWAPLONG(sf_hdr.len); + hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec); + hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec); + } else { + hdr->caplen = sf_hdr.caplen; + hdr->len = sf_hdr.len; + hdr->ts.tv_sec = sf_hdr.ts.tv_sec; + hdr->ts.tv_usec = sf_hdr.ts.tv_usec; + } + + switch (ps->scale_type) { + + case PASS_THROUGH: + /* + * Just pass the time stamp through. + */ + break; + + case SCALE_UP: + /* + * File has microseconds, user wants nanoseconds; convert + * it. + */ + hdr->ts.tv_usec = hdr->ts.tv_usec * 1000; + break; + + case SCALE_DOWN: + /* + * File has nanoseconds, user wants microseconds; convert + * it. + */ + hdr->ts.tv_usec = hdr->ts.tv_usec / 1000; + break; + } + + /* Swap the caplen and len fields, if necessary. */ + switch (ps->lengths_swapped) { + + case NOT_SWAPPED: + break; + + case MAYBE_SWAPPED: + if (hdr->caplen <= hdr->len) { + /* + * The captured length is <= the actual length, + * so presumably they weren't swapped. + */ + break; + } + /* FALLTHROUGH */ + + case SWAPPED: + t = hdr->caplen; + hdr->caplen = hdr->len; + hdr->len = t; + break; + } + + if (hdr->caplen > p->bufsize) { + /* + * This can happen due to Solaris 2.3 systems tripping + * over the BUFMOD problem and not setting the snapshot + * correctly in the savefile header. If the caplen isn't + * grossly wrong, try to salvage. + */ + static u_char *tp = NULL; + static size_t tsize = 0; + + if (hdr->caplen > MAXIMUM_SNAPLEN) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "bogus savefile header"); + return (-1); + } + + if (tsize < hdr->caplen) { + tsize = ((hdr->caplen + 1023) / 1024) * 1024; + if (tp != NULL) + free((u_char *)tp); + tp = (u_char *)malloc(tsize); + if (tp == NULL) { + tsize = 0; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BUFMOD hack malloc"); + return (-1); + } + } + amt_read = fread((char *)tp, 1, hdr->caplen, fp); + if (amt_read != hdr->caplen) { + if (ferror(fp)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %u captured bytes, only got %lu", + hdr->caplen, (unsigned long)amt_read); + } + return (-1); + } + /* + * We can only keep up to p->bufsize bytes. Since + * caplen > p->bufsize is exactly how we got here, + * we know we can only keep the first p->bufsize bytes + * and must drop the remainder. Adjust caplen accordingly, + * so we don't get confused later as to how many bytes we + * have to play with. + */ + hdr->caplen = p->bufsize; + memcpy(p->buffer, (char *)tp, p->bufsize); + } else { + /* read the packet itself */ + amt_read = fread(p->buffer, 1, hdr->caplen, fp); + if (amt_read != hdr->caplen) { + if (ferror(fp)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %u captured bytes, only got %lu", + hdr->caplen, (unsigned long)amt_read); + } + return (-1); + } + } + *data = p->buffer; + + if (p->swapped) + swap_pseudo_headers(p->linktype, hdr, *data); + + return (0); +} + +static int +sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen) +{ + struct pcap_file_header hdr; + + hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC; + hdr.version_major = PCAP_VERSION_MAJOR; + hdr.version_minor = PCAP_VERSION_MINOR; + + hdr.thiszone = thiszone; + hdr.snaplen = snaplen; + hdr.sigfigs = 0; + hdr.linktype = linktype; + + if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) + return (-1); + + return (0); +} + +/* + * Output a packet to the initialized dump file. + */ +void +pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) +{ + register FILE *f; + struct pcap_sf_pkthdr sf_hdr; + + f = (FILE *)user; + sf_hdr.ts.tv_sec = h->ts.tv_sec; + sf_hdr.ts.tv_usec = h->ts.tv_usec; + sf_hdr.caplen = h->caplen; + sf_hdr.len = h->len; + /* XXX we should check the return status */ + (void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f); + (void)fwrite(sp, h->caplen, 1, f); +} + +static pcap_dumper_t * +pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) +{ + +#if defined(WIN32) || defined(MSDOS) + /* + * If we're writing to the standard output, put it in binary + * mode, as savefiles are binary files. + * + * Otherwise, we turn off buffering. + * XXX - why? And why not on the standard output? + */ + if (f == stdout) + SET_BINMODE(f); + else + setbuf(f, NULL); +#endif + if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", + fname, pcap_strerror(errno)); + if (f != stdout) + (void)fclose(f); + return (NULL); + } + return ((pcap_dumper_t *)f); +} + +/* + * Initialize so that sf_write() will output to the file named 'fname'. + */ +pcap_dumper_t * +pcap_dump_open(pcap_t *p, const char *fname) +{ + FILE *f; + int linktype; + + /* + * If this pcap_t hasn't been activated, it doesn't have a + * link-layer type, so we can't use it. + */ + if (!p->activated) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: not-yet-activated pcap_t passed to pcap_dump_open", + fname); + return (NULL); + } + linktype = dlt_to_linktype(p->linktype); + if (linktype == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: link-layer type %d isn't supported in savefiles", + fname, p->linktype); + return (NULL); + } + linktype |= p->linktype_ext; + + if (fname[0] == '-' && fname[1] == '\0') { + f = stdout; + fname = "standard output"; + } else { +#if !defined(WIN32) && !defined(MSDOS) + f = fopen(fname, "w"); +#else + f = fopen(fname, "wb"); +#endif + if (f == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + fname, pcap_strerror(errno)); + return (NULL); + } + } + return (pcap_setup_dump(p, linktype, f, fname)); +} + +/* + * Initialize so that sf_write() will output to the given stream. + */ +pcap_dumper_t * +pcap_dump_fopen(pcap_t *p, FILE *f) +{ + int linktype; + + linktype = dlt_to_linktype(p->linktype); + if (linktype == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "stream: link-layer type %d isn't supported in savefiles", + p->linktype); + return (NULL); + } + linktype |= p->linktype_ext; + + return (pcap_setup_dump(p, linktype, f, "stream")); +} + +pcap_dumper_t * +pcap_dump_open_append(pcap_t *p, const char *fname) +{ + FILE *f; + int linktype; + int amt_read; + struct pcap_file_header ph; + + linktype = dlt_to_linktype(p->linktype); + if (linktype == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: link-layer type %d isn't supported in savefiles", + fname, linktype); + return (NULL); + } + if (fname[0] == '-' && fname[1] == '\0') + return (pcap_setup_dump(p, linktype, stdout, "standard output")); + +#if !defined(WIN32) && !defined(MSDOS) + f = fopen(fname, "r+"); +#else + f = fopen(fname, "rb+"); +#endif + if (f == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + fname, pcap_strerror(errno)); + return (NULL); + } + + /* + * Try to read a pcap header. + */ + amt_read = fread(&ph, 1, sizeof (ph), f); + if (amt_read != sizeof (ph)) { + if (ferror(f)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + fname, pcap_strerror(errno)); + fclose(f); + return (NULL); + } else if (feof(f) && amt_read > 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: truncated pcap file header", fname); + fclose(f); + return (NULL); + } + } + +#if defined(WIN32) || defined(MSDOS) + /* + * We turn off buffering. + * XXX - why? And why not on the standard output? + */ + setbuf(f, NULL); +#endif + + /* + * If a header is already present and: + * + * it's not for a pcap file of the appropriate resolution + * and the right byte order for this machine; + * + * the link-layer header types don't match; + * + * the snapshot lengths don't match; + * + * return an error. + */ + if (amt_read > 0) { + /* + * A header is already present. + * Do the checks. + */ + switch (ph.magic) { + + case TCPDUMP_MAGIC: + if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different time stamp precision, cannot append to file", fname); + fclose(f); + return (NULL); + } + break; + + case NSEC_TCPDUMP_MAGIC: + if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different time stamp precision, cannot append to file", fname); + fclose(f); + return (NULL); + } + break; + + case SWAPLONG(TCPDUMP_MAGIC): + case SWAPLONG(NSEC_TCPDUMP_MAGIC): + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different byte order, cannot append to file", fname); + fclose(f); + return (NULL); + + case KUZNETZOV_TCPDUMP_MAGIC: + case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC): + case NAVTEL_TCPDUMP_MAGIC: + case SWAPLONG(NAVTEL_TCPDUMP_MAGIC): + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: not a pcap file to which we can append", fname); + fclose(f); + return (NULL); + + default: + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: not a pcap file", fname); + fclose(f); + return (NULL); + } + + /* + * Good version? + */ + if (ph.version_major != PCAP_VERSION_MAJOR || + ph.version_minor != PCAP_VERSION_MINOR) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: version is %u.%u, cannot append to file", fname, + ph.version_major, ph.version_minor); + fclose(f); + return (NULL); + } + if (linktype != ph.linktype) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different linktype, cannot append to file", fname); + fclose(f); + return (NULL); + } + if (p->snapshot != ph.snaplen) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different snaplen, cannot append to file", fname); + fclose(f); + return (NULL); + } + } else { + /* + * A header isn't present; attempt to write it. + */ + if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", + fname, pcap_strerror(errno)); + (void)fclose(f); + return (NULL); + } + } + + /* + * Start writing at the end of the file. + */ + if (fseek(f, 0, SEEK_END) == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't seek to end of %s: %s", + fname, pcap_strerror(errno)); + (void)fclose(f); + return (NULL); + } + return ((pcap_dumper_t *)f); +} + +FILE * +pcap_dump_file(pcap_dumper_t *p) +{ + return ((FILE *)p); +} + +long +pcap_dump_ftell(pcap_dumper_t *p) +{ + return (ftell((FILE *)p)); +} + +int +pcap_dump_flush(pcap_dumper_t *p) +{ + + if (fflush((FILE *)p) == EOF) + return (-1); + else + return (0); +} + +void +pcap_dump_close(pcap_dumper_t *p) +{ + +#ifdef notyet + if (ferror((FILE *)p)) + return-an-error; + /* XXX should check return from fclose() too */ +#endif + (void)fclose((FILE *)p); +} diff --git a/tcpdump/jni/libpcap/sf-pcap.h b/tcpdump/jni/libpcap/sf-pcap.h new file mode 100644 index 0000000..e9c7eaf --- /dev/null +++ b/tcpdump/jni/libpcap/sf-pcap.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * sf-pcap.h - libpcap-file-format-specific routines + * Extraction/creation by Jeffrey Mogul, DECWRL + * Modified by Steve McCanne, LBL. + * + * Used to save the received packet headers, after filtering, to + * a file, and then read them later. + * The first record in the file contains saved values for the machine + * dependent values so we can print the dump file on any architecture. + */ + +#ifndef sf_pcap_h +#define sf_pcap_h + +extern pcap_t *pcap_check_header(bpf_u_int32 magic, FILE *fp, + u_int precision, char *errbuf, int *err); + +#endif diff --git a/tcpdump/jni/libpcap/sunatmpos.h b/tcpdump/jni/libpcap/sunatmpos.h new file mode 100644 index 0000000..787de85 --- /dev/null +++ b/tcpdump/jni/libpcap/sunatmpos.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1997 Yen Yen Lim and North Dakota State University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Yen Yen Lim and + North Dakota State University + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* SunATM header for ATM packet */ +#define SUNATM_DIR_POS 0 +#define SUNATM_VPI_POS 1 +#define SUNATM_VCI_POS 2 +#define SUNATM_PKT_BEGIN_POS 4 /* Start of ATM packet */ + +/* Protocol type values in the bottom for bits of the byte at SUNATM_DIR_POS. */ +#define PT_LANE 0x01 /* LANE */ +#define PT_LLC 0x02 /* LLC encapsulation */ +#define PT_ILMI 0x05 /* ILMI */ +#define PT_QSAAL 0x06 /* Q.SAAL */ diff --git a/tcpdump/jni/libpcap/tests/BPF/1.txt b/tcpdump/jni/libpcap/tests/BPF/1.txt new file mode 100644 index 0000000..6608695 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/BPF/1.txt @@ -0,0 +1,2 @@ +# common block merging, same block elimination, result propogation +host 192.168.1.1 diff --git a/tcpdump/jni/libpcap/tests/BPF/2.txt b/tcpdump/jni/libpcap/tests/BPF/2.txt new file mode 100644 index 0000000..e9bc116 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/BPF/2.txt @@ -0,0 +1,2 @@ +# common block merging +port 80 diff --git a/tcpdump/jni/libpcap/tests/BPF/3.txt b/tcpdump/jni/libpcap/tests/BPF/3.txt new file mode 100644 index 0000000..6c08d3d --- /dev/null +++ b/tcpdump/jni/libpcap/tests/BPF/3.txt @@ -0,0 +1 @@ +tcp[tcpflags]&tcp-syn != 0 or tcp[tcpflags]&tcp-fin != 0 or tcp[tcpflags]&tcp-rst != 0 diff --git a/tcpdump/jni/libpcap/tests/BPF/4.txt b/tcpdump/jni/libpcap/tests/BPF/4.txt new file mode 100644 index 0000000..3fd2e66 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/BPF/4.txt @@ -0,0 +1,2 @@ +# or pullup +ether[12:2] = 0x800 or ether[12:2] = 0x8100 or ether[0] & 0x80 != 0 or ether[12:2] = 0x9100 diff --git a/tcpdump/jni/libpcap/tests/BPF/5.txt b/tcpdump/jni/libpcap/tests/BPF/5.txt new file mode 100644 index 0000000..23fc0ca --- /dev/null +++ b/tcpdump/jni/libpcap/tests/BPF/5.txt @@ -0,0 +1 @@ +vlan 186 and ip diff --git a/tcpdump/jni/libpcap/tests/BPF/6.txt b/tcpdump/jni/libpcap/tests/BPF/6.txt new file mode 100644 index 0000000..694c185 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/BPF/6.txt @@ -0,0 +1 @@ +ip and ((icmp and dst host 1.1.1.1 and not host 2.2.2.2) or (host 1.1.1.1 and src host 3.3.3.3)) diff --git a/tcpdump/jni/libpcap/tests/BPF/7.txt b/tcpdump/jni/libpcap/tests/BPF/7.txt new file mode 100644 index 0000000..33978a4 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/BPF/7.txt @@ -0,0 +1 @@ +not vlan and tcp port 80 diff --git a/tcpdump/jni/libpcap/tests/capturetest.c b/tcpdump/jni/libpcap/tests/capturetest.c new file mode 100644 index 0000000..e70e69a --- /dev/null +++ b/tcpdump/jni/libpcap/tests/capturetest.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void usage(void) __attribute__((noreturn)); +static void error(const char *, ...); +static void warning(const char *, ...); +static char *copy_argv(char **); + +static pcap_t *pd; + +extern int optind; +extern int opterr; +extern char *optarg; + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *cmdbuf, *device; + long longarg; + char *p; + int timeout = 1000; + int immediate = 0; + int nonblock = 0; + bpf_u_int32 localnet, netmask; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + int packet_count; + + device = NULL; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:mnt:")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 'm': + immediate = 1; + break; + + case 'n': + nonblock = 1; + break; + + case 't': + longarg = strtol(optarg, &p, 10); + if (p == optarg || *p != '\0') { + error("Timeout value \"%s\" is not a number", + optarg); + /* NOTREACHED */ + } + if (longarg < 0) { + error("Timeout value %ld is negative", longarg); + /* NOTREACHED */ + } + if (longarg > INT_MAX) { + error("Timeout value %ld is too large (> %d)", + longarg, INT_MAX); + /* NOTREACHED */ + } + timeout = (int)longarg; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + device = pcap_lookupdev(ebuf); + if (device == NULL) + error("%s", ebuf); + } + *ebuf = '\0'; + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + if (immediate) { + status = pcap_set_immediate_mode(pd, 1); + if (status != 0) + error("%s: pcap_set_immediate_mode failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, timeout); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + if (pcap_setnonblock(pd, nonblock, ebuf) == -1) + error("pcap_setnonblock failed: %s", ebuf); + printf("Listening on %s\n", device); + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + if (status != 0) { + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + } + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_loop: %s\n", + program_name, pcap_geterr(pd)); + } + pcap_close(pd); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -mn ] [ -i interface ] [ -t timeout] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/tcpdump/jni/libpcap/tests/filtertest.c b/tcpdump/jni/libpcap/tests/filtertest.c new file mode 100644 index 0000000..e45db21 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/filtertest.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef HAVE___ATTRIBUTE__ +#define __attribute__(x) +#endif + +static char *program_name; + +/* Forwards */ +static void usage(void) __attribute__((noreturn)); +static void error(const char *, ...) + __attribute__((noreturn, format (printf, 1, 2))); +static void warn(const char *, ...) + __attribute__((format (printf, 1, 2))); + +extern int optind; +extern int opterr; +extern char *optarg; +#ifdef BDEBUG +int dflag; +#endif + +/* + * On Windows, we need to open the file in binary mode, so that + * we get all the bytes specified by the size we get from "fstat()". + * On UNIX, that's not necessary. O_BINARY is defined on Windows; + * we define it as 0 if it's not defined, so it does nothing. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static char * +read_infile(char *fname) +{ + register int i, fd, cc; + register char *cp; + struct stat buf; + + fd = open(fname, O_RDONLY|O_BINARY); + if (fd < 0) + error("can't open %s: %s", fname, pcap_strerror(errno)); + + if (fstat(fd, &buf) < 0) + error("can't stat %s: %s", fname, pcap_strerror(errno)); + + cp = malloc((u_int)buf.st_size + 1); + if (cp == NULL) + error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, + fname, pcap_strerror(errno)); + cc = read(fd, cp, (u_int)buf.st_size); + if (cc < 0) + error("read %s: %s", fname, pcap_strerror(errno)); + if (cc != buf.st_size) + error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); + + close(fd); + /* replace "# comment" with spaces */ + for (i = 0; i < cc; i++) { + if (cp[i] == '#') + while (i < cc && cp[i] != '\n') + cp[i++] = ' '; + } + cp[cc] = '\0'; + return (cp); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warn(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} + +int +main(int argc, char **argv) +{ + char *cp; + int op; +#ifndef BDEBUG + int dflag; +#endif + char *infile; + int Oflag; + long snaplen; + char *p; + int dlt; + bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; + char *cmdbuf; + pcap_t *pd; + struct bpf_program fcode; + +#ifdef WIN32 + if(wsockinit() != 0) return 1; +#endif /* WIN32 */ + +#ifndef BDEBUG + dflag = 1; +#else + /* if optimizer debugging is enabled, output DOT graph + * `dflag=4' is equivalent to -dddd to follow -d/-dd/-ddd + * convention in tcpdump command line + */ + dflag = 4; +#endif + infile = NULL; + Oflag = 1; + snaplen = 68; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "dF:m:Os:")) != -1) { + switch (op) { + + case 'd': + ++dflag; + break; + + case 'F': + infile = optarg; + break; + + case 'O': + Oflag = 0; + break; + + case 'm': { + in_addr_t addr; + + addr = inet_addr(optarg); + if (addr == INADDR_NONE) + error("invalid netmask %s", optarg); + netmask = addr; + break; + } + + case 's': { + char *end; + + snaplen = strtol(optarg, &end, 0); + if (optarg == end || *end != '\0' + || snaplen < 0 || snaplen > 65535) + error("invalid snaplen %s", optarg); + else if (snaplen == 0) + snaplen = 65535; + break; + } + + default: + usage(); + /* NOTREACHED */ + } + } + + if (optind >= argc) { + usage(); + /* NOTREACHED */ + } + + dlt = pcap_datalink_name_to_val(argv[optind]); + if (dlt < 0) { + dlt = (int)strtol(argv[optind], &p, 10); + if (p == argv[optind] || *p != '\0') + error("invalid data link type %s", argv[optind]); + } + + if (infile) + cmdbuf = read_infile(infile); + else + cmdbuf = copy_argv(&argv[optind+1]); + + pd = pcap_open_dead(dlt, snaplen); + if (pd == NULL) + error("Can't open fake pcap_t"); + + if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (!bpf_validate(fcode.bf_insns, fcode.bf_len)) + warn("Filter doesn't pass validation"); + +#ifdef BDEBUG + // replace line feed with space + for (cp = cmdbuf; *cp != '\0'; ++cp) { + if (*cp == '\r' || *cp == '\n') { + *cp = ' '; + } + } + // only show machine code if BDEBUG defined, since dflag > 3 + printf("machine codes for filter: %s\n", cmdbuf); +#endif + + bpf_dump(&fcode, dflag); + pcap_close(pd); + exit(0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "%s, with %s\n", program_name, + pcap_lib_version()); + (void)fprintf(stderr, + "Usage: %s [-dO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", + program_name); + exit(1); +} diff --git a/tcpdump/jni/libpcap/tests/findalldevstest.c b/tcpdump/jni/libpcap/tests/findalldevstest.c new file mode 100644 index 0000000..6d452f8 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/findalldevstest.c @@ -0,0 +1,142 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include + +static int ifprint(pcap_if_t *d); +static char *iptos(bpf_u_int32 in); + +int main(int argc, char **argv) +{ + pcap_if_t *alldevs; + pcap_if_t *d; + char *s; + bpf_u_int32 net, mask; + int exit_status = 0; + + char errbuf[PCAP_ERRBUF_SIZE+1]; + if (pcap_findalldevs(&alldevs, errbuf) == -1) + { + fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); + exit(1); + } + for(d=alldevs;d;d=d->next) + { + if (!ifprint(d)) + exit_status = 2; + } + + if ( (s = pcap_lookupdev(errbuf)) == NULL) + { + fprintf(stderr,"Error in pcap_lookupdev: %s\n",errbuf); + exit_status = 2; + } + else + { + printf("Preferred device name: %s\n",s); + } + + if (pcap_lookupnet(s, &net, &mask, errbuf) < 0) + { + fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf); + exit_status = 2; + } + else + { + printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask)); + } + + exit(exit_status); +} + +static int ifprint(pcap_if_t *d) +{ + pcap_addr_t *a; +#ifdef INET6 + char ntop_buf[INET6_ADDRSTRLEN]; +#endif + int status = 1; /* success */ + + printf("%s\n",d->name); + if (d->description) + printf("\tDescription: %s\n",d->description); + printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no"); + + for(a=d->addresses;a;a=a->next) { + if (a->addr != NULL) + switch(a->addr->sa_family) { + case AF_INET: + printf("\tAddress Family: AF_INET\n"); + if (a->addr) + printf("\t\tAddress: %s\n", + inet_ntoa(((struct sockaddr_in *)(a->addr))->sin_addr)); + if (a->netmask) + printf("\t\tNetmask: %s\n", + inet_ntoa(((struct sockaddr_in *)(a->netmask))->sin_addr)); + if (a->broadaddr) + printf("\t\tBroadcast Address: %s\n", + inet_ntoa(((struct sockaddr_in *)(a->broadaddr))->sin_addr)); + if (a->dstaddr) + printf("\t\tDestination Address: %s\n", + inet_ntoa(((struct sockaddr_in *)(a->dstaddr))->sin_addr)); + break; +#ifdef INET6 + case AF_INET6: + printf("\tAddress Family: AF_INET6\n"); + if (a->addr) + printf("\t\tAddress: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->addr))->sin6_addr.s6_addr, + ntop_buf, sizeof ntop_buf)); + if (a->netmask) + printf("\t\tNetmask: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->netmask))->sin6_addr.s6_addr, + ntop_buf, sizeof ntop_buf)); + if (a->broadaddr) + printf("\t\tBroadcast Address: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->broadaddr))->sin6_addr.s6_addr, + ntop_buf, sizeof ntop_buf)); + if (a->dstaddr) + printf("\t\tDestination Address: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->dstaddr))->sin6_addr.s6_addr, + ntop_buf, sizeof ntop_buf)); + break; +#endif + default: + printf("\tAddress Family: Unknown (%d)\n", a->addr->sa_family); + break; + } + else + { + fprintf(stderr, "\tWarning: a->addr is NULL, skipping this address.\n"); + status = 0; + } + } + printf("\n"); + return status; +} + +/* From tcptraceroute */ +#define IPTOSBUFFERS 12 +static char *iptos(bpf_u_int32 in) +{ + static char output[IPTOSBUFFERS][3*4+3+1]; + static short which; + u_char *p; + + p = (u_char *)∈ + which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1); + sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + return output[which]; +} diff --git a/tcpdump/jni/libpcap/tests/nonblocktest.c b/tcpdump/jni/libpcap/tests/nonblocktest.c new file mode 100644 index 0000000..70a6bfd --- /dev/null +++ b/tcpdump/jni/libpcap/tests/nonblocktest.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void usage(void) __attribute__((noreturn)); +static void error(const char *, ...); +static void warning(const char *, ...); +static char *copy_argv(char **); + +static pcap_t *pd; + +extern int optind; +extern int opterr; +extern char *optarg; + +int +main(int argc, char **argv) +{ + register int op; + bpf_u_int32 localnet, netmask; + register char *cp, *cmdbuf, *device; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + int packet_count; + + device = NULL; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + device = pcap_lookupdev(ebuf); + if (device == NULL) + error("%s", ebuf); + } + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + if (pcap_setnonblock(pd, 1, ebuf) == -1) + error("pcap_setnonblock failed: %s", ebuf); + printf("Listening on %s\n", device); + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + if (status != 0) { + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + } + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_loop: %s\n", + program_name, pcap_geterr(pd)); + } + pcap_close(pd); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/tcpdump/jni/libpcap/tests/opentest.c b/tcpdump/jni/libpcap/tests/opentest.c new file mode 100644 index 0000000..0c91531 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/opentest.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define MAXIMUM_SNAPLEN 65535 + +static char *program_name; + +/* Forwards */ +static void usage(void) __attribute__((noreturn)); +static void error(const char *, ...); +static void warning(const char *, ...); + +extern int optind; +extern int opterr; +extern char *optarg; + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *device; + int dorfmon, dopromisc, snaplen, useactivate, bufsize; + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_t *pd; + int status = 0; + + device = NULL; + dorfmon = 0; + dopromisc = 0; + snaplen = MAXIMUM_SNAPLEN; + bufsize = 0; + useactivate = 0; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:Ips:aB:")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 'I': + dorfmon = 1; + useactivate = 1; /* required for rfmon */ + break; + + case 'p': + dopromisc = 1; + break; + + case 's': { + char *end; + + snaplen = strtol(optarg, &end, 0); + if (optarg == end || *end != '\0' + || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN) + error("invalid snaplen %s", optarg); + else if (snaplen == 0) + snaplen = MAXIMUM_SNAPLEN; + break; + } + + case 'B': + bufsize = atoi(optarg)*1024; + if (bufsize <= 0) + error("invalid packet buffer size %s", optarg); + useactivate = 1; /* required for bufsize */ + break; + + case 'a': + useactivate = 1; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (useactivate) { + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_set_snaplen(pd, snaplen); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + if (dopromisc) { + status = pcap_set_promisc(pd, 1); + if (status != 0) + error("%s: pcap_set_promisc failed: %s", + device, pcap_statustostr(status)); + } + if (dorfmon) { + status = pcap_set_rfmon(pd, 1); + if (status != 0) + error("%s: pcap_set_rfmon failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, 1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + if (bufsize != 0) { + status = pcap_set_buffer_size(pd, bufsize); + if (status != 0) + error("%s: pcap_set_buffer_size failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + } else { + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + } + pcap_close(pd); + exit(status < 0 ? 1 : 0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, + "Usage: %s [ -Ipa ] [ -i interface ] [ -s snaplen ] [ -B bufsize ]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} diff --git a/tcpdump/jni/libpcap/tests/pcap_compile_test.c b/tcpdump/jni/libpcap/tests/pcap_compile_test.c new file mode 100644 index 0000000..924ec73 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/pcap_compile_test.c @@ -0,0 +1,11 @@ + pcap = pcap_open_dead(link, snaplen); + /* todo: hook together argv to a single string */ + prog = argv[0]; + if (pcap_compile(pcap, &p, prog, optimize, 0) < 0) { + fprintf(stderr, pcap_geterr(pcap)); + exit(1); + } + bpf_dump(&p, option); + pcap_freecode(&p); + pcap_close(pcap); + diff --git a/tcpdump/jni/libpcap/tests/reactivatetest.c b/tcpdump/jni/libpcap/tests/reactivatetest.c new file mode 100644 index 0000000..9031a64 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/reactivatetest.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include + +/* Forwards */ +static void error(const char *, ...); + +int +main(void) +{ + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_t *pd; + int status = 0; + + pd = pcap_open_live("lo0", 65535, 0, 1000, ebuf); + if (pd == NULL) { + pd = pcap_open_live("lo", 65535, 0, 1000, ebuf); + if (pd == NULL) { + error("Neither lo0 nor lo could be opened: %s", + ebuf); + return 2; + } + } + status = pcap_activate(pd); + if (status != PCAP_ERROR_ACTIVATED) { + if (status == 0) + error("pcap_activate() of opened pcap_t succeeded"); + else if (status == PCAP_ERROR) + error("pcap_activate() of opened pcap_t failed with %s, not PCAP_ERROR_ACTIVATED", + pcap_geterr(pd)); + else + error("pcap_activate() of opened pcap_t failed with %s, not PCAP_ERROR_ACTIVATED", + pcap_statustostr(status)); + } + return 0; +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "reactivatetest: "); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} diff --git a/tcpdump/jni/libpcap/tests/selpolltest.c b/tcpdump/jni/libpcap/tests/selpolltest.c new file mode 100644 index 0000000..d94fb56 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/selpolltest.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void usage(void) __attribute__((noreturn)); +static void error(const char *, ...); +static void warning(const char *, ...); +static char *copy_argv(char **); + +static pcap_t *pd; + +extern int optind; +extern int opterr; +extern char *optarg; + +int +main(int argc, char **argv) +{ + register int op; + bpf_u_int32 localnet, netmask; + register char *cp, *cmdbuf, *device; + int doselect, dopoll, dotimeout, dononblock; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + int selectable_fd; + int status; + int packet_count; + + device = NULL; + doselect = 0; + dopoll = 0; + dotimeout = 0; + dononblock = 0; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:sptn")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 's': + doselect = 1; + break; + + case 'p': + dopoll = 1; + break; + + case 't': + dotimeout = 1; + break; + + case 'n': + dononblock = 1; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (doselect && dopoll) { + fprintf(stderr, "selpolltest: choose select (-s) or poll (-p), but not both\n"); + return 1; + } + if (dotimeout && !doselect && !dopoll) { + fprintf(stderr, "selpolltest: timeout (-t) requires select (-s) or poll (-p)\n"); + return 1; + } + if (device == NULL) { + device = pcap_lookupdev(ebuf); + if (device == NULL) + error("%s", ebuf); + } + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + if (pcap_get_selectable_fd(pd) == -1) + error("pcap_get_selectable_fd() fails"); + if (dononblock) { + if (pcap_setnonblock(pd, 1, ebuf) == -1) + error("pcap_setnonblock failed: %s", ebuf); + } + selectable_fd = pcap_get_selectable_fd(pd); + printf("Listening on %s\n", device); + if (doselect) { + for (;;) { + fd_set setread, setexcept; + struct timeval seltimeout; + + FD_ZERO(&setread); + FD_SET(selectable_fd, &setread); + FD_ZERO(&setexcept); + FD_SET(selectable_fd, &setexcept); + if (dotimeout) { + seltimeout.tv_sec = 0; + seltimeout.tv_usec = 1000; + status = select(selectable_fd + 1, &setread, + NULL, &setexcept, &seltimeout); + } else { + status = select(selectable_fd + 1, &setread, + NULL, &setexcept, NULL); + } + if (status == -1) { + printf("Select returns error (%s)\n", + strerror(errno)); + } else { + if (status == 0) + printf("Select timed out: "); + else + printf("Select returned a descriptor: "); + if (FD_ISSET(selectable_fd, &setread)) + printf("readable, "); + else + printf("not readable, "); + if (FD_ISSET(selectable_fd, &setexcept)) + printf("exceptional condition\n"); + else + printf("no exceptional condition\n"); + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + printf("%d packets seen, %d packets counted after select returns\n", + status, packet_count); + } + } + } else if (dopoll) { + for (;;) { + struct pollfd fd; + int polltimeout; + + fd.fd = selectable_fd; + fd.events = POLLIN; + if (dotimeout) + polltimeout = 1; + else + polltimeout = -1; + status = poll(&fd, 1, polltimeout); + if (status == -1) { + printf("Poll returns error (%s)\n", + strerror(errno)); + } else { + if (status == 0) + printf("Poll timed out\n"); + else { + printf("Poll returned a descriptor: "); + if (fd.revents & POLLIN) + printf("readable, "); + else + printf("not readable, "); + if (fd.revents & POLLERR) + printf("exceptional condition, "); + else + printf("no exceptional condition, "); + if (fd.revents & POLLHUP) + printf("disconnect, "); + else + printf("no disconnect, "); + if (fd.revents & POLLNVAL) + printf("invalid\n"); + else + printf("not invalid\n"); + } + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + printf("%d packets seen, %d packets counted after poll returns\n", + status, packet_count); + } + } + } else { + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + } + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_loop: %s\n", + program_name, pcap_geterr(pd)); + } + pcap_close(pd); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/tcpdump/jni/libpcap/tests/valgrindtest.c b/tcpdump/jni/libpcap/tests/valgrindtest.c new file mode 100644 index 0000000..72786e4 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/valgrindtest.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +/* BSD-flavored OS - use BPF */ +#define USE_BPF +#elif defined(linux) +/* Linux - use socket filters */ +#define USE_SOCKET_FILTERS +#else +#error "Unknown platform or platform that doesn't support Valgrind" +#endif + +#if defined(USE_BPF) + +#include +#include + +/* + * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the + * native OS version, as we're going to be doing our own ioctls to + * make sure that, in the uninitialized-data tests, the filters aren't + * checked by libpcap before being handed to BPF. + */ +#define PCAP_DONT_INCLUDE_PCAP_BPF_H + +#elif defined(USE_SOCKET_FILTERS) + +#include +#include +#include + +#endif + +#include +#ifndef HAVE___ATTRIBUTE__ +#define __attribute__(x) +#endif + +static char *program_name; + +/* Forwards */ +static void usage(void) __attribute__((noreturn)); +static void error(const char *, ...) + __attribute__((noreturn, format (printf, 1, 2))); +static void warning(const char *, ...) + __attribute__((format (printf, 1, 2))); + +extern int optind; +extern int opterr; +extern char *optarg; + +/* + * On Windows, we need to open the file in binary mode, so that + * we get all the bytes specified by the size we get from "fstat()". + * On UNIX, that's not necessary. O_BINARY is defined on Windows; + * we define it as 0 if it's not defined, so it does nothing. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static char * +read_infile(char *fname) +{ + register int i, fd, cc; + register char *cp; + struct stat buf; + + fd = open(fname, O_RDONLY|O_BINARY); + if (fd < 0) + error("can't open %s: %s", fname, pcap_strerror(errno)); + + if (fstat(fd, &buf) < 0) + error("can't stat %s: %s", fname, pcap_strerror(errno)); + + cp = malloc((u_int)buf.st_size + 1); + if (cp == NULL) + error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, + fname, pcap_strerror(errno)); + cc = read(fd, cp, (u_int)buf.st_size); + if (cc < 0) + error("read %s: %s", fname, pcap_strerror(errno)); + if (cc != buf.st_size) + error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); + + close(fd); + /* replace "# comment" with spaces */ + for (i = 0; i < cc; i++) { + if (cp[i] == '#') + while (i < cc && cp[i] != '\n') + cp[i++] = ' '; + } + cp[cc] = '\0'; + return (cp); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} + +#define INSN_COUNT 17 + +int +main(int argc, char **argv) +{ + char *cp, *device; + int op; + int dorfmon, useactivate; + char ebuf[PCAP_ERRBUF_SIZE]; + char *infile; + char *cmdbuf; + pcap_t *pd; + int status = 0; + int pcap_fd; +#if defined(USE_BPF) + struct bpf_program bad_fcode; + struct bpf_insn uninitialized[INSN_COUNT]; +#elif defined(USE_SOCKET_FILTERS) + struct sock_fprog bad_fcode; + struct sock_filter uninitialized[INSN_COUNT]; +#endif + struct bpf_program fcode; + + device = NULL; + dorfmon = 0; + useactivate = 0; + infile = NULL; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "aF:i:I")) != -1) { + switch (op) { + + case 'a': + useactivate = 1; + break; + + case 'F': + infile = optarg; + break; + + case 'i': + device = optarg; + break; + + case 'I': + dorfmon = 1; + useactivate = 1; /* required for rfmon */ + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + /* + * No interface specified; get whatever pcap_lookupdev() + * finds. + */ + device = pcap_lookupdev(ebuf); + if (device == NULL) { + error("couldn't find interface to use: %s", + ebuf); + } + } + + if (infile != NULL) { + /* + * Filter specified with "-F" and a file containing + * a filter. + */ + cmdbuf = read_infile(infile); + } else { + if (optind < argc) { + /* + * Filter specified with arguments on the + * command line. + */ + cmdbuf = copy_argv(&argv[optind+1]); + } else { + /* + * No filter specified; use an empty string, which + * compiles to an "accept all" filter. + */ + cmdbuf = ""; + } + } + + if (useactivate) { + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s: pcap_create() failed: %s", device, ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + status = pcap_set_promisc(pd, 1); + if (status != 0) + error("%s: pcap_set_promisc failed: %s", + device, pcap_statustostr(status)); + if (dorfmon) { + status = pcap_set_rfmon(pd, 1); + if (status != 0) + error("%s: pcap_set_rfmon failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, 1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + } else { + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 1, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + } + + pcap_fd = pcap_fileno(pd); + + /* + * Try setting a filter with an uninitialized bpf_program + * structure. This should cause valgrind to report a + * problem. + * + * We don't check for errors, because it could get an + * error due to a bad pointer or count. + */ +#if defined(USE_BPF) + ioctl(pcap_fd, BIOCSETF, &bad_fcode); +#elif defined(USE_SOCKET_FILTERS) + setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, + sizeof(bad_fcode)); +#endif + + /* + * Try setting a filter with an initialized bpf_program + * structure that points to an uninitialized program. + * That should also cause valgrind to report a problem. + * + * We don't check for errors, because it could get an + * error due to a bad pointer or count. + */ +#if defined(USE_BPF) + bad_fcode.bf_len = INSN_COUNT; + bad_fcode.bf_insns = uninitialized; + ioctl(pcap_fd, BIOCSETF, &bad_fcode); +#elif defined(USE_SOCKET_FILTERS) + bad_fcode.len = INSN_COUNT; + bad_fcode.filter = uninitialized; + setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, + sizeof(bad_fcode)); +#endif + + /* + * Now compile a filter and set the filter with that. + * That should *not* cause valgrind to report a + * problem. + */ + if (pcap_compile(pd, &fcode, cmdbuf, 1, 0) < 0) + error("can't compile filter: %s", pcap_geterr(pd)); + if (pcap_setfilter(pd, &fcode) < 0) + error("can't set filter: %s", pcap_geterr(pd)); + + pcap_close(pd); + exit(status < 0 ? 1 : 0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "%s, with %s\n", program_name, + pcap_lib_version()); + (void)fprintf(stderr, + "Usage: %s [-aI] [ -F file ] [ -I interface ] [ expression ]\n", + program_name); + exit(1); +} diff --git a/tcpdump/jni/libpcap/tests/visopts.py b/tcpdump/jni/libpcap/tests/visopts.py new file mode 100755 index 0000000..ab4f396 --- /dev/null +++ b/tcpdump/jni/libpcap/tests/visopts.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python + +""" +This program parse the output from pcap_compile() to visualize the CFG after +each optimize phase. + +Usage guide: +1. Enable optimizier debugging code when configure libpcap, + and build libpcap & filtertest + ./configure --enable-optimizer-dbg + make + make filtertest +2. Run filtertest to compile BPF expression, save to output a.txt + ./filtertest EN10MB host 192.168.1.1 > a.txt +3. Send a.txt to this program's standard input + cat a.txt | tests/visopts.py +4. Step 2&3 can be merged: + ./filtertest EN10MB host 192.168.1.1 | tests/visopts.py +5. The standard output is something like this: + generated files under directory: /tmp/visopts-W9ekBw + the directory will be removed when this programs finished. + open this link: http://localhost:39062/expr1.html +6. Using open link at the 3rd line `http://localhost:39062/expr1.html' + +Note: +1. CFG graph is translated to SVG document, expr1.html embeded them as external + document. If you open expr1.html as local file using file:// protocol, some + browsers will deny such requests so the web pages will not shown properly. + For chrome, you can run it using following command to avoid this: + chromium --disable-web-security + That's why this program start a localhost http server. +2. expr1.html use jquery from http://ajax.googleapis.com, so you need internet + access to show the web page. +""" + +import sys, os +import string +import subprocess +import json + +html_template = string.Template(""" + + + BPF compiler optimization phases for $expr + + + + + + + +
    +

    $expr

    +
    + +          + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + +""") + +def write_html(expr, gcount, logs): + logs = map(lambda s: s.strip().replace("\n", "
    "), logs) + + global html_template + html = html_template.safe_substitute(expr=expr.encode("string-escape"), gcount=gcount, logs=json.dumps(logs).encode("string-escape")) + with file("expr1.html", "wt") as f: + f.write(html) + +def render_on_html(infile): + expr = None + gid = 1 + log = "" + dot = "" + indot = 0 + logs = [] + + for line in infile: + if line.startswith("machine codes for filter:"): + expr = line[len("machine codes for filter:"):].strip() + break + elif line.startswith("digraph BPF {"): + indot = 1 + dot = line + elif indot: + dot += line + if line.startswith("}"): + indot = 2 + else: + log += line + + if indot == 2: + p = subprocess.Popen(['dot', '-Tsvg'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) + svg = p.communicate(dot)[0] + with file("expr1_g%03d.svg" % (gid), "wt") as f: + f.write(svg) + + logs.append(log) + gid += 1 + log = "" + dot = "" + indot = 0 + + if indot != 0: + #unterminated dot graph for expression + return False + if expr is None: + # BPF parser encounter error(s) + return False + write_html(expr, gid - 1, logs) + return True + +def run_httpd(): + import SimpleHTTPServer + import SocketServer + + class MySocketServer(SocketServer.TCPServer): + allow_reuse_address = True + Handler = SimpleHTTPServer.SimpleHTTPRequestHandler + httpd = MySocketServer(("localhost", 0), Handler) + print "open this link: http://localhost:%d/expr1.html" % (httpd.server_address[1]) + try: + httpd.serve_forever() + except KeyboardInterrupt as e: + pass + +def main(): + import tempfile + import atexit + import shutil + os.chdir(tempfile.mkdtemp(prefix="visopts-")) + atexit.register(shutil.rmtree, os.getcwd()) + print "generated files under directory: %s" % os.getcwd() + print " the directory will be removed when this programs finished." + + if not render_on_html(sys.stdin): + return 1 + run_httpd() + return 0 + +if __name__ == "__main__": + if '-h' in sys.argv or '--help' in sys.argv: + print __doc__ + exit(0) + exit(main()) diff --git a/tcpdump/jni/libpcap/tokdefs.h b/tcpdump/jni/libpcap/tokdefs.h new file mode 100644 index 0000000..75671d3 --- /dev/null +++ b/tcpdump/jni/libpcap/tokdefs.h @@ -0,0 +1,316 @@ +/* A Bison parser, made by GNU Bison 2.5. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + DST = 258, + SRC = 259, + HOST = 260, + GATEWAY = 261, + NET = 262, + NETMASK = 263, + PORT = 264, + PORTRANGE = 265, + LESS = 266, + GREATER = 267, + PROTO = 268, + PROTOCHAIN = 269, + CBYTE = 270, + ARP = 271, + RARP = 272, + IP = 273, + SCTP = 274, + TCP = 275, + UDP = 276, + ICMP = 277, + IGMP = 278, + IGRP = 279, + PIM = 280, + VRRP = 281, + CARP = 282, + ATALK = 283, + AARP = 284, + DECNET = 285, + LAT = 286, + SCA = 287, + MOPRC = 288, + MOPDL = 289, + TK_BROADCAST = 290, + TK_MULTICAST = 291, + NUM = 292, + INBOUND = 293, + OUTBOUND = 294, + PF_IFNAME = 295, + PF_RSET = 296, + PF_RNR = 297, + PF_SRNR = 298, + PF_REASON = 299, + PF_ACTION = 300, + TYPE = 301, + SUBTYPE = 302, + DIR = 303, + ADDR1 = 304, + ADDR2 = 305, + ADDR3 = 306, + ADDR4 = 307, + RA = 308, + TA = 309, + LINK = 310, + GEQ = 311, + LEQ = 312, + NEQ = 313, + ID = 314, + EID = 315, + HID = 316, + HID6 = 317, + AID = 318, + LSH = 319, + RSH = 320, + LEN = 321, + IPV6 = 322, + ICMPV6 = 323, + AH = 324, + ESP = 325, + VLAN = 326, + MPLS = 327, + PPPOED = 328, + PPPOES = 329, + ISO = 330, + ESIS = 331, + CLNP = 332, + ISIS = 333, + L1 = 334, + L2 = 335, + IIH = 336, + LSP = 337, + SNP = 338, + CSNP = 339, + PSNP = 340, + STP = 341, + IPX = 342, + NETBEUI = 343, + LANE = 344, + LLC = 345, + METAC = 346, + BCC = 347, + SC = 348, + ILMIC = 349, + OAMF4EC = 350, + OAMF4SC = 351, + OAM = 352, + OAMF4 = 353, + CONNECTMSG = 354, + METACONNECT = 355, + VPI = 356, + VCI = 357, + RADIO = 358, + FISU = 359, + LSSU = 360, + MSU = 361, + HFISU = 362, + HLSSU = 363, + HMSU = 364, + SIO = 365, + OPC = 366, + DPC = 367, + SLS = 368, + HSIO = 369, + HOPC = 370, + HDPC = 371, + HSLS = 372, + AND = 373, + OR = 374, + UMINUS = 375 + }; +#endif +/* Tokens. */ +#define DST 258 +#define SRC 259 +#define HOST 260 +#define GATEWAY 261 +#define NET 262 +#define NETMASK 263 +#define PORT 264 +#define PORTRANGE 265 +#define LESS 266 +#define GREATER 267 +#define PROTO 268 +#define PROTOCHAIN 269 +#define CBYTE 270 +#define ARP 271 +#define RARP 272 +#define IP 273 +#define SCTP 274 +#define TCP 275 +#define UDP 276 +#define ICMP 277 +#define IGMP 278 +#define IGRP 279 +#define PIM 280 +#define VRRP 281 +#define CARP 282 +#define ATALK 283 +#define AARP 284 +#define DECNET 285 +#define LAT 286 +#define SCA 287 +#define MOPRC 288 +#define MOPDL 289 +#define TK_BROADCAST 290 +#define TK_MULTICAST 291 +#define NUM 292 +#define INBOUND 293 +#define OUTBOUND 294 +#define PF_IFNAME 295 +#define PF_RSET 296 +#define PF_RNR 297 +#define PF_SRNR 298 +#define PF_REASON 299 +#define PF_ACTION 300 +#define TYPE 301 +#define SUBTYPE 302 +#define DIR 303 +#define ADDR1 304 +#define ADDR2 305 +#define ADDR3 306 +#define ADDR4 307 +#define RA 308 +#define TA 309 +#define LINK 310 +#define GEQ 311 +#define LEQ 312 +#define NEQ 313 +#define ID 314 +#define EID 315 +#define HID 316 +#define HID6 317 +#define AID 318 +#define LSH 319 +#define RSH 320 +#define LEN 321 +#define IPV6 322 +#define ICMPV6 323 +#define AH 324 +#define ESP 325 +#define VLAN 326 +#define MPLS 327 +#define PPPOED 328 +#define PPPOES 329 +#define ISO 330 +#define ESIS 331 +#define CLNP 332 +#define ISIS 333 +#define L1 334 +#define L2 335 +#define IIH 336 +#define LSP 337 +#define SNP 338 +#define CSNP 339 +#define PSNP 340 +#define STP 341 +#define IPX 342 +#define NETBEUI 343 +#define LANE 344 +#define LLC 345 +#define METAC 346 +#define BCC 347 +#define SC 348 +#define ILMIC 349 +#define OAMF4EC 350 +#define OAMF4SC 351 +#define OAM 352 +#define OAMF4 353 +#define CONNECTMSG 354 +#define METACONNECT 355 +#define VPI 356 +#define VCI 357 +#define RADIO 358 +#define FISU 359 +#define LSSU 360 +#define MSU 361 +#define HFISU 362 +#define HLSSU 363 +#define HMSU 364 +#define SIO 365 +#define OPC 366 +#define DPC 367 +#define SLS 368 +#define HSIO 369 +#define HOPC 370 +#define HDPC 371 +#define HSLS 372 +#define AND 373 +#define OR 374 +#define UMINUS 375 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 2068 of yacc.c */ +#line 242 "grammar.y" + + int i; + bpf_u_int32 h; + u_char *e; + char *s; + struct stmt *stmt; + struct arth *a; + struct { + struct qual q; + int atmfieldtype; + int mtp3fieldtype; + struct block *b; + } blk; + struct block *rblk; + + + +/* Line 2068 of yacc.c */ +#line 308 "y.tab.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +extern YYSTYPE pcap_lval; + + diff --git a/tcpdump/jni/libpcap/version.c b/tcpdump/jni/libpcap/version.c new file mode 100644 index 0000000..795bf1e --- /dev/null +++ b/tcpdump/jni/libpcap/version.c @@ -0,0 +1 @@ +char pcap_version[] = "1.5.2"; diff --git a/tcpdump/jni/libpcap/version.h b/tcpdump/jni/libpcap/version.h new file mode 100644 index 0000000..29c81da --- /dev/null +++ b/tcpdump/jni/libpcap/version.h @@ -0,0 +1 @@ +static const char pcap_version_string[] = "libpcap version 1.5.2"; diff --git a/tcpdump/jni/stub/Android.mk b/tcpdump/jni/stub/Android.mk new file mode 100644 index 0000000..7164eed --- /dev/null +++ b/tcpdump/jni/stub/Android.mk @@ -0,0 +1,10 @@ +# Build stub library in order to declare shared library to include to AAR + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := tcpdump_exec +LOCAL_SRC_FILES := stub.c + +include $(BUILD_SHARED_LIBRARY) diff --git a/tcpdump/jni/stub/stub.c b/tcpdump/jni/stub/stub.c new file mode 100644 index 0000000..e69de29 diff --git a/tcpdump/jni/tcpdump/Android.mk b/tcpdump/jni/tcpdump/Android.mk new file mode 100644 index 0000000..c2e8072 --- /dev/null +++ b/tcpdump/jni/tcpdump/Android.mk @@ -0,0 +1,57 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +tcpdump_CSRC = addrtoname.c af.c checksum.c cpack.c gmpls.c oui.c gmt2local.c ipproto.c \ + nlpid.c l2vpn.c machdep.c parsenfsfh.c in_cksum.c \ + print-802_11.c print-802_15_4.c print-ap1394.c print-ah.c print-ahcp.c \ + print-arcnet.c print-aodv.c print-aoe.c print-arp.c print-ascii.c print-atalk.c \ + print-atm.c print-beep.c print-bfd.c print-bgp.c \ + print-bootp.c print-bt.c print-calm-fast.c print-carp.c print-cdp.c print-cfm.c \ + print-chdlc.c print-cip.c print-cnfp.c print-dccp.c print-decnet.c \ + print-domain.c print-dtp.c print-dvmrp.c print-enc.c print-egp.c \ + print-eap.c print-eigrp.c \ + print-esp.c print-ether.c print-fddi.c print-forces.c print-fr.c print-ftp.c \ + print-geneve.c print-geonet.c print-gre.c print-hsrp.c print-http.c print-icmp.c print-igmp.c \ + print-igrp.c print-ip.c print-ipcomp.c print-ipfc.c print-ipnet.c \ + print-ipx.c print-isoclns.c print-juniper.c print-krb.c \ + print-l2tp.c print-lane.c print-ldp.c print-lldp.c print-llc.c \ + print-lmp.c print-loopback.c print-lspping.c print-lwapp.c print-lwres.c \ + print-m3ua.c print-mobile.c print-mpcp.c print-mpls.c print-mptcp.c print-msdp.c \ + print-msnlb.c print-nflog.c print-nfs.c print-ntp.c print-null.c \ + print-olsr.c print-openflow.c print-openflow-1.0.c print-ospf.c \ + print-pgm.c print-pim.c print-pktap.c\ + print-ppi.c print-ppp.c print-pppoe.c print-pptp.c \ + print-radius.c print-raw.c print-rip.c print-rpki-rtr.c print-rrcp.c print-rsvp.c \ + print-rtsp.c print-rx.c print-sctp.c print-sflow.c print-sip.c print-sl.c print-sll.c \ + print-slow.c print-smtp.c print-snmp.c print-stp.c print-sunatm.c print-sunrpc.c \ + print-symantec.c print-syslog.c print-tcp.c print-telnet.c print-tftp.c \ + print-timed.c print-tipc.c print-token.c print-udld.c print-udp.c \ + print-usb.c print-vjc.c print-vqp.c print-vrrp.c print-vtp.c \ + print-wb.c print-zephyr.c print-zeromq.c print-vxlan.c print-otv.c signature.c setsignal.c tcpdump.c util.c + +tcpdump_LIBNETDISSECT_SRC=print-isakmp.c +tcpdump_LOCALSRC = print-ip6.c print-ip6opts.c print-mobility.c print-ripng.c print-icmp6.c print-frag6.c print-rt6.c print-ospf6.c print-dhcp6.c print-babel.c print-smb.c smbutil.c +tcpdump_GENSRC = version.c + +LOCAL_SRC_FILES:=\ + $(tcpdump_CSRC) $(tcpdump_LIBNETDISSECT_SRC) $(tcpdump_LOCALSRC) $(tcpdump_GENSRC) + +LOCAL_CFLAGS := -O2 -g -pie -fPIE +LOCAL_LDFLAGS += -pie -fPIE +LOCAL_CFLAGS += -DHAVE_CONFIG_H -D_U_="__attribute__((unused))" + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/missing\ + $(LOCAL_PATH)/../libpcap + +#LOCAL_SHARED_LIBRARIES += libssl libcrypto + +LOCAL_STATIC_LIBRARIES += libpcap + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) + +LOCAL_MODULE_TAGS := eng + +LOCAL_MODULE := tcpdump + +include $(BUILD_EXECUTABLE) diff --git a/tcpdump/jni/tcpdump/CHANGES b/tcpdump/jni/tcpdump/CHANGES new file mode 100644 index 0000000..38769f2 --- /dev/null +++ b/tcpdump/jni/tcpdump/CHANGES @@ -0,0 +1,1136 @@ +Friday April 10, 2015 guy@alum.mit.edu + Summary for 4.7.4 tcpdump release + RPKI to Router Protocol: Fix Segmentation Faults and other problems + RPKI to Router Protocol: print strings with fn_printn() + wb: fix some bounds checks + +Wednesday March 11, 2015 mcr@sandelman.ca + Summary for 4.7.3 tcpdump release + Capsicum fixes for FreeBSD 10 + +Tuesday March 10, 2015 mcr@sandelman.ca + Summary for 4.7.2 tcpdump release + DCCP: update Packet Types with RFC4340/IANA names + fixes for CVE-2015-0261: IPv6 mobility header check issue + fixes for CVE-2015-2153, 2154, 2155: kday packets + +Friday Nov. 12, 2014 guy@alum.mit.edu + Summary for 4.7.0 tcpdump release + changes to hex printing of CDP packets + Fix PPI printing + Radius: update Packet Type Codes and Attribute Types with RFC/IANA names + Add a routine to print "text protocols", and add FTP/HTTP/SMTP/RTSP support. + improvements to telnet printer, even if not -v + omit length for bcp, print-tcp uses it + formatting fixes for a bunch of protocols + new bounds checks for a number of protocols + split netflow 1,6, and 6 dissector up. + added geneve dissector + CVE-2014-9140 PPP dissector fixed. + +Tuesday Sep. 2, 2014 mcr@sandelman.ca + Summary for 4.6.2 tcpdump release + fix out-of-source-tree builds: find libpcap that is out of source + better configure check for libsmi + +Saturday Jul. 19, 2014 mcr@sandelman.ca + Summary for 4.6.1 tcpdump release + added FreeBSD capsicum + add a short option '#', same as long option '--number' + +Wednesday Jul. 2, 2014 mcr@sandelman.ca + Summary for 4.6.0 tcpdump release + all of tcpdump is now using the new "NDO" code base (Thanks Denis!) + nflog, mobile, forces, pptp, AODV, AHCP, IPv6, OSPFv4, RPL, DHCPv6 enhancements/fixes + M3UA decode added. + many new test cases: 82 in 4.5.1 to 133 in 4.6.0 + many improvements to travis continuous integration system: OSX, and Coverity options + cleaned up some unnecessary header files + Added bittok2str(). + a number of unaligned access faults fixed + -A flag does not consider CR to be printable anymore + fx.lebail took over coverity baby sitting + default snapshot size increased to 256K for accomodate USB captures + WARNING: this release contains a lot of very worthwhile code churn. + +Wednesday Jan. 15, 2014 guy@alum.mit.edu + Summary for 4.5.2 tcpdump release + Man page fix + Fix crashes on SPARC + +Monday Nov. 11, 2013 mcr@sandelman.ca + Summary for 4.5.1 tcpdump release + CREDITS file fixes + +Thursday Nov. 7, 2013 mcr@sandelman.ca and guy@alum.mit.edu. + Summary for 4.5.0 tcpdump release + some NFSv4 fixes for printing + fix printing of unknown TCP options, and tcp fast-open + fixes for syslog parser + some gcc-version-specific flag tuning + adopt MacOS deprecation workarounds for openssl + improvements to babel printing + add OpenFlow 1.0 (no SSL) and test cases + GeoNet printer. + added STBC Rx support + improvements to DHCPv6 decoder + clarify which autoconf is needed + Point users to the the-tcpdump-group repository on GitHub rather + than the mcr repository + Add MSDP printer. + Fixed IPv6 check on Solaris and other OSes requiring extra + networking libraries. + Add support for VXLAN (draft-mahalingam-dutt-dcops-vxlan-03), + and add "vxlan" as an option for -T. + Add support for OTV (draft-hasmit-otv-04). + fixes for DLT_IEEE802_11_RADIO datalink types + added MPTCP decoder + +Saturday April 6, 2013 guy@alum.mit.edu. + Summary for 4.4.0 tcpdump release + RPKI-RTR (RFC6810) is now official (TCP Port 323) + Fix detection of OpenSSL libcrypto. + Add DNSSL (RFC6106) support. + Add "radius" as an option for -T. + Update Action codes for handle_action function according to + 802.11s amendment. + Decode DHCPv6 AFTR-Name option (RFC6334). + Updates for Babel. + Fix printing of infinite lifetime in ICMPv6. + Added support for SPB, SPBM Service Identifier, and Unicast + Address sub-TLV in ISIS. + Decode RIPv2 authentication up to RFC4822. + Fix RIP Request/full table decoding issues. + On Linux systems with cap-ng.h, drop root privileges + using Linux Capabilities. + Add support for reading multiple files. + Add MS NLB heartbeat printer. + Separate multiple nexthops in BGP. + +Wednesday November 28, 2012 guy@alum.mit.edu. + Summary for 4.3.1 tcpdump release + Print "LLDP, length N" for LLDP packets even when not in verbose + mode, so something is printed even if only the timestamp is + present + Document "-T carp" + Print NTP poll interval correctly (it's an exponent, so print + both its raw value and 2^value) + Document that "-e" is used to get MAC addresses + More clearly document that you need to escape or quote + backslashes in filter expressions on the command line + Fix some "the the" in the man page + Use the right maximum path length + Don't treat 192_1_2, when passed to -i, as an interface number + +Friday April 3, 2012. mcr@sandelman.ca. + Summary for 4.3.0 tcpdump release + fixes for forces: SPARSE data (per RFC 5810) + some more test cases added + updates to documentation on -l, -U and -w flags. + Fix printing of BGP optional headers. + Tried to include DLT_PFSYNC support, failed due to headers required. + added TIPC support. + Fix LLDP Network Policy bit definitions. + fixes for IGMPv3's Max Response Time: it is in units of 0.1 second. + SIGUSR1 can be used rather than SIGINFO for stats + permit -n flag to affect print-ip for protocol numbers + ND_OPT_ADVINTERVAL is in milliseconds, not seconds + Teach PPPoE parser about RFC 4638 + + +Friday December 9, 2011. guy@alum.mit.edu. + Summary for 4.2.1 tcpdump release + Only build the Babel printer if IPv6 is enabled. + Support Babel on port 6696 as well as 6697. + Include ppi.h in release tarball. + Include all the test files in the release tarball, and don't + "include" test files that no longer exist. + Don't assume we have - check for it. + Support "-T carp" as a way of dissecting IP protocol 112 as CARP + rather than VRRP. + Support Hilscher NetAnalyzer link-layer header format. + Constify some pointers and fix compiler warnings. + Get rid of never-true test. + Fix an unintended fall-through in a case statement in the ARP + printer. + Fix several cases where sizeof(sizeof(XXX)) was used when just + sizeof(XXX) was intended. + Make stricter sanity checks in the ES-IS printer. + Get rid of some GCCisms that caused builds to fai with compilers + that don't support them. + Fix typo in man page. + Added length checks to Babel printer. + +Sunday July 24, 2011. mcr@sandelman.ca. + Summary for 4.2.+ + merged 802.15.4 decoder from Dmitry Eremin-Solenikov + updates to forces for new port numbers + Use "-H", not "-h", for the 802.11s option. (-h always help) + Better ICMPv6 checksum handling. + add support for the RPKI/Router Protocol, per -ietf-sidr-rpki-rtr-12 + get rid of uuencoded pcap test files, git can do binary. + sFlow changes for 64-bit counters. + fixes for PPI packet header handling and printing. + Add DCB Exchange protocol (DCBX) version 1.01. + Babel dissector, from Juliusz Chroboczek and Grégoire Henry. + improvements to radiotap for rate values > 127. + Many improvements to ForCES decode, including fix SCTP TML port + updated RPL type code to RPL-17 draft + Improve printout of DHCPv6 options. + added support and test case for QinQ (802.1q VLAN) packets + Handle DLT_IEEE802_15_4_NOFCS like DLT_IEEE802_15_4. + Build fixes for Sparc and other machines with alignment restrictions. + Merged changes from Debian package. + PGM: Add ACK decoding and add PGMCC DATA and FEEDBACK options. + Build fixes for OSX (Snow Leopard and others) + Add support for IEEE 802.15.4 packets + +Tue. July 20, 2010. guy@alum.mit.edu. + Summary for 4.1.2 tcpdump release + If -U is specified, flush the file after creating it, so it's + not zero-length + Fix TCP flags output description, and some typoes, in the man + page + Add a -h flag, and only attempt to recognize 802.11s mesh + headers if it's set + When printing the link-layer type list, send *all* output to + stderr + Include the CFLAGS setting when configure was run in the + compiler flags + +Thu. April 1, 2010. guy@alum.mit.edu. + Summary for 4.1.1 tcpdump release + Fix build on systems with PF, such as FreeBSD and OpenBSD. + Don't blow up if a zero-length link-layer address is passed to + linkaddr_string(). + +Thu. March 11, 2010. ken@netfunctional.ca/guy@alum.mit.edu. + Summary for 4.1.0 tcpdump release + Fix printing of MAC addresses for VLAN frames with a length + field + Add some additional bounds checks and use the EXTRACT_ macros + more + Add a -b flag to print the AS number in BGP packets in ASDOT + notation rather than ASPLAIN notation + Add ICMPv6 RFC 5006 support + Decode the access flags in NFS access requests + Handle the new DLT_ for memory-mapped USB captures on Linux + Make the default snapshot (-s) the maximum + Print name of device (when -L is used) + Support for OpenSolaris (and SXCE build 125 and later) + Print new TCP flags + Add support for RPL DIO + Add support for TCP User Timeout (UTO) + Add support for non-standard Ethertypes used by 3com PPPoE gear + Add support for 802.11n and 802.11s + Add support for Transparent Ethernet Bridge ethertype in GRE + Add 4 byte AS support for BGP printer + Add support for the MDT SAFI 66 BG printer + Add basic IPv6 support to print-olsr + Add USB printer + Add printer for ForCES + Handle frames with an FCS + Handle 802.11n Control Wrapper, Block Acq Req and Block Ack frames + Fix TCP sequence number printing + Report 802.2 packets as 802.2 instead of 802.3 + Don't include -L/usr/lib in LDFLAGS + On x86_64 Linux, look in lib64 directory too + Lots of code clean ups + Autoconf clean ups + Update testcases to make output changes + Fix compiling with/out smi (--with{,out}-smi) + Fix compiling without IPv6 support (--disable-ipv6) + +Mon. October 27, 2008. ken@netfunctional.ca. Summary for 4.0.0 tcpdump release + Add support for Bluetooth Sniffing + Add support for Realtek Remote Control Protocol (openrrcp.org.ru) + Add support for 802.11 AVS + Add support for SMB over TCP + Add support for 4 byte BGP AS printing + Add support for compiling on case-insensitive file systems + Add support for ikev2 printing + Update support for decoding AFS + Update DHCPv6 printer + Use newer libpcap API's (allows -B option on all platforms) + Add -I to turn on monitor mode + Bugfixes in lldp, lspping, dccp, ESP, NFS printers + Cleanup unused files and various cruft + +Mon. September 10, 2007. ken@xelerance.com. Summary for 3.9.8 tcpdump release + Rework ARP printer + Rework OSPFv3 printer + Add support for Frame-Relay ARP + Decode DHCP Option 121 (RFC 3442 Classless Static Route) + Decode DHCP Option 249 (MS Classless Static Route) the same as Option 121 + TLV: Add support for Juniper .pcap extensions + Print EGP header in new-world-order style + Converted print-isakmp.c to NETDISSECT + Moved AF specific stuff into af.h + Test subsystem now table driven, and saves outputs and diffs to one place + Require for pf definitions - allows reading of pflog formatted + libpcap files on an OS other than where the file was generated + + +Wed. July 23, 2007. mcr@xelerance.com. Summary for 3.9.7 libpcap release + + NFS: Print unsigned values as such. + RX: parse safely. + BGP: fixes for IPv6-less builds. + 801.1ag: use standard codepoint. + use /dev/bpf on systems with such a device. + 802.11: print QoS data, avoid dissect of no-data frame, ignore padding. + smb: make sure that we haven't gone past the end of the captured data. + smb: squelch an uninitialized complaint from coverity. + NFS: from NetBSD; don't interpret the reply as a possible NFS reply + if it got MSG_DENIED. + BGP: don't print TLV values that didn't fit, from www.digit-labs.org. + revised INSTALL.txt about libpcap dependancy. + +Wed. April 25, 2007. ken@xelerance.com. Summary for 3.9.6 tcpdump release + Update man page to reflect changes to libpcap + Changes to both TCP and IP Printer Output + Fix a potential buffer overflow in the 802.11 printer + Print basic info about a few more Cisco LAN protocols. + mDNS cleanup + ICMP MPLS rework of the extension code + bugfix: use the correct codepoint for the OSPF simple text auth token + entry, and use safeputs to print the password. + Add support in pflog for additional values + Add support for OIF RSVP Extensions UNI 1.0 Rev. 2 and additional RSVP objects + Add support for the Message-id NACK c-type. + Add support for 802.3ah loopback ctrl msg + Add support for Multiple-STP as per 802.1s + Add support for rapid-SPT as per 802.1w + Add support for CFM Link-trace msg, Link-trace-Reply msg, + Sender-ID tlv, private tlv, port, interface status + Add support for unidirectional link detection as per + http://www.ietf.org/internet-drafts/draft-foschiano-udld-02.txt + Add support for the olsr protocol as per RFC 3626 plus the LQ + extensions from olsr.org + Add support for variable-length checksum in DCCP, as per section 9 of + RFC 4340. + Add support for per-VLAN spanning tree and per-VLAN rapid spanning tree + Add support for Multiple-STP as per 802.1s + Add support for the cisco propriatry 'dynamic trunking protocol' + Add support for the cisco proprietary VTP protocol + Update dhcp6 options table as per IETF standardization activities + + +Tue. September 19, 2006. ken@xelerance.com. Summary for 3.9.5 tcpdump release + + Fix compiling on AIX (, at end of ENUM) + Updated list of DNS RR typecodes + Use local Ethernet defs on WIN32 + Add support for Frame-Relay ARP + Fixes for compiling under MSVC++ + Add support for parsing Juniper .pcap files + Add support for FRF.16 Multilink Frame-Relay (DLT_MFR) + Rework the OSPFv3 printer + Fix printing for 4.4BSD/NetBSD NFS Filehandles + Add support for Cisco style NLPID encapsulation + Add cisco prop. eigrp related, extended communities + Add support for BGP signaled VPLS + Cleanup the bootp printer + Add support for PPP over Frame-Relay + Add some bounds checking to the IP options code, and clean up + the options output a bit. + Add additional modp groups to ISAKMP printer + Add support for Address-Withdraw and Label-Withdraw Msgs + Add support for the BFD Discriminator TLV + Fixes for 64bit compiling + Add support for PIMv2 checksum verification + Add support for further dissection of the IPCP Compression Option + Add support for Cisco's proposed VQP protocol + Add basic support for keyed authentication TCP option + Lots of minor cosmetic changes to output printers + + +Mon. September 19, 2005. ken@xelerance.com. Summary for 3.9.4 tcpdump release + Decoder support for more Juniper link-layer types + Fix a potential buffer overflow (although it can't occur in + practice). + Fix the handling of unknown management frame types in the 802.11 + printer. + Add FRF.16 support, fix various Frame Relay bugs. + Add support for RSVP integrity objects, update fast-reroute + object printer to latest spec. + Clean up documentation of vlan filter expression, document mpls + filter expression. + Document new pppoed and pppoes filter expressions. + Update diffserver-TE codepoints as per RFC 4124. + Spelling fixes in ICMPv6. + Don't require any fields other than flags to be present in IS-IS + restart signaling TLVs, and only print the system ID in + those TLVs as system IDs, not as node IDs. + Support for DCCP. + +Tue. July 5, 2005. ken@xelerance.com. Summary for 3.9.3 tcpdump release + + Option to chroot() when dropping privs + Fixes for compiling on nearly every platform, + including improved 64bit support + Many new testcases + Support for sending packets + Many compliation fixes on most platforms + Fixes for recent version of GCC to eliminate warnings + Improved Unicode support + + Decoders & DLT Changes, Updates and New: + AES ESP support + Juniper ATM, FRF.15, FRF.16, PPPoE, + ML-FR, ML-PIC, ML-PPP, PL-PPP, LS-PIC + GGSN,ES,MONITOR,SERVICES + L2VPN + Axent Raptor/Symantec Firewall + TCP-MD5 (RFC 2385) + ESP-in-UDP (RFC 3948) + ATM OAM + LMP, LMP Service Discovery + IP over FC + IP over IEEE 1394 + BACnet MS/TP + SS7 + LDP over TCP + LACP, MARKER as per 802.3ad + PGM (RFC 3208) + LSP-PING + G.7041/Y.1303 Generic Framing Procedure + EIGRP-IP, EIGRP-IPX + ICMP6 + Radio - via radiotap + DHCPv6 + HDLC over PPP + +Tue. March 30, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.3 release + + No changes from 3.8.2. Version bumped only to maintain consistency + with libpcap 0.8.3. + +Mon. March 29, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.2 release + + Fixes for print-isakmp.c CVE: CAN-2004-0183, CAN-2004-0184 + http://www.rapid7.com/advisories/R7-0017.html + IP-over-IEEE1394 printing. + some MINGW32 changes. + updates for autoconf 2.5 + fixes for print-aodv.c - check for too short packets + formatting changes to print-ascii for hex output. + check for too short packets: print-bgp.c, print-bootp.c, print-cdp.c, + print-chdlc.c, print-domain.c, print-icmp.c, print-icmp6.c, + print-ip.c, print-lwres.c, print-ospf.c, print-pim.c, + print-ppp.c,print-pppoe.c, print-rsvp.c, print-wb.c + print-ether.c - better handling of unknown types. + print-isoclns.c - additional decoding of types. + print-llc.c - strings for LLC names added. + print-pfloc.c - various enhancements + print-radius.c - better decoding to strings. + +Wed. November 12, 2003. mcr@sandelman.ottawa.on.ca. Summary for 3.8 release + + changed syntax of -E argument so that multiple SAs can be decrypted + fixes for Digital Unix headers and Documentation + __attribute__ fixes + CDP changes from Terry Kennedy . + IPv6 mobility updates from Kazushi Sugyo + Fixes for ASN.1 decoder for 2.100.3 forms. + Added a count of packets received and processed to clarify numbers. + Incorporated WinDUMP patches for Win32 builds. + PPPoE payload length headers. + Fixes for HP C compiler builds. + Use new pcap_breakloop() and pcap_findalldevs() if we can. + BGP output split into multiple lines. + Fixes to 802.11 decoding. + Fixes to PIM decoder. + SuperH is a CPU that can't handle unaligned access. Many fixes for + unaligned access work. + Fixes to Frame-Relay decoder for Q.933/922 frames. + Clarified when Solaris can do captures as non-root. + Added tests/ subdir for examples/regression tests. + New -U flag. -flush stdout after every packet + New -A flag -print ascii only + support for decoding IS-IS inside Cisco HDLC Frames + more verbosity for tftp decoder + mDNS decoder + new BFD decoder + cross compilation patches + RFC 3561 AODV support. + UDP/TCP pseudo-checksum properly for source-route options. + sanitized all files to modified BSD license + Add support for RFC 2625 IP-over-Fibre Channel. + fixes for DECnet support. + Support RFC 2684 bridging of Ethernet, 802.5 Token Ring, and FDDI. + RFC 2684 encapsulation of BPDUs. + +Tuesday, February 25, 2003. fenner@research.att.com. 3.7.2 release + + Fixed infinite loop when parsing malformed isakmp packets. + (reported by iDefense; already fixed in CVS) + Fixed infinite loop when parsing malformed BGP packets. + Fixed buffer overflow with certain malformed NFS packets. + Pretty-print unprintable network names in 802.11 printer. + Handle truncated nbp (appletalk) packets. + Updated DHCPv6 printer to match draft-ietf-dhc-dhcpv6-22.txt + Print IP protocol name even if we don't have a printer for it. + Print IP protocol name or number for fragments. + Print the whole MPLS label stack, not just the top label. + Print request header and file handle for NFS v3 FSINFO and PATHCONF + requests. + Fix NFS packet truncation checks. + Handle "old" DR-Priority and Bidir-Capable PIM HELLO options. + Handle unknown RADIUS attributes properly. + Fix an ASN.1 parsing error that would cause e.g. the OID + 2.100.3 to be misrepresented as 4.20.3 . + +Monday, January 21, 2002. mcr@sandelman.ottawa.on.ca. Summary for 3.7 release +see http://www.tcpdump.org/cvs-log/2002-01-21.10:16:48.html for commit log. + keyword "ipx" added. + Better OSI/802.2 support on Linux. + IEEE 802.11 support, from clenahan@fortresstech.com, achirica@ttd.net. + LLC SAP support for FDDI/token ring/RFC-1483 style ATM + BXXP protocol was replaced by the BEEP protocol; + improvements to SNAP demux. + Changes to "any" interface documentation. + Documentation on pcap_stats() counters. + Fix a memory leak found by Miklos Szeredi - pcap_ether_aton(). + Added MPLS encapsulation decoding per RFC3032. + DNS dissector handles TKEY, TSIG and IXFR. + adaptive SLIP interface patch from Igor Khristophorov + SMB printing has much improved bounds checks + OUI 0x0000f8 decoded as encapsulated ethernet for Cisco-custom bridging + Zephyr support, from Nickolai Zeldovich . + Solaris - devices with digits in them. Stefan Hudson + IPX socket 0x85be is for Cisco EIGRP over IPX. + Improvements to fragmented ESP handling. + SCTP support from Armando L. Caro Jr. + Linux ARPHDR_ATM support fixed. + Added a "netbeui" keyword, which selects NetBEUI packets. + IPv6 ND improvements, MobileIP dissector, 2292bis-02 for RA option. + Handle ARPHDR_HDLC from Marcus Felipe Pereira . + Handle IPX socket 0x553 -> NetBIOS-over-IPX socket, "nwlink-dgm" + Better Linux libc5 compat. + BIND9 lwres dissector added. + MIPS and SPARC get strict alignment macros (affects print-bgp.c) + Apple LocalTalk LINKTYPE_ reserved. + New time stamp formats documented. + DHCP6 updated to draft-22.txt spec. + ICMP types/codes now accept symbolic names. + Add SIGINFO handler from LBL + encrypted CIPE tunnels in IRIX, from Franz Schaefer . + now we are -Wstrict-prototype clean. + NetBSD DLT_PPP_ETHER; adapted from Martin Husemann . + PPPoE dissector cleaned up. + Support for LocalTalk hardware, from Uns Lider . + In dissector, now the caller prints the IP addresses rather than proto. + cjclark@alum.mit.edu: print the IP proto for non-initial fragments. + LLC frames with a DSAP and LSAP of 0xe0 are IPX frames. + Linux cooked frames with a type value of LINUX_SLL_P_802_3 are IPX. + captures on the "any" device won't be done in promiscuous mode + Token Ring support on DLPI - Onno van der Linden + ARCNet support, from NetBSD. + HSRP dissector, from Julian Cowley . + Handle (GRE-encapsulated) PPTP + added -C option to rotate save file every optarg * 1,000,000 bytes. + support for "vrrp" name - NetBSD, by Klaus Klein . + PPTP support, from Motonori Shindo . + IS-IS over PPP support, from Hannes Gredler . + CNFP support for IPv6,format. Harry Raaymakers . + ESP printing updated to RFC2406. + HP-UX can now handle large number of PPAs. + MSDP printer added. + L2TP dissector improvements from Motonori Shindo. + +Tuesday January 9, 2001. mcr@sandelman.ottawa.on.ca. Summary for 3.6 release + Cleaned up documentation. + Promisc mode fixes for Linux + IPsec changes/cleanups. + Alignment fixes for picky architectures + + Removed dependency on native headers for packet dissectors. + Removed Linux specific headers that were shipped + + libpcap changes provide for exchanging capture files between + systems. Save files now have well known PACKET_ values instead of + depending upon system dependant mappings of DLT_* types. + + Support for computing/checking IP and UDP/TCP checksums. + + Updated autoconf stock files. + + IPv6 improvements: dhcp (draft-15), mobile-ip6, ppp, ospf6, + + Added dissector support for: ISOCLNS, Token Ring, IGMPv3, bxxp, + timed, vrrp, radius, chdlc, cnfp, cdp, IEEE802.1d, raw-AppleTalk + + Added filtering support for: VLANs, ESIS, ISIS + + Improvements to: print-telnet, IPTalk, bootp/dhcp, ECN, PPP, + L2TP, PPPoE + + HP-UX 11.0 -- find the right dlpi device. + Solaris 8 - IPv6 works + Linux - Added support for an "any" device to capture on all interfaces + + Security fixes: buffer overrun audit done. Strcpy replaced with + strlcpy, sprintf replaced with snprintf. + Look for lex problems, and warn about them. + + +v3.5 Fri Jan 28 18:00:00 PST 2000 + +Bill Fenner +- switch to config.h for autoconf +- unify RCSID strings +- Updated PIMv1, PIMv2, DVMRP, IGMP parsers, add Cisco Auto-RP parser +- Really fix the RIP printer +- Fix MAC address -> name translation. +- some -Wall -Wformat fixes +- update makemib to parse much of SMIv2 +- Print TCP sequence # with -vv even if you normally wouldn't +- Print as much of IP/TCP/UDP headers as possible even if truncated. + +itojun@iijlab.net +- -X will make a ascii dump. from netbsd. +- telnet command sequence decoder (ff xx xx). from netbsd. +- print-bgp.c: improve options printing. ugly code exists for + unaligned option parsing (need some fix). +- const poisoning in SMB decoder. +- -Wall -Werror clean checks. +- bring in KAME IPv6/IPsec decoding code. + +Assar Westerlund +- SNMPv2 and SNMPv3 printer +- If compiled with libsmi, tcpdump can load MIBs on the fly to decode + SNMP packets. +- Incorporate NFS parsing code from NetBSD. Adds support for nfsv3. +- portability fixes +- permit building in different directories. + +Ken Hornstein +- bring in code at + /afs/transarc.com/public/afs-contrib/tools/tcpdump for parsing + AFS3 packets + +Andrew Tridgell +- SMB printing code + +Love +- print-rx.c: add code for printing MakeDir and StoreStatus. Also + change date format to the right one. + +Michael C. Richardson +- Created tcpdump.org repository + +v3.4 Sat Jul 25 12:40:55 PDT 1998 + +- Hardwire Linux slip support since it's too hard to detect. + +- Redo configuration of "network" libraries (-lsocket and -lnsl) to + deal with IRIX. Thanks to John Hawkinson (jhawk@mit.edu) + +- Added -a which tries to translate network and broadcast addresses to + names. Suggested by Rob van Nieuwkerk (robn@verdi.et.tudelft.nl) + +- Added a configure option to disable gcc. + +- Added a "raw" packet printer. + +- Not having an interface address is no longer fatal. Requested by John + Hawkinson. + +- Rework signal setup to accommodate Linux. + +- OSPF truncation check fix. Also display the type of OSPF packets + using MD5 authentication. Thanks to Brian Wellington + (bwelling@tis.com) + +- Fix truncation check bugs in the Kerberos printer. Reported by Ezra + Peisach (epeisach@mit.edu) + +- Don't catch SIGHUP when invoked with nohup(1). Thanks to Dave Plonka + (plonka@mfa.com) + +- Specify full install target as a way of detecting if install + directory does not exist. Thanks to Dave Plonka. + +- Bit-swap FDDI addresses for BSD/OS too. Thanks to Paul Vixie + (paul@vix.com) + +- Fix off-by-one bug when testing size of ethernet packets. Thanks to + Marty Leisner (leisner@sdsp.mc.xerox.com) + +- Add a local autoconf macro to check for routines in libraries; the + autoconf version is broken (it only puts the library name in the + cache variable name). Thanks to John Hawkinson. + +- Add a local autoconf macro to check for types; the autoconf version + is broken (it uses grep instead of actually compiling a code fragment). + +- Modified to support the new BSD/OS 2.1 PPP and SLIP link layer header + formats. + +- Extend OSF ip header workaround to versions 1 and 2. + +- Fix some signed problems in the nfs printer. As reported by David + Sacerdote (davids@silence.secnet.com) + +- Detect group wheel and use it as the default since BSD/OS' install + can't hack numeric groups. Reported by David Sacerdote. + +- AIX needs special loader options. Thanks to Jonathan I. Kamens + (jik@cam.ov.com) + +- Fixed the nfs printer to print port numbers in decimal. Thanks to + Kent Vander Velden (graphix@iastate.edu) + +- Find installed libpcap in /usr/local/lib when not using gcc. + +- Disallow network masks with non-network bits set. + +- Attempt to detect "egcs" versions of gcc. + +- Add missing closing double quotes when displaying bootp strings. + Reported by Viet-Trung Luu (vluu@picard.math.uwaterloo.ca) + +v3.3 Sat Nov 30 20:56:27 PST 1996 + +- Added Linux support. + +- GRE encapsulated packet printer thanks to John Hawkinson + (jhawk@mit.edu) + +- Rewrite gmt2local() to avoid problematic os dependencies. + +- Suppress nfs truncation message on errors. + +- Add missing m4 quoting in AC_LBL_UNALIGNED_ACCESS autoconf macro. + Reported by Joachim Ott (ott@ardala.han.de) + +- Enable "ip_hl vs. ip_vhl" workaround for OSF4 too. + +- Print arp hardware type in host order. Thanks to Onno van der Linden + (onno@simplex.nl) + +- Avoid solaris compiler warnings. Thanks to Bruce Barnett + (barnett@grymoire.crd.ge.com) + +- Fix rip printer to not print one more route than is actually in the + packet. Thanks to Jean-Luc Richier (Jean-Luc.Richier@imag.fr) and + Bill Fenner (fenner@parc.xerox.com) + +- Use autoconf endian detection since BYTE_ORDER isn't defined on all systems. + +- Fix dvmrp printer truncation checks and add a dvmrp probe printer. + Thanks to Danny J. Mitzel (mitzel@ipsilon.com) + +- Rewrite ospf printer to improve truncation checks. + +- Don't parse tcp options past the EOL. As noted by David Sacerdote + (davids@secnet.com). Also, check tcp options to make sure they ar + actually in the tcp header (in addition to the normal truncation + checks). Fix the SACK code to print the N blocks (instead of the + first block N times). + +- Don't say really small UDP packets are truncated just because they + aren't big enough to be a RPC. As noted by David Sacerdote. + +v3.2.1 Sun Jul 14 03:02:26 PDT 1996 + +- Added rfc1716 icmp codes as suggested by Martin Fredriksson + (martin@msp.se) + +- Print mtu for icmp unreach need frag packets. Thanks to John + Hawkinson (jhawk@mit.edu) + +- Decode icmp router discovery messages. Thanks to Jeffrey Honig + (jch@bsdi.com) + +- Added a printer entry for DLT_IEEE802 as suggested by Tak Kushida + (kushida@trl.ibm.co.jp) + +- Check igmp checksum if possible. Thanks to John Hawkinson. + +- Made changes for SINIX. Thanks to Andrej Borsenkow + (borsenkow.msk@sni.de) + +- Use autoconf's idea of the top level directory in install targets. + Thanks to John Hawkinson. + +- Avoid infinite loop in tcp options printing code. Thanks to Jeffrey + Mogul (mogul@pa.dec.com) + +- Avoid using -lsocket in IRIX 5.2 and earlier since it breaks snoop. + Thanks to John Hawkinson. + +- Added some more packet truncation checks. + +- On systems that have it, use sigset() instead of signal() since + signal() has different semantics on these systems. + +- Fixed some more alignment problems on the alpha. + +- Add code to massage unprintable characters in the domain and ipx + printers. Thanks to John Hawkinson. + +- Added explicit netmask support. Thanks to Steve Nuchia + (steve@research.oknet.com) + +- Add "sca" keyword (for DEC cluster services) as suggested by Terry + Kennedy (terry@spcvxa.spc.edu) + +- Add "atalk" keyword as suggested by John Hawkinson. + +- Added an igrp printer. Thanks to Francis Dupont + (francis.dupont@inria.fr) + +- Print IPX net numbers in hex a la Novell Netware. Thanks to Terry + Kennedy (terry@spcvxa.spc.edu) + +- Fixed snmp extended tag field parsing bug. Thanks to Pascal Hennequin + (pascal.hennequin@hugo.int-evry.fr) + +- Added some ETHERTYPEs missing on some systems. + +- Added truncated packet macros and various checks. + +- Fixed endian problems with the DECnet printer. + +- Use $CC when checking gcc version. Thanks to Carl Lindberg + (carl_lindberg@blacksmith.com) + +- Fixes for AIX (although this system is not yet supported). Thanks to + John Hawkinson. + +- Fix bugs in the autoconf misaligned accesses code fragment. + +- Include sys/param.h to get BYTE_ORDER in a few places. Thanks to + Pavlin Ivanov Radoslavov (pavlin@cs.titech.ac.jp) + +v3.2 Sun Jun 23 02:28:10 PDT 1996 + +- Print new icmp unreachable codes as suggested by Martin Fredriksson + (martin@msp.se). Also print code value when unknown for icmp redirect + and time exceeded. + +- Fix an alignment endian bug in getname(). Thanks to John Hawkinson. + +- Define "new" domain record types if not found in arpa/nameserv.h. + Resulted from a suggestion from John Hawkinson (jhawk@mit.edu). Also + fixed an endian bug when printing mx record and added some new record + types. + +- Added RIP V2 support. Thanks to Jeffrey Honig (jch@bsdi.com) + +- Added T/TCP options printing. As suggested by Richard Stevens + (rstevens@noao.edu) + +- Use autoconf to detect architectures that can't handle misaligned + accesses. + +v3.1 Thu Jun 13 20:59:32 PDT 1996 + +- Changed u_int32/int32 to u_int32_t/int32_t to be consistent with bsd + and bind (as suggested by Charles Hannum). + +- Port to GNU autoconf. + +- Add support for printing DVMRP and PIM traffic thanks to + Havard Eidnes (Havard.Eidnes@runit.sintef.no). + +- Fix AppleTalk, IPX and DECnet byte order problems due to wrong endian + define being referenced. Reported by Terry Kennedy. + +- Minor fixes to the man page thanks to Mark Andrews. + +- Endian fixes to RTP and vat packet dumpers, thanks to Bruce Mah + (bmah@cs.berkeley.edu). + +- Added support for new dns types, thanks to Rainer Orth. + +- Fixed tftp_print() to print the block number for ACKs. + +- Document -dd and -ddd. Resulted from a bug report from Charlie Slater + (cslater@imatek.com). + +- Check return status from malloc/calloc/etc. + +- Check return status from pcap_loop() so we can print an error and + exit with a bad status if there were problems. + +- Bail if ip option length is <= 0. Resulted from a bug report from + Darren Reed (darrenr@vitruvius.arbld.unimelb.edu.au). + +- Print out a little more information for sun rpc packets. + +- Add suport for Kerberos 4 thanks to John Hawkinson (jhawk@mit.edu). + +- Fixed the Fix EXTRACT_SHORT() and EXTRACT_LONG() macros (which were + wrong on little endian machines). + +- Fixed alignment bug in ipx_decode(). Thanks to Matt Crawford + (crawdad@fnal.gov). + +- Fix ntp_print() to not print garbage when the stratum is + "unspecified." Thanks to Deus Ex Machina (root@belle.bork.com). + +- Rewrote tcp options printer code to check for truncation. Added + selective acknowledgment case. + +- Fixed an endian bug in the ospf printer. Thanks to Jeffrey C Honig + (jch@bsdi.com) + +- Fix rip printer to handle 4.4 BSD sockaddr struct which only uses one + octet for the sa_family member. Thanks to Yoshitaka Tokugawa + (toku@dit.co.jp) + +- Don't checksum ip header if we don't have all of it. Thanks to John + Hawkinson (jhawk@mit.edu). + +- Print out hostnames if possible in egp printer. Thanks to Jeffrey + Honig (jhc@bsdi.com) + + +v3.1a1 Wed May 3 19:21:11 PDT 1995 + +- Include time.h when SVR4 is defined to avoid problems under Solaris + 2.3. + +- Fix etheraddr_string() in the ETHER_SERVICE to return the saved + strings, not the local buffer. Thanks to Stefan Petri + (petri@ibr.cs.tu-bs.de). + +- Detect when pcap raises the snaplen (e.g. with snit). Print a warning + that the selected value was not used. Thanks to Pascal Hennequin + (Pascal.Hennequin@hugo.int-evry.fr). + +- Add a truncated packet test to print-nfs.c. Thanks to Pascal Hennequin. + +- BYTEORDER -> BYTE_ORDER Thanks to Terry Kennedy (terry@spcvxa.spc.edu). + +v3.0.3 Sun Oct 1 18:35:00 GMT 1995 + +- Although there never was a 3.0.3 release, the linux boys cleverly + "released" one in late 1995. + +v3.0.2 Thu Apr 20 21:28:16 PDT 1995 + +- Change configuration to not use gcc v2 flags with gcc v1. + +- Redo gmt2local() so that it works under BSDI (which seems to return + an empty timezone struct from gettimeofday()). Based on report from + Terry Kennedy (terry@spcvxa.spc.edu). + +- Change configure to recognize IP[0-9]* as "mips" SGI hardware. Based + on report from Mark Andrews (mandrews@alias.com). + +- Don't pass cc flags to gcc. Resulted from a bug report from Rainer + Orth (ro@techfak.uni-bielefeld.de). + +- Fixed printout of connection id for uncompressed tcp slip packets. + Resulted from a bug report from Richard Stevens (rstevens@noao.edu). + +- Hack around deficiency in Ultrix's make. + +- Add ETHERTYPE_TRAIL define which is missing from irix5. + +v3.0.1 Wed Aug 31 22:42:26 PDT 1994 + +- Fix problems with gcc2 vs. malloc() and read() prototypes under SunOS 4. + +v3.0 Mon Jun 20 19:23:27 PDT 1994 + +- Added support for printing tcp option timestamps thanks to + Mark Andrews (mandrews@alias.com). + +- Reorganize protocol dumpers to take const pointers to packets so they + never change the contents (i.e., they used to do endian conversions + in place). Previously, whenever more than one pass was taken over + the packet, the packet contents would be dumped incorrectly (i.e., + the output form -x would be wrong on little endian machines because + the protocol dumpers would modify the data). Thanks to Charles Hannum + (mycroft@gnu.ai.mit.edu) for reporting this problem. + +- Added support for decnet protocol dumping thanks to Jeff Mogul + (mogul@pa.dec.com). + +- Fix bug that caused length of packet to be incorrectly printed + (off by ether header size) for unknown ethernet types thanks + to Greg Miller (gmiller@kayak.mitre.org). + +- Added support for IPX protocol dumping thanks to Brad Parker + (brad@fcr.com). + +- Added check to verify IP header checksum under -v thanks to + Brad Parker (brad@fcr.com). + +- Move packet capture code to new libpcap library (which is + packaged separately). + +- Prototype everything and assume an ansi compiler. + +- print-arp.c: Print hardware ethernet addresses if they're not + what we expect. + +- print-bootp.c: Decode the cmu vendor field. Add RFC1497 tags. + Many helpful suggestions from Gordon Ross (gwr@jericho.mc.com). + +- print-fddi.c: Improvements. Thanks to Jeffrey Mogul + (mogul@pa.dec.com). + +- print-icmp.c: Byte swap netmask before printing. Thanks to + Richard Stevens (rstevens@noao.edu). Print icmp type when unknown. + +- print-ip.c: Print the inner ip datagram of ip-in-ip encapsulated packets. + By default, only the inner packet is dumped, appended with the token + "(encap)". Under -v, both the inner and output packets are dumped + (on the same line). Note that the filter applies to the original packet, + not the encapsulated packet. So if you run tcpdump on a net with an + IP Multicast tunnel, you cannot filter out the datagrams using the + conventional syntax. (You can filter away all the ip-in-ip traffic + with "not ip proto 4".) + +- print-nfs.c: Keep pending rpc's in circular table. Add generic + nfs header and remove os dependences. Thanks to Jeffrey Mogul. + +- print-ospf.c: Improvements. Thanks to Jeffrey Mogul. + +- tcpdump.c: Add -T flag allows interpretation of "vat", "wb", "rpc" + (sunrpc) and rtp packets. Added "inbound" and "outbound" keywords + Add && and || operators + +v2.2.1 Tue Jun 6 17:57:22 PDT 1992 + +- Fix bug with -c flag. + +v2.2 Fri May 22 17:19:41 PDT 1992 + +- savefile.c: Remove hack that shouldn't have been exported. Add + truncate checks. + +- Added the 'icmp' keyword. For example, 'icmp[0] != 8 and icmp[0] != 0' + matches non-echo/reply ICMP packets. + +- Many improvements to filter code optimizer. + +- Added 'multicast' keyword and extended the 'broadcast' keyword can now be + so that protocol qualifications are allowed. For example, "ip broadcast" + and "ether multicast" are valid filters. + +- Added support for monitoring the loopback interface (i.e. 'tcpdump -i lo'). + Jeffrey Honig (jch@MITCHELL.CIT.CORNELL.EDU) contributed the kernel + patches to netinet/if_loop.c. + +- Added support for the Ungermann-Bass Ethernet on IBM/PC-RTs running AOS. + Contact Jeffrey Honig (jch@MITCHELL.CIT.CORNELL.EDU) for the diffs. + +- Added EGP and OSPF printers, thanks to Jeffrey Honig. + +v2.1 Tue Jan 28 11:00:14 PST 1992 + +- Internal release (never publically exported). + +v2.0.1 Sun Jan 26 21:10:10 PDT + +- Various byte ordering fixes. + +- Add truncation checks. + +- inet.c: Support BSD style SIOCGIFCONF. + +- nametoaddr.c: Handle multi addresses for single host. + +- optimize.c: Rewritten. + +- pcap-bpf.c: don't choke when we get ptraced. only set promiscuous + for broadcast nets. + +- print-atal.c: Fix an alignment bug (thanks to + stanonik@nprdc.navy.mil) Add missing printf() argument. + +- print-bootp.c: First attempt at decoding the vendor buffer. + +- print-domain.c: Fix truncation checks. + +- print-icmp.c: Calculate length of packets from the ip header. + +- print-ip.c: Print frag id in decimal (so it's easier to match up + with non-frags). Add support for ospf, egp and igmp. + +- print-nfs.c: Lots of changes. + +- print-ntp.c: Make some verbose output depend on -v. + +- print-snmp.c: New version from John LoVerso. + +- print-tcp.c: Print rfc1072 tcp options. + +- tcpdump.c: Print "0x" prefix for %x formats. Always print 6 digits + (microseconds) worth of precision. Fix uid bugs. + +- A packet dumper has been added (thanks to Jeff Mogul of DECWRL). + With this option, you can create an architecture independent binary + trace file in real time, without the overhead of the packet printer. + At a later time, the packets can be filtered (again) and printed. + +- BSD is supported. You must have BPF in your kernel. + Since the filtering is now done in the kernel, fewer packets are + dropped. In fact, with BPF and the packet dumper option, a measly + Sun 3/50 can keep up with a busy network. + +- Compressed SLIP packets can now be dumped, provided you use our + SLIP software and BPF. These packets are dumped as any other IP + packet; the compressed headers are dumped with the '-e' option. + +- Machines with little-endian byte ordering are supported (thanks to + Jeff Mogul). + +- Ultrix 4.0 is supported (also thanks to Jeff Mogul). + +- IBM RT and Stanford Enetfilter support has been added by + Rayan Zachariassen . Tcpdump has been tested under + both the vanilla Enetfilter interface, and the extended interface + (#ifdef'd by IBMRTPC) present in the MERIT version of the Enetfilter. + +- TFTP packets are now printed (requests only). + +- BOOTP packets are now printed. + +- SNMP packets are now printed. (thanks to John LoVerso of Xylogics). + +- Sparc architectures, including the Sparcstation-1, are now + supported thanks to Steve McCanne and Craig Leres. + +- SunOS 4 is now supported thanks to Micky Liu of Columbia + University (micky@cunixc.cc.columbia.edu). + +- IP options are now printed. + +- RIP packets are now printed. + +- There's a -v flag that prints out more information than the + default (e.g., it will enable printing of IP ttl, tos and id) + and -q flag that prints out less (e.g., it will disable + interpretation of AppleTalk-in-UDP). + +- The grammar has undergone substantial changes (if you have an + earlier version of tcpdump, you should re-read the manual + entry). + + The most useful change is the addition of an expression + syntax that lets you filter on arbitrary fields or values in the + packet. E.g., "ip[0] > 0x45" would print only packets with IP + options, "tcp[13] & 3 != 0" would print only TCP SYN and FIN + packets. + + The most painful change is that concatenation no longer means + "and" -- e.g., you have to say "host foo and port bar" instead + of "host foo port bar". The up side to this down is that + repeated qualifiers can be omitted, making most filter + expressions shorter. E.g., you can now say "ip host foo and + (bar or baz)" to look at ip traffic between hosts foo and bar or + between hosts foo and baz. [The old way of saying this was "ip + host foo and (ip host bar or ip host baz)".] + +v2.0 Sun Jan 13 12:20:40 PST 1991 + +- Initial public release. diff --git a/tcpdump/jni/tcpdump/CREDITS b/tcpdump/jni/tcpdump/CREDITS new file mode 100644 index 0000000..a21311a --- /dev/null +++ b/tcpdump/jni/tcpdump/CREDITS @@ -0,0 +1,229 @@ +This file lists people who have contributed to tcpdump: + +The current maintainers: + Bill Fenner + Denis Ovsienko + Fulvio Risso + Guy Harris + Hannes Gredler + Michael Richardson + Francois-Xavier Le Bail + +Additional people who have contributed patches: + + Aaron Campbell + A Costa + Albert Chin + Alexandra Kossovsky + Alfredo Andres + Ananth Suryanarayana + Andrea Bittau + Andrew Brown + Andrew Church + Andrew Hintz + Andrew Nording + Andrew Tridgell + Andy Heffernan + Anton Bernal + Arkadiusz Miskiewicz + Armando L. Caro Jr. + Arnaldo Carvalho de Melo + Atsushi Onoe + Baptiste Jonglez + Ben Byer + Ben Smithurst + Bert Vermeulen + Bjoern A. Zeeb + Bram + Brent L. Bates + Brian Ginsbach + Bruce M. Simpson + Carles Kishimoto Bisbe + Charles M. Hannum + Charlie Lenahan + Chris Cogdon + Chris G. Demetriou + Chris Jepeway + Chris Larson + Christian Sievers + Christophe Rhodes + Cliff Frey + Craig Rodrigues + Crist J. Clark + Daniel Hagerty + Darren Reed + David Binderman + David Horn + David Smith + David Young + Dmitrij Tejblum + Dmitry Eremin-Solenikov + Don Ebright + Eddie Kohler + Elmar Kirchner + Fang Wang + Florent Drouin + Florian Forster + fra + Francesco Fondelli + Francisco Matias Cuenca-Acuna + Francis Dupont + Frank Volf + Fulvio Risso + George Bakos + Gerald Combs + Gerrit Renker + Gert Doering + Gilbert Ramirez Jr. + Gisle Vanem + Greg Minshall + Grégoire Henry + Gregory Detal + Greg Stark + Hank Leininger + Hannes Viertel + Harry Raaymakers + Heinz-Ado Arnolds + Hendrik Scholz + Herwin Weststrate + Ian McDonald + Ilpo Järvinen + Jacek Tobiasz + Jakob Schlyter + Jamal Hadi Salim + Jan Oravec + Jason R. Thorpe + Jefferson Ogata + Jeffrey Hutzelman + Jesper Peterson + Jesse Gross + Jim Hutchins + João Medeiros + Joerg Mayer + Jonathan Heusser + Jorge Boncompte [DTI2] + Jørgen Thomsen + Julian Cowley + Juliusz Chroboczek + Kaarthik Sivakumar + Kaladhar Musunuru + Karl Norby + Kazushi Sugyo + Kelly Carmichael + Ken Hornstein + Kenichi Maehashi + Kevin Steves + Klaus Klein + Kris Kennaway + Krzysztof Halasa + Larry Lile + Lennert Buytenhek + Loganaden Velvindron + Longinus00 + Loris Degioanni + Love Hörnquist-Åstrand + Lucas C. Villa Real + Luis MartinGarcia + Maciej W. Rozycki + Manu Pathak + Marc Abramowitz + Marc A. Lehmann + Marc Binderberger + Mark Ellzey Thomas + Marko Kiiskila + Markus Schöpflin + Marshall Rose + Martin Husemann + Max Laier + Michael A. Meffie III + Michael Madore + Michael Riepe + Michael Shalayeff + Michael Shields + Michael T. Stolarchuk + Michal Sekletar + Michele "mydecay" Marchetto + Mike Frysinger + Minto Jeyananth + Monroe Williams + Motonori Shindo + Nathaniel Couper-Noles + Nathan J. Williams + Neil T. Spring + Nickolai Zeldovich + Nicolas Ferrero + Niels Provos + Noritoshi Demizu + Olaf Kirch + Ola Martin Lykkja + Oleksij Rempel + Onno van der Linden + Paolo Abeni + Pascal Hennequin + Pasvorn Boonmark + Paul Ferrell + Paul Mundt + Paul S. Traina + Pavlin Radoslavov + Pawel Worach + Pekka Savola + Petar Alilovic + Peter Fales + Peter Jeremy + Peter Volkov + + Phil Wood + Rafal Maszkowski + Randy Sofia + Raphael Raimbault + Rick Cheng + Rick Jones + Rick Watson + Rob Braun + Robert Edmonds + Roderick Schertler + Romain Francoise + Ruben Kerkhof + Sagun Shakya + Sami Farin + Scott Mcmillan + Scott Rose + Sebastian Krahmer + Sebastien Raveau + Sebastien Vincent + Sepherosa Ziehau + Seth Webster + Shinsuke Suzuki + Simon Ruderich + Steinar Haug + Stephane Bortzmeyer + Swaminathan Chandrasekaran + Swaathi Vetrivel + Takashi Yamamoto + Tatuya Jinmei + Terry Kennedy + Thomas Jacob + Timo Koskiahde + Tony Li + Toshihiro Kanda + Udayakumar + Uns Lider + Victor Oppleman + Vyacheslav Trushkin + Weesan Lee + Wesley Griffin + Wesley Shields + Wilbert de Graaf + Will Drewry + William J. Hulley + Wim Torfs + Yen Yen Lim + Yoshifumi Nishida + +The original LBL crew: + Steve McCanne + Craig Leres + Van Jacobson + +Past maintainers: + Jun-ichiro itojun Hagino Also see: http://www.wide.ad.jp/itojun-award/ diff --git a/tcpdump/jni/tcpdump/CleanSpec.mk b/tcpdump/jni/tcpdump/CleanSpec.mk new file mode 100644 index 0000000..b84e1b6 --- /dev/null +++ b/tcpdump/jni/tcpdump/CleanSpec.mk @@ -0,0 +1,49 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ diff --git a/tcpdump/jni/tcpdump/INSTALL.txt b/tcpdump/jni/tcpdump/INSTALL.txt new file mode 100644 index 0000000..dcb52b8 --- /dev/null +++ b/tcpdump/jni/tcpdump/INSTALL.txt @@ -0,0 +1,213 @@ +If you have not built libpcap, and your system does not have libpcap +installed, install libpcap first. Your system might provide a version +of libpcap that can be installed; if so, to compile tcpdump you might +need to install a "developer" version of libpcap as well as the +"run-time" version. You can also install tcpdump.org's version of +libpcap; see the README file in this directory for the ftp location. + +You will need an ANSI C compiler to build tcpdump. The configure script +will abort if your compiler is not ANSI compliant. If this happens, use +the generally available GNU C compiler (GCC). + +After libpcap has been built (either install it with "make install" or +make sure both the libpcap and tcpdump source trees are in the same +directory), run ./configure (a shell script). "configure" will +determine your system attributes and generate an appropriate Makefile +from Makefile.in. Now build tcpdump by running "make". + +If everything builds ok, su and type "make install". This will install +tcpdump and the manual entry. Any user will be able to use tcpdump to +read saved captures. Whether a user will be able to capture traffic +depends on the OS and the configuration of the system; see the tcpdump +man page for details. DO NOT give untrusted users the ability to +capture traffic. If a user can capture traffic, he or she could use +utilities such as tcpdump to capture any traffic on your net, including +passwords. + +Note that most systems ship tcpdump, but usually an older version. +Remember to remove or rename the installed binary when upgrading. + +If your system is not one which we have tested tcpdump on, you may have +to modify the configure script and Makefile.in. Please send us patches +for any modifications you need to make. + +Please see "PLATFORMS" for notes about tested platforms. + + +FILES +----- +CHANGES - description of differences between releases +CREDITS - people that have helped tcpdump along +INSTALL.txt - this file +LICENSE - the license under which tcpdump is distributed +Makefile.in - compilation rules (input to the configure script) +README - description of distribution +Readme.Win32 - notes on building tcpdump on Win32 systems (with WinPcap) +VERSION - version of this release +aclocal.m4 - autoconf macros +addrtoname.c - address to hostname routines +addrtoname.h - address to hostname definitions +ah.h - IPSEC Authentication Header definitions +appletalk.h - AppleTalk definitions +atime.awk - TCP ack awk script +atm.h - ATM traffic type definitions +atmuni31.h - ATM Q.2931 definitions +bpf_dump.c - BPF program printing routines, in case libpcap doesn't + have them +chdlc.h - Cisco HDLC definitions +cpack.c - functions to extract packed data +cpack.h - declarations of functions to extract packed data +config.guess - autoconf support +config.h.in - autoconf input +config.sub - autoconf support +configure - configure script (run this first) +configure.in - configure script source +ether.h - Ethernet definitions +ethertype.h - Ethernet type value definitions +extract.h - alignment definitions +gmpls.c - GMPLS definitions +gmpls.h - GMPLS declarations +gmt2local.c - time conversion routines +gmt2local.h - time conversion prototypes +install-sh - BSD style install script +interface.h - globals, prototypes and definitions +ip.h - IP definitions +ip6.h - IPv6 definitions +ipproto.c - IP protocol type value-to-name table +ipproto.h - IP protocol type value definitions +l2vpn.c - L2VPN encapsulation value-to-name table +l2vpn.h - L2VPN encapsulation definitions +lbl/os-*.h - OS-dependent defines and prototypes +llc.h - LLC definitions +machdep.c - machine dependent routines +machdep.h - machine dependent definitions +makemib - mib to header script +mib.h - mib definitions +missing/* - replacements for missing library functions +mkdep - construct Makefile dependency list +mpls.h - MPLS definitions +nameser.h - DNS definitions +netdissect.h - definitions and declarations for tcpdump-as-library + (under development) +nfs.h - Network File System V2 definitions +nfsfh.h - Network File System file handle definitions +nlpid.c - OSI NLPID value-to-name table +nlpid.h - OSI NLPID definitions +ospf.h - Open Shortest Path First definitions +packetdat.awk - TCP chunk summary awk script +parsenfsfh.c - Network File System file parser routines +pcap_dump_ftell.c - pcap_dump_ftell() implementation, in case libpcap + doesn't have it +pcap-missing.h - declarations of functions possibly missing from libpcap +ppp.h - Point to Point Protocol definitions +print-802_11.c - IEEE 802.11 printer routines +print-ap1394.c - Apple IP-over-IEEE 1394 printer routines +print-ah.c - IPSEC Authentication Header printer routines +print-aodv.c - AODV printer routines +print-arcnet.c - ARCNET printer routines +print-arp.c - Address Resolution Protocol printer routines +print-ascii.c - ASCII packet dump routines +print-atalk.c - AppleTalk printer routines +print-atm.c - ATM printer routines +print-beep.c - BEEP printer routines +print-bgp.c - Border Gateway Protocol printer routines +print-bootp.c - BOOTP and IPv4 DHCP printer routines +print-bt.c - Bluetooth printer routines +print-cdp.c - Cisco Discovery Protocol printer routines +print-chdlc.c - Cisco HDLC printer routines +print-cip.c - Classical-IP over ATM routines +print-cnfp.c - Cisco NetFlow printer routines +print-dccp.c - DCCP printer routines +print-decnet.c - DECnet printer routines +print-dhcp6.c - IPv6 DHCP printer routines +print-domain.c - Domain Name System printer routines +print-dvmrp.c - Distance Vector Multicast Routing Protocol printer routines +print-eap.c - EAP printer routines +print-enc.c - OpenBSD IPsec encapsulation BPF layer printer routines +print-egp.c - External Gateway Protocol printer routines +print-esp.c - IPSEC Encapsulating Security Payload printer routines +print-ether.c - Ethernet printer routines +print-fddi.c - Fiber Distributed Data Interface printer routines +print-fr.c - Frame Relay printer routines +print-frag6.c - IPv6 fragmentation header printer routines +print-gre.c - Generic Routing Encapsulation printer routines +print-hsrp.c - Cisco Hot Standby Router Protocol printer routines +print-icmp.c - Internet Control Message Protocol printer routines +print-icmp6.c - IPv6 Internet Control Message Protocol printer routines +print-igmp.c - Internet Group Management Protocol printer routines +print-igrp.c - Interior Gateway Routing Protocol printer routines +print-ip.c - IP printer routines +print-ip6.c - IPv6 printer routines +print-ip6opts.c - IPv6 header option printer routines +print-ipcomp.c - IP Payload Compression Protocol printer routines +print-ipx.c - IPX printer routines +print-isakmp.c - Internet Security Association and Key Management Protocol +print-isoclns.c - ISO CLNS, ESIS, and ISIS printer routines +print-krb.c - Kerberos printer routines +print-l2tp.c - Layer Two Tunneling Protocol printer routines +print-lane.c - ATM LANE printer routines +print-llc.c - IEEE 802.2 LLC printer routines +print-lspping.c - LSPPING printer routines +print-lwres.c - Lightweight Resolver protocol printer routines +print-mobile.c - IPv4 mobility printer routines +print-mobility.c - IPv6 mobility printer routines +print-mpls.c - Multi-Protocol Label Switching printer routines +print-msdp.c - Multicast Source Discovery Protocol printer routines +print-nfs.c - Network File System printer routines +print-ntp.c - Network Time Protocol printer routines +print-null.c - BSD loopback device printer routines +print-ospf.c - Open Shortest Path First printer routines +print-ospf6.c - IPv6 Open Shortest Path First printer routines +print-pflog.c - OpenBSD packet filter log file printer routines +print-pgm.c - Pragmatic General Multicast printer routines +print-pim.c - Protocol Independent Multicast printer routines +print-ppp.c - Point to Point Protocol printer routines +print-pppoe.c - PPP-over-Ethernet printer routines +print-pptp.c - Point-to-Point Tunnelling Protocol printer routines +print-radius.c - Radius protocol printer routines +print-raw.c - Raw IP printer routines +print-rip.c - Routing Information Protocol printer routines +print-ripng.c - IPv6 Routing Information Protocol printer routines +print-rrcp.c - Realtek Remote Control Protocol routines +print-rsvp.c - Resource reSerVation Protocol (RSVP) printer routines +print-rt6.c - IPv6 routing header printer routines +print-rx.c - AFS RX printer routines +print-sctp.c - Stream Control Transmission Protocol printer routines +print-sip.c - SIP printer routines +print-sl.c - Compressed Serial Line Internet Protocol printer routines +print-sll.c - Linux "cooked" capture printer routines +print-slow.c - IEEE "slow protocol" (802.3ad) printer routines +print-smb.c - SMB/CIFS printer routines +print-snmp.c - Simple Network Management Protocol printer routines +print-stp.c - IEEE 802.1d spanning tree protocol printer routines +print-sunatm.c - SunATM DLPI capture printer routines +print-sunrpc.c - Sun Remote Procedure Call printer routines +print-symantec.c - Symantec Enterprise Firewall printer routines +print-tcp.c - TCP printer routines +print-telnet.c - Telnet option printer routines +print-tftp.c - Trivial File Transfer Protocol printer routines +print-timed.c - BSD time daemon protocol printer routines +print-token.c - Token Ring printer routines +print-udp.c - UDP printer routines +print-usb.c - USB printer routines +print-vjc.c - PPP Van Jacobson compression (RFC1144) printer routines +print-vrrp.c - Virtual Router Redundancy Protocol +print-wb.c - White Board printer routines +print-zephyr.c - Zephyr printer routines +rpc_auth.h - definitions for ONC RPC authentication +rpc_msg.h - definitions for ONC RPC messages +send-ack.awk - unidirectional tcp send/ack awk script +setsignal.c - OS-independent signal routines +setsignal.h - OS-independent signal prototypes +slcompress.h - SLIP/PPP Van Jacobson compression (RFC1144) definitions +smb.h - SMB/CIFS definitions +smbutil.c - SMB/CIFS utility routines +stime.awk - TCP send awk script +strcasecmp.c - missing routine +tcp.h - TCP definitions +tcpdump.1 - manual entry +tcpdump.c - main program +udp.h - UDP definitions +util.c - utility routines +vfprintf.c - emulation routine +win32 - headers and routines for building on Win32 systems diff --git a/tcpdump/jni/tcpdump/LICENSE b/tcpdump/jni/tcpdump/LICENSE new file mode 100644 index 0000000..dea5f7d --- /dev/null +++ b/tcpdump/jni/tcpdump/LICENSE @@ -0,0 +1,19 @@ +License: BSD + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. diff --git a/tcpdump/jni/tcpdump/Makefile-devel-adds b/tcpdump/jni/tcpdump/Makefile-devel-adds new file mode 100644 index 0000000..7bf6420 --- /dev/null +++ b/tcpdump/jni/tcpdump/Makefile-devel-adds @@ -0,0 +1,22 @@ +# +# Auto-regenerate configure script or Makefile when things change. +# From autoconf.info . Works best with GNU Make. +# +${srcdir}/configure: configure.in aclocal.m4 + cd ${srcdir} && autoconf + +# autoheader might not change config.h.in, so touch a stamp file. +${srcdir}/config.h.in: ${srcdir}/stamp-h.in +${srcdir}/stamp-h.in: configure.in aclocal.m4 + cd ${srcdir} && autoheader + echo timestamp > ${srcdir}/stamp-h.in + +config.h: stamp-h +stamp-h: ${srcdir}/config.h.in config.status + ./config.status + +Makefile: Makefile.in config.status + ./config.status + +config.status: ${srcdir}/configure + ./config.status --recheck diff --git a/tcpdump/jni/tcpdump/Makefile.in b/tcpdump/jni/tcpdump/Makefile.in new file mode 100644 index 0000000..a0dc559 --- /dev/null +++ b/tcpdump/jni/tcpdump/Makefile.in @@ -0,0 +1,454 @@ +# Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that: (1) source code distributions +# retain the above copyright notice and this paragraph in its entirety, (2) +# distributions including binary code include the above copyright notice and +# this paragraph in its entirety in the documentation or other materials +# provided with the distribution, and (3) all advertising materials mentioning +# features or use of this software display the following acknowledgement: +# ``This product includes software developed by the University of California, +# Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +# the University nor the names of its contributors may be used to endorse +# or promote products derived from this software without specific prior +# written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +# +# Various configurable paths (remember to edit Makefile.in, not Makefile) +# + +# Top level hierarchy +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +# Pathname of directory to install the binary +sbindir = @sbindir@ +# Pathname of directory to install the man page +mandir = @mandir@ + +# VPATH +srcdir = @srcdir@ +VPATH = @srcdir@ + +# +# You shouldn't need to edit anything below here. +# + +CC = @CC@ +AR = @AR@ +MKDEP = @MKDEP@ +PROG = tcpdump +CCOPT = @V_CCOPT@ +INCLS = -I. @V_INCLS@ +DEFS = @DEFS@ @CPPFLAGS@ @V_DEFS@ + +# Standard CFLAGS +CFLAGS = @CFLAGS@ +FULL_CFLAGS = $(CCOPT) $(DEFS) $(INCLS) $(CFLAGS) + +# Standard LDFLAGS +LDFLAGS = @LDFLAGS@ + +# Standard LIBS +LIBS = @LIBS@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +RANLIB = @RANLIB@ + +DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ + +# Explicitly define compilation rule since SunOS 4's make doesn't like gcc. +# Also, gcc does not remove the .o before forking 'as', which can be a +# problem if you don't own the file but can write to the directory. +.c.o: + @rm -f $@ + $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c + +CSRC = setsignal.c tcpdump.c + +LIBNETDISSECT_SRC=\ + addrtoname.c \ + af.c \ + checksum.c \ + cpack.c \ + gmpls.c \ + gmt2local.c \ + in_cksum.c \ + ipproto.c \ + l2vpn.c \ + machdep.c \ + nlpid.c \ + oui.c \ + parsenfsfh.c \ + print-802_11.c \ + print-802_15_4.c \ + print-ah.c \ + print-ahcp.c \ + print-aodv.c \ + print-aoe.c \ + print-ap1394.c \ + print-arcnet.c \ + print-arp.c \ + print-ascii.c \ + print-atalk.c \ + print-atm.c \ + print-beep.c \ + print-bfd.c \ + print-bgp.c \ + print-bootp.c \ + print-bt.c \ + print-calm-fast.c \ + print-carp.c \ + print-cdp.c \ + print-cfm.c \ + print-chdlc.c \ + print-cip.c \ + print-cnfp.c \ + print-dccp.c \ + print-decnet.c \ + print-domain.c \ + print-dtp.c \ + print-dvmrp.c \ + print-eap.c \ + print-egp.c \ + print-eigrp.c \ + print-enc.c \ + print-esp.c \ + print-ether.c \ + print-fddi.c \ + print-forces.c \ + print-fr.c \ + print-ftp.c \ + print-geneve.c \ + print-geonet.c \ + print-gre.c \ + print-hsrp.c \ + print-http.c \ + print-icmp.c \ + print-igmp.c \ + print-igrp.c \ + print-ip.c \ + print-ip6.c \ + print-ipcomp.c \ + print-ipfc.c \ + print-ipnet.c \ + print-ipx.c \ + print-isakmp.c \ + print-isoclns.c \ + print-juniper.c \ + print-krb.c \ + print-l2tp.c \ + print-lane.c \ + print-ldp.c \ + print-llc.c \ + print-lldp.c \ + print-lmp.c \ + print-loopback.c \ + print-lspping.c \ + print-lwapp.c \ + print-lwres.c \ + print-m3ua.c \ + print-mobile.c \ + print-mpcp.c \ + print-mpls.c \ + print-mptcp.c \ + print-msdp.c \ + print-msnlb.c \ + print-nflog.c \ + print-nfs.c \ + print-ntp.c \ + print-null.c \ + print-olsr.c \ + print-openflow-1.0.c \ + print-openflow.c \ + print-ospf.c \ + print-otv.c \ + print-pgm.c \ + print-pim.c \ + print-pktap.c \ + print-ppi.c \ + print-ppp.c \ + print-pppoe.c \ + print-pptp.c \ + print-radius.c \ + print-raw.c \ + print-rip.c \ + print-rpki-rtr.c \ + print-rrcp.c \ + print-rsvp.c \ + print-rtsp.c \ + print-rx.c \ + print-sctp.c \ + print-sflow.c \ + print-sip.c \ + print-sl.c \ + print-sll.c \ + print-slow.c \ + print-smtp.c \ + print-snmp.c \ + print-stp.c \ + print-sunatm.c \ + print-sunrpc.c \ + print-symantec.c \ + print-syslog.c \ + print-tcp.c \ + print-telnet.c \ + print-tftp.c \ + print-timed.c \ + print-tipc.c \ + print-token.c \ + print-udld.c \ + print-udp.c \ + print-usb.c \ + print-vjc.c \ + print-vqp.c \ + print-vrrp.c \ + print-vtp.c \ + print-vxlan.c \ + print-wb.c \ + print-zephyr.c \ + print-zeromq.c \ + signature.c \ + util.c + +LOCALSRC = @LOCALSRC@ +GENSRC = version.c +LIBOBJS = @LIBOBJS@ + +LIBNETDISSECT_OBJ=$(LIBNETDISSECT_SRC:.c=.o) ${LOCALSRC:.c=.o} ${LIBOBJS} +LIBNETDISSECT=libnetdissect.a + + +SRC = $(CSRC) $(GENSRC) $(LOCALSRC) $(LIBNETDISSECT_SRC) + +# We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot +# hack the extra indirection +OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) $(LIBNETDISSECT_OBJ) +HDR = \ + addrtoname.h \ + af.h \ + ah.h \ + appletalk.h \ + atm.h \ + atmuni31.h \ + chdlc.h \ + cpack.h \ + ether.h \ + ethertype.h \ + extract.h \ + getopt_long.h \ + gmpls.h \ + gmt2local.h \ + interface.h \ + ip.h \ + ip6.h \ + ipproto.h \ + l2vpn.h \ + llc.h \ + machdep.h \ + mib.h \ + mpls.h \ + nameser.h \ + netdissect.h \ + nfs.h \ + nfsfh.h \ + nlpid.h \ + openflow.h \ + ospf.h \ + oui.h \ + pcap-missing.h \ + ppp.h \ + rpc_auth.h \ + rpc_msg.h \ + rpl.h \ + setsignal.h \ + signature.h \ + slcompress.h \ + smb.h \ + tcp.h \ + tcpdump-stdinc.h \ + udp.h + +TAGHDR = \ + /usr/include/arpa/tftp.h \ + /usr/include/net/if_arp.h \ + /usr/include/net/slip.h \ + /usr/include/netinet/if_ether.h \ + /usr/include/netinet/in.h \ + /usr/include/netinet/ip_icmp.h \ + /usr/include/netinet/tcp.h \ + /usr/include/netinet/udp.h \ + /usr/include/protocols/routed.h + +TAGFILES = $(SRC) $(HDR) $(TAGHDR) + +CLEANFILES = $(PROG) $(OBJ) $(GENSRC) + +EXTRA_DIST = \ + CHANGES \ + CREDITS \ + INSTALL.txt \ + LICENSE \ + Makefile.in \ + Makefile-devel-adds \ + README.md \ + Readme.Win32 \ + VERSION \ + aclocal.m4 \ + atime.awk \ + bpf_dump.c \ + config.guess \ + config.h.in \ + config.sub \ + configure \ + configure.in \ + install-sh \ + lbl/os-osf4.h \ + lbl/os-solaris2.h \ + lbl/os-sunos4.h \ + lbl/os-ultrix4.h \ + makemib \ + missing/addrinfo.h \ + missing/dlnames.c \ + missing/datalinks.c \ + missing/getnameinfo.c \ + missing/getopt_long.c \ + missing/inet_aton.c \ + missing/inet_ntop.c \ + missing/inet_pton.c \ + missing/snprintf.c \ + missing/strdup.c \ + missing/strlcat.c \ + missing/strlcpy.c \ + missing/strsep.c \ + mkdep \ + packetdat.awk \ + pcap_dump_ftell.c \ + print-babel.c \ + print-dhcp6.c \ + print-frag6.c \ + print-icmp6.c \ + print-ip6opts.c \ + print-mobility.c \ + print-ospf6.c \ + print-pflog.c \ + print-ripng.c \ + print-rt6.c \ + print-smb.c \ + send-ack.awk \ + smbutil.c \ + stime.awk \ + strcasecmp.c \ + tcpdump.1.in \ + vfprintf.c \ + win32/Include/w32_fzs.h \ + win32/prj/GNUmakefile \ + win32/prj/WinDump.dsp \ + win32/prj/WinDump.dsw + +TEST_DIST= `find tests \( -name 'DIFF' -prune \) -o \( -name NEW -prune \) -o -type f \! -name '.*' \! -name '*~' -print` + +all: $(PROG) $(LIBNETDISSECT) + +$(PROG): $(OBJ) @V_PCAPDEP@ + @rm -f $@ + $(CC) $(FULL_CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) + +$(LIBNETDISSECT): $(LIBNETDISSECT_OBJ) + @rm -f $@ + $(AR) cr $@ $(LIBNETDISSECT_OBJ) + $(RANLIB) $@ + +datalinks.o: $(srcdir)/missing/datalinks.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/datalinks.c +dlnames.o: $(srcdir)/missing/dlnames.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/dlnames.c +getnameinfo.o: $(srcdir)/missing/getnameinfo.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/getnameinfo.c +getopt_long.o: $(srcdir)/missing/getopt_long.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/getopt_long.c +inet_pton.o: $(srcdir)/missing/inet_pton.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/inet_pton.c +inet_ntop.o: $(srcdir)/missing/inet_ntop.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/inet_ntop.c +inet_aton.o: $(srcdir)/missing/inet_aton.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/inet_aton.c +snprintf.o: $(srcdir)/missing/snprintf.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/snprintf.c +strdup.o: $(srcdir)/missing/strdup.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strdup.c +strlcat.o: $(srcdir)/missing/strlcat.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strlcat.c +strlcpy.o: $(srcdir)/missing/strlcpy.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strlcpy.c +strsep.o: $(srcdir)/missing/strsep.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strsep.c + +version.o: version.c + $(CC) $(FULL_CFLAGS) -c version.c + +version.c: $(srcdir)/VERSION + @rm -f $@ + if grep GIT ${srcdir}/VERSION >/dev/null; then \ + read ver <${srcdir}/VERSION; \ + echo $$ver | tr -d '\012'; \ + date +_%Y_%m_%d; \ + else \ + cat ${srcdir}/VERSION; \ + fi | sed -e 's/.*/const char version[] = "&";/' > $@ + +install: all + [ -d $(DESTDIR)$(sbindir) ] || \ + (mkdir -p $(DESTDIR)$(sbindir); chmod 755 $(DESTDIR)$(sbindir)) + $(INSTALL_PROGRAM) $(PROG) $(DESTDIR)$(sbindir)/$(PROG) + $(INSTALL_PROGRAM) $(PROG) $(DESTDIR)$(sbindir)/$(PROG).`cat ${srcdir}/VERSION` + [ -d $(DESTDIR)$(mandir)/man1 ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man1; chmod 755 $(DESTDIR)$(mandir)/man1) + $(INSTALL_DATA) $(PROG).1 $(DESTDIR)$(mandir)/man1/$(PROG).1 + +uninstall: + rm -f $(DESTDIR)$(sbindir)/$(PROG) + rm -f $(DESTDIR)$(mandir)/man1/$(PROG).1 + +lint: $(GENSRC) + lint -hbxn $(SRC) | \ + grep -v 'struct/union .* never defined' | \ + grep -v 'possible pointer alignment problem' + +clean: + rm -f $(CLEANFILES) $(PROG)-`cat VERSION`.tar.gz + +distclean: + rm -f $(CLEANFILES) Makefile config.cache config.log config.status \ + config.h gnuc.h os-proto.h stamp-h stamp-h.in $(PROG).1 \ + libnetdissect.a tests/.failed tests/.passed \ + tests/failure-outputs.txt + rm -rf autom4te.cache tests/DIFF tests/NEW + +check: tcpdump + (cd tests && ./TESTrun.sh) + +tags: $(TAGFILES) + ctags -wtd $(TAGFILES) + +TAGS: $(TAGFILES) + etags $(TAGFILES) + +releasetar: + @cwd=`pwd` ; dir=`basename $$cwd` ; name=$(PROG)-`cat VERSION` ; \ + mkdir $$name; \ + tar cf - $(CSRC) $(HDR) $(LIBNETDISSECT_SRC) $(EXTRA_DIST) $(TEST_DIST) | (cd $$name; tar xf -); \ + tar -c -z -f $$name.tar.gz $$name; \ + rm -rf $$name + +testlist: + echo $(TEST_DIST) + +depend: $(GENSRC) + $(MKDEP) -c $(CC) -m $(DEPENDENCY_CFLAG) $(DEFS) $(INCLS) $(SRC) diff --git a/tcpdump/jni/tcpdump/PLATFORMS b/tcpdump/jni/tcpdump/PLATFORMS new file mode 100644 index 0000000..03bfed7 --- /dev/null +++ b/tcpdump/jni/tcpdump/PLATFORMS @@ -0,0 +1,9 @@ +== Tested platforms == +NetBSD 5.1/i386 (mcr - 2012/4/1) +Debian Linux (squeeze/i386) (mcr - 2012/4/1) + +--- +RedHat Linux 6.1/i386 (assar) +FreeBSD 2.2.8/i386 (itojun) + + diff --git a/tcpdump/jni/tcpdump/README b/tcpdump/jni/tcpdump/README new file mode 100644 index 0000000..42061c0 --- /dev/null +++ b/tcpdump/jni/tcpdump/README @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/tcpdump/jni/tcpdump/README.md b/tcpdump/jni/tcpdump/README.md new file mode 100644 index 0000000..c83ffab --- /dev/null +++ b/tcpdump/jni/tcpdump/README.md @@ -0,0 +1,243 @@ +# tcpdump + +[![Build +Status](https://travis-ci.org/the-tcpdump-group/tcpdump.png)](https://travis-ci.org/the-tcpdump-group/tcpdump) + +TCPDUMP 4.x.y +Now maintained by "The Tcpdump Group" +See www.tcpdump.org + +Please send inquiries/comments/reports to: + +* tcpdump-workers@lists.tcpdump.org + +Anonymous Git is available via: + + git clone git://bpf.tcpdump.org/tcpdump + +Please submit patches by forking the branch on GitHub at: + +* http://github.com/the-tcpdump-group/tcpdump/tree/master + +and issuing a pull request. + +formerly from Lawrence Berkeley National Laboratory + Network Research Group + ftp://ftp.ee.lbl.gov/old/tcpdump.tar.Z (3.4) + +This directory contains source code for tcpdump, a tool for network +monitoring and data acquisition. This software was originally +developed by the Network Research Group at the Lawrence Berkeley +National Laboratory. The original distribution is available via +anonymous ftp to `ftp.ee.lbl.gov`, in `tcpdump.tar.Z`. More recent +development is performed at tcpdump.org, http://www.tcpdump.org/ + +Tcpdump uses libpcap, a system-independent interface for user-level +packet capture. Before building tcpdump, you must first retrieve and +build libpcap, also originally from LBL and now being maintained by +tcpdump.org; see http://www.tcpdump.org/ . + +Once libpcap is built (either install it or make sure it's in +`../libpcap`), you can build tcpdump using the procedure in the `INSTALL.txt` +file. + +The program is loosely based on SMI's "etherfind" although none of the +etherfind code remains. It was originally written by Van Jacobson as +part of an ongoing research project to investigate and improve tcp and +internet gateway performance. The parts of the program originally +taken from Sun's etherfind were later re-written by Steven McCanne of +LBL. To insure that there would be no vestige of proprietary code in +tcpdump, Steve wrote these pieces from the specification given by the +manual entry, with no access to the source of tcpdump or etherfind. + +Over the past few years, tcpdump has been steadily improved by the +excellent contributions from the Internet community (just browse +through the `CHANGES` file). We are grateful for all the input. + +Richard Stevens gives an excellent treatment of the Internet protocols +in his book *"TCP/IP Illustrated, Volume 1"*. If you want to learn more +about tcpdump and how to interpret its output, pick up this book. + +Some tools for viewing and analyzing tcpdump trace files are available +from the Internet Traffic Archive: + +* http://www.sigcomm.org/ITA/ + +Another tool that tcpdump users might find useful is tcpslice: + +* https://github.com/the-tcpdump-group/tcpslice + +It is a program that can be used to extract portions of tcpdump binary +trace files. See the above distribution for further details and +documentation. + +Problems, bugs, questions, desirable enhancements, etc. should be sent +to the address "tcpdump-workers@lists.tcpdump.org". Bugs, support +requests, and feature requests may also be submitted on the GitHub issue +tracker for tcpdump at: + +* https://github.com/the-tcpdump-group/tcpdump/issues + +Source code contributions, etc. should be sent to the email address +above or submitted by forking the branch on GitHub at: + +* http://github.com/the-tcpdump-group/tcpdump/tree/master + +and issuing a pull request. + +Current versions can be found at www.tcpdump.org. + + - The TCPdump team + +original text by: Steve McCanne, Craig Leres, Van Jacobson + +------------------------------------- +``` +This directory also contains some short awk programs intended as +examples of ways to reduce tcpdump data when you're tracking +particular network problems: + +send-ack.awk + Simplifies the tcpdump trace for an ftp (or other unidirectional + tcp transfer). Since we assume that one host only sends and + the other only acks, all address information is left off and + we just note if the packet is a "send" or an "ack". + + There is one output line per line of the original trace. + Field 1 is the packet time in decimal seconds, relative + to the start of the conversation. Field 2 is delta-time + from last packet. Field 3 is packet type/direction. + "Send" means data going from sender to receiver, "ack" + means an ack going from the receiver to the sender. A + preceding "*" indicates that the data is a retransmission. + A preceding "-" indicates a hole in the sequence space + (i.e., missing packet(s)), a "#" means an odd-size (not max + seg size) packet. Field 4 has the packet flags + (same format as raw trace). Field 5 is the sequence + number (start seq. num for sender, next expected seq number + for acks). The number in parens following an ack is + the delta-time from the first send of the packet to the + ack. A number in parens following a send is the + delta-time from the first send of the packet to the + current send (on duplicate packets only). Duplicate + sends or acks have a number in square brackets showing + the number of duplicates so far. + + Here is a short sample from near the start of an ftp: + 3.00 0.20 send . 512 + 3.20 0.20 ack . 1024 (0.20) + 3.20 0.00 send P 1024 + 3.40 0.20 ack . 1536 (0.20) + 3.80 0.40 * send . 0 (3.80) [2] + 3.82 0.02 * ack . 1536 (0.62) [2] + Three seconds into the conversation, bytes 512 through 1023 + were sent. 200ms later they were acked. Shortly thereafter + bytes 1024-1535 were sent and again acked after 200ms. + Then, for no apparent reason, 0-511 is retransmitted, 3.8 + seconds after its initial send (the round trip time for this + ftp was 1sec, +-500ms). Since the receiver is expecting + 1536, 1536 is re-acked when 0 arrives. + +packetdat.awk + Computes chunk summary data for an ftp (or similar + unidirectional tcp transfer). [A "chunk" refers to + a chunk of the sequence space -- essentially the packet + sequence number divided by the max segment size.] + + A summary line is printed showing the number of chunks, + the number of packets it took to send that many chunks + (if there are no lost or duplicated packets, the number + of packets should equal the number of chunks) and the + number of acks. + + Following the summary line is one line of information + per chunk. The line contains eight fields: + 1 - the chunk number + 2 - the start sequence number for this chunk + 3 - time of first send + 4 - time of last send + 5 - time of first ack + 6 - time of last ack + 7 - number of times chunk was sent + 8 - number of times chunk was acked + (all times are in decimal seconds, relative to the start + of the conversation.) + + As an example, here is the first part of the output for + an ftp trace: + + # 134 chunks. 536 packets sent. 508 acks. + 1 1 0.00 5.80 0.20 0.20 4 1 + 2 513 0.28 6.20 0.40 0.40 4 1 + 3 1025 1.16 6.32 1.20 1.20 4 1 + 4 1561 1.86 15.00 2.00 2.00 6 1 + 5 2049 2.16 15.44 2.20 2.20 5 1 + 6 2585 2.64 16.44 2.80 2.80 5 1 + 7 3073 3.00 16.66 3.20 3.20 4 1 + 8 3609 3.20 17.24 3.40 5.82 4 11 + 9 4097 6.02 6.58 6.20 6.80 2 5 + + This says that 134 chunks were transferred (about 70K + since the average packet size was 512 bytes). It took + 536 packets to transfer the data (i.e., on the average + each chunk was transmitted four times). Looking at, + say, chunk 4, we see it represents the 512 bytes of + sequence space from 1561 to 2048. It was first sent + 1.86 seconds into the conversation. It was last + sent 15 seconds into the conversation and was sent + a total of 6 times (i.e., it was retransmitted every + 2 seconds on the average). It was acked once, 140ms + after it first arrived. + +stime.awk +atime.awk + Output one line per send or ack, respectively, in the form + %s%s" + "%s%s\n", + n, path, slash, name, slash, (unsigned long) t, mod, + flags & MG_FS_DIR ? (int64_t) -1 : (int64_t) size, sz); + } +} + +static void listdir(struct mg_connection *c, struct mg_http_message *hm, + const struct mg_http_serve_opts *opts, char *dir) { + const char *sort_js_code = + ""; + struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; + struct printdirentrydata d = {c, hm, opts, dir}; + char tmp[10], buf[MG_PATH_MAX]; + size_t off, n; + int len = mg_url_decode(hm->uri.buf, hm->uri.len, buf, sizeof(buf), 0); + struct mg_str uri = len > 0 ? mg_str_n(buf, (size_t) len) : hm->uri; + + mg_printf(c, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html; charset=utf-8\r\n" + "%s" + "Content-Length: \r\n\r\n", + opts->extra_headers == NULL ? "" : opts->extra_headers); + off = c->send.len; // Start of body + mg_printf(c, + "Index of %.*s%s%s" + "" + "

    Index of %.*s

    " + "" + "" + "" + "" + "\n", + (int) uri.len, uri.buf, sort_js_code, sort_js_code2, (int) uri.len, + uri.buf); + mg_printf(c, "%s", + " " + "\n"); + + fs->ls(dir, printdirentry, &d); + mg_printf(c, + "" + "
    Name" + "ModifiedSize

    ..[DIR]

    Mongoose v.%s
    \n", + MG_VERSION); + n = mg_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off)); + if (n > sizeof(tmp)) n = 0; + memcpy(c->send.buf + off - 12, tmp, n); // Set content length + c->is_resp = 0; // Mark response end +} +#endif + +// Resolve requested file into `path` and return its fs->st() result +static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, + struct mg_fs *fs, struct mg_str url, struct mg_str dir, + char *path, size_t path_size) { + int flags, tmp; + // Append URI to the root_dir, and sanitize it + size_t n = mg_snprintf(path, path_size, "%.*s", (int) dir.len, dir.buf); + if (n + 2 >= path_size) { + mg_http_reply(c, 400, "", "Exceeded path size"); + return -1; + } + path[path_size - 1] = '\0'; + // Terminate root dir with slash + if (n > 0 && path[n - 1] != '/') path[n++] = '/', path[n] = '\0'; + if (url.len < hm->uri.len) { + mg_url_decode(hm->uri.buf + url.len, hm->uri.len - url.len, path + n, + path_size - n, 0); + } + path[path_size - 1] = '\0'; // Double-check + if (!mg_path_is_sane(mg_str_n(path, path_size))) { + mg_http_reply(c, 400, "", "Invalid path"); + return -1; + } + n = strlen(path); + while (n > 1 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes + flags = mg_strcmp(hm->uri, mg_str("/")) == 0 ? MG_FS_DIR + : fs->st(path, NULL, NULL); + MG_VERBOSE(("%lu %.*s -> %s %d", c->id, (int) hm->uri.len, hm->uri.buf, path, + flags)); + if (flags == 0) { + // Do nothing - let's caller decide + } else if ((flags & MG_FS_DIR) && hm->uri.len > 0 && + hm->uri.buf[hm->uri.len - 1] != '/') { + mg_printf(c, + "HTTP/1.1 301 Moved\r\n" + "Location: %.*s/\r\n" + "Content-Length: 0\r\n" + "\r\n", + (int) hm->uri.len, hm->uri.buf); + c->is_resp = 0; + flags = -1; + } else if (flags & MG_FS_DIR) { + if (((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX) > 0 && + (tmp = fs->st(path, NULL, NULL)) != 0) || + (mg_snprintf(path + n, path_size - n, "/index.shtml") > 0 && + (tmp = fs->st(path, NULL, NULL)) != 0))) { + flags = tmp; + } else if ((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX ".gz") > + 0 && + (tmp = fs->st(path, NULL, NULL)) != + 0)) { // check for gzipped index + flags = tmp; + path[n + 1 + strlen(MG_HTTP_INDEX)] = + '\0'; // Remove appended .gz in index file name + } else { + path[n] = '\0'; // Remove appended index file name + } + } + return flags; +} + +static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm, + const struct mg_http_serve_opts *opts, char *path, + size_t path_size) { + struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; + struct mg_str k, v, part, s = mg_str(opts->root_dir), u = {NULL, 0}, p = u; + while (mg_span(s, &part, &s, ',')) { + if (!mg_span(part, &k, &v, '=')) k = part, v = mg_str_n(NULL, 0); + if (v.len == 0) v = k, k = mg_str("/"), u = k, p = v; + if (hm->uri.len < k.len) continue; + if (mg_strcmp(k, mg_str_n(hm->uri.buf, k.len)) != 0) continue; + u = k, p = v; + } + return uri_to_path2(c, hm, fs, u, p, path, path_size); +} + +void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm, + const struct mg_http_serve_opts *opts) { + char path[MG_PATH_MAX]; + const char *sp = opts->ssi_pattern; + int flags = uri_to_path(c, hm, opts, path, sizeof(path)); + if (flags < 0) { + // Do nothing: the response has already been sent by uri_to_path() + } else if (flags & MG_FS_DIR) { +#if MG_ENABLE_DIRLIST + listdir(c, hm, opts, path); +#else + mg_http_reply(c, 403, "", "Forbidden\n"); +#endif + } else if (flags && sp != NULL && mg_match(mg_str(path), mg_str(sp), NULL)) { + mg_http_serve_ssi(c, opts->root_dir, path); + } else { + mg_http_serve_file(c, hm, path, opts); + } +} + +static bool mg_is_url_safe(int c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~'; +} + +size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) { + size_t i, n = 0; + for (i = 0; i < sl; i++) { + int c = *(unsigned char *) &s[i]; + if (n + 4 >= len) return 0; + if (mg_is_url_safe(c)) { + buf[n++] = s[i]; + } else { + mg_snprintf(&buf[n], 4, "%%%M", mg_print_hex, 1, &s[i]); + n += 3; + } + } + if (len > 0 && n < len - 1) buf[n] = '\0'; // Null-terminate the destination + if (len > 0) buf[len - 1] = '\0'; // Always. + return n; +} + +void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen, + char *pass, size_t passlen) { + struct mg_str *v = mg_http_get_header(hm, "Authorization"); + user[0] = pass[0] = '\0'; + if (v != NULL && v->len > 6 && memcmp(v->buf, "Basic ", 6) == 0) { + char buf[256]; + size_t n = mg_base64_decode(v->buf + 6, v->len - 6, buf, sizeof(buf)); + const char *p = (const char *) memchr(buf, ':', n > 0 ? n : 0); + if (p != NULL) { + mg_snprintf(user, userlen, "%.*s", p - buf, buf); + mg_snprintf(pass, passlen, "%.*s", n - (size_t) (p - buf) - 1, p + 1); + } + } else if (v != NULL && v->len > 7 && memcmp(v->buf, "Bearer ", 7) == 0) { + mg_snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->buf + 7); + } else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) { + struct mg_str t = mg_http_get_header_var(*v, mg_str_n("access_token", 12)); + if (t.len > 0) mg_snprintf(pass, passlen, "%.*s", (int) t.len, t.buf); + } else { + mg_http_get_var(&hm->query, "access_token", pass, passlen); + } +} + +static struct mg_str stripquotes(struct mg_str s) { + return s.len > 1 && s.buf[0] == '"' && s.buf[s.len - 1] == '"' + ? mg_str_n(s.buf + 1, s.len - 2) + : s; +} + +struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) { + size_t i; + for (i = 0; v.len > 0 && i + v.len + 2 < s.len; i++) { + if (s.buf[i + v.len] == '=' && memcmp(&s.buf[i], v.buf, v.len) == 0) { + const char *p = &s.buf[i + v.len + 1], *b = p, *x = &s.buf[s.len]; + int q = p < x && *p == '"' ? 1 : 0; + while (p < x && + (q ? p == b || *p != '"' : *p != ';' && *p != ' ' && *p != ',')) + p++; + // MG_INFO(("[%.*s] [%.*s] [%.*s]", (int) s.len, s.buf, (int) v.len, + // v.buf, (int) (p - b), b)); + return stripquotes(mg_str_n(b, (size_t) (p - b + q))); + } + } + return mg_str_n(NULL, 0); +} + +long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, + struct mg_fs *fs, const char *dir, size_t max_size) { + char buf[20] = "0", file[MG_PATH_MAX], path[MG_PATH_MAX]; + long res = 0, offset; + mg_http_get_var(&hm->query, "offset", buf, sizeof(buf)); + mg_http_get_var(&hm->query, "file", file, sizeof(file)); + offset = strtol(buf, NULL, 0); + mg_snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, file); + if (hm->body.len == 0) { + mg_http_reply(c, 200, "", "%ld", res); // Nothing to write + } else if (file[0] == '\0') { + mg_http_reply(c, 400, "", "file required"); + res = -1; + } else if (mg_path_is_sane(mg_str(file)) == false) { + mg_http_reply(c, 400, "", "%s: invalid file", file); + res = -2; + } else if (offset < 0) { + mg_http_reply(c, 400, "", "offset required"); + res = -3; + } else if ((size_t) offset + hm->body.len > max_size) { + mg_http_reply(c, 400, "", "%s: over max size of %lu", path, + (unsigned long) max_size); + res = -4; + } else { + struct mg_fd *fd; + size_t current_size = 0; + MG_DEBUG(("%s -> %lu bytes @ %ld", path, hm->body.len, offset)); + if (offset == 0) fs->rm(path); // If offset if 0, truncate file + fs->st(path, ¤t_size, NULL); + if (offset > 0 && current_size != (size_t) offset) { + mg_http_reply(c, 400, "", "%s: offset mismatch", path); + res = -5; + } else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { + mg_http_reply(c, 400, "", "open(%s): %d", path, errno); + res = -6; + } else { + res = offset + (long) fs->wr(fd->fd, hm->body.buf, hm->body.len); + mg_fs_close(fd); + mg_http_reply(c, 200, "", "%ld", res); + } + } + return res; +} + +int mg_http_status(const struct mg_http_message *hm) { + return atoi(hm->uri.buf); +} + +static bool is_hex_digit(int c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); +} + +static int skip_chunk(const char *buf, int len, int *pl, int *dl) { + int i = 0, n = 0; + if (len < 3) return 0; + while (i < len && is_hex_digit(buf[i])) i++; + if (i == 0) return -1; // Error, no length specified + if (i > (int) sizeof(int) * 2) return -1; // Chunk length is too big + if (len < i + 1 || buf[i] != '\r' || buf[i + 1] != '\n') return -1; // Error + if (mg_str_to_num(mg_str_n(buf, (size_t) i), 16, &n, sizeof(int)) == false) + return -1; // Decode chunk length, overflow + if (n < 0) return -1; // Error. TODO(): some checks now redundant + if (n > len - i - 4) return 0; // Chunk not yet fully buffered + if (buf[i + n + 2] != '\r' || buf[i + n + 3] != '\n') return -1; // Error + *pl = i + 2, *dl = n; + return i + 2 + n + 2; +} + +static void http_cb(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_READ || ev == MG_EV_CLOSE) { + struct mg_http_message hm; + size_t ofs = 0; // Parsing offset + while (c->is_resp == 0 && ofs < c->recv.len) { + const char *buf = (char *) c->recv.buf + ofs; + int n = mg_http_parse(buf, c->recv.len - ofs, &hm); + struct mg_str *te; // Transfer - encoding header + bool is_chunked = false; + if (n < 0) { + // We don't use mg_error() here, to avoid closing pipelined requests + // prematurely, see #2592 + MG_ERROR(("HTTP parse, %lu bytes", c->recv.len)); + c->is_draining = 1; + mg_hexdump(buf, c->recv.len - ofs > 16 ? 16 : c->recv.len - ofs); + c->recv.len = 0; + return; + } + if (n == 0) break; // Request is not buffered yet + mg_call(c, MG_EV_HTTP_HDRS, &hm); // Got all HTTP headers + if (ev == MG_EV_CLOSE) { // If client did not set Content-Length + hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG + hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf); + } + if ((te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) { + if (mg_strcasecmp(*te, mg_str("chunked")) == 0) { + is_chunked = true; + } else { + mg_error(c, "Invalid Transfer-Encoding"); // See #2460 + return; + } + } else if (mg_http_get_header(&hm, "Content-length") == NULL) { + // #2593: HTTP packets must contain either Transfer-Encoding or + // Content-length + bool is_response = mg_ncasecmp(hm.method.buf, "HTTP/", 5) == 0; + bool require_content_len = false; + if (!is_response && (mg_strcasecmp(hm.method, mg_str("POST")) == 0 || + mg_strcasecmp(hm.method, mg_str("PUT")) == 0)) { + // POST and PUT should include an entity body. Therefore, they should + // contain a Content-length header. Other requests can also contain a + // body, but their content has no defined semantics (RFC 7231) + require_content_len = true; + } else if (is_response) { + // HTTP spec 7.2 Entity body: All other responses must include a body + // or Content-Length header field defined with a value of 0. + int status = mg_http_status(&hm); + require_content_len = status >= 200 && status != 204 && status != 304; + } + if (require_content_len) { + mg_http_reply(c, 411, "", ""); + MG_ERROR(("%s", "Content length missing from request")); + } + } + + if (is_chunked) { + // For chunked data, strip off prefixes and suffixes from chunks + // and relocate them right after the headers, then report a message + char *s = (char *) c->recv.buf + ofs + n; + int o = 0, pl, dl, cl, len = (int) (c->recv.len - ofs - (size_t) n); + + // Find zero-length chunk (the end of the body) + while ((cl = skip_chunk(s + o, len - o, &pl, &dl)) > 0 && dl) o += cl; + if (cl == 0) break; // No zero-len chunk, buffer more data + if (cl < 0) { + mg_error(c, "Invalid chunk"); + break; + } + + // Zero chunk found. Second pass: strip + relocate + o = 0, hm.body.len = 0, hm.message.len = (size_t) n; + while ((cl = skip_chunk(s + o, len - o, &pl, &dl)) > 0) { + memmove(s + hm.body.len, s + o + pl, (size_t) dl); + o += cl, hm.body.len += (size_t) dl, hm.message.len += (size_t) dl; + if (dl == 0) break; + } + ofs += (size_t) (n + o); + } else { // Normal, non-chunked data + size_t len = c->recv.len - ofs - (size_t) n; + if (hm.body.len > len) break; // Buffer more data + ofs += (size_t) n + hm.body.len; + } + + if (c->is_accepted) c->is_resp = 1; // Start generating response + mg_call(c, MG_EV_HTTP_MSG, &hm); // User handler can clear is_resp + } + if (ofs > 0) mg_iobuf_del(&c->recv, 0, ofs); // Delete processed data + } + (void) ev_data; +} + +static void mg_hfn(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_HTTP_MSG) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/quit"), NULL)) { + mg_http_reply(c, 200, "", "ok\n"); + c->is_draining = 1; + c->data[0] = 'X'; + } else if (mg_match(hm->uri, mg_str("/debug"), NULL)) { + int level = (int) mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG); + mg_log_set(level); + mg_http_reply(c, 200, "", "Debug level set to %d\n", level); + } else { + mg_http_reply(c, 200, "", "hi\n"); + } + } else if (ev == MG_EV_CLOSE) { + if (c->data[0] == 'X') *(bool *) c->fn_data = true; + } +} + +void mg_hello(const char *url) { + struct mg_mgr mgr; + bool done = false; + mg_mgr_init(&mgr); + if (mg_http_listen(&mgr, url, mg_hfn, &done) == NULL) done = true; + while (done == false) mg_mgr_poll(&mgr, 100); + mg_mgr_free(&mgr); +} + +struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = mg_connect(mgr, url, fn, fn_data); + if (c != NULL) c->pfn = http_cb; + return c; +} + +struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = mg_listen(mgr, url, fn, fn_data); + if (c != NULL) c->pfn = http_cb; + return c; +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/iobuf.c" +#endif + + + + + +static size_t roundup(size_t size, size_t align) { + return align == 0 ? size : (size + align - 1) / align * align; +} + +int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) { + int ok = 1; + new_size = roundup(new_size, io->align); + if (new_size == 0) { + mg_bzero(io->buf, io->size); + free(io->buf); + io->buf = NULL; + io->len = io->size = 0; + } else if (new_size != io->size) { + // NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the + // porting to some obscure platforms like FreeRTOS + void *p = calloc(1, new_size); + if (p != NULL) { + size_t len = new_size < io->len ? new_size : io->len; + if (len > 0 && io->buf != NULL) memmove(p, io->buf, len); + mg_bzero(io->buf, io->size); + free(io->buf); + io->buf = (unsigned char *) p; + io->size = new_size; + } else { + ok = 0; + MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size)); + } + } + return ok; +} + +int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) { + io->buf = NULL; + io->align = align; + io->size = io->len = 0; + return mg_iobuf_resize(io, size); +} + +size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf, + size_t len) { + size_t new_size = roundup(io->len + len, io->align); + mg_iobuf_resize(io, new_size); // Attempt to resize + if (new_size != io->size) len = 0; // Resize failure, append nothing + if (ofs < io->len) memmove(io->buf + ofs + len, io->buf + ofs, io->len - ofs); + if (buf != NULL) memmove(io->buf + ofs, buf, len); + if (ofs > io->len) io->len += ofs - io->len; + io->len += len; + return len; +} + +size_t mg_iobuf_del(struct mg_iobuf *io, size_t ofs, size_t len) { + if (ofs > io->len) ofs = io->len; + if (ofs + len > io->len) len = io->len - ofs; + if (io->buf) memmove(io->buf + ofs, io->buf + ofs + len, io->len - ofs - len); + if (io->buf) mg_bzero(io->buf + io->len - len, len); + io->len -= len; + return len; +} + +void mg_iobuf_free(struct mg_iobuf *io) { + mg_iobuf_resize(io, 0); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/json.c" +#endif + + + + +static const char *escapeseq(int esc) { + return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\""; +} + +static char json_esc(int c, int esc) { + const char *p, *esc1 = escapeseq(esc), *esc2 = escapeseq(!esc); + for (p = esc1; *p != '\0'; p++) { + if (*p == c) return esc2[p - esc1]; + } + return 0; +} + +static int mg_pass_string(const char *s, int len) { + int i; + for (i = 0; i < len; i++) { + if (s[i] == '\\' && i + 1 < len && json_esc(s[i + 1], 1)) { + i++; + } else if (s[i] == '\0') { + return MG_JSON_INVALID; + } else if (s[i] == '"') { + return i; + } + } + return MG_JSON_INVALID; +} + +static double mg_atod(const char *p, int len, int *numlen) { + double d = 0.0; + int i = 0, sign = 1; + + // Sign + if (i < len && *p == '-') { + sign = -1, i++; + } else if (i < len && *p == '+') { + i++; + } + + // Decimal + for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { + d *= 10.0; + d += p[i] - '0'; + } + d *= sign; + + // Fractional + if (i < len && p[i] == '.') { + double frac = 0.0, base = 0.1; + i++; + for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { + frac += base * (p[i] - '0'); + base /= 10.0; + } + d += frac * sign; + } + + // Exponential + if (i < len && (p[i] == 'e' || p[i] == 'E')) { + int j, exp = 0, minus = 0; + i++; + if (i < len && p[i] == '-') minus = 1, i++; + if (i < len && p[i] == '+') i++; + while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308) + exp = exp * 10 + (p[i++] - '0'); + if (minus) exp = -exp; + for (j = 0; j < exp; j++) d *= 10.0; + for (j = 0; j < -exp; j++) d /= 10.0; + } + + if (numlen != NULL) *numlen = i; + return d; +} + +// Iterate over object or array elements +size_t mg_json_next(struct mg_str obj, size_t ofs, struct mg_str *key, + struct mg_str *val) { + if (ofs >= obj.len) { + ofs = 0; // Out of boundaries, stop scanning + } else if (obj.len < 2 || (*obj.buf != '{' && *obj.buf != '[')) { + ofs = 0; // Not an array or object, stop + } else { + struct mg_str sub = mg_str_n(obj.buf + ofs, obj.len - ofs); + if (ofs == 0) ofs++, sub.buf++, sub.len--; + if (*obj.buf == '[') { // Iterate over an array + int n = 0, o = mg_json_get(sub, "$", &n); + if (n < 0 || o < 0 || (size_t) (o + n) > sub.len) { + ofs = 0; // Error parsing key, stop scanning + } else { + if (key) *key = mg_str_n(NULL, 0); + if (val) *val = mg_str_n(sub.buf + o, (size_t) n); + ofs = (size_t) (&sub.buf[o + n] - obj.buf); + } + } else { // Iterate over an object + int n = 0, o = mg_json_get(sub, "$", &n); + if (n < 0 || o < 0 || (size_t) (o + n) > sub.len) { + ofs = 0; // Error parsing key, stop scanning + } else { + if (key) *key = mg_str_n(sub.buf + o, (size_t) n); + sub.buf += o + n, sub.len -= (size_t) (o + n); + while (sub.len > 0 && *sub.buf != ':') sub.len--, sub.buf++; + if (sub.len > 0 && *sub.buf == ':') sub.len--, sub.buf++; + n = 0, o = mg_json_get(sub, "$", &n); + if (n < 0 || o < 0 || (size_t) (o + n) > sub.len) { + ofs = 0; // Error parsing value, stop scanning + } else { + if (val) *val = mg_str_n(sub.buf + o, (size_t) n); + ofs = (size_t) (&sub.buf[o + n] - obj.buf); + } + } + } + // MG_INFO(("SUB ofs %u %.*s", ofs, sub.len, sub.buf)); + while (ofs && ofs < obj.len && + (obj.buf[ofs] == ' ' || obj.buf[ofs] == '\t' || + obj.buf[ofs] == '\n' || obj.buf[ofs] == '\r')) { + ofs++; + } + if (ofs && ofs < obj.len && obj.buf[ofs] == ',') ofs++; + if (ofs > obj.len) ofs = 0; + } + return ofs; +} + +int mg_json_get(struct mg_str json, const char *path, int *toklen) { + const char *s = json.buf; + int len = (int) json.len; + enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE; + unsigned char nesting[MG_JSON_MAX_DEPTH]; + int i = 0; // Current offset in `s` + int j = 0; // Offset in `s` we're looking for (return value) + int depth = 0; // Current depth (nesting level) + int ed = 0; // Expected depth + int pos = 1; // Current position in `path` + int ci = -1, ei = -1; // Current and expected index in array + + if (toklen) *toklen = 0; + if (path[0] != '$') return MG_JSON_INVALID; + +#define MG_CHECKRET(x) \ + do { \ + if (depth == ed && path[pos] == '\0' && ci == ei) { \ + if (toklen) *toklen = i - j + 1; \ + return j; \ + } \ + } while (0) + +// In the ascii table, the distance between `[` and `]` is 2. +// Ditto for `{` and `}`. Hence +2 in the code below. +#define MG_EOO(x) \ + do { \ + if (depth == ed && ci != ei) return MG_JSON_NOT_FOUND; \ + if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \ + depth--; \ + MG_CHECKRET(x); \ + } while (0) + + for (i = 0; i < len; i++) { + unsigned char c = ((unsigned char *) s)[i]; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; + switch (expecting) { + case S_VALUE: + // p("V %s [%.*s] %d %d %d %d\n", path, pos, path, depth, ed, ci, ei); + if (depth == ed) j = i; + if (c == '{') { + if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; + if (depth == ed && path[pos] == '.' && ci == ei) { + // If we start the object, reset array indices + ed++, pos++, ci = ei = -1; + } + nesting[depth++] = c; + expecting = S_KEY; + break; + } else if (c == '[') { + if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; + if (depth == ed && path[pos] == '[' && ei == ci) { + ed++, pos++, ci = 0; + for (ei = 0; path[pos] != ']' && path[pos] != '\0'; pos++) { + ei *= 10; + ei += path[pos] - '0'; + } + if (path[pos] != 0) pos++; + } + nesting[depth++] = c; + break; + } else if (c == ']' && depth > 0) { // Empty array + MG_EOO(']'); + } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) { + i += 3; + } else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) { + i += 3; + } else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) { + i += 4; + } else if (c == '-' || ((c >= '0' && c <= '9'))) { + int numlen = 0; + mg_atod(&s[i], len - i, &numlen); + i += numlen - 1; + } else if (c == '"') { + int n = mg_pass_string(&s[i + 1], len - i - 1); + if (n < 0) return n; + i += n + 1; + } else { + return MG_JSON_INVALID; + } + MG_CHECKRET('V'); + if (depth == ed && ei >= 0) ci++; + expecting = S_COMMA_OR_EOO; + break; + + case S_KEY: + if (c == '"') { + int n = mg_pass_string(&s[i + 1], len - i - 1); + if (n < 0) return n; + if (i + 1 + n >= len) return MG_JSON_NOT_FOUND; + if (depth < ed) return MG_JSON_NOT_FOUND; + if (depth == ed && path[pos - 1] != '.') return MG_JSON_NOT_FOUND; + // printf("K %s [%.*s] [%.*s] %d %d %d %d %d\n", path, pos, path, n, + // &s[i + 1], n, depth, ed, ci, ei); + // NOTE(cpq): in the check sequence below is important. + // strncmp() must go first: it fails fast if the remaining length + // of the path is smaller than `n`. + if (depth == ed && path[pos - 1] == '.' && + strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 && + (path[pos + n] == '\0' || path[pos + n] == '.' || + path[pos + n] == '[')) { + pos += n; + } + i += n + 1; + expecting = S_COLON; + } else if (c == '}') { // Empty object + MG_EOO('}'); + expecting = S_COMMA_OR_EOO; + if (depth == ed && ei >= 0) ci++; + } else { + return MG_JSON_INVALID; + } + break; + + case S_COLON: + if (c == ':') { + expecting = S_VALUE; + } else { + return MG_JSON_INVALID; + } + break; + + case S_COMMA_OR_EOO: + if (depth <= 0) { + return MG_JSON_INVALID; + } else if (c == ',') { + expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE; + } else if (c == ']' || c == '}') { + if (depth == ed && c == '}' && path[pos - 1] == '.') + return MG_JSON_NOT_FOUND; + if (depth == ed && c == ']' && path[pos - 1] == ',') + return MG_JSON_NOT_FOUND; + MG_EOO('O'); + if (depth == ed && ei >= 0) ci++; + } else { + return MG_JSON_INVALID; + } + break; + } + } + return MG_JSON_NOT_FOUND; +} + +struct mg_str mg_json_get_tok(struct mg_str json, const char *path) { + int len = 0, ofs = mg_json_get(json, path, &len); + return mg_str_n(ofs < 0 ? NULL : json.buf + ofs, + (size_t) (len < 0 ? 0 : len)); +} + +bool mg_json_get_num(struct mg_str json, const char *path, double *v) { + int n, toklen, found = 0; + if ((n = mg_json_get(json, path, &toklen)) >= 0 && + (json.buf[n] == '-' || (json.buf[n] >= '0' && json.buf[n] <= '9'))) { + if (v != NULL) *v = mg_atod(json.buf + n, toklen, NULL); + found = 1; + } + return found; +} + +bool mg_json_get_bool(struct mg_str json, const char *path, bool *v) { + int found = 0, off = mg_json_get(json, path, NULL); + if (off >= 0 && (json.buf[off] == 't' || json.buf[off] == 'f')) { + if (v != NULL) *v = json.buf[off] == 't'; + found = 1; + } + return found; +} + +bool mg_json_unescape(struct mg_str s, char *to, size_t n) { + size_t i, j; + for (i = 0, j = 0; i < s.len && j < n; i++, j++) { + if (s.buf[i] == '\\' && i + 5 < s.len && s.buf[i + 1] == 'u') { + // \uXXXX escape. We process simple one-byte chars \u00xx within ASCII + // range. More complex chars would require dragging in a UTF8 library, + // which is too much for us + if (mg_str_to_num(mg_str_n(s.buf + i + 2, 4), 16, &to[j], + sizeof(uint8_t)) == false) + return false; + i += 5; + } else if (s.buf[i] == '\\' && i + 1 < s.len) { + char c = json_esc(s.buf[i + 1], 0); + if (c == 0) return false; + to[j] = c; + i++; + } else { + to[j] = s.buf[i]; + } + } + if (j >= n) return false; + if (n > 0) to[j] = '\0'; + return true; +} + +char *mg_json_get_str(struct mg_str json, const char *path) { + char *result = NULL; + int len = 0, off = mg_json_get(json, path, &len); + if (off >= 0 && len > 1 && json.buf[off] == '"') { + if ((result = (char *) calloc(1, (size_t) len)) != NULL && + !mg_json_unescape(mg_str_n(json.buf + off + 1, (size_t) (len - 2)), + result, (size_t) len)) { + free(result); + result = NULL; + } + } + return result; +} + +char *mg_json_get_b64(struct mg_str json, const char *path, int *slen) { + char *result = NULL; + int len = 0, off = mg_json_get(json, path, &len); + if (off >= 0 && json.buf[off] == '"' && len > 1 && + (result = (char *) calloc(1, (size_t) len)) != NULL) { + size_t k = mg_base64_decode(json.buf + off + 1, (size_t) (len - 2), result, + (size_t) len); + if (slen != NULL) *slen = (int) k; + } + return result; +} + +char *mg_json_get_hex(struct mg_str json, const char *path, int *slen) { + char *result = NULL; + int len = 0, off = mg_json_get(json, path, &len); + if (off >= 0 && json.buf[off] == '"' && len > 1 && + (result = (char *) calloc(1, (size_t) len / 2)) != NULL) { + int i; + for (i = 0; i < len - 2; i += 2) { + mg_str_to_num(mg_str_n(json.buf + off + 1 + i, 2), 16, &result[i >> 1], + sizeof(uint8_t)); + } + result[len / 2 - 1] = '\0'; + if (slen != NULL) *slen = len / 2 - 1; + } + return result; +} + +long mg_json_get_long(struct mg_str json, const char *path, long dflt) { + double dv; + long result = dflt; + if (mg_json_get_num(json, path, &dv)) result = (long) dv; + return result; +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/log.c" +#endif + + + + + +int mg_log_level = MG_LL_INFO; +static mg_pfn_t s_log_func = mg_pfn_stdout; +static void *s_log_func_param = NULL; + +void mg_log_set_fn(mg_pfn_t fn, void *param) { + s_log_func = fn; + s_log_func_param = param; +} + +static void logc(unsigned char c) { + s_log_func((char) c, s_log_func_param); +} + +static void logs(const char *buf, size_t len) { + size_t i; + for (i = 0; i < len; i++) logc(((unsigned char *) buf)[i]); +} + +#if MG_ENABLE_CUSTOM_LOG +// Let user define their own mg_log_prefix() and mg_log() +#else +void mg_log_prefix(int level, const char *file, int line, const char *fname) { + const char *p = strrchr(file, '/'); + char buf[41]; + size_t n; + if (p == NULL) p = strrchr(file, '\\'); + n = mg_snprintf(buf, sizeof(buf), "%-6llx %d %s:%d:%s", mg_millis(), level, + p == NULL ? file : p + 1, line, fname); + if (n > sizeof(buf) - 2) n = sizeof(buf) - 2; + while (n < sizeof(buf)) buf[n++] = ' '; + logs(buf, n - 1); +} + +void mg_log(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + mg_vxprintf(s_log_func, s_log_func_param, fmt, &ap); + va_end(ap); + logs("\r\n", 2); +} +#endif + +static unsigned char nibble(unsigned c) { + return (unsigned char) (c < 10 ? c + '0' : c + 'W'); +} + +#define ISPRINT(x) ((x) >= ' ' && (x) <= '~') +void mg_hexdump(const void *buf, size_t len) { + const unsigned char *p = (const unsigned char *) buf; + unsigned char ascii[16], alen = 0; + size_t i; + for (i = 0; i < len; i++) { + if ((i % 16) == 0) { + // Print buffered ascii chars + if (i > 0) logs(" ", 2), logs((char *) ascii, 16), logc('\n'), alen = 0; + // Print hex address, then \t + logc(nibble((i >> 12) & 15)), logc(nibble((i >> 8) & 15)), + logc(nibble((i >> 4) & 15)), logc('0'), logs(" ", 3); + } + logc(nibble(p[i] >> 4)), logc(nibble(p[i] & 15)); // Two nibbles, e.g. c5 + logc(' '); // Space after hex number + ascii[alen++] = ISPRINT(p[i]) ? p[i] : '.'; // Add to the ascii buf + } + while (alen < 16) logs(" ", 3), ascii[alen++] = ' '; + logs(" ", 2), logs((char *) ascii, 16), logc('\n'); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/md5.c" +#endif + + + +// This code implements the MD5 message-digest algorithm. +// The algorithm is due to Ron Rivest. This code was +// written by Colin Plumb in 1993, no copyright is claimed. +// This code is in the public domain; do with it what you wish. +// +// Equivalent code is available from RSA Data Security, Inc. +// This code has been tested against that, and is equivalent, +// except that you don't need to include two pages of legalese +// with every copy. +// +// To compute the message digest of a chunk of bytes, declare an +// MD5Context structure, pass it to MD5Init, call MD5Update as +// needed on buffers full of bytes, and then call MD5Final, which +// will fill a supplied 16-byte array with the digest. + +#if defined(MG_ENABLE_MD5) && MG_ENABLE_MD5 + +static void mg_byte_reverse(unsigned char *buf, unsigned longs) { + if (MG_BIG_ENDIAN) { + do { + uint32_t t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32_t *) buf = t; + buf += 4; + } while (--longs); + } else { + (void) buf, (void) longs; // Little endian. Do nothing + } +} + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define MD5STEP(f, w, x, y, z, data, s) \ + (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void mg_md5_init(mg_md5_ctx *ctx) { + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +static void mg_md5_transform(uint32_t buf[4], uint32_t const in[16]) { + uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +void mg_md5_update(mg_md5_ctx *ctx, const unsigned char *buf, size_t len) { + uint32_t t; + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++; + ctx->bits[1] += (uint32_t) len >> 29; + + t = (t >> 3) & 0x3f; + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + mg_byte_reverse(ctx->in, 16); + mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); + buf += t; + len -= t; + } + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + mg_byte_reverse(ctx->in, 16); + mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); + buf += 64; + len -= 64; + } + + memcpy(ctx->in, buf, len); +} + +void mg_md5_final(mg_md5_ctx *ctx, unsigned char digest[16]) { + unsigned count; + unsigned char *p; + uint32_t *a; + + count = (ctx->bits[0] >> 3) & 0x3F; + + p = ctx->in + count; + *p++ = 0x80; + count = 64 - 1 - count; + if (count < 8) { + memset(p, 0, count); + mg_byte_reverse(ctx->in, 16); + mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); + memset(ctx->in, 0, 56); + } else { + memset(p, 0, count - 8); + } + mg_byte_reverse(ctx->in, 14); + + a = (uint32_t *) ctx->in; + a[14] = ctx->bits[0]; + a[15] = ctx->bits[1]; + + mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); + mg_byte_reverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset((char *) ctx, 0, sizeof(*ctx)); +} +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/mqtt.c" +#endif + + + + + + + + +#define MQTT_CLEAN_SESSION 0x02 +#define MQTT_HAS_WILL 0x04 +#define MQTT_WILL_RETAIN 0x20 +#define MQTT_HAS_PASSWORD 0x40 +#define MQTT_HAS_USER_NAME 0x80 + +struct mg_mqtt_pmap { + uint8_t id; + uint8_t type; +}; + +static const struct mg_mqtt_pmap s_prop_map[] = { + {MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT}, + {MQTT_PROP_CONTENT_TYPE, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_RESPONSE_TOPIC, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_CORRELATION_DATA, MQTT_PROP_TYPE_BINARY_DATA}, + {MQTT_PROP_SUBSCRIPTION_IDENTIFIER, MQTT_PROP_TYPE_VARIABLE_INT}, + {MQTT_PROP_SESSION_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT}, + {MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_SERVER_KEEP_ALIVE, MQTT_PROP_TYPE_SHORT}, + {MQTT_PROP_AUTHENTICATION_METHOD, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_AUTHENTICATION_DATA, MQTT_PROP_TYPE_BINARY_DATA}, + {MQTT_PROP_REQUEST_PROBLEM_INFORMATION, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_WILL_DELAY_INTERVAL, MQTT_PROP_TYPE_INT}, + {MQTT_PROP_REQUEST_RESPONSE_INFORMATION, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_RESPONSE_INFORMATION, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_SERVER_REFERENCE, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_REASON_STRING, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_RECEIVE_MAXIMUM, MQTT_PROP_TYPE_SHORT}, + {MQTT_PROP_TOPIC_ALIAS_MAXIMUM, MQTT_PROP_TYPE_SHORT}, + {MQTT_PROP_TOPIC_ALIAS, MQTT_PROP_TYPE_SHORT}, + {MQTT_PROP_MAXIMUM_QOS, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_RETAIN_AVAILABLE, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_USER_PROPERTY, MQTT_PROP_TYPE_STRING_PAIR}, + {MQTT_PROP_MAXIMUM_PACKET_SIZE, MQTT_PROP_TYPE_INT}, + {MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}}; + +void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags, + uint32_t len) { + uint8_t buf[1 + sizeof(len)], *vlen = &buf[1]; + buf[0] = (uint8_t) ((cmd << 4) | flags); + do { + *vlen = len % 0x80; + len /= 0x80; + if (len > 0) *vlen |= 0x80; + vlen++; + } while (len > 0 && vlen < &buf[sizeof(buf)]); + mg_send(c, buf, (size_t) (vlen - buf)); +} + +static void mg_send_u16(struct mg_connection *c, uint16_t value) { + mg_send(c, &value, sizeof(value)); +} + +static void mg_send_u32(struct mg_connection *c, uint32_t value) { + mg_send(c, &value, sizeof(value)); +} + +static uint8_t varint_size(size_t length) { + uint8_t bytes_needed = 0; + do { + bytes_needed++; + length /= 0x80; + } while (length > 0); + return bytes_needed; +} + +static size_t encode_varint(uint8_t *buf, size_t value) { + size_t len = 0; + + do { + uint8_t b = (uint8_t) (value % 128); + value /= 128; + if (value > 0) b |= 0x80; + buf[len++] = b; + } while (value > 0); + + return len; +} + +static size_t decode_varint(const uint8_t *buf, size_t len, size_t *value) { + size_t multiplier = 1, offset; + *value = 0; + + for (offset = 0; offset < 4 && offset < len; offset++) { + uint8_t encoded_byte = buf[offset]; + *value += (encoded_byte & 0x7f) * multiplier; + multiplier *= 128; + + if ((encoded_byte & 0x80) == 0) return offset + 1; + } + + return 0; +} + +static int mqtt_prop_type_by_id(uint8_t prop_id) { + size_t i, num_properties = sizeof(s_prop_map) / sizeof(s_prop_map[0]); + for (i = 0; i < num_properties; ++i) { + if (s_prop_map[i].id == prop_id) return s_prop_map[i].type; + } + return -1; // Property ID not found +} + +// Returns the size of the properties section, without the +// size of the content's length +static size_t get_properties_length(struct mg_mqtt_prop *props, size_t count) { + size_t i, size = 0; + for (i = 0; i < count; i++) { + size++; // identifier + switch (mqtt_prop_type_by_id(props[i].id)) { + case MQTT_PROP_TYPE_STRING_PAIR: + size += (uint32_t) (props[i].val.len + props[i].key.len + + 2 * sizeof(uint16_t)); + break; + case MQTT_PROP_TYPE_STRING: + size += (uint32_t) (props[i].val.len + sizeof(uint16_t)); + break; + case MQTT_PROP_TYPE_BINARY_DATA: + size += (uint32_t) (props[i].val.len + sizeof(uint16_t)); + break; + case MQTT_PROP_TYPE_VARIABLE_INT: + size += varint_size((uint32_t) props[i].iv); + break; + case MQTT_PROP_TYPE_INT: + size += (uint32_t) sizeof(uint32_t); + break; + case MQTT_PROP_TYPE_SHORT: + size += (uint32_t) sizeof(uint16_t); + break; + case MQTT_PROP_TYPE_BYTE: + size += (uint32_t) sizeof(uint8_t); + break; + default: + return size; // cannot parse further down + } + } + + return size; +} + +// returns the entire size of the properties section, including the +// size of the variable length of the content +static size_t get_props_size(struct mg_mqtt_prop *props, size_t count) { + size_t size = get_properties_length(props, count); + size += varint_size(size); + return size; +} + +static void mg_send_mqtt_properties(struct mg_connection *c, + struct mg_mqtt_prop *props, size_t nprops) { + size_t total_size = get_properties_length(props, nprops); + uint8_t buf_v[4] = {0, 0, 0, 0}; + uint8_t buf[4] = {0, 0, 0, 0}; + size_t i, len = encode_varint(buf, total_size); + + mg_send(c, buf, (size_t) len); + for (i = 0; i < nprops; i++) { + mg_send(c, &props[i].id, sizeof(props[i].id)); + switch (mqtt_prop_type_by_id(props[i].id)) { + case MQTT_PROP_TYPE_STRING_PAIR: + mg_send_u16(c, mg_htons((uint16_t) props[i].key.len)); + mg_send(c, props[i].key.buf, props[i].key.len); + mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)); + mg_send(c, props[i].val.buf, props[i].val.len); + break; + case MQTT_PROP_TYPE_BYTE: + mg_send(c, &props[i].iv, sizeof(uint8_t)); + break; + case MQTT_PROP_TYPE_SHORT: + mg_send_u16(c, mg_htons((uint16_t) props[i].iv)); + break; + case MQTT_PROP_TYPE_INT: + mg_send_u32(c, mg_htonl((uint32_t) props[i].iv)); + break; + case MQTT_PROP_TYPE_STRING: + mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)); + mg_send(c, props[i].val.buf, props[i].val.len); + break; + case MQTT_PROP_TYPE_BINARY_DATA: + mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)); + mg_send(c, props[i].val.buf, props[i].val.len); + break; + case MQTT_PROP_TYPE_VARIABLE_INT: + len = encode_varint(buf_v, props[i].iv); + mg_send(c, buf_v, (size_t) len); + break; + } + } +} + +size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop, + size_t ofs) { + uint8_t *i = (uint8_t *) msg->dgram.buf + msg->props_start + ofs; + uint8_t *end = (uint8_t *) msg->dgram.buf + msg->dgram.len; + size_t new_pos = ofs, len; + prop->id = i[0]; + + if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size) + return 0; + i++, new_pos++; + + switch (mqtt_prop_type_by_id(prop->id)) { + case MQTT_PROP_TYPE_STRING_PAIR: + prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + prop->key.buf = (char *) i + 2; + i += 2 + prop->key.len; + prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + prop->val.buf = (char *) i + 2; + new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len; + break; + case MQTT_PROP_TYPE_BYTE: + prop->iv = (uint8_t) i[0]; + new_pos++; + break; + case MQTT_PROP_TYPE_SHORT: + prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + new_pos += sizeof(uint16_t); + break; + case MQTT_PROP_TYPE_INT: + prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) | + ((uint32_t) i[2] << 8) | i[3]; + new_pos += sizeof(uint32_t); + break; + case MQTT_PROP_TYPE_STRING: + prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + prop->val.buf = (char *) i + 2; + new_pos += 2 + prop->val.len; + break; + case MQTT_PROP_TYPE_BINARY_DATA: + prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + prop->val.buf = (char *) i + 2; + new_pos += 2 + prop->val.len; + break; + case MQTT_PROP_TYPE_VARIABLE_INT: + len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv); + new_pos = (!len) ? 0 : new_pos + len; + break; + default: + new_pos = 0; + } + + return new_pos; +} + +void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) { + char client_id[21]; + struct mg_str cid = opts->client_id; + size_t total_len = 7 + 1 + 2 + 2; + uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', opts->version, 0}; + + if (cid.len == 0) { + mg_random_str(client_id, sizeof(client_id) - 1); + client_id[sizeof(client_id) - 1] = '\0'; + cid = mg_str(client_id); + } + + if (hdr[6] == 0) hdr[6] = 4; // If version is not set, use 4 (3.1.1) + c->is_mqtt5 = hdr[6] == 5; // Set version 5 flag + hdr[7] = (uint8_t) ((opts->qos & 3) << 3); // Connection flags + if (opts->user.len > 0) { + total_len += 2 + (uint32_t) opts->user.len; + hdr[7] |= MQTT_HAS_USER_NAME; + } + if (opts->pass.len > 0) { + total_len += 2 + (uint32_t) opts->pass.len; + hdr[7] |= MQTT_HAS_PASSWORD; + } + if (opts->topic.len > 0) { // allow zero-length msgs, message.len is size_t + total_len += 4 + (uint32_t) opts->topic.len + (uint32_t) opts->message.len; + hdr[7] |= MQTT_HAS_WILL; + } + if (opts->clean || cid.len == 0) hdr[7] |= MQTT_CLEAN_SESSION; + if (opts->retain) hdr[7] |= MQTT_WILL_RETAIN; + total_len += (uint32_t) cid.len; + if (c->is_mqtt5) { + total_len += get_props_size(opts->props, opts->num_props); + if (hdr[7] & MQTT_HAS_WILL) + total_len += get_props_size(opts->will_props, opts->num_will_props); + } + + mg_mqtt_send_header(c, MQTT_CMD_CONNECT, 0, (uint32_t) total_len); + mg_send(c, hdr, sizeof(hdr)); + // keepalive == 0 means "do not disconnect us!" + mg_send_u16(c, mg_htons((uint16_t) opts->keepalive)); + + if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props); + + mg_send_u16(c, mg_htons((uint16_t) cid.len)); + mg_send(c, cid.buf, cid.len); + + if (hdr[7] & MQTT_HAS_WILL) { + if (c->is_mqtt5) + mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props); + + mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)); + mg_send(c, opts->topic.buf, opts->topic.len); + mg_send_u16(c, mg_htons((uint16_t) opts->message.len)); + mg_send(c, opts->message.buf, opts->message.len); + } + if (opts->user.len > 0) { + mg_send_u16(c, mg_htons((uint16_t) opts->user.len)); + mg_send(c, opts->user.buf, opts->user.len); + } + if (opts->pass.len > 0) { + mg_send_u16(c, mg_htons((uint16_t) opts->pass.len)); + mg_send(c, opts->pass.buf, opts->pass.len); + } +} + +uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) { + uint16_t id = opts->retransmit_id; + uint8_t flags = (uint8_t) (((opts->qos & 3) << 1) | (opts->retain ? 1 : 0)); + size_t len = 2 + opts->topic.len + opts->message.len; + MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int) opts->topic.len, + (char *) opts->topic.buf, (int) opts->message.len, + (char *) opts->message.buf)); + if (opts->qos > 0) len += 2; + if (c->is_mqtt5) len += get_props_size(opts->props, opts->num_props); + + if (opts->qos > 0 && id != 0) flags |= 1 << 3; + mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) len); + mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)); + mg_send(c, opts->topic.buf, opts->topic.len); + if (opts->qos > 0) { // need to send 'id' field + if (id == 0) { // generate new one if not resending + if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id; + id = c->mgr->mqtt_id; + } + mg_send_u16(c, mg_htons(id)); + } + + if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props); + + if (opts->message.len > 0) mg_send(c, opts->message.buf, opts->message.len); + return id; +} + +void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts) { + uint8_t qos_ = opts->qos & 3; + size_t plen = c->is_mqtt5 ? get_props_size(opts->props, opts->num_props) : 0; + size_t len = 2 + opts->topic.len + 2 + 1 + plen; + + mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, 2, (uint32_t) len); + if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id; + mg_send_u16(c, mg_htons(c->mgr->mqtt_id)); + if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props); + + mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)); + mg_send(c, opts->topic.buf, opts->topic.len); + mg_send(c, &qos_, sizeof(qos_)); +} + +int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version, + struct mg_mqtt_message *m) { + uint8_t lc = 0, *p, *end; + uint32_t n = 0, len_len = 0; + + memset(m, 0, sizeof(*m)); + m->dgram.buf = (char *) buf; + if (len < 2) return MQTT_INCOMPLETE; + m->cmd = (uint8_t) (buf[0] >> 4); + m->qos = (buf[0] >> 1) & 3; + + n = len_len = 0; + p = (uint8_t *) buf + 1; + while ((size_t) (p - buf) < len) { + lc = *((uint8_t *) p++); + n += (uint32_t) ((lc & 0x7f) << 7 * len_len); + len_len++; + if (!(lc & 0x80)) break; + if (len_len >= 4) return MQTT_MALFORMED; + } + end = p + n; + if ((lc & 0x80) || (end > buf + len)) return MQTT_INCOMPLETE; + m->dgram.len = (size_t) (end - buf); + + switch (m->cmd) { + case MQTT_CMD_CONNACK: + if (end - p < 2) return MQTT_MALFORMED; + m->ack = p[1]; + break; + case MQTT_CMD_PUBACK: + case MQTT_CMD_PUBREC: + case MQTT_CMD_PUBREL: + case MQTT_CMD_PUBCOMP: + case MQTT_CMD_SUBSCRIBE: + case MQTT_CMD_SUBACK: + case MQTT_CMD_UNSUBSCRIBE: + case MQTT_CMD_UNSUBACK: + if (p + 2 > end) return MQTT_MALFORMED; + m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]); + p += 2; + break; + case MQTT_CMD_PUBLISH: { + if (p + 2 > end) return MQTT_MALFORMED; + m->topic.len = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]); + m->topic.buf = (char *) p + 2; + p += 2 + m->topic.len; + if (p > end) return MQTT_MALFORMED; + if (m->qos > 0) { + if (p + 2 > end) return MQTT_MALFORMED; + m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]); + p += 2; + } + if (p > end) return MQTT_MALFORMED; + if (version == 5 && p + 2 < end) { + len_len = + (uint32_t) decode_varint(p, (size_t) (end - p), &m->props_size); + if (!len_len) return MQTT_MALFORMED; + m->props_start = (size_t) (p + len_len - buf); + p += len_len + m->props_size; + } + if (p > end) return MQTT_MALFORMED; + m->data.buf = (char *) p; + m->data.len = (size_t) (end - p); + break; + } + default: + break; + } + return MQTT_OK; +} + +static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_READ) { + for (;;) { + uint8_t version = c->is_mqtt5 ? 5 : 4; + struct mg_mqtt_message mm; + int rc = mg_mqtt_parse(c->recv.buf, c->recv.len, version, &mm); + if (rc == MQTT_MALFORMED) { + MG_ERROR(("%lu MQTT malformed message", c->id)); + c->is_closing = 1; + break; + } else if (rc == MQTT_OK) { + MG_VERBOSE(("%lu MQTT CMD %d len %d [%.*s]", c->id, mm.cmd, + (int) mm.dgram.len, (int) mm.data.len, mm.data.buf)); + switch (mm.cmd) { + case MQTT_CMD_CONNACK: + mg_call(c, MG_EV_MQTT_OPEN, &mm.ack); + if (mm.ack == 0) { + MG_DEBUG(("%lu Connected", c->id)); + } else { + MG_ERROR(("%lu MQTT auth failed, code %d", c->id, mm.ack)); + c->is_closing = 1; + } + break; + case MQTT_CMD_PUBLISH: { + /*MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int) mm.topic.len, + mm.topic.buf, (int) mm.data.len, mm.data.buf));*/ + if (mm.qos > 0) { + uint16_t id = mg_ntohs(mm.id); + uint32_t remaining_len = sizeof(id); + if (c->is_mqtt5) remaining_len += 2; // 3.4.2 + + mg_mqtt_send_header( + c, + (uint8_t) (mm.qos == 2 ? MQTT_CMD_PUBREC : MQTT_CMD_PUBACK), + 0, remaining_len); + mg_send(c, &id, sizeof(id)); + + if (c->is_mqtt5) { + uint16_t zero = 0; + mg_send(c, &zero, sizeof(zero)); + } + } + mg_call(c, MG_EV_MQTT_MSG, &mm); // let the app handle qos stuff + break; + } + case MQTT_CMD_PUBREC: { // MQTT5: 3.5.2-1 TODO(): variable header rc + uint16_t id = mg_ntohs(mm.id); + uint32_t remaining_len = sizeof(id); // MQTT5 3.6.2-1 + mg_mqtt_send_header(c, MQTT_CMD_PUBREL, 2, remaining_len); + mg_send(c, &id, sizeof(id)); // MQTT5 3.6.1-1, flags = 2 + break; + } + case MQTT_CMD_PUBREL: { // MQTT5: 3.6.2-1 TODO(): variable header rc + uint16_t id = mg_ntohs(mm.id); + uint32_t remaining_len = sizeof(id); // MQTT5 3.7.2-1 + mg_mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len); + mg_send(c, &id, sizeof(id)); + break; + } + } + mg_call(c, MG_EV_MQTT_CMD, &mm); + mg_iobuf_del(&c->recv, 0, mm.dgram.len); + } else { + break; + } + } + } + (void) ev_data; +} + +void mg_mqtt_ping(struct mg_connection *nc) { + mg_mqtt_send_header(nc, MQTT_CMD_PINGREQ, 0, 0); +} + +void mg_mqtt_pong(struct mg_connection *nc) { + mg_mqtt_send_header(nc, MQTT_CMD_PINGRESP, 0, 0); +} + +void mg_mqtt_disconnect(struct mg_connection *c, + const struct mg_mqtt_opts *opts) { + size_t len = 0; + if (c->is_mqtt5) len = 1 + get_props_size(opts->props, opts->num_props); + mg_mqtt_send_header(c, MQTT_CMD_DISCONNECT, 0, (uint32_t) len); + + if (c->is_mqtt5) { + uint8_t zero = 0; + mg_send(c, &zero, sizeof(zero)); // reason code + mg_send_mqtt_properties(c, opts->props, opts->num_props); + } +} + +struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url, + const struct mg_mqtt_opts *opts, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = mg_connect(mgr, url, fn, fn_data); + if (c != NULL) { + struct mg_mqtt_opts empty; + memset(&empty, 0, sizeof(empty)); + mg_mqtt_login(c, opts == NULL ? &empty : opts); + c->pfn = mqtt_cb; + } + return c; +} + +struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = mg_listen(mgr, url, fn, fn_data); + if (c != NULL) c->pfn = mqtt_cb, c->pfn_data = mgr; + return c; +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/net.c" +#endif + + + + + + + + + +size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) { + size_t old = c->send.len; + mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap); + return c->send.len - old; +} + +size_t mg_printf(struct mg_connection *c, const char *fmt, ...) { + size_t len = 0; + va_list ap; + va_start(ap, fmt); + len = mg_vprintf(c, fmt, &ap); + va_end(ap); + return len; +} + +static bool mg_atonl(struct mg_str str, struct mg_addr *addr) { + uint32_t localhost = mg_htonl(0x7f000001); + if (mg_strcasecmp(str, mg_str("localhost")) != 0) return false; + memcpy(addr->ip, &localhost, sizeof(uint32_t)); + addr->is_ip6 = false; + return true; +} + +static bool mg_atone(struct mg_str str, struct mg_addr *addr) { + if (str.len > 0) return false; + memset(addr->ip, 0, sizeof(addr->ip)); + addr->is_ip6 = false; + return true; +} + +static bool mg_aton4(struct mg_str str, struct mg_addr *addr) { + uint8_t data[4] = {0, 0, 0, 0}; + size_t i, num_dots = 0; + for (i = 0; i < str.len; i++) { + if (str.buf[i] >= '0' && str.buf[i] <= '9') { + int octet = data[num_dots] * 10 + (str.buf[i] - '0'); + if (octet > 255) return false; + data[num_dots] = (uint8_t) octet; + } else if (str.buf[i] == '.') { + if (num_dots >= 3 || i == 0 || str.buf[i - 1] == '.') return false; + num_dots++; + } else { + return false; + } + } + if (num_dots != 3 || str.buf[i - 1] == '.') return false; + memcpy(&addr->ip, data, sizeof(data)); + addr->is_ip6 = false; + return true; +} + +static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) { + int i; + uint32_t ipv4; + if (str.len < 14) return false; + if (str.buf[0] != ':' || str.buf[1] != ':' || str.buf[6] != ':') return false; + for (i = 2; i < 6; i++) { + if (str.buf[i] != 'f' && str.buf[i] != 'F') return false; + } + // struct mg_str s = mg_str_n(&str.buf[7], str.len - 7); + if (!mg_aton4(mg_str_n(&str.buf[7], str.len - 7), addr)) return false; + memcpy(&ipv4, addr->ip, sizeof(ipv4)); + memset(addr->ip, 0, sizeof(addr->ip)); + addr->ip[10] = addr->ip[11] = 255; + memcpy(&addr->ip[12], &ipv4, 4); + addr->is_ip6 = true; + return true; +} + +static bool mg_aton6(struct mg_str str, struct mg_addr *addr) { + size_t i, j = 0, n = 0, dc = 42; + addr->scope_id = 0; + if (str.len > 2 && str.buf[0] == '[') str.buf++, str.len -= 2; + if (mg_v4mapped(str, addr)) return true; + for (i = 0; i < str.len; i++) { + if ((str.buf[i] >= '0' && str.buf[i] <= '9') || + (str.buf[i] >= 'a' && str.buf[i] <= 'f') || + (str.buf[i] >= 'A' && str.buf[i] <= 'F')) { + unsigned long val; // TODO(): This loops on chars, refactor + if (i > j + 3) return false; + // MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j])); + mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val)); + addr->ip[n] = (uint8_t) ((val >> 8) & 255); + addr->ip[n + 1] = (uint8_t) (val & 255); + } else if (str.buf[i] == ':') { + j = i + 1; + if (i > 0 && str.buf[i - 1] == ':') { + dc = n; // Double colon + if (i > 1 && str.buf[i - 2] == ':') return false; + } else if (i > 0) { + n += 2; + } + if (n > 14) return false; + addr->ip[n] = addr->ip[n + 1] = 0; // For trailing :: + } else if (str.buf[i] == '%') { // Scope ID, last in string + return mg_str_to_num(mg_str_n(&str.buf[i + 1], str.len - i - 1), 10, + &addr->scope_id, sizeof(uint8_t)); + } else { + return false; + } + } + if (n < 14 && dc == 42) return false; + if (n < 14) { + memmove(&addr->ip[dc + (14 - n)], &addr->ip[dc], n - dc + 2); + memset(&addr->ip[dc], 0, 14 - n); + } + + addr->is_ip6 = true; + return true; +} + +bool mg_aton(struct mg_str str, struct mg_addr *addr) { + // MG_INFO(("[%.*s]", (int) str.len, str.buf)); + return mg_atone(str, addr) || mg_atonl(str, addr) || mg_aton4(str, addr) || + mg_aton6(str, addr); +} + +struct mg_connection *mg_alloc_conn(struct mg_mgr *mgr) { + struct mg_connection *c = + (struct mg_connection *) calloc(1, sizeof(*c) + mgr->extraconnsize); + if (c != NULL) { + c->mgr = mgr; + c->send.align = c->recv.align = c->rtls.align = MG_IO_SIZE; + c->id = ++mgr->nextid; + MG_PROF_INIT(c); + } + return c; +} + +void mg_close_conn(struct mg_connection *c) { + mg_resolve_cancel(c); // Close any pending DNS query + LIST_DELETE(struct mg_connection, &c->mgr->conns, c); + if (c == c->mgr->dns4.c) c->mgr->dns4.c = NULL; + if (c == c->mgr->dns6.c) c->mgr->dns6.c = NULL; + // Order of operations is important. `MG_EV_CLOSE` event must be fired + // before we deallocate received data, see #1331 + mg_call(c, MG_EV_CLOSE, NULL); + MG_DEBUG(("%lu %ld closed", c->id, c->fd)); + MG_PROF_DUMP(c); + MG_PROF_FREE(c); + + mg_tls_free(c); + mg_iobuf_free(&c->recv); + mg_iobuf_free(&c->send); + mg_iobuf_free(&c->rtls); + mg_bzero((unsigned char *) c, sizeof(*c)); + free(c); +} + +struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = NULL; + if (url == NULL || url[0] == '\0') { + MG_ERROR(("null url")); + } else if ((c = mg_alloc_conn(mgr)) == NULL) { + MG_ERROR(("OOM")); + } else { + LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); + c->is_udp = (strncmp(url, "udp:", 4) == 0); + c->fd = (void *) (size_t) MG_INVALID_SOCKET; + c->fn = fn; + c->is_client = true; + c->fn_data = fn_data; + MG_DEBUG(("%lu %ld %s", c->id, c->fd, url)); + mg_call(c, MG_EV_OPEN, (void *) url); + mg_resolve(c, url); + } + return c; +} + +struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = NULL; + if ((c = mg_alloc_conn(mgr)) == NULL) { + MG_ERROR(("OOM %s", url)); + } else if (!mg_open_listener(c, url)) { + MG_ERROR(("Failed: %s, errno %d", url, errno)); + MG_PROF_FREE(c); + free(c); + c = NULL; + } else { + c->is_listening = 1; + c->is_udp = strncmp(url, "udp:", 4) == 0; + LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); + c->fn = fn; + c->fn_data = fn_data; + mg_call(c, MG_EV_OPEN, NULL); + if (mg_url_is_ssl(url)) c->is_tls = 1; // Accepted connection must + MG_DEBUG(("%lu %ld %s", c->id, c->fd, url)); + } + return c; +} + +struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = mg_alloc_conn(mgr); + if (c != NULL) { + c->fd = (void *) (size_t) fd; + c->fn = fn; + c->fn_data = fn_data; + MG_EPOLL_ADD(c); + mg_call(c, MG_EV_OPEN, NULL); + LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); + } + return c; +} + +struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds, + unsigned flags, void (*fn)(void *), void *arg) { + struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t)); + if (t != NULL) { + mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg); + t->id = mgr->timerid++; + } + return t; +} + +long mg_io_recv(struct mg_connection *c, void *buf, size_t len) { + if (c->rtls.len == 0) return MG_IO_WAIT; + if (len > c->rtls.len) len = c->rtls.len; + memcpy(buf, c->rtls.buf, len); + mg_iobuf_del(&c->rtls, 0, len); + return (long) len; +} + +void mg_mgr_free(struct mg_mgr *mgr) { + struct mg_connection *c; + struct mg_timer *tmp, *t = mgr->timers; + while (t != NULL) tmp = t->next, free(t), t = tmp; + mgr->timers = NULL; // Important. Next call to poll won't touch timers + for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1; + mg_mgr_poll(mgr, 0); +#if MG_ENABLE_FREERTOS_TCP + FreeRTOS_DeleteSocketSet(mgr->ss); +#endif + MG_DEBUG(("All connections closed")); +#if MG_ENABLE_EPOLL + if (mgr->epoll_fd >= 0) close(mgr->epoll_fd), mgr->epoll_fd = -1; +#endif + mg_tls_ctx_free(mgr); +} + +void mg_mgr_init(struct mg_mgr *mgr) { + memset(mgr, 0, sizeof(*mgr)); +#if MG_ENABLE_EPOLL + if ((mgr->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) + MG_ERROR(("epoll_create1 errno %d", errno)); +#else + mgr->epoll_fd = -1; +#endif +#if MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK + // clang-format off + { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); } + // clang-format on +#elif MG_ENABLE_FREERTOS_TCP + mgr->ss = FreeRTOS_CreateSocketSet(); +#elif defined(__unix) || defined(__unix__) || defined(__APPLE__) + // Ignore SIGPIPE signal, so if client cancels the request, it + // won't kill the whole process. + signal(SIGPIPE, SIG_IGN); +#elif MG_ENABLE_TCPIP_DRIVER_INIT && defined(MG_TCPIP_DRIVER_INIT) + MG_TCPIP_DRIVER_INIT(mgr); +#endif + mgr->pipe = MG_INVALID_SOCKET; + mgr->dnstimeout = 3000; + mgr->dns4.url = "udp://8.8.8.8:53"; + mgr->dns6.url = "udp://[2001:4860:4860::8888]:53"; + mg_tls_ctx_init(mgr); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/net_builtin.c" +#endif + + +#if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP +#define MG_EPHEMERAL_PORT_BASE 32768 +#define PDIFF(a, b) ((size_t) (((char *) (b)) - ((char *) (a)))) + +#ifndef MIP_TCP_KEEPALIVE_MS +#define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms +#endif + +#define MIP_TCP_ACK_MS 150 // Timeout for ACKing +#define MIP_TCP_ARP_MS 100 // Timeout for ARP response +#define MIP_TCP_SYN_MS 15000 // Timeout for connection establishment +#define MIP_TCP_FIN_MS 1000 // Timeout for closing connection +#define MIP_TCP_WIN 6000 // TCP window size + +struct connstate { + uint32_t seq, ack; // TCP seq/ack counters + uint64_t timer; // TCP keep-alive / ACK timer + uint32_t acked; // Last ACK-ed number + size_t unacked; // Not acked bytes + uint8_t mac[6]; // Peer MAC address + uint8_t ttype; // Timer type. 0: ack, 1: keep-alive +#define MIP_TTYPE_KEEPALIVE 0 // Connection is idle for long, send keepalive +#define MIP_TTYPE_ACK 1 // Peer sent us data, we have to ack it soon +#define MIP_TTYPE_ARP 2 // ARP resolve sent, waiting for response +#define MIP_TTYPE_SYN 3 // SYN sent, waiting for response +#define MIP_TTYPE_FIN 4 // FIN sent, waiting until terminating the connection + uint8_t tmiss; // Number of keep-alive misses + struct mg_iobuf raw; // For TLS only. Incoming raw data +}; + +#pragma pack(push, 1) + +struct lcp { + uint8_t addr, ctrl, proto[2], code, id, len[2]; +}; + +struct eth { + uint8_t dst[6]; // Destination MAC address + uint8_t src[6]; // Source MAC address + uint16_t type; // Ethernet type +}; + +struct ip { + uint8_t ver; // Version + uint8_t tos; // Unused + uint16_t len; // Length + uint16_t id; // Unused + uint16_t frag; // Fragmentation +#define IP_FRAG_OFFSET_MSK 0xFF1F +#define IP_MORE_FRAGS_MSK 0x20 + uint8_t ttl; // Time to live + uint8_t proto; // Upper level protocol + uint16_t csum; // Checksum + uint32_t src; // Source IP + uint32_t dst; // Destination IP +}; + +struct ip6 { + uint8_t ver; // Version + uint8_t opts[3]; // Options + uint16_t len; // Length + uint8_t proto; // Upper level protocol + uint8_t ttl; // Time to live + uint8_t src[16]; // Source IP + uint8_t dst[16]; // Destination IP +}; + +struct icmp { + uint8_t type; + uint8_t code; + uint16_t csum; +}; + +struct arp { + uint16_t fmt; // Format of hardware address + uint16_t pro; // Format of protocol address + uint8_t hlen; // Length of hardware address + uint8_t plen; // Length of protocol address + uint16_t op; // Operation + uint8_t sha[6]; // Sender hardware address + uint32_t spa; // Sender protocol address + uint8_t tha[6]; // Target hardware address + uint32_t tpa; // Target protocol address +}; + +struct tcp { + uint16_t sport; // Source port + uint16_t dport; // Destination port + uint32_t seq; // Sequence number + uint32_t ack; // Acknowledgement number + uint8_t off; // Data offset + uint8_t flags; // TCP flags +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 +#define TH_ECE 0x40 +#define TH_CWR 0x80 + uint16_t win; // Window + uint16_t csum; // Checksum + uint16_t urp; // Urgent pointer +}; + +struct udp { + uint16_t sport; // Source port + uint16_t dport; // Destination port + uint16_t len; // UDP length + uint16_t csum; // UDP checksum +}; + +struct dhcp { + uint8_t op, htype, hlen, hops; + uint32_t xid; + uint16_t secs, flags; + uint32_t ciaddr, yiaddr, siaddr, giaddr; + uint8_t hwaddr[208]; + uint32_t magic; + uint8_t options[32]; +}; + +#pragma pack(pop) + +struct pkt { + struct mg_str raw; // Raw packet data + struct mg_str pay; // Payload data + struct eth *eth; + struct llc *llc; + struct arp *arp; + struct ip *ip; + struct ip6 *ip6; + struct icmp *icmp; + struct tcp *tcp; + struct udp *udp; + struct dhcp *dhcp; +}; + +static void send_syn(struct mg_connection *c); + +static void mkpay(struct pkt *pkt, void *p) { + pkt->pay = + mg_str_n((char *) p, (size_t) (&pkt->raw.buf[pkt->raw.len] - (char *) p)); +} + +static uint32_t csumup(uint32_t sum, const void *buf, size_t len) { + size_t i; + const uint8_t *p = (const uint8_t *) buf; + for (i = 0; i < len; i++) sum += i & 1 ? p[i] : (uint32_t) (p[i] << 8); + return sum; +} + +static uint16_t csumfin(uint32_t sum) { + while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); + return mg_htons(~sum & 0xffff); +} + +static uint16_t ipcsum(const void *buf, size_t len) { + uint32_t sum = csumup(0, buf, len); + return csumfin(sum); +} + +static void settmout(struct mg_connection *c, uint8_t type) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + struct connstate *s = (struct connstate *) (c + 1); + unsigned n = type == MIP_TTYPE_ACK ? MIP_TCP_ACK_MS + : type == MIP_TTYPE_ARP ? MIP_TCP_ARP_MS + : type == MIP_TTYPE_SYN ? MIP_TCP_SYN_MS + : type == MIP_TTYPE_FIN ? MIP_TCP_FIN_MS + : MIP_TCP_KEEPALIVE_MS; + s->timer = ifp->now + n; + s->ttype = type; + MG_VERBOSE(("%lu %d -> %llx", c->id, type, s->timer)); +} + +static size_t ether_output(struct mg_tcpip_if *ifp, size_t len) { + size_t n = ifp->driver->tx(ifp->tx.buf, len, ifp); + if (n == len) ifp->nsent++; + return n; +} + +static void arp_ask(struct mg_tcpip_if *ifp, uint32_t ip) { + struct eth *eth = (struct eth *) ifp->tx.buf; + struct arp *arp = (struct arp *) (eth + 1); + memset(eth->dst, 255, sizeof(eth->dst)); + memcpy(eth->src, ifp->mac, sizeof(eth->src)); + eth->type = mg_htons(0x806); + memset(arp, 0, sizeof(*arp)); + arp->fmt = mg_htons(1), arp->pro = mg_htons(0x800), arp->hlen = 6, + arp->plen = 4; + arp->op = mg_htons(1), arp->tpa = ip, arp->spa = ifp->ip; + memcpy(arp->sha, ifp->mac, sizeof(arp->sha)); + ether_output(ifp, PDIFF(eth, arp + 1)); +} + +static void onstatechange(struct mg_tcpip_if *ifp) { + if (ifp->state == MG_TCPIP_STATE_READY) { + MG_INFO(("READY, IP: %M", mg_print_ip4, &ifp->ip)); + MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw)); + MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac)); + arp_ask(ifp, ifp->gw); + } else if (ifp->state == MG_TCPIP_STATE_UP) { + MG_ERROR(("Link up")); + srand((unsigned int) mg_millis()); + } else if (ifp->state == MG_TCPIP_STATE_DOWN) { + MG_ERROR(("Link down")); + } +} + +static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *mac_dst, + uint8_t proto, uint32_t ip_src, uint32_t ip_dst, + size_t plen) { + struct eth *eth = (struct eth *) ifp->tx.buf; + struct ip *ip = (struct ip *) (eth + 1); + memcpy(eth->dst, mac_dst, sizeof(eth->dst)); + memcpy(eth->src, ifp->mac, sizeof(eth->src)); // Use our MAC + eth->type = mg_htons(0x800); + memset(ip, 0, sizeof(*ip)); + ip->ver = 0x45; // Version 4, header length 5 words + ip->frag = 0x40; // Don't fragment + ip->len = mg_htons((uint16_t) (sizeof(*ip) + plen)); + ip->ttl = 64; + ip->proto = proto; + ip->src = ip_src; + ip->dst = ip_dst; + ip->csum = ipcsum(ip, sizeof(*ip)); + return ip; +} + +static void tx_udp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, + uint16_t sport, uint32_t ip_dst, uint16_t dport, + const void *buf, size_t len) { + struct ip *ip = + tx_ip(ifp, mac_dst, 17, ip_src, ip_dst, len + sizeof(struct udp)); + struct udp *udp = (struct udp *) (ip + 1); + // MG_DEBUG(("UDP XX LEN %d %d", (int) len, (int) ifp->tx.len)); + udp->sport = sport; + udp->dport = dport; + udp->len = mg_htons((uint16_t) (sizeof(*udp) + len)); + udp->csum = 0; + uint32_t cs = csumup(0, udp, sizeof(*udp)); + cs = csumup(cs, buf, len); + cs = csumup(cs, &ip->src, sizeof(ip->src)); + cs = csumup(cs, &ip->dst, sizeof(ip->dst)); + cs += (uint32_t) (ip->proto + sizeof(*udp) + len); + udp->csum = csumfin(cs); + memmove(udp + 1, buf, len); + // MG_DEBUG(("UDP LEN %d %d", (int) len, (int) ifp->frame_len)); + ether_output(ifp, sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len); +} + +static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, + uint32_t ip_dst, uint8_t *opts, size_t optslen, + bool ciaddr) { + // https://datatracker.ietf.org/doc/html/rfc2132#section-9.6 + struct dhcp dhcp = {1, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; + dhcp.magic = mg_htonl(0x63825363); + memcpy(&dhcp.hwaddr, ifp->mac, sizeof(ifp->mac)); + memcpy(&dhcp.xid, ifp->mac + 2, sizeof(dhcp.xid)); + memcpy(&dhcp.options, opts, optslen); + if (ciaddr) dhcp.ciaddr = ip_src; + tx_udp(ifp, mac_dst, ip_src, mg_htons(68), ip_dst, mg_htons(67), &dhcp, + sizeof(dhcp)); +} + +static const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255}; + +// RFC-2131 #4.3.6, #4.4.1 +static void tx_dhcp_request_sel(struct mg_tcpip_if *ifp, uint32_t ip_req, + uint32_t ip_srv) { + uint8_t opts[] = { + 53, 1, 3, // Type: DHCP request + 55, 2, 1, 3, // GW and mask + 12, 3, 'm', 'i', 'p', // Host name: "mip" + 54, 4, 0, 0, 0, 0, // DHCP server ID + 50, 4, 0, 0, 0, 0, // Requested IP + 255 // End of options + }; + memcpy(opts + 14, &ip_srv, sizeof(ip_srv)); + memcpy(opts + 20, &ip_req, sizeof(ip_req)); + tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false); + MG_DEBUG(("DHCP req sent")); +} + +// RFC-2131 #4.3.6, #4.4.5 (renewing: unicast, rebinding: bcast) +static void tx_dhcp_request_re(struct mg_tcpip_if *ifp, uint8_t *mac_dst, + uint32_t ip_src, uint32_t ip_dst) { + uint8_t opts[] = { + 53, 1, 3, // Type: DHCP request + 255 // End of options + }; + tx_dhcp(ifp, mac_dst, ip_src, ip_dst, opts, sizeof(opts), true); + MG_DEBUG(("DHCP req sent")); +} + +static void tx_dhcp_discover(struct mg_tcpip_if *ifp) { + uint8_t opts[] = { + 53, 1, 1, // Type: DHCP discover + 55, 2, 1, 3, // Parameters: ip, mask + 255 // End of options + }; + tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false); + MG_DEBUG(("DHCP discover sent. Our MAC: %M", mg_print_mac, ifp->mac)); +} + +static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt, + bool lsn) { + struct mg_connection *c = NULL; + for (c = mgr->conns; c != NULL; c = c->next) { + if (c->is_arplooking && pkt->arp && + memcmp(&pkt->arp->spa, c->rem.ip, sizeof(pkt->arp->spa)) == 0) + break; + if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport) break; + if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport && + lsn == c->is_listening && (lsn || c->rem.port == pkt->tcp->sport)) + break; + } + return c; +} + +static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) { + if (pkt->arp->op == mg_htons(1) && pkt->arp->tpa == ifp->ip) { + // ARP request. Make a response, then send + // MG_DEBUG(("ARP op %d %M: %M", mg_ntohs(pkt->arp->op), mg_print_ip4, + // &pkt->arp->spa, mg_print_ip4, &pkt->arp->tpa)); + struct eth *eth = (struct eth *) ifp->tx.buf; + struct arp *arp = (struct arp *) (eth + 1); + memcpy(eth->dst, pkt->eth->src, sizeof(eth->dst)); + memcpy(eth->src, ifp->mac, sizeof(eth->src)); + eth->type = mg_htons(0x806); + *arp = *pkt->arp; + arp->op = mg_htons(2); + memcpy(arp->tha, pkt->arp->sha, sizeof(pkt->arp->tha)); + memcpy(arp->sha, ifp->mac, sizeof(pkt->arp->sha)); + arp->tpa = pkt->arp->spa; + arp->spa = ifp->ip; + MG_DEBUG(("ARP: tell %M we're %M", mg_print_ip4, &arp->tpa, mg_print_mac, + &ifp->mac)); + ether_output(ifp, PDIFF(eth, arp + 1)); + } else if (pkt->arp->op == mg_htons(2)) { + if (memcmp(pkt->arp->tha, ifp->mac, sizeof(pkt->arp->tha)) != 0) return; + if (pkt->arp->spa == ifp->gw) { + // Got response for the GW ARP request. Set ifp->gwmac + memcpy(ifp->gwmac, pkt->arp->sha, sizeof(ifp->gwmac)); + } else { + struct mg_connection *c = getpeer(ifp->mgr, pkt, false); + if (c != NULL && c->is_arplooking) { + struct connstate *s = (struct connstate *) (c + 1); + memcpy(s->mac, pkt->arp->sha, sizeof(s->mac)); + MG_DEBUG(("%lu ARP resolved %M -> %M", c->id, mg_print_ip4, c->rem.ip, + mg_print_mac, s->mac)); + c->is_arplooking = 0; + send_syn(c); + settmout(c, MIP_TTYPE_SYN); + } + } + } +} + +static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) { + // MG_DEBUG(("ICMP %d", (int) len)); + if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) { + size_t hlen = sizeof(struct eth) + sizeof(struct ip) + sizeof(struct icmp); + size_t space = ifp->tx.len - hlen, plen = pkt->pay.len; + if (plen > space) plen = space; + struct ip *ip = tx_ip(ifp, pkt->eth->src, 1, ifp->ip, pkt->ip->src, + sizeof(struct icmp) + plen); + struct icmp *icmp = (struct icmp *) (ip + 1); + memset(icmp, 0, sizeof(*icmp)); // Set csum to 0 + memcpy(icmp + 1, pkt->pay.buf, plen); // Copy RX payload to TX + icmp->csum = ipcsum(icmp, sizeof(*icmp) + plen); + ether_output(ifp, hlen + plen); + } +} + +static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { + uint32_t ip = 0, gw = 0, mask = 0, lease = 0; + uint8_t msgtype = 0, state = ifp->state; + // perform size check first, then access fields + uint8_t *p = pkt->dhcp->options, + *end = (uint8_t *) &pkt->raw.buf[pkt->raw.len]; + if (end < (uint8_t *) (pkt->dhcp + 1)) return; + if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return; + while (p + 1 < end && p[0] != 255) { // Parse options RFC-1533 #9 + if (p[0] == 1 && p[1] == sizeof(ifp->mask) && p + 6 < end) { // Mask + memcpy(&mask, p + 2, sizeof(mask)); + } else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW + memcpy(&gw, p + 2, sizeof(gw)); + ip = pkt->dhcp->yiaddr; + } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease + memcpy(&lease, p + 2, sizeof(lease)); + lease = mg_ntohl(lease); + } else if (p[0] == 53 && p[1] == 1 && p + 6 < end) { // Msg Type + msgtype = p[2]; + } + p += p[1] + 2; + } + // Process message type, RFC-1533 (9.4); RFC-2131 (3.1, 4) + if (msgtype == 6 && ifp->ip == ip) { // DHCPNACK, release IP + ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; + } else if (msgtype == 2 && ifp->state == MG_TCPIP_STATE_UP && ip && gw && + lease) { // DHCPOFFER + // select IP, (4.4.1) (fallback to IP source addr on foul play) + tx_dhcp_request_sel(ifp, ip, + pkt->dhcp->siaddr ? pkt->dhcp->siaddr : pkt->ip->src); + ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state + } else if (msgtype == 5) { // DHCPACK + if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP + ifp->lease_expire = ifp->now + lease * 1000; + MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); + // assume DHCP server = router until ARP resolves + memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); + ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; + ifp->state = MG_TCPIP_STATE_READY; // BOUND state + uint64_t rand; + mg_random(&rand, sizeof(rand)); + srand((unsigned int) (rand + mg_millis())); + } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew + ifp->lease_expire = ifp->now + lease * 1000; + MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); + } // TODO(): accept provided T1/T2 and store server IP for renewal (4.4) + } + if (ifp->state != state) onstatechange(ifp); +} + +// Simple DHCP server that assigns a next IP address: ifp->ip + 1 +static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) { + uint8_t op = 0, *p = pkt->dhcp->options, + *end = (uint8_t *) &pkt->raw.buf[pkt->raw.len]; + if (end < (uint8_t *) (pkt->dhcp + 1)) return; + // struct dhcp *req = pkt->dhcp; + struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; + res.yiaddr = ifp->ip; + ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1 + while (p + 1 < end && p[0] != 255) { // Parse options + if (p[0] == 53 && p[1] == 1 && p + 2 < end) { // Message type + op = p[2]; + } + p += p[1] + 2; + } + if (op == 1 || op == 3) { // DHCP Discover or DHCP Request + uint8_t msg = op == 1 ? 2 : 5; // Message type: DHCP OFFER or DHCP ACK + uint8_t opts[] = { + 53, 1, msg, // Message type + 1, 4, 0, 0, 0, 0, // Subnet mask + 54, 4, 0, 0, 0, 0, // Server ID + 12, 3, 'm', 'i', 'p', // Host name: "mip" + 51, 4, 255, 255, 255, 255, // Lease time + 255 // End of options + }; + memcpy(&res.hwaddr, pkt->dhcp->hwaddr, 6); + memcpy(opts + 5, &ifp->mask, sizeof(ifp->mask)); + memcpy(opts + 11, &ifp->ip, sizeof(ifp->ip)); + memcpy(&res.options, opts, sizeof(opts)); + res.magic = pkt->dhcp->magic; + res.xid = pkt->dhcp->xid; + if (ifp->enable_get_gateway) { + ifp->gw = res.yiaddr; + memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); + } + tx_udp(ifp, pkt->eth->src, ifp->ip, mg_htons(67), + op == 1 ? ~0U : res.yiaddr, mg_htons(68), &res, sizeof(res)); + } +} + +static void rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) { + struct mg_connection *c = getpeer(ifp->mgr, pkt, true); + if (c == NULL) { + // No UDP listener on this port. Should send ICMP, but keep silent. + } else { + c->rem.port = pkt->udp->sport; + memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t)); + struct connstate *s = (struct connstate *) (c + 1); + memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); + if (c->recv.len >= MG_MAX_RECV_SIZE) { + mg_error(c, "max_recv_buf_size reached"); + } else if (c->recv.size - c->recv.len < pkt->pay.len && + !mg_iobuf_resize(&c->recv, c->recv.len + pkt->pay.len)) { + mg_error(c, "oom"); + } else { + memcpy(&c->recv.buf[c->recv.len], pkt->pay.buf, pkt->pay.len); + c->recv.len += pkt->pay.len; + mg_call(c, MG_EV_READ, &pkt->pay.len); + } + } +} + +static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip, + uint8_t flags, uint16_t sport, uint16_t dport, + uint32_t seq, uint32_t ack, const void *buf, size_t len) { +#if 0 + uint8_t opts[] = {2, 4, 5, 0xb4, 4, 2, 0, 0}; // MSS = 1460, SACK permitted + if (flags & TH_SYN) { + // Handshake? Set MSS + buf = opts; + len = sizeof(opts); + } +#endif + struct ip *ip = + tx_ip(ifp, dst_mac, 6, ifp->ip, dst_ip, sizeof(struct tcp) + len); + struct tcp *tcp = (struct tcp *) (ip + 1); + memset(tcp, 0, sizeof(*tcp)); + if (buf != NULL && len) memmove(tcp + 1, buf, len); + tcp->sport = sport; + tcp->dport = dport; + tcp->seq = seq; + tcp->ack = ack; + tcp->flags = flags; + tcp->win = mg_htons(MIP_TCP_WIN); + tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4); + // if (flags & TH_SYN) tcp->off = 0x70; // Handshake? header size 28 bytes + + uint32_t cs = 0; + uint16_t n = (uint16_t) (sizeof(*tcp) + len); + uint8_t pseudo[] = {0, ip->proto, (uint8_t) (n >> 8), (uint8_t) (n & 255)}; + cs = csumup(cs, tcp, n); + cs = csumup(cs, &ip->src, sizeof(ip->src)); + cs = csumup(cs, &ip->dst, sizeof(ip->dst)); + cs = csumup(cs, pseudo, sizeof(pseudo)); + tcp->csum = csumfin(cs); + MG_VERBOSE(("TCP %M:%hu -> %M:%hu fl %x len %u", mg_print_ip4, &ip->src, + mg_ntohs(tcp->sport), mg_print_ip4, &ip->dst, + mg_ntohs(tcp->dport), tcp->flags, len)); + // mg_hexdump(ifp->tx.buf, PDIFF(ifp->tx.buf, tcp + 1) + len); + return ether_output(ifp, PDIFF(ifp->tx.buf, tcp + 1) + len); +} + +static size_t tx_tcp_pkt(struct mg_tcpip_if *ifp, struct pkt *pkt, + uint8_t flags, uint32_t seq, const void *buf, + size_t len) { + uint32_t delta = (pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0; + return tx_tcp(ifp, pkt->eth->src, pkt->ip->src, flags, pkt->tcp->dport, + pkt->tcp->sport, seq, mg_htonl(mg_ntohl(pkt->tcp->seq) + delta), + buf, len); +} + +static struct mg_connection *accept_conn(struct mg_connection *lsn, + struct pkt *pkt) { + struct mg_connection *c = mg_alloc_conn(lsn->mgr); + if (c == NULL) { + MG_ERROR(("OOM")); + return NULL; + } + struct connstate *s = (struct connstate *) (c + 1); + s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq); + memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); + settmout(c, MIP_TTYPE_KEEPALIVE); + memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t)); + c->rem.port = pkt->tcp->sport; + MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem)); + LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c); + c->is_accepted = 1; + c->is_hexdumping = lsn->is_hexdumping; + c->pfn = lsn->pfn; + c->loc = lsn->loc; + c->pfn_data = lsn->pfn_data; + c->fn = lsn->fn; + c->fn_data = lsn->fn_data; + mg_call(c, MG_EV_OPEN, NULL); + mg_call(c, MG_EV_ACCEPT, NULL); + return c; +} + +static size_t trim_len(struct mg_connection *c, size_t len) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + size_t eth_h_len = 14, ip_max_h_len = 24, tcp_max_h_len = 60, udp_h_len = 8; + size_t max_headers_len = + eth_h_len + ip_max_h_len + (c->is_udp ? udp_h_len : tcp_max_h_len); + size_t min_mtu = c->is_udp ? 68 /* RFC-791 */ : max_headers_len - eth_h_len; + + // If the frame exceeds the available buffer, trim the length + if (len + max_headers_len > ifp->tx.len) { + len = ifp->tx.len - max_headers_len; + } + // Ensure the MTU isn't lower than the minimum allowed value + if (ifp->mtu < min_mtu) { + MG_ERROR(("MTU is lower than minimum, capping to %lu", min_mtu)); + ifp->mtu = (uint16_t) min_mtu; + } + // If the total packet size exceeds the MTU, trim the length + if (len + max_headers_len - eth_h_len > ifp->mtu) { + len = ifp->mtu - max_headers_len + eth_h_len; + if (c->is_udp) { + MG_ERROR(("UDP datagram exceeds MTU. Truncating it.")); + } + } + + return len; +} + +long mg_io_send(struct mg_connection *c, const void *buf, size_t len) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + struct connstate *s = (struct connstate *) (c + 1); + uint32_t dst_ip = *(uint32_t *) c->rem.ip; + len = trim_len(c, len); + if (c->is_udp) { + tx_udp(ifp, s->mac, ifp->ip, c->loc.port, dst_ip, c->rem.port, buf, len); + } else { + size_t sent = + tx_tcp(ifp, s->mac, dst_ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq), mg_htonl(s->ack), buf, len); + if (sent == 0) { + return MG_IO_WAIT; + } else if (sent == (size_t) -1) { + return MG_IO_ERR; + } else { + s->seq += (uint32_t) len; + if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE); + } + } + return (long) len; +} + +static void handle_tls_recv(struct mg_connection *c, struct mg_iobuf *io) { + long n = mg_tls_recv(c, &io->buf[io->len], io->size - io->len); + if (n == MG_IO_ERR) { + mg_error(c, "TLS recv error"); + } else if (n > 0) { + // Decrypted successfully - trigger MG_EV_READ + io->len += (size_t) n; + mg_call(c, MG_EV_READ, &n); + } +} + +static void read_conn(struct mg_connection *c, struct pkt *pkt) { + struct connstate *s = (struct connstate *) (c + 1); + struct mg_iobuf *io = c->is_tls ? &c->rtls : &c->recv; + uint32_t seq = mg_ntohl(pkt->tcp->seq); + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + if (pkt->tcp->flags & TH_FIN) { + // If we initiated the closure, we reply with ACK upon receiving FIN + // If we didn't initiate it, we reply with FIN as part of the normal TCP + // closure process + uint8_t flags = TH_ACK; + s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1); + if (c->is_draining && s->ttype == MIP_TTYPE_FIN) { + if (s->seq == mg_htonl(pkt->tcp->ack)) { // Simultaneous closure ? + s->seq++; // Yes. Increment our SEQ + } else { // Otherwise, + s->seq = mg_htonl(pkt->tcp->ack); // Set to peer's ACK + } + } else { + flags |= TH_FIN; + c->is_draining = 1; + settmout(c, MIP_TTYPE_FIN); + } + tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, flags, + c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0); + } else if (pkt->pay.len == 0) { + // TODO(cpq): handle this peer's ACK + } else if (seq != s->ack) { + uint32_t ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len); + if (s->ack == ack) { + MG_VERBOSE(("ignoring duplicate pkt")); + } else { + MG_VERBOSE(("SEQ != ACK: %x %x %x", seq, s->ack, ack)); + tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, TH_ACK, + c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", + 0); + } + } else if (io->size - io->len < pkt->pay.len && + !mg_iobuf_resize(io, io->len + pkt->pay.len)) { + mg_error(c, "oom"); + } else { + // Copy TCP payload into the IO buffer. If the connection is plain text, + // we copy to c->recv. If the connection is TLS, this data is encrypted, + // therefore we copy that encrypted data to the c->rtls iobuffer instead, + // and then call mg_tls_recv() to decrypt it. NOTE: mg_tls_recv() will + // call back mg_io_recv() which grabs raw data from c->rtls + memcpy(&io->buf[io->len], pkt->pay.buf, pkt->pay.len); + io->len += pkt->pay.len; + + MG_VERBOSE(("%lu SEQ %x -> %x", c->id, mg_htonl(pkt->tcp->seq), s->ack)); + // Advance ACK counter + s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len); + s->unacked += pkt->pay.len; + // size_t diff = s->acked <= s->ack ? s->ack - s->acked : s->ack; + if (s->unacked > MIP_TCP_WIN / 2 && s->acked != s->ack) { + // Send ACK immediately + MG_VERBOSE(("%lu imm ACK %lu", c->id, s->acked)); + tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, TH_ACK, + c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), NULL, + 0); + s->unacked = 0; + s->acked = s->ack; + if (s->ttype != MIP_TTYPE_KEEPALIVE) settmout(c, MIP_TTYPE_KEEPALIVE); + } else { + // if not already running, setup a timer to send an ACK later + if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK); + } + + if (c->is_tls && c->is_tls_hs) { + mg_tls_handshake(c); + } else if (c->is_tls) { + // TLS connection. Make room for decrypted data in c->recv + io = &c->recv; + if (io->size - io->len < pkt->pay.len && + !mg_iobuf_resize(io, io->len + pkt->pay.len)) { + mg_error(c, "oom"); + } else { + // Decrypt data directly into c->recv + handle_tls_recv(c, io); + } + } else { + // Plain text connection, data is already in c->recv, trigger + // MG_EV_READ + mg_call(c, MG_EV_READ, &pkt->pay.len); + } + } +} + +static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) { + struct mg_connection *c = getpeer(ifp->mgr, pkt, false); + struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1); +#if 0 + MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len)); +#endif + if (c != NULL && c->is_connecting && pkt->tcp->flags == (TH_SYN | TH_ACK)) { + s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1; + tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0); + c->is_connecting = 0; // Client connected + settmout(c, MIP_TTYPE_KEEPALIVE); + mg_call(c, MG_EV_CONNECT, NULL); // Let user know + } else if (c != NULL && c->is_connecting && pkt->tcp->flags != TH_ACK) { + // mg_hexdump(pkt->raw.buf, pkt->raw.len); + tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); + } else if (c != NULL && pkt->tcp->flags & TH_RST) { + mg_error(c, "peer RST"); // RFC-1122 4.2.2.13 + } else if (c != NULL) { +#if 0 + MG_DEBUG(("%lu %d %M:%hu -> %M:%hu", c->id, (int) pkt->raw.len, + mg_print_ip4, &pkt->ip->src, mg_ntohs(pkt->tcp->sport), + mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->tcp->dport))); + mg_hexdump(pkt->pay.buf, pkt->pay.len); +#endif + s->tmiss = 0; // Reset missed keep-alive counter + if (s->ttype == MIP_TTYPE_KEEPALIVE) // Advance keep-alive timer + settmout(c, + MIP_TTYPE_KEEPALIVE); // unless a former ACK timeout is pending + read_conn(c, pkt); // Override timer with ACK timeout if needed + } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) { + tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); + } else if (pkt->tcp->flags & TH_RST) { + if (c->is_accepted) mg_error(c, "peer RST"); // RFC-1122 4.2.2.13 + // ignore RST if not connected + } else if (pkt->tcp->flags & TH_SYN) { + // Use peer's source port as ISN, in order to recognise the handshake + uint32_t isn = mg_htonl((uint32_t) mg_ntohs(pkt->tcp->sport)); + tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0); + } else if (pkt->tcp->flags & TH_FIN) { + tx_tcp_pkt(ifp, pkt, TH_FIN | TH_ACK, pkt->tcp->ack, NULL, 0); + } else if (mg_htonl(pkt->tcp->ack) == mg_htons(pkt->tcp->sport) + 1U) { + accept_conn(c, pkt); + } else if (!c->is_accepted) { // no peer + tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); + } else { + // MG_VERBOSE(("dropped silently..")); + } +} + +static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) { + if (pkt->ip->frag & IP_MORE_FRAGS_MSK || pkt->ip->frag & IP_FRAG_OFFSET_MSK) { + if (pkt->ip->proto == 17) pkt->udp = (struct udp *) (pkt->ip + 1); + if (pkt->ip->proto == 6) pkt->tcp = (struct tcp *) (pkt->ip + 1); + struct mg_connection *c = getpeer(ifp->mgr, pkt, false); + if (c) mg_error(c, "Received fragmented packet"); + } else if (pkt->ip->proto == 1) { + pkt->icmp = (struct icmp *) (pkt->ip + 1); + if (pkt->pay.len < sizeof(*pkt->icmp)) return; + mkpay(pkt, pkt->icmp + 1); + rx_icmp(ifp, pkt); + } else if (pkt->ip->proto == 17) { + pkt->udp = (struct udp *) (pkt->ip + 1); + if (pkt->pay.len < sizeof(*pkt->udp)) return; + mkpay(pkt, pkt->udp + 1); + MG_VERBOSE(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src, + mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst, + mg_ntohs(pkt->udp->dport), (int) pkt->pay.len)); + if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(68)) { + pkt->dhcp = (struct dhcp *) (pkt->udp + 1); + mkpay(pkt, pkt->dhcp + 1); + rx_dhcp_client(ifp, pkt); + } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67)) { + pkt->dhcp = (struct dhcp *) (pkt->udp + 1); + mkpay(pkt, pkt->dhcp + 1); + rx_dhcp_server(ifp, pkt); + } else { + rx_udp(ifp, pkt); + } + } else if (pkt->ip->proto == 6) { + pkt->tcp = (struct tcp *) (pkt->ip + 1); + if (pkt->pay.len < sizeof(*pkt->tcp)) return; + mkpay(pkt, pkt->tcp + 1); + uint16_t iplen = mg_ntohs(pkt->ip->len); + uint16_t off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U)); + if (iplen >= off) pkt->pay.len = (size_t) (iplen - off); + MG_VERBOSE(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src, + mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst, + mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len)); + rx_tcp(ifp, pkt); + } +} + +static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) { + // MG_DEBUG(("IP %d", (int) len)); + if (pkt->ip6->proto == 1 || pkt->ip6->proto == 58) { + pkt->icmp = (struct icmp *) (pkt->ip6 + 1); + if (pkt->pay.len < sizeof(*pkt->icmp)) return; + mkpay(pkt, pkt->icmp + 1); + rx_icmp(ifp, pkt); + } else if (pkt->ip6->proto == 17) { + pkt->udp = (struct udp *) (pkt->ip6 + 1); + if (pkt->pay.len < sizeof(*pkt->udp)) return; + // MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport), + // mg_htons(udp->dport))); + mkpay(pkt, pkt->udp + 1); + } +} + +static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) { + struct pkt pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.raw.buf = (char *) buf; + pkt.raw.len = len; + pkt.eth = (struct eth *) buf; + // mg_hexdump(buf, len > 16 ? 16: len); + if (pkt.raw.len < sizeof(*pkt.eth)) return; // Truncated - runt? + if (ifp->enable_mac_check && + memcmp(pkt.eth->dst, ifp->mac, sizeof(pkt.eth->dst)) != 0 && + memcmp(pkt.eth->dst, broadcast, sizeof(pkt.eth->dst)) != 0) + return; + if (ifp->enable_crc32_check && len > 4) { + len -= 4; // TODO(scaprile): check on bigendian + uint32_t crc = mg_crc32(0, (const char *) buf, len); + if (memcmp((void *) ((size_t) buf + len), &crc, sizeof(crc))) return; + } + if (pkt.eth->type == mg_htons(0x806)) { + pkt.arp = (struct arp *) (pkt.eth + 1); + if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.raw.len) return; // Truncated + rx_arp(ifp, &pkt); + } else if (pkt.eth->type == mg_htons(0x86dd)) { + pkt.ip6 = (struct ip6 *) (pkt.eth + 1); + if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip6)) return; // Truncated + if ((pkt.ip6->ver >> 4) != 0x6) return; // Not IP + mkpay(&pkt, pkt.ip6 + 1); + rx_ip6(ifp, &pkt); + } else if (pkt.eth->type == mg_htons(0x800)) { + pkt.ip = (struct ip *) (pkt.eth + 1); + if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated + // Truncate frame to what IP header tells us + if ((size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth) < pkt.raw.len) { + pkt.raw.len = (size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth); + } + if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated + if ((pkt.ip->ver >> 4) != 4) return; // Not IP + mkpay(&pkt, pkt.ip + 1); + rx_ip(ifp, &pkt); + } else { + MG_DEBUG(("Unknown eth type %x", mg_htons(pkt.eth->type))); + if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump(buf, len >= 32 ? 32 : len); + } +} + +static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { + struct mg_connection *c; + bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, now); + ifp->now = now; + +#if MG_ENABLE_TCPIP_PRINT_DEBUG_STATS + if (expired_1000ms) { + const char *names[] = {"down", "up", "req", "ready"}; + MG_INFO(("Status: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u", + names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent, + ifp->ndrop, ifp->nerr)); + } +#endif + // Handle physical interface up/down status + if (expired_1000ms && ifp->driver->up) { + bool up = ifp->driver->up(ifp); + bool current = ifp->state != MG_TCPIP_STATE_DOWN; + if (up != current) { + ifp->state = up == false ? MG_TCPIP_STATE_DOWN + : ifp->enable_dhcp_client ? MG_TCPIP_STATE_UP + : MG_TCPIP_STATE_READY; + if (!up && ifp->enable_dhcp_client) ifp->ip = 0; + onstatechange(ifp); + } + if (ifp->state == MG_TCPIP_STATE_DOWN) MG_ERROR(("Network is down")); + } + if (ifp->state == MG_TCPIP_STATE_DOWN) return; + + // DHCP RFC-2131 (4.4) + if (ifp->state == MG_TCPIP_STATE_UP && expired_1000ms) { + tx_dhcp_discover(ifp); // INIT (4.4.1) + } else if (expired_1000ms && ifp->state == MG_TCPIP_STATE_READY && + ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING + if (ifp->now >= ifp->lease_expire) { + ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP + onstatechange(ifp); + } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && + ((ifp->now / 1000) % 60) == 0) { + // hack: 30 min before deadline, try to rebind (4.3.6) every min + tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); + } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) + } + + // Read data from the network + if (ifp->driver->rx != NULL) { // Polling driver. We must call it + size_t len = + ifp->driver->rx(ifp->recv_queue.buf, ifp->recv_queue.size, ifp); + if (len > 0) { + ifp->nrecv++; + mg_tcpip_rx(ifp, ifp->recv_queue.buf, len); + } + } else { // Interrupt-based driver. Fills recv queue itself + char *buf; + size_t len = mg_queue_next(&ifp->recv_queue, &buf); + if (len > 0) { + mg_tcpip_rx(ifp, buf, len); + mg_queue_del(&ifp->recv_queue, len); + } + } + + // Process timeouts + for (c = ifp->mgr->conns; c != NULL; c = c->next) { + if (c->is_udp || c->is_listening || c->is_resolving) continue; + struct connstate *s = (struct connstate *) (c + 1); + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + if (now > s->timer) { + if (s->ttype == MIP_TTYPE_ACK && s->acked != s->ack) { + MG_VERBOSE(("%lu ack %x %x", c->id, s->seq, s->ack)); + tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); + s->acked = s->ack; + } else if (s->ttype == MIP_TTYPE_ARP) { + mg_error(c, "ARP timeout"); + } else if (s->ttype == MIP_TTYPE_SYN) { + mg_error(c, "Connection timeout"); + } else if (s->ttype == MIP_TTYPE_FIN) { + c->is_closing = 1; + continue; + } else { + if (s->tmiss++ > 2) { + mg_error(c, "keepalive"); + } else { + MG_VERBOSE(("%lu keepalive", c->id)); + tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq - 1), mg_htonl(s->ack), NULL, 0); + } + } + + settmout(c, MIP_TTYPE_KEEPALIVE); + } + } +} + +// This function executes in interrupt context, thus it should copy data +// somewhere fast. Note that newlib's malloc is not thread safe, thus use +// our lock-free queue with preallocated buffer to copy data and return asap +void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp) { + char *p; + if (mg_queue_book(&ifp->recv_queue, &p, len) >= len) { + memcpy(p, buf, len); + mg_queue_add(&ifp->recv_queue, len); + ifp->nrecv++; + } else { + ifp->ndrop++; + } +} + +void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) { + // If MAC address is not set, make a random one + if (ifp->mac[0] == 0 && ifp->mac[1] == 0 && ifp->mac[2] == 0 && + ifp->mac[3] == 0 && ifp->mac[4] == 0 && ifp->mac[5] == 0) { + ifp->mac[0] = 0x02; // Locally administered, unicast + mg_random(&ifp->mac[1], sizeof(ifp->mac) - 1); + MG_INFO(("MAC not set. Generated random: %M", mg_print_mac, ifp->mac)); + } + + if (ifp->driver->init && !ifp->driver->init(ifp)) { + MG_ERROR(("driver init failed")); + } else { + size_t framesize = 1540; + ifp->tx.buf = (char *) calloc(1, framesize), ifp->tx.len = framesize; + if (ifp->recv_queue.size == 0) + ifp->recv_queue.size = ifp->driver->rx ? framesize : 8192; + ifp->recv_queue.buf = (char *) calloc(1, ifp->recv_queue.size); + ifp->timer_1000ms = mg_millis(); + mgr->priv = ifp; + ifp->mgr = mgr; + ifp->mtu = MG_TCPIP_MTU_DEFAULT; + mgr->extraconnsize = sizeof(struct connstate); + if (ifp->ip == 0) ifp->enable_dhcp_client = true; + memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set to broadcast + mg_random(&ifp->eport, sizeof(ifp->eport)); // Random from 0 to 65535 + ifp->eport |= MG_EPHEMERAL_PORT_BASE; // Random from + // MG_EPHEMERAL_PORT_BASE to 65535 + if (ifp->tx.buf == NULL || ifp->recv_queue.buf == NULL) MG_ERROR(("OOM")); + } +} + +void mg_tcpip_free(struct mg_tcpip_if *ifp) { + free(ifp->recv_queue.buf); + free(ifp->tx.buf); +} + +static void send_syn(struct mg_connection *c) { + struct connstate *s = (struct connstate *) (c + 1); + uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port)); + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + tx_tcp(ifp, s->mac, rem_ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL, + 0); +} + +void mg_connect_resolved(struct mg_connection *c) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + c->is_resolving = 0; + if (ifp->eport < MG_EPHEMERAL_PORT_BASE) ifp->eport = MG_EPHEMERAL_PORT_BASE; + memcpy(c->loc.ip, &ifp->ip, sizeof(uint32_t)); + c->loc.port = mg_htons(ifp->eport++); + MG_DEBUG(("%lu %M -> %M", c->id, mg_print_ip_port, &c->loc, mg_print_ip_port, + &c->rem)); + mg_call(c, MG_EV_RESOLVE, NULL); + if (c->is_udp && (rem_ip == 0xffffffff || rem_ip == (ifp->ip | ~ifp->mask))) { + struct connstate *s = (struct connstate *) (c + 1); + memset(s->mac, 0xFF, sizeof(s->mac)); // global or local broadcast + } else if (ifp->ip && ((rem_ip & ifp->mask) == (ifp->ip & ifp->mask))) { + // If we're in the same LAN, fire an ARP lookup. + MG_DEBUG(("%lu ARP lookup...", c->id)); + arp_ask(ifp, rem_ip); + settmout(c, MIP_TTYPE_ARP); + c->is_arplooking = 1; + c->is_connecting = 1; + } else if ((*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) { + struct connstate *s = (struct connstate *) (c + 1); // 224 to 239, E0 to EF + uint8_t mcastp[3] = {0x01, 0x00, 0x5E}; // multicast group + memcpy(s->mac, mcastp, 3); + memcpy(s->mac + 3, ((uint8_t *) &rem_ip) + 1, 3); // 23 LSb + s->mac[3] &= 0x7F; + } else { + struct connstate *s = (struct connstate *) (c + 1); + memcpy(s->mac, ifp->gwmac, sizeof(ifp->gwmac)); + if (c->is_udp) { + mg_call(c, MG_EV_CONNECT, NULL); + } else { + send_syn(c); + settmout(c, MIP_TTYPE_SYN); + c->is_connecting = 1; + } + } +} + +bool mg_open_listener(struct mg_connection *c, const char *url) { + c->loc.port = mg_htons(mg_url_port(url)); + return true; +} + +static void write_conn(struct mg_connection *c) { + long len = c->is_tls ? mg_tls_send(c, c->send.buf, c->send.len) + : mg_io_send(c, c->send.buf, c->send.len); + if (len == MG_IO_ERR) { + mg_error(c, "tx err"); + } else if (len > 0) { + mg_iobuf_del(&c->send, 0, (size_t) len); + mg_call(c, MG_EV_WRITE, &len); + } +} + +static void init_closure(struct mg_connection *c) { + struct connstate *s = (struct connstate *) (c + 1); + if (c->is_udp == false && c->is_listening == false && + c->is_connecting == false) { // For TCP conns, + struct mg_tcpip_if *ifp = + (struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + tx_tcp(ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); + settmout(c, MIP_TTYPE_FIN); + } +} + +static void close_conn(struct mg_connection *c) { + struct connstate *s = (struct connstate *) (c + 1); + mg_iobuf_free(&s->raw); // For TLS connections, release raw data + mg_close_conn(c); +} + +static bool can_write(struct mg_connection *c) { + return c->is_connecting == 0 && c->is_resolving == 0 && c->send.len > 0 && + c->is_tls_hs == 0 && c->is_arplooking == 0; +} + +void mg_mgr_poll(struct mg_mgr *mgr, int ms) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) mgr->priv; + struct mg_connection *c, *tmp; + uint64_t now = mg_millis(); + mg_timer_poll(&mgr->timers, now); + if (ifp == NULL || ifp->driver == NULL) return; + mg_tcpip_poll(ifp, now); + for (c = mgr->conns; c != NULL; c = tmp) { + tmp = c->next; + struct connstate *s = (struct connstate *) (c + 1); + mg_call(c, MG_EV_POLL, &now); + MG_VERBOSE(("%lu .. %c%c%c%c%c", c->id, c->is_tls ? 'T' : 't', + c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h', + c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c')); + if (c->is_tls && mg_tls_pending(c) > 0) + handle_tls_recv(c, (struct mg_iobuf *) &c->rtls); + if (can_write(c)) write_conn(c); + if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN) + init_closure(c); + if (c->is_closing) close_conn(c); + } + (void) ms; +} + +bool mg_send(struct mg_connection *c, const void *buf, size_t len) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + bool res = false; + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + if (ifp->ip == 0 || ifp->state != MG_TCPIP_STATE_READY) { + mg_error(c, "net down"); + } else if (c->is_udp) { + struct connstate *s = (struct connstate *) (c + 1); + len = trim_len(c, len); // Trimming length if necessary + tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len); + res = true; + } else { + res = mg_iobuf_add(&c->send, c->send.len, buf, len); + } + return res; +} +#endif // MG_ENABLE_TCPIP + +#ifdef MG_ENABLE_LINES +#line 1 "src/ota_dummy.c" +#endif + + + +#if MG_OTA == MG_OTA_NONE +bool mg_ota_begin(size_t new_firmware_size) { + (void) new_firmware_size; + return true; +} +bool mg_ota_write(const void *buf, size_t len) { + (void) buf, (void) len; + return true; +} +bool mg_ota_end(void) { + return true; +} +bool mg_ota_commit(void) { + return true; +} +bool mg_ota_rollback(void) { + return true; +} +int mg_ota_status(int fw) { + (void) fw; + return 0; +} +uint32_t mg_ota_crc32(int fw) { + (void) fw; + return 0; +} +uint32_t mg_ota_timestamp(int fw) { + (void) fw; + return 0; +} +size_t mg_ota_size(int fw) { + (void) fw; + return 0; +} +MG_IRAM void mg_ota_boot(void) { +} +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/ota_esp32.c" +#endif + + +#if MG_ARCH == MG_ARCH_ESP32 && MG_OTA == MG_OTA_ESP32 + +static const esp_partition_t *s_ota_update_partition; +static esp_ota_handle_t s_ota_update_handle; +static bool s_ota_success; + +// Those empty macros do nothing, but mark places in the code which could +// potentially trigger a watchdog reboot due to the log flash erase operation +#define disable_wdt() +#define enable_wdt() + +bool mg_ota_begin(size_t new_firmware_size) { + if (s_ota_update_partition != NULL) { + MG_ERROR(("Update in progress. Call mg_ota_end() ?")); + return false; + } else { + s_ota_success = false; + disable_wdt(); + s_ota_update_partition = esp_ota_get_next_update_partition(NULL); + esp_err_t err = esp_ota_begin(s_ota_update_partition, new_firmware_size, + &s_ota_update_handle); + enable_wdt(); + MG_DEBUG(("esp_ota_begin(): %d", err)); + s_ota_success = (err == ESP_OK); + } + return s_ota_success; +} + +bool mg_ota_write(const void *buf, size_t len) { + disable_wdt(); + esp_err_t err = esp_ota_write(s_ota_update_handle, buf, len); + enable_wdt(); + MG_INFO(("esp_ota_write(): %d", err)); + s_ota_success = err == ESP_OK; + return s_ota_success; +} + +bool mg_ota_end(void) { + esp_err_t err = esp_ota_end(s_ota_update_handle); + MG_DEBUG(("esp_ota_end(%p): %d", s_ota_update_handle, err)); + if (s_ota_success && err == ESP_OK) { + err = esp_ota_set_boot_partition(s_ota_update_partition); + s_ota_success = (err == ESP_OK); + } + MG_DEBUG(("Finished ESP32 OTA, success: %d", s_ota_success)); + s_ota_update_partition = NULL; + return s_ota_success; +} + +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/ota_flash.c" +#endif + + + + + +// This OTA implementation uses the internal flash API outlined in device.h +// It splits flash into 2 equal partitions, and stores OTA status in the +// last sector of the partition. + +#if MG_OTA == MG_OTA_FLASH + +#define MG_OTADATA_KEY 0xb07afed0 + +static char *s_addr; // Current address to write to +static size_t s_size; // Firmware size to flash. In-progress indicator +static uint32_t s_crc32; // Firmware checksum + +struct mg_otadata { + uint32_t crc32, size, timestamp, status; +}; + +bool mg_ota_begin(size_t new_firmware_size) { + bool ok = false; + if (s_size) { + MG_ERROR(("OTA already in progress. Call mg_ota_end()")); + } else { + size_t half = mg_flash_size() / 2, max = half - mg_flash_sector_size(); + s_crc32 = 0; + s_addr = (char *) mg_flash_start() + half; + MG_DEBUG(("Firmware %lu bytes, max %lu", new_firmware_size, max)); + if (new_firmware_size < max) { + ok = true; + s_size = new_firmware_size; + MG_INFO(("Starting OTA, firmware size %lu", s_size)); + } else { + MG_ERROR(("Firmware %lu is too big to fit %lu", new_firmware_size, max)); + } + } + return ok; +} + +bool mg_ota_write(const void *buf, size_t len) { + bool ok = false; + if (s_size == 0) { + MG_ERROR(("OTA is not started, call mg_ota_begin()")); + } else { + size_t align = mg_flash_write_align(); + size_t len_aligned_down = MG_ROUND_DOWN(len, align); + if (len_aligned_down) ok = mg_flash_write(s_addr, buf, len_aligned_down); + if (len_aligned_down < len) { + size_t left = len - len_aligned_down; + char tmp[align]; + memset(tmp, 0xff, sizeof(tmp)); + memcpy(tmp, (char *) buf + len_aligned_down, left); + ok = mg_flash_write(s_addr + len_aligned_down, tmp, sizeof(tmp)); + } + s_crc32 = mg_crc32(s_crc32, (char *) buf, len); // Update CRC + MG_DEBUG(("%#x %p %lu -> %d", s_addr - len, buf, len, ok)); + s_addr += len; + } + return ok; +} + +MG_IRAM static uint32_t mg_fwkey(int fw) { + uint32_t key = MG_OTADATA_KEY + fw; + int bank = mg_flash_bank(); + if (bank == 2 && fw == MG_FIRMWARE_PREVIOUS) key--; + if (bank == 2 && fw == MG_FIRMWARE_CURRENT) key++; + return key; +} + +bool mg_ota_end(void) { + char *base = (char *) mg_flash_start() + mg_flash_size() / 2; + bool ok = false; + if (s_size) { + size_t size = s_addr - base; + uint32_t crc32 = mg_crc32(0, base, s_size); + if (size == s_size && crc32 == s_crc32) { + uint32_t now = (uint32_t) (mg_now() / 1000); + struct mg_otadata od = {crc32, size, now, MG_OTA_FIRST_BOOT}; + uint32_t key = mg_fwkey(MG_FIRMWARE_PREVIOUS); + ok = mg_flash_save(NULL, key, &od, sizeof(od)); + } + MG_DEBUG(("CRC: %x/%x, size: %lu/%lu, status: %s", s_crc32, crc32, s_size, + size, ok ? "ok" : "fail")); + s_size = 0; + if (ok) ok = mg_flash_swap_bank(); + } + MG_INFO(("Finishing OTA: %s", ok ? "ok" : "fail")); + return ok; +} + +MG_IRAM static struct mg_otadata mg_otadata(int fw) { + uint32_t key = mg_fwkey(fw); + struct mg_otadata od = {}; + MG_INFO(("Loading %s OTA data", fw == MG_FIRMWARE_CURRENT ? "curr" : "prev")); + mg_flash_load(NULL, key, &od, sizeof(od)); + // MG_DEBUG(("Loaded OTA data. fw %d, bank %d, key %p", fw, bank, key)); + // mg_hexdump(&od, sizeof(od)); + return od; +} + +int mg_ota_status(int fw) { + struct mg_otadata od = mg_otadata(fw); + return od.status; +} +uint32_t mg_ota_crc32(int fw) { + struct mg_otadata od = mg_otadata(fw); + return od.crc32; +} +uint32_t mg_ota_timestamp(int fw) { + struct mg_otadata od = mg_otadata(fw); + return od.timestamp; +} +size_t mg_ota_size(int fw) { + struct mg_otadata od = mg_otadata(fw); + return od.size; +} + +MG_IRAM bool mg_ota_commit(void) { + bool ok = true; + struct mg_otadata od = mg_otadata(MG_FIRMWARE_CURRENT); + if (od.status != MG_OTA_COMMITTED) { + od.status = MG_OTA_COMMITTED; + MG_INFO(("Committing current firmware, OD size %lu", sizeof(od))); + ok = mg_flash_save(NULL, mg_fwkey(MG_FIRMWARE_CURRENT), &od, sizeof(od)); + } + return ok; +} + +bool mg_ota_rollback(void) { + MG_DEBUG(("Rolling firmware back")); + if (mg_flash_bank() == 0) { + // No dual bank support. Mark previous firmware as FIRST_BOOT + struct mg_otadata prev = mg_otadata(MG_FIRMWARE_PREVIOUS); + prev.status = MG_OTA_FIRST_BOOT; + return mg_flash_save(NULL, MG_OTADATA_KEY + MG_FIRMWARE_PREVIOUS, &prev, + sizeof(prev)); + } else { + return mg_flash_swap_bank(); + } +} + +MG_IRAM void mg_ota_boot(void) { + MG_INFO(("Booting. Flash bank: %d", mg_flash_bank())); + struct mg_otadata curr = mg_otadata(MG_FIRMWARE_CURRENT); + struct mg_otadata prev = mg_otadata(MG_FIRMWARE_PREVIOUS); + + if (curr.status == MG_OTA_FIRST_BOOT) { + if (prev.status == MG_OTA_UNAVAILABLE) { + MG_INFO(("Setting previous firmware state to committed")); + prev.status = MG_OTA_COMMITTED; + mg_flash_save(NULL, mg_fwkey(MG_FIRMWARE_PREVIOUS), &prev, sizeof(prev)); + } + curr.status = MG_OTA_UNCOMMITTED; + MG_INFO(("First boot, setting status to UNCOMMITTED")); + mg_flash_save(NULL, mg_fwkey(MG_FIRMWARE_CURRENT), &curr, sizeof(curr)); + } else if (prev.status == MG_OTA_FIRST_BOOT && mg_flash_bank() == 0) { + // Swap paritions. Pray power does not disappear + size_t fs = mg_flash_size(), ss = mg_flash_sector_size(); + char *partition1 = mg_flash_start(); + char *partition2 = mg_flash_start() + fs / 2; + size_t ofs, max = fs / 2 - ss; // Set swap size to the whole partition + + if (curr.status != MG_OTA_UNAVAILABLE && + prev.status != MG_OTA_UNAVAILABLE) { + // We know exact sizes of both firmwares. + // Shrink swap size to the MAX(firmware1, firmware2) + size_t sz = curr.size > prev.size ? curr.size : prev.size; + if (sz > 0 && sz < max) max = sz; + } + + // MG_OTA_FIRST_BOOT -> MG_OTA_UNCOMMITTED + prev.status = MG_OTA_UNCOMMITTED; + mg_flash_save(NULL, MG_OTADATA_KEY + MG_FIRMWARE_CURRENT, &prev, + sizeof(prev)); + mg_flash_save(NULL, MG_OTADATA_KEY + MG_FIRMWARE_PREVIOUS, &curr, + sizeof(curr)); + + MG_INFO(("Swapping partitions, size %u (%u sectors)", max, max / ss)); + MG_INFO(("Do NOT power off...")); + mg_log_level = MG_LL_NONE; + + // We use the last sector of partition2 for OTA data/config storage + // Therefore we can use last sector of partition1 for swapping + char *tmpsector = partition1 + fs / 2 - ss; // Last sector of partition1 + (void) tmpsector; + for (ofs = 0; ofs < max; ofs += ss) { + // mg_flash_erase(tmpsector); + mg_flash_write(tmpsector, partition1 + ofs, ss); + // mg_flash_erase(partition1 + ofs); + mg_flash_write(partition1 + ofs, partition2 + ofs, ss); + // mg_flash_erase(partition2 + ofs); + mg_flash_write(partition2 + ofs, tmpsector, ss); + } + mg_device_reset(); + } +} +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/printf.c" +#endif + + + + +size_t mg_queue_vprintf(struct mg_queue *q, const char *fmt, va_list *ap) { + size_t len = mg_snprintf(NULL, 0, fmt, ap); + char *buf; + if (len == 0 || mg_queue_book(q, &buf, len + 1) < len + 1) { + len = 0; // Nah. Not enough space + } else { + len = mg_vsnprintf((char *) buf, len + 1, fmt, ap); + mg_queue_add(q, len); + } + return len; +} + +size_t mg_queue_printf(struct mg_queue *q, const char *fmt, ...) { + va_list ap; + size_t len; + va_start(ap, fmt); + len = mg_queue_vprintf(q, fmt, &ap); + va_end(ap); + return len; +} + +static void mg_pfn_iobuf_private(char ch, void *param, bool expand) { + struct mg_iobuf *io = (struct mg_iobuf *) param; + if (expand && io->len + 2 > io->size) mg_iobuf_resize(io, io->len + 2); + if (io->len + 2 <= io->size) { + io->buf[io->len++] = (uint8_t) ch; + io->buf[io->len] = 0; + } else if (io->len < io->size) { + io->buf[io->len++] = 0; // Guarantee to 0-terminate + } +} + +static void mg_putchar_iobuf_static(char ch, void *param) { + mg_pfn_iobuf_private(ch, param, false); +} + +void mg_pfn_iobuf(char ch, void *param) { + mg_pfn_iobuf_private(ch, param, true); +} + +size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap) { + struct mg_iobuf io = {(uint8_t *) buf, len, 0, 0}; + size_t n = mg_vxprintf(mg_putchar_iobuf_static, &io, fmt, ap); + if (n < len) buf[n] = '\0'; + return n; +} + +size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) { + va_list ap; + size_t n; + va_start(ap, fmt); + n = mg_vsnprintf(buf, len, fmt, &ap); + va_end(ap); + return n; +} + +char *mg_vmprintf(const char *fmt, va_list *ap) { + struct mg_iobuf io = {0, 0, 0, 256}; + mg_vxprintf(mg_pfn_iobuf, &io, fmt, ap); + return (char *) io.buf; +} + +char *mg_mprintf(const char *fmt, ...) { + char *s; + va_list ap; + va_start(ap, fmt); + s = mg_vmprintf(fmt, &ap); + va_end(ap); + return s; +} + +void mg_pfn_stdout(char c, void *param) { + putchar(c); + (void) param; +} + +static size_t print_ip4(void (*out)(char, void *), void *arg, uint8_t *p) { + return mg_xprintf(out, arg, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); +} + +static size_t print_ip6(void (*out)(char, void *), void *arg, uint16_t *p) { + return mg_xprintf(out, arg, "[%x:%x:%x:%x:%x:%x:%x:%x]", mg_ntohs(p[0]), + mg_ntohs(p[1]), mg_ntohs(p[2]), mg_ntohs(p[3]), + mg_ntohs(p[4]), mg_ntohs(p[5]), mg_ntohs(p[6]), + mg_ntohs(p[7])); +} + +size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap) { + uint8_t *p = va_arg(*ap, uint8_t *); + return print_ip4(out, arg, p); +} + +size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap) { + uint16_t *p = va_arg(*ap, uint16_t *); + return print_ip6(out, arg, p); +} + +size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) { + struct mg_addr *addr = va_arg(*ap, struct mg_addr *); + if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip); + return print_ip4(out, arg, (uint8_t *) &addr->ip); +} + +size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) { + struct mg_addr *a = va_arg(*ap, struct mg_addr *); + return mg_xprintf(out, arg, "%M:%hu", mg_print_ip, a, mg_ntohs(a->port)); +} + +size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap) { + uint8_t *p = va_arg(*ap, uint8_t *); + return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2], + p[3], p[4], p[5]); +} + +static char mg_esc(int c, bool esc) { + const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\""; + for (p = esc ? esc1 : esc2; *p != '\0'; p++) { + if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2]; + } + return 0; +} + +static char mg_escape(int c) { + return mg_esc(c, true); +} + +static size_t qcpy(void (*out)(char, void *), void *ptr, char *buf, + size_t len) { + size_t i = 0, extra = 0; + for (i = 0; i < len && buf[i] != '\0'; i++) { + char c = mg_escape(buf[i]); + if (c) { + out('\\', ptr), out(c, ptr), extra++; + } else { + out(buf[i], ptr); + } + } + return i + extra; +} + +static size_t bcpy(void (*out)(char, void *), void *arg, uint8_t *buf, + size_t len) { + size_t i, j, n = 0; + const char *t = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + for (i = 0; i < len; i += 3) { + uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0, + c3 = i + 2 < len ? buf[i + 2] : 0; + char tmp[4] = {t[c1 >> 2], t[(c1 & 3) << 4 | (c2 >> 4)], '=', '='}; + if (i + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)]; + if (i + 2 < len) tmp[3] = t[c3 & 63]; + for (j = 0; j < sizeof(tmp) && tmp[j] != '\0'; j++) out(tmp[j], arg); + n += j; + } + return n; +} + +size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap) { + size_t bl = (size_t) va_arg(*ap, int); + uint8_t *p = va_arg(*ap, uint8_t *); + const char *hex = "0123456789abcdef"; + size_t j; + for (j = 0; j < bl; j++) { + out(hex[(p[j] >> 4) & 0x0F], arg); + out(hex[p[j] & 0x0F], arg); + } + return 2 * bl; +} +size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap) { + size_t len = (size_t) va_arg(*ap, int); + uint8_t *buf = va_arg(*ap, uint8_t *); + return bcpy(out, arg, buf, len); +} + +size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap) { + size_t len = (size_t) va_arg(*ap, int); + char *p = va_arg(*ap, char *); + if (len == 0) len = p == NULL ? 0 : strlen(p); + return qcpy(out, arg, p, len); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/queue.c" +#endif + + + +#if (defined(__GNUC__) && (__GNUC__ > 4) || \ + (defined(__GNUC_MINOR__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ + defined(__clang__) +#define MG_MEMORY_BARRIER() __sync_synchronize() +#elif defined(_MSC_VER) && _MSC_VER >= 1700 +#define MG_MEMORY_BARRIER() MemoryBarrier() +#elif !defined(MG_MEMORY_BARRIER) +#define MG_MEMORY_BARRIER() +#endif + +// Every message in a queue is prepended by a 32-bit message length (ML). +// If ML is 0, then it is the end, and reader must wrap to the beginning. +// +// Queue when q->tail <= q->head: +// |----- free -----| ML | message1 | ML | message2 | ----- free ------| +// ^ ^ ^ ^ +// buf tail head len +// +// Queue when q->tail > q->head: +// | ML | message2 |----- free ------| ML | message1 | 0 |---- free ----| +// ^ ^ ^ ^ +// buf head tail len + +void mg_queue_init(struct mg_queue *q, char *buf, size_t size) { + q->size = size; + q->buf = buf; + q->head = q->tail = 0; +} + +static size_t mg_queue_read_len(struct mg_queue *q) { + uint32_t n = 0; + MG_MEMORY_BARRIER(); + memcpy(&n, q->buf + q->tail, sizeof(n)); + assert(q->tail + n + sizeof(n) <= q->size); + return n; +} + +static void mg_queue_write_len(struct mg_queue *q, size_t len) { + uint32_t n = (uint32_t) len; + memcpy(q->buf + q->head, &n, sizeof(n)); + MG_MEMORY_BARRIER(); +} + +size_t mg_queue_book(struct mg_queue *q, char **buf, size_t len) { + size_t space = 0, hs = sizeof(uint32_t) * 2; // *2 is for the 0 marker + if (q->head >= q->tail && q->head + len + hs <= q->size) { + space = q->size - q->head - hs; // There is enough space + } else if (q->head >= q->tail && q->tail > hs) { + mg_queue_write_len(q, 0); // Not enough space ahead + q->head = 0; // Wrap head to the beginning + } + if (q->head + hs + len < q->tail) space = q->tail - q->head - hs; + if (buf != NULL) *buf = q->buf + q->head + sizeof(uint32_t); + return space; +} + +size_t mg_queue_next(struct mg_queue *q, char **buf) { + size_t len = 0; + if (q->tail != q->head) { + len = mg_queue_read_len(q); + if (len == 0) { // Zero (head wrapped) ? + q->tail = 0; // Reset tail to the start + if (q->head > q->tail) len = mg_queue_read_len(q); // Read again + } + } + if (buf != NULL) *buf = q->buf + q->tail + sizeof(uint32_t); + assert(q->tail + len <= q->size); + return len; +} + +void mg_queue_add(struct mg_queue *q, size_t len) { + assert(len > 0); + mg_queue_write_len(q, len); + assert(q->head + sizeof(uint32_t) * 2 + len <= q->size); + q->head += len + sizeof(uint32_t); +} + +void mg_queue_del(struct mg_queue *q, size_t len) { + q->tail += len + sizeof(uint32_t); + assert(q->tail + sizeof(uint32_t) <= q->size); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/rpc.c" +#endif + + + +void mg_rpc_add(struct mg_rpc **head, struct mg_str method, + void (*fn)(struct mg_rpc_req *), void *fn_data) { + struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc)); + if (rpc != NULL) { + rpc->method.buf = mg_mprintf("%.*s", method.len, method.buf); + rpc->method.len = method.len; + rpc->fn = fn; + rpc->fn_data = fn_data; + rpc->next = *head, *head = rpc; + } +} + +void mg_rpc_del(struct mg_rpc **head, void (*fn)(struct mg_rpc_req *)) { + struct mg_rpc *r; + while ((r = *head) != NULL) { + if (r->fn == fn || fn == NULL) { + *head = r->next; + free((void *) r->method.buf); + free(r); + } else { + head = &(*head)->next; + } + } +} + +static void mg_rpc_call(struct mg_rpc_req *r, struct mg_str method) { + struct mg_rpc *h = r->head == NULL ? NULL : *r->head; + while (h != NULL && !mg_match(method, h->method, NULL)) h = h->next; + if (h != NULL) { + r->rpc = h; + h->fn(r); + } else { + mg_rpc_err(r, -32601, "\"%.*s not found\"", (int) method.len, method.buf); + } +} + +void mg_rpc_process(struct mg_rpc_req *r) { + int len, off = mg_json_get(r->frame, "$.method", &len); + if (off > 0 && r->frame.buf[off] == '"') { + struct mg_str method = mg_str_n(&r->frame.buf[off + 1], (size_t) len - 2); + mg_rpc_call(r, method); + } else if ((off = mg_json_get(r->frame, "$.result", &len)) > 0 || + (off = mg_json_get(r->frame, "$.error", &len)) > 0) { + mg_rpc_call(r, mg_str("")); // JSON response! call "" method handler + } else { + mg_rpc_err(r, -32700, "%m", mg_print_esc, (int) r->frame.len, + r->frame.buf); // Invalid + } +} + +void mg_rpc_vok(struct mg_rpc_req *r, const char *fmt, va_list *ap) { + int len, off = mg_json_get(r->frame, "$.id", &len); + if (off > 0) { + mg_xprintf(r->pfn, r->pfn_data, "{%m:%.*s,%m:", mg_print_esc, 0, "id", len, + &r->frame.buf[off], mg_print_esc, 0, "result"); + mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap); + mg_xprintf(r->pfn, r->pfn_data, "}"); + } +} + +void mg_rpc_ok(struct mg_rpc_req *r, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + mg_rpc_vok(r, fmt, &ap); + va_end(ap); +} + +void mg_rpc_verr(struct mg_rpc_req *r, int code, const char *fmt, va_list *ap) { + int len, off = mg_json_get(r->frame, "$.id", &len); + mg_xprintf(r->pfn, r->pfn_data, "{"); + if (off > 0) { + mg_xprintf(r->pfn, r->pfn_data, "%m:%.*s,", mg_print_esc, 0, "id", len, + &r->frame.buf[off]); + } + mg_xprintf(r->pfn, r->pfn_data, "%m:{%m:%d,%m:", mg_print_esc, 0, "error", + mg_print_esc, 0, "code", code, mg_print_esc, 0, "message"); + mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap); + mg_xprintf(r->pfn, r->pfn_data, "}}"); +} + +void mg_rpc_err(struct mg_rpc_req *r, int code, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + mg_rpc_verr(r, code, fmt, &ap); + va_end(ap); +} + +static size_t print_methods(mg_pfn_t pfn, void *pfn_data, va_list *ap) { + struct mg_rpc *h, **head = (struct mg_rpc **) va_arg(*ap, void **); + size_t len = 0; + for (h = *head; h != NULL; h = h->next) { + if (h->method.len == 0) continue; // Ignore response handler + len += mg_xprintf(pfn, pfn_data, "%s%m", h == *head ? "" : ",", + mg_print_esc, (int) h->method.len, h->method.buf); + } + return len; +} + +void mg_rpc_list(struct mg_rpc_req *r) { + mg_rpc_ok(r, "[%M]", print_methods, r->head); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/sha1.c" +#endif +/* Copyright(c) By Steve Reid */ +/* 100% Public Domain */ + + + +union char64long16 { + unsigned char c[64]; + uint32_t l[16]; +}; + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +static uint32_t blk0(union char64long16 *block, int i) { + if (MG_BIG_ENDIAN) { + } else { + block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | + (rol(block->l[i], 8) & 0x00FF00FF); + } + return block->l[i]; +} + +/* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */ +#undef blk +#undef R0 +#undef R1 +#undef R2 +#undef R3 +#undef R4 + +#define blk(i) \ + (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \ + block->l[(i + 2) & 15] ^ block->l[i & 15], \ + 1)) +#define R0(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ + w = rol(w, 30); +#define R3(v, w, x, y, z, i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w = rol(w, 30); + +static void mg_sha1_transform(uint32_t state[5], + const unsigned char *buffer) { + uint32_t a, b, c, d, e; + union char64long16 block[1]; + + memcpy(block, buffer, 64); + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Erase working structures. The order of operations is important, + * used to ensure that compiler doesn't optimize those out. */ + memset(block, 0, sizeof(block)); + a = b = c = d = e = 0; + (void) a; + (void) b; + (void) c; + (void) d; + (void) e; +} + +void mg_sha1_init(mg_sha1_ctx *context) { + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + +void mg_sha1_update(mg_sha1_ctx *context, const unsigned char *data, + size_t len) { + size_t i, j; + + j = context->count[0]; + if ((context->count[0] += (uint32_t) len << 3) < j) context->count[1]++; + context->count[1] += (uint32_t) (len >> 29); + j = (j >> 3) & 63; + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64 - j)); + mg_sha1_transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) { + mg_sha1_transform(context->state, &data[i]); + } + j = 0; + } else + i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + +void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *context) { + unsigned i; + unsigned char finalcount[8], c; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> + ((3 - (i & 3)) * 8)) & + 255); + } + c = 0200; + mg_sha1_update(context, &c, 1); + while ((context->count[0] & 504) != 448) { + c = 0000; + mg_sha1_update(context, &c, 1); + } + mg_sha1_update(context, finalcount, 8); + for (i = 0; i < 20; i++) { + digest[i] = + (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + memset(context, '\0', sizeof(*context)); + memset(&finalcount, '\0', sizeof(finalcount)); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/sha256.c" +#endif +// https://github.com/B-Con/crypto-algorithms +// Author: Brad Conte (brad AT bradconte.com) +// Disclaimer: This code is presented "as is" without any guarantees. +// Details: Defines the API for the corresponding SHA1 implementation. +// Copyright: public domain + + + +#define ror(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define ch(x, y, z) (((x) & (y)) ^ (~(x) & (z))) +#define maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define ep0(x) (ror(x, 2) ^ ror(x, 13) ^ ror(x, 22)) +#define ep1(x) (ror(x, 6) ^ ror(x, 11) ^ ror(x, 25)) +#define sig0(x) (ror(x, 7) ^ ror(x, 18) ^ ((x) >> 3)) +#define sig1(x) (ror(x, 17) ^ ror(x, 19) ^ ((x) >> 10)) + +static const uint32_t mg_sha256_k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +void mg_sha256_init(mg_sha256_ctx *ctx) { + ctx->len = 0; + ctx->bits = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +static void mg_sha256_chunk(mg_sha256_ctx *ctx) { + int i, j; + uint32_t a, b, c, d, e, f, g, h; + uint32_t m[64]; + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (uint32_t) (((uint32_t) ctx->buffer[j] << 24) | + ((uint32_t) ctx->buffer[j + 1] << 16) | + ((uint32_t) ctx->buffer[j + 2] << 8) | + ((uint32_t) ctx->buffer[j + 3])); + for (; i < 64; ++i) + m[i] = sig1(m[i - 2]) + m[i - 7] + sig0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + uint32_t t1 = h + ep1(e) + ch(e, f, g) + mg_sha256_k[i] + m[i]; + uint32_t t2 = ep0(a) + maj(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void mg_sha256_update(mg_sha256_ctx *ctx, const unsigned char *data, + size_t len) { + size_t i; + for (i = 0; i < len; i++) { + ctx->buffer[ctx->len] = data[i]; + if ((++ctx->len) == 64) { + mg_sha256_chunk(ctx); + ctx->bits += 512; + ctx->len = 0; + } + } +} + +// TODO: make final reusable (remove side effects) +void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *ctx) { + uint32_t i = ctx->len; + if (i < 56) { + ctx->buffer[i++] = 0x80; + while (i < 56) { + ctx->buffer[i++] = 0x00; + } + } else { + ctx->buffer[i++] = 0x80; + while (i < 64) { + ctx->buffer[i++] = 0x00; + } + mg_sha256_chunk(ctx); + memset(ctx->buffer, 0, 56); + } + + ctx->bits += ctx->len * 8; + ctx->buffer[63] = (uint8_t) ((ctx->bits) & 0xff); + ctx->buffer[62] = (uint8_t) ((ctx->bits >> 8) & 0xff); + ctx->buffer[61] = (uint8_t) ((ctx->bits >> 16) & 0xff); + ctx->buffer[60] = (uint8_t) ((ctx->bits >> 24) & 0xff); + ctx->buffer[59] = (uint8_t) ((ctx->bits >> 32) & 0xff); + ctx->buffer[58] = (uint8_t) ((ctx->bits >> 40) & 0xff); + ctx->buffer[57] = (uint8_t) ((ctx->bits >> 48) & 0xff); + ctx->buffer[56] = (uint8_t) ((ctx->bits >> 56) & 0xff); + mg_sha256_chunk(ctx); + + for (i = 0; i < 4; ++i) { + digest[i] = (uint8_t) ((ctx->state[0] >> (24 - i * 8)) & 0xff); + digest[i + 4] = (uint8_t) ((ctx->state[1] >> (24 - i * 8)) & 0xff); + digest[i + 8] = (uint8_t) ((ctx->state[2] >> (24 - i * 8)) & 0xff); + digest[i + 12] = (uint8_t) ((ctx->state[3] >> (24 - i * 8)) & 0xff); + digest[i + 16] = (uint8_t) ((ctx->state[4] >> (24 - i * 8)) & 0xff); + digest[i + 20] = (uint8_t) ((ctx->state[5] >> (24 - i * 8)) & 0xff); + digest[i + 24] = (uint8_t) ((ctx->state[6] >> (24 - i * 8)) & 0xff); + digest[i + 28] = (uint8_t) ((ctx->state[7] >> (24 - i * 8)) & 0xff); + } +} + +void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, + size_t datasz) { + mg_sha256_ctx ctx; + uint8_t k[64] = {0}; + uint8_t o_pad[64], i_pad[64]; + unsigned int i; + memset(i_pad, 0x36, sizeof(i_pad)); + memset(o_pad, 0x5c, sizeof(o_pad)); + if (keysz < 64) { + if (keysz > 0) memmove(k, key, keysz); + } else { + mg_sha256_init(&ctx); + mg_sha256_update(&ctx, key, keysz); + mg_sha256_final(k, &ctx); + } + for (i = 0; i < sizeof(k); i++) { + i_pad[i] ^= k[i]; + o_pad[i] ^= k[i]; + } + mg_sha256_init(&ctx); + mg_sha256_update(&ctx, i_pad, sizeof(i_pad)); + mg_sha256_update(&ctx, data, datasz); + mg_sha256_final(dst, &ctx); + mg_sha256_init(&ctx); + mg_sha256_update(&ctx, o_pad, sizeof(o_pad)); + mg_sha256_update(&ctx, dst, 32); + mg_sha256_final(dst, &ctx); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/sntp.c" +#endif + + + + + + +#define SNTP_TIME_OFFSET 2208988800U // (1970 - 1900) in seconds +#define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1 + +static int64_t gettimestamp(const uint32_t *data) { + uint32_t sec = mg_ntohl(data[0]), frac = mg_ntohl(data[1]); + if (sec) sec -= SNTP_TIME_OFFSET; + return ((int64_t) sec) * 1000 + (int64_t) (frac / SNTP_MAX_FRAC * 1000.0); +} + +int64_t mg_sntp_parse(const unsigned char *buf, size_t len) { + int64_t res = -1; + int mode = len > 0 ? buf[0] & 7 : 0; + int version = len > 0 ? (buf[0] >> 3) & 7 : 0; + if (len < 48) { + MG_ERROR(("%s", "corrupt packet")); + } else if (mode != 4 && mode != 5) { + MG_ERROR(("%s", "not a server reply")); + } else if (buf[1] == 0) { + MG_ERROR(("%s", "server sent a kiss of death")); + } else if (version == 4 || version == 3) { + // int64_t ref = gettimestamp((uint32_t *) &buf[16]); + int64_t t0 = gettimestamp((uint32_t *) &buf[24]); + int64_t t1 = gettimestamp((uint32_t *) &buf[32]); + int64_t t2 = gettimestamp((uint32_t *) &buf[40]); + int64_t t3 = (int64_t) mg_millis(); + int64_t delta = (t3 - t0) - (t2 - t1); + MG_VERBOSE(("%lld %lld %lld %lld delta:%lld", t0, t1, t2, t3, delta)); + res = t2 + delta / 2; + } else { + MG_ERROR(("unexpected version: %d", version)); + } + return res; +} + +static void sntp_cb(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_READ) { + int64_t milliseconds = mg_sntp_parse(c->recv.buf, c->recv.len); + if (milliseconds > 0) { + MG_DEBUG(("%lu got time: %lld ms from epoch", c->id, milliseconds)); + mg_call(c, MG_EV_SNTP_TIME, (uint64_t *) &milliseconds); + MG_VERBOSE(("%u.%u", (unsigned) (milliseconds / 1000), + (unsigned) (milliseconds % 1000))); + } + mg_iobuf_del(&c->recv, 0, c->recv.len); // Free receive buffer + } else if (ev == MG_EV_CONNECT) { + mg_sntp_request(c); + } else if (ev == MG_EV_CLOSE) { + } + (void) ev_data; +} + +void mg_sntp_request(struct mg_connection *c) { + if (c->is_resolving) { + MG_ERROR(("%lu wait until resolved", c->id)); + } else { + int64_t now = (int64_t) mg_millis(); // Use int64_t, for vc98 + uint8_t buf[48] = {0}; + uint32_t *t = (uint32_t *) &buf[40]; + double frac = ((double) (now % 1000)) / 1000.0 * SNTP_MAX_FRAC; + buf[0] = (0 << 6) | (4 << 3) | 3; + t[0] = mg_htonl((uint32_t) (now / 1000) + SNTP_TIME_OFFSET); + t[1] = mg_htonl((uint32_t) frac); + mg_send(c, buf, sizeof(buf)); + } +} + +struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fnd) { + struct mg_connection *c = NULL; + if (url == NULL) url = "udp://time.google.com:123"; + if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) c->pfn = sntp_cb; + return c; +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/sock.c" +#endif + + + + + + + + + + + +#if MG_ENABLE_SOCKET + +#ifndef closesocket +#define closesocket(x) close(x) +#endif + +#define FD(c_) ((MG_SOCKET_TYPE) (size_t) (c_)->fd) +#define S2PTR(s_) ((void *) (size_t) (s_)) + +#ifndef MSG_NONBLOCKING +#define MSG_NONBLOCKING 0 +#endif + +#ifndef AF_INET6 +#define AF_INET6 10 +#endif + +#ifndef MG_SOCK_ERR +#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? errno : 0) +#endif + +#ifndef MG_SOCK_INTR +#define MG_SOCK_INTR(fd) (fd == MG_INVALID_SOCKET && MG_SOCK_ERR(-1) == EINTR) +#endif + +#ifndef MG_SOCK_PENDING +#define MG_SOCK_PENDING(errcode) \ + (((errcode) < 0) && (errno == EINPROGRESS || errno == EWOULDBLOCK)) +#endif + +#ifndef MG_SOCK_RESET +#define MG_SOCK_RESET(errcode) \ + (((errcode) < 0) && (errno == EPIPE || errno == ECONNRESET)) +#endif + +union usa { + struct sockaddr sa; + struct sockaddr_in sin; +#if MG_ENABLE_IPV6 + struct sockaddr_in6 sin6; +#endif +}; + +static socklen_t tousa(struct mg_addr *a, union usa *usa) { + socklen_t len = sizeof(usa->sin); + memset(usa, 0, sizeof(*usa)); + usa->sin.sin_family = AF_INET; + usa->sin.sin_port = a->port; + memcpy(&usa->sin.sin_addr, a->ip, sizeof(uint32_t)); +#if MG_ENABLE_IPV6 + if (a->is_ip6) { + usa->sin.sin_family = AF_INET6; + usa->sin6.sin6_port = a->port; + usa->sin6.sin6_scope_id = a->scope_id; + memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip)); + len = sizeof(usa->sin6); + } +#endif + return len; +} + +static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) { + a->is_ip6 = is_ip6; + a->port = usa->sin.sin_port; + memcpy(&a->ip, &usa->sin.sin_addr, sizeof(uint32_t)); +#if MG_ENABLE_IPV6 + if (is_ip6) { + memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip)); + a->port = usa->sin6.sin6_port; + a->scope_id = (uint8_t) usa->sin6.sin6_scope_id; + } +#endif +} + +static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) { + union usa usa; + socklen_t n = sizeof(usa); + if (getsockname(fd, &usa.sa, &n) == 0) { + tomgaddr(&usa, addr, n != sizeof(usa.sin)); + } +} + +static void iolog(struct mg_connection *c, char *buf, long n, bool r) { + if (n == MG_IO_WAIT) { + // Do nothing + } else if (n <= 0) { + c->is_closing = 1; // Termination. Don't call mg_error(): #1529 + } else if (n > 0) { + if (c->is_hexdumping) { + MG_INFO(("\n-- %lu %M %s %M %ld", c->id, mg_print_ip_port, &c->loc, + r ? "<-" : "->", mg_print_ip_port, &c->rem, n)); + mg_hexdump(buf, (size_t) n); + } + if (r) { + c->recv.len += (size_t) n; + mg_call(c, MG_EV_READ, &n); + } else { + mg_iobuf_del(&c->send, 0, (size_t) n); + // if (c->send.len == 0) mg_iobuf_resize(&c->send, 0); + if (c->send.len == 0) { + MG_EPOLL_MOD(c, 0); + } + mg_call(c, MG_EV_WRITE, &n); + } + } +} + +long mg_io_send(struct mg_connection *c, const void *buf, size_t len) { + long n; + if (c->is_udp) { + union usa usa; + socklen_t slen = tousa(&c->rem, &usa); + n = sendto(FD(c), (char *) buf, len, 0, &usa.sa, slen); + if (n > 0) setlocaddr(FD(c), &c->loc); + } else { + n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING); + } + MG_VERBOSE(("%lu %ld %d", c->id, n, MG_SOCK_ERR(n))); + if (MG_SOCK_PENDING(n)) return MG_IO_WAIT; + if (MG_SOCK_RESET(n)) return MG_IO_RESET; + if (n <= 0) return MG_IO_ERR; + return n; +} + +bool mg_send(struct mg_connection *c, const void *buf, size_t len) { + if (c->is_udp) { + long n = mg_io_send(c, buf, len); + MG_DEBUG(("%lu %ld %lu:%lu:%lu %ld err %d", c->id, c->fd, c->send.len, + c->recv.len, c->rtls.len, n, MG_SOCK_ERR(n))); + iolog(c, (char *) buf, n, false); + return n > 0; + } else { + return mg_iobuf_add(&c->send, c->send.len, buf, len); + } +} + +static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) { +#if defined(MG_CUSTOM_NONBLOCK) + MG_CUSTOM_NONBLOCK(fd); +#elif MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK + unsigned long on = 1; + ioctlsocket(fd, FIONBIO, &on); +#elif MG_ENABLE_RL + unsigned long on = 1; + ioctlsocket(fd, FIONBIO, &on); +#elif MG_ENABLE_FREERTOS_TCP + const BaseType_t off = 0; + if (setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off)) != 0) (void) 0; + if (setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)) != 0) (void) 0; +#elif MG_ENABLE_LWIP + lwip_fcntl(fd, F_SETFL, O_NONBLOCK); +#elif MG_ARCH == MG_ARCH_AZURERTOS + fcntl(fd, F_SETFL, O_NONBLOCK); +#elif MG_ARCH == MG_ARCH_TIRTOS + int val = 0; + setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val)); + // SPRU524J section 3.3.3 page 63, SO_SNDLOWAT + int sz = sizeof(val); + getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &sz); + val /= 2; // set send low-water mark at half send buffer size + setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &val, sizeof(val)); +#else + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); // Non-blocking mode + fcntl(fd, F_SETFD, FD_CLOEXEC); // Set close-on-exec +#endif +} + +bool mg_open_listener(struct mg_connection *c, const char *url) { + MG_SOCKET_TYPE fd = MG_INVALID_SOCKET; + bool success = false; + c->loc.port = mg_htons(mg_url_port(url)); + if (!mg_aton(mg_url_host(url), &c->loc)) { + MG_ERROR(("invalid listening URL: %s", url)); + } else { + union usa usa; + socklen_t slen = tousa(&c->loc, &usa); + int rc, on = 1, af = c->loc.is_ip6 ? AF_INET6 : AF_INET; + int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM; + int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; + (void) on; + + if ((fd = socket(af, type, proto)) == MG_INVALID_SOCKET) { + MG_ERROR(("socket: %d", MG_SOCK_ERR(-1))); +#if defined(SO_EXCLUSIVEADDRUSE) + } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, + (char *) &on, sizeof(on))) != 0) { + // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" + MG_ERROR(("setsockopt(SO_EXCLUSIVEADDRUSE): %d %d", on, MG_SOCK_ERR(rc))); +#elif defined(SO_REUSEADDR) && (!defined(LWIP_SOCKET) || SO_REUSE) + } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, + sizeof(on))) != 0) { + // 1. SO_REUSEADDR semantics on UNIX and Windows is different. On + // Windows, SO_REUSEADDR allows to bind a socket to a port without error + // even if the port is already open by another program. This is not the + // behavior SO_REUSEADDR was designed for, and leads to hard-to-track + // failure scenarios. + // + // 2. For LWIP, SO_REUSEADDR should be explicitly enabled by defining + // SO_REUSE = 1 in lwipopts.h, otherwise the code below will compile but + // won't work! (setsockopt will return EINVAL) + MG_ERROR(("setsockopt(SO_REUSEADDR): %d", MG_SOCK_ERR(rc))); +#endif +#if MG_IPV6_V6ONLY + // Bind only to the V6 address, not V4 address on this port + } else if (c->loc.is_ip6 && + (rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, + sizeof(on))) != 0) { + // See #2089. Allow to bind v4 and v6 sockets on the same port + MG_ERROR(("setsockopt(IPV6_V6ONLY): %d", MG_SOCK_ERR(rc))); +#endif + } else if ((rc = bind(fd, &usa.sa, slen)) != 0) { + MG_ERROR(("bind: %d", MG_SOCK_ERR(rc))); + } else if ((type == SOCK_STREAM && + (rc = listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE)) != 0)) { + // NOTE(lsm): FreeRTOS uses backlog value as a connection limit + // In case port was set to 0, get the real port number + MG_ERROR(("listen: %d", MG_SOCK_ERR(rc))); + } else { + setlocaddr(fd, &c->loc); + mg_set_non_blocking_mode(fd); + c->fd = S2PTR(fd); + MG_EPOLL_ADD(c); + success = true; + } + } + if (success == false && fd != MG_INVALID_SOCKET) closesocket(fd); + return success; +} + +static long recv_raw(struct mg_connection *c, void *buf, size_t len) { + long n = 0; + if (c->is_udp) { + union usa usa; + socklen_t slen = tousa(&c->rem, &usa); + n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen); + if (n > 0) tomgaddr(&usa, &c->rem, slen != sizeof(usa.sin)); + } else { + n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING); + } + MG_VERBOSE(("%lu %ld %d", c->id, n, MG_SOCK_ERR(n))); + if (MG_SOCK_PENDING(n)) return MG_IO_WAIT; + if (MG_SOCK_RESET(n)) return MG_IO_RESET; + if (n <= 0) return MG_IO_ERR; + return n; +} + +static bool ioalloc(struct mg_connection *c, struct mg_iobuf *io) { + bool res = false; + if (io->len >= MG_MAX_RECV_SIZE) { + mg_error(c, "MG_MAX_RECV_SIZE"); + } else if (io->size <= io->len && + !mg_iobuf_resize(io, io->size + MG_IO_SIZE)) { + mg_error(c, "OOM"); + } else { + res = true; + } + return res; +} + +// NOTE(lsm): do only one iteration of reads, cause some systems +// (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data +static void read_conn(struct mg_connection *c) { + if (ioalloc(c, &c->recv)) { + char *buf = (char *) &c->recv.buf[c->recv.len]; + size_t len = c->recv.size - c->recv.len; + long n = -1; + if (c->is_tls) { + if (!ioalloc(c, &c->rtls)) return; + n = recv_raw(c, (char *) &c->rtls.buf[c->rtls.len], + c->rtls.size - c->rtls.len); + if (n == MG_IO_ERR && c->rtls.len == 0) { + // Close only if we have fully drained both raw (rtls) and TLS buffers + c->is_closing = 1; + } else { + if (n > 0) c->rtls.len += (size_t) n; + if (c->is_tls_hs) mg_tls_handshake(c); + n = c->is_tls_hs ? (long) MG_IO_WAIT : mg_tls_recv(c, buf, len); + } + } else { + n = recv_raw(c, buf, len); + } + MG_DEBUG(("%lu %ld %lu:%lu:%lu %ld err %d", c->id, c->fd, c->send.len, + c->recv.len, c->rtls.len, n, MG_SOCK_ERR(n))); + iolog(c, buf, n, true); + } +} + +static void write_conn(struct mg_connection *c) { + char *buf = (char *) c->send.buf; + size_t len = c->send.len; + long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len); + MG_DEBUG(("%lu %ld snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd, + (long) c->send.len, (long) c->send.size, (long) c->recv.len, + (long) c->recv.size, n, MG_SOCK_ERR(n))); + iolog(c, buf, n, false); +} + +static void close_conn(struct mg_connection *c) { + if (FD(c) != MG_INVALID_SOCKET) { +#if MG_ENABLE_EPOLL + epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_DEL, FD(c), NULL); +#endif + closesocket(FD(c)); +#if MG_ENABLE_FREERTOS_TCP + FreeRTOS_FD_CLR(c->fd, c->mgr->ss, eSELECT_ALL); +#endif + } + mg_close_conn(c); +} + +static void connect_conn(struct mg_connection *c) { + union usa usa; + socklen_t n = sizeof(usa); + // Use getpeername() to test whether we have connected + if (getpeername(FD(c), &usa.sa, &n) == 0) { + c->is_connecting = 0; + setlocaddr(FD(c), &c->loc); + mg_call(c, MG_EV_CONNECT, NULL); + MG_EPOLL_MOD(c, 0); + if (c->is_tls_hs) mg_tls_handshake(c); + } else { + mg_error(c, "socket error"); + } +} + +static void setsockopts(struct mg_connection *c) { +#if MG_ENABLE_FREERTOS_TCP || MG_ARCH == MG_ARCH_AZURERTOS || \ + MG_ARCH == MG_ARCH_TIRTOS + (void) c; +#else + int on = 1; +#if !defined(SOL_TCP) +#define SOL_TCP IPPROTO_TCP +#endif + if (setsockopt(FD(c), SOL_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) != 0) + (void) 0; + if (setsockopt(FD(c), SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) != + 0) + (void) 0; +#endif +} + +void mg_connect_resolved(struct mg_connection *c) { + int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM; + int rc, af = c->rem.is_ip6 ? AF_INET6 : AF_INET; // c->rem has resolved IP + c->fd = S2PTR(socket(af, type, 0)); // Create outbound socket + c->is_resolving = 0; // Clear resolving flag + if (FD(c) == MG_INVALID_SOCKET) { + mg_error(c, "socket(): %d", MG_SOCK_ERR(-1)); + } else if (c->is_udp) { + MG_EPOLL_ADD(c); +#if MG_ARCH == MG_ARCH_TIRTOS + union usa usa; // TI-RTOS NDK requires binding to receive on UDP sockets + socklen_t slen = tousa(&c->loc, &usa); + if ((rc = bind(c->fd, &usa.sa, slen)) != 0) + MG_ERROR(("bind: %d", MG_SOCK_ERR(rc))); +#endif + setlocaddr(FD(c), &c->loc); + mg_call(c, MG_EV_RESOLVE, NULL); + mg_call(c, MG_EV_CONNECT, NULL); + } else { + union usa usa; + socklen_t slen = tousa(&c->rem, &usa); + mg_set_non_blocking_mode(FD(c)); + setsockopts(c); + MG_EPOLL_ADD(c); + mg_call(c, MG_EV_RESOLVE, NULL); + rc = connect(FD(c), &usa.sa, slen); // Attempt to connect + if (rc == 0) { // Success + setlocaddr(FD(c), &c->loc); + mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user + } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake + MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem)); + c->is_connecting = 1; + } else { + mg_error(c, "connect: %d", MG_SOCK_ERR(rc)); + } + } +} + +static MG_SOCKET_TYPE raccept(MG_SOCKET_TYPE sock, union usa *usa, + socklen_t *len) { + MG_SOCKET_TYPE fd = MG_INVALID_SOCKET; + do { + memset(usa, 0, sizeof(*usa)); + fd = accept(sock, &usa->sa, len); + } while (MG_SOCK_INTR(fd)); + return fd; +} + +static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) { + struct mg_connection *c = NULL; + union usa usa; + socklen_t sa_len = sizeof(usa); + MG_SOCKET_TYPE fd = raccept(FD(lsn), &usa, &sa_len); + if (fd == MG_INVALID_SOCKET) { +#if MG_ARCH == MG_ARCH_AZURERTOS || defined(__ECOS) + // AzureRTOS, in non-block socket mode can mark listening socket readable + // even it is not. See comment for 'select' func implementation in + // nx_bsd.c That's not an error, just should try later + if (errno != EAGAIN) +#endif + MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERR(-1))); +#if (MG_ARCH != MG_ARCH_WIN32) && !MG_ENABLE_FREERTOS_TCP && \ + (MG_ARCH != MG_ARCH_TIRTOS) && !MG_ENABLE_POLL && !MG_ENABLE_EPOLL + } else if ((long) fd >= FD_SETSIZE) { + MG_ERROR(("%ld > %ld", (long) fd, (long) FD_SETSIZE)); + closesocket(fd); +#endif + } else if ((c = mg_alloc_conn(mgr)) == NULL) { + MG_ERROR(("%lu OOM", lsn->id)); + closesocket(fd); + } else { + tomgaddr(&usa, &c->rem, sa_len != sizeof(usa.sin)); + LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); + c->fd = S2PTR(fd); + MG_EPOLL_ADD(c); + mg_set_non_blocking_mode(FD(c)); + setsockopts(c); + c->is_accepted = 1; + c->is_hexdumping = lsn->is_hexdumping; + c->loc = lsn->loc; + c->pfn = lsn->pfn; + c->pfn_data = lsn->pfn_data; + c->fn = lsn->fn; + c->fn_data = lsn->fn_data; + MG_DEBUG(("%lu %ld accepted %M -> %M", c->id, c->fd, mg_print_ip_port, + &c->rem, mg_print_ip_port, &c->loc)); + mg_call(c, MG_EV_OPEN, NULL); + mg_call(c, MG_EV_ACCEPT, NULL); + } +} + +static bool can_read(const struct mg_connection *c) { + return c->is_full == false; +} + +static bool can_write(const struct mg_connection *c) { + return c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0); +} + +static bool skip_iotest(const struct mg_connection *c) { + return (c->is_closing || c->is_resolving || FD(c) == MG_INVALID_SOCKET) || + (can_read(c) == false && can_write(c) == false); +} + +static void mg_iotest(struct mg_mgr *mgr, int ms) { +#if MG_ENABLE_FREERTOS_TCP + struct mg_connection *c; + for (c = mgr->conns; c != NULL; c = c->next) { + c->is_readable = c->is_writable = 0; + if (skip_iotest(c)) continue; + if (can_read(c)) + FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_READ | eSELECT_EXCEPT); + if (can_write(c)) FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_WRITE); + if (c->is_closing) ms = 1; + } + FreeRTOS_select(mgr->ss, pdMS_TO_TICKS(ms)); + for (c = mgr->conns; c != NULL; c = c->next) { + EventBits_t bits = FreeRTOS_FD_ISSET(c->fd, mgr->ss); + c->is_readable = bits & (eSELECT_READ | eSELECT_EXCEPT) ? 1U : 0; + c->is_writable = bits & eSELECT_WRITE ? 1U : 0; + if (c->fd != MG_INVALID_SOCKET) + FreeRTOS_FD_CLR(c->fd, mgr->ss, + eSELECT_READ | eSELECT_EXCEPT | eSELECT_WRITE); + } +#elif MG_ENABLE_EPOLL + size_t max = 1; + for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { + c->is_readable = c->is_writable = 0; + if (c->rtls.len > 0 || mg_tls_pending(c) > 0) ms = 1, c->is_readable = 1; + if (can_write(c)) MG_EPOLL_MOD(c, 1); + if (c->is_closing) ms = 1; + max++; + } + struct epoll_event *evs = (struct epoll_event *) alloca(max * sizeof(evs[0])); + int n = epoll_wait(mgr->epoll_fd, evs, (int) max, ms); + for (int i = 0; i < n; i++) { + struct mg_connection *c = (struct mg_connection *) evs[i].data.ptr; + if (evs[i].events & EPOLLERR) { + mg_error(c, "socket error"); + } else if (c->is_readable == 0) { + bool rd = evs[i].events & (EPOLLIN | EPOLLHUP); + bool wr = evs[i].events & EPOLLOUT; + c->is_readable = can_read(c) && rd ? 1U : 0; + c->is_writable = can_write(c) && wr ? 1U : 0; + if (c->rtls.len > 0 || mg_tls_pending(c) > 0) c->is_readable = 1; + } + } + (void) skip_iotest; +#elif MG_ENABLE_POLL + nfds_t n = 0; + for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) n++; + struct pollfd *fds = (struct pollfd *) alloca(n * sizeof(fds[0])); + memset(fds, 0, n * sizeof(fds[0])); + n = 0; + for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { + c->is_readable = c->is_writable = 0; + if (skip_iotest(c)) { + // Socket not valid, ignore + } else if (c->rtls.len > 0 || mg_tls_pending(c) > 0) { + ms = 1; // Don't wait if TLS is ready + } else { + fds[n].fd = FD(c); + if (can_read(c)) fds[n].events |= POLLIN; + if (can_write(c)) fds[n].events |= POLLOUT; + if (c->is_closing) ms = 1; + n++; + } + } + + // MG_INFO(("poll n=%d ms=%d", (int) n, ms)); + if (poll(fds, n, ms) < 0) { +#if MG_ARCH == MG_ARCH_WIN32 + if (n == 0) Sleep(ms); // On Windows, poll fails if no sockets +#endif + memset(fds, 0, n * sizeof(fds[0])); + } + n = 0; + for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { + if (skip_iotest(c)) { + // Socket not valid, ignore + } else if (c->rtls.len > 0 || mg_tls_pending(c) > 0) { + c->is_readable = 1; + } else { + if (fds[n].revents & POLLERR) { + mg_error(c, "socket error"); + } else { + c->is_readable = + (unsigned) (fds[n].revents & (POLLIN | POLLHUP) ? 1 : 0); + c->is_writable = (unsigned) (fds[n].revents & POLLOUT ? 1 : 0); + if (c->rtls.len > 0 || mg_tls_pending(c) > 0) c->is_readable = 1; + } + n++; + } + } +#else + struct timeval tv = {ms / 1000, (ms % 1000) * 1000}, tv_zero = {0, 0}, *tvp; + struct mg_connection *c; + fd_set rset, wset, eset; + MG_SOCKET_TYPE maxfd = 0; + int rc; + + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&eset); + tvp = ms < 0 ? NULL : &tv; + for (c = mgr->conns; c != NULL; c = c->next) { + c->is_readable = c->is_writable = 0; + if (skip_iotest(c)) continue; + FD_SET(FD(c), &eset); + if (can_read(c)) FD_SET(FD(c), &rset); + if (can_write(c)) FD_SET(FD(c), &wset); + if (c->rtls.len > 0 || mg_tls_pending(c) > 0) tvp = &tv_zero; + if (FD(c) > maxfd) maxfd = FD(c); + if (c->is_closing) ms = 1; + } + + if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, tvp)) < 0) { +#if MG_ARCH == MG_ARCH_WIN32 + if (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets +#else + MG_ERROR(("select: %d %d", rc, MG_SOCK_ERR(rc))); +#endif + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&eset); + } + + for (c = mgr->conns; c != NULL; c = c->next) { + if (FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &eset)) { + mg_error(c, "socket error"); + } else { + c->is_readable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &rset); + c->is_writable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &wset); + if (c->rtls.len > 0 || mg_tls_pending(c) > 0) c->is_readable = 1; + } + } +#endif +} + +static bool mg_socketpair(MG_SOCKET_TYPE sp[2], union usa usa[2]) { + socklen_t n = sizeof(usa[0].sin); + bool success = false; + + sp[0] = sp[1] = MG_INVALID_SOCKET; + (void) memset(&usa[0], 0, sizeof(usa[0])); + usa[0].sin.sin_family = AF_INET; + *(uint32_t *) &usa->sin.sin_addr = mg_htonl(0x7f000001U); // 127.0.0.1 + usa[1] = usa[0]; + + if ((sp[0] = socket(AF_INET, SOCK_DGRAM, 0)) != MG_INVALID_SOCKET && + (sp[1] = socket(AF_INET, SOCK_DGRAM, 0)) != MG_INVALID_SOCKET && + bind(sp[0], &usa[0].sa, n) == 0 && // + bind(sp[1], &usa[1].sa, n) == 0 && // + getsockname(sp[0], &usa[0].sa, &n) == 0 && // + getsockname(sp[1], &usa[1].sa, &n) == 0 && // + connect(sp[0], &usa[1].sa, n) == 0 && // + connect(sp[1], &usa[0].sa, n) == 0) { // + success = true; + } + if (!success) { + if (sp[0] != MG_INVALID_SOCKET) closesocket(sp[0]); + if (sp[1] != MG_INVALID_SOCKET) closesocket(sp[1]); + sp[0] = sp[1] = MG_INVALID_SOCKET; + } + return success; +} + +// mg_wakeup() event handler +static void wufn(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_READ) { + unsigned long *id = (unsigned long *) c->recv.buf; + // MG_INFO(("Got data")); + // mg_hexdump(c->recv.buf, c->recv.len); + if (c->recv.len >= sizeof(*id)) { + struct mg_connection *t; + for (t = c->mgr->conns; t != NULL; t = t->next) { + if (t->id == *id) { + struct mg_str data = mg_str_n((char *) c->recv.buf + sizeof(*id), + c->recv.len - sizeof(*id)); + mg_call(t, MG_EV_WAKEUP, &data); + } + } + } + c->recv.len = 0; // Consume received data + } else if (ev == MG_EV_CLOSE) { + closesocket(c->mgr->pipe); // When we're closing, close the other + c->mgr->pipe = MG_INVALID_SOCKET; // side of the socketpair, too + } + (void) ev_data; +} + +bool mg_wakeup_init(struct mg_mgr *mgr) { + bool ok = false; + if (mgr->pipe == MG_INVALID_SOCKET) { + union usa usa[2]; + MG_SOCKET_TYPE sp[2] = {MG_INVALID_SOCKET, MG_INVALID_SOCKET}; + struct mg_connection *c = NULL; + if (!mg_socketpair(sp, usa)) { + MG_ERROR(("Cannot create socket pair")); + } else if ((c = mg_wrapfd(mgr, (int) sp[1], wufn, NULL)) == NULL) { + closesocket(sp[0]); + closesocket(sp[1]); + sp[0] = sp[1] = MG_INVALID_SOCKET; + } else { + tomgaddr(&usa[0], &c->rem, false); + MG_DEBUG(("%lu %p pipe %lu", c->id, c->fd, (unsigned long) sp[0])); + mgr->pipe = sp[0]; + ok = true; + } + } + return ok; +} + +bool mg_wakeup(struct mg_mgr *mgr, unsigned long conn_id, const void *buf, + size_t len) { + if (mgr->pipe != MG_INVALID_SOCKET && conn_id > 0) { + char *extended_buf = (char *) alloca(len + sizeof(conn_id)); + memcpy(extended_buf, &conn_id, sizeof(conn_id)); + memcpy(extended_buf + sizeof(conn_id), buf, len); + send(mgr->pipe, extended_buf, len + sizeof(conn_id), MSG_NONBLOCKING); + return true; + } + return false; +} + +void mg_mgr_poll(struct mg_mgr *mgr, int ms) { + struct mg_connection *c, *tmp; + uint64_t now; + + mg_iotest(mgr, ms); + now = mg_millis(); + mg_timer_poll(&mgr->timers, now); + + for (c = mgr->conns; c != NULL; c = tmp) { + bool is_resp = c->is_resp; + tmp = c->next; + mg_call(c, MG_EV_POLL, &now); + if (is_resp && !c->is_resp) { + long n = 0; + mg_call(c, MG_EV_READ, &n); + } + MG_VERBOSE(("%lu %c%c %c%c%c%c%c %lu %lu", c->id, + c->is_readable ? 'r' : '-', c->is_writable ? 'w' : '-', + c->is_tls ? 'T' : 't', c->is_connecting ? 'C' : 'c', + c->is_tls_hs ? 'H' : 'h', c->is_resolving ? 'R' : 'r', + c->is_closing ? 'C' : 'c', mg_tls_pending(c), c->rtls.len)); + if (c->is_resolving || c->is_closing) { + // Do nothing + } else if (c->is_listening && c->is_udp == 0) { + if (c->is_readable) accept_conn(mgr, c); + } else if (c->is_connecting) { + if (c->is_readable || c->is_writable) connect_conn(c); + //} else if (c->is_tls_hs) { + // if ((c->is_readable || c->is_writable)) mg_tls_handshake(c); + } else { + if (c->is_readable) read_conn(c); + if (c->is_writable) write_conn(c); + } + + if (c->is_draining && c->send.len == 0) c->is_closing = 1; + if (c->is_closing) close_conn(c); + } +} +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/ssi.c" +#endif + + + + +#ifndef MG_MAX_SSI_DEPTH +#define MG_MAX_SSI_DEPTH 5 +#endif + +#ifndef MG_SSI_BUFSIZ +#define MG_SSI_BUFSIZ 1024 +#endif + +#if MG_ENABLE_SSI +static char *mg_ssi(const char *path, const char *root, int depth) { + struct mg_iobuf b = {NULL, 0, 0, MG_IO_SIZE}; + FILE *fp = fopen(path, "rb"); + if (fp != NULL) { + char buf[MG_SSI_BUFSIZ], arg[sizeof(buf)]; + int ch, intag = 0; + size_t len = 0; + buf[0] = arg[0] = '\0'; + while ((ch = fgetc(fp)) != EOF) { + if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') { + buf[len++] = (char) (ch & 0xff); + buf[len] = '\0'; + if (sscanf(buf, " %#x %#x", s_txdesc[s_txno][1], tsr)); + if (!(s_txdesc[s_txno][1] & MG_BIT(31))) s_txdesc[s_txno][1] |= MG_BIT(31); + } + + GMAC_REGS->GMAC_RSR = rsr; + GMAC_REGS->GMAC_TSR = tsr; +} + +struct mg_tcpip_driver mg_tcpip_driver_same54 = { + mg_tcpip_driver_same54_init, mg_tcpip_driver_same54_tx, NULL, + mg_tcpip_driver_same54_up}; +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/stm32f.c" +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \ + MG_ENABLE_DRIVER_STM32F +struct stm32f_eth { + volatile uint32_t MACCR, MACFFR, MACHTHR, MACHTLR, MACMIIAR, MACMIIDR, MACFCR, + MACVLANTR, RESERVED0[2], MACRWUFFR, MACPMTCSR, RESERVED1, MACDBGR, MACSR, + MACIMR, MACA0HR, MACA0LR, MACA1HR, MACA1LR, MACA2HR, MACA2LR, MACA3HR, + MACA3LR, RESERVED2[40], MMCCR, MMCRIR, MMCTIR, MMCRIMR, MMCTIMR, + RESERVED3[14], MMCTGFSCCR, MMCTGFMSCCR, RESERVED4[5], MMCTGFCR, + RESERVED5[10], MMCRFCECR, MMCRFAECR, RESERVED6[10], MMCRGUFCR, + RESERVED7[334], PTPTSCR, PTPSSIR, PTPTSHR, PTPTSLR, PTPTSHUR, PTPTSLUR, + PTPTSAR, PTPTTHR, PTPTTLR, RESERVED8, PTPTSSR, PTPPPSCR, RESERVED9[564], + DMABMR, DMATPDR, DMARPDR, DMARDLAR, DMATDLAR, DMASR, DMAOMR, DMAIER, + DMAMFBOCR, DMARSWTR, RESERVED10[8], DMACHTDR, DMACHRDR, DMACHTBAR, + DMACHRBAR; +}; +#undef ETH +#define ETH ((struct stm32f_eth *) (uintptr_t) 0x40028000) + +#define ETH_PKT_SIZE 1540 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 4 // Descriptor size (words) + +static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors +static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers +static uint8_t s_txno; // Current TX descriptor +static uint8_t s_rxno; // Current RX descriptor + +static struct mg_tcpip_if *s_ifp; // MIP interface + +static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { + ETH->MACMIIAR &= (7 << 2); + ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6); + ETH->MACMIIAR |= MG_BIT(0); + while (ETH->MACMIIAR & MG_BIT(0)) (void) 0; + return ETH->MACMIIDR & 0xffff; +} + +static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { + ETH->MACMIIDR = val; + ETH->MACMIIAR &= (7 << 2); + ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | MG_BIT(1); + ETH->MACMIIAR |= MG_BIT(0); + while (ETH->MACMIIAR & MG_BIT(0)) (void) 0; +} + +static uint32_t get_hclk(void) { + struct rcc { + volatile uint32_t CR, PLLCFGR, CFGR; + } *rcc = (struct rcc *) 0x40023800; + uint32_t clk = 0, hsi = 16000000 /* 16 MHz */, hse = 8000000 /* 8MHz */; + + if (rcc->CFGR & (1 << 2)) { + clk = hse; + } else if (rcc->CFGR & (1 << 3)) { + uint32_t vco, m, n, p; + m = (rcc->PLLCFGR & (0x3f << 0)) >> 0; + n = (rcc->PLLCFGR & (0x1ff << 6)) >> 6; + p = (((rcc->PLLCFGR & (3 << 16)) >> 16) + 1) * 2; + clk = (rcc->PLLCFGR & (1 << 22)) ? hse : hsi; + vco = (uint32_t) ((uint64_t) clk * n / m); + clk = vco / p; + } else { + clk = hsi; + } + uint32_t hpre = (rcc->CFGR & (15 << 4)) >> 4; + if (hpre < 8) return clk; + + uint8_t ahbptab[8] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div) + return ((uint32_t) clk) >> ahbptab[hpre - 8]; +} + +// Guess CR from HCLK. MDC clock is generated from HCLK (AHB); as per 802.3, +// it must not exceed 2.5MHz As the AHB clock can be (and usually is) derived +// from the HSI (internal RC), and it can go above specs, the datasheets +// specify a range of frequencies and activate one of a series of dividers to +// keep the MDC clock safely below 2.5MHz. We guess a divider setting based on +// HCLK with a +5% drift. If the user uses a different clock from our +// defaults, needs to set the macros on top Valid for STM32F74xxx/75xxx +// (38.8.1) and STM32F42xxx/43xxx (33.8.1) (both 4.5% worst case drift) +static int guess_mdc_cr(void) { + uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMIIAR::CR values + uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers + uint32_t hclk = get_hclk(); // Guess system HCLK + int result = -1; // Invalid CR value + if (hclk < 25000000) { + MG_ERROR(("HCLK too low")); + } else { + for (int i = 0; i < 6; i++) { + if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { + result = crs[i]; + break; + } + } + if (result < 0) MG_ERROR(("HCLK too high")); + } + MG_DEBUG(("HCLK: %u, CR: %d", hclk, result)); + return result; +} + +static bool mg_tcpip_driver_stm32f_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_stm32f_data *d = + (struct mg_tcpip_driver_stm32f_data *) ifp->driver_data; + uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; + s_ifp = ifp; + + // Init RX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][0] = MG_BIT(31); // Own + s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | MG_BIT(14); // 2nd address chained + s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer + s_rxdesc[i][3] = + (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain + } + + // Init TX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer + s_txdesc[i][3] = + (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain + } + + ETH->DMABMR |= MG_BIT(0); // Software reset + while ((ETH->DMABMR & MG_BIT(0)) != 0) (void) 0; // Wait until done + + // Set MDC clock divider. If user told us the value, use it. Otherwise, guess + int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr; + ETH->MACMIIAR = ((uint32_t) cr & 7) << 2; + + // NOTE(cpq): we do not use extended descriptor bit 7, and do not use + // hardware checksum. Therefore, descriptor size is 4, not 8 + // ETH->DMABMR = MG_BIT(13) | MG_BIT(16) | MG_BIT(22) | MG_BIT(23) | + // MG_BIT(25); + ETH->MACIMR = MG_BIT(3) | MG_BIT(9); // Mask timestamp & PMT IT + ETH->MACFCR = MG_BIT(7); // Disable zero quarta pause + // ETH->MACFFR = MG_BIT(31); // Receive all + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + mg_phy_init(&phy, phy_addr, MG_PHY_CLOCKS_MAC); + ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors + ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors + ETH->DMAIER = MG_BIT(6) | MG_BIT(16); // RIE, NISE + ETH->MACCR = + MG_BIT(2) | MG_BIT(3) | MG_BIT(11) | MG_BIT(14); // RE, TE, Duplex, Fast + ETH->DMAOMR = + MG_BIT(1) | MG_BIT(13) | MG_BIT(21) | MG_BIT(25); // SR, ST, TSF, RSF + + // MAC address filtering + ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; + ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) | + ((uint32_t) ifp->mac[2] << 16) | + ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0]; + return true; +} + +static size_t mg_tcpip_driver_stm32f_tx(const void *buf, size_t len, + struct mg_tcpip_if *ifp) { + if (len > sizeof(s_txbuf[s_txno])) { + MG_ERROR(("Frame too big, %ld", (long) len)); + len = 0; // Frame is too big + } else if ((s_txdesc[s_txno][0] & MG_BIT(31))) { + ifp->nerr++; + MG_ERROR(("No free descriptors")); + // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) ETH->DMASR); + len = 0; // All descriptors are busy, fail + } else { + memcpy(s_txbuf[s_txno], buf, len); // Copy data + s_txdesc[s_txno][1] = (uint32_t) len; // Set data len + s_txdesc[s_txno][0] = MG_BIT(20) | MG_BIT(28) | MG_BIT(29); // Chain,FS,LS + s_txdesc[s_txno][0] |= MG_BIT(31); // Set OWN bit - let DMA take over + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; + } + MG_DSB(); // ensure descriptors have been written + ETH->DMASR = MG_BIT(2) | MG_BIT(5); // Clear any prior TBUS/TUS + ETH->DMATPDR = 0; // and resume + return len; +} + +static bool mg_tcpip_driver_stm32f_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_stm32f_data *d = + (struct mg_tcpip_driver_stm32f_data *) ifp->driver_data; + uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; + uint8_t speed = MG_PHY_SPEED_10M; + bool up = false, full_duplex = false; + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + up = mg_phy_up(&phy, phy_addr, &full_duplex, &speed); + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + // tmp = reg with flags set to the most likely situation: 100M full-duplex + // if(link is slow or half) set flags otherwise + // reg = tmp + uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(11); // 100M, Full-duplex + if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M + if (full_duplex == false) maccr &= ~MG_BIT(11); // Half-duplex + ETH->MACCR = maccr; // IRQ handler does not fiddle with this register + MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10, + maccr & MG_BIT(11) ? "full" : "half")); + } + return up; +} + +#ifdef __riscv +__attribute__((interrupt())) // For RISCV CH32V307, which share the same MAC +#endif +void ETH_IRQHandler(void); +void ETH_IRQHandler(void) { + if (ETH->DMASR & MG_BIT(6)) { // Frame received, loop + ETH->DMASR = MG_BIT(16) | MG_BIT(6); // Clear flag + for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever + if (s_rxdesc[s_rxno][0] & MG_BIT(31)) break; // exit when done + if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) == + (MG_BIT(8) | MG_BIT(9))) && + !(s_rxdesc[s_rxno][0] & MG_BIT(15))) { // skip partial/errored frames + uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (MG_BIT(14) - 1)); + // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0], + // ETH->DMASR); + mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); + } + s_rxdesc[s_rxno][0] = MG_BIT(31); + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; + } + } + // Cleanup flags + ETH->DMASR = MG_BIT(16) // NIS, normal interrupt summary + | MG_BIT(7); // Clear possible RBUS while processing + ETH->DMARPDR = 0; // and resume RX +} + +struct mg_tcpip_driver mg_tcpip_driver_stm32f = { + mg_tcpip_driver_stm32f_init, mg_tcpip_driver_stm32f_tx, NULL, + mg_tcpip_driver_stm32f_up}; +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/stm32h.c" +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \ + MG_ENABLE_DRIVER_STM32H +struct stm32h_eth { + volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R, + RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR, + RESERVED4[2], MACTFCR, RESERVED5[7], MACRFCR, RESERVED6[7], MACISR, + MACIER, MACRXTXSR, RESERVED7, MACPCSR, MACRWKPFR, RESERVED8[2], MACLCSR, + MACLTCR, MACLETR, MAC1USTCR, RESERVED9[12], MACVR, MACDR, RESERVED10, + MACHWF0R, MACHWF1R, MACHWF2R, RESERVED11[54], MACMDIOAR, MACMDIODR, + RESERVED12[2], MACARPAR, RESERVED13[59], MACA0HR, MACA0LR, MACA1HR, + MACA1LR, MACA2HR, MACA2LR, MACA3HR, MACA3LR, RESERVED14[248], MMCCR, + MMCRIR, MMCTIR, MMCRIMR, MMCTIMR, RESERVED15[14], MMCTSCGPR, MMCTMCGPR, + RESERVED16[5], MMCTPCGR, RESERVED17[10], MMCRCRCEPR, MMCRAEPR, + RESERVED18[10], MMCRUPGR, RESERVED19[9], MMCTLPIMSTR, MMCTLPITCR, + MMCRLPIMSTR, MMCRLPITCR, RESERVED20[65], MACL3L4C0R, MACL4A0R, + RESERVED21[2], MACL3A0R0R, MACL3A1R0R, MACL3A2R0R, MACL3A3R0R, + RESERVED22[4], MACL3L4C1R, MACL4A1R, RESERVED23[2], MACL3A0R1R, + MACL3A1R1R, MACL3A2R1R, MACL3A3R1R, RESERVED24[108], MACTSCR, MACSSIR, + MACSTSR, MACSTNR, MACSTSUR, MACSTNUR, MACTSAR, RESERVED25, MACTSSR, + RESERVED26[3], MACTTSSNR, MACTTSSSR, RESERVED27[2], MACACR, RESERVED28, + MACATSNR, MACATSSR, MACTSIACR, MACTSEACR, MACTSICNR, MACTSECNR, + RESERVED29[4], MACPPSCR, RESERVED30[3], MACPPSTTSR, MACPPSTTNR, MACPPSIR, + MACPPSWR, RESERVED31[12], MACPOCR, MACSPI0R, MACSPI1R, MACSPI2R, MACLMIR, + RESERVED32[11], MTLOMR, RESERVED33[7], MTLISR, RESERVED34[55], MTLTQOMR, + MTLTQUR, MTLTQDR, RESERVED35[8], MTLQICSR, MTLRQOMR, MTLRQMPOCR, MTLRQDR, + RESERVED36[177], DMAMR, DMASBMR, DMAISR, DMADSR, RESERVED37[60], DMACCR, + DMACTCR, DMACRCR, RESERVED38[2], DMACTDLAR, RESERVED39, DMACRDLAR, + DMACTDTPR, RESERVED40, DMACRDTPR, DMACTDRLR, DMACRDRLR, DMACIER, + DMACRIWTR, DMACSFCSR, RESERVED41, DMACCATDR, RESERVED42, DMACCARDR, + RESERVED43, DMACCATBR, RESERVED44, DMACCARBR, DMACSR, RESERVED45[2], + DMACMFCR; +}; +#undef ETH +#define ETH \ + ((struct stm32h_eth *) (uintptr_t) (0x40000000UL + 0x00020000UL + 0x8000UL)) + +#define ETH_PKT_SIZE 1540 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 4 // Descriptor size (words) + +static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors +static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers +static struct mg_tcpip_if *s_ifp; // MIP interface + +static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { + ETH->MACMDIOAR &= (0xF << 8); + ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 3 << 2; + ETH->MACMDIOAR |= MG_BIT(0); + while (ETH->MACMDIOAR & MG_BIT(0)) (void) 0; + return (uint16_t) ETH->MACMDIODR; +} + +static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { + ETH->MACMDIODR = val; + ETH->MACMDIOAR &= (0xF << 8); + ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 1 << 2; + ETH->MACMDIOAR |= MG_BIT(0); + while (ETH->MACMDIOAR & MG_BIT(0)) (void) 0; +} + +static uint32_t get_hclk(void) { + struct rcc { + volatile uint32_t CR, HSICFGR, CRRCR, CSICFGR, CFGR, RESERVED1, D1CFGR, + D2CFGR, D3CFGR, RESERVED2, PLLCKSELR, PLLCFGR, PLL1DIVR, PLL1FRACR, + PLL2DIVR, PLL2FRACR, PLL3DIVR, PLL3FRACR, RESERVED3, D1CCIPR, D2CCIP1R, + D2CCIP2R, D3CCIPR, RESERVED4, CIER, CIFR, CICR, RESERVED5, BDCR, CSR, + RESERVED6, AHB3RSTR, AHB1RSTR, AHB2RSTR, AHB4RSTR, APB3RSTR, APB1LRSTR, + APB1HRSTR, APB2RSTR, APB4RSTR, GCR, RESERVED8, D3AMR, RESERVED11[9], + RSR, AHB3ENR, AHB1ENR, AHB2ENR, AHB4ENR, APB3ENR, APB1LENR, APB1HENR, + APB2ENR, APB4ENR, RESERVED12, AHB3LPENR, AHB1LPENR, AHB2LPENR, + AHB4LPENR, APB3LPENR, APB1LLPENR, APB1HLPENR, APB2LPENR, APB4LPENR, + RESERVED13[4]; + } *rcc = ((struct rcc *) (0x40000000 + 0x18020000 + 0x4400)); + uint32_t clk = 0, hsi = 64000000 /* 64 MHz */, hse = 8000000 /* 8MHz */, + csi = 4000000 /* 4MHz */; + unsigned int sel = (rcc->CFGR & (7 << 3)) >> 3; + + if (sel == 1) { + clk = csi; + } else if (sel == 2) { + clk = hse; + } else if (sel == 3) { + uint32_t vco, m, n, p; + unsigned int src = (rcc->PLLCKSELR & (3 << 0)) >> 0; + m = ((rcc->PLLCKSELR & (0x3F << 4)) >> 4); + n = ((rcc->PLL1DIVR & (0x1FF << 0)) >> 0) + 1 + + ((rcc->PLLCFGR & MG_BIT(0)) ? 1 : 0); // round-up in fractional mode + p = ((rcc->PLL1DIVR & (0x7F << 9)) >> 9) + 1; + if (src == 1) { + clk = csi; + } else if (src == 2) { + clk = hse; + } else { + clk = hsi; + clk >>= ((rcc->CR & 3) >> 3); + } + vco = (uint32_t) ((uint64_t) clk * n / m); + clk = vco / p; + } else { + clk = hsi; + clk >>= ((rcc->CR & 3) >> 3); + } + const uint8_t cptab[12] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div) + uint32_t d1cpre = (rcc->D1CFGR & (0x0F << 8)) >> 8; + if (d1cpre >= 8) clk >>= cptab[d1cpre - 8]; + MG_DEBUG(("D1 CLK: %u", clk)); + uint32_t hpre = (rcc->D1CFGR & (0x0F << 0)) >> 0; + if (hpre < 8) return clk; + return ((uint32_t) clk) >> cptab[hpre - 8]; +} + +// Guess CR from AHB1 clock. MDC clock is generated from the ETH peripheral +// clock (AHB1); as per 802.3, it must not exceed 2. As the AHB clock can +// be derived from HSI or CSI (internal RC) clocks, and those can go above +// specs, the datasheets specify a range of frequencies and activate one of a +// series of dividers to keep the MDC clock safely below 2.5MHz. We guess a +// divider setting based on HCLK with some drift. If the user uses a different +// clock from our defaults, needs to set the macros on top. Valid for +// STM32H74xxx/75xxx (58.11.4)(4.5% worst case drift)(CSI clock has a 7.5 % +// worst case drift @ max temp) +static int guess_mdc_cr(void) { + const uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMDIOAR::CR values + const uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers + uint32_t hclk = get_hclk(); // Guess system HCLK + int result = -1; // Invalid CR value + for (int i = 0; i < 6; i++) { + if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { + result = crs[i]; + break; + } + } + if (result < 0) MG_ERROR(("HCLK too high")); + MG_DEBUG(("HCLK: %u, CR: %d", hclk, result)); + return result; +} + +static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_stm32h_data *d = + (struct mg_tcpip_driver_stm32h_data *) ifp->driver_data; + s_ifp = ifp; + uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; + uint8_t phy_conf = d == NULL ? MG_PHY_CLOCKS_MAC : d->phy_conf; + + // Init RX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer + s_rxdesc[i][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V + } + + // Init TX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer + } + + ETH->DMAMR |= MG_BIT(0); // Software reset + while ((ETH->DMAMR & MG_BIT(0)) != 0) (void) 0; // Wait until done + + // Set MDC clock divider. If user told us the value, use it. Otherwise, guess + int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr; + ETH->MACMDIOAR = ((uint32_t) cr & 0xF) << 8; + + // NOTE(scaprile): We do not use timing facilities so the DMA engine does not + // re-write buffer address + ETH->DMAMR = 0 << 16; // use interrupt mode 0 (58.8.1) (reset value) + ETH->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed + ETH->MACIER = 0; // Do not enable additional irq sources (reset value) + ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause + // ETH->MACPFR = MG_BIT(31); // Receive all + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + mg_phy_init(&phy, phy_addr, phy_conf); + ETH->DMACRDLAR = + (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors start address + ETH->DMACRDRLR = ETH_DESC_CNT - 1; // ring length + ETH->DMACRDTPR = + (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT - + 1]; // last valid descriptor address + ETH->DMACTDLAR = + (uint32_t) (uintptr_t) s_txdesc; // TX descriptors start address + ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length + ETH->DMACTDTPR = + (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address + ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value) + ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE + ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) | + MG_BIT(15); // RE, TE, Duplex, Fast, Reserved + ETH->MTLTQOMR |= MG_BIT(1); // TSF + ETH->MTLRQOMR |= MG_BIT(5); // RSF + ETH->DMACTCR |= MG_BIT(0); // ST + ETH->DMACRCR |= MG_BIT(0); // SR + + // MAC address filtering + ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; + ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) | + ((uint32_t) ifp->mac[2] << 16) | + ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0]; + return true; +} + +static uint32_t s_txno; +static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len, + struct mg_tcpip_if *ifp) { + if (len > sizeof(s_txbuf[s_txno])) { + MG_ERROR(("Frame too big, %ld", (long) len)); + len = 0; // Frame is too big + } else if ((s_txdesc[s_txno][3] & MG_BIT(31))) { + ifp->nerr++; + MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno, + s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR)); + for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3])); + len = 0; // All descriptors are busy, fail + } else { + memcpy(s_txbuf[s_txno], buf, len); // Copy data + s_txdesc[s_txno][2] = (uint32_t) len; // Set data len + s_txdesc[s_txno][3] = MG_BIT(28) | MG_BIT(29); // FD, LD + s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; + } + ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS + ETH->DMACTDTPR = (uint32_t) (uintptr_t) &s_txdesc[s_txno]; // and resume + return len; + (void) ifp; +} + +static bool mg_tcpip_driver_stm32h_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_stm32h_data *d = + (struct mg_tcpip_driver_stm32h_data *) ifp->driver_data; + uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; + uint8_t speed = MG_PHY_SPEED_10M; + bool up = false, full_duplex = false; + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + up = mg_phy_up(&phy, phy_addr, &full_duplex, &speed); + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + // tmp = reg with flags set to the most likely situation: 100M full-duplex + // if(link is slow or half) set flags otherwise + // reg = tmp + uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex + if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M + if (full_duplex == false) maccr &= ~MG_BIT(13); // Half-duplex + ETH->MACCR = maccr; // IRQ handler does not fiddle with this register + MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10, + maccr & MG_BIT(13) ? "full" : "half")); + } + return up; +} + +void ETH_IRQHandler(void); +static uint32_t s_rxno; +void ETH_IRQHandler(void) { + if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop + ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag + for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever + if (s_rxdesc[s_rxno][3] & MG_BIT(31)) break; // exit when done + if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) == + (MG_BIT(28) | MG_BIT(29))) && + !(s_rxdesc[s_rxno][3] & MG_BIT(15))) { // skip partial/errored frames + uint32_t len = s_rxdesc[s_rxno][3] & (MG_BIT(15) - 1); + // MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3], + // ETH->DMACSR)); + mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); + } + s_rxdesc[s_rxno][3] = + MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; + } + } + ETH->DMACSR = + MG_BIT(7) | MG_BIT(8); // Clear possible RBU RPS while processing + ETH->DMACRDTPR = + (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT - 1]; // and resume RX +} + +struct mg_tcpip_driver mg_tcpip_driver_stm32h = { + mg_tcpip_driver_stm32h_init, mg_tcpip_driver_stm32h_tx, NULL, + mg_tcpip_driver_stm32h_up}; +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/tm4c.c" +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TM4C) && MG_ENABLE_DRIVER_TM4C +struct tm4c_emac { + volatile uint32_t EMACCFG, EMACFRAMEFLTR, EMACHASHTBLH, EMACHASHTBLL, + EMACMIIADDR, EMACMIIDATA, EMACFLOWCTL, EMACVLANTG, RESERVED0, EMACSTATUS, + EMACRWUFF, EMACPMTCTLSTAT, RESERVED1[2], EMACRIS, EMACIM, EMACADDR0H, + EMACADDR0L, EMACADDR1H, EMACADDR1L, EMACADDR2H, EMACADDR2L, EMACADDR3H, + EMACADDR3L, RESERVED2[31], EMACWDOGTO, RESERVED3[8], EMACMMCCTRL, + EMACMMCRXRIS, EMACMMCTXRIS, EMACMMCRXIM, EMACMMCTXIM, RESERVED4, + EMACTXCNTGB, RESERVED5[12], EMACTXCNTSCOL, EMACTXCNTMCOL, RESERVED6[4], + EMACTXOCTCNTG, RESERVED7[6], EMACRXCNTGB, RESERVED8[4], EMACRXCNTCRCERR, + EMACRXCNTALGNERR, RESERVED9[10], EMACRXCNTGUNI, RESERVED10[239], + EMACVLNINCREP, EMACVLANHASH, RESERVED11[93], EMACTIMSTCTRL, EMACSUBSECINC, + EMACTIMSEC, EMACTIMNANO, EMACTIMSECU, EMACTIMNANOU, EMACTIMADD, + EMACTARGSEC, EMACTARGNANO, EMACHWORDSEC, EMACTIMSTAT, EMACPPSCTRL, + RESERVED12[12], EMACPPS0INTVL, EMACPPS0WIDTH, RESERVED13[294], + EMACDMABUSMOD, EMACTXPOLLD, EMACRXPOLLD, EMACRXDLADDR, EMACTXDLADDR, + EMACDMARIS, EMACDMAOPMODE, EMACDMAIM, EMACMFBOC, EMACRXINTWDT, + RESERVED14[8], EMACHOSTXDESC, EMACHOSRXDESC, EMACHOSTXBA, EMACHOSRXBA, + RESERVED15[218], EMACPP, EMACPC, EMACCC, RESERVED16, EMACEPHYRIS, + EMACEPHYIM, EMACEPHYIMSC; +}; +#undef EMAC +#define EMAC ((struct tm4c_emac *) (uintptr_t) 0x400EC000) + +#define ETH_PKT_SIZE 1540 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 4 // Descriptor size (words) + +static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors +static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers +static struct mg_tcpip_if *s_ifp; // MIP interface +enum { + EPHY_ADDR = 0, + EPHYBMCR = 0, + EPHYBMSR = 1, + EPHYSTS = 16 +}; // PHY constants + +static inline void tm4cspin(volatile uint32_t count) { + while (count--) (void) 0; +} + +static uint32_t emac_read_phy(uint8_t addr, uint8_t reg) { + EMAC->EMACMIIADDR &= (0xf << 2); + EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6); + EMAC->EMACMIIADDR |= MG_BIT(0); + while (EMAC->EMACMIIADDR & MG_BIT(0)) tm4cspin(1); + return EMAC->EMACMIIDATA; +} + +static void emac_write_phy(uint8_t addr, uint8_t reg, uint32_t val) { + EMAC->EMACMIIDATA = val; + EMAC->EMACMIIADDR &= (0xf << 2); + EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | MG_BIT(1); + EMAC->EMACMIIADDR |= MG_BIT(0); + while (EMAC->EMACMIIADDR & MG_BIT(0)) tm4cspin(1); +} + +static uint32_t get_sysclk(void) { + struct sysctl { + volatile uint32_t DONTCARE0[44], RSCLKCFG, DONTCARE1[43], PLLFREQ0, + PLLFREQ1; + } *sysctl = (struct sysctl *) 0x400FE000; + uint32_t clk = 0, piosc = 16000000 /* 16 MHz */, mosc = 25000000 /* 25MHz */; + if (sysctl->RSCLKCFG & (1 << 28)) { // USEPLL + uint32_t fin, vco, mdiv, n, q, psysdiv; + uint32_t pllsrc = (sysctl->RSCLKCFG & (0xf << 24)) >> 24; + if (pllsrc == 0) { + clk = piosc; + } else if (pllsrc == 3) { + clk = mosc; + } else { + MG_ERROR(("Unsupported clock source")); + } + q = (sysctl->PLLFREQ1 & (0x1f << 8)) >> 8; + n = (sysctl->PLLFREQ1 & (0x1f << 0)) >> 0; + fin = clk / ((q + 1) * (n + 1)); + mdiv = (sysctl->PLLFREQ0 & (0x3ff << 0)) >> + 0; // mint + (mfrac / 1024); MFRAC not supported + psysdiv = (sysctl->RSCLKCFG & (0x3f << 0)) >> 0; + vco = (uint32_t) ((uint64_t) fin * mdiv); + return vco / (psysdiv + 1); + } + uint32_t oscsrc = (sysctl->RSCLKCFG & (0xf << 20)) >> 20; + if (oscsrc == 0) { + clk = piosc; + } else if (oscsrc == 3) { + clk = mosc; + } else { + MG_ERROR(("Unsupported clock source")); + } + uint32_t osysdiv = (sysctl->RSCLKCFG & (0xf << 16)) >> 16; + return clk / (osysdiv + 1); +} + +// Guess CR from SYSCLK. MDC clock is generated from SYSCLK (AHB); as per +// 802.3, it must not exceed 2.5MHz (also 20.4.2.6) As the AHB clock can be +// derived from the PIOSC (internal RC), and it can go above specs, the +// datasheets specify a range of frequencies and activate one of a series of +// dividers to keep the MDC clock safely below 2.5MHz. We guess a divider +// setting based on SYSCLK with a +5% drift. If the user uses a different clock +// from our defaults, needs to set the macros on top Valid for TM4C129x (20.7) +// (4.5% worst case drift) +// The PHY receives the main oscillator (MOSC) (20.3.1) +static int guess_mdc_cr(void) { + uint8_t crs[] = {2, 3, 0, 1}; // EMAC->MACMIIAR::CR values + uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers + uint32_t sysclk = get_sysclk(); // Guess system SYSCLK + int result = -1; // Invalid CR value + if (sysclk < 25000000) { + MG_ERROR(("SYSCLK too low")); + } else { + for (int i = 0; i < 4; i++) { + if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { + result = crs[i]; + break; + } + } + if (result < 0) MG_ERROR(("SYSCLK too high")); + } + MG_DEBUG(("SYSCLK: %u, CR: %d", sysclk, result)); + return result; +} + +static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_tm4c_data *d = + (struct mg_tcpip_driver_tm4c_data *) ifp->driver_data; + s_ifp = ifp; + + // Init RX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][0] = MG_BIT(31); // Own + s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | MG_BIT(14); // 2nd address chained + s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer + s_rxdesc[i][3] = + (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain + // MG_DEBUG(("%d %p", i, s_rxdesc[i])); + } + + // Init TX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer + s_txdesc[i][3] = + (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain + } + + EMAC->EMACDMABUSMOD |= MG_BIT(0); // Software reset + while ((EMAC->EMACDMABUSMOD & MG_BIT(0)) != 0) tm4cspin(1); // Wait until done + + // Set MDC clock divider. If user told us the value, use it. Otherwise, guess + int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr; + EMAC->EMACMIIADDR = ((uint32_t) cr & 0xf) << 2; + + // NOTE(cpq): we do not use extended descriptor bit 7, and do not use + // hardware checksum. Therefore, descriptor size is 4, not 8 + // EMAC->EMACDMABUSMOD = MG_BIT(13) | MG_BIT(16) | MG_BIT(22) | MG_BIT(23) | MG_BIT(25); + EMAC->EMACIM = MG_BIT(3) | MG_BIT(9); // Mask timestamp & PMT IT + EMAC->EMACFLOWCTL = MG_BIT(7); // Disable zero-quanta pause + // EMAC->EMACFRAMEFLTR = MG_BIT(31); // Receive all + // EMAC->EMACPC defaults to internal PHY (EPHY) in MMI mode + emac_write_phy(EPHY_ADDR, EPHYBMCR, MG_BIT(15)); // Reset internal PHY (EPHY) + emac_write_phy(EPHY_ADDR, EPHYBMCR, MG_BIT(12)); // Set autonegotiation + EMAC->EMACRXDLADDR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors + EMAC->EMACTXDLADDR = (uint32_t) (uintptr_t) s_txdesc; // TX descriptors + EMAC->EMACDMAIM = MG_BIT(6) | MG_BIT(16); // RIE, NIE + EMAC->EMACCFG = MG_BIT(2) | MG_BIT(3) | MG_BIT(11) | MG_BIT(14); // RE, TE, Duplex, Fast + EMAC->EMACDMAOPMODE = + MG_BIT(1) | MG_BIT(13) | MG_BIT(21) | MG_BIT(25); // SR, ST, TSF, RSF + EMAC->EMACADDR0H = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; + EMAC->EMACADDR0L = (uint32_t) (ifp->mac[3] << 24) | + ((uint32_t) ifp->mac[2] << 16) | + ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0]; + // NOTE(scaprile) There are 3 additional slots for filtering, disabled by + // default. This also applies to the STM32 driver (at least for F7) + return true; +} + +static uint32_t s_txno; +static size_t mg_tcpip_driver_tm4c_tx(const void *buf, size_t len, + struct mg_tcpip_if *ifp) { + if (len > sizeof(s_txbuf[s_txno])) { + MG_ERROR(("Frame too big, %ld", (long) len)); + len = 0; // fail + } else if ((s_txdesc[s_txno][0] & MG_BIT(31))) { + ifp->nerr++; + MG_ERROR(("No descriptors available")); + // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) + // EMAC->EMACDMARIS); + len = 0; // fail + } else { + memcpy(s_txbuf[s_txno], buf, len); // Copy data + s_txdesc[s_txno][1] = (uint32_t) len; // Set data len + s_txdesc[s_txno][0] = + MG_BIT(20) | MG_BIT(28) | MG_BIT(29) | MG_BIT(30); // Chain,FS,LS,IC + s_txdesc[s_txno][0] |= MG_BIT(31); // Set OWN bit - let DMA take over + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; + } + EMAC->EMACDMARIS = MG_BIT(2) | MG_BIT(5); // Clear any prior TU/UNF + EMAC->EMACTXPOLLD = 0; // and resume + return len; + (void) ifp; +} + +static bool mg_tcpip_driver_tm4c_up(struct mg_tcpip_if *ifp) { + uint32_t bmsr = emac_read_phy(EPHY_ADDR, EPHYBMSR); + bool up = (bmsr & MG_BIT(2)) ? 1 : 0; + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + uint32_t sts = emac_read_phy(EPHY_ADDR, EPHYSTS); + // tmp = reg with flags set to the most likely situation: 100M full-duplex + // if(link is slow or half) set flags otherwise + // reg = tmp + uint32_t emaccfg = EMAC->EMACCFG | MG_BIT(14) | MG_BIT(11); // 100M, Full-duplex + if (sts & MG_BIT(1)) emaccfg &= ~MG_BIT(14); // 10M + if ((sts & MG_BIT(2)) == 0) emaccfg &= ~MG_BIT(11); // Half-duplex + EMAC->EMACCFG = emaccfg; // IRQ handler does not fiddle with this register + MG_DEBUG(("Link is %uM %s-duplex", emaccfg & MG_BIT(14) ? 100 : 10, + emaccfg & MG_BIT(11) ? "full" : "half")); + } + return up; +} + +void EMAC0_IRQHandler(void); +static uint32_t s_rxno; +void EMAC0_IRQHandler(void) { + if (EMAC->EMACDMARIS & MG_BIT(6)) { // Frame received, loop + EMAC->EMACDMARIS = MG_BIT(16) | MG_BIT(6); // Clear flag + for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever + if (s_rxdesc[s_rxno][0] & MG_BIT(31)) break; // exit when done + if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) == (MG_BIT(8) | MG_BIT(9))) && + !(s_rxdesc[s_rxno][0] & MG_BIT(15))) { // skip partial/errored frames + uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (MG_BIT(14) - 1)); + // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0], + // EMAC->EMACDMARIS); + mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); + } + s_rxdesc[s_rxno][0] = MG_BIT(31); + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; + } + } + EMAC->EMACDMARIS = MG_BIT(7); // Clear possible RU while processing + EMAC->EMACRXPOLLD = 0; // and resume RX +} + +struct mg_tcpip_driver mg_tcpip_driver_tm4c = {mg_tcpip_driver_tm4c_init, + mg_tcpip_driver_tm4c_tx, NULL, + mg_tcpip_driver_tm4c_up}; +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/w5500.c" +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5500) && MG_ENABLE_DRIVER_W5500 + +enum { W5500_CR = 0, W5500_S0 = 1, W5500_TX0 = 2, W5500_RX0 = 3 }; + +static void w5500_txn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, + bool wr, void *buf, size_t len) { + size_t i; + uint8_t *p = (uint8_t *) buf; + uint8_t cmd[] = {(uint8_t) (addr >> 8), (uint8_t) (addr & 255), + (uint8_t) ((block << 3) | (wr ? 4 : 0))}; + s->begin(s->spi); + for (i = 0; i < sizeof(cmd); i++) s->txn(s->spi, cmd[i]); + for (i = 0; i < len; i++) { + uint8_t r = s->txn(s->spi, p[i]); + if (!wr) p[i] = r; + } + s->end(s->spi); +} + +// clang-format off +static void w5500_wn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, void *buf, size_t len) { w5500_txn(s, block, addr, true, buf, len); } +static void w5500_w1(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, uint8_t val) { w5500_wn(s, block, addr, &val, 1); } +static void w5500_w2(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, uint16_t val) { uint8_t buf[2] = {(uint8_t) (val >> 8), (uint8_t) (val & 255)}; w5500_wn(s, block, addr, buf, sizeof(buf)); } +static void w5500_rn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, void *buf, size_t len) { w5500_txn(s, block, addr, false, buf, len); } +static uint8_t w5500_r1(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr) { uint8_t r = 0; w5500_rn(s, block, addr, &r, 1); return r; } +static uint16_t w5500_r2(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr) { uint8_t buf[2] = {0, 0}; w5500_rn(s, block, addr, buf, sizeof(buf)); return (uint16_t) ((buf[0] << 8) | buf[1]); } +// clang-format on + +static size_t w5500_rx(void *buf, size_t buflen, struct mg_tcpip_if *ifp) { + struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; + uint16_t r = 0, n = 0, len = (uint16_t) buflen, n2; // Read recv len + while ((n2 = w5500_r2(s, W5500_S0, 0x26)) > n) n = n2; // Until it is stable + // printf("RSR: %d\n", (int) n); + if (n > 0) { + uint16_t ptr = w5500_r2(s, W5500_S0, 0x28); // Get read pointer + n = w5500_r2(s, W5500_RX0, ptr); // Read frame length + if (n <= len + 2 && n > 1) { + r = (uint16_t) (n - 2); + w5500_rn(s, W5500_RX0, (uint16_t) (ptr + 2), buf, r); + } + w5500_w2(s, W5500_S0, 0x28, (uint16_t) (ptr + n)); // Advance read pointer + w5500_w1(s, W5500_S0, 1, 0x40); // Sock0 CR -> RECV + // printf(" RX_RD: tot=%u n=%u r=%u\n", n2, n, r); + } + return r; +} + +static size_t w5500_tx(const void *buf, size_t buflen, + struct mg_tcpip_if *ifp) { + struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; + uint16_t i, ptr, n = 0, len = (uint16_t) buflen; + while (n < len) n = w5500_r2(s, W5500_S0, 0x20); // Wait for space + ptr = w5500_r2(s, W5500_S0, 0x24); // Get write pointer + w5500_wn(s, W5500_TX0, ptr, (void *) buf, len); // Write data + w5500_w2(s, W5500_S0, 0x24, (uint16_t) (ptr + len)); // Advance write pointer + w5500_w1(s, W5500_S0, 1, 0x20); // Sock0 CR -> SEND + for (i = 0; i < 40; i++) { + uint8_t ir = w5500_r1(s, W5500_S0, 2); // Read S0 IR + if (ir == 0) continue; + // printf("IR %d, len=%d, free=%d, ptr %d\n", ir, (int) len, (int) n, ptr); + w5500_w1(s, W5500_S0, 2, ir); // Write S0 IR: clear it! + if (ir & 8) len = 0; // Timeout. Report error + if (ir & (16 | 8)) break; // Stop on SEND_OK or timeout + } + return len; +} + +static bool w5500_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; + s->end(s->spi); + w5500_w1(s, W5500_CR, 0, 0x80); // Reset chip: CR -> 0x80 + w5500_w1(s, W5500_CR, 0x2e, 0); // CR PHYCFGR -> reset + w5500_w1(s, W5500_CR, 0x2e, 0xf8); // CR PHYCFGR -> set + // w5500_wn(s, W5500_CR, 9, s->mac, 6); // Set source MAC + w5500_w1(s, W5500_S0, 0x1e, 16); // Sock0 RX buf size + w5500_w1(s, W5500_S0, 0x1f, 16); // Sock0 TX buf size + w5500_w1(s, W5500_S0, 0, 4); // Sock0 MR -> MACRAW + w5500_w1(s, W5500_S0, 1, 1); // Sock0 CR -> OPEN + return w5500_r1(s, W5500_S0, 3) == 0x42; // Sock0 SR == MACRAW +} + +static bool w5500_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_spi *spi = (struct mg_tcpip_spi *) ifp->driver_data; + uint8_t phycfgr = w5500_r1(spi, W5500_CR, 0x2e); + return phycfgr & 1; // Bit 0 of PHYCFGR is LNK (0 - down, 1 - up) +} + +struct mg_tcpip_driver mg_tcpip_driver_w5500 = {w5500_init, w5500_tx, w5500_rx, + w5500_up}; +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/xmc.c" +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC + +struct ETH_GLOBAL_TypeDef { + volatile uint32_t MAC_CONFIGURATION, MAC_FRAME_FILTER, HASH_TABLE_HIGH, + HASH_TABLE_LOW, GMII_ADDRESS, GMII_DATA, FLOW_CONTROL, VLAN_TAG, VERSION, + DEBUG, REMOTE_WAKE_UP_FRAME_FILTER, PMT_CONTROL_STATUS, RESERVED[2], + INTERRUPT_STATUS, INTERRUPT_MASK, MAC_ADDRESS0_HIGH, MAC_ADDRESS0_LOW, + MAC_ADDRESS1_HIGH, MAC_ADDRESS1_LOW, MAC_ADDRESS2_HIGH, MAC_ADDRESS2_LOW, + MAC_ADDRESS3_HIGH, MAC_ADDRESS3_LOW, RESERVED1[40], MMC_CONTROL, + MMC_RECEIVE_INTERRUPT, MMC_TRANSMIT_INTERRUPT, MMC_RECEIVE_INTERRUPT_MASK, + MMC_TRANSMIT_INTERRUPT_MASK, TX_STATISTICS[26], RESERVED2, + RX_STATISTICS_1[26], RESERVED3[6], MMC_IPC_RECEIVE_INTERRUPT_MASK, + RESERVED4, MMC_IPC_RECEIVE_INTERRUPT, RESERVED5, RX_STATISTICS_2[30], + RESERVED7[286], TIMESTAMP_CONTROL, SUB_SECOND_INCREMENT, + SYSTEM_TIME_SECONDS, SYSTEM_TIME_NANOSECONDS, + SYSTEM_TIME_SECONDS_UPDATE, SYSTEM_TIME_NANOSECONDS_UPDATE, + TIMESTAMP_ADDEND, TARGET_TIME_SECONDS, TARGET_TIME_NANOSECONDS, + SYSTEM_TIME_HIGHER_WORD_SECONDS, TIMESTAMP_STATUS, + PPS_CONTROL, RESERVED8[564], BUS_MODE, TRANSMIT_POLL_DEMAND, + RECEIVE_POLL_DEMAND, RECEIVE_DESCRIPTOR_LIST_ADDRESS, + TRANSMIT_DESCRIPTOR_LIST_ADDRESS, STATUS, OPERATION_MODE, + INTERRUPT_ENABLE, MISSED_FRAME_AND_BUFFER_OVERFLOW_COUNTER, + RECEIVE_INTERRUPT_WATCHDOG_TIMER, RESERVED9, AHB_STATUS, + RESERVED10[6], CURRENT_HOST_TRANSMIT_DESCRIPTOR, + CURRENT_HOST_RECEIVE_DESCRIPTOR, CURRENT_HOST_TRANSMIT_BUFFER_ADDRESS, + CURRENT_HOST_RECEIVE_BUFFER_ADDRESS, HW_FEATURE; +}; + +#undef ETH0 +#define ETH0 ((struct ETH_GLOBAL_TypeDef*) 0x5000C000UL) + +#define ETH_PKT_SIZE 1536 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 4 // Descriptor size (words) + +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; +static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors +static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors +static uint8_t s_txno; // Current TX descriptor +static uint8_t s_rxno; // Current RX descriptor + +static struct mg_tcpip_if *s_ifp; // MIP interface +enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 }; + +static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { + ETH0->GMII_ADDRESS = (ETH0->GMII_ADDRESS & 0x3c) | + ((uint32_t)addr << 11) | + ((uint32_t)reg << 6) | 1; + while ((ETH0->GMII_ADDRESS & 1) != 0) (void) 0; + return (uint16_t)(ETH0->GMII_DATA & 0xffff); +} + +static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { + ETH0->GMII_DATA = val; + ETH0->GMII_ADDRESS = (ETH0->GMII_ADDRESS & 0x3c) | + ((uint32_t)addr << 11) | + ((uint32_t)reg << 6) | 3; + while ((ETH0->GMII_ADDRESS & 1) != 0) (void) 0; +} + +static uint32_t get_clock_rate(struct mg_tcpip_driver_xmc_data *d) { + if (d->mdc_cr == -1) { + // assume ETH clock is 60MHz by default + // then according to 13.2.8.1, we need to set value 3 + return 3; + } + + return d->mdc_cr; +} + +static bool mg_tcpip_driver_xmc_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_xmc_data *d = + (struct mg_tcpip_driver_xmc_data *) ifp->driver_data; + s_ifp = ifp; + + // reset MAC + ETH0->BUS_MODE |= 1; + while (ETH0->BUS_MODE & 1) (void) 0; + + // set clock rate + ETH0->GMII_ADDRESS = get_clock_rate(d) << 2; + + // init phy + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + mg_phy_init(&phy, d->phy_addr, MG_PHY_CLOCKS_MAC); + + // configure MAC: DO, DM, FES, TC + ETH0->MAC_CONFIGURATION = MG_BIT(13) | MG_BIT(11) | MG_BIT(14) | MG_BIT(24); + + // set the MAC address + ETH0->MAC_ADDRESS0_HIGH = MG_U32(0, 0, ifp->mac[5], ifp->mac[4]); + ETH0->MAC_ADDRESS0_LOW = + MG_U32(ifp->mac[3], ifp->mac[2], ifp->mac[1], ifp->mac[0]); + + // Configure the receive filter + ETH0->MAC_FRAME_FILTER = MG_BIT(10) | MG_BIT(2); // HFP, HMC + // Disable flow control + ETH0->FLOW_CONTROL = 0; + // Enable store and forward mode + ETH0->OPERATION_MODE = MG_BIT(25) | MG_BIT(21); // RSF, TSF + + // Configure DMA bus mode (AAL, USP, RPBL, PBL) + ETH0->BUS_MODE = MG_BIT(25) | MG_BIT(23) | (32 << 17) | (32 << 8); + + // init RX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][0] = MG_BIT(31); // OWN descriptor + s_rxdesc[i][1] = MG_BIT(14) | ETH_PKT_SIZE; + s_rxdesc[i][2] = (uint32_t) s_rxbuf[i]; + if (i == ETH_DESC_CNT - 1) { + s_rxdesc[i][3] = (uint32_t) &s_rxdesc[0][0]; + } else { + s_rxdesc[i][3] = (uint32_t) &s_rxdesc[i + 1][0]; + } + } + ETH0->RECEIVE_DESCRIPTOR_LIST_ADDRESS = (uint32_t) &s_rxdesc[0][0]; + + // init TX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_txdesc[i][0] = MG_BIT(30) | MG_BIT(20); + s_txdesc[i][2] = (uint32_t) s_txbuf[i]; + if (i == ETH_DESC_CNT - 1) { + s_txdesc[i][3] = (uint32_t) &s_txdesc[0][0]; + } else { + s_txdesc[i][3] = (uint32_t) &s_txdesc[i + 1][0]; + } + } + ETH0->TRANSMIT_DESCRIPTOR_LIST_ADDRESS = (uint32_t) &s_txdesc[0][0]; + + // Clear interrupts + ETH0->STATUS = 0xFFFFFFFF; + + // Disable MAC interrupts + ETH0->MMC_TRANSMIT_INTERRUPT_MASK = 0xFFFFFFFF; + ETH0->MMC_RECEIVE_INTERRUPT_MASK = 0xFFFFFFFF; + ETH0->MMC_IPC_RECEIVE_INTERRUPT_MASK = 0xFFFFFFFF; + ETH0->INTERRUPT_MASK = MG_BIT(9) | MG_BIT(3); // TSIM, PMTIM + + //Enable interrupts (NIE, RIE, TIE) + ETH0->INTERRUPT_ENABLE = MG_BIT(16) | MG_BIT(6) | MG_BIT(0); + + // Enable MAC transmission and reception (TE, RE) + ETH0->MAC_CONFIGURATION |= MG_BIT(3) | MG_BIT(2); + // Enable DMA transmission and reception (ST, SR) + ETH0->OPERATION_MODE |= MG_BIT(13) | MG_BIT(1); + return true; +} + +static size_t mg_tcpip_driver_xmc_tx(const void *buf, size_t len, + struct mg_tcpip_if *ifp) { + if (len > sizeof(s_txbuf[s_txno])) { + MG_ERROR(("Frame too big, %ld", (long) len)); + len = 0; // Frame is too big + } else if ((s_txdesc[s_txno][0] & MG_BIT(31))) { + ifp->nerr++; + MG_ERROR(("No free descriptors")); + len = 0; // All descriptors are busy, fail + } else { + memcpy(s_txbuf[s_txno], buf, len); + s_txdesc[s_txno][1] = len; + // Table 13-19 Transmit Descriptor Word 0 (IC, LS, FS, TCH) + s_txdesc[s_txno][0] = MG_BIT(30) | MG_BIT(29) | MG_BIT(28) | MG_BIT(20); + s_txdesc[s_txno][0] |= MG_BIT(31); // OWN bit: handle control to DMA + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; + } + + // Resume processing + ETH0->STATUS = MG_BIT(2); // clear Transmit unavailable + ETH0->TRANSMIT_POLL_DEMAND = 0; + return len; +} + +static bool mg_tcpip_driver_xmc_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_xmc_data *d = + (struct mg_tcpip_driver_xmc_data *) ifp->driver_data; + uint8_t speed = MG_PHY_SPEED_10M; + bool up = false, full_duplex = false; + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + MG_DEBUG(("Link is %uM %s-duplex", speed == MG_PHY_SPEED_10M ? 10 : 100, + full_duplex ? "full" : "half")); + } + return up; +} + +void ETH0_IRQHandler(void); +void ETH0_IRQHandler(void) { + uint32_t irq_status = ETH0->STATUS; + + // check if a frame was received + if (irq_status & MG_BIT(6)) { + for (uint8_t i = 0; i < ETH_DESC_CNT; i++) { + if ((s_rxdesc[s_rxno][0] & MG_BIT(31)) == 0) { + size_t len = (s_rxdesc[s_rxno][0] & 0x3fff0000) >> 16; + mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); + s_rxdesc[s_rxno][0] = MG_BIT(31); // OWN bit: handle control to DMA + // Resume processing + ETH0->STATUS = MG_BIT(7) | MG_BIT(6); // clear RU and RI + ETH0->RECEIVE_POLL_DEMAND = 0; + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; + } + } + ETH0->STATUS = MG_BIT(6); + } + + // clear Successful transmission interrupt + if (irq_status & 1) { + ETH0->STATUS = 1; + } + + // clear normal interrupt + if (irq_status & MG_BIT(16)) { + ETH0->STATUS = MG_BIT(16); + } +} + +struct mg_tcpip_driver mg_tcpip_driver_xmc = { + mg_tcpip_driver_xmc_init, mg_tcpip_driver_xmc_tx, NULL, + mg_tcpip_driver_xmc_up}; +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/xmc7.c" +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7 + +struct ETH_Type { + volatile uint32_t CTL, STATUS, RESERVED[1022], NETWORK_CONTROL, + NETWORK_CONFIG, NETWORK_STATUS, USER_IO_REGISTER, DMA_CONFIG, + TRANSMIT_STATUS, RECEIVE_Q_PTR, TRANSMIT_Q_PTR, RECEIVE_STATUS, + INT_STATUS, INT_ENABLE, INT_DISABLE, INT_MASK, PHY_MANAGEMENT, PAUSE_TIME, + TX_PAUSE_QUANTUM, PBUF_TXCUTTHRU, PBUF_RXCUTTHRU, JUMBO_MAX_LENGTH, + EXTERNAL_FIFO_INTERFACE, RESERVED1, AXI_MAX_PIPELINE, RSC_CONTROL, + INT_MODERATION, SYS_WAKE_TIME, RESERVED2[7], HASH_BOTTOM, HASH_TOP, + SPEC_ADD1_BOTTOM, SPEC_ADD1_TOP, SPEC_ADD2_BOTTOM, SPEC_ADD2_TOP, + SPEC_ADD3_BOTTOM, SPEC_ADD3_TOP, SPEC_ADD4_BOTTOM, SPEC_ADD4_TOP, + SPEC_TYPE1, SPEC_TYPE2, SPEC_TYPE3, SPEC_TYPE4, WOL_REGISTER, + STRETCH_RATIO, STACKED_VLAN, TX_PFC_PAUSE, MASK_ADD1_BOTTOM, + MASK_ADD1_TOP, DMA_ADDR_OR_MASK, RX_PTP_UNICAST, TX_PTP_UNICAST, + TSU_NSEC_CMP, TSU_SEC_CMP, TSU_MSB_SEC_CMP, TSU_PTP_TX_MSB_SEC, + TSU_PTP_RX_MSB_SEC, TSU_PEER_TX_MSB_SEC, TSU_PEER_RX_MSB_SEC, + DPRAM_FILL_DBG, REVISION_REG, OCTETS_TXED_BOTTOM, OCTETS_TXED_TOP, + FRAMES_TXED_OK, BROADCAST_TXED, MULTICAST_TXED, PAUSE_FRAMES_TXED, + FRAMES_TXED_64, FRAMES_TXED_65, FRAMES_TXED_128, FRAMES_TXED_256, + FRAMES_TXED_512, FRAMES_TXED_1024, FRAMES_TXED_1519, TX_UNDERRUNS, + SINGLE_COLLISIONS, MULTIPLE_COLLISIONS, EXCESSIVE_COLLISIONS, + LATE_COLLISIONS, DEFERRED_FRAMES, CRS_ERRORS, OCTETS_RXED_BOTTOM, + OCTETS_RXED_TOP, FRAMES_RXED_OK, BROADCAST_RXED, MULTICAST_RXED, + PAUSE_FRAMES_RXED, FRAMES_RXED_64, FRAMES_RXED_65, FRAMES_RXED_128, + FRAMES_RXED_256, FRAMES_RXED_512, FRAMES_RXED_1024, FRAMES_RXED_1519, + UNDERSIZE_FRAMES, EXCESSIVE_RX_LENGTH, RX_JABBERS, FCS_ERRORS, + RX_LENGTH_ERRORS, RX_SYMBOL_ERRORS, ALIGNMENT_ERRORS, RX_RESOURCE_ERRORS, + RX_OVERRUNS, RX_IP_CK_ERRORS, RX_TCP_CK_ERRORS, RX_UDP_CK_ERRORS, + AUTO_FLUSHED_PKTS, RESERVED3, TSU_TIMER_INCR_SUB_NSEC, TSU_TIMER_MSB_SEC, + TSU_STROBE_MSB_SEC, TSU_STROBE_SEC, TSU_STROBE_NSEC, TSU_TIMER_SEC, + TSU_TIMER_NSEC, TSU_TIMER_ADJUST, TSU_TIMER_INCR, TSU_PTP_TX_SEC, + TSU_PTP_TX_NSEC, TSU_PTP_RX_SEC, TSU_PTP_RX_NSEC, TSU_PEER_TX_SEC, + TSU_PEER_TX_NSEC, TSU_PEER_RX_SEC, TSU_PEER_RX_NSEC, PCS_CONTROL, + PCS_STATUS, RESERVED4[2], PCS_AN_ADV, PCS_AN_LP_BASE, PCS_AN_EXP, + PCS_AN_NP_TX, PCS_AN_LP_NP, RESERVED5[6], PCS_AN_EXT_STATUS, RESERVED6[8], + TX_PAUSE_QUANTUM1, TX_PAUSE_QUANTUM2, TX_PAUSE_QUANTUM3, RESERVED7, + RX_LPI, RX_LPI_TIME, TX_LPI, TX_LPI_TIME, DESIGNCFG_DEBUG1, + DESIGNCFG_DEBUG2, DESIGNCFG_DEBUG3, DESIGNCFG_DEBUG4, DESIGNCFG_DEBUG5, + DESIGNCFG_DEBUG6, DESIGNCFG_DEBUG7, DESIGNCFG_DEBUG8, DESIGNCFG_DEBUG9, + DESIGNCFG_DEBUG10, RESERVED8[22], SPEC_ADD5_BOTTOM, SPEC_ADD5_TOP, + RESERVED9[60], SPEC_ADD36_BOTTOM, SPEC_ADD36_TOP, INT_Q1_STATUS, + INT_Q2_STATUS, INT_Q3_STATUS, RESERVED10[11], INT_Q15_STATUS, RESERVED11, + TRANSMIT_Q1_PTR, TRANSMIT_Q2_PTR, TRANSMIT_Q3_PTR, RESERVED12[11], + TRANSMIT_Q15_PTR, RESERVED13, RECEIVE_Q1_PTR, RECEIVE_Q2_PTR, + RECEIVE_Q3_PTR, RESERVED14[3], RECEIVE_Q7_PTR, RESERVED15, + DMA_RXBUF_SIZE_Q1, DMA_RXBUF_SIZE_Q2, DMA_RXBUF_SIZE_Q3, RESERVED16[3], + DMA_RXBUF_SIZE_Q7, CBS_CONTROL, CBS_IDLESLOPE_Q_A, CBS_IDLESLOPE_Q_B, + UPPER_TX_Q_BASE_ADDR, TX_BD_CONTROL, RX_BD_CONTROL, UPPER_RX_Q_BASE_ADDR, + RESERVED17[2], HIDDEN_REG0, HIDDEN_REG1, HIDDEN_REG2, HIDDEN_REG3, + RESERVED18[2], HIDDEN_REG4, HIDDEN_REG5; +}; + +#define ETH0 ((struct ETH_Type *) 0x40490000) + +#define ETH_PKT_SIZE 1536 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 2 // Descriptor size (words) + +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; +static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors +static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors +static uint8_t s_txno; // Current TX descriptor +static uint8_t s_rxno; // Current RX descriptor + +static struct mg_tcpip_if *s_ifp; // MIP interface +enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 }; + +static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { + // WRITE1, READ OPERATION, PHY, REG, WRITE10 + ETH0->PHY_MANAGEMENT = MG_BIT(30) | MG_BIT(29) | ((addr & 0xf) << 24) | + ((reg & 0x1f) << 18) | MG_BIT(17); + while ((ETH0->NETWORK_STATUS & MG_BIT(2)) == 0) (void) 0; + return ETH0->PHY_MANAGEMENT & 0xffff; +} + +static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { + ETH0->PHY_MANAGEMENT = MG_BIT(30) | MG_BIT(28) | ((addr & 0xf) << 24) | + ((reg & 0x1f) << 18) | MG_BIT(17) | val; + while ((ETH0->NETWORK_STATUS & MG_BIT(2)) == 0) (void) 0; +} + +static uint32_t get_clock_rate(struct mg_tcpip_driver_xmc7_data *d) { + // see ETH0 -> NETWORK_CONFIG register + (void) d; + return 3; +} + +static bool mg_tcpip_driver_xmc7_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_xmc7_data *d = + (struct mg_tcpip_driver_xmc7_data *) ifp->driver_data; + s_ifp = ifp; + + // enable controller, set RGMII mode + ETH0->CTL = MG_BIT(31) | 2; + + uint32_t cr = get_clock_rate(d); + // set NSP change, ignore RX FCS, data bus width, clock rate + // frame length 1536, full duplex, speed + ETH0->NETWORK_CONFIG = MG_BIT(29) | MG_BIT(26) | MG_BIT(21) | + ((cr & 7) << 18) | MG_BIT(8) | MG_BIT(4) | + MG_BIT(1) | MG_BIT(0); + + // config DMA settings: Force TX burst, Discard on Error, set RX buffer size + // to 1536, TX_PBUF_SIZE, RX_PBUF_SIZE, AMBA_BURST_LENGTH + ETH0->DMA_CONFIG = + MG_BIT(26) | MG_BIT(24) | (0x18 << 16) | MG_BIT(10) | (3 << 8) | 4; + + // initialize descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][0] = (uint32_t) s_rxbuf[i]; + if (i == ETH_DESC_CNT - 1) { + s_rxdesc[i][0] |= MG_BIT(1); // mark last descriptor + } + + s_txdesc[i][0] = (uint32_t) s_txbuf[i]; + s_txdesc[i][1] = MG_BIT(31); // OWN descriptor + if (i == ETH_DESC_CNT - 1) { + s_txdesc[i][1] |= MG_BIT(30); // mark last descriptor + } + } + ETH0->RECEIVE_Q_PTR = (uint32_t) s_rxdesc; + ETH0->TRANSMIT_Q_PTR = (uint32_t) s_txdesc; + + // disable other queues + ETH0->TRANSMIT_Q2_PTR = 1; + ETH0->TRANSMIT_Q1_PTR = 1; + ETH0->RECEIVE_Q2_PTR = 1; + ETH0->RECEIVE_Q1_PTR = 1; + + // enable interrupts (TX and RX complete) + ETH0->INT_ENABLE = MG_BIT(7) | MG_BIT(1); + + // set MAC address + ETH0->SPEC_ADD1_BOTTOM = + ifp->mac[3] << 24 | ifp->mac[2] << 16 | ifp->mac[1] << 8 | ifp->mac[0]; + ETH0->SPEC_ADD1_TOP = ifp->mac[5] << 8 | ifp->mac[4]; + + // enable MDIO, TX, RX + ETH0->NETWORK_CONTROL = MG_BIT(4) | MG_BIT(3) | MG_BIT(2); + + // start transmission + ETH0->NETWORK_CONTROL |= MG_BIT(9); + + // init phy + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + mg_phy_init(&phy, d->phy_addr, MG_PHY_CLOCKS_MAC); + + (void) d; + return true; +} + +static size_t mg_tcpip_driver_xmc7_tx(const void *buf, size_t len, + struct mg_tcpip_if *ifp) { + if (len > sizeof(s_txbuf[s_txno])) { + MG_ERROR(("Frame too big, %ld", (long) len)); + len = 0; // Frame is too big + } else if (((s_txdesc[s_txno][1] & MG_BIT(31)) == 0)) { + ifp->nerr++; + MG_ERROR(("No free descriptors")); + len = 0; // All descriptors are busy, fail + } else { + memcpy(s_txbuf[s_txno], buf, len); + s_txdesc[s_txno][1] = (s_txno == ETH_DESC_CNT - 1 ? MG_BIT(30) : 0) | + MG_BIT(15) | len; // Last buffer and length + + ETH0->NETWORK_CONTROL |= MG_BIT(9); // enable transmission + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; + } + + MG_DSB(); + ETH0->TRANSMIT_STATUS = ETH0->TRANSMIT_STATUS; + ETH0->NETWORK_CONTROL |= MG_BIT(9); // enable transmission + + return len; +} + +static bool mg_tcpip_driver_xmc7_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_xmc7_data *d = + (struct mg_tcpip_driver_xmc7_data *) ifp->driver_data; + uint8_t speed = MG_PHY_SPEED_10M; + bool up = false, full_duplex = false; + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + if (speed == MG_PHY_SPEED_1000M) { + ETH0->NETWORK_CONFIG |= MG_BIT(10); + } + MG_DEBUG(("Link is %uM %s-duplex", + speed == MG_PHY_SPEED_10M ? 10 : + (speed == MG_PHY_SPEED_100M ? 100 : 1000), + full_duplex ? "full" : "half")); + } + (void) d; + return up; +} + +void ETH_IRQHandler(void) { + uint32_t irq_status = ETH0->INT_STATUS; + if (irq_status & MG_BIT(1)) { + for (uint8_t i = 0; i < ETH_DESC_CNT; i++) { + if (s_rxdesc[s_rxno][0] & MG_BIT(0)) { + size_t len = s_rxdesc[s_rxno][1] & (MG_BIT(13) - 1); + //MG_INFO(("Receive complete: %ld bytes", len)); + mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); + s_rxdesc[s_rxno][0] &= ~MG_BIT(0); // OWN bit: handle control to DMA + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; + } + } + } + + ETH0->INT_STATUS = irq_status; +} + +struct mg_tcpip_driver mg_tcpip_driver_xmc7 = {mg_tcpip_driver_xmc7_init, + mg_tcpip_driver_xmc7_tx, NULL, + mg_tcpip_driver_xmc7_up}; +#endif diff --git a/webserver/jni/mongoose/mongoose.h b/webserver/jni/mongoose/mongoose.h new file mode 100644 index 0000000..b408184 --- /dev/null +++ b/webserver/jni/mongoose/mongoose.h @@ -0,0 +1,3013 @@ +// Copyright (c) 2004-2013 Sergey Lyubka +// Copyright (c) 2013-2024 Cesanta Software Limited +// All rights reserved +// +// This software is dual-licensed: you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. For the terms of this +// license, see http://www.gnu.org/licenses/ +// +// You are free to use this software under the terms of the GNU General +// Public License, but WITHOUT ANY WARRANTY; without even the implied +// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// Alternatively, you can license this software under a commercial +// license, as set out in https://www.mongoose.ws/licensing/ +// +// SPDX-License-Identifier: GPL-2.0-only or commercial + +#ifndef MONGOOSE_H +#define MONGOOSE_H + +#define MG_VERSION "7.14" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MG_ARCH_CUSTOM 0 // User creates its own mongoose_config.h +#define MG_ARCH_UNIX 1 // Linux, BSD, Mac, ... +#define MG_ARCH_WIN32 2 // Windows +#define MG_ARCH_ESP32 3 // ESP32 +#define MG_ARCH_ESP8266 4 // ESP8266 +#define MG_ARCH_FREERTOS 5 // FreeRTOS +#define MG_ARCH_AZURERTOS 6 // MS Azure RTOS +#define MG_ARCH_ZEPHYR 7 // Zephyr RTOS +#define MG_ARCH_NEWLIB 8 // Bare metal ARM +#define MG_ARCH_CMSIS_RTOS1 9 // CMSIS-RTOS API v1 (Keil RTX) +#define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS +#define MG_ARCH_RP2040 11 // Raspberry Pi RP2040 +#define MG_ARCH_ARMCC 12 // Keil MDK-Core with Configuration Wizard +#define MG_ARCH_CMSIS_RTOS2 13 // CMSIS-RTOS API v2 (Keil RTX5, FreeRTOS) +#define MG_ARCH_RTTHREAD 14 // RT-Thread RTOS + +#if !defined(MG_ARCH) +#if defined(__unix__) || defined(__APPLE__) +#define MG_ARCH MG_ARCH_UNIX +#elif defined(_WIN32) +#define MG_ARCH MG_ARCH_WIN32 +#endif +#endif // !defined(MG_ARCH) + +#if !defined(MG_ARCH) || (MG_ARCH == MG_ARCH_CUSTOM) +#include "mongoose_config.h" // keep this include +#endif + +#if !defined(MG_ARCH) +#error "MG_ARCH is not specified and we couldn't guess it. Define MG_ARCH=... in your compiler" +#endif + +// http://esr.ibiblio.org/?p=5095 +#define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100) + + + + + + + + + + + + + + + +#if MG_ARCH == MG_ARCH_AZURERTOS + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#define PATH_MAX FX_MAXIMUM_PATH +#define MG_DIRSEP '\\' + +#define socklen_t int +#define closesocket(x) soc_close(x) + +#undef FOPEN_MAX + +#endif + + +#if MG_ARCH == MG_ARCH_ESP32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // Use angle brackets to avoid +#include // amalgamation ditching them + +#define MG_PATH_MAX 128 + +#endif + + +#if MG_ARCH == MG_ARCH_ESP8266 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MG_PATH_MAX 128 + +#endif + + +#if MG_ARCH == MG_ARCH_FREERTOS + +#include +#if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP +#include +#endif +#include +#include +#include +#include +#include +#include // rand(), strtol(), atoi() +#include +#if defined(__ARMCC_VERSION) +#define mode_t size_t +#include +#include +#elif defined(__CCRH__) +#else +#include +#endif + +#include +#include + +#ifndef MG_IO_SIZE +#define MG_IO_SIZE 512 +#endif + +#define calloc(a, b) mg_calloc(a, b) +#define free(a) vPortFree(a) +#define malloc(a) pvPortMalloc(a) +#define strdup(s) mg_mprintf("%s", s) + +// Re-route calloc/free to the FreeRTOS's functions, don't use stdlib +static inline void *mg_calloc(size_t cnt, size_t size) { + void *p = pvPortMalloc(cnt * size); + if (p != NULL) memset(p, 0, size * cnt); + return p; +} + +#define mkdir(a, b) mg_mkdir(a, b) +static inline int mg_mkdir(const char *path, mode_t mode) { + (void) path, (void) mode; + return -1; +} + +#endif // MG_ARCH == MG_ARCH_FREERTOS + + +#if MG_ARCH == MG_ARCH_NEWLIB +#define _POSIX_TIMERS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MG_PATH_MAX 100 +#define MG_ENABLE_SOCKET 0 +#define MG_ENABLE_DIRLIST 0 + +#endif + + +#if MG_ARCH == MG_ARCH_RP2040 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +int mkdir(const char *, mode_t); +#endif + + +#if MG_ARCH == MG_ARCH_RTTHREAD + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MG_IO_SIZE +#define MG_IO_SIZE 1460 +#endif + +#endif // MG_ARCH == MG_ARCH_RTTHREAD + + +#if MG_ARCH == MG_ARCH_ARMCC || MG_ARCH == MG_ARCH_CMSIS_RTOS1 || \ + MG_ARCH == MG_ARCH_CMSIS_RTOS2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if MG_ARCH == MG_ARCH_CMSIS_RTOS1 +#include "cmsis_os.h" // keep this include +// https://developer.arm.com/documentation/ka003821/latest +extern uint32_t rt_time_get(void); +#elif MG_ARCH == MG_ARCH_CMSIS_RTOS2 +#include "cmsis_os2.h" // keep this include +#endif + +#define strdup(s) mg_mprintf("%s", s) + +#if defined(__ARMCC_VERSION) +#define mode_t size_t +#define mkdir(a, b) mg_mkdir(a, b) +static inline int mg_mkdir(const char *path, mode_t mode) { + (void) path, (void) mode; + return -1; +} +#endif + +#if (MG_ARCH == MG_ARCH_CMSIS_RTOS1 || MG_ARCH == MG_ARCH_CMSIS_RTOS2) && \ + !defined MG_ENABLE_RL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP) && \ + (!defined(MG_ENABLE_TCPIP) || !MG_ENABLE_TCPIP) +#define MG_ENABLE_RL 1 +#ifndef MG_SOCK_LISTEN_BACKLOG_SIZE +#define MG_SOCK_LISTEN_BACKLOG_SIZE 3 +#endif +#endif + +#endif + + +#if MG_ARCH == MG_ARCH_TIRTOS + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#endif + + +#if MG_ARCH == MG_ARCH_UNIX + +#define _DARWIN_UNLIMITED_SELECT 1 // No limit on file descriptors + +#if defined(__APPLE__) +#include +#endif + +#if !defined(MG_ENABLE_EPOLL) && defined(__linux__) +#define MG_ENABLE_EPOLL 1 +#elif !defined(MG_ENABLE_POLL) +#define MG_ENABLE_POLL 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(MG_ENABLE_EPOLL) && MG_ENABLE_EPOLL +#include +#elif defined(MG_ENABLE_POLL) && MG_ENABLE_POLL +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef MG_ENABLE_DIRLIST +#define MG_ENABLE_DIRLIST 1 +#endif + +#ifndef MG_PATH_MAX +#define MG_PATH_MAX FILENAME_MAX +#endif + +#endif + + +#if MG_ARCH == MG_ARCH_WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1700 +#define __func__ "" +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef unsigned char uint8_t; +typedef char int8_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned int uint32_t; +typedef int int32_t; +typedef enum { false = 0, true = 1 } bool; +#else +#include +#include +#include +#endif + +#include +#include +#include + +// Protect from calls like std::snprintf in app code +// See https://github.com/cesanta/mongoose/issues/1047 +#ifndef __cplusplus +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#ifndef strdup // For MSVC with _DEBUG, see #1359 +#define strdup(x) _strdup(x) +#endif +#endif + +#define MG_INVALID_SOCKET INVALID_SOCKET +#define MG_SOCKET_TYPE SOCKET +typedef unsigned long nfds_t; +#if defined(_MSC_VER) +#pragma comment(lib, "ws2_32.lib") +#ifndef alloca +#define alloca(a) _alloca(a) +#endif +#endif +#define poll(a, b, c) WSAPoll((a), (b), (c)) +#define closesocket(x) closesocket(x) + +typedef int socklen_t; +#define MG_DIRSEP '\\' + +#ifndef MG_PATH_MAX +#define MG_PATH_MAX FILENAME_MAX +#endif + +#ifndef SO_EXCLUSIVEADDRUSE +#define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR)) +#endif + +#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? WSAGetLastError() : 0) + +#define MG_SOCK_PENDING(errcode) \ + (((errcode) < 0) && \ + (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS || \ + WSAGetLastError() == WSAEWOULDBLOCK)) + +#define MG_SOCK_RESET(errcode) \ + (((errcode) < 0) && (WSAGetLastError() == WSAECONNRESET)) + +#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX) +#define sleep(x) Sleep((x) *1000) +#define mkdir(a, b) _mkdir(a) +#define timegm(x) _mkgmtime(x) + +#ifndef S_ISDIR +#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR) +#endif + +#ifndef MG_ENABLE_DIRLIST +#define MG_ENABLE_DIRLIST 1 +#endif + +#ifndef SIGPIPE +#define SIGPIPE 0 +#endif + +#endif + + +#if MG_ARCH == MG_ARCH_ZEPHYR + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MG_PUTCHAR(x) printk("%c", x) +#ifndef strdup +#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf) +#endif +#define strerror(x) zsock_gai_strerror(x) + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 0 +#endif + +#ifndef F_SETFD +#define F_SETFD 0 +#endif + +#define MG_ENABLE_SSI 0 + +int rand(void); +int sscanf(const char *, const char *, ...); + +#endif + + +#if defined(MG_ENABLE_FREERTOS_TCP) && MG_ENABLE_FREERTOS_TCP + +#include +#include + +#include +#include +#include // contents to be moved and file removed, some day + +#define MG_SOCKET_TYPE Socket_t +#define MG_INVALID_SOCKET FREERTOS_INVALID_SOCKET + +// Why FreeRTOS-TCP did not implement a clean BSD API, but its own thing +// with FreeRTOS_ prefix, is beyond me +#define IPPROTO_TCP FREERTOS_IPPROTO_TCP +#define IPPROTO_UDP FREERTOS_IPPROTO_UDP +#define AF_INET FREERTOS_AF_INET +#define SOCK_STREAM FREERTOS_SOCK_STREAM +#define SOCK_DGRAM FREERTOS_SOCK_DGRAM +#define SO_BROADCAST 0 +#define SO_ERROR 0 +#define SOL_SOCKET 0 +#define SO_REUSEADDR 0 + +#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? (errcode) : 0) + +#define MG_SOCK_PENDING(errcode) \ + ((errcode) == -pdFREERTOS_ERRNO_EWOULDBLOCK || \ + (errcode) == -pdFREERTOS_ERRNO_EISCONN || \ + (errcode) == -pdFREERTOS_ERRNO_EINPROGRESS || \ + (errcode) == -pdFREERTOS_ERRNO_EAGAIN) + +#define MG_SOCK_RESET(errcode) ((errcode) == -pdFREERTOS_ERRNO_ENOTCONN) + +// actually only if optional timeout is enabled +#define MG_SOCK_INTR(fd) (fd == NULL) + +#define sockaddr_in freertos_sockaddr +#define sockaddr freertos_sockaddr +#define accept(a, b, c) FreeRTOS_accept((a), (b), (c)) +#define connect(a, b, c) FreeRTOS_connect((a), (b), (c)) +#define bind(a, b, c) FreeRTOS_bind((a), (b), (c)) +#define listen(a, b) FreeRTOS_listen((a), (b)) +#define socket(a, b, c) FreeRTOS_socket((a), (b), (c)) +#define send(a, b, c, d) FreeRTOS_send((a), (b), (c), (d)) +#define recv(a, b, c, d) FreeRTOS_recv((a), (b), (c), (d)) +#define setsockopt(a, b, c, d, e) FreeRTOS_setsockopt((a), (b), (c), (d), (e)) +#define sendto(a, b, c, d, e, f) FreeRTOS_sendto((a), (b), (c), (d), (e), (f)) +#define recvfrom(a, b, c, d, e, f) \ + FreeRTOS_recvfrom((a), (b), (c), (d), (e), (f)) +#define closesocket(x) FreeRTOS_closesocket(x) +#define gethostbyname(x) FreeRTOS_gethostbyname(x) +#define getsockname(a, b, c) mg_getsockname((a), (b), (c)) +#define getpeername(a, b, c) mg_getpeername((a), (b), (c)) + +static inline int mg_getsockname(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) { + (void) fd, (void) buf, (void) len; + return -1; +} + +static inline int mg_getpeername(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) { + (void) fd, (void) buf, (void) len; + return 0; +} +#endif + + +#if defined(MG_ENABLE_LWIP) && MG_ENABLE_LWIP + +#if defined(__GNUC__) && !defined(__ARMCC_VERSION) +#include +#endif + +struct timeval; + +#include + +#if !LWIP_TIMEVAL_PRIVATE +#if defined(__GNUC__) && !defined(__ARMCC_VERSION) // armclang sets both +#include +#else +struct timeval { + time_t tv_sec; + long tv_usec; +}; +#endif +#endif + +#if LWIP_SOCKET != 1 +// Sockets support disabled in LWIP by default +#error Set LWIP_SOCKET variable to 1 (in lwipopts.h) +#endif +#endif + + +#if defined(MG_ENABLE_RL) && MG_ENABLE_RL +#include + +#define closesocket(x) closesocket(x) + +#define TCP_NODELAY SO_KEEPALIVE + +#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? (errcode) : 0) + +#define MG_SOCK_PENDING(errcode) \ + ((errcode) == BSD_EWOULDBLOCK || (errcode) == BSD_EALREADY || \ + (errcode) == BSD_EINPROGRESS) + +#define MG_SOCK_RESET(errcode) \ + ((errcode) == BSD_ECONNABORTED || (errcode) == BSD_ECONNRESET) + +// In blocking mode, which is enabled by default, accept() waits for a +// connection request. In non blocking mode, you must call accept() +// again if the error code BSD_EWOULDBLOCK is returned. +#define MG_SOCK_INTR(fd) (fd == BSD_EWOULDBLOCK) + +#define socklen_t int +#endif + + +#ifndef MG_ENABLE_LOG +#define MG_ENABLE_LOG 1 +#endif + +#ifndef MG_ENABLE_CUSTOM_LOG +#define MG_ENABLE_CUSTOM_LOG 0 // Let user define their own MG_LOG +#endif + +#ifndef MG_ENABLE_TCPIP +#define MG_ENABLE_TCPIP 0 // Mongoose built-in network stack +#endif + +#ifndef MG_ENABLE_LWIP +#define MG_ENABLE_LWIP 0 // lWIP network stack +#endif + +#ifndef MG_ENABLE_FREERTOS_TCP +#define MG_ENABLE_FREERTOS_TCP 0 // Amazon FreeRTOS-TCP network stack +#endif + +#ifndef MG_ENABLE_RL +#define MG_ENABLE_RL 0 // ARM MDK network stack +#endif + +#ifndef MG_ENABLE_SOCKET +#define MG_ENABLE_SOCKET !MG_ENABLE_TCPIP +#endif + +#ifndef MG_ENABLE_POLL +#define MG_ENABLE_POLL 0 +#endif + +#ifndef MG_ENABLE_EPOLL +#define MG_ENABLE_EPOLL 0 +#endif + +#ifndef MG_ENABLE_FATFS +#define MG_ENABLE_FATFS 0 +#endif + +#ifndef MG_ENABLE_SSI +#define MG_ENABLE_SSI 0 +#endif + +#ifndef MG_ENABLE_IPV6 +#define MG_ENABLE_IPV6 0 +#endif + +#ifndef MG_IPV6_V6ONLY +#define MG_IPV6_V6ONLY 0 // IPv6 socket binds only to V6, not V4 address +#endif + +#ifndef MG_ENABLE_MD5 +#define MG_ENABLE_MD5 1 +#endif + +// Set MG_ENABLE_WINSOCK=0 for Win32 builds with external IP stack (like LWIP) +#ifndef MG_ENABLE_WINSOCK +#define MG_ENABLE_WINSOCK 1 +#endif + +#ifndef MG_ENABLE_DIRLIST +#define MG_ENABLE_DIRLIST 0 +#endif + +#ifndef MG_ENABLE_CUSTOM_RANDOM +#define MG_ENABLE_CUSTOM_RANDOM 0 +#endif + +#ifndef MG_ENABLE_CUSTOM_MILLIS +#define MG_ENABLE_CUSTOM_MILLIS 0 +#endif + +#ifndef MG_ENABLE_PACKED_FS +#define MG_ENABLE_PACKED_FS 0 +#endif + +#ifndef MG_ENABLE_ASSERT +#define MG_ENABLE_ASSERT 0 +#endif + +#ifndef MG_IO_SIZE +#define MG_IO_SIZE 2048 // Granularity of the send/recv IO buffer growth +#endif + +#ifndef MG_MAX_RECV_SIZE +#define MG_MAX_RECV_SIZE (3UL * 1024UL * 1024UL) // Maximum recv IO buffer size +#endif + +#ifndef MG_DATA_SIZE +#define MG_DATA_SIZE 32 // struct mg_connection :: data size +#endif + +#ifndef MG_MAX_HTTP_HEADERS +#define MG_MAX_HTTP_HEADERS 30 +#endif + +#ifndef MG_HTTP_INDEX +#define MG_HTTP_INDEX "index.html" +#endif + +#ifndef MG_PATH_MAX +#ifdef PATH_MAX +#define MG_PATH_MAX PATH_MAX +#else +#define MG_PATH_MAX 128 +#endif +#endif + +#ifndef MG_SOCK_LISTEN_BACKLOG_SIZE +#define MG_SOCK_LISTEN_BACKLOG_SIZE 128 +#endif + +#ifndef MG_DIRSEP +#define MG_DIRSEP '/' +#endif + +#ifndef MG_ENABLE_POSIX_FS +#if defined(FOPEN_MAX) +#define MG_ENABLE_POSIX_FS 1 +#else +#define MG_ENABLE_POSIX_FS 0 +#endif +#endif + +#ifndef MG_INVALID_SOCKET +#define MG_INVALID_SOCKET (-1) +#endif + +#ifndef MG_SOCKET_TYPE +#define MG_SOCKET_TYPE int +#endif + +#ifndef MG_SOCKET_ERRNO +#define MG_SOCKET_ERRNO errno +#endif + +#if MG_ENABLE_EPOLL +#define MG_EPOLL_ADD(c) \ + do { \ + struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}}; \ + epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_ADD, (int) (size_t) c->fd, &ev); \ + } while (0) +#define MG_EPOLL_MOD(c, wr) \ + do { \ + struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}}; \ + if (wr) ev.events |= EPOLLOUT; \ + epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_MOD, (int) (size_t) c->fd, &ev); \ + } while (0) +#else +#define MG_EPOLL_ADD(c) +#define MG_EPOLL_MOD(c, wr) +#endif + +#ifndef MG_ENABLE_PROFILE +#define MG_ENABLE_PROFILE 0 +#endif + +#ifndef MG_ENABLE_TCPIP_DRIVER_INIT // mg_mgr_init() will also initialize +#define MG_ENABLE_TCPIP_DRIVER_INIT 1 // enabled built-in driver for +#endif // Mongoose built-in network stack + +#ifndef MG_TCPIP_IP // e.g. MG_IPV4(192, 168, 0, 223) +#define MG_TCPIP_IP MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP) +#endif + +#ifndef MG_TCPIP_MASK +#define MG_TCPIP_MASK MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP) +#endif + +#ifndef MG_TCPIP_GW +#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP) +#endif + +#ifndef MG_SET_MAC_ADDRESS +#define MG_SET_MAC_ADDRESS(mac) +#endif + +#ifndef MG_ENABLE_TCPIP_PRINT_DEBUG_STATS +#define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0 +#endif + + + + +// Describes an arbitrary chunk of memory +struct mg_str { + char *buf; // String data + size_t len; // String length +}; + +// Using macro to avoid shadowing C++ struct constructor, see #1298 +#define mg_str(s) mg_str_s(s) + +struct mg_str mg_str(const char *s); +struct mg_str mg_str_n(const char *s, size_t n); +int mg_casecmp(const char *s1, const char *s2); +int mg_strcmp(const struct mg_str str1, const struct mg_str str2); +int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2); +bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps); +bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char delim); + +bool mg_str_to_num(struct mg_str, int base, void *val, size_t val_len); + + + + +// Single producer, single consumer non-blocking queue + +struct mg_queue { + char *buf; + size_t size; + volatile size_t tail; + volatile size_t head; +}; + +void mg_queue_init(struct mg_queue *, char *, size_t); // Init queue +size_t mg_queue_book(struct mg_queue *, char **buf, size_t); // Reserve space +void mg_queue_add(struct mg_queue *, size_t); // Add new message +size_t mg_queue_next(struct mg_queue *, char **); // Get oldest message +void mg_queue_del(struct mg_queue *, size_t); // Delete oldest message + + + + +typedef void (*mg_pfn_t)(char, void *); // Output function +typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *); // %M printer + +size_t mg_vxprintf(void (*)(char, void *), void *, const char *fmt, va_list *); +size_t mg_xprintf(void (*fn)(char, void *), void *, const char *fmt, ...); + + + + + + +// Convenience wrappers around mg_xprintf +size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap); +size_t mg_snprintf(char *, size_t, const char *fmt, ...); +char *mg_vmprintf(const char *fmt, va_list *ap); +char *mg_mprintf(const char *fmt, ...); +size_t mg_queue_vprintf(struct mg_queue *, const char *fmt, va_list *); +size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...); + +// %M print helper functions +size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap); + +// Various output functions +void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf * +void mg_pfn_stdout(char c, void *param); // param: ignored + +// A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi")) +#define MG_ESC(str) mg_print_esc, 0, (str) + + + + + + +enum { MG_LL_NONE, MG_LL_ERROR, MG_LL_INFO, MG_LL_DEBUG, MG_LL_VERBOSE }; +extern int mg_log_level; // Current log level, one of MG_LL_* + +void mg_log(const char *fmt, ...); +void mg_log_prefix(int ll, const char *file, int line, const char *fname); +// bool mg_log2(int ll, const char *file, int line, const char *fmt, ...); +void mg_hexdump(const void *buf, size_t len); +void mg_log_set_fn(mg_pfn_t fn, void *param); + +#define mg_log_set(level_) mg_log_level = (level_) + +#if MG_ENABLE_LOG +#define MG_LOG(level, args) \ + do { \ + if ((level) <= mg_log_level) { \ + mg_log_prefix((level), __FILE__, __LINE__, __func__); \ + mg_log args; \ + } \ + } while (0) +#else +#define MG_LOG(level, args) \ + do { \ + if (0) mg_log args; \ + } while (0) +#endif + +#define MG_ERROR(args) MG_LOG(MG_LL_ERROR, args) +#define MG_INFO(args) MG_LOG(MG_LL_INFO, args) +#define MG_DEBUG(args) MG_LOG(MG_LL_DEBUG, args) +#define MG_VERBOSE(args) MG_LOG(MG_LL_VERBOSE, args) + + + + +struct mg_timer { + unsigned long id; // Timer ID + uint64_t period_ms; // Timer period in milliseconds + uint64_t expire; // Expiration timestamp in milliseconds + unsigned flags; // Possible flags values below +#define MG_TIMER_ONCE 0 // Call function once +#define MG_TIMER_REPEAT 1 // Call function periodically +#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set + void (*fn)(void *); // Function to call + void *arg; // Function argument + struct mg_timer *next; // Linkage +}; + +void mg_timer_init(struct mg_timer **head, struct mg_timer *timer, + uint64_t milliseconds, unsigned flags, void (*fn)(void *), + void *arg); +void mg_timer_free(struct mg_timer **head, struct mg_timer *); +void mg_timer_poll(struct mg_timer **head, uint64_t new_ms); +bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now); + + + + + +enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 }; + +// Filesystem API functions +// st() returns MG_FS_* flags and populates file size and modification time +// ls() calls fn() for every directory entry, allowing to list a directory +// +// NOTE: UNIX-style shorthand names for the API functions are deliberately +// chosen to avoid conflicts with some libraries that make macros for e.g. +// stat(), write(), read() calls. +struct mg_fs { + int (*st)(const char *path, size_t *size, time_t *mtime); // stat file + void (*ls)(const char *path, void (*fn)(const char *, void *), + void *); // List directory entries: call fn(file_name, fn_data) + // for each directory entry + void *(*op)(const char *path, int flags); // Open file + void (*cl)(void *fd); // Close file + size_t (*rd)(void *fd, void *buf, size_t len); // Read file + size_t (*wr)(void *fd, const void *buf, size_t len); // Write file + size_t (*sk)(void *fd, size_t offset); // Set file position + bool (*mv)(const char *from, const char *to); // Rename file + bool (*rm)(const char *path); // Delete file + bool (*mkd)(const char *path); // Create directory +}; + +extern struct mg_fs mg_fs_posix; // POSIX open/close/read/write/seek +extern struct mg_fs mg_fs_packed; // Packed FS, see examples/device-dashboard +extern struct mg_fs mg_fs_fat; // FAT FS + +// File descriptor +struct mg_fd { + void *fd; + struct mg_fs *fs; +}; + +struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags); +void mg_fs_close(struct mg_fd *fd); +bool mg_fs_ls(struct mg_fs *fs, const char *path, char *buf, size_t len); +struct mg_str mg_file_read(struct mg_fs *fs, const char *path); +bool mg_file_write(struct mg_fs *fs, const char *path, const void *, size_t); +bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...); + +// Packed API +const char *mg_unpack(const char *path, size_t *size, time_t *mtime); +const char *mg_unlist(size_t no); // Get no'th packed filename +struct mg_str mg_unpacked(const char *path); // Packed file as mg_str + + + + + + + +#if MG_ENABLE_ASSERT +#include +#elif !defined(assert) +#define assert(x) +#endif + +void mg_bzero(volatile unsigned char *buf, size_t len); +void mg_random(void *buf, size_t len); +char *mg_random_str(char *buf, size_t len); +uint16_t mg_ntohs(uint16_t net); +uint32_t mg_ntohl(uint32_t net); +uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len); +uint64_t mg_millis(void); // Return milliseconds since boot +uint64_t mg_now(void); // Return milliseconds since Epoch +bool mg_path_is_sane(const struct mg_str path); + +#define mg_htons(x) mg_ntohs(x) +#define mg_htonl(x) mg_ntohl(x) + +#define MG_U32(a, b, c, d) \ + (((uint32_t) ((a) & 255) << 24) | ((uint32_t) ((b) & 255) << 16) | \ + ((uint32_t) ((c) & 255) << 8) | (uint32_t) ((d) & 255)) + +#define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d)) + +// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip)) +#define MG_U8P(ADDR) ((uint8_t *) (ADDR)) +#define MG_IPADDR_PARTS(ADDR) \ + MG_U8P(ADDR)[0], MG_U8P(ADDR)[1], MG_U8P(ADDR)[2], MG_U8P(ADDR)[3] + +#define MG_REG(x) ((volatile uint32_t *) (x))[0] +#define MG_BIT(x) (((uint32_t) 1U) << (x)) +#define MG_SET_BITS(R, CLRMASK, SETMASK) (R) = ((R) & ~(CLRMASK)) | (SETMASK) + +#define MG_ROUND_UP(x, a) ((a) == 0 ? (x) : ((((x) + (a) -1) / (a)) * (a))) +#define MG_ROUND_DOWN(x, a) ((a) == 0 ? (x) : (((x) / (a)) * (a))) + +#if defined(__GNUC__) +#define MG_ARM_DISABLE_IRQ() asm volatile("cpsid i" : : : "memory") +#define MG_ARM_ENABLE_IRQ() asm volatile("cpsie i" : : : "memory") +#elif defined(__CCRH__) +#define MG_RH850_DISABLE_IRQ() __DI() +#define MG_RH850_ENABLE_IRQ() __EI() +#else +#define MG_ARM_DISABLE_IRQ() +#define MG_ARM_ENABLE_IRQ() +#endif + +#if defined(__CC_ARM) +#define MG_DSB() __dsb(0xf) +#elif defined(__ARMCC_VERSION) +#define MG_DSB() __builtin_arm_dsb(0xf) +#elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__) +#define MG_DSB() asm("DSB 0xf") +#elif defined(__ICCARM__) +#define MG_DSB() __iar_builtin_DSB() +#else +#define MG_DSB() +#endif + +struct mg_addr; +int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip); + +// Linked list management macros +#define LIST_ADD_HEAD(type_, head_, elem_) \ + do { \ + (elem_)->next = (*head_); \ + *(head_) = (elem_); \ + } while (0) + +#define LIST_ADD_TAIL(type_, head_, elem_) \ + do { \ + type_ **h = head_; \ + while (*h != NULL) h = &(*h)->next; \ + *h = (elem_); \ + } while (0) + +#define LIST_DELETE(type_, head_, elem_) \ + do { \ + type_ **h = head_; \ + while (*h != (elem_)) h = &(*h)->next; \ + *h = (elem_)->next; \ + } while (0) + + + +unsigned short mg_url_port(const char *url); +int mg_url_is_ssl(const char *url); +struct mg_str mg_url_host(const char *url); +struct mg_str mg_url_user(const char *url); +struct mg_str mg_url_pass(const char *url); +const char *mg_url_uri(const char *url); + + + + +struct mg_iobuf { + unsigned char *buf; // Pointer to stored data + size_t size; // Total size available + size_t len; // Current number of bytes + size_t align; // Alignment during allocation +}; + +int mg_iobuf_init(struct mg_iobuf *, size_t, size_t); +int mg_iobuf_resize(struct mg_iobuf *, size_t); +void mg_iobuf_free(struct mg_iobuf *); +size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t); +size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len); + + +size_t mg_base64_update(unsigned char input_byte, char *buf, size_t len); +size_t mg_base64_final(char *buf, size_t len); +size_t mg_base64_encode(const unsigned char *p, size_t n, char *buf, size_t); +size_t mg_base64_decode(const char *src, size_t n, char *dst, size_t); + + + + +typedef struct { + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +} mg_md5_ctx; + +void mg_md5_init(mg_md5_ctx *c); +void mg_md5_update(mg_md5_ctx *c, const unsigned char *data, size_t len); +void mg_md5_final(mg_md5_ctx *c, unsigned char[16]); + + + + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} mg_sha1_ctx; + +void mg_sha1_init(mg_sha1_ctx *); +void mg_sha1_update(mg_sha1_ctx *, const unsigned char *data, size_t len); +void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *); +// https://github.com/B-Con/crypto-algorithms +// Author: Brad Conte (brad AT bradconte.com) +// Disclaimer: This code is presented "as is" without any guarantees. +// Details: Defines the API for the corresponding SHA1 implementation. +// Copyright: public domain + + + + + +typedef struct { + uint32_t state[8]; + uint64_t bits; + uint32_t len; + unsigned char buffer[64]; +} mg_sha256_ctx; + +void mg_sha256_init(mg_sha256_ctx *); +void mg_sha256_update(mg_sha256_ctx *, const unsigned char *data, size_t len); +void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *); +void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, + size_t datasz); +#ifndef TLS_X15519_H +#define TLS_X15519_H + + + +#define X25519_BYTES 32 +extern const uint8_t X25519_BASE_POINT[X25519_BYTES]; + +int mg_tls_x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES], + const uint8_t x1[X25519_BYTES], int clamp); + + +#endif /* TLS_X15519_H */ +/****************************************************************************** + * + * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL + * + * This is a simple and straightforward implementation of AES-GCM authenticated + * encryption. The focus of this work was correctness & accuracy. It is written + * in straight 'C' without any particular focus upon optimization or speed. It + * should be endian (memory byte order) neutral since the few places that care + * are handled explicitly. + * + * This implementation of AES-GCM was created by Steven M. Gibson of GRC.com. + * + * It is intended for general purpose use, but was written in support of GRC's + * reference implementation of the SQRL (Secure Quick Reliable Login) client. + * + * See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \ + * gcm/gcm-revised-spec.pdf + * + * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE + * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. + * + *******************************************************************************/ +#ifndef TLS_AES128_H +#define TLS_AES128_H + +typedef unsigned char uchar; // add some convienent shorter types +typedef unsigned int uint; + +/****************************************************************************** + * AES_CONTEXT : cipher context / holds inter-call data + ******************************************************************************/ +typedef struct { + int mode; // 1 for Encryption, 0 for Decryption + int rounds; // keysize-based rounds count + uint32_t *rk; // pointer to current round key + uint32_t buf[68]; // key expansion buffer +} aes_context; + + +#define GCM_AUTH_FAILURE 0x55555555 // authentication failure + +/****************************************************************************** + * GCM_CONTEXT : MUST be called once before ANY use of this library + ******************************************************************************/ +int mg_gcm_initialize(void); + +// +// aes-gcm.h +// MKo +// +// Created by Markus Kosmal on 20/11/14. +// +// +int mg_aes_gcm_encrypt(unsigned char *output, const unsigned char *input, + size_t input_length, const unsigned char *key, + const size_t key_len, const unsigned char *iv, + const size_t iv_len, unsigned char *aead, + size_t aead_len, unsigned char *tag, + const size_t tag_len); + +int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input, + size_t input_length, const unsigned char *key, + const size_t key_len, const unsigned char *iv, + const size_t iv_len); + +#endif /* TLS_AES128_H */ + +// End of aes128 PD + + + +#define MG_UECC_SUPPORTS_secp256r1 1 +/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_H_ +#define _UECC_H_ + +/* Platform selection options. +If MG_UECC_PLATFORM is not defined, the code will try to guess it based on +compiler macros. Possible values for MG_UECC_PLATFORM are defined below: */ +#define mg_uecc_arch_other 0 +#define mg_uecc_x86 1 +#define mg_uecc_x86_64 2 +#define mg_uecc_arm 3 +#define mg_uecc_arm_thumb 4 +#define mg_uecc_arm_thumb2 5 +#define mg_uecc_arm64 6 +#define mg_uecc_avr 7 + +/* If desired, you can define MG_UECC_WORD_SIZE as appropriate for your platform +(1, 4, or 8 bytes). If MG_UECC_WORD_SIZE is not explicitly defined then it will +be automatically set based on your platform. */ + +/* Optimization level; trade speed for code size. + Larger values produce code that is faster but larger. + Currently supported values are 0 - 4; 0 is unusably slow for most + applications. Optimization level 4 currently only has an effect ARM platforms + where more than one curve is enabled. */ +#ifndef MG_UECC_OPTIMIZATION_LEVEL +#define MG_UECC_OPTIMIZATION_LEVEL 2 +#endif + +/* MG_UECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a +specific function to be used for (scalar) squaring instead of the generic +multiplication function. This can make things faster somewhat faster, but +increases the code size. */ +#ifndef MG_UECC_SQUARE_FUNC +#define MG_UECC_SQUARE_FUNC 0 +#endif + +/* MG_UECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will +switch to native little-endian format for *all* arrays passed in and out of the +public API. This includes public and private keys, shared secrets, signatures +and message hashes. Using this switch reduces the amount of call stack memory +used by uECC, since less intermediate translations are required. Note that this +will *only* work on native little-endian processors and it will treat the +uint8_t arrays passed into the public API as word arrays, therefore requiring +the provided byte arrays to be word aligned on architectures that do not support +unaligned accesses. IMPORTANT: Keys and signatures generated with +MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible with keys and signatures +generated with MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use the same +endianness. */ +#ifndef MG_UECC_VLI_NATIVE_LITTLE_ENDIAN +#define MG_UECC_VLI_NATIVE_LITTLE_ENDIAN 0 +#endif + +/* Curve support selection. Set to 0 to remove that curve. */ +#ifndef MG_UECC_SUPPORTS_secp160r1 +#define MG_UECC_SUPPORTS_secp160r1 0 +#endif +#ifndef MG_UECC_SUPPORTS_secp192r1 +#define MG_UECC_SUPPORTS_secp192r1 0 +#endif +#ifndef MG_UECC_SUPPORTS_secp224r1 +#define MG_UECC_SUPPORTS_secp224r1 0 +#endif +#ifndef MG_UECC_SUPPORTS_secp256r1 +#define MG_UECC_SUPPORTS_secp256r1 1 +#endif +#ifndef MG_UECC_SUPPORTS_secp256k1 +#define MG_UECC_SUPPORTS_secp256k1 0 +#endif + +/* Specifies whether compressed point format is supported. + Set to 0 to disable point compression/decompression functions. */ +#ifndef MG_UECC_SUPPORT_COMPRESSED_POINT +#define MG_UECC_SUPPORT_COMPRESSED_POINT 1 +#endif + +struct MG_UECC_Curve_t; +typedef const struct MG_UECC_Curve_t *MG_UECC_Curve; + +#ifdef __cplusplus +extern "C" { +#endif + +#if MG_UECC_SUPPORTS_secp160r1 +MG_UECC_Curve mg_uecc_secp160r1(void); +#endif +#if MG_UECC_SUPPORTS_secp192r1 +MG_UECC_Curve mg_uecc_secp192r1(void); +#endif +#if MG_UECC_SUPPORTS_secp224r1 +MG_UECC_Curve mg_uecc_secp224r1(void); +#endif +#if MG_UECC_SUPPORTS_secp256r1 +MG_UECC_Curve mg_uecc_secp256r1(void); +#endif +#if MG_UECC_SUPPORTS_secp256k1 +MG_UECC_Curve mg_uecc_secp256k1(void); +#endif + +/* MG_UECC_RNG_Function type +The RNG function should fill 'size' random bytes into 'dest'. It should return 1 +if 'dest' was filled with random data, or 0 if the random data could not be +generated. The filled-in values should be either truly random, or from a +cryptographically-secure PRNG. + +A correctly functioning RNG function must be set (using mg_uecc_set_rng()) +before calling mg_uecc_make_key() or mg_uecc_sign(). + +Setting a correctly functioning RNG function improves the resistance to +side-channel attacks for mg_uecc_shared_secret() and +mg_uecc_sign_deterministic(). + +A correct RNG function is set by default when building for Windows, Linux, or OS +X. If you are building on another POSIX-compliant system that supports +/dev/random or /dev/urandom, you can define MG_UECC_POSIX to use the predefined +RNG. For embedded platforms there is no predefined RNG function; you must +provide your own. +*/ +typedef int (*MG_UECC_RNG_Function)(uint8_t *dest, unsigned size); + +/* mg_uecc_set_rng() function. +Set the function that will be used to generate random bytes. The RNG function +should return 1 if the random data was generated, or 0 if the random data could +not be generated. + +On platforms where there is no predefined RNG function (eg embedded platforms), +this must be called before mg_uecc_make_key() or mg_uecc_sign() are used. + +Inputs: + rng_function - The function that will be used to generate random bytes. +*/ +void mg_uecc_set_rng(MG_UECC_RNG_Function rng_function); + +/* mg_uecc_get_rng() function. + +Returns the function that will be used to generate random bytes. +*/ +MG_UECC_RNG_Function mg_uecc_get_rng(void); + +/* mg_uecc_curve_private_key_size() function. + +Returns the size of a private key for the curve in bytes. +*/ +int mg_uecc_curve_private_key_size(MG_UECC_Curve curve); + +/* mg_uecc_curve_public_key_size() function. + +Returns the size of a public key for the curve in bytes. +*/ +int mg_uecc_curve_public_key_size(MG_UECC_Curve curve); + +/* mg_uecc_make_key() function. +Create a public/private key pair. + +Outputs: + public_key - Will be filled in with the public key. Must be at least 2 * +the curve size (in bytes) long. For example, if the curve is secp256r1, +public_key must be 64 bytes long. private_key - Will be filled in with the +private key. Must be as long as the curve order; this is typically the same as +the curve size, except for secp160r1. For example, if the curve is secp256r1, +private_key must be 32 bytes long. + + For secp160r1, private_key must be 21 bytes long! Note that +the first byte will almost always be 0 (there is about a 1 in 2^80 chance of it +being non-zero). + +Returns 1 if the key pair was generated successfully, 0 if an error occurred. +*/ +int mg_uecc_make_key(uint8_t *public_key, uint8_t *private_key, + MG_UECC_Curve curve); + +/* mg_uecc_shared_secret() function. +Compute a shared secret given your secret key and someone else's public key. If +the public key is not from a trusted source and has not been previously +verified, you should verify it first using mg_uecc_valid_public_key(). Note: It +is recommended that you hash the result of mg_uecc_shared_secret() before using +it for symmetric encryption or HMAC. + +Inputs: + public_key - The public key of the remote party. + private_key - Your private key. + +Outputs: + secret - Will be filled in with the shared secret value. Must be the same +size as the curve size; for example, if the curve is secp256r1, secret must be +32 bytes long. + +Returns 1 if the shared secret was generated successfully, 0 if an error +occurred. +*/ +int mg_uecc_shared_secret(const uint8_t *public_key, const uint8_t *private_key, + uint8_t *secret, MG_UECC_Curve curve); + +#if MG_UECC_SUPPORT_COMPRESSED_POINT +/* mg_uecc_compress() function. +Compress a public key. + +Inputs: + public_key - The public key to compress. + +Outputs: + compressed - Will be filled in with the compressed public key. Must be at +least (curve size + 1) bytes long; for example, if the curve is secp256r1, + compressed must be 33 bytes long. +*/ +void mg_uecc_compress(const uint8_t *public_key, uint8_t *compressed, + MG_UECC_Curve curve); + +/* mg_uecc_decompress() function. +Decompress a compressed public key. + +Inputs: + compressed - The compressed public key. + +Outputs: + public_key - Will be filled in with the decompressed public key. +*/ +void mg_uecc_decompress(const uint8_t *compressed, uint8_t *public_key, + MG_UECC_Curve curve); +#endif /* MG_UECC_SUPPORT_COMPRESSED_POINT */ + +/* mg_uecc_valid_public_key() function. +Check to see if a public key is valid. + +Note that you are not required to check for a valid public key before using any +other uECC functions. However, you may wish to avoid spending CPU time computing +a shared secret or verifying a signature using an invalid public key. + +Inputs: + public_key - The public key to check. + +Returns 1 if the public key is valid, 0 if it is invalid. +*/ +int mg_uecc_valid_public_key(const uint8_t *public_key, MG_UECC_Curve curve); + +/* mg_uecc_compute_public_key() function. +Compute the corresponding public key for a private key. + +Inputs: + private_key - The private key to compute the public key for + +Outputs: + public_key - Will be filled in with the corresponding public key + +Returns 1 if the key was computed successfully, 0 if an error occurred. +*/ +int mg_uecc_compute_public_key(const uint8_t *private_key, uint8_t *public_key, + MG_UECC_Curve curve); + +/* mg_uecc_sign() function. +Generate an ECDSA signature for a given hash value. + +Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and +pass it in to this function along with your private key. + +Inputs: + private_key - Your private key. + message_hash - The hash of the message to sign. + hash_size - The size of message_hash in bytes. + +Outputs: + signature - Will be filled in with the signature value. Must be at least 2 * +curve size long. For example, if the curve is secp256r1, signature must be 64 +bytes long. + +Returns 1 if the signature generated successfully, 0 if an error occurred. +*/ +int mg_uecc_sign(const uint8_t *private_key, const uint8_t *message_hash, + unsigned hash_size, uint8_t *signature, MG_UECC_Curve curve); + +/* MG_UECC_HashContext structure. +This is used to pass in an arbitrary hash function to +mg_uecc_sign_deterministic(). The structure will be used for multiple hash +computations; each time a new hash is computed, init_hash() will be called, +followed by one or more calls to update_hash(), and finally a call to +finish_hash() to produce the resulting hash. + +The intention is that you will create a structure that includes +MG_UECC_HashContext followed by any hash-specific data. For example: + +typedef struct SHA256_HashContext { + MG_UECC_HashContext uECC; + SHA256_CTX ctx; +} SHA256_HashContext; + +void init_SHA256(MG_UECC_HashContext *base) { + SHA256_HashContext *context = (SHA256_HashContext *)base; + SHA256_Init(&context->ctx); +} + +void update_SHA256(MG_UECC_HashContext *base, + const uint8_t *message, + unsigned message_size) { + SHA256_HashContext *context = (SHA256_HashContext *)base; + SHA256_Update(&context->ctx, message, message_size); +} + +void finish_SHA256(MG_UECC_HashContext *base, uint8_t *hash_result) { + SHA256_HashContext *context = (SHA256_HashContext *)base; + SHA256_Final(hash_result, &context->ctx); +} + +... when signing ... +{ + uint8_t tmp[32 + 32 + 64]; + SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, +32, tmp}}; mg_uecc_sign_deterministic(key, message_hash, &ctx.uECC, signature); +} +*/ +typedef struct MG_UECC_HashContext { + void (*init_hash)(const struct MG_UECC_HashContext *context); + void (*update_hash)(const struct MG_UECC_HashContext *context, + const uint8_t *message, unsigned message_size); + void (*finish_hash)(const struct MG_UECC_HashContext *context, + uint8_t *hash_result); + unsigned + block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */ + unsigned + result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */ + uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + + block_size) bytes. */ +} MG_UECC_HashContext; + +/* mg_uecc_sign_deterministic() function. +Generate an ECDSA signature for a given hash value, using a deterministic +algorithm (see RFC 6979). You do not need to set the RNG using mg_uecc_set_rng() +before calling this function; however, if the RNG is defined it will improve +resistance to side-channel attacks. + +Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and +pass it to this function along with your private key and a hash context. Note +that the message_hash does not need to be computed with the same hash function +used by hash_context. + +Inputs: + private_key - Your private key. + message_hash - The hash of the message to sign. + hash_size - The size of message_hash in bytes. + hash_context - A hash context to use. + +Outputs: + signature - Will be filled in with the signature value. + +Returns 1 if the signature generated successfully, 0 if an error occurred. +*/ +int mg_uecc_sign_deterministic(const uint8_t *private_key, + const uint8_t *message_hash, unsigned hash_size, + const MG_UECC_HashContext *hash_context, + uint8_t *signature, MG_UECC_Curve curve); + +/* mg_uecc_verify() function. +Verify an ECDSA signature. + +Usage: Compute the hash of the signed data using the same hash as the signer and +pass it to this function along with the signer's public key and the signature +values (r and s). + +Inputs: + public_key - The signer's public key. + message_hash - The hash of the signed data. + hash_size - The size of message_hash in bytes. + signature - The signature value. + +Returns 1 if the signature is valid, 0 if it is invalid. +*/ +int mg_uecc_verify(const uint8_t *public_key, const uint8_t *message_hash, + unsigned hash_size, const uint8_t *signature, + MG_UECC_Curve curve); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _UECC_H_ */ + +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_VLI_H_ +#define _UECC_VLI_H_ + +// +// + +/* Functions for raw large-integer manipulation. These are only available + if uECC.c is compiled with MG_UECC_ENABLE_VLI_API defined to 1. */ +#ifndef MG_UECC_ENABLE_VLI_API +#define MG_UECC_ENABLE_VLI_API 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if MG_UECC_ENABLE_VLI_API + +void mg_uecc_vli_clear(mg_uecc_word_t *vli, wordcount_t num_words); + +/* Constant-time comparison to zero - secure way to compare long integers */ +/* Returns 1 if vli == 0, 0 otherwise. */ +mg_uecc_word_t mg_uecc_vli_isZero(const mg_uecc_word_t *vli, + wordcount_t num_words); + +/* Returns nonzero if bit 'bit' of vli is set. */ +mg_uecc_word_t mg_uecc_vli_testBit(const mg_uecc_word_t *vli, bitcount_t bit); + +/* Counts the number of bits required to represent vli. */ +bitcount_t mg_uecc_vli_numBits(const mg_uecc_word_t *vli, + const wordcount_t max_words); + +/* Sets dest = src. */ +void mg_uecc_vli_set(mg_uecc_word_t *dest, const mg_uecc_word_t *src, + wordcount_t num_words); + +/* Constant-time comparison function - secure way to compare long integers */ +/* Returns one if left == right, zero otherwise */ +mg_uecc_word_t mg_uecc_vli_equal(const mg_uecc_word_t *left, + const mg_uecc_word_t *right, + wordcount_t num_words); + +/* Constant-time comparison function - secure way to compare long integers */ +/* Returns sign of left - right, in constant time. */ +cmpresult_t mg_uecc_vli_cmp(const mg_uecc_word_t *left, + const mg_uecc_word_t *right, wordcount_t num_words); + +/* Computes vli = vli >> 1. */ +void mg_uecc_vli_rshift1(mg_uecc_word_t *vli, wordcount_t num_words); + +/* Computes result = left + right, returning carry. Can modify in place. */ +mg_uecc_word_t mg_uecc_vli_add(mg_uecc_word_t *result, + const mg_uecc_word_t *left, + const mg_uecc_word_t *right, + wordcount_t num_words); + +/* Computes result = left - right, returning borrow. Can modify in place. */ +mg_uecc_word_t mg_uecc_vli_sub(mg_uecc_word_t *result, + const mg_uecc_word_t *left, + const mg_uecc_word_t *right, + wordcount_t num_words); + +/* Computes result = left * right. Result must be 2 * num_words long. */ +void mg_uecc_vli_mult(mg_uecc_word_t *result, const mg_uecc_word_t *left, + const mg_uecc_word_t *right, wordcount_t num_words); + +/* Computes result = left^2. Result must be 2 * num_words long. */ +void mg_uecc_vli_square(mg_uecc_word_t *result, const mg_uecc_word_t *left, + wordcount_t num_words); + +/* Computes result = (left + right) % mod. + Assumes that left < mod and right < mod, and that result does not overlap + mod. */ +void mg_uecc_vli_modAdd(mg_uecc_word_t *result, const mg_uecc_word_t *left, + const mg_uecc_word_t *right, const mg_uecc_word_t *mod, + wordcount_t num_words); + +/* Computes result = (left - right) % mod. + Assumes that left < mod and right < mod, and that result does not overlap + mod. */ +void mg_uecc_vli_modSub(mg_uecc_word_t *result, const mg_uecc_word_t *left, + const mg_uecc_word_t *right, const mg_uecc_word_t *mod, + wordcount_t num_words); + +/* Computes result = product % mod, where product is 2N words long. + Currently only designed to work for mod == curve->p or curve_n. */ +void mg_uecc_vli_mmod(mg_uecc_word_t *result, mg_uecc_word_t *product, + const mg_uecc_word_t *mod, wordcount_t num_words); + +/* Calculates result = product (mod curve->p), where product is up to + 2 * curve->num_words long. */ +void mg_uecc_vli_mmod_fast(mg_uecc_word_t *result, mg_uecc_word_t *product, + MG_UECC_Curve curve); + +/* Computes result = (left * right) % mod. + Currently only designed to work for mod == curve->p or curve_n. */ +void mg_uecc_vli_modMult(mg_uecc_word_t *result, const mg_uecc_word_t *left, + const mg_uecc_word_t *right, const mg_uecc_word_t *mod, + wordcount_t num_words); + +/* Computes result = (left * right) % curve->p. */ +void mg_uecc_vli_modMult_fast(mg_uecc_word_t *result, + const mg_uecc_word_t *left, + const mg_uecc_word_t *right, MG_UECC_Curve curve); + +/* Computes result = left^2 % mod. + Currently only designed to work for mod == curve->p or curve_n. */ +void mg_uecc_vli_modSquare(mg_uecc_word_t *result, const mg_uecc_word_t *left, + const mg_uecc_word_t *mod, wordcount_t num_words); + +/* Computes result = left^2 % curve->p. */ +void mg_uecc_vli_modSquare_fast(mg_uecc_word_t *result, + const mg_uecc_word_t *left, + MG_UECC_Curve curve); + +/* Computes result = (1 / input) % mod.*/ +void mg_uecc_vli_modInv(mg_uecc_word_t *result, const mg_uecc_word_t *input, + const mg_uecc_word_t *mod, wordcount_t num_words); + +#if MG_UECC_SUPPORT_COMPRESSED_POINT +/* Calculates a = sqrt(a) (mod curve->p) */ +void mg_uecc_vli_mod_sqrt(mg_uecc_word_t *a, MG_UECC_Curve curve); +#endif + +/* Converts an integer in uECC native format to big-endian bytes. */ +void mg_uecc_vli_nativeToBytes(uint8_t *bytes, int num_bytes, + const mg_uecc_word_t *native); +/* Converts big-endian bytes to an integer in uECC native format. */ +void mg_uecc_vli_bytesToNative(mg_uecc_word_t *native, const uint8_t *bytes, + int num_bytes); + +unsigned mg_uecc_curve_num_words(MG_UECC_Curve curve); +unsigned mg_uecc_curve_num_bytes(MG_UECC_Curve curve); +unsigned mg_uecc_curve_num_bits(MG_UECC_Curve curve); +unsigned mg_uecc_curve_num_n_words(MG_UECC_Curve curve); +unsigned mg_uecc_curve_num_n_bytes(MG_UECC_Curve curve); +unsigned mg_uecc_curve_num_n_bits(MG_UECC_Curve curve); + +const mg_uecc_word_t *mg_uecc_curve_p(MG_UECC_Curve curve); +const mg_uecc_word_t *mg_uecc_curve_n(MG_UECC_Curve curve); +const mg_uecc_word_t *mg_uecc_curve_G(MG_UECC_Curve curve); +const mg_uecc_word_t *mg_uecc_curve_b(MG_UECC_Curve curve); + +int mg_uecc_valid_point(const mg_uecc_word_t *point, MG_UECC_Curve curve); + +/* Multiplies a point by a scalar. Points are represented by the X coordinate + followed by the Y coordinate in the same array, both coordinates are + curve->num_words long. Note that scalar must be curve->num_n_words long (NOT + curve->num_words). */ +void mg_uecc_point_mult(mg_uecc_word_t *result, const mg_uecc_word_t *point, + const mg_uecc_word_t *scalar, MG_UECC_Curve curve); + +/* Generates a random integer in the range 0 < random < top. + Both random and top have num_words words. */ +int mg_uecc_generate_random_int(mg_uecc_word_t *random, + const mg_uecc_word_t *top, + wordcount_t num_words); + +#endif /* MG_UECC_ENABLE_VLI_API */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _UECC_VLI_H_ */ + +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_TYPES_H_ +#define _UECC_TYPES_H_ + +#ifndef MG_UECC_PLATFORM +#if defined(__AVR__) && __AVR__ +#define MG_UECC_PLATFORM mg_uecc_avr +#elif defined(__thumb2__) || \ + defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */ +#define MG_UECC_PLATFORM mg_uecc_arm_thumb2 +#elif defined(__thumb__) +#define MG_UECC_PLATFORM mg_uecc_arm_thumb +#elif defined(__arm__) || defined(_M_ARM) +#define MG_UECC_PLATFORM mg_uecc_arm +#elif defined(__aarch64__) +#define MG_UECC_PLATFORM mg_uecc_arm64 +#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || \ + defined(__I86__) +#define MG_UECC_PLATFORM mg_uecc_x86 +#elif defined(__amd64__) || defined(_M_X64) +#define MG_UECC_PLATFORM mg_uecc_x86_64 +#else +#define MG_UECC_PLATFORM mg_uecc_arch_other +#endif +#endif + +#ifndef MG_UECC_ARM_USE_UMAAL +#if (MG_UECC_PLATFORM == mg_uecc_arm) && (__ARM_ARCH >= 6) +#define MG_UECC_ARM_USE_UMAAL 1 +#elif (MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && (__ARM_ARCH >= 6) && \ + (!defined(__ARM_ARCH_7M__) || !__ARM_ARCH_7M__) +#define MG_UECC_ARM_USE_UMAAL 1 +#else +#define MG_UECC_ARM_USE_UMAAL 0 +#endif +#endif + +#ifndef MG_UECC_WORD_SIZE +#if MG_UECC_PLATFORM == mg_uecc_avr +#define MG_UECC_WORD_SIZE 1 +#elif (MG_UECC_PLATFORM == mg_uecc_x86_64 || MG_UECC_PLATFORM == mg_uecc_arm64) +#define MG_UECC_WORD_SIZE 8 +#else +#define MG_UECC_WORD_SIZE 4 +#endif +#endif + +#if (MG_UECC_WORD_SIZE != 1) && (MG_UECC_WORD_SIZE != 4) && \ + (MG_UECC_WORD_SIZE != 8) +#error "Unsupported value for MG_UECC_WORD_SIZE" +#endif + +#if ((MG_UECC_PLATFORM == mg_uecc_avr) && (MG_UECC_WORD_SIZE != 1)) +#pragma message("MG_UECC_WORD_SIZE must be 1 for AVR") +#undef MG_UECC_WORD_SIZE +#define MG_UECC_WORD_SIZE 1 +#endif + +#if ((MG_UECC_PLATFORM == mg_uecc_arm || \ + MG_UECC_PLATFORM == mg_uecc_arm_thumb || \ + MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && \ + (MG_UECC_WORD_SIZE != 4)) +#pragma message("MG_UECC_WORD_SIZE must be 4 for ARM") +#undef MG_UECC_WORD_SIZE +#define MG_UECC_WORD_SIZE 4 +#endif + +typedef int8_t wordcount_t; +typedef int16_t bitcount_t; +typedef int8_t cmpresult_t; + +#if (MG_UECC_WORD_SIZE == 1) + +typedef uint8_t mg_uecc_word_t; +typedef uint16_t mg_uecc_dword_t; + +#define HIGH_BIT_SET 0x80 +#define MG_UECC_WORD_BITS 8 +#define MG_UECC_WORD_BITS_SHIFT 3 +#define MG_UECC_WORD_BITS_MASK 0x07 + +#elif (MG_UECC_WORD_SIZE == 4) + +typedef uint32_t mg_uecc_word_t; +typedef uint64_t mg_uecc_dword_t; + +#define HIGH_BIT_SET 0x80000000 +#define MG_UECC_WORD_BITS 32 +#define MG_UECC_WORD_BITS_SHIFT 5 +#define MG_UECC_WORD_BITS_MASK 0x01F + +#elif (MG_UECC_WORD_SIZE == 8) + +typedef uint64_t mg_uecc_word_t; + +#define HIGH_BIT_SET 0x8000000000000000U +#define MG_UECC_WORD_BITS 64 +#define MG_UECC_WORD_BITS_SHIFT 6 +#define MG_UECC_WORD_BITS_MASK 0x03F + +#endif /* MG_UECC_WORD_SIZE */ + +#endif /* _UECC_TYPES_H_ */ +// End of uecc BSD-2 + + +struct mg_connection; +typedef void (*mg_event_handler_t)(struct mg_connection *, int ev, + void *ev_data); +void mg_call(struct mg_connection *c, int ev, void *ev_data); +void mg_error(struct mg_connection *c, const char *fmt, ...); + +enum { + MG_EV_ERROR, // Error char *error_message + MG_EV_OPEN, // Connection created NULL + MG_EV_POLL, // mg_mgr_poll iteration uint64_t *uptime_millis + MG_EV_RESOLVE, // Host name is resolved NULL + MG_EV_CONNECT, // Connection established NULL + MG_EV_ACCEPT, // Connection accepted NULL + MG_EV_TLS_HS, // TLS handshake succeeded NULL + MG_EV_READ, // Data received from socket long *bytes_read + MG_EV_WRITE, // Data written to socket long *bytes_written + MG_EV_CLOSE, // Connection closed NULL + MG_EV_HTTP_HDRS, // HTTP headers struct mg_http_message * + MG_EV_HTTP_MSG, // Full HTTP request/response struct mg_http_message * + MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message * + MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message * + MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message * + MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message * + MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message * + MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code + MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis + MG_EV_WAKEUP, // mg_wakeup() data received struct mg_str *data + MG_EV_USER // Starting ID for user events +}; + + + + + + + + + +struct mg_dns { + const char *url; // DNS server URL + struct mg_connection *c; // DNS server connection +}; + +struct mg_addr { + uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order + uint16_t port; // TCP or UDP port in network byte order + uint8_t scope_id; // IPv6 scope ID + bool is_ip6; // True when address is IPv6 address +}; + +struct mg_mgr { + struct mg_connection *conns; // List of active connections + struct mg_dns dns4; // DNS for IPv4 + struct mg_dns dns6; // DNS for IPv6 + int dnstimeout; // DNS resolve timeout in milliseconds + bool use_dns6; // Use DNS6 server by default, see #1532 + unsigned long nextid; // Next connection ID + unsigned long timerid; // Next timer ID + void *userdata; // Arbitrary user data pointer + void *tls_ctx; // TLS context shared by all TLS sessions + uint16_t mqtt_id; // MQTT IDs for pub/sub + void *active_dns_requests; // DNS requests in progress + struct mg_timer *timers; // Active timers + int epoll_fd; // Used when MG_EPOLL_ENABLE=1 + void *priv; // Used by the MIP stack + size_t extraconnsize; // Used by the MIP stack + MG_SOCKET_TYPE pipe; // Socketpair end for mg_wakeup() +#if MG_ENABLE_FREERTOS_TCP + SocketSet_t ss; // NOTE(lsm): referenced from socket struct +#endif +}; + +struct mg_connection { + struct mg_connection *next; // Linkage in struct mg_mgr :: connections + struct mg_mgr *mgr; // Our container + struct mg_addr loc; // Local address + struct mg_addr rem; // Remote address + void *fd; // Connected socket, or LWIP data + unsigned long id; // Auto-incrementing unique connection ID + struct mg_iobuf recv; // Incoming data + struct mg_iobuf send; // Outgoing data + struct mg_iobuf prof; // Profile data enabled by MG_ENABLE_PROFILE + struct mg_iobuf rtls; // TLS only. Incoming encrypted data + mg_event_handler_t fn; // User-specified event handler function + void *fn_data; // User-specified function parameter + mg_event_handler_t pfn; // Protocol-specific handler function + void *pfn_data; // Protocol-specific function parameter + char data[MG_DATA_SIZE]; // Arbitrary connection data + void *tls; // TLS specific data + unsigned is_listening : 1; // Listening connection + unsigned is_client : 1; // Outbound (client) connection + unsigned is_accepted : 1; // Accepted (server) connection + unsigned is_resolving : 1; // Non-blocking DNS resolution is in progress + unsigned is_arplooking : 1; // Non-blocking ARP resolution is in progress + unsigned is_connecting : 1; // Non-blocking connect is in progress + unsigned is_tls : 1; // TLS-enabled connection + unsigned is_tls_hs : 1; // TLS handshake is in progress + unsigned is_udp : 1; // UDP connection + unsigned is_websocket : 1; // WebSocket connection + unsigned is_mqtt5 : 1; // For MQTT connection, v5 indicator + unsigned is_hexdumping : 1; // Hexdump in/out traffic + unsigned is_draining : 1; // Send remaining data, then close and free + unsigned is_closing : 1; // Close and free the connection immediately + unsigned is_full : 1; // Stop reads, until cleared + unsigned is_resp : 1; // Response is still being generated + unsigned is_readable : 1; // Connection is ready to read + unsigned is_writable : 1; // Connection is ready to write +}; + +void mg_mgr_poll(struct mg_mgr *, int ms); +void mg_mgr_init(struct mg_mgr *); +void mg_mgr_free(struct mg_mgr *); + +struct mg_connection *mg_listen(struct mg_mgr *, const char *url, + mg_event_handler_t fn, void *fn_data); +struct mg_connection *mg_connect(struct mg_mgr *, const char *url, + mg_event_handler_t fn, void *fn_data); +struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd, + mg_event_handler_t fn, void *fn_data); +void mg_connect_resolved(struct mg_connection *); +bool mg_send(struct mg_connection *, const void *, size_t); +size_t mg_printf(struct mg_connection *, const char *fmt, ...); +size_t mg_vprintf(struct mg_connection *, const char *fmt, va_list *ap); +bool mg_aton(struct mg_str str, struct mg_addr *addr); + +// These functions are used to integrate with custom network stacks +struct mg_connection *mg_alloc_conn(struct mg_mgr *); +void mg_close_conn(struct mg_connection *c); +bool mg_open_listener(struct mg_connection *c, const char *url); + +// Utility functions +bool mg_wakeup(struct mg_mgr *, unsigned long id, const void *buf, size_t len); +bool mg_wakeup_init(struct mg_mgr *); +struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds, + unsigned flags, void (*fn)(void *), void *arg); + + + + + + + + +struct mg_http_header { + struct mg_str name; // Header name + struct mg_str value; // Header value +}; + +struct mg_http_message { + struct mg_str method, uri, query, proto; // Request/response line + struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers + struct mg_str body; // Body + struct mg_str head; // Request + headers + struct mg_str message; // Request + headers + body +}; + +// Parameter for mg_http_serve_dir() +struct mg_http_serve_opts { + const char *root_dir; // Web root directory, must be non-NULL + const char *ssi_pattern; // SSI file name pattern, e.g. #.shtml + const char *extra_headers; // Extra HTTP headers to add in responses + const char *mime_types; // Extra mime types, ext1=type1,ext2=type2,.. + const char *page404; // Path to the 404 page, or NULL by default + struct mg_fs *fs; // Filesystem implementation. Use NULL for POSIX +}; + +// Parameter for mg_http_next_multipart +struct mg_http_part { + struct mg_str name; // Form field name + struct mg_str filename; // Filename for file uploads + struct mg_str body; // Part contents +}; + +int mg_http_parse(const char *s, size_t len, struct mg_http_message *); +int mg_http_get_request_len(const unsigned char *buf, size_t buf_len); +void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...); +void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len); +void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm); +struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url, + mg_event_handler_t fn, void *fn_data); +struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url, + mg_event_handler_t fn, void *fn_data); +void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm, + const struct mg_http_serve_opts *); +void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm, + const char *path, const struct mg_http_serve_opts *); +void mg_http_reply(struct mg_connection *, int status_code, const char *headers, + const char *body_fmt, ...); +struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name); +struct mg_str mg_http_var(struct mg_str buf, struct mg_str name); +int mg_http_get_var(const struct mg_str *, const char *name, char *, size_t); +int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form); +size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len); +void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t); +long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, + struct mg_fs *fs, const char *dir, size_t max_size); +void mg_http_bauth(struct mg_connection *, const char *user, const char *pass); +struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v); +size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *); +int mg_http_status(const struct mg_http_message *hm); +void mg_hello(const char *url); + + +void mg_http_serve_ssi(struct mg_connection *c, const char *root, + const char *fullpath); + + +#define MG_TLS_NONE 0 // No TLS support +#define MG_TLS_MBED 1 // mbedTLS +#define MG_TLS_OPENSSL 2 // OpenSSL +#define MG_TLS_WOLFSSL 5 // WolfSSL (based on OpenSSL) +#define MG_TLS_BUILTIN 3 // Built-in +#define MG_TLS_CUSTOM 4 // Custom implementation + +#ifndef MG_TLS +#define MG_TLS MG_TLS_NONE +#endif + + + + + +struct mg_tls_opts { + struct mg_str ca; // PEM or DER + struct mg_str cert; // PEM or DER + struct mg_str key; // PEM or DER + struct mg_str name; // If not empty, enable host name verification + int skip_verification; // Skip certificate and host name verification +}; + +void mg_tls_init(struct mg_connection *, const struct mg_tls_opts *opts); +void mg_tls_free(struct mg_connection *); +long mg_tls_send(struct mg_connection *, const void *buf, size_t len); +long mg_tls_recv(struct mg_connection *, void *buf, size_t len); +size_t mg_tls_pending(struct mg_connection *); +void mg_tls_handshake(struct mg_connection *); + +// Private +void mg_tls_ctx_init(struct mg_mgr *); +void mg_tls_ctx_free(struct mg_mgr *); + +// Low-level IO primives used by TLS layer +enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 }; +long mg_io_send(struct mg_connection *c, const void *buf, size_t len); +long mg_io_recv(struct mg_connection *c, void *buf, size_t len); + + + + + + + +#if MG_TLS == MG_TLS_MBED +#include +#include +#include +#include + +struct mg_tls_ctx { + int dummy; +#ifdef MBEDTLS_SSL_SESSION_TICKETS + mbedtls_ssl_ticket_context tickets; +#endif +}; + +struct mg_tls { + mbedtls_x509_crt ca; // Parsed CA certificate + mbedtls_x509_crt cert; // Parsed certificate + mbedtls_pk_context pk; // Private key context + mbedtls_ssl_context ssl; // SSL/TLS context + mbedtls_ssl_config conf; // SSL-TLS config +#ifdef MBEDTLS_SSL_SESSION_TICKETS + mbedtls_ssl_ticket_context ticket; // Session tickets context +#endif +}; +#endif + + +#if MG_TLS == MG_TLS_OPENSSL || MG_TLS == MG_TLS_WOLFSSL + +#include +#include + +struct mg_tls { + BIO_METHOD *bm; + SSL_CTX *ctx; + SSL *ssl; +}; +#endif + + +#define WEBSOCKET_OP_CONTINUE 0 +#define WEBSOCKET_OP_TEXT 1 +#define WEBSOCKET_OP_BINARY 2 +#define WEBSOCKET_OP_CLOSE 8 +#define WEBSOCKET_OP_PING 9 +#define WEBSOCKET_OP_PONG 10 + + + +struct mg_ws_message { + struct mg_str data; // Websocket message data + uint8_t flags; // Websocket message flags +}; + +struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url, + mg_event_handler_t fn, void *fn_data, + const char *fmt, ...); +void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *, + const char *fmt, ...); +size_t mg_ws_send(struct mg_connection *, const void *buf, size_t len, int op); +size_t mg_ws_wrap(struct mg_connection *, size_t len, int op); +size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...); +size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt, + va_list *); + + + + +struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data); +void mg_sntp_request(struct mg_connection *c); +int64_t mg_sntp_parse(const unsigned char *buf, size_t len); + + + + + +#define MQTT_CMD_CONNECT 1 +#define MQTT_CMD_CONNACK 2 +#define MQTT_CMD_PUBLISH 3 +#define MQTT_CMD_PUBACK 4 +#define MQTT_CMD_PUBREC 5 +#define MQTT_CMD_PUBREL 6 +#define MQTT_CMD_PUBCOMP 7 +#define MQTT_CMD_SUBSCRIBE 8 +#define MQTT_CMD_SUBACK 9 +#define MQTT_CMD_UNSUBSCRIBE 10 +#define MQTT_CMD_UNSUBACK 11 +#define MQTT_CMD_PINGREQ 12 +#define MQTT_CMD_PINGRESP 13 +#define MQTT_CMD_DISCONNECT 14 +#define MQTT_CMD_AUTH 15 + +#define MQTT_PROP_PAYLOAD_FORMAT_INDICATOR 0x01 +#define MQTT_PROP_MESSAGE_EXPIRY_INTERVAL 0x02 +#define MQTT_PROP_CONTENT_TYPE 0x03 +#define MQTT_PROP_RESPONSE_TOPIC 0x08 +#define MQTT_PROP_CORRELATION_DATA 0x09 +#define MQTT_PROP_SUBSCRIPTION_IDENTIFIER 0x0B +#define MQTT_PROP_SESSION_EXPIRY_INTERVAL 0x11 +#define MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER 0x12 +#define MQTT_PROP_SERVER_KEEP_ALIVE 0x13 +#define MQTT_PROP_AUTHENTICATION_METHOD 0x15 +#define MQTT_PROP_AUTHENTICATION_DATA 0x16 +#define MQTT_PROP_REQUEST_PROBLEM_INFORMATION 0x17 +#define MQTT_PROP_WILL_DELAY_INTERVAL 0x18 +#define MQTT_PROP_REQUEST_RESPONSE_INFORMATION 0x19 +#define MQTT_PROP_RESPONSE_INFORMATION 0x1A +#define MQTT_PROP_SERVER_REFERENCE 0x1C +#define MQTT_PROP_REASON_STRING 0x1F +#define MQTT_PROP_RECEIVE_MAXIMUM 0x21 +#define MQTT_PROP_TOPIC_ALIAS_MAXIMUM 0x22 +#define MQTT_PROP_TOPIC_ALIAS 0x23 +#define MQTT_PROP_MAXIMUM_QOS 0x24 +#define MQTT_PROP_RETAIN_AVAILABLE 0x25 +#define MQTT_PROP_USER_PROPERTY 0x26 +#define MQTT_PROP_MAXIMUM_PACKET_SIZE 0x27 +#define MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE 0x28 +#define MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE 0x29 +#define MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE 0x2A + +enum { + MQTT_PROP_TYPE_BYTE, + MQTT_PROP_TYPE_STRING, + MQTT_PROP_TYPE_STRING_PAIR, + MQTT_PROP_TYPE_BINARY_DATA, + MQTT_PROP_TYPE_VARIABLE_INT, + MQTT_PROP_TYPE_INT, + MQTT_PROP_TYPE_SHORT +}; + +enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED }; + +struct mg_mqtt_prop { + uint8_t id; // Enumerated at MQTT5 Reference + uint32_t iv; // Integer value for 8-, 16-, 32-bit integers types + struct mg_str key; // Non-NULL only for user property type + struct mg_str val; // Non-NULL only for UTF-8 types and user properties +}; + +struct mg_mqtt_opts { + struct mg_str user; // Username, can be empty + struct mg_str pass; // Password, can be empty + struct mg_str client_id; // Client ID + struct mg_str topic; // message/subscription topic + struct mg_str message; // message content + uint8_t qos; // message quality of service + uint8_t version; // Can be 4 (3.1.1), or 5. If 0, assume 4 + uint16_t keepalive; // Keep-alive timer in seconds + uint16_t retransmit_id; // For PUBLISH, init to 0 + bool retain; // Retain flag + bool clean; // Clean session flag + struct mg_mqtt_prop *props; // MQTT5 props array + size_t num_props; // number of props + struct mg_mqtt_prop *will_props; // Valid only for CONNECT packet (MQTT5) + size_t num_will_props; // Number of will props +}; + +struct mg_mqtt_message { + struct mg_str topic; // Parsed topic for PUBLISH + struct mg_str data; // Parsed message for PUBLISH + struct mg_str dgram; // Whole MQTT packet, including headers + uint16_t id; // For PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, PUBLISH + uint8_t cmd; // MQTT command, one of MQTT_CMD_* + uint8_t qos; // Quality of service + uint8_t ack; // CONNACK return code, 0 = success + size_t props_start; // Offset to the start of the properties (MQTT5) + size_t props_size; // Length of the properties +}; + +struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url, + const struct mg_mqtt_opts *opts, + mg_event_handler_t fn, void *fn_data); +struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data); +void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts); +uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts); +void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts); +int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *); +void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags, + uint32_t len); +void mg_mqtt_ping(struct mg_connection *); +void mg_mqtt_pong(struct mg_connection *); +void mg_mqtt_disconnect(struct mg_connection *, const struct mg_mqtt_opts *); +size_t mg_mqtt_next_prop(struct mg_mqtt_message *, struct mg_mqtt_prop *, + size_t ofs); + + + + + +// Mongoose sends DNS queries that contain only one question: +// either A (IPv4) or AAAA (IPv6) address lookup. +// Therefore, we expect zero or one answer. +// If `resolved` is true, then `addr` contains resolved IPv4 or IPV6 address. +struct mg_dns_message { + uint16_t txnid; // Transaction ID + bool resolved; // Resolve successful, addr is set + struct mg_addr addr; // Resolved address + char name[256]; // Host name +}; + +struct mg_dns_header { + uint16_t txnid; // Transaction ID + uint16_t flags; + uint16_t num_questions; + uint16_t num_answers; + uint16_t num_authority_prs; + uint16_t num_other_prs; +}; + +// DNS resource record +struct mg_dns_rr { + uint16_t nlen; // Name or pointer length + uint16_t atype; // Address type + uint16_t aclass; // Address class + uint16_t alen; // Address length +}; + +void mg_resolve(struct mg_connection *, const char *url); +void mg_resolve_cancel(struct mg_connection *); +bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *); +size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, + bool is_question, struct mg_dns_rr *); + + + + + +#ifndef MG_JSON_MAX_DEPTH +#define MG_JSON_MAX_DEPTH 30 +#endif + +// Error return values - negative. Successful returns are >= 0 +enum { MG_JSON_TOO_DEEP = -1, MG_JSON_INVALID = -2, MG_JSON_NOT_FOUND = -3 }; +int mg_json_get(struct mg_str json, const char *path, int *toklen); + +struct mg_str mg_json_get_tok(struct mg_str json, const char *path); +bool mg_json_get_num(struct mg_str json, const char *path, double *v); +bool mg_json_get_bool(struct mg_str json, const char *path, bool *v); +long mg_json_get_long(struct mg_str json, const char *path, long dflt); +char *mg_json_get_str(struct mg_str json, const char *path); +char *mg_json_get_hex(struct mg_str json, const char *path, int *len); +char *mg_json_get_b64(struct mg_str json, const char *path, int *len); + +bool mg_json_unescape(struct mg_str str, char *buf, size_t len); +size_t mg_json_next(struct mg_str obj, size_t ofs, struct mg_str *key, + struct mg_str *val); + + + + +// JSON-RPC request descriptor +struct mg_rpc_req { + struct mg_rpc **head; // RPC handlers list head + struct mg_rpc *rpc; // RPC handler being called + mg_pfn_t pfn; // Response printing function + void *pfn_data; // Response printing function data + void *req_data; // Arbitrary request data + struct mg_str frame; // Request, e.g. {"id":1,"method":"add","params":[1,2]} +}; + +// JSON-RPC method handler +struct mg_rpc { + struct mg_rpc *next; // Next in list + struct mg_str method; // Method pattern + void (*fn)(struct mg_rpc_req *); // Handler function + void *fn_data; // Handler function argument +}; + +void mg_rpc_add(struct mg_rpc **head, struct mg_str method_pattern, + void (*handler)(struct mg_rpc_req *), void *handler_data); +void mg_rpc_del(struct mg_rpc **head, void (*handler)(struct mg_rpc_req *)); +void mg_rpc_process(struct mg_rpc_req *); + +// Helper functions to print result or error frame +void mg_rpc_ok(struct mg_rpc_req *, const char *fmt, ...); +void mg_rpc_vok(struct mg_rpc_req *, const char *fmt, va_list *ap); +void mg_rpc_err(struct mg_rpc_req *, int code, const char *fmt, ...); +void mg_rpc_verr(struct mg_rpc_req *, int code, const char *fmt, va_list *); +void mg_rpc_list(struct mg_rpc_req *r); +// Copyright (c) 2023 Cesanta Software Limited +// All rights reserved + + + + + +#define MG_OTA_NONE 0 // No OTA support +#define MG_OTA_FLASH 1 // OTA via an internal flash +#define MG_OTA_ESP32 2 // ESP32 OTA implementation +#define MG_OTA_CUSTOM 100 // Custom implementation + +#ifndef MG_OTA +#define MG_OTA MG_OTA_NONE +#endif + +#if defined(__GNUC__) && !defined(__APPLE__) +#define MG_IRAM __attribute__((section(".iram"))) +#else +#define MG_IRAM +#endif + +// Firmware update API +bool mg_ota_begin(size_t new_firmware_size); // Start writing +bool mg_ota_write(const void *buf, size_t len); // Write chunk, aligned to 1k +bool mg_ota_end(void); // Stop writing + +enum { + MG_OTA_UNAVAILABLE = 0, // No OTA information is present + MG_OTA_FIRST_BOOT = 1, // Device booting the first time after the OTA + MG_OTA_UNCOMMITTED = 2, // Ditto, but marking us for the rollback + MG_OTA_COMMITTED = 3 // The firmware is good +}; +enum { MG_FIRMWARE_CURRENT = 0, MG_FIRMWARE_PREVIOUS = 1 }; + +int mg_ota_status(int firmware); // Return firmware status MG_OTA_* +uint32_t mg_ota_crc32(int firmware); // Return firmware checksum +uint32_t mg_ota_timestamp(int firmware); // Firmware timestamp, UNIX UTC epoch +size_t mg_ota_size(int firmware); // Firmware size + +bool mg_ota_commit(void); // Commit current firmware +bool mg_ota_rollback(void); // Rollback to the previous firmware +MG_IRAM void mg_ota_boot(void); // Bootloader function +// Copyright (c) 2023 Cesanta Software Limited +// All rights reserved + + + + + +#define MG_DEVICE_NONE 0 // Dummy system + +#define MG_DEVICE_STM32H5 1 // STM32 H5 +#define MG_DEVICE_STM32H7 2 // STM32 H7 +#define MG_DEVICE_CH32V307 100 // WCH CH32V307 +#define MG_DEVICE_U2A 200 // Renesas U2A16, U2A8, U2A6 +#define MG_DEVICE_RT1020 300 // IMXRT1020 +#define MG_DEVICE_RT1060 301 // IMXRT1060 +#define MG_DEVICE_CUSTOM 1000 // Custom implementation + +#ifndef MG_DEVICE +#define MG_DEVICE MG_DEVICE_NONE +#endif + +// Flash information +void *mg_flash_start(void); // Return flash start address +size_t mg_flash_size(void); // Return flash size +size_t mg_flash_sector_size(void); // Return flash sector size +size_t mg_flash_write_align(void); // Return flash write align, minimum 4 +int mg_flash_bank(void); // 0: not dual bank, 1: bank1, 2: bank2 + +// Write, erase, swap bank +bool mg_flash_write(void *addr, const void *buf, size_t len); +bool mg_flash_erase(void *sector); +bool mg_flash_swap_bank(void); + +// Convenience functions to store data on a flash sector with wear levelling +// If `sector` is NULL, then the last sector of flash is used +bool mg_flash_load(void *sector, uint32_t key, void *buf, size_t len); +bool mg_flash_save(void *sector, uint32_t key, const void *buf, size_t len); + +void mg_device_reset(void); // Reboot device immediately + + + + + + +#if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP +struct mg_tcpip_if; // Mongoose TCP/IP network interface + +struct mg_tcpip_driver { + bool (*init)(struct mg_tcpip_if *); // Init driver + size_t (*tx)(const void *, size_t, struct mg_tcpip_if *); // Transmit frame + size_t (*rx)(void *buf, size_t len, struct mg_tcpip_if *); // Receive frame + bool (*up)(struct mg_tcpip_if *); // Up/down status +}; + +// Network interface +struct mg_tcpip_if { + uint8_t mac[6]; // MAC address. Must be set to a valid MAC + uint32_t ip, mask, gw; // IP address, mask, default gateway + struct mg_str tx; // Output (TX) buffer + bool enable_dhcp_client; // Enable DCHP client + bool enable_dhcp_server; // Enable DCHP server + bool enable_get_gateway; // DCHP server sets client as gateway + bool enable_crc32_check; // Do a CRC check on RX frames and strip it + bool enable_mac_check; // Do a MAC check on RX frames + struct mg_tcpip_driver *driver; // Low level driver + void *driver_data; // Driver-specific data + struct mg_mgr *mgr; // Mongoose event manager + struct mg_queue recv_queue; // Receive queue + uint16_t mtu; // Interface MTU +#define MG_TCPIP_MTU_DEFAULT 1500 + + // Internal state, user can use it but should not change it + uint8_t gwmac[6]; // Router's MAC + uint64_t now; // Current time + uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state + uint64_t lease_expire; // Lease expiration time, in ms + uint16_t eport; // Next ephemeral port + volatile uint32_t ndrop; // Number of received, but dropped frames + volatile uint32_t nrecv; // Number of received frames + volatile uint32_t nsent; // Number of transmitted frames + volatile uint32_t nerr; // Number of driver errors + uint8_t state; // Current state +#define MG_TCPIP_STATE_DOWN 0 // Interface is down +#define MG_TCPIP_STATE_UP 1 // Interface is up +#define MG_TCPIP_STATE_REQ 2 // Interface is up and has requested an IP +#define MG_TCPIP_STATE_READY 3 // Interface is up and has an IP assigned +}; + +void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *); +void mg_tcpip_free(struct mg_tcpip_if *); +void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp); + +extern struct mg_tcpip_driver mg_tcpip_driver_stm32f; +extern struct mg_tcpip_driver mg_tcpip_driver_w5500; +extern struct mg_tcpip_driver mg_tcpip_driver_tm4c; +extern struct mg_tcpip_driver mg_tcpip_driver_stm32h; +extern struct mg_tcpip_driver mg_tcpip_driver_imxrt; +extern struct mg_tcpip_driver mg_tcpip_driver_same54; +extern struct mg_tcpip_driver mg_tcpip_driver_cmsis; +extern struct mg_tcpip_driver mg_tcpip_driver_ra; +extern struct mg_tcpip_driver mg_tcpip_driver_xmc; +extern struct mg_tcpip_driver mg_tcpip_driver_xmc7; + +// Drivers that require SPI, can use this SPI abstraction +struct mg_tcpip_spi { + void *spi; // Opaque SPI bus descriptor + void (*begin)(void *); // SPI begin: slave select low + void (*end)(void *); // SPI end: slave select high + uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply +}; +#endif + + + +// Macros to record timestamped events that happens with a connection. +// They are saved into a c->prof IO buffer, each event is a name and a 32-bit +// timestamp in milliseconds since connection init time. +// +// Test (run in two separate terminals): +// make -C examples/http-server/ CFLAGS_EXTRA=-DMG_ENABLE_PROFILE=1 +// curl localhost:8000 +// Output: +// 1ea1f1e7 2 net.c:150:mg_close_conn 3 profile: +// 1ea1f1e8 2 net.c:150:mg_close_conn 1ea1f1e6 init +// 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_OPEN +// 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_ACCEPT +// 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_READ +// 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_HTTP_MSG +// 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_WRITE +// 1ea1f1e8 2 net.c:150:mg_close_conn 1 EV_CLOSE +// +// Usage: +// Enable profiling by setting MG_ENABLE_PROFILE=1 +// Invoke MG_PROF_ADD(c, "MY_EVENT_1") in the places you'd like to measure + +#if MG_ENABLE_PROFILE +struct mg_profitem { + const char *name; // Event name + uint32_t timestamp; // Milliseconds since connection creation (MG_EV_OPEN) +}; + +#define MG_PROFILE_ALLOC_GRANULARITY 256 // Can save 32 items wih to realloc + +// Adding a profile item to the c->prof. Must be as fast as possible. +// Reallocation of the c->prof iobuf is not desirable here, that's why we +// pre-allocate c->prof with MG_PROFILE_ALLOC_GRANULARITY. +// This macro just inits and copies 8 bytes, and calls mg_millis(), +// which should be fast enough. +#define MG_PROF_ADD(c, name_) \ + do { \ + struct mg_iobuf *io = &c->prof; \ + uint32_t inittime = ((struct mg_profitem *) io->buf)->timestamp; \ + struct mg_profitem item = {name_, (uint32_t) mg_millis() - inittime}; \ + mg_iobuf_add(io, io->len, &item, sizeof(item)); \ + } while (0) + +// Initialising profile for a new connection. Not time sensitive +#define MG_PROF_INIT(c) \ + do { \ + struct mg_profitem first = {"init", (uint32_t) mg_millis()}; \ + mg_iobuf_init(&(c)->prof, 0, MG_PROFILE_ALLOC_GRANULARITY); \ + mg_iobuf_add(&c->prof, c->prof.len, &first, sizeof(first)); \ + } while (0) + +#define MG_PROF_FREE(c) mg_iobuf_free(&(c)->prof) + +// Dumping the profile. Not time sensitive +#define MG_PROF_DUMP(c) \ + do { \ + struct mg_iobuf *io = &c->prof; \ + struct mg_profitem *p = (struct mg_profitem *) io->buf; \ + struct mg_profitem *e = &p[io->len / sizeof(*p)]; \ + MG_INFO(("%lu profile:", c->id)); \ + while (p < e) { \ + MG_INFO(("%5lx %s", (unsigned long) p->timestamp, p->name)); \ + p++; \ + } \ + } while (0) + +#else +#define MG_PROF_INIT(c) +#define MG_PROF_FREE(c) +#define MG_PROF_ADD(c, name) +#define MG_PROF_DUMP(c) +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_CMSIS) && MG_ENABLE_DRIVER_CMSIS + +#include "Driver_ETH_MAC.h" // keep this include +#include "Driver_ETH_PHY.h" // keep this include + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_IMXRT) && MG_ENABLE_DRIVER_IMXRT + +struct mg_tcpip_driver_imxrt_data { + // MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk), + // must not exceed 2.5MHz. Configuration for clock range 2.36~2.50 MHz + // 37.5.1.8.2, Table 37-46 : f = ipg_clk / (2(mdc_cr + 1)) + // ipg_clk mdc_cr VALUE + // -------------------------- + // -1 <-- TODO() tell driver to guess the value + // 25 MHz 4 + // 33 MHz 6 + // 40 MHz 7 + // 50 MHz 9 + // 66 MHz 13 + int mdc_cr; // Valid values: -1 to 63 + + uint8_t phy_addr; // PHY address +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 2 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 24 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_imxrt_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_imxrt; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: imxrt, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + + + + +struct mg_phy { + uint16_t (*read_reg)(uint8_t addr, uint8_t reg); + void (*write_reg)(uint8_t addr, uint8_t reg, uint16_t value); +}; + +// PHY configuration settings, bitmask +enum { + MG_PHY_LEDS_ACTIVE_HIGH = + (1 << 0), // Set if PHY LEDs are connected to ground + MG_PHY_CLOCKS_MAC = + (1 << 1) // Set when PHY clocks MAC. Otherwise, MAC clocks PHY +}; + +enum { MG_PHY_SPEED_10M, MG_PHY_SPEED_100M, MG_PHY_SPEED_1000M }; + +void mg_phy_init(struct mg_phy *, uint8_t addr, uint8_t config); +bool mg_phy_up(struct mg_phy *, uint8_t addr, bool *full_duplex, + uint8_t *speed); + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RA) && MG_ENABLE_DRIVER_RA + +struct mg_tcpip_driver_ra_data { + // MDC clock "divider". MDC clock is software generated, + uint32_t clock; // core clock frequency in Hz + uint16_t irqno; // IRQn, R_ICU->IELSR[irqno] + uint8_t phy_addr; // PHY address +}; + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54 + +struct mg_tcpip_driver_same54_data { + int mdc_cr; +}; + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 5 +#endif + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \ + MG_ENABLE_DRIVER_STM32F + +struct mg_tcpip_driver_stm32f_data { + // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz + // HCLK range DIVIDER mdc_cr VALUE + // ------------------------------------- + // -1 <-- tell driver to guess the value + // 60-100 MHz HCLK/42 0 + // 100-150 MHz HCLK/62 1 + // 20-35 MHz HCLK/16 2 + // 35-60 MHz HCLK/26 3 + // 150-216 MHz HCLK/102 4 <-- value for Nucleo-F* on max speed + // 216-310 MHz HCLK/124 5 + // 110, 111 Reserved + int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 + + uint8_t phy_addr; // PHY address +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 0 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 4 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_stm32f_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_stm32f; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: stm32f, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \ + MG_ENABLE_DRIVER_STM32H + +struct mg_tcpip_driver_stm32h_data { + // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz + // HCLK range DIVIDER mdc_cr VALUE + // ------------------------------------- + // -1 <-- tell driver to guess the value + // 60-100 MHz HCLK/42 0 + // 100-150 MHz HCLK/62 1 + // 20-35 MHz HCLK/16 2 + // 35-60 MHz HCLK/26 3 + // 150-250 MHz HCLK/102 4 <-- value for max speed HSI + // 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on CSI + // 110, 111 Reserved + int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 + + uint8_t phy_addr; // PHY address + uint8_t phy_conf; // PHY config +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 0 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 4 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_stm32h_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_stm32h; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TM4C) && MG_ENABLE_DRIVER_TM4C + +struct mg_tcpip_driver_tm4c_data { + // MDC clock divider. MDC clock is derived from SYSCLK, must not exceed 2.5MHz + // SYSCLK range DIVIDER mdc_cr VALUE + // ------------------------------------- + // -1 <-- tell driver to guess the value + // 60-100 MHz SYSCLK/42 0 + // 100-150 MHz SYSCLK/62 1 <-- value for EK-TM4C129* on max speed + // 20-35 MHz SYSCLK/16 2 + // 35-60 MHz SYSCLK/26 3 + // 0x4-0xF Reserved + int mdc_cr; // Valid values: -1, 0, 1, 2, 3 +}; + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 1 +#endif + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5500) && MG_ENABLE_DRIVER_W5500 + +#undef MG_ENABLE_TCPIP_DRIVER_INIT +#define MG_ENABLE_TCPIP_DRIVER_INIT 0 + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7 + +struct mg_tcpip_driver_xmc7_data { + int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 + uint8_t phy_addr; +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 0 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 3 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_xmc7_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_xmc7; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC + +struct mg_tcpip_driver_xmc_data { + // 13.2.8.1 Station Management Functions + // MDC clock divider (). MDC clock is derived from ETH MAC clock + // It must not exceed 2.5MHz + // ETH Clock range DIVIDER mdc_cr VALUE + // -------------------------------------------- + // -1 <-- tell driver to guess the value + // 60-100 MHz ETH Clock/42 0 + // 100-150 MHz ETH Clock/62 1 + // 20-35 MHz ETH Clock/16 2 + // 35-60 MHz ETH Clock/26 3 + // 150-250 MHz ETH Clock/102 4 + // 250-300 MHz ETH Clock/124 5 + // 110, 111 Reserved + int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 + uint8_t phy_addr; +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 0 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 4 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_xmc_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_xmc; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: xmc, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + +#ifdef __cplusplus +} +#endif +#endif // MONGOOSE_H diff --git a/webserver/jni/stub.c b/webserver/jni/stub.c new file mode 100644 index 0000000..e69de29 diff --git a/webserver/jni/webserver.c b/webserver/jni/webserver.c new file mode 100644 index 0000000..3ce4c89 --- /dev/null +++ b/webserver/jni/webserver.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include +#include +#include "mongoose/mongoose.h" + +#define THIS_FILE "WebServer" + +// TODO Test difference between 127.0.0.1 + [::1] and localhost +#define HTTP_URL "http://localhost:80" +#define HTTPS_URL "https://localhost:443" + +#define OOM_ADJ_PATH "/proc/self/oom_score_adj" +#define OOM_ADJ_NOKILL -17 + +static int s_sig_num = 0; + +struct settings { + bool init; + struct mg_tls_opts tls_opts; + char test_path[100]; + char icon_path[100]; + bool icon; + bool debug; +}; + +static void fn(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_HTTP_MSG && c->fn_data != NULL) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + struct settings *s = (struct settings *) c->fn_data; + if (mg_strcmp(hm->uri, mg_str("/internal-test")) == 0) { + struct mg_http_serve_opts opts; + memset(&opts, 0, sizeof(opts)); + mg_http_serve_file(c, hm, s->test_path, &opts); + } else if (s->icon) { + struct mg_http_serve_opts opts; + memset(&opts, 0, sizeof(opts)); + mg_http_serve_file(c, hm, s->icon_path, &opts); + } else { + mg_http_reply(c, 200, "", ""); + } + } +} + +static void tls_fn(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_ACCEPT && c->fn_data != NULL) { + struct settings *s = (struct settings *) c->fn_data; + mg_tls_init(c, &s->tls_opts); + } else { + fn(c, ev, ev_data); + } +} + +static void signal_handler(int sig_num) { + signal(sig_num, signal_handler); + s_sig_num = sig_num; +} + +/* + * Tell the kernel's out-of-memory killer to avoid this process. + */ +void oom_adjust_setup(void) { + FILE *fp; + int oom_score = INT_MIN; + if ((fp = fopen(OOM_ADJ_PATH, "r+")) != NULL) { + if (fscanf(fp, "%d", &oom_score) != 1) + __android_log_print(ANDROID_LOG_INFO, THIS_FILE, "error reading %s: %s", OOM_ADJ_PATH, + strerror(errno)); + else { + rewind(fp); + if (fprintf(fp, "%d\n", OOM_ADJ_NOKILL) <= 0) + __android_log_print(ANDROID_LOG_INFO, THIS_FILE, "error writing %s: %s", + OOM_ADJ_PATH, strerror(errno)); + else + __android_log_print(ANDROID_LOG_INFO, THIS_FILE, "Set %s from %d to %d", + OOM_ADJ_PATH, oom_score, OOM_ADJ_NOKILL); + } + fclose(fp); + } +} + +struct settings parse_cli_parameters(int argc, char *argv[]) { + struct settings s = { + .init = false, + .tls_opts = { 0 }, + .icon = false, + .debug = false + }; + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--resources") == 0 && i < argc - 1) { + char *resource_path = argv[++i]; + // Initialize TLS options + char cert_path[100]; + char key_path[100]; + strcpy(cert_path, resource_path); + strcat(cert_path, "/localhost-2410.crt"); + strcpy(key_path, resource_path); + strcat(key_path, "/localhost-2410.key"); + s.tls_opts.cert = mg_file_read(&mg_fs_posix, cert_path); + s.tls_opts.key = mg_file_read(&mg_fs_posix, key_path); + // Initialize resource paths + strcpy(s.icon_path, resource_path); + strcat(s.icon_path, "/icon.svg"); + strcpy(s.test_path, resource_path); + strcat(s.test_path, "/test.html"); + s.init = true; + } else if (strcmp(argv[i], "--icon") == 0) { + s.icon = true; + } else if (strcmp(argv[i], "--debug") == 0) { + s.debug = true; + } + } + return s; +} + +int main(int argc, char *argv[]) { + struct mg_mgr mgr; + struct mg_connection *http_connection; + struct mg_connection *https_connection; + + struct settings s = parse_cli_parameters(argc, argv); + if (!s.init) { + __android_log_print(ANDROID_LOG_FATAL, THIS_FILE, "Missing parameters."); + return EXIT_FAILURE; + } + + if (s.debug) { + __android_log_print(ANDROID_LOG_FATAL, THIS_FILE, "Debug mode activated."); + mg_log_set(MG_LL_DEBUG); + } + + oom_adjust_setup(); + + mg_mgr_init(&mgr); + http_connection = mg_http_listen(&mgr, HTTP_URL, fn, &s); + if (http_connection == NULL) { + __android_log_print(ANDROID_LOG_FATAL, THIS_FILE, "Failed to listen on http port."); + return EXIT_FAILURE; + } + https_connection = mg_http_listen(&mgr, HTTPS_URL, tls_fn, &s); + if (https_connection == NULL) { + __android_log_print(ANDROID_LOG_FATAL, THIS_FILE, "Failed to listen on https port."); + return EXIT_FAILURE; + } + + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + + __android_log_print(ANDROID_LOG_INFO, THIS_FILE, "Starting server."); + while (s_sig_num == 0) { + mg_mgr_poll(&mgr, 1000); + } + + mg_mgr_free(&mgr); + __android_log_print(ANDROID_LOG_INFO, THIS_FILE, "Stopping server on signal %d.", s_sig_num); + return EXIT_SUCCESS; +} diff --git a/webserver/src/main/AndroidManifest.xml b/webserver/src/main/AndroidManifest.xml new file mode 100644 index 0000000..cc947c5 --- /dev/null +++ b/webserver/src/main/AndroidManifest.xml @@ -0,0 +1 @@ +

    Boot στο Boot Menu της συσκευή σας, κÏατώντας πατημένο το πληκτÏο volume down, ενώ πατάτε το πλήκτÏο Power Button ταυτόχÏονα και το κείμενο στην κοÏυφή θα εμφανίσει το flag status είτε ως S-OFF ή S-ON. Ένα πλήÏης Root σημαίνει γενικά S-OFF. +

    ΠεÏισσότεÏες πληÏοφοÏίες μποÏοÏν να βÏεθοÏν στην www.addictivetips.com. ΠÏόσθετες μέθοδοι S-OFF από Unrevokable (in link) που μποÏεί να σας ενδιαφέÏουν συγκεκÏιμένα: Revolutionary, Revone, Firewater, RumRunner, Moonshine, Sunshine…

    `F~60x0jlmt()A<5EBtI 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 literal 0 HcmV?d00001 diff --git a/Resources/status_bar_icon.svg b/Resources/status_bar_icon.svg new file mode 100644 index 0000000..b8c89b9 --- /dev/null +++ b/Resources/status_bar_icon.svg @@ -0,0 +1,358 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Resources/symlink_hosts_to_data.zip b/Resources/symlink_hosts_to_data.zip new file mode 100644 index 0000000000000000000000000000000000000000..53d5255c9c3d59ba34293827cff1073a1ad7eb26 GIT binary patch literal 141823 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 Kn-~Y`Gb3aPhb?qmW?t_2$ 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�GU3mRu^|%kv+gN)2J7^|nlSAlW1jY%s@Q?8> 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 literal 0 HcmV?d00001 diff --git a/Resources/tasker/1-create-tasks.jpg b/Resources/tasker/1-create-tasks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b4d40edfdadf40b8057ecdc5e63e8188e8851bf5 GIT binary patch literal 43448 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 GgZ~L?S- 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 literal 0 HcmV?d00001 diff --git a/Resources/tasker/3-enable-adblock-task-details1.jpg b/Resources/tasker/3-enable-adblock-task-details1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..651eddbb5b0f39bb15fa1200888e667b0eac6365 GIT binary patch literal 91067 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 E0IU?8g8%>k literal 0 HcmV?d00001 diff --git a/Resources/tasker/4-enable-adblock-task-details2.jpg b/Resources/tasker/4-enable-adblock-task-details2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2f5cd5c88d015640e0d4260e872cfb63e92e40df GIT binary patch literal 95768 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