1 #
2 # win-setup - Prepare a Windows development environment for building Wireshark.
3 #
4 # Copyright 2015 Gerald Combs <gerald@wireshark.org>
5 #
6 # Wireshark - Network traffic analyzer
7 # By Gerald Combs <gerald@wireshark.org>
8 # Copyright 1998 Gerald Combs
9 #
10 # SPDX-License-Identifier: GPL-2.0-or-later
11 
12 #requires -version 2
13 
14 # Makefile.nmake + win-setup.sh does:
15 # - verify_tools: Checks required executables. CMake does this.
16 # - clean_setup: Removes current and past lib dirs.
17 # - process_libs: calls libverify or download for each lib.
18 
19 # To do:
20 # - Make this the source of truth. Keep the list of libs here.
21 # - Download everything unconditionally, at least initially.
22 
23 # Bugs:
24 # - Unzipping from the shell seems to be slower than Cygwin's unzip or 7zip.
25 
26 <#
27 .SYNOPSIS
28 Prepare a Windows development environment for building Wireshark.
29 
30 .DESCRIPTION
31 This script downloads and extracts third-party libraries required to compile
32 Wireshark.
33 
34 .PARAMETER Destination
35 Specifies the destination directory for the text files. The path must
36 contain the pattern "wireshark-*-libs-3.6".
37 
38 .PARAMETER Platform
39 Target platform. One of "win64" or "win32".
40 
41 .INPUTS
42 -Destination Destination directory.
43 -Platform Target platform.
44 
45 .OUTPUTS
46 A set of libraries required to compile Wireshark on Windows, along with
47 their compressed archives.
48 A date stamp (current-tag.txt)
49 
50 .EXAMPLE
51 C:\PS> .\tools\win-setup.ps1 -Destination C:\wireshark-master-64-libs-3.6 -Platform win64
52 #>
53 
54 Param(
55     [Parameter(Mandatory=$true, Position=0)]
56     [ValidateScript({$_ -like "*[/\]wireshark-*-libs-3.6"})]
57     [String]
58     $Destination,
59 
60     [Parameter(Mandatory=$true, Position=1)]
61     [ValidateSet("win32", "win64")]
62     [String]
63     $Platform
64 )
65 
66 # Variables
67 
68 # We create and delete files and directories. Bail out at the first sign of
69 # trouble instead of trying to catch exceptions everywhere.
70 $ErrorActionPreference = "Stop"
71 
72 $Win64CurrentTag = "2021-09-29"
73 $Win32CurrentTag = "2021-09-29"
74 
75 # Archive file / SHA256
76 $Win64Archives = @{
77     "AirPcap_Devpack_4_1_0_1622.zip" = "09d637f28a79b1d2ecb09f35436271a90c0f69bd0a1ee82b803abaaf63c18a69";
78     "bcg729-1.0.4-win64ws.zip" = "9a095fda4c39860d96f0c568830faa6651cd17635f68e27aa6de46c689aa0ee2";
79     "brotli-1.0.9-1-win64ws.zip" = "3f8d24aec8668201994327ff8d8542fe507d1d468a500a1aec50d0415f695aab";
80     "c-ares-1.17.2-1-win64ws.zip" = "6572a9dac4317b7a84544f3f85b1028a715c73e4f063c0e1f36ca59168d04070";
81     "gnutls-3.6.3-1-win64ws.zip" = "994ac2578e7b4ca01e589ab2598927d53f7370bc3ff679f3006b0e6bb7a06df4";
82     "krb5-1.17-1-win64ws.zip" = "1f4a7ab86ae331ea9e58c9776a60def81ae9fe622882b2e8da2ad6ce6f6fb1d8";
83     "libgcrypt-1.8.3-win64ws.zip" = "53b1c636cb89de308ca4ea01b4990cf1deca7f6c2446189c7ff6e971137ffd76";
84     "libilbc-2.0.2-3-win64ws.zip" = "d7baeb98627c405bd7c3e41d6b07c4ea4f0f5db88436e566148320afd10cbb66";
85     "libmaxminddb-1.4.3-1-win64ws.zip" = "ee89944a19ab6e1c873bdecb9fc6205d317c41e6da6ec1d30bc892fddfd143da";
86     "libpcap-1.10.1-1-win64ws.zip" = "59f8e0e90a3ab5671df561266ed2b02870a6f8f3a895b80c9db19fea9a12ffb2";
87     "libsmi-svn-40773-win64ws.zip" = "571fcee71d741bf847c3247d4c2e1c42388ca6a9feebe08fc0d4ce053571d15d";
88     "libssh-0.9.5-win64ws.zip" = "3226fcb89969a77643bd2bca7a1ff6b5a79261b680a09a6bfedb3d40f7a187e3";
89     "lua-5.2.4-unicode-win64-vc14.zip" = "e8968d2c7871ce1ea82cbd29ac1b3a2c59d3dec25e483c5e12de85df66f5d928";
90     "lz4-1.9.3-1-win64ws.zip" = "7129515893ffdc439f4ffe9673c4bc43f9042e910bb2607e68dde6b99a1ab058";
91     "minizip-1.2.11-4-win64ws.zip" = "dd6bf24e2d946465ad19aa4f8c38e0db91da6585887935de68011982cd6fb2cb";
92     "nghttp2-1.44.0-1-win64ws.zip" = "30e4925d48bbd401b03ce6502e8df01f81f114366f28682206e08423486cf161";
93     "opus-1.3.1-3-win64ws.zip" = "1f7a55a6d2d7215dffa4a43bca8ca05024bd4ba1ac3d0d0c405fd38b09cc2205";
94     "sbc-1.3-1-win64ws.zip" = "08cef6898c421277a6582ef3225d8820f74a037cbd5b6e673a4d8f4593ce80a1";
95     "snappy-1.1.9-1-win64ws.zip" = "fa907724be019bcc55d27ebe88257ba8898b5c38b719099b8164ac78600d81cc";
96     "spandsp-0.0.6-2-win64ws.zip" = "2eb8278633037f60f44815ea1606486ab5dcdf3bddc500b20c9fe356856236b2";
97     "vcpkg-export-20210609-1-win64ws.zip" = "2207112ecae2d93e64405cb33e625d37c85f9b9db90b440a4d0f0362346564e4";
98     "WinSparkle-0.5.7.zip" = "56d396ef0c4e8b0589ea74134e484376ca6459d972cd1ab1da6b9624d82e6d04";
99     "zstd-1.4.0-win64ws.zip" = "154199227bdfdfa608972bcdcea38e20768937085e5a59a8fa06c72d07b00d6b";
100 }
101 
102 $Win32Archives = @{
103     "AirPcap_Devpack_4_1_0_1622.zip" = "09d637f28a79b1d2ecb09f35436271a90c0f69bd0a1ee82b803abaaf63c18a69";
104     "bcg729-1.0.4-win32ws.zip" = "b785ec78dec6bca8252130eb884bfa28c1140001dd7369a535579176de9e4271";
105     "brotli-1.0.9-1-win32ws.zip" = "37ce13b3d41f025b8f6ca962e7fbacca6421d9b3b58f2ebaa81b1262d0a972ba";
106     "c-ares-1.17.2-1-win32ws.zip" = "ce901f69b46697a52bf239a5a77d6d389c06d637ad2d1bebfaf1333fc4f89e46";
107     "gnutls-3.6.3-1-win32ws.zip" = "42d8313ffb888f525d6c39330c39bcc2182e68ee8433a09dd85e1f1e1474f592";
108     "krb5-1.17-1-win32ws.zip" = "f90cac08355ccfe624652d3e05f8e2e077b8830382315d4ea0a6fa52af08260b";
109     "libgcrypt-1.8.3-win32ws.zip" = "409b72f2809019050cca91b9e670047c50a0752ff52999089178da54ef926393";
110     "libilbc-2.0.2-3-win32ws.zip" = "b87967b5e46cd96d178bc3b3dbba5a75c069ef28ab8a86838c9d004690703997";
111     "libmaxminddb-1.4.3-1-win32ws.zip" = "956f33daa63ce671df4c3e9210308f105e193e7a62c2d947f786d441758ed5e4";
112     "libpcap-1.10.1-1-win32ws.zip" = "145060e567d19b599e2e91e6c3e8023c3d2219acde4bf8bd45ec12e951d57909";
113     "libsmi-svn-40773-win32ws.zip" = "44bc81edfeb8948322ca365fc632e419383907c305cc922e6b74fdbb13827958";
114     "libssh-0.9.5-win32ws.zip" = "0cbdc1b9a65c38e601fda6df3fcdd76f8a0b83e98fa5c836764e1592d8a79194";
115     "lua-5.2.4-unicode-win32-vc14.zip" = "ca2368a83f623674178e9441f71fb791e3c0b46f208e3dac28c6ac735f034bff";
116     "lz4-1.9.3-1-win32ws.zip" = "4b74f9f41a1d364909d9815500dcd10931aa4fbed7fcc39503dfa84c9fcd58d3";
117     "minizip-1.2.11-4-win32ws.zip" = "41e113930902c2519c4644e8307a0cc51c5855e001e1e69768c48deb376142d0";
118     "nghttp2-1.44.0-1-win32ws.zip" = "3a19e076523ef263f6900749f345725b4e8bf2c4027e0f349404ad81c4613bde";
119     "opus-1.3.1-3-win32ws.zip" = "9700b14c8945fcfed2188b806a2ee7e8628922c22569a4c5183075f3dc133177";
120     "sbc-1.3-1-win32ws.zip" = "ad37825e9ace4b849a5442c08f1ed7e30634e6b774bba4307fb86f35f82e71ba";
121     "snappy-1.1.9-1-win32ws.zip" = "28bae646f1dff80ceb1b1756b1fdec0ebc47580a412a8a4980f3d61c63cb0858";
122     "spandsp-0.0.6-2-win32ws.zip" = "31a4b5ca228c719ab4190e1b46801f1483efb8756f1e33d10ecc915244612fca";
123     "vcpkg-export-20210609-1-win32ws.zip" = "da544758352e31aed6cf9e62a6670df218b3d369cd113a462e94010b0ef8e472";
124     "WinSparkle-0.5.7.zip" = "56d396ef0c4e8b0589ea74134e484376ca6459d972cd1ab1da6b9624d82e6d04";
125     "zstd-1.4.0-win32ws.zip" = "9141716d4d749e67dad40d4aab6bbb3206085bf68e5acb03baf1e5667aa0b6f5";
126 }
127 
128 # Subdirectory to extract an archive to
129 $ArchivesSubDirectory = @{
130     "AirPcap_Devpack_4_1_0_1622.zip" = "AirPcap_Devpack_4_1_0_1622";
131 }
132 
133 # Plain file downloads
134 
135 $Win32Files = @{
136     "npcap-1.55.exe" = "0bcc56aef29b24985d7f658cd34013b08cb53ad5bf6b6ac2a982a5f6d4d95800";
137     "USBPcapSetup-1.5.4.0.exe" = "87a7edf9bbbcf07b5f4373d9a192a6770d2ff3add7aa1e276e82e38582ccb622";
138 }
139 
140 $Win64Files = @{
141     "npcap-1.55.exe" = "0bcc56aef29b24985d7f658cd34013b08cb53ad5bf6b6ac2a982a5f6d4d95800";
142     "USBPcapSetup-1.5.4.0.exe" = "87a7edf9bbbcf07b5f4373d9a192a6770d2ff3add7aa1e276e82e38582ccb622";
143 }
144 
145 $Archives = $Win64Archives;
146 $Files = $Win64Files;
147 $CurrentTag = $Win64CurrentTag;
148 
149 if ($Platform -eq "win32") {
150     $Archives = $Win32Archives;
151     $Files = $Win32Files;
152     $CurrentTag = $Win32CurrentTag;
153 }
154 
155 $CleanupItems = @(
156     "bcg729-1.0.4-win??ws"
157     "brotli-1.0.*-win??ws"
158     "c-ares-1.9.1-1-win??ws"
159     "c-ares-1.1*-win??ws"
160     "gnutls-3.?.*-*-win??ws"
161     "glib2-2.*-win??ws"
162     "gtk2"
163     "gtk3"
164     "json-glib-1.0.2-*-win??ws"
165     "kfw-3-2-2*"
166     "krb5-*-win??ws"
167     "libgcrypt-*-win??ws"
168     "libilbc-2.0.2-3-win??ws"
169     "libmaxminddb-1.4.3-1-win??ws"
170     "libpcap-1.9.1-1-win??ws"
171     "libsmi-0.4.8"
172     "libsmi-svn-40773-win??ws"
173     "libssh-0.*-win??ws"
174     "libxml2-*-win??ws"
175     "lua5.1.4"
176     "lua5.2.?"
177     "lua5.2.?-win??"
178     "lua-5.?.?-unicode-win??-vc??"
179     "lz4-*-win??ws"
180     "MaxMindDB-1.3.2-win??ws"
181     "minizip-*-win??ws"
182     "nghttp2-*-win??ws"
183     "opus-1.3.1-?-win??ws"
184     "portaudio_v19"
185     "portaudio_v19_2"
186     "sbc-1.3-win??ws"
187     "snappy-1.1.*-win??ws"
188     "spandsp-0.0.6-win??ws"
189     "upx301w"
190     "upx303w"
191     "user-guide"
192     "vcpkg-export-*-win??ws"
193     "zlib-1.2.5"
194     "zlib-1.2.8"
195     "zlib-1.2.*-ws"
196     "zstd-*-win??ws"
197     "AirPcap_Devpack_4_1_0_1622"
198     "GeoIP-1.*-win??ws"
199     "WinSparkle-0.3-44-g2c8d9d3-win??ws"
200     "WinSparkle-0.5.?"
201     "WpdPack"
202     "current-tag.txt"
203 )
204 
205 [Uri] $DownloadPrefix = "https://anonsvn.wireshark.org/wireshark-$($Platform)-libs/tags/$($CurrentTag)/packages"
206 $Global:SevenZip = "7-zip-not-found"
207 $proxy = $null
208 
209 # Functions
210 
211 # Verifies the contents of a file against a SHA256 checksum.
212 # Returns success (0) if the file exists and verifies.
213 # Returns error (1) if the file does not exist.
214 # Returns error (2) if the integrity check fails (an error is also printed).
VerifyIntegrity($filename, $hash)215 function VerifyIntegrity($filename, $hash) {
216     # Use absolute path because PS and .NET may have different working directories.
217     $filepath = Convert-Path -Path $filename -ErrorAction SilentlyContinue
218     if (-not ($filepath)) {
219         return 1
220     }
221     # may throw due to permission error, I/O error, etc.
222     try { $stream = [IO.File]::OpenRead($filepath) } catch { throw }
223 
224     try {
225         $sha256 = New-Object Security.Cryptography.SHA256Managed
226         $binaryHash = $sha256.ComputeHash([IO.Stream]$stream)
227         $hexHash = ([System.BitConverter]::ToString($binaryHash) -Replace "-").ToLower()
228         $hash = $hash.ToLower()
229         if ($hexHash -ne $hash) {
230             Write-Warning "$($filename): computed checksum $hexHash did NOT match $hash"
231             return 2
232         }
233         return 0
234     } finally {
235         $stream.Close()
236     }
237 }
238 
239 # Downloads a file and checks its integrity. If a corrupt file already exists,
240 # it is removed and re-downloaded. Succeeds only if the SHA256 checksum matches.
DownloadFile($fileName, $checksum, [Uri] $fileUrl = $null)241 function DownloadFile($fileName, $checksum, [Uri] $fileUrl = $null) {
242     if ([string]::IsNullOrEmpty($fileUrl)) {
243         $fileUrl = "$DownloadPrefix/$fileName"
244     }
245     $destinationFile = "$Destination\$fileName"
246     if (Test-Path $destinationFile -PathType 'Leaf') {
247         if ((VerifyIntegrity $destinationFile $checksum) -ne 0) {
248             Write-Output "$fileName is corrupt, removing and retrying download."
249             Remove-Item $destinationFile
250         } else {
251             Write-Output "$fileName already there; not retrieving."
252             return
253         }
254     }
255 
256     if (-not ($Script:proxy)) {
257         $Script:proxy = [System.Net.WebRequest]::GetSystemWebProxy()
258         $Script:proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
259     }
260 
261     Write-Output "Downloading $fileUrl into $Destination"
262     $webClient = New-Object System.Net.WebClient
263     $webClient.proxy = $Script:proxy
264     $webClient.DownloadFile($fileUrl, "$destinationFile")
265     Write-Output "Verifying $destinationFile"
266     if ((VerifyIntegrity $destinationFile $checksum) -ne 0) {
267         Write-Output "Download is corrupted, aborting!"
268         exit 1
269     }
270 }
271 
272 # Find 7-Zip, downloading it if necessary.
273 # If we ever add NuGet support we might be able to use
274 # https://github.com/thoemmi/7Zip4Powershell
Bootstrap7Zip()275 function Bootstrap7Zip() {
276     $searchExes = @("7z.exe", "7za.exe")
277     $binDir = "$Destination\bin"
278 
279     # First, check $env:Path.
280     foreach ($exe in $searchExes) {
281         if (Get-Command $exe -ErrorAction SilentlyContinue)  {
282             $Global:SevenZip = "$exe"
283             Write-Output "Found 7-zip on the path"
284             return
285         }
286     }
287 
288     # Next, look in a few likely places.
289     $searchDirs = @(
290         "${env:ProgramFiles}\7-Zip"
291         "${env:ProgramFiles(x86)}\7-Zip"
292         "${env:ProgramW6432}\7-Zip"
293         "${env:ChocolateyInstall}\bin"
294         "${env:ChocolateyInstall}\tools"
295         "$binDir"
296     )
297 
298     foreach ($dir in $searchDirs) {
299         if ($dir -ne $null -and (Test-Path $dir -PathType 'Container')) {
300             foreach ($exe in $searchExes) {
301                 if (Test-Path "$dir\$exe" -PathType 'Leaf') {
302                     $Global:SevenZip = "$dir\$exe"
303                     Write-Output "Found 7-zip at $dir\$exe"
304                     return
305                 }
306             }
307         }
308     }
309 
310     # Finally, download a copy from anonsvn.
311     if ( -not (Test-Path $binDir -PathType 'Container') ) {
312         New-Item -ItemType 'Container' "$binDir" > $null
313     }
314 
315     Write-Output "Unable to find 7-zip, retrieving from anonsvn into $binDir\7za.exe"
316     [Uri] $bbUrl = "https://anonsvn.wireshark.org/wireshark-win32-libs/trunk/bin/7za.exe"
317     $checksum = "77613cca716edf68b9d5bab951463ed7fade5bc0ec465b36190a76299c50f117"
318     DownloadFile "bin\7za.exe" "$checksum" "$bbUrl"
319 
320     $Global:SevenZip = "$binDir\7za.exe"
321 }
322 
DownloadArchive($fileName, $checksum, $subDir)323 function DownloadArchive($fileName, $checksum, $subDir) {
324     DownloadFile $fileName $checksum
325     # $shell = New-Object -com shell.application
326     $archiveFile = "$Destination\$fileName"
327     $archiveDir = "$Destination\$subDir"
328     if ($subDir -and -not (Test-Path $archiveDir -PathType 'Container')) {
329         New-Item -ItemType Directory -Path $archiveDir > $null
330     }
331     if (Test-Path 'env:WIRESHARK_DO_NOT_USE_7ZIP') {
332         # Display a progress bar while extracting and overwriting existing files.
333         Expand-Archive $archiveFile $archiveDir -Force -ErrorVariable $expandError
334         if ($expandError) {
335             exit 1
336         }
337         return
338     }
339 
340     $activity = "Extracting into $($archiveDir)"
341     Write-Progress -Activity "$activity" -Status "Running 7z x $archiveFile ..."
342     & "$SevenZip" x "-o$archiveDir" -y "$archiveFile" 2>&1 |
343         Set-Variable -Name SevenZOut
344     $bbStatus = $LASTEXITCODE
345     Write-Progress -Activity "$activity" -Status "Done" -Completed
346     if ($bbStatus -gt 0) {
347         Write-Output $SevenZOut
348         exit 1
349     }
350 }
351 
352 # On with the show
353 
354 # Make sure $Destination exists and do our work there.
355 if ( -not (Test-Path $Destination -PathType 'Container') ) {
356     New-Item -ItemType 'Container' "$Destination" > $null
357 }
358 
359 # CMake's file TO_NATIVE_PATH passive-aggressively omits the drive letter.
360 Set-Location "$Destination"
361 $Destination = $(Get-Item -Path ".\")
362 Write-Output "Working in $Destination"
363 
364 # Check our last known state
365 $destinationTag = "INVALID"
366 $tagFile = "current_tag.txt"
367 if ((Test-Path $tagFile -PathType 'Leaf') -and -not ($Force)) {
368     $destinationTag = Get-Content $tagFile
369 }
370 
371 if ($destinationTag -ne $CurrentTag) {
372     Write-Output "Tag $CurrentTag not found. Refreshing."
373     Bootstrap7Zip
374     $activity = "Removing directories"
375     foreach ($oldItem in $CleanupItems) {
376         if (Test-Path $oldItem) {
377             Write-Progress -Activity "$activity" -Status "Removing $oldItem"
378             Remove-Item -force -recurse $oldItem
379         }
380     }
381     Write-Progress -Activity "$activity" -Status "Done" -Completed
382 } else {
383     Write-Output "Tag $CurrentTag found. Skipping."
384     exit 0
385 }
386 
387 # Download files
388 foreach ($item in $Files.GetEnumerator() | Sort-Object -property key) {
389     DownloadFile $item.Name $item.Value
390 }
391 
392 # Download and extract archives
393 foreach ($item in $Archives.GetEnumerator() | Sort-Object -property key) {
394     $subDir = $ArchivesSubDirectory[$item.Name]
395     DownloadArchive $item.Name $item.Value $subDir
396 }
397 
398 # Save our last known state
399 Set-Content -Path $tagFile -Value "$CurrentTag"
400