This commit is contained in:
knqyf263
2019-04-01 23:34:38 +09:00
parent 552c4de1a0
commit ec2b20dcd8
3 changed files with 75 additions and 9 deletions

View File

@@ -1,8 +1,7 @@
package analyzer package analyzer
import ( import (
"os" "io"
"path/filepath"
"github.com/knqyf263/fanal/extractor" "github.com/knqyf263/fanal/extractor"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -59,11 +58,9 @@ func RequiredFilenames() []string {
return filenames return filenames
} }
func Analyze(dir string) (filesMap extractor.FilesMap, err error) { func Analyze(r io.ReadCloser) (filesMap extractor.FilesMap, err error) {
extractor := extractor.DockerExtractor{} extractor := extractor.DockerExtractor{}
file, _ := os.Open(filepath.Join(dir, "layer.tar")) filesMap, err = extractor.Extract(r, RequiredFilenames())
filesMap, err = extractor.ExtractFiles(file, RequiredFilenames())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Failed to extract files") return nil, errors.Wrap(err, "Failed to extract files")
} }

View File

@@ -1,21 +1,38 @@
package main package main
import ( import (
"flag"
"log" "log"
"os" "os"
"golang.org/x/crypto/ssh/terminal"
"github.com/knqyf263/fanal/analyzer" "github.com/knqyf263/fanal/analyzer"
_ "github.com/knqyf263/fanal/analyzer/os/alpine" _ "github.com/knqyf263/fanal/analyzer/os/alpine"
_ "github.com/knqyf263/fanal/analyzer/pkg/apk" _ "github.com/knqyf263/fanal/analyzer/pkg/apk"
) )
func main() { func main() {
dir, err := os.Getwd() tarPath := flag.String("f", "-", "layer.tar path")
flag.Parse()
rc, err := openStream(*tarPath)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
files, _ := analyzer.Analyze(dir) files, _ := analyzer.Analyze(rc)
analyzer.GetOS(files) analyzer.GetOS(files)
analyzer.GetPackages(files) analyzer.GetPackages(files)
} }
func openStream(path string) (*os.File, error) {
if path == "-" {
if terminal.IsTerminal(0) {
flag.Usage()
os.Exit(64)
} else {
return os.Stdin, nil
}
}
return os.Open(path)
}

View File

@@ -2,14 +2,66 @@ package extractor
import ( import (
"archive/tar" "archive/tar"
"encoding/json"
"io" "io"
"io/ioutil" "io/ioutil"
"path" "path"
"path/filepath"
"strings"
) )
type manifest struct {
Config string `json:"Config"`
RepoTags []string `json:"RepoTags"`
Layers []string `json:"Layers"`
}
type DockerExtractor struct{} type DockerExtractor struct{}
func (d DockerExtractor) ExtractFiles(layer io.ReadCloser, filenames []string) (FilesMap, error) { func (d DockerExtractor) Extract(r io.ReadCloser, filenames []string) (FilesMap, error) {
manifests := make([]manifest, 0)
filesInLayers := make(map[string]FilesMap)
tr := tar.NewReader(r)
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return nil, ErrCouldNotExtract
}
switch {
case header.Name == "manifest.json":
if err := json.NewDecoder(tr).Decode(&manifests); err != nil {
return nil, err
}
case strings.HasSuffix(header.Name, ".tar"):
layerID := filepath.Base(filepath.Dir(header.Name))
files, err := d.ExtractFiles(tr, filenames)
if err != nil {
return nil, err
}
filesInLayers[layerID] = files
//case strings.HasSuffix(header.Name, ".json"):
// if err := json.NewDecoder(tr).Decode(&imageMeta); err != nil {
// return nil, err
// }
// imageMetas[header.Name] = imageMeta
default:
}
}
filesMap := map[string][]byte{}
for _, layerID := range manifests[0].Layers {
layerID := strings.Split(layerID, "/")[0]
for k, v := range filesInLayers[layerID] {
filesMap[k] = v
}
}
return filesMap, nil
}
func (d DockerExtractor) ExtractFiles(layer io.Reader, filenames []string) (FilesMap, error) {
data := make(map[string][]byte) data := make(map[string][]byte)
tr := tar.NewReader(layer) tr := tar.NewReader(layer)